diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 624189a04a..3abe388588 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -51,6 +51,7 @@ typedef struct MOVIentry { int cts; int64_t dts; #define MOV_SYNC_SAMPLE 0x0001 +#define MOV_PARTIAL_SYNC_SAMPLE 0x0002 uint32_t flags; } MOVIentry; @@ -63,7 +64,9 @@ typedef struct MOVIndex { 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 @@ static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack *track) } /* 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; ientry; 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 @@ static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack *track) 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 @@ static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack *track, AVStream *st) 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 @@ static int mov_write_header(AVFormatContext *s) 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 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) 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;