X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmux.c;h=1c08c74b90b350e02e346bb5b2719204ba957289;hb=30f7021aa0be2c978aefb73894b643c9bafbf51c;hp=fddf1f86be5976476e5da687eef2d19e09069616;hpb=64063512227c4c87a7d16a1076481dc6baf19841;p=ffmpeg diff --git a/libavformat/mux.c b/libavformat/mux.c index fddf1f86be5..1c08c74b90b 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -22,6 +22,7 @@ #include "avformat.h" #include "internal.h" #include "libavcodec/internal.h" +#include "libavcodec/packet_internal.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/pixdesc.h" @@ -132,7 +133,7 @@ enum AVChromaLocation ff_choose_chroma_location(AVFormatContext *s, AVStream *st } -int avformat_alloc_output_context2(AVFormatContext **avctx, ff_const59 AVOutputFormat *oformat, +int avformat_alloc_output_context2(AVFormatContext **avctx, const AVOutputFormat *oformat, const char *format, const char *filename) { AVFormatContext *s = avformat_alloc_context(); @@ -174,11 +175,6 @@ int avformat_alloc_output_context2(AVFormatContext **avctx, ff_const59 AVOutputF s->priv_data = NULL; if (filename) { -#if FF_API_FORMAT_FILENAME -FF_DISABLE_DEPRECATION_WARNINGS - av_strlcpy(s->filename, filename, sizeof(s->filename)); -FF_ENABLE_DEPRECATION_WARNINGS -#endif if (!(s->url = av_strdup(filename))) goto nomem; @@ -246,13 +242,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) (ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; -#if FF_API_FORMAT_FILENAME -FF_DISABLE_DEPRECATION_WARNINGS - if (!s->url && !(s->url = av_strdup(s->filename))) { -FF_ENABLE_DEPRECATION_WARNINGS -#else if (!s->url && !(s->url = av_strdup(""))) { -#endif ret = AVERROR(ENOMEM); goto fail; } @@ -540,13 +530,13 @@ fail: #define AV_PKT_FLAG_UNCODED_FRAME 0x2000 -#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX +#if FF_API_COMPUTE_PKT_FIELDS2 FF_DISABLE_DEPRECATION_WARNINGS //FIXME merge with compute_pkt_fields static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket *pkt) { int delay = FFMAX(st->codecpar->video_delay, st->internal->avctx->max_b_frames > 0); - int num, den, i; + int i; int frame_size; if (!s->internal->missing_ts_warning && @@ -564,20 +554,6 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * av_log(s, AV_LOG_DEBUG, "compute_muxer_pkt_fields: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d\n", av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), delay, pkt->size, pkt->stream_index); - if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { - av_log(s, AV_LOG_WARNING, "Packet with invalid duration %"PRId64" in stream %d\n", - pkt->duration, pkt->stream_index); - pkt->duration = 0; - } - - /* duration field */ - if (pkt->duration == 0) { - ff_compute_frame_duration(s, &num, &den, st, NULL, pkt); - if (den && num) { - pkt->duration = av_rescale(1, num * (int64_t)st->time_base.den * st->codec->ticks_per_frame, den * (int64_t)st->time_base.num); - } - } - if (pkt->pts == AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && delay == 0) pkt->pts = pkt->dts; @@ -595,13 +571,13 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * //calculate dts from pts if (pkt->pts != AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) { - st->pts_buffer[0] = pkt->pts; - for (i = 1; i < delay + 1 && st->pts_buffer[i] == AV_NOPTS_VALUE; i++) - st->pts_buffer[i] = pkt->pts + (i - delay - 1) * pkt->duration; - for (i = 0; ipts_buffer[i] > st->pts_buffer[i + 1]; i++) - FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]); + st->internal->pts_buffer[0] = pkt->pts; + for (i = 1; i < delay + 1 && st->internal->pts_buffer[i] == AV_NOPTS_VALUE; i++) + st->internal->pts_buffer[i] = pkt->pts + (i - delay - 1) * pkt->duration; + for (i = 0; iinternal->pts_buffer[i] > st->internal->pts_buffer[i + 1]; i++) + FFSWAP(int64_t, st->internal->pts_buffer[i], st->internal->pts_buffer[i + 1]); - pkt->dts = st->pts_buffer[0]; + pkt->dts = st->internal->pts_buffer[0]; } if (st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && @@ -634,7 +610,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * case AVMEDIA_TYPE_AUDIO: frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ? (*(AVFrame **)pkt->data)->nb_samples : - av_get_audio_frame_duration(st->codec, pkt->size); + av_get_audio_frame_duration2(st->codecpar, pkt->size); /* HACK/FIXME, we skip the initial 0 size packets as they are most * likely equal to the encoder delay, but it would be better if we @@ -652,6 +628,37 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * FF_ENABLE_DEPRECATION_WARNINGS #endif +static void guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { + av_log(s, AV_LOG_WARNING, "Packet with invalid duration %"PRId64" in stream %d\n", + pkt->duration, pkt->stream_index); + pkt->duration = 0; + } + + if (pkt->duration) + return; + + switch (st->codecpar->codec_type) { + case AVMEDIA_TYPE_VIDEO: + if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) { + pkt->duration = av_rescale_q(1, av_inv_q(st->avg_frame_rate), + st->time_base); + } else if (st->time_base.num * 1000LL > st->time_base.den) + pkt->duration = 1; + break; + case AVMEDIA_TYPE_AUDIO: { + int frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size); + if (frame_size && st->codecpar->sample_rate) { + pkt->duration = av_rescale_q(frame_size, + (AVRational){1, st->codecpar->sample_rate}, + st->time_base); + } + break; + } + } +} + /** * Shift timestamps and call muxer; the original pts/dts are not kept. * @@ -678,7 +685,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) if (s->avoid_negative_ts > 0) { AVStream *st = s->streams[pkt->stream_index]; - int64_t offset = st->mux_ts_offset; + int64_t offset = st->internal->mux_ts_offset; int64_t ts = s->internal->avoid_negative_ts_use_pts ? pkt->pts : pkt->dts; if (s->internal->offset == AV_NOPTS_VALUE && ts != AV_NOPTS_VALUE && @@ -688,7 +695,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) } if (s->internal->offset != AV_NOPTS_VALUE && !offset) { - offset = st->mux_ts_offset = + offset = st->internal->mux_ts_offset = av_rescale_q_rnd(s->internal->offset, s->internal->offset_timebase, st->time_base, @@ -759,16 +766,9 @@ static int check_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int prepare_input_packet(AVFormatContext *s, AVPacket *pkt) +static int prepare_input_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt) { - int ret; - AVStream *st = s->streams[pkt->stream_index]; - - ret = check_packet(s, pkt); - if (ret < 0) - return ret; - -#if !FF_API_COMPUTE_PKT_FIELDS2 || !FF_API_LAVF_AVCTX +#if !FF_API_COMPUTE_PKT_FIELDS2 /* sanitize the timestamps */ if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { @@ -820,11 +820,11 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, int (*compare)(AVFormatContext *, const AVPacket *, const AVPacket *)) { int ret; - AVPacketList **next_point, *this_pktl; + PacketList **next_point, *this_pktl; AVStream *st = s->streams[pkt->stream_index]; int chunked = s->max_chunk_size || s->max_chunk_duration; - this_pktl = av_malloc(sizeof(AVPacketList)); + this_pktl = av_malloc(sizeof(PacketList)); if (!this_pktl) { av_packet_unref(pkt); return AVERROR(ENOMEM); @@ -838,27 +838,27 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, 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); + if (st->internal->last_in_packet_buffer) { + next_point = &(st->internal->last_in_packet_buffer->next); } else { next_point = &s->internal->packet_buffer; } if (chunked) { uint64_t max= av_rescale_q_rnd(s->max_chunk_duration, AV_TIME_BASE_Q, st->time_base, AV_ROUND_UP); - st->interleaver_chunk_size += pkt->size; - 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; + st->internal->interleaver_chunk_size += pkt->size; + st->internal->interleaver_chunk_duration += pkt->duration; + if ( (s->max_chunk_size && st->internal->interleaver_chunk_size > s->max_chunk_size) + || (max && st->internal->interleaver_chunk_duration > max)) { + st->internal->interleaver_chunk_size = 0; pkt->flags |= CHUNK_START; - if (max && st->interleaver_chunk_duration > max) { + if (max && st->internal->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; - st->interleaver_chunk_duration += (pkt->dts - syncto)/8 - max; + st->internal->interleaver_chunk_duration += (pkt->dts - syncto)/8 - max; } else - st->interleaver_chunk_duration = 0; + st->internal->interleaver_chunk_duration = 0; } } if (*next_point) { @@ -883,7 +883,7 @@ next_non_null: this_pktl->next = *next_point; - st->last_in_packet_buffer = *next_point = this_pktl; + st->internal->last_in_packet_buffer = *next_point = this_pktl; return 0; } @@ -921,7 +921,7 @@ static int interleave_compare_dts(AVFormatContext *s, const AVPacket *next, int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush) { - AVPacketList *pktl; + PacketList *pktl; int stream_count = 0; int noninterleaved_count = 0; int i, ret; @@ -933,7 +933,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } for (i = 0; i < s->nb_streams; i++) { - if (s->streams[i]->last_in_packet_buffer) { + if (s->streams[i]->internal->last_in_packet_buffer) { ++stream_count; } else if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT && s->streams[i]->codecpar->codec_id != AV_CODEC_ID_VP8 && @@ -958,7 +958,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, for (i = 0; i < s->nb_streams; i++) { int64_t last_dts; - const AVPacketList *last = s->streams[i]->last_in_packet_buffer; + const PacketList *last = s->streams[i]->internal->last_in_packet_buffer; if (!last) continue; @@ -1007,8 +1007,8 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, if (!s->internal->packet_buffer) s->internal->packet_buffer_end = NULL; - if (st->last_in_packet_buffer == pktl) - st->last_in_packet_buffer = NULL; + if (st->internal->last_in_packet_buffer == pktl) + st->internal->last_in_packet_buffer = NULL; av_packet_unref(&pktl->pkt); av_freep(&pktl); @@ -1026,8 +1026,8 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, if (!s->internal->packet_buffer) s->internal->packet_buffer_end = NULL; - if (st->last_in_packet_buffer == pktl) - st->last_in_packet_buffer = NULL; + if (st->internal->last_in_packet_buffer == pktl) + st->internal->last_in_packet_buffer = NULL; av_freep(&pktl); return 1; @@ -1036,30 +1036,32 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } } -int ff_interleaved_peek(AVFormatContext *s, int stream, - AVPacket *pkt, int add_offset) +int ff_get_muxer_ts_offset(AVFormatContext *s, int stream_index, int64_t *offset) +{ + AVStream *st; + + if (stream_index < 0 || stream_index >= s->nb_streams) + return AVERROR(EINVAL); + + st = s->streams[stream_index]; + *offset = st->internal->mux_ts_offset; + + if (s->output_ts_offset) + *offset += av_rescale_q(s->output_ts_offset, AV_TIME_BASE_Q, st->time_base); + + return 0; +} + +const AVPacket *ff_interleaved_peek(AVFormatContext *s, int stream) { - AVPacketList *pktl = s->internal->packet_buffer; + PacketList *pktl = s->internal->packet_buffer; while (pktl) { if (pktl->pkt.stream_index == stream) { - *pkt = pktl->pkt; - if (add_offset) { - AVStream *st = s->streams[pkt->stream_index]; - int64_t offset = st->mux_ts_offset; - - if (s->output_ts_offset) - offset += av_rescale_q(s->output_ts_offset, AV_TIME_BASE_Q, st->time_base); - - if (pkt->dts != AV_NOPTS_VALUE) - pkt->dts += offset; - if (pkt->pts != AV_NOPTS_VALUE) - pkt->pts += offset; - } - return 0; + return &pktl->pkt; } pktl = pktl->next; } - return AVERROR(ENOENT); + return NULL; } /** @@ -1074,16 +1076,13 @@ int ff_interleaved_peek(AVFormatContext *s, int stream, static int interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush) { if (s->oformat->interleave_packet) { - int ret = s->oformat->interleave_packet(s, out, in, flush); - if (in) - av_packet_unref(in); - return ret; + return s->oformat->interleave_packet(s, out, in, flush); } else return ff_interleave_packet_per_dts(s, out, in, flush); } -static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { - AVStream *st = s->streams[pkt->stream_index]; +static int check_bitstream(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ int ret; if (!(s->flags & AVFMT_FLAG_AUTO_BSF)) @@ -1098,30 +1097,6 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { } } - 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) { - av_log(ctx, AV_LOG_ERROR, - "Failed to send packet to filter %s for stream %d\n", - ctx->filter->name, pkt->stream_index); - return ret; - } - // TODO: when any automatically-added bitstream filter is generating multiple - // output packets for a single input one, we'll need to call this in a loop - // and write each output packet. - if ((ret = av_bsf_receive_packet(ctx, pkt)) < 0) { - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - return 0; - av_log(ctx, AV_LOG_ERROR, - "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; - return 0; - } - } return 1; } @@ -1152,7 +1127,9 @@ static int write_packet_common(AVFormatContext *s, AVStream *st, AVPacket *pkt, av_log(s, AV_LOG_DEBUG, "%s size:%d dts:%s pts:%s\n", __FUNCTION__, pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts)); -#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX + guess_pkt_duration(s, st, pkt); + +#if FF_API_COMPUTE_PKT_FIELDS2 if ((ret = compute_muxer_pkt_fields(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) return ret; #endif @@ -1166,23 +1143,64 @@ static int write_packet_common(AVFormatContext *s, AVStream *st, AVPacket *pkt, } } +static int write_packets_from_bsfs(AVFormatContext *s, AVStream *st, AVPacket *pkt, int interleaved) +{ + AVBSFContext *bsfc = st->internal->bsfc; + int ret; + + if ((ret = av_bsf_send_packet(bsfc, pkt)) < 0) { + av_log(s, AV_LOG_ERROR, + "Failed to send packet to filter %s for stream %d\n", + bsfc->filter->name, st->index); + return ret; + } + + do { + ret = av_bsf_receive_packet(bsfc, pkt); + if (ret < 0) { + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return 0; + av_log(s, AV_LOG_ERROR, "Error applying bitstream filters to an output " + "packet for stream #%d: %s\n", st->index, av_err2str(ret)); + if (!(s->error_recognition & AV_EF_EXPLODE) && ret != AVERROR(ENOMEM)) + continue; + return ret; + } + av_packet_rescale_ts(pkt, bsfc->time_base_out, st->time_base); + ret = write_packet_common(s, st, pkt, interleaved); + if (ret >= 0 && !interleaved) // a successful write_packet_common already unrefed pkt for interleaved + av_packet_unref(pkt); + } while (ret >= 0); + + return ret; +} + static int write_packets_common(AVFormatContext *s, AVPacket *pkt, int interleaved) { - AVStream *st = s->streams[pkt->stream_index]; - int ret = prepare_input_packet(s, pkt); + AVStream *st; + int ret = check_packet(s, pkt); + if (ret < 0) + return ret; + st = s->streams[pkt->stream_index]; + + ret = prepare_input_packet(s, st, pkt); if (ret < 0) return ret; - ret = do_packet_auto_bsf(s, pkt); - if (ret <= 0) + ret = check_bitstream(s, st, pkt); + if (ret < 0) return ret; - return write_packet_common(s, st, pkt, interleaved); + if (st->internal->bsfc) { + return write_packets_from_bsfs(s, st, pkt, interleaved); + } else { + return write_packet_common(s, st, pkt, interleaved); + } } int av_write_frame(AVFormatContext *s, AVPacket *in) { - AVPacket local_pkt, *pkt = &local_pkt; + AVPacket *pkt = s->internal->pkt; int ret; if (!in) { @@ -1203,6 +1221,7 @@ int av_write_frame(AVFormatContext *s, AVPacket *in) * 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. */ + av_packet_unref(pkt); pkt->buf = NULL; pkt->data = in->data; pkt->size = in->size; @@ -1243,9 +1262,22 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) int av_write_trailer(AVFormatContext *s) { - int ret, i; + int i, ret1, ret = 0; + AVPacket *pkt = s->internal->pkt; - ret = interleaved_write_packet(s, NULL, 1); + av_packet_unref(pkt); + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->internal->bsfc) { + ret1 = write_packets_from_bsfs(s, s->streams[i], pkt, 1/*interleaved*/); + if (ret1 < 0) + av_packet_unref(pkt); + if (ret >= 0) + ret = ret1; + } + } + ret1 = interleaved_write_packet(s, NULL, 1); + if (ret >= 0) + ret = ret1; if (s->oformat->write_trailer) { if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) @@ -1265,7 +1297,7 @@ int av_write_trailer(AVFormatContext *s) ret = s->pb ? s->pb->error : 0; for (i = 0; i < s->nb_streams; i++) { av_freep(&s->streams[i]->priv_data); - av_freep(&s->streams[i]->index_entries); + av_freep(&s->streams[i]->internal->index_entries); } if (s->oformat->priv_class) av_opt_free(s->priv_data); @@ -1312,7 +1344,7 @@ static void uncoded_frame_free(void *unused, uint8_t *data) static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index, AVFrame *frame, int interleaved) { - AVPacket pkt, *pktp; + AVPacket *pkt = s->internal->pkt; av_assert0(s->oformat); if (!s->oformat->write_uncoded_frame) { @@ -1321,18 +1353,17 @@ static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index, } if (!frame) { - pktp = NULL; + pkt = 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.buf = av_buffer_create((void *)framep, bufsize, + av_packet_unref(pkt); + pkt->buf = av_buffer_create((void *)framep, bufsize, uncoded_frame_free, NULL, 0); - if (!pkt.buf) { + if (!pkt->buf) { av_free(framep); fail: av_frame_free(&frame); @@ -1340,17 +1371,17 @@ static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index, } *framep = frame; - pkt.data = (void *)framep; - pkt.size = sizeof(frame); - pkt.pts = - pkt.dts = frame->pts; - pkt.duration = frame->pkt_duration; - pkt.stream_index = stream_index; - pkt.flags |= AV_PKT_FLAG_UNCODED_FRAME; + pkt->data = (void *)framep; + pkt->size = sizeof(frame); + pkt->pts = + pkt->dts = frame->pts; + pkt->duration = frame->pkt_duration; + pkt->stream_index = stream_index; + pkt->flags |= AV_PKT_FLAG_UNCODED_FRAME; } - return interleaved ? av_interleaved_write_frame(s, pktp) : - av_write_frame(s, pktp); + return interleaved ? av_interleaved_write_frame(s, pkt) : + av_write_frame(s, pkt); } int av_write_uncoded_frame(AVFormatContext *s, int stream_index,