X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmux.c;h=3d1f71ab1add237451e04942ad778a6ed9c70713;hb=f93bd302821e08df5ee037e67c4b85bec5d4d475;hp=2847a02a19c15fd7c5839916ea1dba856232f4e6;hpb=ace96d2e693d804a0ed16aebc1b1027cfff2c527;p=ffmpeg diff --git a/libavformat/mux.c b/libavformat/mux.c index 2847a02a19c..3d1f71ab1ad 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -20,29 +20,16 @@ */ #include "avformat.h" -#include "avio_internal.h" #include "internal.h" #include "libavcodec/internal.h" -#include "libavcodec/bytestream.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/pixdesc.h" #include "libavutil/timestamp.h" -#include "metadata.h" -#include "id3v2.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/internal.h" #include "libavutil/mathematics.h" -#include "libavutil/parseutils.h" -#include "libavutil/time.h" -#include "riff.h" -#include "audiointerleave.h" -#include "url.h" -#include -#if CONFIG_NETWORK -#include "network.h" -#endif /** * @file @@ -145,7 +132,7 @@ enum AVChromaLocation ff_choose_chroma_location(AVFormatContext *s, AVStream *st } -int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, +int avformat_alloc_output_context2(AVFormatContext **avctx, ff_const59 AVOutputFormat *oformat, const char *format, const char *filename) { AVFormatContext *s = avformat_alloc_context(); @@ -246,7 +233,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) AVStream *st; AVDictionary *tmp = NULL; AVCodecParameters *par = NULL; - AVOutputFormat *of = s->oformat; + const AVOutputFormat *of = s->oformat; const AVCodecDescriptor *desc; AVDictionaryEntry *e; @@ -485,6 +472,14 @@ static void flush_if_needed(AVFormatContext *s) } } +static void deinit_muxer(AVFormatContext *s) +{ + if (s->oformat && s->oformat->deinit && s->internal->initialized) + s->oformat->deinit(s); + s->internal->initialized = + s->internal->streams_initialized = 0; +} + int avformat_init_output(AVFormatContext *s, AVDictionary **options) { int ret = 0; @@ -536,19 +531,12 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) return streams_already_initialized; fail: - if (s->oformat->deinit) - s->oformat->deinit(s); + deinit_muxer(s); return ret; } #define AV_PKT_FLAG_UNCODED_FRAME 0x2000 -/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but - it is only being used internally to this file as a consistency check. - The value is chosen to be very unlikely to appear on its own and to cause - immediate failure if used anywhere as a real size. */ -#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame)) - #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS @@ -643,7 +631,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ? - ((AVFrame *)pkt->data)->nb_samples : + (*(AVFrame **)pkt->data)->nb_samples : av_get_audio_frame_duration(st->codec, pkt->size); /* HACK/FIXME, we skip the initial 0 size packets as they are most @@ -663,8 +651,7 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif /** - * Make timestamps non negative, move side data from payload to internal struct, call muxer, and restore - * sidedata. + * Shift timestamps and call muxer; the original pts/dts are not kept. * * FIXME: this function should NEVER get undefined pts/dts beside when the * AVFMT_NOTIMESTAMPS is set. @@ -674,10 +661,6 @@ FF_ENABLE_DEPRECATION_WARNINGS static int write_packet(AVFormatContext *s, AVPacket *pkt) { int ret; - int64_t pts_backup, dts_backup; - - pts_backup = pkt->pts; - dts_backup = pkt->dts; // If the timestamp offsetting below is adjusted, adjust // ff_interleaved_peek similarly. @@ -739,10 +722,9 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) } if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { - AVFrame *frame = (AVFrame *)pkt->data; - av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); - ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0); - av_frame_free(&frame); + AVFrame **frame = (AVFrame **)pkt->data; + av_assert0(pkt->size == sizeof(*frame)); + ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, frame, 0); } else { ret = s->oformat->write_packet(s, pkt); } @@ -753,19 +735,14 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) ret = s->pb->error; } - if (ret < 0) { - pkt->pts = pts_backup; - pkt->dts = dts_backup; - } + if (ret >= 0) + s->streams[pkt->stream_index]->nb_frames++; return ret; } static int check_packet(AVFormatContext *s, AVPacket *pkt) { - if (!pkt) - return 0; - if (pkt->stream_index < 0 || pkt->stream_index >= s->nb_streams) { av_log(s, AV_LOG_ERROR, "Invalid packet stream index: %d\n", pkt->stream_index); @@ -834,7 +811,7 @@ static int prepare_input_packet(AVFormatContext *s, AVPacket *pkt) static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; - int i, ret; + int ret; if (!(s->flags & AVFMT_FLAG_AUTO_BSF)) return 1; @@ -848,8 +825,8 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { } } - for (i = 0; i < st->internal->nb_bsfcs; i++) { - AVBSFContext *ctx = st->internal->bsfcs[i]; + if (st->internal->bsfc) { + AVBSFContext *ctx = st->internal->bsfc; // TODO: when any bitstream filter requires flushing at EOF, we'll need to // flush each stream's BSF chain on write_trailer. if ((ret = av_bsf_send_packet(ctx, pkt)) < 0) { @@ -865,7 +842,7 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return 0; av_log(ctx, AV_LOG_ERROR, - "Failed to send packet to filter %s for stream %d\n", + "Failed to receive packet from filter %s for stream %d\n", ctx->filter->name, pkt->stream_index); if (s->error_recognition & AV_EF_EXPLODE) return ret; @@ -875,15 +852,12 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { return 1; } -int av_write_frame(AVFormatContext *s, AVPacket *pkt) +int av_write_frame(AVFormatContext *s, AVPacket *in) { + AVPacket local_pkt, *pkt = &local_pkt; int ret; - ret = prepare_input_packet(s, pkt); - if (ret < 0) - return ret; - - if (!pkt) { + if (!in) { if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { ret = s->oformat->write_packet(s, NULL); flush_if_needed(s); @@ -894,54 +868,76 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) return 1; } + if (in->flags & AV_PKT_FLAG_UNCODED_FRAME) { + pkt = in; + } else { + /* We don't own in, so we have to make sure not to modify it. + * The following avoids copying in's data unnecessarily. + * Copying side data is unavoidable as a bitstream filter + * may change it, e.g. free it on errors. */ + pkt->buf = NULL; + pkt->data = in->data; + pkt->size = in->size; + ret = av_packet_copy_props(pkt, in); + if (ret < 0) + return ret; + if (in->buf) { + pkt->buf = av_buffer_ref(in->buf); + if (!pkt->buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + } + + ret = prepare_input_packet(s, pkt); + if (ret < 0) + goto fail; + ret = do_packet_auto_bsf(s, pkt); if (ret <= 0) - return ret; + goto fail; #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX ret = compute_muxer_pkt_fields(s, s->streams[pkt->stream_index], pkt); if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - return ret; + goto fail; #endif ret = write_packet(s, pkt); - if (ret >= 0 && s->pb && s->pb->error < 0) - ret = s->pb->error; - if (ret >= 0) - s->streams[pkt->stream_index]->nb_frames++; +fail: + // Uncoded frames using the noninterleaved codepath are also freed here + av_packet_unref(pkt); return ret; } #define CHUNK_START 0x1000 int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, - int (*compare)(AVFormatContext *, AVPacket *, AVPacket *)) + int (*compare)(AVFormatContext *, const AVPacket *, const AVPacket *)) { int ret; AVPacketList **next_point, *this_pktl; - AVStream *st = s->streams[pkt->stream_index]; - int chunked = s->max_chunk_size || s->max_chunk_duration; + AVStream *st = s->streams[pkt->stream_index]; + int chunked = s->max_chunk_size || s->max_chunk_duration; - this_pktl = av_mallocz(sizeof(AVPacketList)); - if (!this_pktl) + this_pktl = av_malloc(sizeof(AVPacketList)); + if (!this_pktl) { + av_packet_unref(pkt); return AVERROR(ENOMEM); - if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { - av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); - av_assert0(((AVFrame *)pkt->data)->buf); - this_pktl->pkt = *pkt; - pkt->buf = NULL; - pkt->side_data = NULL; - pkt->side_data_elems = 0; - } else { - if ((ret = av_packet_ref(&this_pktl->pkt, pkt)) < 0) { - av_free(this_pktl); - return ret; - } + } + if ((ret = av_packet_make_refcounted(pkt)) < 0) { + av_free(this_pktl); + av_packet_unref(pkt); + return ret; } - if (s->streams[pkt->stream_index]->last_in_packet_buffer) { + av_packet_move_ref(&this_pktl->pkt, pkt); + pkt = &this_pktl->pkt; + + if (st->last_in_packet_buffer) { next_point = &(st->last_in_packet_buffer->next); } else { next_point = &s->internal->packet_buffer; @@ -953,8 +949,8 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, st->interleaver_chunk_duration += pkt->duration; if ( (s->max_chunk_size && st->interleaver_chunk_size > s->max_chunk_size) || (max && st->interleaver_chunk_duration > max)) { - st->interleaver_chunk_size = 0; - this_pktl->pkt.flags |= CHUNK_START; + st->interleaver_chunk_size = 0; + pkt->flags |= CHUNK_START; if (max && st->interleaver_chunk_duration > max) { int64_t syncoffset = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)*max/2; int64_t syncto = av_rescale(pkt->dts + syncoffset, 1, max)*max - syncoffset; @@ -965,7 +961,7 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, } } if (*next_point) { - if (chunked && !(this_pktl->pkt.flags & CHUNK_START)) + if (chunked && !(pkt->flags & CHUNK_START)) goto next_non_null; if (compare(s, &s->internal->packet_buffer_end->pkt, pkt)) { @@ -986,30 +982,34 @@ next_non_null: this_pktl->next = *next_point; - s->streams[pkt->stream_index]->last_in_packet_buffer = - *next_point = this_pktl; - - av_packet_unref(pkt); + st->last_in_packet_buffer = *next_point = this_pktl; return 0; } -static int interleave_compare_dts(AVFormatContext *s, AVPacket *next, - AVPacket *pkt) +static int interleave_compare_dts(AVFormatContext *s, const AVPacket *next, + const AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; AVStream *st2 = s->streams[next->stream_index]; int comp = av_compare_ts(next->dts, st2->time_base, pkt->dts, st->time_base); - if (s->audio_preload && ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) != (st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO))) { - int64_t ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st ->codecpar->codec_type == AVMEDIA_TYPE_AUDIO); - int64_t ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO); - if (ts == ts2) { - ts= ( pkt ->dts* st->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st ->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)* st->time_base.den)*st2->time_base.den - -( next->dts*st2->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)*st2->time_base.den)* st->time_base.den; - ts2=0; + if (s->audio_preload) { + int preload = st ->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; + int preload2 = st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; + if (preload != preload2) { + int64_t ts, ts2; + preload *= s->audio_preload; + preload2 *= s->audio_preload; + ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - preload; + ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - preload2; + if (ts == ts2) { + ts = ((uint64_t)pkt ->dts*st ->time_base.num*AV_TIME_BASE - (uint64_t)preload *st ->time_base.den)*st2->time_base.den + - ((uint64_t)next->dts*st2->time_base.num*AV_TIME_BASE - (uint64_t)preload2*st2->time_base.den)*st ->time_base.den; + ts2 = 0; + } + comp = (ts2 > ts) - (ts2 < ts); } - comp= (ts>ts2) - (tsstreams[pkt->stream_index]; + ret = prepare_input_packet(s, pkt); + if (ret < 0) + goto fail; + ret = do_packet_auto_bsf(s, pkt); if (ret == 0) return 0; @@ -1220,24 +1219,17 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) for (;; ) { AVPacket opkt; int ret = interleave_packet(s, &opkt, pkt, flush); - if (pkt) { - memset(pkt, 0, sizeof(*pkt)); - av_init_packet(pkt); - pkt = NULL; - } - if (ret <= 0) //FIXME cleanup needed for ret<0 ? + if (ret <= 0) return ret; + pkt = NULL; + ret = write_packet(s, &opkt); - if (ret >= 0) - s->streams[opkt.stream_index]->nb_frames++; av_packet_unref(&opkt); if (ret < 0) return ret; - if(s->pb && s->pb->error) - return s->pb->error; } fail: av_packet_unref(pkt); @@ -1257,15 +1249,11 @@ int av_write_trailer(AVFormatContext *s) break; ret = write_packet(s, &pkt); - if (ret >= 0) - s->streams[pkt.stream_index]->nb_frames++; av_packet_unref(&pkt); if (ret < 0) goto fail; - if(s->pb && s->pb->error) - goto fail; } fail: @@ -1279,11 +1267,7 @@ fail: } } - if (s->oformat->deinit) - s->oformat->deinit(s); - - s->internal->initialized = - s->internal->streams_initialized = 0; + deinit_muxer(s); if (s->pb) avio_flush(s->pb); @@ -1316,18 +1300,10 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, local_pkt = *pkt; local_pkt.stream_index = dst_stream; - if (pkt->pts != AV_NOPTS_VALUE) - local_pkt.pts = av_rescale_q(pkt->pts, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - if (pkt->dts != AV_NOPTS_VALUE) - local_pkt.dts = av_rescale_q(pkt->dts, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - if (pkt->duration) - local_pkt.duration = av_rescale_q(pkt->duration, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); + + av_packet_rescale_ts(&local_pkt, + src->streams[pkt->stream_index]->time_base, + dst->streams[dst_stream]->time_base); if (interleave) ret = av_interleaved_write_frame(dst, &local_pkt); else ret = av_write_frame(dst, &local_pkt); @@ -1337,22 +1313,45 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, return ret; } -static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index, - AVFrame *frame, int interleaved) +static void uncoded_frame_free(void *unused, uint8_t *data) +{ + av_frame_free((AVFrame **)data); + av_free(data); +} + +static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index, + AVFrame *frame, int interleaved) { AVPacket pkt, *pktp; av_assert0(s->oformat); - if (!s->oformat->write_uncoded_frame) + if (!s->oformat->write_uncoded_frame) { + av_frame_free(&frame); return AVERROR(ENOSYS); + } if (!frame) { pktp = NULL; } else { + size_t bufsize = sizeof(frame) + AV_INPUT_BUFFER_PADDING_SIZE; + AVFrame **framep = av_mallocz(bufsize); + + if (!framep) + goto fail; pktp = &pkt; av_init_packet(&pkt); - pkt.data = (void *)frame; - pkt.size = UNCODED_FRAME_PACKET_SIZE; + pkt.buf = av_buffer_create((void *)framep, bufsize, + uncoded_frame_free, NULL, 0); + if (!pkt.buf) { + av_free(framep); + fail: + av_frame_free(&frame); + return AVERROR(ENOMEM); + } + *framep = frame; + + pkt.data = (void *)framep; + pkt.size = sizeof(frame); pkt.pts = pkt.dts = frame->pts; pkt.duration = frame->pkt_duration; @@ -1367,13 +1366,13 @@ static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index, int av_write_uncoded_frame(AVFormatContext *s, int stream_index, AVFrame *frame) { - return av_write_uncoded_frame_internal(s, stream_index, frame, 0); + return write_uncoded_frame_internal(s, stream_index, frame, 0); } int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index, AVFrame *frame) { - return av_write_uncoded_frame_internal(s, stream_index, frame, 1); + return write_uncoded_frame_internal(s, stream_index, frame, 1); } int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index)