[FFmpeg-cvslog] avformat/mux: implement AVFMT_FLAG_SHORTEST
ffmpeg | branch: master | Michael Niedermayer | Fri Aug 12 21:28:08 2016 +0200| [cb114ed464069ac83f05a4ebdfe992e8f1549815] | committer: Michael Niedermayer avformat/mux: implement AVFMT_FLAG_SHORTEST This will allow fixing several bugs with the -shortest option Signed-off-by: Michael Niedermayer > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=cb114ed464069ac83f05a4ebdfe992e8f1549815 --- doc/formats.texi| 4 libavformat/avformat.h | 1 + libavformat/internal.h | 5 + libavformat/mux.c | 39 +++ libavformat/options.c | 1 + libavformat/options_table.h | 1 + 6 files changed, 51 insertions(+) diff --git a/doc/formats.texi b/doc/formats.texi index f79ebe2..dda81e6 100644 --- a/doc/formats.texi +++ b/doc/formats.texi @@ -61,6 +61,10 @@ Reduce the latency introduced by optional buffering Only write platform-, build- and time-independent data. This ensures that file and data checksums are reproducible and match between platforms. Its primary use is for regression testing. +@item shortest +Stop muxing at the end of the shortest stream. +It may be needed to increase max_interleave_delta to avoid flusing the longer +streams before EOF. @end table @item seek2any @var{integer} (@emph{input}) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 3ee7051..74915a1 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1448,6 +1448,7 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_PRIV_OPT0x2 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #define AVFMT_FLAG_KEEP_SIDE_DATA 0x4 ///< Don't merge side data but keep it separate. #define AVFMT_FLAG_FAST_SEEK 0x8 ///< Enable fast, but inaccurate seeks for some formats +#define AVFMT_FLAG_SHORTEST 0x10 ///< Stop muxing when the shortest stream stops. /** * Maximum size of the data read from input for determining diff --git a/libavformat/internal.h b/libavformat/internal.h index f9278c5..49244fa 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -125,6 +125,11 @@ struct AVFormatInternal { */ int header_written; int write_header_ret; + +/** + * Timestamp of the end of the shortest stream. + */ +int64_t shortest_end; }; struct AVStreamInternal { diff --git a/libavformat/mux.c b/libavformat/mux.c index a427f46..176af59 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -1032,6 +1032,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, int stream_count = 0; int noninterleaved_count = 0; int i, ret; +int eof = flush; if (pkt) { if ((ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts)) < 0) @@ -1084,6 +1085,44 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } } +if (s->internal->packet_buffer && +eof && +(s->flags & AVFMT_FLAG_SHORTEST) && +s->internal->shortest_end == AV_NOPTS_VALUE) { +AVPacket *top_pkt = &s->internal->packet_buffer->pkt; + +s->internal->shortest_end = av_rescale_q(top_pkt->dts, + s->streams[top_pkt->stream_index]->time_base, + AV_TIME_BASE_Q); +} + +if (s->internal->shortest_end != AV_NOPTS_VALUE) { +while (s->internal->packet_buffer) { +AVPacket *top_pkt = &s->internal->packet_buffer->pkt; +AVStream *st; +int64_t top_dts = av_rescale_q(top_pkt->dts, + s->streams[top_pkt->stream_index]->time_base, +AV_TIME_BASE_Q); + +if (s->internal->shortest_end + 1 >= top_dts) +break; + +pktl = s->internal->packet_buffer; +st = s->streams[pktl->pkt.stream_index]; + +s->internal->packet_buffer = pktl->next; +if (!s->internal->packet_buffer) +s->internal->packet_buffer_end = NULL; + +if (st->last_in_packet_buffer == pktl) +st->last_in_packet_buffer = NULL; + +av_packet_unref(&pktl->pkt); +av_freep(&pktl); +flush = 0; +} +} + if (stream_count && flush) { AVStream *st; pktl = s->internal->packet_buffer; diff --git a/libavformat/options.c b/libavformat/options.c index 04d9c45..25a506e 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -143,6 +143,7 @@ AVFormatContext *avformat_alloc_context(void) } ic->internal->offset = AV_NOPTS_VALUE; ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; +ic->internal->shortest_end = AV_NOPTS_VALUE; return ic; } diff --git a/libavformat/options_table.h b/libavformat/options_table.h index 3b74d1b..699809a 100644 --- a/libavformat/o
[FFmpeg-cvslog] avformat/tee: Use BSF list API
ffmpeg | branch: master | Jan Sebechlebsky | Thu Jul 7 17:56:10 2016 +0200| [b7760dd8d437d1b5d325d48a9dd317281d1d973c] | committer: Jan Sebechlebsky avformat/tee: Use BSF list API Signed-off-by: Jan Sebechlebsky > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=b7760dd8d437d1b5d325d48a9dd317281d1d973c --- libavformat/tee.c | 136 +++--- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/libavformat/tee.c b/libavformat/tee.c index 5689ca3..518af4a 100644 --- a/libavformat/tee.c +++ b/libavformat/tee.c @@ -37,7 +37,7 @@ typedef enum { typedef struct { AVFormatContext *avf; -AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream +AVBSFContext **bsfs; ///< bitstream filters per stream SlaveFailurePolicy on_fail; @@ -64,46 +64,6 @@ static const AVClass tee_muxer_class = { .version= LIBAVUTIL_VERSION_INT, }; -/** - * Parse list of bitstream filters and add them to the list of filters - * pointed to by bsfs. - * - * The list must be specified in the form: - * BSFS ::= BSF[,BSFS] - */ -static int parse_bsfs(void *log_ctx, const char *bsfs_spec, - AVBitStreamFilterContext **bsfs) -{ -char *bsf_name, *buf, *dup, *saveptr; -int ret = 0; - -if (!(dup = buf = av_strdup(bsfs_spec))) -return AVERROR(ENOMEM); - -while (bsf_name = av_strtok(buf, ",", &saveptr)) { -AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name); - -if (!bsf) { -av_log(log_ctx, AV_LOG_ERROR, - "Cannot initialize bitstream filter with name '%s', " - "unknown filter or internal error happened\n", - bsf_name); -ret = AVERROR_UNKNOWN; -goto end; -} - -/* append bsf context to the list of bsf contexts */ -*bsfs = bsf; -bsfs = &bsf->next; - -buf = NULL; -} - -end: -av_free(dup); -return ret; -} - static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave) { if (!opt) { @@ -135,14 +95,8 @@ static int close_slave(TeeSlave *tee_slave) ret = av_write_trailer(avf); if (tee_slave->bsfs) { -for (i = 0; i < avf->nb_streams; ++i) { -AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i]; -while (bsf) { -bsf_next = bsf->next; -av_bitstream_filter_close(bsf); -bsf = bsf_next; -} -} +for (i = 0; i < avf->nb_streams; ++i) +av_bsf_free(&tee_slave->bsfs[i]); } av_freep(&tee_slave->stream_map); av_freep(&tee_slave->bsfs); @@ -312,7 +266,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) "output '%s', filters will be ignored\n", i, filename); continue; } -ret = parse_bsfs(avf, entry->value, &tee_slave->bsfs[i]); +ret = av_bsf_list_parse_str(entry->value, &tee_slave->bsfs[i]); if (ret < 0) { av_log(avf, AV_LOG_ERROR, "Error parsing bitstream filter sequence '%s' associated to " @@ -325,6 +279,37 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) av_dict_set(&options, entry->key, NULL, 0); } +for (i = 0; i < avf->nb_streams; i++){ +int target_stream = tee_slave->stream_map[i]; +if (target_stream < 0) +continue; + +if (!tee_slave->bsfs[target_stream]) { +/* Add pass-through bitstream filter */ +ret = av_bsf_get_null_filter(&tee_slave->bsfs[target_stream]); +if (ret < 0) { +av_log(avf, AV_LOG_ERROR, + "Failed to create pass-through bitstream filter: %s\n", + av_err2str(ret)); +goto end; +} +} + +tee_slave->bsfs[target_stream]->time_base_in = avf->streams[i]->time_base; +ret = avcodec_parameters_copy(tee_slave->bsfs[target_stream]->par_in, + avf->streams[i]->codecpar); +if (ret < 0) +goto end; + +ret = av_bsf_init(tee_slave->bsfs[target_stream]); +if (ret < 0) { +av_log(avf, AV_LOG_ERROR, +"Failed to initialize bitstream filter(s): %s\n", +av_err2str(ret)); +goto end; +} +} + if (options) { entry = NULL; while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX))) @@ -349,20 +334,16 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int log_level) slave->avf->filename, slave->avf->oformat->name); for (i = 0; i < slave->avf->nb_streams; i++) { AVStream *st = slave->avf->streams[i]; -AVBitStreamFilterContext *bsf = s
[FFmpeg-cvslog] libavcodec/mmaldec.c: set AVFrame interlaced_frame and top_field_first, AVCodecContext framerate
ffmpeg | branch: master | Jens Ziller | Sun Aug 14 16:44:39 2016 +0200| [bc7066fd5dcfa33264e9e846284f44d80dd6] | committer: Michael Niedermayer libavcodec/mmaldec.c: set AVFrame interlaced_frame and top_field_first, AVCodecContext framerate Signed-off-by: Michael Niedermayer > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=bc7066fd5dcfa33264e9e846284f44d80dd6 --- libavcodec/mmaldec.c | 20 1 file changed, 20 insertions(+) diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index 099a8c5..56ad948 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -88,6 +88,8 @@ typedef struct MMALDecodeContext { int eos_received; int eos_sent; int extradata_sent; +int interlaced_frame; +int top_field_first; } MMALDecodeContext; // Assume decoder is guaranteed to produce output after at least this many @@ -274,6 +276,7 @@ static int ffmal_update_format(AVCodecContext *avctx) int ret = 0; MMAL_COMPONENT_T *decoder = ctx->decoder; MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format; +MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type; ffmmal_poolref_unref(ctx->pool_out); if (!(ctx->pool_out = av_mallocz(sizeof(*ctx->pool_out { @@ -300,6 +303,16 @@ static int ffmal_update_format(AVCodecContext *avctx) if ((status = mmal_port_format_commit(decoder->output[0]))) goto fail; +interlace_type.hdr.id = MMAL_PARAMETER_VIDEO_INTERLACE_TYPE; +interlace_type.hdr.size = sizeof(MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T); +status = mmal_port_parameter_get(decoder->output[0], &interlace_type.hdr); +if (status != MMAL_SUCCESS) { +av_log(avctx, AV_LOG_ERROR, "Cannot read MMAL interlace information!\n"); +} else { +ctx->interlaced_frame = (interlace_type.eMode != MMAL_InterlaceProgressive); +ctx->top_field_first = (interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst); +} + if ((ret = ff_set_dimensions(avctx, format_out->es->video.crop.x + format_out->es->video.crop.width, format_out->es->video.crop.y + format_out->es->video.crop.height)) < 0) goto fail; @@ -308,6 +321,10 @@ static int ffmal_update_format(AVCodecContext *avctx) avctx->sample_aspect_ratio.num = format_out->es->video.par.num; avctx->sample_aspect_ratio.den = format_out->es->video.par.den; } +if (format_out->es->video.frame_rate.num && format_out->es->video.frame_rate.den) { +avctx->framerate.num = format_out->es->video.frame_rate.num; +avctx->framerate.den = format_out->es->video.frame_rate.den; +} avctx->colorspace = ffmmal_csp_to_av_csp(format_out->es->video.color_space); @@ -609,6 +626,9 @@ static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame, MMALDecodeContext *ctx = avctx->priv_data; int ret = 0; +frame->interlaced_frame = ctx->interlaced_frame; +frame->top_field_first = ctx->top_field_first; + if (avctx->pix_fmt == AV_PIX_FMT_MMAL) { if (!ctx->pool_out) return AVERROR_UNKNOWN; // format change code failed with OOM previously ___ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog