X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmovenc.c;h=185d89f43ad50d571ae94f29bde80fb89f6fc622;hb=be9c00615b5c2cb858b9905854726ebe578c007b;hp=711aa68e9871f08e72cb1b0028b011e779ecc7a3;hpb=0abdb2931719d96dee725e555e9b46b2b2f8a6be;p=ffmpeg diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 711aa68e987..185d89f43ad 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -4,20 +4,20 @@ * Copyright (c) 2004 Gildas Bazin * Copyright (c) 2009 Baptiste Coudurier * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -32,17 +32,36 @@ #include "libavcodec/put_bits.h" #include "internal.h" #include "libavutil/avstring.h" +#include "libavutil/intfloat_readwrite.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" +#include "libavutil/dict.h" +#include "rtpenc.h" #undef NDEBUG #include +static const AVOption options[] = { + { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), FF_OPT_TYPE_FLAGS, {.dbl = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "rtphint", "Add RTP hint tracks", 0, FF_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), + { NULL }, +}; + +static const AVClass mov_muxer_class = { + .class_name = "MOV/3GP/MP4/3G2 muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + //FIXME support 64 bit variant with wide placeholders static int64_t updateSize(AVIOContext *pb, int64_t pos) { - int64_t curpos = url_ftell(pb); - url_fseek(pb, pos, SEEK_SET); + int64_t curpos = avio_tell(pb); + avio_seek(pb, pos, SEEK_SET); avio_wb32(pb, curpos - pos); /* rewrite size */ - url_fseek(pb, curpos, SEEK_SET); + avio_seek(pb, curpos, SEEK_SET); return curpos - pos; } @@ -52,7 +71,7 @@ static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) { int i; int mode64 = 0; // use 32 bit size variant if possible - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ if (pos > UINT32_MAX) { mode64 = 1; @@ -76,7 +95,7 @@ static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track) int equalChunks = 1; int i, j, entries = 0, tst = -1, oldtst = -1; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "stsz"); avio_wb32(pb, 0); /* version & flags */ @@ -91,6 +110,7 @@ static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track) } if (equalChunks) { int sSize = track->cluster[0].size/track->cluster[0].entries; + sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0 avio_wb32(pb, sSize); // sample size avio_wb32(pb, entries); // sample count } @@ -113,11 +133,11 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) int index = 0, oldval = -1, i; int64_t entryPos, curpos; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "stsc"); avio_wb32(pb, 0); // version & flags - entryPos = url_ftell(pb); + entryPos = avio_tell(pb); avio_wb32(pb, track->entry); // entry count for (i=0; ientry; i++) { if(oldval != track->cluster[i].samplesInChunk) @@ -129,10 +149,10 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) index++; } } - curpos = url_ftell(pb); - url_fseek(pb, entryPos, SEEK_SET); + curpos = avio_tell(pb); + avio_seek(pb, entryPos, SEEK_SET); avio_wb32(pb, index); // rewrite size - url_fseek(pb, curpos, SEEK_SET); + avio_seek(pb, curpos, SEEK_SET); return updateSize(pb, pos); } @@ -142,11 +162,11 @@ static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag) { int64_t curpos, entryPos; int i, index = 0; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); // size ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps"); avio_wb32(pb, 0); // version & flags - entryPos = url_ftell(pb); + entryPos = avio_tell(pb); avio_wb32(pb, track->entry); // entry count for (i=0; ientry; i++) { if (track->cluster[i].flags & flag) { @@ -154,10 +174,10 @@ static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag) index++; } } - curpos = url_ftell(pb); - url_fseek(pb, entryPos, SEEK_SET); + curpos = avio_tell(pb); + avio_seek(pb, entryPos, SEEK_SET); avio_wb32(pb, index); // rewrite size - url_fseek(pb, curpos, SEEK_SET); + avio_seek(pb, curpos, SEEK_SET); return updateSize(pb, pos); } @@ -237,16 +257,9 @@ static int mov_write_enda_tag(AVIOContext *pb) return 10; } -static unsigned int descrLength(unsigned int len) -{ - int i; - for(i=1; len>>(7*i); i++); - return len + 1 + i; -} - static void putDescr(AVIOContext *pb, int tag, unsigned int size) { - int i= descrLength(size) - size - 2; + int i = 3; avio_w8(pb, tag); for(; i>0; i--) avio_w8(pb, (size>>(7*i)) | 0x80); @@ -255,16 +268,15 @@ static void putDescr(AVIOContext *pb, int tag, unsigned int size) static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic { - int64_t pos = url_ftell(pb); - int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0; + int64_t pos = avio_tell(pb); + int decoderSpecificInfoLen = track->vosLen ? 5+track->vosLen : 0; avio_wb32(pb, 0); // size ffio_wfourcc(pb, "esds"); avio_wb32(pb, 0); // Version // ES descriptor - putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) + - descrLength(1)); + putDescr(pb, 0x03, 3 + 5+13 + decoderSpecificInfoLen + 5+1); avio_wb16(pb, track->trackID); avio_w8(pb, 0x00); // flags (= no flags) @@ -317,7 +329,7 @@ static int mov_pcm_le_gt16(enum CodecID codec_id) static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); avio_wl32(pb, track->tag); // store it byteswapped track->enc->codec_tag = av_bswap16(track->tag >> 16); @@ -327,7 +339,7 @@ static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "wave"); @@ -400,7 +412,7 @@ static int mov_get_lpcm_flags(enum CodecID codec_id) static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); int version = 0; uint32_t tag = track->tag; @@ -518,7 +530,7 @@ static int mov_write_svq3_tag(AVIOContext *pb) static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); ffio_wfourcc(pb, "avcC"); @@ -534,7 +546,7 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "ACLR"); ffio_wfourcc(pb, "ACLR"); ffio_wfourcc(pb, "0001"); - avio_wb32(pb, 1); /* yuv 1 / rgb 2 ? */ + avio_wb32(pb, 2); /* yuv range: full 1 / normal 2 */ avio_wb32(pb, 0); /* unknown */ avio_wb32(pb, 24); /* size */ @@ -623,12 +635,23 @@ 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'); + if (track->enc->width == 720) /* SD */ + 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->height == 720) /* HD 720 line */ + if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q'); + else tag = MKTAG('d','v','h','p'); + else if (track->enc->height == 1080) /* HD 1080 line */ + if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5'); + else tag = MKTAG('d','v','h','6'); + else { + av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n"); + return 0; + } return tag; } @@ -753,7 +776,7 @@ static int mov_write_uuid_tag_ipod(AVIOContext *pb) static int mov_write_subtitle_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ avio_wl32(pb, track->tag); // store it byteswapped avio_wb32(pb, 0); /* Reserved */ @@ -781,7 +804,7 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); char compressor_name[32]; avio_wb32(pb, 0); /* size */ @@ -816,7 +839,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) memset(compressor_name,0,32); /* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */ if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name) - strncpy(compressor_name,track->enc->codec->name,31); + av_strlcpy(compressor_name,track->enc->codec->name,32); avio_w8(pb, strlen(compressor_name)); avio_write(pb, compressor_name, 31); @@ -840,8 +863,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) } else if(track->vosLen > 0) mov_write_glbl_tag(pb, track); - if (track->mode == MODE_MOV && - track->enc->sample_aspect_ratio.den && track->enc->sample_aspect_ratio.num && + if (track->enc->sample_aspect_ratio.den && track->enc->sample_aspect_ratio.num && track->enc->sample_aspect_ratio.den != track->enc->sample_aspect_ratio.num) { mov_write_pasp_tag(pb, track); } @@ -851,7 +873,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "rtp "); avio_wb32(pb, 0); /* Reserved */ @@ -871,7 +893,7 @@ static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "stsd"); avio_wb32(pb, 0); /* version & flags */ @@ -978,7 +1000,7 @@ static int mov_write_dref_tag(AVIOContext *pb) static int mov_write_stbl_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "stbl"); mov_write_stsd_tag(pb, track); @@ -1000,7 +1022,7 @@ static int mov_write_stbl_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_dinf_tag(AVIOContext *pb) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "dinf"); mov_write_dref_tag(pb); @@ -1053,7 +1075,7 @@ static int mov_write_vmhd_tag(AVIOContext *pb) static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) { const char *hdlr, *descr = NULL, *hdlr_type = NULL; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); if (!track) { /* no media --> data handler */ hdlr = "dhlr"; @@ -1110,7 +1132,7 @@ static int mov_write_hmhd_tag(AVIOContext *pb) static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "minf"); if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO) @@ -1162,7 +1184,7 @@ static int mov_write_mdhd_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_mdia_tag(AVIOContext *pb, MOVTrack *track) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "mdia"); mov_write_mdhd_tag(pb, track); @@ -1216,11 +1238,16 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) /* Track width and height, for visual only */ if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO || track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) { - double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); - if(!sample_aspect_ratio || track->height != track->enc->height) - sample_aspect_ratio = 1; - avio_wb32(pb, sample_aspect_ratio * track->enc->width*0x10000); - avio_wb32(pb, track->height*0x10000); + if(track->mode == MODE_MOV) { + avio_wb32(pb, track->enc->width << 16); + avio_wb32(pb, track->height << 16); + } else { + double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); + if(!sample_aspect_ratio || track->height != track->enc->height) + sample_aspect_ratio = 1; + avio_wb32(pb, sample_aspect_ratio * track->enc->width*0x10000); + avio_wb32(pb, track->height*0x10000); + } } else { avio_wb32(pb, 0); @@ -1229,23 +1256,77 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) return 0x5c; } +static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track) +{ + int32_t width = av_rescale(track->enc->sample_aspect_ratio.num, track->enc->width, + track->enc->sample_aspect_ratio.den); + + int64_t pos = avio_tell(pb); + + avio_wb32(pb, 0); /* size */ + ffio_wfourcc(pb, "tapt"); + + avio_wb32(pb, 20); + ffio_wfourcc(pb, "clef"); + avio_wb32(pb, 0); + avio_wb32(pb, width << 16); + avio_wb32(pb, track->enc->height << 16); + + avio_wb32(pb, 20); + ffio_wfourcc(pb, "enof"); + avio_wb32(pb, 0); + avio_wb32(pb, track->enc->width << 16); + avio_wb32(pb, track->enc->height << 16); + + return updateSize(pb, pos); +}; + // This box seems important for the psp playback ... without it the movie seems to hang static int mov_write_edts_tag(AVIOContext *pb, MOVTrack *track) { - avio_wb32(pb, 0x24); /* size */ + int64_t duration = av_rescale_rnd(track->trackDuration, MOV_TIMESCALE, + track->timescale, AV_ROUND_UP); + int version = duration < INT32_MAX ? 0 : 1; + int entry_size, entry_count, size; + int64_t delay, start_ct = track->cluster[0].cts; + delay = av_rescale_rnd(track->cluster[0].dts + start_ct, MOV_TIMESCALE, + track->timescale, AV_ROUND_DOWN); + version |= delay < INT32_MAX ? 0 : 1; + + entry_size = (version == 1) ? 20 : 12; + entry_count = 1 + (delay > 0); + size = 24 + entry_count * entry_size; + + /* write the atom data */ + avio_wb32(pb, size); ffio_wfourcc(pb, "edts"); - avio_wb32(pb, 0x1c); /* size */ + avio_wb32(pb, size - 8); ffio_wfourcc(pb, "elst"); - avio_wb32(pb, 0x0); - avio_wb32(pb, 0x1); + avio_w8(pb, version); + avio_wb24(pb, 0); /* flags */ - /* duration ... doesn't seem to effect psp */ - avio_wb32(pb, av_rescale_rnd(track->trackDuration, MOV_TIMESCALE, - track->timescale, AV_ROUND_UP)); + avio_wb32(pb, entry_count); + if (delay > 0) { /* add an empty edit to delay presentation */ + if (version == 1) { + avio_wb64(pb, delay); + avio_wb64(pb, -1); + } else { + avio_wb32(pb, delay); + avio_wb32(pb, -1); + } + avio_wb32(pb, 0x00010000); + } - avio_wb32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */ + /* duration */ + if (version == 1) { + avio_wb64(pb, duration); + avio_wb64(pb, start_ct); + } else { + avio_wb32(pb, duration); + avio_wb32(pb, start_ct); + } avio_wb32(pb, 0x00010000); - return 0x24; + return size; } static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track) @@ -1277,12 +1358,12 @@ static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov) return 0x34; } -static int mov_write_udta_sdp(AVIOContext *pb, AVCodecContext *ctx, int index) +static int mov_write_udta_sdp(AVIOContext *pb, AVFormatContext *ctx, int index) { char buf[1000] = ""; int len; - ff_sdp_write_media(buf, sizeof(buf), ctx, NULL, NULL, 0, 0); + ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0]->codec, NULL, NULL, 0, 0, ctx); av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", index); len = strlen(buf); @@ -1298,11 +1379,11 @@ static int mov_write_udta_sdp(AVIOContext *pb, AVCodecContext *ctx, int index) static int mov_write_trak_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "trak"); mov_write_tkhd_tag(pb, track, st); - if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS) + if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS || track->cluster[0].dts) mov_write_edts_tag(pb, track); // PSP Movies require edts box if (track->tref_tag) mov_write_tref_tag(pb, track); @@ -1310,7 +1391,12 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) if (track->mode == MODE_PSP) mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box if (track->tag == MKTAG('r','t','p',' ')) - mov_write_udta_sdp(pb, track->rtp_ctx->streams[0]->codec, track->trackID); + mov_write_udta_sdp(pb, track->rtp_ctx, track->trackID); + if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && track->mode == MODE_MOV) { + double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); + if (0.0 != sample_aspect_ratio && 1.0 != sample_aspect_ratio) + mov_write_tapt_tag(pb, track); + }; return updateSize(pb, pos); } @@ -1430,7 +1516,7 @@ static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang static int mov_write_string_tag(AVIOContext *pb, const char *name, const char *value, int lang, int long_style){ int size = 0; if (value && value[0]) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, name); mov_write_string_data_tag(pb, value, lang, long_style); @@ -1444,15 +1530,15 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb, int long_style) { int l, lang = 0, len, len2; - AVMetadataTag *t, *t2 = NULL; + AVDictionaryEntry *t, *t2 = NULL; char tag2[16]; - if (!(t = av_metadata_get(s->metadata, tag, NULL, 0))) + if (!(t = av_dict_get(s->metadata, tag, NULL, 0))) return 0; len = strlen(t->key); snprintf(tag2, sizeof(tag2), "%s-", tag); - while ((t2 = av_metadata_get(s->metadata, tag2, t2, AV_METADATA_IGNORE_SUFFIX))) { + while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) { len2 = strlen(t2->key); if (len2 == len+4 && !strcmp(t->value, t2->value) && (l=ff_mov_iso639_to_lang(&t2->key[len2-3], 1)) >= 0) { @@ -1467,7 +1553,7 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb, static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { - AVMetadataTag *t = av_metadata_get(s->metadata, "track", NULL, 0); + AVDictionaryEntry *t = av_dict_get(s->metadata, "track", NULL, 0); int size = 0, track = t ? atoi(t->value) : 0; if (track) { avio_wb32(pb, 32); /* size */ @@ -1489,7 +1575,7 @@ static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov, static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "ilst"); mov_write_string_metadata(s, pb, "\251nam", "title" , 1); @@ -1518,7 +1604,7 @@ static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { int size = 0; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "meta"); avio_wb32(pb, 0); @@ -1558,8 +1644,8 @@ static uint16_t language_code(const char *str) static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, const char *tag, const char *str) { - int64_t pos = url_ftell(pb); - AVMetadataTag *t = av_metadata_get(s->metadata, str, NULL, 0); + int64_t pos = avio_tell(pb); + AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0); if (!t || !utf8len(t->value)) return 0; avio_wb32(pb, 0); /* size */ @@ -1571,7 +1657,7 @@ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, avio_wb16(pb, language_code("eng")); /* language */ avio_write(pb, t->value, strlen(t->value)+1); /* UTF8 string value */ if (!strcmp(tag, "albm") && - (t = av_metadata_get(s->metadata, "track", NULL, 0))) + (t = av_dict_get(s->metadata, "track", NULL, 0))) avio_w8(pb, atoi(t->value)); } return updateSize(pb, pos); @@ -1579,7 +1665,7 @@ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s) { - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); int i, nb_chapters = FFMIN(s->nb_chapters, 255); avio_wb32(pb, 0); // size @@ -1590,10 +1676,10 @@ static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s) for (i = 0; i < nb_chapters; i++) { AVChapter *c = s->chapters[i]; - AVMetadataTag *t; + AVDictionaryEntry *t; avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000})); - if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) { + if ((t = av_dict_get(c->metadata, "title", NULL, 0))) { int len = FFMIN(strlen(t->value), 255); avio_w8(pb, len); avio_write(pb, t->value, len); @@ -1615,7 +1701,7 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, return 0; } - ret = url_open_dyn_buf(&pb_buf); + ret = avio_open_dyn_buf(&pb_buf); if(ret < 0) return ret; @@ -1646,7 +1732,7 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, if (s->nb_chapters) mov_write_chpl_tag(pb_buf, s); - if ((size = url_close_dyn_buf(pb_buf, &buf)) > 0) { + if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) { avio_wb32(pb, size+8); ffio_wfourcc(pb, "udta"); avio_write(pb, buf, size); @@ -1671,11 +1757,11 @@ static void mov_write_psp_udta_tag(AVIOContext *pb, static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) { - AVMetadataTag *title = av_metadata_get(s->metadata, "title", NULL, 0); + AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0); int64_t pos, pos2; if (title) { - pos = url_ftell(pb); + pos = avio_tell(pb); avio_wb32(pb, 0); /* size placeholder*/ ffio_wfourcc(pb, "uuid"); ffio_wfourcc(pb, "USMT"); @@ -1683,7 +1769,7 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) avio_wb32(pb, 0xbb88695c); avio_wb32(pb, 0xfac9c740); - pos2 = url_ftell(pb); + pos2 = avio_tell(pb); avio_wb32(pb, 0); /* size placeholder*/ ffio_wfourcc(pb, "MTDT"); avio_wb16(pb, 4); @@ -1711,7 +1797,7 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { int i; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size placeholder*/ ffio_wfourcc(pb, "moov"); @@ -1756,7 +1842,7 @@ static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov) avio_wb32(pb, 8); // placeholder for extended size field (64 bit) ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free"); - mov->mdat_pos = url_ftell(pb); + mov->mdat_pos = avio_tell(pb); avio_wb32(pb, 0); /* size placeholder*/ ffio_wfourcc(pb, "mdat"); return 0; @@ -1766,7 +1852,7 @@ static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov) static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; - int64_t pos = url_ftell(pb); + int64_t pos = avio_tell(pb); int has_h264 = 0, has_video = 0; int minor = 0x200; int i; @@ -1910,7 +1996,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) unsigned int samplesInChunk = 0; int size= pkt->size; - if (url_is_streamed(s->pb)) return 0; /* Can't handle that */ + if (!s->pb->seekable) return 0; /* Can't handle that */ if (!size) return 0; /* Discard 0 sized packets */ if (enc->codec_id == CODEC_ID_AMR_NB) { @@ -1966,7 +2052,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) return -1; } - trk->cluster[trk->entry].pos = url_ftell(pb) - size; + trk->cluster[trk->entry].pos = avio_tell(pb) - size; trk->cluster[trk->entry].samplesInChunk = samplesInChunk; trk->cluster[trk->entry].size = size; trk->cluster[trk->entry].entries = samplesInChunk; @@ -1997,7 +2083,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) trk->sampleCount += samplesInChunk; mov->mdat_size += size; - put_flush_packet(pb); + avio_flush(pb); if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry); @@ -2016,18 +2102,18 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum) track->mode = mov->mode; track->tag = MKTAG('t','e','x','t'); track->timescale = MOV_TIMESCALE; - track->enc = avcodec_alloc_context(); + track->enc = avcodec_alloc_context3(NULL); track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE; for (i = 0; i < s->nb_chapters; i++) { AVChapter *c = s->chapters[i]; - AVMetadataTag *t; + AVDictionaryEntry *t; int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,MOV_TIMESCALE}); pkt.pts = pkt.dts = av_rescale_q(c->start, c->time_base, (AVRational){1,MOV_TIMESCALE}); pkt.duration = end - pkt.dts; - if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) { + if ((t = av_dict_get(c->metadata, "title", NULL, 0))) { len = strlen(t->value); pkt.size = len+2; pkt.data = av_malloc(pkt.size); @@ -2043,9 +2129,10 @@ static int mov_write_header(AVFormatContext *s) { AVIOContext *pb = s->pb; MOVMuxContext *mov = s->priv_data; + AVDictionaryEntry *t; int i, hint_track = 0; - if (url_is_streamed(s->pb)) { + if (!s->pb->seekable) { av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); return -1; } @@ -2074,7 +2161,15 @@ static int mov_write_header(AVFormatContext *s) if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters) mov->chapter_track = mov->nb_streams++; +#if FF_API_FLAG_RTP_HINT if (s->flags & AVFMT_FLAG_RTP_HINT) { + av_log(s, AV_LOG_WARNING, "The RTP_HINT flag is deprecated, enable it " + "via the -movflags rtphint muxer option " + "instead.\n"); + mov->flags |= FF_MOV_FLAG_RTP_HINT; + } +#endif + if (mov->flags & FF_MOV_FLAG_RTP_HINT) { /* Add hint tracks for each audio and video stream */ hint_track = mov->nb_streams; for (i = 0; i < s->nb_streams; i++) { @@ -2093,7 +2188,7 @@ static int mov_write_header(AVFormatContext *s) for(i=0; inb_streams; i++){ AVStream *st= s->streams[i]; MOVTrack *track= &mov->tracks[i]; - AVMetadataTag *lang = av_metadata_get(st->metadata, "language", NULL,0); + AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0); track->enc = st->codec; track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV); @@ -2165,12 +2260,20 @@ static int mov_write_header(AVFormatContext *s) } mov_write_mdat_tag(pb, mov); - mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based + +#if FF_API_TIMESTAMP + if (s->timestamp) + mov->time = s->timestamp; + else +#endif + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + mov->time = ff_iso8601_to_unix_time(t->value); + mov->time += 0x7C25B080; //1970 based -> 1904 based if (mov->chapter_track) mov_create_chapter_track(s, mov->chapter_track); - if (s->flags & AVFMT_FLAG_RTP_HINT) { + if (mov->flags & FF_MOV_FLAG_RTP_HINT) { /* Initialize the hint tracks for each audio and video stream */ for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; @@ -2182,7 +2285,7 @@ static int mov_write_header(AVFormatContext *s) } } - put_flush_packet(pb); + avio_flush(pb); return 0; error: @@ -2197,20 +2300,20 @@ static int mov_write_trailer(AVFormatContext *s) int res = 0; int i; - int64_t moov_pos = url_ftell(pb); + int64_t moov_pos = avio_tell(pb); /* Write size of mdat tag */ if (mov->mdat_size+8 <= UINT32_MAX) { - url_fseek(pb, mov->mdat_pos, SEEK_SET); + avio_seek(pb, mov->mdat_pos, SEEK_SET); avio_wb32(pb, mov->mdat_size+8); } else { /* overwrite 'wide' placeholder atom */ - url_fseek(pb, mov->mdat_pos - 8, SEEK_SET); + avio_seek(pb, mov->mdat_pos - 8, SEEK_SET); avio_wb32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */ ffio_wfourcc(pb, "mdat"); avio_wb64(pb, mov->mdat_size+16); } - url_fseek(pb, moov_pos, SEEK_SET); + avio_seek(pb, moov_pos, SEEK_SET); mov_write_moov_tag(pb, mov, s); @@ -2226,7 +2329,7 @@ static int mov_write_trailer(AVFormatContext *s) } - put_flush_packet(pb); + avio_flush(pb); av_freep(&mov->tracks); @@ -2235,97 +2338,99 @@ static int mov_write_trailer(AVFormatContext *s) #if CONFIG_MOV_MUXER AVOutputFormat ff_mov_muxer = { - "mov", - NULL_IF_CONFIG_SMALL("MOV format"), - NULL, - "mov", - sizeof(MOVMuxContext), - CODEC_ID_AAC, - CODEC_ID_MPEG4, - mov_write_header, - ff_mov_write_packet, - mov_write_trailer, + .name = "mov", + .long_name = NULL_IF_CONFIG_SMALL("MOV format"), + .extensions = "mov", + .priv_data_size = sizeof(MOVMuxContext), + .audio_codec = CODEC_ID_AAC, + .video_codec = CODEC_ID_MPEG4, + .write_header = mov_write_header, + .write_packet = ff_mov_write_packet, + .write_trailer = mov_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){codec_movvideo_tags, codec_movaudio_tags, 0}, + .priv_class = &mov_muxer_class, }; #endif #if CONFIG_TGP_MUXER AVOutputFormat ff_tgp_muxer = { - "3gp", - NULL_IF_CONFIG_SMALL("3GP format"), - NULL, - "3gp", - sizeof(MOVMuxContext), - CODEC_ID_AMR_NB, - CODEC_ID_H263, - mov_write_header, - ff_mov_write_packet, - mov_write_trailer, + .name = "3gp", + .long_name = NULL_IF_CONFIG_SMALL("3GP format"), + .extensions = "3gp", + .priv_data_size = sizeof(MOVMuxContext), + .audio_codec = CODEC_ID_AMR_NB, + .video_codec = CODEC_ID_H263, + .write_header = mov_write_header, + .write_packet = ff_mov_write_packet, + .write_trailer = mov_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0}, + .priv_class = &mov_muxer_class, }; #endif #if CONFIG_MP4_MUXER AVOutputFormat ff_mp4_muxer = { - "mp4", - NULL_IF_CONFIG_SMALL("MP4 format"), - "application/mp4", - "mp4", - sizeof(MOVMuxContext), - CODEC_ID_AAC, - CODEC_ID_MPEG4, - mov_write_header, - ff_mov_write_packet, - mov_write_trailer, + .name = "mp4", + .long_name = NULL_IF_CONFIG_SMALL("MP4 format"), + .mime_type = "application/mp4", + .extensions = "mp4", + .priv_data_size = sizeof(MOVMuxContext), + .audio_codec = CODEC_ID_AAC, + .video_codec = CODEC_ID_MPEG4, + .write_header = mov_write_header, + .write_packet = ff_mov_write_packet, + .write_trailer = mov_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0}, + .priv_class = &mov_muxer_class, }; #endif #if CONFIG_PSP_MUXER AVOutputFormat ff_psp_muxer = { - "psp", - NULL_IF_CONFIG_SMALL("PSP MP4 format"), - NULL, - "mp4,psp", - sizeof(MOVMuxContext), - CODEC_ID_AAC, - CODEC_ID_MPEG4, - mov_write_header, - ff_mov_write_packet, - mov_write_trailer, + .name = "psp", + .long_name = NULL_IF_CONFIG_SMALL("PSP MP4 format"), + .extensions = "mp4,psp", + .priv_data_size = sizeof(MOVMuxContext), + .audio_codec = CODEC_ID_AAC, + .video_codec = CODEC_ID_MPEG4, + .write_header = mov_write_header, + .write_packet = ff_mov_write_packet, + .write_trailer = mov_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0}, + .priv_class = &mov_muxer_class, }; #endif #if CONFIG_TG2_MUXER AVOutputFormat ff_tg2_muxer = { - "3g2", - NULL_IF_CONFIG_SMALL("3GP2 format"), - NULL, - "3g2", - sizeof(MOVMuxContext), - CODEC_ID_AMR_NB, - CODEC_ID_H263, - mov_write_header, - ff_mov_write_packet, - mov_write_trailer, + .name = "3g2", + .long_name = NULL_IF_CONFIG_SMALL("3GP2 format"), + .extensions = "3g2", + .priv_data_size = sizeof(MOVMuxContext), + .audio_codec = CODEC_ID_AMR_NB, + .video_codec = CODEC_ID_H263, + .write_header = mov_write_header, + .write_packet = ff_mov_write_packet, + .write_trailer = mov_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0}, + .priv_class = &mov_muxer_class, }; #endif #if CONFIG_IPOD_MUXER AVOutputFormat ff_ipod_muxer = { - "ipod", - NULL_IF_CONFIG_SMALL("iPod H.264 MP4 format"), - "application/mp4", - "m4v,m4a", - sizeof(MOVMuxContext), - CODEC_ID_AAC, - CODEC_ID_H264, - mov_write_header, - ff_mov_write_packet, - mov_write_trailer, + .name = "ipod", + .long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 format"), + .mime_type = "application/mp4", + .extensions = "m4v,m4a", + .priv_data_size = sizeof(MOVMuxContext), + .audio_codec = CODEC_ID_AAC, + .video_codec = CODEC_ID_H264, + .write_header = mov_write_header, + .write_packet = ff_mov_write_packet, + .write_trailer = mov_write_trailer, .flags = AVFMT_GLOBALHEADER, .codec_tag = (const AVCodecTag* const []){codec_ipod_tags, 0}, + .priv_class = &mov_muxer_class, }; #endif