Hi,

the attached patches allow to remux MPEGTS files containing KLV
metadata. Since there are two kinds of metadata (synchronous and
asynchronous), the first patch creates side data which stores the
stream ID used to distinguish the two kind of packets, which is
otherwise lost.

At the moment, I'm storing a single byte in the side data
(corresponding to the stream ID), but the metadata could be extended
to contain more information.

The second patch disables monotonicity checks for data packets in the
muxer. Indeed there is a case where several data packets can have the
same PTS/DTS in MPEGTS so it should be enabled at least for this
special case (either explicitly enabling this for MPEGTS -
e.g. through a capability flag, or enabling an option to disable the
montonicity check, whatever people prefer).

Comments are very welcome.
-- 
FFmpeg = Funny & Fabulous Meaningful Picky Exxagerate Guru
>From 9ad3c8fda108b4fb5a2b6779189cfca3e069b89e Mon Sep 17 00:00:00 2001
From: Stefano Sabatini <stefa...@gmail.com>
Date: Wed, 18 Nov 2015 19:23:03 +0100
Subject: [PATCH] lavc/lavf: transmit stream_id information for mpegts KLV data
 packets

This allows to copy information related to the stream ID from the demuxer
to the muxer, thus allowing for example to retain information related to
synchronous and asynchronous KLV data packets.
---
 libavcodec/avcodec.h    |  7 +++++++
 libavcodec/avpacket.c   |  1 +
 libavformat/mpegts.c    | 12 +++++++++++-
 libavformat/mpegtsenc.c | 27 ++++++++++++++++++++-------
 4 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index f365775..b5b884d 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1402,6 +1402,13 @@ enum AVPacketSideDataType {
      * side data includes updated metadata which appeared in the stream.
      */
     AV_PKT_DATA_METADATA_UPDATE,
+
+    /**
+     * MPEG private metadata. This is required to transmit information
+     * from the MPEGTS demuxer to the corresponding muxer, for example
+     * the stream ID information.
+     */
+    AV_PKT_DATA_MPEGTS_METADATA,
 };
 
 #define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index 4901d36..e23fa5c 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -351,6 +351,7 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type)
     case AV_PKT_DATA_WEBVTT_IDENTIFIER:         return "WebVTT ID";
     case AV_PKT_DATA_WEBVTT_SETTINGS:           return "WebVTT Settings";
     case AV_PKT_DATA_METADATA_UPDATE:           return "Metadata Update";
+    case AV_PKT_DATA_MPEGTS_METADATA:           return "MPEGTS Metadata";
     }
     return NULL;
 }
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 22874e6..5f5de62 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -235,6 +235,7 @@ typedef struct PESContext {
     int total_size;
     int pes_header_size;
     int extended_stream_id;
+    uint8_t stream_id;
     int64_t pts, dts;
     int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
     uint8_t header[MAX_PES_HEADER_SIZE];
@@ -862,14 +863,21 @@ static void reset_pes_packet_state(PESContext *pes)
     av_buffer_unref(&pes->buffer);
 }
 
-static void new_pes_packet(PESContext *pes, AVPacket *pkt)
+static int new_pes_packet(PESContext *pes, AVPacket *pkt)
 {
+    char *sd;
+
     av_init_packet(pkt);
 
     pkt->buf  = pes->buffer;
     pkt->data = pes->buffer->data;
     pkt->size = pes->data_index;
 
+    sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_METADATA, 1);
+    if (!sd)
+        return AVERROR(ENOMEM);
+    *sd = pes->stream_id;
+
     if (pes->total_size != MAX_PES_PAYLOAD &&
         pes->pes_header_size + pes->data_index != pes->total_size +
         PES_START_SIZE) {
@@ -891,6 +899,7 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt)
 
     pes->buffer = NULL;
     reset_pes_packet_state(pes);
+    return 0;
 }
 
 static uint64_t get_ts64(GetBitContext *gb, int bits)
