[FFmpeg-devel] Mov / Mp4 Muxer in streaming

Marco Fucci mfucci
Tue Apr 14 20:09:16 CEST 2009


Hi,

Here is the patch, I hope it is correct, I made it with Tortoise. Let me
know if this works and when this is merged with the main trunk.

Best,
Marco

---------------------------------------------------------------------------------------------------------------------

Index: movenc.c
===================================================================
--- movenc.c	(revision 18510)
+++ movenc.c	(working copy)
@@ -26,8 +26,7 @@
 #include "avio.h"
 #include "isom.h"
 #include "avc.h"
-#include "libavcodec/get_bits.h"
-#include "libavcodec/put_bits.h"
+#include "libavcodec/bitstream.h"

 #undef NDEBUG
 #include <assert.h>
@@ -547,154 +546,98 @@
     return 0;
 }

-static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
-{
-    int tag = track->enc->codec_tag;
-
-    if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
-        return 0;
-
-    if      (track->enc->codec_id == CODEC_ID_H264)      tag =
MKTAG('a','v','c','1');
-    else if (track->enc->codec_id == CODEC_ID_AC3)       tag =
MKTAG('a','c','-','3');
-    else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag =
MKTAG('d','r','a','c');
-    else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag =
MKTAG('t','x','3','g');
-    else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag =
MKTAG('m','p','4','v');
-    else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag =
MKTAG('m','p','4','a');
-
-    return tag;
-}
-
-static const AVCodecTag codec_ipod_tags[] = {
+static const AVCodecTag codec_3gp_tags[] = {
+    { CODEC_ID_H263,   MKTAG('s','2','6','3') },
     { CODEC_ID_H264,   MKTAG('a','v','c','1') },
     { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
     { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
-    { CODEC_ID_ALAC,   MKTAG('a','l','a','c') },
-    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
+    { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
+    { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
     { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
-    { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
     { CODEC_ID_NONE, 0 },
 };

-static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
-{
-    int tag = track->enc->codec_tag;
-
-    // keep original tag for subs, ipod supports both formats
-    if (!(track->enc->codec_type == CODEC_TYPE_SUBTITLE &&
-        (tag == MKTAG('t','x','3','g') ||
-         tag == MKTAG('t','e','x','t'))))
-        tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id);
-
-    if (!match_ext(s->filename, "m4a") && !match_ext(s->filename, "m4v"))
-        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
-               "Quicktime/Ipod might not play the file\n");
-
-    return tag;
-}
-
-static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
-{
-    int tag;
-
-    if (track->enc->height == 480) /* NTSC */
-        if  (track->enc->pix_fmt == PIX_FMT_YUV422P) tag =
MKTAG('d','v','5','n');
-        else                                         tag =
MKTAG('d','v','c',' ');
-    else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag =
MKTAG('d','v','5','p');
-    else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag =
MKTAG('d','v','c','p');
-    else                                             tag =
MKTAG('d','v','p','p');
-
-    return tag;
-}
-
-static const struct {
-    enum PixelFormat pix_fmt;
-    uint32_t tag;
-    unsigned bps;
-} mov_pix_fmt_tags[] = {
-    { PIX_FMT_YUYV422, MKTAG('y','u','v','s'),  0 },
-    { PIX_FMT_UYVY422, MKTAG('2','v','u','y'),  0 },
-    { PIX_FMT_BGR555,  MKTAG('r','a','w',' '), 16 },
-    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
-    { PIX_FMT_BGR32_1, MKTAG('r','a','w',' '), 32 },
+static const AVCodecTag mov_pix_fmt_tags[] = {
+    { PIX_FMT_YUYV422, MKTAG('y','u','v','s') },
+    { PIX_FMT_UYVY422, MKTAG('2','v','u','y') },
+    { PIX_FMT_BGR555,  MKTAG('r','a','w',' ') },
+    { PIX_FMT_RGB24,   MKTAG('r','a','w',' ') },
+    { PIX_FMT_BGR32_1, MKTAG('r','a','w',' ') },
 };

-static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
-{
-    int tag = track->enc->codec_tag;
-    int i;
-
-    for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
-        if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) {
-            tag = mov_pix_fmt_tags[i].tag;
-            track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
-            break;
-        }
-    }
-
-    return tag;
-}
-
-static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
-{
-    int tag = track->enc->codec_tag;
-
-    if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
-                 (tag == MKTAG('d','v','c','p') ||
-                  track->enc->codec_id == CODEC_ID_RAWVIDEO ||
-                  av_get_bits_per_sample(track->enc->codec_id)))) {
// pcm audio
-        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
-            tag = mov_get_dv_codec_tag(s, track);
-        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
-            tag = mov_get_rawvideo_codec_tag(s, track);
-        else if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
-            tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
-            if (!tag) { // if no mac fcc found, try with Microsoft tags
-                tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
-                if (tag)
-                    av_log(s, AV_LOG_INFO, "Warning, using MS style
video codec tag, "
-                           "the file may be unplayable!\n");
-            }
-        } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
-            tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
-            if (!tag) { // if no mac fcc found, try with Microsoft tags
-                int ms_tag = codec_get_tag(codec_wav_tags,
track->enc->codec_id);
-                if (ms_tag) {
-                    tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff),
(ms_tag & 0xff));
-                    av_log(s, AV_LOG_INFO, "Warning, using MS style
audio codec tag, "
-                           "the file may be unplayable!\n");
-                }
-            }
-        } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
-            tag = codec_get_tag(ff_codec_movsubtitle_tags,
track->enc->codec_id);
-    }
-
-    return tag;
-}
-
-static const AVCodecTag codec_3gp_tags[] = {
-    { CODEC_ID_H263,   MKTAG('s','2','6','3') },
+static const AVCodecTag codec_ipod_tags[] = {
     { CODEC_ID_H264,   MKTAG('a','v','c','1') },
     { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
     { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
-    { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
-    { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
+    { CODEC_ID_ALAC,   MKTAG('a','l','a','c') },
+    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
     { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
+    { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
     { CODEC_ID_NONE, 0 },
 };

 static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
 {
     int tag = track->enc->codec_tag;
-
-    if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
-        tag = mp4_get_codec_tag(s, track);
-    else if (track->mode == MODE_IPOD)
-        tag = ipod_get_codec_tag(s, track);
-    else if (track->mode & MODE_3GP)
+    if (track->mode == MODE_MP4 || track->mode == MODE_PSP) {
+        if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
+            return 0;
+        if      (track->enc->codec_id == CODEC_ID_H264)      tag =
MKTAG('a','v','c','1');
+        else if (track->enc->codec_id == CODEC_ID_AC3)       tag =
MKTAG('a','c','-','3');
+        else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag =
MKTAG('d','r','a','c');
+        else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag =
MKTAG('t','x','3','g');
+        else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag =
MKTAG('m','p','4','v');
+        else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag =
MKTAG('m','p','4','a');
+    } else if (track->mode == MODE_IPOD) {
+        if (track->enc->codec_type == CODEC_TYPE_SUBTITLE &&
+            (tag == MKTAG('t','x','3','g') ||
+             tag == MKTAG('t','e','x','t')))
+            track->tag = tag; // keep original tag
+        else
+            tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id);
+        if (!match_ext(s->filename, "m4a") && !match_ext(s->filename, "m4v"))
+            av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a
nor .m4v "
+                   "Quicktime/Ipod might not play the file\n");
+    } else if (track->mode & MODE_3GP) {
         tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
-    else
-        tag = mov_get_codec_tag(s, track);
-
+    } else if (!tag || (track->enc->strict_std_compliance >=
FF_COMPLIANCE_NORMAL &&
+                        (tag == MKTAG('d','v','c','p') ||
+                         track->enc->codec_id == CODEC_ID_RAWVIDEO))) {
+        if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
+            if (track->enc->height == 480) /* NTSC */
+                if  (track->enc->pix_fmt == PIX_FMT_YUV422P) tag =
MKTAG('d','v','5','n');
+                else                                         tag =
MKTAG('d','v','c',' ');
+            else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag =
MKTAG('d','v','5','p');
+            else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag =
MKTAG('d','v','c','p');
+            else                                             tag =
MKTAG('d','v','p','p');
+        } else if (track->enc->codec_id == CODEC_ID_RAWVIDEO) {
+            tag = codec_get_tag(mov_pix_fmt_tags, track->enc->pix_fmt);
+            if (!tag) // restore tag
+                tag = track->enc->codec_tag;
+        } else {
+            if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
+                tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
+                if (!tag) { // if no mac fcc found, try with Microsoft tags
+                    tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
+                    if (tag)
+                        av_log(s, AV_LOG_INFO, "Warning, using MS
style video codec tag, "
+                               "the file may be unplayable!\n");
+                }
+            } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
+                tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
+                if (!tag) { // if no mac fcc found, try with Microsoft tags
+                    int ms_tag = codec_get_tag(codec_wav_tags,
track->enc->codec_id);
+                    if (ms_tag) {
+                        tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff),
(ms_tag & 0xff));
+                        av_log(s, AV_LOG_INFO, "Warning, using MS
style audio codec tag, "
+                               "the file may be unplayable!\n");
+                    }
+                }
+            } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) {
+                tag = codec_get_tag(ff_codec_movsubtitle_tags,
track->enc->codec_id);
+            }
+        }
+    }
     return tag;
 }

