[FFmpeg-devel] [PATCH] adding support for writing m2ts bluray container

Herr Sven Alisch BSc. svenali
Sun Feb 13 21:30:52 CET 2011


Hello,

here my complete working patch for m2ts. I added the line ts->last_arrival_time_stamp = ts->first_pcr. It is better, because the arrival_time_stamp needs to be <= pcr ticks. The streams are playable with the ps3 from sony. 

regards,
Sven

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 1d4e75e..f408ad9 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -145,6 +145,7 @@ OBJS-$(CONFIG_MPEG2VIDEO_MUXER)          += rawenc.o
 OBJS-$(CONFIG_MPEGPS_DEMUXER)            += mpeg.o
 OBJS-$(CONFIG_MPEGTS_DEMUXER)            += mpegts.o isom.o
 OBJS-$(CONFIG_MPEGTS_MUXER)              += mpegtsenc.o adtsenc.o
+OBJS-$(CONFIG_MPEG2TS_MUXER)             += mpegtsenc.o adtsenc.o
 OBJS-$(CONFIG_MPEGVIDEO_DEMUXER)         += mpegvideodec.o rawdec.o
 OBJS-$(CONFIG_MPJPEG_MUXER)              += mpjpeg.o
 OBJS-$(CONFIG_MSNWC_TCP_DEMUXER)         += msnwc_tcp.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 0ff4b5a..55045f0 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -135,6 +135,7 @@ void av_register_all(void)
     REGISTER_MUXER    (MPEG2VOB, mpeg2vob);
     REGISTER_DEMUXER  (MPEGPS, mpegps);
     REGISTER_MUXDEMUX (MPEGTS, mpegts);
+    REGISTER_MUXER    (MPEG2TS, mpeg2ts);
     REGISTER_DEMUXER  (MPEGTSRAW, mpegtsraw);
     REGISTER_DEMUXER  (MPEGVIDEO, mpegvideo);
     REGISTER_MUXER    (MPJPEG, mpjpeg);
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index b1bccd1..25a7f0f 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -1,6 +1,7 @@
 /*
  * MPEG2 transport stream (aka DVB) muxer
  * Copyright (c) 2003 Fabrice Bellard
+ * M2TS patches Copyright (c) 2011 Sven Alisch
  *
  * This file is part of FFmpeg.
  *
@@ -66,6 +67,11 @@ typedef struct MpegTSWrite {
     int64_t first_pcr;
     int mux_rate; ///< set to 1 when VBR
 
+    int64_t last_arrival_time_stamp; /* contains the last written arrival timestamp */
+    int counted_null_packets; /* Null Packets were not written into m2ts streams. But the pcr has to calculate with the bytes not written. */
+    int last_null_packets; /* To calculate the exact arrival_time_stamp, we have to get the number of last counted null packets. */
+    int m2ts_mode; /* 0, if not, 1 if yes */
+
     int transport_stream_id;
     int original_network_id;
     int service_id;
@@ -95,6 +101,29 @@ static const AVClass mpegts_muxer_class = {
     LIBAVUTIL_VERSION_INT,
 };
 
+/* generates a arrival time stamp for the m2ts header */
+static int64_t get_arrival_time_stamp(MpegTSWrite *ts, ByteIOContext *pb) 
+{
+    int64_t pcr_diff = (ts->last_null_packets + 1) * av_rescale(188 * 8, PCR_TIME_BASE, ts->mux_rate);   
+
+    ts->last_arrival_time_stamp += pcr_diff;
+    return ts->last_arrival_time_stamp;
+}
+
+/* The arrival_time_stamp consists of 4 byte. The first two bits are reserved for a copyright and should set to 11 (binary) */ 
+static void write_starttime_code(uint8_t* q, int64_t arrival_time_stamp) 
+{
+    *q = 3 << 6;
+    int val = (arrival_time_stamp >> 24) & 0xFF; 
+    *q++ |= val;
+    val = (arrival_time_stamp >> 16) & 0xFF;
+    *q++ = val;
+    val = (arrival_time_stamp >> 8) & 0xFF;
+    *q++ = val;
+    val = arrival_time_stamp;
+    *q++ = val; 
+}
+
 /* NOTE: 4 bytes must be left at the end for the crc32 */
 static void mpegts_write_section(MpegTSSection *s, uint8_t *buf, int len)
 {
@@ -411,6 +440,20 @@ static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
     put_buffer(ctx->pb, packet, TS_PACKET_SIZE);
 }
 
