diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-01-28 04:23:26 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-01-28 07:53:34 +0100 |
commit | e37f161e66e042d6c2c7470c4d9881df9427fc4a (patch) | |
tree | 6400fd6453f0525a65724937532d5baa33deead3 /libavformat/movenc.c | |
parent | f21b6159cf3110a5f018d6addf7382840d427199 (diff) | |
parent | e771e6dd63e837220aa5d959486546d2be972e83 (diff) | |
download | ffmpeg-e37f161e66e042d6c2c7470c4d9881df9427fc4a.tar.gz |
Merge remote-tracking branch 'qatar/master'
* qatar/master: (71 commits)
movenc: Allow writing to a non-seekable output if using empty moov
movenc: Support adding isml (smooth streaming live) metadata
libavcodec: Don't crash in avcodec_encode_audio if time_base isn't set
sunrast: Document the different Sun Raster file format types.
sunrast: Add a check for experimental type.
libspeexenc: use AVSampleFormat instead of deprecated/removed SampleFormat
lavf: remove disabled FF_API_SET_PTS_INFO cruft
lavf: remove disabled FF_API_OLD_INTERRUPT_CB cruft
lavf: remove disabled FF_API_REORDER_PRIVATE cruft
lavf: remove disabled FF_API_SEEK_PUBLIC cruft
lavf: remove disabled FF_API_STREAM_COPY cruft
lavf: remove disabled FF_API_PRELOAD cruft
lavf: remove disabled FF_API_NEW_STREAM cruft
lavf: remove disabled FF_API_RTSP_URL_OPTIONS cruft
lavf: remove disabled FF_API_MUXRATE cruft
lavf: remove disabled FF_API_FILESIZE cruft
lavf: remove disabled FF_API_TIMESTAMP cruft
lavf: remove disabled FF_API_LOOP_OUTPUT cruft
lavf: remove disabled FF_API_LOOP_INPUT cruft
lavf: remove disabled FF_API_AVSTREAM_QUALITY cruft
...
Conflicts:
doc/APIchanges
libavcodec/8bps.c
libavcodec/avcodec.h
libavcodec/libx264.c
libavcodec/mjpegbdec.c
libavcodec/options.c
libavcodec/sunrast.c
libavcodec/utils.c
libavcodec/version.h
libavcodec/x86/h264_deblock.asm
libavdevice/libdc1394.c
libavdevice/v4l2.c
libavformat/avformat.h
libavformat/avio.c
libavformat/avio.h
libavformat/aviobuf.c
libavformat/dv.c
libavformat/mov.c
libavformat/utils.c
libavformat/version.h
libavformat/wtv.c
libavutil/Makefile
libavutil/file.c
libswscale/x86/input.asm
libswscale/x86/swscale_mmx.c
libswscale/x86/swscale_template.c
tests/ref/lavf/ffm
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/movenc.c')
-rw-r--r-- | libavformat/movenc.c | 158 |
1 files changed, 143 insertions, 15 deletions
diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 6ed1005d33..4574df3de9 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -50,6 +50,7 @@ static const AVOption options[] = { { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.dbl = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, @@ -1975,6 +1976,128 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, return updateSize(pb, pos); } +static void param_write_int(AVIOContext *pb, const char *name, int value) +{ + avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value); +} + +static void param_write_string(AVIOContext *pb, const char *name, const char *value) +{ + avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value); +} + +static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len) +{ + char buf[150]; + len = FFMIN(sizeof(buf)/2 - 1, len); + ff_data_to_hex(buf, value, len, 0); + buf[2*len] = '\0'; + avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf); +} + +static void write_h264_extradata(AVIOContext *pb, AVCodecContext *enc) +{ + uint16_t sps_size, pps_size, len; + char buf[150]; + sps_size = AV_RB16(&enc->extradata[6]); + if (11 + sps_size > enc->extradata_size) + return; + pps_size = AV_RB16(&enc->extradata[9 + sps_size]); + if (11 + sps_size + pps_size > enc->extradata_size) + return; + len = FFMIN(sizeof(buf)/2 - 1, sps_size); + ff_data_to_hex(buf, &enc->extradata[8], len, 0); + buf[2*len] = '\0'; + avio_printf(pb, "<param name=\"CodecPrivateData\" value=\"00000001%s", buf); + len = FFMIN(sizeof(buf)/2 - 1, pps_size); + ff_data_to_hex(buf, &enc->extradata[11 + sps_size], len, 0); + buf[2*len] = '\0'; + avio_printf(pb, "00000001%s\" valuetype=\"data\"/>\n", buf); +} + +static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov) +{ + int64_t pos = avio_tell(pb); + int i; + const uint8_t uuid[] = { + 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd, + 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 + }; + + avio_wb32(pb, 0); + ffio_wfourcc(pb, "uuid"); + avio_write(pb, uuid, sizeof(uuid)); + avio_wb32(pb, 0); + + avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); + avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n"); + avio_printf(pb, "<head>\n"); + avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n", + LIBAVFORMAT_IDENT); + avio_printf(pb, "</head>\n"); + avio_printf(pb, "<body>\n"); + avio_printf(pb, "<switch>\n"); + for (i = 0; i < mov->nb_streams; i++) { + MOVTrack *track = &mov->tracks[i]; + const char *type; + /* track->trackID is initialized in write_moov, and thus isn't known + * here yet */ + int track_id = i + 1; + + if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) { + type = "video"; + } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) { + type = "audio"; + } else { + continue; + } + avio_printf(pb, "<%s systemBitrate=\"%d\">\n", type, + track->enc->bit_rate); + param_write_int(pb, "systemBitrate", track->enc->bit_rate); + param_write_int(pb, "trackID", track_id); + if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) { + if (track->enc->codec_id == CODEC_ID_H264 && + track->enc->extradata_size >= 11 && + track->enc->extradata[0] == 1) { + write_h264_extradata(pb, track->enc); + } else { + param_write_hex(pb, "CodecPrivateData", track->enc->extradata, + track->enc->extradata_size); + } + if (track->enc->codec_id == CODEC_ID_H264) { + param_write_string(pb, "FourCC", "H264"); + } else if (track->enc->codec_id == CODEC_ID_VC1) { + param_write_string(pb, "FourCC", "WVC1"); + } + param_write_int(pb, "MaxWidth", track->enc->width); + param_write_int(pb, "MaxHeight", track->enc->height); + param_write_int(pb, "DisplayWidth", track->enc->width); + param_write_int(pb, "DisplayHeight", track->enc->height); + } else { + if (track->enc->codec_id == CODEC_ID_AAC) { + param_write_string(pb, "FourCC", "AACL"); + } else if (track->enc->codec_id == CODEC_ID_WMAPRO) { + param_write_string(pb, "FourCC", "WMAP"); + } + param_write_hex(pb, "CodecPrivateData", track->enc->extradata, + track->enc->extradata_size); + param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags, + track->enc->codec_id)); + param_write_int(pb, "Channels", track->enc->channels); + param_write_int(pb, "SamplingRate", track->enc->sample_rate); + param_write_int(pb, "BitsPerSample", 16); + param_write_int(pb, "PacketSize", track->enc->block_align ? + track->enc->block_align : 4); + } + avio_printf(pb, "</%s>\n", type); + } + avio_printf(pb, "</switch>\n"); + avio_printf(pb, "</body>\n"); + avio_printf(pb, "</smil>\n"); + + return updateSize(pb, pos); +} + static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov) { avio_wb32(pb, 16); @@ -2245,6 +2368,10 @@ static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov) avio_wb32(pb, 0); /* size placeholder */ ffio_wfourcc(pb, "mfra"); + /* An empty mfra atom is enough to indicate to the publishing point that + * the stream has ended. */ + if (mov->flags & FF_MOV_FLAG_ISML) + return updateSize(pb, pos); for (i = 0; i < mov->nb_streams; i++) { MOVTrack *track = &mov->tracks[i]; @@ -2446,6 +2573,7 @@ static int mov_flush_fragment(AVFormatContext *s) mov->tracks[i].cluster[0].dts; mov->tracks[i].entry = 0; } + avio_flush(s->pb); return 0; } @@ -2485,6 +2613,7 @@ static int mov_flush_fragment(AVFormatContext *s) if (write_moof) { MOVFragmentInfo *info; + avio_flush(s->pb); track->nb_frag_info++; track->frag_info = av_realloc(track->frag_info, sizeof(*track->frag_info) * @@ -2517,6 +2646,7 @@ static int mov_flush_fragment(AVFormatContext *s) mov->mdat_size = 0; + avio_flush(s->pb); return 0; } @@ -2530,7 +2660,9 @@ static int mov_write_packet_internal(AVFormatContext *s, AVPacket *pkt) int size= pkt->size; uint8_t *reformatted_data = NULL; - if (!s->pb->seekable) return 0; /* Can't handle that */ + if (!s->pb->seekable && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) + return 0; /* Can't handle that */ + if (!size) return 0; /* Discard 0 sized packets */ if ((mov->max_fragment_duration && trk->entry && @@ -2718,7 +2850,13 @@ static int mov_write_header(AVFormatContext *s) AVDictionaryEntry *t; int i, hint_track = 0; - if (!s->pb->seekable) { + /* Non-seekable output is ok if EMPTY_MOOV is set, or if using the ismv + * format (which sets EMPTY_MOOV later in this function). If ism_lookahead + * is enabled, we don't support non-seekable output at all. */ + if (!s->pb->seekable && + ((!(mov->flags & FF_MOV_FLAG_EMPTY_MOOV) && + !(s->oformat && !strcmp(s->oformat->name, "ismv"))) + || mov->ism_lookahead)) { av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); return -1; } @@ -2748,14 +2886,6 @@ 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; @@ -2883,11 +3013,6 @@ static int mov_write_header(AVFormatContext *s) if (!(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) mov_write_mdat_tag(pb, mov); -#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); if (mov->time) @@ -2910,6 +3035,9 @@ static int mov_write_header(AVFormatContext *s) avio_flush(pb); + if (mov->flags & FF_MOV_FLAG_ISML) + mov_write_isml_manifest(pb, mov); + if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) { mov_write_moov_tag(pb, mov, s); mov->fragments++; |