@@ -1561,6 +1504,15 @@
     return updateSize(pb, pos);
 }

+static int mov_write_mdat_tag_size(ByteIOContext *pb, MOVMuxContext
*mov, int size) {
+    put_be32(pb, 8);    // placeholder for extended size field (64 bit)
+    put_tag(pb, mov->mode == MODE_MOV ? "wide" : "free");
+
+    put_be32(pb, size+8); // size
+    put_tag(pb, "mdat");
+    return 16;
+}
+
 static int mov_write_mdat_tag(ByteIOContext *pb, MOVMuxContext *mov)
 {
     put_be32(pb, 8);    // placeholder for extended size field (64 bit)
@@ -1695,12 +1647,9 @@
     ByteIOContext *pb = s->pb;
     MOVMuxContext *mov = s->priv_data;
     int i;
+	
+	int64_t pos = url_ftell(pb);

-    if (url_is_streamed(s->pb)) {
-        av_log(s, AV_LOG_ERROR, "muxer does not support non seekable
output\n");
-        return -1;
-    }
-
     /* Default mode == MP4 */
     mov->mode = MODE_MP4;

@@ -1784,7 +1733,13 @@
             track->height = st->codec->height;
     }

-    mov_write_mdat_tag(pb, mov);
+    if (!url_is_streamed(s->pb)) {
+		mov_write_mdat_tag(pb, mov);
+	} else {
+		int movHeaderSize = updateSize(pb, pos);
+		mov->mdat_pos = movHeaderSize;
+	}
+
     mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based
     mov->nb_streams = s->nb_streams;

@@ -1796,6 +1751,23 @@
     return -1;
 }