+/* a version for m2ts streams */
+static void section_write_packet2(MpegTSSection *s, const uint8_t *packet)
+{
+    AVFormatContext *ctx = s->opaque;
+    MpegTSWrite *ts = ctx->priv_data; 
+    uint8_t buf[TS_PACKET_SIZE + 4];
+    int64_t arrival_time_stamp = get_arrival_time_stamp(ctx->priv_data, ctx->pb);
+
+    write_starttime_code(buf, arrival_time_stamp);
+    memcpy(&buf[4], packet, TS_PACKET_SIZE);
+	
+    put_buffer(ctx->pb, buf, TS_PACKET_SIZE + 4);
+}
+
 static int mpegts_write_header(AVFormatContext *s)
 {
     MpegTSWrite *ts = s->priv_data;
@@ -423,8 +466,13 @@ static int mpegts_write_header(AVFormatContext *s)
     const char *provider_name;
     int *pids;
 
+    if (ts->m2ts_mode != 1) /* if mpeg2ts_write_header is not called first */
+        ts->m2ts_mode = 0;
     ts->tsid = ts->transport_stream_id;
     ts->onid = ts->original_network_id;
+    /* Initializing the m2ts parameters. Not important for normal ts streams! */
+    ts->counted_null_packets = 0;
+    ts->last_null_packets = 0;
     /* allocate a single DVB service */
     title = av_metadata_get(s->metadata, "service_name", NULL, 0);
     if (!title)
@@ -433,18 +481,27 @@ static int mpegts_write_header(AVFormatContext *s)
     provider = av_metadata_get(s->metadata, "service_provider", NULL, 0);
     provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
     service = mpegts_add_service(ts, ts->service_id, provider_name, service_name);
-    service->pmt.write_packet = section_write_packet;
+    if (ts->m2ts_mode == 1)
+        service->pmt.write_packet = section_write_packet2;
+    else
+        service->pmt.write_packet = section_write_packet;
     service->pmt.opaque = s;
     service->pmt.cc = 15;
 
     ts->pat.pid = PAT_PID;
     ts->pat.cc = 15; // Initialize at 15 so that it wraps and be equal to 0 for the first packet we write
-    ts->pat.write_packet = section_write_packet;
+    if (ts->m2ts_mode == 1)
+        ts->pat.write_packet = section_write_packet2;
+    else
+        ts->pat.write_packet = section_write_packet;
     ts->pat.opaque = s;
 
     ts->sdt.pid = SDT_PID;
     ts->sdt.cc = 15;
-    ts->sdt.write_packet = section_write_packet;
+    if (ts->m2ts_mode == 1)
+        ts->sdt.write_packet = section_write_packet2;
+    else
+        ts->sdt.write_packet = section_write_packet;
     ts->sdt.opaque = s;
 
     pids = av_malloc(s->nb_streams * sizeof(*pids));
@@ -520,6 +577,7 @@ static int mpegts_write_header(AVFormatContext *s)
             (TS_PACKET_SIZE * 8 * 1000);
 
         ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
+        ts->last_arrival_time_stamp = ts->first_pcr;
     } else {
         /* Arbitrary values, PAT/PMT could be written on key frames */
         ts->sdt_packet_period = 200;
@@ -588,7 +646,12 @@ static void retransmit_si_info(AVFormatContext *s)
 
 static int64_t get_pcr(const MpegTSWrite *ts, ByteIOContext *pb)
 {
-    return av_rescale(url_ftell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
+    /* if a m2ts is build, an offset is possible (depends on the muxrate), because 
+       the null packets are only counted and NOT written! So url_ftell gives not the correct
+       written bytes. We have to add an offset of 192 multiplied by counted null packets. */
+    int byteoffset = (TS_PACKET_SIZE + 4) * ts->counted_null_packets;
+  
+    return av_rescale(url_ftell(pb) + byteoffset + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
            ts->first_pcr;
 }
 
@@ -628,6 +691,7 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
     MpegTSWriteStream *ts_st = st->priv_data;
     uint8_t *q;
     uint8_t buf[TS_PACKET_SIZE];
+    uint8_t source_packet[TS_PACKET_SIZE + 4];
 
     q = buf;
     *q++ = 0x47;
@@ -643,7 +707,16 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
 
     /* stuffing bytes */
     memset(q, 0xFF, TS_PACKET_SIZE - (q - buf));
-    put_buffer(s->pb, buf, TS_PACKET_SIZE);
+
+    if (ts->m2ts_mode == 1) {
+        memcpy(&source_packet[4], buf, TS_PACKET_SIZE);
+        int64_t arrival_time_stamp = get_arrival_time_stamp(ts, s->pb);
+        write_starttime_code(source_packet, arrival_time_stamp);
+
+        put_buffer(s->pb, source_packet, TS_PACKET_SIZE + 4);
+    } 
+    else
+        put_buffer(s->pb, buf, TS_PACKET_SIZE);
 }
 
 static void write_pts(uint8_t *q, int fourbits, int64_t pts)
@@ -672,6 +745,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
     MpegTSWriteStream *ts_st = st->priv_data;
     MpegTSWrite *ts = s->priv_data;
     uint8_t buf[TS_PACKET_SIZE];
+    uint8_t source_packet[TS_PACKET_SIZE + 4];	/* we copy the content from buf into source_packet if m2ts mode :-) */
     uint8_t *q;
     int val, is_start, len, header_len, write_pcr, private_code, flags;
     int afc_len, stuffing_len;
@@ -698,8 +772,14 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
             /* pcr insert gets priority over null packet insert */
             if (write_pcr)
                 mpegts_insert_pcr_only(s, st);
-            else
-                mpegts_insert_null_packet(s);
+            else {
+            	if (ts->m2ts_mode == 1) {
+                    ts->counted_null_packets++;
+                    ts->last_null_packets++;
+                }
+                else
+                    mpegts_insert_null_packet(s);
+            }
             continue; /* recalculate write_pcr and possibly retransmit si_info */
         }
 
@@ -837,7 +917,19 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
         memcpy(buf + TS_PACKET_SIZE - len, payload, len);
         payload += len;
         payload_size -= len;
-        put_buffer(s->pb, buf, TS_PACKET_SIZE);
+        if (ts->m2ts_mode == 1) {
+            memcpy(&source_packet[4], buf, TS_PACKET_SIZE);
+            int64_t arrival_time_stamp = get_arrival_time_stamp(s->priv_data, s->pb);
+
+            if (ts->last_null_packets > 0) {
+                ts->last_null_packets = 0;
+            }
+
+            write_starttime_code(source_packet, arrival_time_stamp);	
+            put_buffer(s->pb, source_packet, TS_PACKET_SIZE + 4);
+        }
+        else
+            put_buffer(s->pb, buf, TS_PACKET_SIZE);
     }
     put_flush_packet(s->pb);
 }
@@ -975,6 +1067,14 @@ static int mpegts_write_end(AVFormatContext *s)
     return 0;
 }
 
+/* resetting the function pointer */
+static int mpeg2ts_write_header(AVFormatContext *s)
+{
+    MpegTSWrite *ts = s->priv_data;
+    ts->m2ts_mode = 1;
+    return mpegts_write_header(s);
+}
+
 AVOutputFormat ff_mpegts_muxer = {
     "mpegts",
     NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"),
@@ -988,3 +1088,17 @@ AVOutputFormat ff_mpegts_muxer = {
     mpegts_write_end,
     .priv_class = &mpegts_muxer_class,
 };
+
+AVOutputFormat ff_mpeg2ts_muxer = {
+    "mpeg2ts",
+    NULL_IF_CONFIG_SMALL("BDAV MPEG-2 transport stream format"),
+    "video/x-mpeg2ts",
+    "m2ts",
+    sizeof(MpegTSWrite),
+    CODEC_ID_MP2,
+    CODEC_ID_MPEG2VIDEO,
+    mpeg2ts_write_header,
+    mpegts_write_packet,
+    mpegts_write_end,
+    .priv_class = &mpegts_muxer_class,
+};




More information about the ffmpeg-devel mailing list