@@ -1014,6 +1023,7 @@ static int mpegts_push_data(MpegTSFilter *filter,
                     code = pes->header[3] | 0x100;
                     av_log(pes->stream, AV_LOG_TRACE, "pid=%x pes_code=%#x\n", pes->pid,
                             code);
+                    pes->stream_id = pes->header[3];
 
                     if ((pes->st && pes->st->discard == AVDISCARD_ALL &&
                          (!pes->sub_st ||
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 2c12043..d890e93 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -1100,7 +1100,7 @@ static uint8_t *get_ts_payload_start(uint8_t *pkt)
  * NOTE: 'payload' contains a complete PES payload. */
 static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
                              const uint8_t *payload, int payload_size,
-                             int64_t pts, int64_t dts, int key)
+                             int64_t pts, int64_t dts, int key, uint8_t stream_id)
 {
     MpegTSWriteStream *ts_st = st->priv_data;
     MpegTSWrite *ts = s->priv_data;
@@ -1198,7 +1198,11 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
                         ts->m2ts_mode) {
                 *q++ = 0xfd;
             } else {
-                *q++ = 0xbd;
+                *q++ = stream_id ? stream_id : 0xbd;
+
+                if (stream_id == 0xbd) /* asynchronous KLV */
+                    pts = dts = AV_NOPTS_VALUE;
+
                 if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                     if (st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
                         is_dvb_subtitle = 1;
@@ -1440,6 +1444,15 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     const int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE) * 2;
     int64_t dts = pkt->dts, pts = pkt->pts;
     int opus_samples = 0;
+    int side_data_size;
+    char *side_data = NULL;
+    int stream_id = 0xbd;
+
+    side_data = av_packet_get_side_data(pkt,
+                                        AV_PKT_DATA_MPEGTS_METADATA,
+                                        &side_data_size);
+    if (side_data)
+        stream_id = side_data[0];
 
     if (ts->reemit_pat_pmt) {
         av_log(s, AV_LOG_WARNING,
@@ -1620,8 +1633,8 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
             if (   ts_st2->payload_size
                && (ts_st2->payload_dts == AV_NOPTS_VALUE || dts - ts_st2->payload_dts > delay/2)) {
                 mpegts_write_pes(s, st2, ts_st2->payload, ts_st2->payload_size,
-                                ts_st2->payload_pts, ts_st2->payload_dts,
-                                ts_st2->payload_flags & AV_PKT_FLAG_KEY);
+                                 ts_st2->payload_pts, ts_st2->payload_dts,
+                                 ts_st2->payload_flags & AV_PKT_FLAG_KEY, stream_id);
                 ts_st2->payload_size = 0;
             }
         }
@@ -1634,7 +1647,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
         ts_st->opus_queued_samples + opus_samples >= 5760 /* 120ms */)) {
         mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size,
                          ts_st->payload_pts, ts_st->payload_dts,
-                         ts_st->payload_flags & AV_PKT_FLAG_KEY);
+                         ts_st->payload_flags & AV_PKT_FLAG_KEY, stream_id);
         ts_st->payload_size = 0;
         ts_st->opus_queued_samples = 0;
     }
@@ -1643,7 +1656,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
         av_assert0(!ts_st->payload_size);
         // for video and subtitle, write a single pes packet
         mpegts_write_pes(s, st, buf, size, pts, dts,
-                         pkt->flags & AV_PKT_FLAG_KEY);
+                         pkt->flags & AV_PKT_FLAG_KEY, stream_id);
         ts_st->opus_queued_samples = 0;
         av_free(data);
         return 0;
@@ -1675,7 +1688,7 @@ static void mpegts_write_flush(AVFormatContext *s)
         if (ts_st->payload_size > 0) {
             mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size,
                              ts_st->payload_pts, ts_st->payload_dts,
-                             ts_st->payload_flags & AV_PKT_FLAG_KEY);
+                             ts_st->payload_flags & AV_PKT_FLAG_KEY, 0);
             ts_st->payload_size = 0;
             ts_st->opus_queued_samples = 0;
         }
-- 
1.9.1

>From 0f0e68558f385d4a2546f80c0aeba2d947013f62 Mon Sep 17 00:00:00 2001
From: Stefano Sabatini <stefa...@gmail.com>
Date: Thu, 17 Dec 2015 20:51:42 +0100
Subject: [PATCH] lavf/mux: do not fail in case of non monotonically increasing
 DTS values for data packets

Disable monotonicity test for data packets. Data packets are not supposed
to be decoded by FFmpeg, and this checks cause conversion failure with
some files with non strictly monotonous timestamps.
---
 libavformat/mux.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavformat/mux.c b/libavformat/mux.c
index 2da8cf2..9f4eded 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -557,10 +557,11 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket *
         pkt->dts = st->pts_buffer[0];
     }
 
-    if (st->cur_dts && st->cur_dts != AV_NOPTS_VALUE &&
+    if ((st->codec->codec_type != AVMEDIA_TYPE_DATA) &&
+        (st->cur_dts && st->cur_dts != AV_NOPTS_VALUE &&
         ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) &&
           st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE &&
-          st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)) {
+          st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts))) {
         av_log(s, AV_LOG_ERROR,
                "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %s >= %s\n",
                st->index, av_ts2str(st->cur_dts), av_ts2str(pkt->dts));
-- 
1.9.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to