+int ff_avc_parse_nal_units_size(ByteIOContext *pb, const uint8_t
*buf_in, int size)
+{
+    const uint8_t *p = buf_in;
+    const uint8_t *end = p + size;
+    const uint8_t *nal_start, *nal_end;
+
+    size = 0;
+    nal_start = ff_avc_find_startcode(p, end);
+    while (nal_start < end) {
+        while(!*(nal_start++));
+        nal_end = ff_avc_find_startcode(nal_start, end);
+        size += 4 + nal_end - nal_start;
+        nal_start = nal_end;
+	}
+	return size;
+}
+
 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MOVMuxContext *mov = s->priv_data;
@@ -1804,8 +1776,8 @@
     AVCodecContext *enc = trk->enc;
     unsigned int samplesInChunk = 0;
     int size= pkt->size;
+	int mdatHeaderSize = 0;

-    if (url_is_streamed(s->pb)) return 0; /* Can't handle that */
     if (!size) return 0; /* Discard 0 sized packets */

     if (enc->codec_id == CODEC_ID_AMR_NB) {
@@ -1837,8 +1809,15 @@
     if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 &&
*(uint8_t *)trk->vosData != 1) {
         /* from x264 or from bytestream h264 */
         /* nal reformating needed */
+		if (url_is_streamed(s->pb)) {
+			size = ff_avc_parse_nal_units_size(pb, pkt->data, pkt->size);
+			mdatHeaderSize = mov_write_mdat_tag_size(pb, mov, size);
+		}
         size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
     } else {
+		if (url_is_streamed(s->pb)) {
+			mdatHeaderSize = mov_write_mdat_tag_size(pb, mov, size);
+		}
         put_buffer(pb, pkt->data, size);
     }

