changeset 4941:45a08facad6f libavformat

write 'stps' for mpeg-2 open gop in .mov
author bcoudurier
date Fri, 15 May 2009 06:11:53 +0000
parents 9bc9feb36557
children 02e9151a011e
files movenc.c
diffstat 1 files changed, 44 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/movenc.c	Fri May 15 05:33:05 2009 +0000
+++ b/movenc.c	Fri May 15 06:11:53 2009 +0000
@@ -51,6 +51,7 @@
     int          cts;
     int64_t      dts;
 #define MOV_SYNC_SAMPLE         0x0001
+#define MOV_PARTIAL_SYNC_SAMPLE 0x0002
     uint32_t     flags;
 } MOVIentry;
 
@@ -63,7 +64,9 @@
     long        sampleCount;
     long        sampleSize;
     int         hasKeyframes;
-    int         hasBframes;
+#define MOV_TRACK_CTTS         0x0001
+#define MOV_TRACK_STPS         0x0002
+    uint32_t    flags;
     int         language;
     int         trackID;
     int         tag; ///< stsd fourcc
@@ -188,18 +191,18 @@
 }
 
 /* Sync sample atom */
-static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack *track)
+static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack *track, uint32_t flag)
 {
     int64_t curpos, entryPos;
     int i, index = 0;
     int64_t pos = url_ftell(pb);
     put_be32(pb, 0); // size
-    put_tag(pb, "stss");
+    put_tag(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
     put_be32(pb, 0); // version & flags
     entryPos = url_ftell(pb);
     put_be32(pb, track->entry); // entry count
     for (i=0; i<track->entry; i++) {
-        if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
+        if (track->cluster[i].flags & flag) {
             put_be32(pb, i+1);
             index++;
         }
@@ -914,9 +917,11 @@
     mov_write_stts_tag(pb, track);
     if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
         track->hasKeyframes && track->hasKeyframes < track->entry)
-        mov_write_stss_tag(pb, track);
+        mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
+    if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
+        mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
     if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
-        track->hasBframes)
+        track->flags & MOV_TRACK_CTTS)
         mov_write_ctts_tag(pb, track);
     mov_write_stsc_tag(pb, track);
     mov_write_stsz_tag(pb, track);
@@ -1173,7 +1178,7 @@
     put_be32(pb, 0); /* size */
     put_tag(pb, "trak");
     mov_write_tkhd_tag(pb, track, st);
-    if (track->mode == MODE_PSP || track->hasBframes)
+    if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS)
         mov_write_edts_tag(pb, track);  // PSP Movies require edts box
     mov_write_mdia_tag(pb, track);
     if (track->mode == MODE_PSP)
@@ -1802,6 +1807,27 @@
     return -1;
 }
 
+static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
+{
+    uint32_t c = -1;
+    int i, closed_gop = 0;
+
+    for (i = 0; i < pkt->size - 4; i++) {
+        c = (c<<8) + pkt->data[i];
+        if (c == 0x1b8) { // gop
+            closed_gop = pkt->data[i+4]>>6 & 0x01;
+        } else if (c == 0x100) { // pic
+            int temp_ref = (pkt->data[i+1]<<2) | (pkt->data[i+2]>>6);
+            if (!temp_ref || closed_gop) // I picture is not reordered
+                *flags = MOV_SYNC_SAMPLE;
+            else
+                *flags = MOV_PARTIAL_SYNC_SAMPLE;
+            break;
+        }
+    }
+    return 0;
+}
+
 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MOVMuxContext *mov = s->priv_data;
@@ -1876,11 +1902,19 @@
         pkt->pts = pkt->dts;
     }
     if (pkt->dts != pkt->pts)
-        trk->hasBframes = 1;
+        trk->flags |= MOV_TRACK_CTTS;
     trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
+    trk->cluster[trk->entry].flags = 0;
     if (pkt->flags & PKT_FLAG_KEY) {
-        trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
-        trk->hasKeyframes++;
+        if (mov->mode == MODE_MOV && enc->codec_id == CODEC_ID_MPEG2VIDEO) {
+            mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
+            if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
+                trk->flags |= MOV_TRACK_STPS;
+        } else {
+            trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
+        }
+        if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
+            trk->hasKeyframes++;
     }
     trk->entry++;
     trk->sampleCount += samplesInChunk;