@@ -1857,8 +1836,12 @@
         if (!trk->cluster)
             return -1;
     }
-
-    trk->cluster[trk->entry].pos = url_ftell(pb) - size;
+	
+	if (url_is_streamed(s->pb)) {
+		trk->cluster[trk->entry].pos = mov->mdat_pos + mdatHeaderSize;
+	} else {
+		trk->cluster[trk->entry].pos = url_ftell(pb) - size;
+	}
     trk->cluster[trk->entry].samplesInChunk = samplesInChunk;
     trk->cluster[trk->entry].size = size;
     trk->cluster[trk->entry].entries = samplesInChunk;
@@ -1877,7 +1860,11 @@
         trk->hasKeyframes++;
     trk->entry++;
     trk->sampleCount += samplesInChunk;
-    mov->mdat_size += size;
+	if (url_is_streamed(s->pb)) {
+		mov->mdat_pos += mdatHeaderSize+size;
+	} else {
+		mov->mdat_size += size;
+	}

     put_flush_packet(pb);
     return 0;
@@ -1890,20 +1877,22 @@
     int res = 0;
     int i;

-    int64_t moov_pos = url_ftell(pb);
+	if (!url_is_streamed(s->pb)) {
+		int64_t moov_pos = url_ftell(pb);

-    /* Write size of mdat tag */
-    if (mov->mdat_size+8 <= UINT32_MAX) {
-        url_fseek(pb, mov->mdat_pos, SEEK_SET);
-        put_be32(pb, mov->mdat_size+8);
-    } else {
-        /* overwrite 'wide' placeholder atom */
-        url_fseek(pb, mov->mdat_pos - 8, SEEK_SET);
-        put_be32(pb, 1); /* special value: real atom size will be 64
bit value after tag field */
-        put_tag(pb, "mdat");
-        put_be64(pb, mov->mdat_size+16);
-    }
-    url_fseek(pb, moov_pos, SEEK_SET);
+		/* Write size of mdat tag */
+		if (mov->mdat_size+8 <= UINT32_MAX) {
+			url_fseek(pb, mov->mdat_pos, SEEK_SET);
+			put_be32(pb, mov->mdat_size+8);
+		} else {
+			/* overwrite 'wide' placeholder atom */
+			url_fseek(pb, mov->mdat_pos - 8, SEEK_SET);
+			put_be32(pb, 1); /* special value: real atom size will be 64 bit
value after tag field */
+			put_tag(pb, "mdat");
+			put_be64(pb, mov->mdat_size+16);
+		}
+		url_fseek(pb, moov_pos, SEEK_SET);
+	}

     mov_write_moov_tag(pb, mov, s);




> We want a patch, not the new file.
>
> Diego
>
>



More information about the ffmpeg-devel mailing list