Re: [FFmpeg-devel] [PATCH 3/3] tests: add README.md file with simple instructions
Hi, Am 03.04.22 um 15:59 schrieb Stefano Sabatini: --- tests/README.md | 48 1 file changed, 48 insertions(+) create mode 100644 tests/README.md diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00..4bcae0b403 --- /dev/null +++ b/tests/README.md currently we got part of that in doc/fate.texi. Doesn't it make more sense to add that there? -Thilo ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v7 09/10] qsv: use a new method to create mfx session when using oneVPL
On Tue, Mar 15, 2022 at 8:24 AM Xiang, Haihao wrote: > > On Fri, 2022-03-11 at 15:00 +0100, Hendrik Leppkes wrote: > > On Fri, Mar 11, 2022 at 2:43 PM Xiang, Haihao > > wrote: > > > > > > On Fri, 2022-03-11 at 09:35 +0100, Hendrik Leppkes wrote: > > > > On Fri, Mar 11, 2022 at 9:18 AM Xiang, Haihao > > > > wrote: > > > > > diff --git a/libavutil/hwcontext_d3d11va.c > > > > > b/libavutil/hwcontext_d3d11va.c > > > > > index 8ab96bad25..e0e820f164 100644 > > > > > --- a/libavutil/hwcontext_d3d11va.c > > > > > +++ b/libavutil/hwcontext_d3d11va.c > > > > > @@ -525,6 +525,13 @@ static void > > > > > d3d11va_device_uninit(AVHWDeviceContext > > > > > *hwdev) > > > > > } > > > > > } > > > > > > > > > > +static void d3d11va_device_free(AVHWDeviceContext *ctx) > > > > > +{ > > > > > +AVD3D11VADeviceContext *hwctx = ctx->hwctx; > > > > > + > > > > > +av_free(hwctx->device_name); > > > > > +} > > > > > + > > > > > static int d3d11va_device_create(AVHWDeviceContext *ctx, const char > > > > > *device, > > > > > AVDictionary *opts, int flags) > > > > > { > > > > > @@ -537,6 +544,8 @@ static int d3d11va_device_create(AVHWDeviceContext > > > > > *ctx, > > > > > const char *device, > > > > > int is_debug = !!av_dict_get(opts, "debug", NULL, 0); > > > > > int ret; > > > > > > > > > > +ctx->free = d3d11va_device_free; > > > > > + > > > > > // (On UWP we can't check this.) > > > > > #if !HAVE_UWP > > > > > if (!LoadLibrary("d3d11_1sdklayers.dll")) > > > > > @@ -561,6 +570,10 @@ static int > > > > > d3d11va_device_create(AVHWDeviceContext > > > > > *ctx, const char *device, > > > > > if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, > > > > > adapter, > > > > > &pAdapter))) > > > > > pAdapter = NULL; > > > > > IDXGIFactory2_Release(pDXGIFactory); > > > > > + > > > > > +device_hwctx->device_name = av_strdup(device); > > > > > +if (!device_hwctx->device_name) > > > > > +return AVERROR(ENOMEM); > > > > > } > > > > > } > > > > > > > > > > diff --git a/libavutil/hwcontext_d3d11va.h > > > > > b/libavutil/hwcontext_d3d11va.h > > > > > index 77d2d72f1b..41a315b9e6 100644 > > > > > --- a/libavutil/hwcontext_d3d11va.h > > > > > +++ b/libavutil/hwcontext_d3d11va.h > > > > > @@ -94,6 +94,11 @@ typedef struct AVD3D11VADeviceContext { > > > > > void (*lock)(void *lock_ctx); > > > > > void (*unlock)(void *lock_ctx); > > > > > void *lock_ctx; > > > > > + > > > > > +/** > > > > > + * The string for the used adapter > > > > > + */ > > > > > +char *device_name; > > > > > } AVD3D11VADeviceContext; > > > > > > > > > > /** > > > > > diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c > > > > > index 53d00fa815..6967357093 100644 > > > > > --- a/libavutil/hwcontext_dxva2.c > > > > > +++ b/libavutil/hwcontext_dxva2.c > > > > > @@ -431,6 +431,7 @@ static void dxva2_device_free(AVHWDeviceContext > > > > > *ctx) > > > > > dlclose(priv->dxva2lib); > > > > > > > > > > av_freep(&ctx->user_opaque); > > > > > +av_free(hwctx->device_name); > > > > > } > > > > > > > > > > static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter) > > > > > @@ -571,6 +572,13 @@ static int dxva2_device_create(AVHWDeviceContext > > > > > *ctx, > > > > > const char *device, > > > > > return AVERROR_UNKNOWN; > > > > > } > > > > > > > > > > +if (device) { > > > > > +hwctx->device_name = av_strdup(device); > > > > > + > > > > > +if (!hwctx->device_name) > > > > > +return AVERROR(ENOMEM); > > > > > +} > > > > > + > > > > > return 0; > > > > > } > > > > > > > > > > diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h > > > > > index e1b79bc0de..253ddbed51 100644 > > > > > --- a/libavutil/hwcontext_dxva2.h > > > > > +++ b/libavutil/hwcontext_dxva2.h > > > > > @@ -38,6 +38,10 @@ > > > > > */ > > > > > typedef struct AVDXVA2DeviceContext { > > > > > IDirect3DDeviceManager9 *devmgr; > > > > > +/** > > > > > + * The string for the used adapter > > > > > + */ > > > > > +char *device_name; > > > > > } AVDXVA2DeviceContext; > > > > > > > > > > /** > > > > > > > > Why are these device names required? I would think deriving a child > > > > device would use the actual device, eg. ID3D11Device or > > > > IDirect3DDeviceManager9 (and whatever for VAAPI), and not some string > > > > (that may or may not even be set). > > > > It feels quite a bit icky to store these in the context just for qsv > > > > to do... what with? > > > > > > Yes, it is a little ugly here. MediaSDK or oneVPL application creates mfx > > > session and the device (dxva2, d3d11va or vaapi), then pass this device to > > > the > > > SDK through MFXVideoCORE_SetHandle(). implementation is introduced in > > > oneVPL > > > ( > > > > https://spec.oneapi.io/versions/latest/elem
[FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
From: Jan Ekström Additionally, they should not be probed, as this is essentially various types of binary data. Signed-off-by: Jan Ekström --- libavformat/mpegts.c| 48 + tests/fate/mpegts.mak | 3 ++ tests/ref/fate/mpegts-probe-sdt-data-stream | 14 ++ 3 files changed, 65 insertions(+) create mode 100644 tests/ref/fate/mpegts-probe-sdt-data-stream diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index da77b50669..3788faf848 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2512,6 +2512,13 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } p = desc_list_end; + +if (!ts->pkt && (stream_type >= 0x80 && stream_type <= 0xFF) && +st->codecpar->codec_id == AV_CODEC_ID_NONE) +// if we are reading headers, and still have a user private stream +// with no proper codec set, do not stop reading at PMT. Data +// streams are marked within SDT. +ts->stop_parse = 0; } if (!ts->pids[pcr_pid]) @@ -2691,6 +2698,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (val < 0) return; for (;;) { +struct Program *program = NULL; sid = get16(&p, p_end); if (sid < 0) break; @@ -2704,6 +2712,15 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len desc_list_end = p + desc_list_len; if (desc_list_end > p_end) break; + +program = get_program(ts, sid); + +if (!ts->pkt && program && program->pmt_found) +// if during header reading we have already received a PMT for +// this program and now have received an SDT for it, stop further +// reading at this point. +ts->stop_parse = 2; + for (;;) { desc_tag = get8(&p, desc_list_end); if (desc_tag < 0) @@ -2736,6 +2753,37 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len av_free(name); av_free(provider_name); break; +case 0x64: /* ETSI data broadcast descriptor; EN 300 468 6.2.11 */ +{ +AVStream *st = NULL; +FFStream *sti = NULL; + +uint16_t data_broadcast_id = get16(&p, p_end); // TS 101 162 +uint8_t component_tag = get8(&p, p_end); +if (!component_tag) +// no stream mapping according to component_tag +break; + +av_log(ts->stream, AV_LOG_TRACE, + "data broadcast id: %d, component tag: %d\n", + data_broadcast_id, component_tag); + +if (!program) +break; + +st = find_matching_stream(ts, 0, sid, component_tag + 1, 0, + program); +if (!st) +break; + +sti = ffstream(st); + +st->codecpar->codec_type = AVMEDIA_TYPE_DATA; +st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; +sti->request_probe = sti->need_parsing = 0; +sti->need_context_update = 1; +break; +} default: break; } diff --git a/tests/fate/mpegts.mak b/tests/fate/mpegts.mak index bbcbfc47b2..ae21ee87d0 100644 --- a/tests/fate/mpegts.mak +++ b/tests/fate/mpegts.mak @@ -19,6 +19,9 @@ FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS) += fate-mpegts-probe-pmt-merge fate-mpegts-probe-pmt-merge: SRC = $(TARGET_SAMPLES)/mpegts/pmtchange.ts fate-mpegts-probe-pmt-merge: CMD = run $(PROBE_CODEC_NAME_COMMAND) -merge_pmt_versions 1 -i "$(SRC)" +FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS, MP2) += fate-mpegts-probe-sdt-data-stream +fate-mpegts-probe-sdt-data-stream: SRC = $(TARGET_SAMPLES)/mpegts/mpegts_sdt_data_stream.ts +fate-mpegts-probe-sdt-data-stream: CMD = run $(PROBE_CODEC_NAME_COMMAND) -i "$(SRC)" FATE_SAMPLES_FFPROBE += $(FATE_MPEGTS_PROBE-yes) diff --git a/tests/ref/fate/mpegts-probe-sdt-data-stream b/tests/ref/fate/mpegts-probe-sdt-data-stream new file mode 100644 index 00..0b8e90962f --- /dev/null +++ b/tests/ref/fate/mpegts-probe-sdt-data-stream @@ -0,0 +1,14 @@ +[PROGRAM] +[STREAM] +codec_name=mp2 +[/STREAM] +[STREAM] +codec_name=bin_data +[/STREAM] +[/PROGRAM] +[STREAM] +codec_name=mp2 +[/STREAM] +[STREAM] +codec_name=bin_data +[/STREAM] -- 2.35.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with
Re: [FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
On Mon, Apr 4, 2022 at 12:53 PM Jan Ekström wrote: > > From: Jan Ekström > > Additionally, they should not be probed, as this is essentially > various types of binary data. > > Signed-off-by: Jan Ekström > --- The test file referenced with this sort of signaling is available at: https://megumin.fushizen.eu/samples/2022-02-04-radio_with_data_stream/mpegts_sdt_data_stream.ts Jan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/2] lafi/vf_edgedetect: Move some common functions into seperate file
Hi, v3 updated to current HEAD. -ThiloFrom ba103f0a51557aae4f1c242ccc394da6ddce64fb Mon Sep 17 00:00:00 2001 From: Thilo Borgmann Date: Tue, 30 Nov 2021 00:16:52 +0100 Subject: [PATCH v3 1/2] lafi/vf_edgedetect: Move some common functions into seperate file --- libavfilter/Makefile| 2 +- libavfilter/edge_common.c | 181 +++ libavfilter/edge_common.h | 107 + libavfilter/vf_edgedetect.c | 183 ++-- 4 files changed, 296 insertions(+), 177 deletions(-) create mode 100644 libavfilter/edge_common.c create mode 100644 libavfilter/edge_common.h diff --git a/libavfilter/Makefile b/libavfilter/Makefile index c4c946a988..006e59b2bd 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -265,7 +265,7 @@ OBJS-$(CONFIG_DRAWBOX_FILTER)+= vf_drawbox.o OBJS-$(CONFIG_DRAWGRAPH_FILTER) += f_drawgraph.o OBJS-$(CONFIG_DRAWGRID_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o -OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o +OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o edge_common.o OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o OBJS-$(CONFIG_ENTROPY_FILTER)+= vf_entropy.o OBJS-$(CONFIG_EPX_FILTER)+= vf_epx.o diff --git a/libavfilter/edge_common.c b/libavfilter/edge_common.c new file mode 100644 index 00..d72e8521cd --- /dev/null +++ b/libavfilter/edge_common.c @@ -0,0 +1,181 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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, + * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "edge_common.h" + +// Internal helper for ff_sobel() +static int get_rounded_direction(int gx, int gy) +{ +/* reference angles: + * tan( pi/8) = sqrt(2)-1 + * tan(3pi/8) = sqrt(2)+1 + * Gy/Gx is the tangent of the angle (theta), so Gy/Gx is compared against + * , or more simply Gy against *Gx + * + * Gx and Gy bounds = [-1020;1020], using 16-bit arithmetic: + * round((sqrt(2)-1) * (1<<16)) = 27146 + * round((sqrt(2)+1) * (1<<16)) = 158218 + */ +if (gx) { +int tanpi8gx, tan3pi8gx; + +if (gx < 0) +gx = -gx, gy = -gy; +gy *= (1 << 16); +tanpi8gx = 27146 * gx; +tan3pi8gx = 158218 * gx; +if (gy > -tan3pi8gx && gy < -tanpi8gx) return DIRECTION_45UP; +if (gy > -tanpi8gx && gy < tanpi8gx) return DIRECTION_HORIZONTAL; +if (gy > tanpi8gx && gy < tan3pi8gx) return DIRECTION_45DOWN; +} +return DIRECTION_VERTICAL; +} + +// Simple sobel operator to get rounded gradients +void ff_sobel(int w, int h, +uint16_t *dst, int dst_linesize, +int8_t *dir, int dir_linesize, +const uint8_t *src, int src_linesize) +{ +int i, j; + +for (j = 1; j < h - 1; j++) { +dst += dst_linesize; +dir += dir_linesize; +src += src_linesize; +for (i = 1; i < w - 1; i++) { +const int gx = +-1*src[-src_linesize + i-1] + 1*src[-src_linesize + i+1] +-2*src[i-1] + 2*src[i+1] +-1*src[ src_linesize + i-1] + 1*src[ src_linesize + i+1]; +const int gy = +-1*src[-src_linesize + i-1] + 1*src[ src_linesize + i-1] +-2*src[-src_linesize + i ] + 2*src[ src_linesize + i ] +-1*src[-src_linesize + i+1] + 1*src[ src_linesize + i+1]; + +dst[i] = FFABS(gx) + FFABS(gy); +dir[i] = get_rounded_direction(gx, gy); +} +} +} + +// Filters rounded gradients to drop all non-maxima +// Expects gradients generated by ff_sobel() +// Expects zero's destination buffer +void ff_non_maximum_suppression(int w, int h, + uint8_t *dst, int dst_linesize, + const int8_t *dir, int dir_linesize, + const uint16_t *src, int src_linesize) +{ +int i, j; + +#define COPY_MAXIMA(ay, ax, by, bx) do {\ +if (src[i] > src[(ay)*src_linesize + i+(ax)] && \ +src[i] > src[(by)*src_linesize + i+(bx)]) \ +d
Re: [FFmpeg-devel] [PATCH 2/2] lavfi: Add blurriness filter
Hi, v3 updated to current HEAD. Named blurdetect filter now. Minor fixes on allocation and removed -f option. -ThiloFrom 1c81cf6f0586a3cc670e6d8354f35e5bdbe2a282 Mon Sep 17 00:00:00 2001 From: Thilo Borgmann Date: Mon, 4 Apr 2022 12:21:14 +0200 Subject: [PATCH v3 2/2] lavfi: Add blurdetect filter --- doc/filters.texi| 49 + libavfilter/Makefile| 1 + libavfilter/allfilters.c| 1 + libavfilter/vf_blurdetect.c | 368 4 files changed, 419 insertions(+) create mode 100644 libavfilter/vf_blurdetect.c diff --git a/doc/filters.texi b/doc/filters.texi index 636c80dbff..f15fb719d5 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -7990,6 +7990,55 @@ tblend=all_mode=grainextract @subsection Commands This filter supports same @ref{commands} as options. +@anchor{blurdetect} +@section blurdetect + +Determines blurriness of frames without altering the input frames. + +Based on Marziliano, Pina, et al. "A no-reference perceptual blur metric." +Allows for a block-based abbreviation. + +The filter accepts the following options: + +@table @option +@item low +@item high +Set low and high threshold values used by the Canny thresholding +algorithm. + +The high threshold selects the "strong" edge pixels, which are then +connected through 8-connectivity with the "weak" edge pixels selected +by the low threshold. + +@var{low} and @var{high} threshold values must be chosen in the range +[0,1], and @var{low} should be lesser or equal to @var{high}. + +Default value for @var{low} is @code{20/255}, and default value for @var{high} +is @code{50/255}. + +@item radius +Define the radius to search around an edge pixel for local maxima. + +@item block_pct +Determine blurriness only for the most significant blocks, given in percentage. + +@item block_width +Determine blurriness for blocks of width @var{block_width}. If set to any value smaller 1, no blocks are used and the whole image is processed as one no matter of @var{block_height}. + +@item block_height +Determine blurriness for blocks of height @var{block_height}. If set to any value smaller 1, no blocks are used and the whole image is processed as one no matter of @var{block_width}. +@end table + +@subsection Examples + +@itemize +@item +Determine blur for 80% of most significant 32x32 blocks: +@example +blurdetect=block_width=32:block_height=32:block_pct=80 +@end example +@end itemize + @section bm3d Denoise frames using Block-Matching 3D algorithm. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 006e59b2bd..6332a6f799 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -195,6 +195,7 @@ OBJS-$(CONFIG_BLACKDETECT_FILTER)+= vf_blackdetect.o OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o framesync.o OBJS-$(CONFIG_BLEND_VULKAN_FILTER) += vf_blend_vulkan.o framesync.o vulkan.o vulkan_filter.o +OBJS-$(CONFIG_BLURDETECT_FILTER) += vf_blurdetect.o edge_common.o OBJS-$(CONFIG_BM3D_FILTER) += vf_bm3d.o framesync.o OBJS-$(CONFIG_BOXBLUR_FILTER)+= vf_boxblur.o boxblur.o OBJS-$(CONFIG_BOXBLUR_OPENCL_FILTER) += vf_avgblur_opencl.o opencl.o \ diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9fbaaacf47..2667d153ad 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -183,6 +183,7 @@ extern const AVFilter ff_vf_blackdetect; extern const AVFilter ff_vf_blackframe; extern const AVFilter ff_vf_blend; extern const AVFilter ff_vf_blend_vulkan; +extern const AVFilter ff_vf_blurdetect; extern const AVFilter ff_vf_bm3d; extern const AVFilter ff_vf_boxblur; extern const AVFilter ff_vf_boxblur_opencl; diff --git a/libavfilter/vf_blurdetect.c b/libavfilter/vf_blurdetect.c new file mode 100644 index 00..050cec9529 --- /dev/null +++ b/libavfilter/vf_blurdetect.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2021 Thilo Borgmann + * + * This file is part of FFmpeg. + * + * FFmpeg 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, + * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * No-reference blurdetect filter + * + * Implementing: + * Marziliano, Pina, et al. "A no-reference perceptual blur metric." Proceedings. + * International conference on image
Re: [FFmpeg-devel] [PATCH 2/2] lavfi: Add blurriness filter
On Mon, Apr 4, 2022 at 12:25 PM Thilo Borgmann wrote: > Hi, > > v3 updated to current HEAD. > > Named blurdetect filter now. > Minor fixes on allocation and removed -f option. > Please make this per plane filtering, with default to measure only first plane. > -Thilo___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [RFC] Switching ffmpeg.c to a threaded architecture
Hi, this WIP patchset is the first major part of my ongoing work to change ffmpeg.c architecture such that every - demuxer - decoder - filtergraph - encoder - muxer lives in its own thread. The advantages of doing this, beyond increased throughput, would be enforced separation between these components, making the code more local and easier to reason about. This set implements threading for muxers. My tentative plan is to continue with encoders and then filters. The patches still need some polishing, especially the last one. Two FATE tests do not yet pass, this will be fixed in later iterations. Meanwhile, comments on the overall approach are especially welcome. -- Anton Khirnov ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 02/49] fftools/ffmpeg: move a comment to a more appropriate place
--- fftools/ffmpeg.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index afa1b012a6..13be32f0cf 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1238,6 +1238,11 @@ static void do_video_out(OutputFile *of, } } +/* + * For video, number of frames in == number of packets out. + * But there may be reordering, so we can't throw away frames on encoder + * flush, we need to limit them here, before they go into encoder. + */ nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); nb0_frames = FFMIN(nb0_frames, nb_frames); @@ -1392,11 +1397,6 @@ static void do_video_out(OutputFile *of, } } ost->sync_opts++; -/* - * For video, number of frames in == number of packets out. - * But there may be reordering, so we can't throw away frames on encoder - * flush, we need to limit them here, before they go into encoder. - */ ost->frame_number++; if (vstats_filename && frame_size) -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 01/49] fftools/ffmpeg: drop an obsolete hack
Introduced in 05741d70c7a. All encoders should set the timestamps properly now, so it should never be necessary. --- fftools/ffmpeg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 6d62bdc7b0..afa1b012a6 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1372,9 +1372,6 @@ static void do_video_out(OutputFile *of, av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); } -if (pkt->pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & AV_CODEC_CAP_DELAY)) -pkt->pts = ost->sync_opts; - av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); if (debug_ts) { -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 04/49] fftools/ffmpeg: pass the muxer context explicitly to some functions
Stop accessing OutputFile.ctx. This will be useful in the following commits, where it will become hidden. --- fftools/ffmpeg_opt.c | 16 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 22c88287df..8e217af4ab 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2125,10 +2125,10 @@ static int opt_streamid(void *optctx, const char *opt, const char *arg) return 0; } -static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) +static int copy_chapters(InputFile *ifile, OutputFile *ofile, AVFormatContext *os, + int copy_metadata) { AVFormatContext *is = ifile->ctx; -AVFormatContext *os = ofile->ctx; AVChapter **tmp; int i; @@ -2168,14 +2168,14 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) return 0; } -static int set_dispositions(OutputFile *of) +static int set_dispositions(OutputFile *of, AVFormatContext *ctx) { int nb_streams[AVMEDIA_TYPE_NB] = { 0 }; int have_default[AVMEDIA_TYPE_NB] = { 0 }; int have_manual = 0; // first, copy the input dispositions -for (int i = 0; i< of->ctx->nb_streams; i++) { +for (int i = 0; i < ctx->nb_streams; i++) { OutputStream *ost = output_streams[of->ost_index + i]; nb_streams[ost->st->codecpar->codec_type]++; @@ -2192,7 +2192,7 @@ static int set_dispositions(OutputFile *of) if (have_manual) { // process manually set dispositions - they override the above copy -for (int i = 0; i< of->ctx->nb_streams; i++) { +for (int i = 0; i < ctx->nb_streams; i++) { OutputStream *ost = output_streams[of->ost_index + i]; int ret; @@ -2218,7 +2218,7 @@ static int set_dispositions(OutputFile *of) // For each media type with more than one stream, find a suitable stream to // mark as default, unless one is already marked default. // "Suitable" means the first of that type, skipping attached pictures. -for (int i = 0; i< of->ctx->nb_streams; i++) { +for (int i = 0; i < ctx->nb_streams; i++) { OutputStream *ost = output_streams[of->ost_index + i]; enum AVMediaType type = ost->st->codecpar->codec_type; @@ -2760,7 +2760,7 @@ loop_end: } } if (o->chapters_input_file >= 0) -copy_chapters(input_files[o->chapters_input_file], of, +copy_chapters(input_files[o->chapters_input_file], of, oc, !o->metadata_chapters_manual); /* copy global metadata by default */ @@ -2913,7 +2913,7 @@ loop_end: } } -err = set_dispositions(of); +err = set_dispositions(of, oc); if (err < 0) { av_log(NULL, AV_LOG_FATAL, "Error setting output stream dispositions\n"); exit_program(1); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 03/49] fftools/ffmpeg: stop using OutputStream.frame_number for streamcopy
This field is currently used by checks - skipping packets before the first keyframe - skipping packets before start time to test whether any packets have been output already. But since frame_number is incremented after the bitstream filters are applied (which may involve delay), this use is incorrect. The keyframe check works around this by adding an extra flag, the start-time check does not. Simplify both checks by replacing the seen_kf flag with a flag tracking whether any packets have been output by do_streamcopy(). --- fftools/ffmpeg.c | 10 +- fftools/ffmpeg.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 13be32f0cf..29b01f9d93 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -894,8 +894,6 @@ static void output_packet(OutputFile *of, AVPacket *pkt, /* apply the output bitstream filters */ if (ost->bsf_ctx) { -if (pkt->flags & AV_PKT_FLAG_KEY) -ost->seen_kf = 1; ret = av_bsf_send_packet(ost->bsf_ctx, eof ? NULL : pkt); if (ret < 0) goto finish; @@ -2043,11 +2041,11 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p return; } -if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && -!ost->copy_initial_nonkeyframes && !ost->seen_kf) +if (!ost->streamcopy_started && !(pkt->flags & AV_PKT_FLAG_KEY) && +!ost->copy_initial_nonkeyframes) return; -if (!ost->frame_number && !ost->copy_prior_start) { +if (!ost->streamcopy_started && !ost->copy_prior_start) { int64_t comp_start = start_time; if (copy_ts && f->start_time != AV_NOPTS_VALUE) comp_start = FFMAX(start_time, f->start_time + f->ts_offset); @@ -2101,6 +2099,8 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p ost->sync_opts += opkt->duration; output_packet(of, opkt, ost, 0); + +ost->streamcopy_started = 1; } int guess_input_channel_layout(InputStream *ist) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 1e14bf9fa9..04369df139 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -536,7 +536,7 @@ typedef struct OutputStream { int inputs_done; const char *attachment_filename; -int seen_kf; +int streamcopy_started; int copy_initial_nonkeyframes; int copy_prior_start; char *disposition; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 13/49] fftools/ffmpeg: refactor limiting output file size with -fs
Move the file size checking code to ffmpeg_mux. Use the recently introduced of_filesize(), making this code consistent with the size shown by print_report(). --- fftools/ffmpeg.c | 4 +--- fftools/ffmpeg.h | 4 ++-- fftools/ffmpeg_mux.c | 11 ++- fftools/ffmpeg_opt.c | 3 +-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 52dffa57bd..05e14c42c5 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3508,10 +3508,8 @@ static int need_output(void) for (i = 0; i < nb_output_streams; i++) { OutputStream *ost= output_streams[i]; OutputFile *of = output_files[ost->file_index]; -AVFormatContext *os = output_files[ost->file_index]->ctx; -if (ost->finished || -(os->pb && avio_tell(os->pb) >= of->limit_filesize)) +if (ost->finished || of_finished(of)) continue; if (ost->frame_number >= ost->max_frames) { int j; diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index d76f4266d6..c3b90ac9a2 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -589,7 +589,6 @@ typedef struct OutputFile { int ost_index; /* index of the first stream in output_streams */ int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units -int64_t limit_filesize; /* filesize limit expressed in bytes */ int shortest; } OutputFile; @@ -690,7 +689,7 @@ int hw_device_setup_for_filter(FilterGraph *fg); int hwaccel_decode_init(AVCodecContext *avctx); -int of_muxer_init(OutputFile *of); +int of_muxer_init(OutputFile *of, int64_t limit_filesize); /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); @@ -698,6 +697,7 @@ void of_close(OutputFile **pof); void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue); +int of_finished(OutputFile *of); int64_t of_filesize(OutputFile *of); #endif /* FFTOOLS_FFMPEG_H */ diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 930a7bdfe7..78bb338bce 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -33,6 +33,8 @@ #include "libavformat/avio.h" struct Muxer { +/* filesize limit expressed in bytes */ +int64_t limit_filesize; int header_written; }; @@ -335,7 +337,7 @@ void of_close(OutputFile **pof) av_freep(pof); } -int of_muxer_init(OutputFile *of) +int of_muxer_init(OutputFile *of, int64_t limit_filesize) { Muxer *mux = av_mallocz(sizeof(*mux)); @@ -344,9 +346,16 @@ int of_muxer_init(OutputFile *of) of->mux = mux; +mux->limit_filesize = limit_filesize; + return 0; } +int of_finished(OutputFile *of) +{ +return of_filesize(of) >= of->mux->limit_filesize; +} + int64_t of_filesize(OutputFile *of) { AVIOContext *pb = of->ctx->pb; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 4e601f1cf8..4a41ebc736 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2318,7 +2318,6 @@ static int open_output_file(OptionsContext *o, const char *filename) of->ost_index = nb_output_streams; of->recording_time = o->recording_time; of->start_time = o->start_time; -of->limit_filesize = o->limit_filesize; of->shortest = o->shortest; av_dict_copy(&of->opts, o->g->format_opts, 0); @@ -2921,7 +2920,7 @@ loop_end: exit_program(1); } -err = of_muxer_init(of); +err = of_muxer_init(of, o->limit_filesize); if (err < 0) { av_log(NULL, AV_LOG_FATAL, "Error initializing internal muxing state\n"); exit_program(1); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 14/49] fftools/ffmpeg: set want_sdp when initializing the muxer
Allows making the variable local to ffmpeg_mux. --- fftools/ffmpeg.c | 9 + fftools/ffmpeg.h | 1 - fftools/ffmpeg_mux.c | 5 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 05e14c42c5..688e1c7e56 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -139,8 +139,6 @@ static int nb_frames_drop = 0; static int64_t decode_error_stat[2]; unsigned nb_output_dumped = 0; -int want_sdp = 1; - static BenchmarkTimeStamps current_time; AVIOContext *progress_avio = NULL; @@ -4563,7 +4561,7 @@ static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl) int main(int argc, char **argv) { -int i, ret; +int ret; BenchmarkTimeStamps ti; init_dynload(); @@ -4606,11 +4604,6 @@ int main(int argc, char **argv) exit_program(1); } -for (i = 0; i < nb_output_files; i++) { -if (strcmp(output_files[i]->format->name, "rtp")) -want_sdp = 0; -} - current_time = ti = get_benchmark_time_stamps(); if (transcode() < 0) exit_program(1); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index c3b90ac9a2..d0ddaeaeff 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -649,7 +649,6 @@ extern char *qsv_device; #endif extern HWDevice *filter_hw_device; -extern int want_sdp; extern unsigned nb_output_dumped; extern int main_return_code; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 78bb338bce..f1ec5881c4 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -38,6 +38,8 @@ struct Muxer { int header_written; }; +static int want_sdp = 1; + static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others) { int i; @@ -348,6 +350,9 @@ int of_muxer_init(OutputFile *of, int64_t limit_filesize) mux->limit_filesize = limit_filesize; +if (strcmp(of->format->name, "rtp")) +want_sdp = 0; + return 0; } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 16/49] fftools/ffmpeg: move closing the file into of_write_trailer()
The current code postpones closing the files until after printing the final report, which accesses the output file size. Deal with this by storing the final file size before closing the file. --- fftools/ffmpeg.c | 13 - fftools/ffmpeg_mux.c | 16 +++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index e862a57215..252b14a710 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -4358,7 +4358,6 @@ static int transcode_step(void) static int transcode(void) { int ret, i; -AVFormatContext *os; OutputStream *ost; InputStream *ist; int64_t timer_start; @@ -4427,18 +4426,6 @@ static int transcode(void) /* dump report by using the first video and audio streams */ print_report(1, timer_start, av_gettime_relative()); -/* close the output files */ -for (i = 0; i < nb_output_files; i++) { -os = output_files[i]->ctx; -if (os && os->oformat && !(os->oformat->flags & AVFMT_NOFILE)) { -if ((ret = avio_closep(&os->pb)) < 0) { -av_log(NULL, AV_LOG_ERROR, "Error closing file %s: %s\n", os->url, av_err2str(ret)); -if (exit_on_error) -exit_program(1); -} -} -} - /* close each encoder */ for (i = 0; i < nb_output_streams; i++) { ost = output_streams[i]; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 2a95b2602d..927d9228b7 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -35,6 +35,7 @@ struct Muxer { /* filesize limit expressed in bytes */ int64_t limit_filesize; +int64_t final_filesize; int header_written; }; @@ -317,6 +318,17 @@ int of_write_trailer(OutputFile *of) return ret; } +of->mux->final_filesize = of_filesize(of); + +if (!(of->format->flags & AVFMT_NOFILE)) { +ret = avio_closep(&of->ctx->pb); +if (ret < 0) { +av_log(NULL, AV_LOG_ERROR, "Error closing file %s: %s\n", + of->ctx->url, av_err2str(ret)); +return ret; +} +} + return 0; } @@ -373,7 +385,9 @@ int64_t of_filesize(OutputFile *of) AVIOContext *pb = of->ctx->pb; int64_t ret = -1; -if (pb) { +if (of->mux->final_filesize) +ret = of->mux->final_filesize; +else if (pb) { ret = avio_size(pb); if (ret <= 0) // FIXME improve avio_size() so it works with non seekable output too ret = avio_tell(pb); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 06/49] fftools/ffmpeg: move some muxing-related code into a separate file
This is a first step towards making muxers more independent from the rest of the code. --- fftools/Makefile | 6 +- fftools/ffmpeg.c | 272 ++-- fftools/ffmpeg.h | 10 ++ fftools/ffmpeg_mux.c | 292 +++ 4 files changed, 314 insertions(+), 266 deletions(-) create mode 100644 fftools/ffmpeg_mux.c diff --git a/fftools/Makefile b/fftools/Makefile index 5ebf50d42e..81ad6c4f4f 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -9,7 +9,11 @@ AVBASENAMES = ffmpeg ffplay ffprobe ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF)) ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF)) -OBJS-ffmpeg+= fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o +OBJS-ffmpeg += \ +fftools/ffmpeg_filter.o \ +fftools/ffmpeg_hw.o \ +fftools/ffmpeg_mux.o\ +fftools/ffmpeg_opt.o\ define DOFFTOOL OBJS-$(1) += fftools/cmdutils.o fftools/opt_common.o fftools/$(1).o $(OBJS-$(1)-yes) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index bc700052b6..47724f7231 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -137,9 +137,9 @@ static int nb_frames_dup = 0; static unsigned dup_warning = 1000; static int nb_frames_drop = 0; static int64_t decode_error_stat[2]; -static unsigned nb_output_dumped = 0; +unsigned nb_output_dumped = 0; -static int want_sdp = 1; +int want_sdp = 1; static BenchmarkTimeStamps current_time; AVIOContext *progress_avio = NULL; @@ -345,7 +345,7 @@ static volatile int received_sigterm = 0; static volatile int received_nb_signals = 0; static atomic_int transcode_init_done = ATOMIC_VAR_INIT(0); static volatile int ffmpeg_exited = 0; -static int main_return_code = 0; +int main_return_code = 0; static int64_t copy_ts_first_pts = AV_NOPTS_VALUE; static void @@ -711,159 +711,6 @@ static void update_benchmark(const char *fmt, ...) } } -static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others) -{ -int i; -for (i = 0; i < nb_output_streams; i++) { -OutputStream *ost2 = output_streams[i]; -ost2->finished |= ost == ost2 ? this_stream : others; -} -} - -static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue) -{ -AVFormatContext *s = of->ctx; -AVStream *st = ost->st; -int ret; - -/* - * Audio encoders may split the packets -- #frames in != #packets out. - * But there is no reordering, so we can limit the number of output packets - * by simply dropping them here. - * Counting encoded video frames needs to be done separately because of - * reordering, see do_video_out(). - * Do not count the packet when unqueued because it has been counted when queued. - */ -if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) && !unqueue) { -if (ost->frame_number >= ost->max_frames) { -av_packet_unref(pkt); -return; -} -ost->frame_number++; -} - -if (!of->header_written) { -AVPacket *tmp_pkt; -/* the muxer is not initialized yet, buffer the packet */ -if (!av_fifo_can_write(ost->muxing_queue)) { -size_t cur_size = av_fifo_can_read(ost->muxing_queue); -unsigned int are_we_over_size = -(ost->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold; -size_t limit= are_we_over_size ? ost->max_muxing_queue_size : SIZE_MAX; -size_t new_size = FFMIN(2 * cur_size, limit); - -if (new_size <= cur_size) { -av_log(NULL, AV_LOG_ERROR, - "Too many packets buffered for output stream %d:%d.\n", - ost->file_index, ost->st->index); -exit_program(1); -} -ret = av_fifo_grow2(ost->muxing_queue, new_size - cur_size); -if (ret < 0) -exit_program(1); -} -ret = av_packet_make_refcounted(pkt); -if (ret < 0) -exit_program(1); -tmp_pkt = av_packet_alloc(); -if (!tmp_pkt) -exit_program(1); -av_packet_move_ref(tmp_pkt, pkt); -ost->muxing_queue_data_size += tmp_pkt->size; -av_fifo_write(ost->muxing_queue, &tmp_pkt, 1); -return; -} - -if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) || -(st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0)) -pkt->pts = pkt->dts = AV_NOPTS_VALUE; - -if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { -int i; -uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, - NULL); -ost->quality = sd ? AV_RL32(sd) : -1; -ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE; - -
[FFmpeg-devel] [PATCH 15/49] fftools/ffmpeg: write the header for stream-less outputs when initializing the muxer
There is no reason to delay this. --- fftools/ffmpeg.c | 11 --- fftools/ffmpeg_mux.c | 7 +++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 688e1c7e56..e862a57215 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3320,7 +3320,6 @@ static void report_new_stream(int input_index, AVPacket *pkt) static int transcode_init(void) { int ret = 0, i, j, k; -AVFormatContext *oc; OutputStream *ost; InputStream *ist; char error[1024] = {0}; @@ -3394,16 +3393,6 @@ static int transcode_init(void) } } -/* write headers for files with no streams */ -for (i = 0; i < nb_output_files; i++) { -oc = output_files[i]->ctx; -if (output_files[i]->format->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) { -ret = of_check_init(output_files[i]); -if (ret < 0) -goto dump_format; -} -} - dump_format: /* dump the stream mapping */ av_log(NULL, AV_LOG_INFO, "Stream mapping:\n"); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index f1ec5881c4..2a95b2602d 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -353,6 +353,13 @@ int of_muxer_init(OutputFile *of, int64_t limit_filesize) if (strcmp(of->format->name, "rtp")) want_sdp = 0; +/* write the header for files with no streams */ +if (of->format->flags & AVFMT_NOSTREAMS && of->ctx->nb_streams == 0) { +int ret = of_check_init(of); +if (ret < 0) +return ret; +} + return 0; } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 22/49] fftools/ffmpeg_mux: split of_write_packet()
It is currently called from two places: - output_packet() in ffmpeg.c, which submits the newly available output packet to the muxer - from of_check_init() in ffmpeg_mux.c after the header has been written, to flush the muxing queue Some packets will thus be processed by this function twice, so it requires an extra parameter to indicate the place it is called from and avoid modifying some state twice. This is fragile and hard to follow, so split this function into two. Also rename of_write_packet() to of_submit_packet() to better reflect its new purpose. --- fftools/ffmpeg.c | 4 +-- fftools/ffmpeg.h | 3 +-- fftools/ffmpeg_mux.c | 63 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index b240bbd984..ef0d5156eb 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -726,11 +726,11 @@ static void output_packet(OutputFile *of, AVPacket *pkt, if (ret < 0) goto finish; while ((ret = av_bsf_receive_packet(ost->bsf_ctx, pkt)) >= 0) -of_write_packet(of, pkt, ost, 0); +of_submit_packet(of, pkt, ost); if (ret == AVERROR(EAGAIN)) ret = 0; } else if (!eof) -of_write_packet(of, pkt, ost, 0); +of_submit_packet(of, pkt, ost); finish: if (ret < 0 && ret != AVERROR_EOF) { diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index f0c3a3de7c..5f002521ab 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -687,8 +687,7 @@ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); void of_close(OutputFile **pof); -void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, - int unqueue); +void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost); int of_finished(OutputFile *of); int64_t of_filesize(OutputFile *of); AVChapter * const * diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index e7b0a9ca99..2b85d55504 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -102,39 +102,12 @@ static int queue_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) return 0; } -void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, - int unqueue) +static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) { AVFormatContext *s = of->ctx; AVStream *st = ost->st; int ret; -/* - * Audio encoders may split the packets -- #frames in != #packets out. - * But there is no reordering, so we can limit the number of output packets - * by simply dropping them here. - * Counting encoded video frames needs to be done separately because of - * reordering, see do_video_out(). - * Do not count the packet when unqueued because it has been counted when queued. - */ -if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) && !unqueue) { -if (ost->frame_number >= ost->max_frames) { -av_packet_unref(pkt); -return; -} -ost->frame_number++; -} - -/* the muxer is not initialized yet, buffer the packet */ -if (!of->mux->header_written) { -ret = queue_packet(of, ost, pkt); -if (ret < 0) { -av_packet_unref(pkt); -exit_program(1); -} -return; -} - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) || (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0)) pkt->pts = pkt->dts = AV_NOPTS_VALUE; @@ -225,6 +198,38 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, } } +void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) +{ +AVStream *st = ost->st; +int ret; + +/* + * Audio encoders may split the packets -- #frames in != #packets out. + * But there is no reordering, so we can limit the number of output packets + * by simply dropping them here. + * Counting encoded video frames needs to be done separately because of + * reordering, see do_video_out(). + */ +if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) { +if (ost->frame_number >= ost->max_frames) { +av_packet_unref(pkt); +return; +} +ost->frame_number++; +} + +if (of->mux->header_written) { +write_packet(of, ost, pkt); +} else { +/* the muxer is not initialized yet, buffer the packet */ +ret = queue_packet(of, ost, pkt); +if (ret < 0) { +av_packet_unref(pkt); +exit_program(1); +} +} +} + static int print_sdp(void) { char sdp[16384]; @@ -323,7 +328,7 @@ int of_check_init(OutputFile *of) while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0) { ms->muxing_queue_data_size -= pkt->size; -of_write_pac
[FFmpeg-devel] [PATCH 11/49] fftools/ffmpeg: add a helper function to access output file size
Stop accessing muxer internals from outside of ffmpeg_mux. --- fftools/ffmpeg.c | 10 +- fftools/ffmpeg.h | 1 + fftools/ffmpeg_mux.c | 14 ++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index a85ed18b08..52dffa57bd 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1513,8 +1513,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti { AVBPrint buf, buf_script; OutputStream *ost; -AVFormatContext *oc; -int64_t total_size; +int64_t total_size = of_filesize(output_files[0]); AVCodecContext *enc; int frame_number, vid, i; double bitrate; @@ -1543,13 +1542,6 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti t = (cur_time-timer_start) / 100.0; - -oc = output_files[0]->ctx; - -total_size = avio_size(oc->pb); -if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too -total_size = avio_tell(oc->pb); - vid = 0; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 3db03e0cfe..fa7b202ae6 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -698,5 +698,6 @@ void of_close(OutputFile **pof); void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue); +int64_t of_filesize(OutputFile *of); #endif /* FFTOOLS_FFMPEG_H */ diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 84c94e46be..930a7bdfe7 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -346,3 +346,17 @@ int of_muxer_init(OutputFile *of) return 0; } + +int64_t of_filesize(OutputFile *of) +{ +AVIOContext *pb = of->ctx->pb; +int64_t ret = -1; + +if (pb) { +ret = avio_size(pb); +if (ret <= 0) // FIXME improve avio_size() so it works with non seekable output too +ret = avio_tell(pb); +} + +return ret; +} -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 21/49] fftools/ffmpeg_mux: split queuing packets into a separate function
--- fftools/ffmpeg_mux.c | 72 +++- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 33cea56c62..e7b0a9ca99 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -63,12 +63,50 @@ static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, } } +static int queue_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) +{ +MuxStream *ms = &of->mux->streams[ost->index]; +AVPacket *tmp_pkt; +int ret; + +if (!av_fifo_can_write(ms->muxing_queue)) { +size_t cur_size = av_fifo_can_read(ms->muxing_queue); +unsigned int are_we_over_size = +(ms->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold; +size_t limit= are_we_over_size ? ost->max_muxing_queue_size : SIZE_MAX; +size_t new_size = FFMIN(2 * cur_size, limit); + +if (new_size <= cur_size) { +av_log(NULL, AV_LOG_ERROR, + "Too many packets buffered for output stream %d:%d.\n", + ost->file_index, ost->st->index); +return AVERROR(ENOSPC); +} +ret = av_fifo_grow2(ms->muxing_queue, new_size - cur_size); +if (ret < 0) +return ret; +} + +ret = av_packet_make_refcounted(pkt); +if (ret < 0) +return ret; + +tmp_pkt = av_packet_alloc(); +if (!tmp_pkt) +return AVERROR(ENOMEM); + +av_packet_move_ref(tmp_pkt, pkt); +ms->muxing_queue_data_size += tmp_pkt->size; +av_fifo_write(ms->muxing_queue, &tmp_pkt, 1); + +return 0; +} + void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue) { AVFormatContext *s = of->ctx; AVStream *st = ost->st; -MuxStream *ms = &of->mux->streams[st->index]; int ret; /* @@ -87,35 +125,13 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, ost->frame_number++; } +/* the muxer is not initialized yet, buffer the packet */ if (!of->mux->header_written) { -AVPacket *tmp_pkt; -/* the muxer is not initialized yet, buffer the packet */ -if (!av_fifo_can_write(ms->muxing_queue)) { -size_t cur_size = av_fifo_can_read(ms->muxing_queue); -unsigned int are_we_over_size = -(ms->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold; -size_t limit= are_we_over_size ? ost->max_muxing_queue_size : SIZE_MAX; -size_t new_size = FFMIN(2 * cur_size, limit); - -if (new_size <= cur_size) { -av_log(NULL, AV_LOG_ERROR, - "Too many packets buffered for output stream %d:%d.\n", - ost->file_index, ost->st->index); -exit_program(1); -} -ret = av_fifo_grow2(ms->muxing_queue, new_size - cur_size); -if (ret < 0) -exit_program(1); -} -ret = av_packet_make_refcounted(pkt); -if (ret < 0) -exit_program(1); -tmp_pkt = av_packet_alloc(); -if (!tmp_pkt) +ret = queue_packet(of, ost, pkt); +if (ret < 0) { +av_packet_unref(pkt); exit_program(1); -av_packet_move_ref(tmp_pkt, pkt); -ms->muxing_queue_data_size += tmp_pkt->size; -av_fifo_write(ms->muxing_queue, &tmp_pkt, 1); +} return; } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 24/49] fftools/ffmpeg: move processing video stats to ffmpeg_mux
Currently it is called from - do_video_out(), at the end of each encode loop iteration - from flush_encoders(), after muxing each packet Since this function processes the data from the last encoded packet, neither of the above is fully correct, because - an encoder can in principle produce multiple packets per one submitted frame - bitstream filters may modify the number of encoded packets or their properties. It thus makes most sense to call this function right before sending the packet to the muxer. --- fftools/ffmpeg.c | 61 +--- fftools/ffmpeg.h | 5 fftools/ffmpeg_mux.c | 47 ++ 3 files changed, 53 insertions(+), 60 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index ef0d5156eb..68e720d889 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -110,7 +110,7 @@ const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; -static FILE *vstats_file; +FILE *vstats_file; const char *const forced_keyframes_const_names[] = { "n", @@ -127,7 +127,6 @@ typedef struct BenchmarkTimeStamps { int64_t sys_usec; } BenchmarkTimeStamps; -static void do_video_stats(OutputStream *ost, int frame_size); static BenchmarkTimeStamps get_benchmark_time_stamps(void); static int64_t getmaxrss(void); static int ifilter_has_all_input_formats(FilterGraph *fg); @@ -977,7 +976,6 @@ static void do_video_out(OutputFile *of, double delta, delta0; double duration = 0; double sync_ipts = AV_NOPTS_VALUE; -int frame_size = 0; InputStream *ist = NULL; AVFilterContext *filter = ost->filter->filter; @@ -1214,7 +1212,6 @@ static void do_video_out(OutputFile *of, av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ost->mux_timebase)); } -frame_size = pkt->size; output_packet(of, pkt, ost, 0); /* if two pass, output log */ @@ -1224,9 +1221,6 @@ static void do_video_out(OutputFile *of, } ost->sync_opts++; ost->frame_number++; - -if (vstats_filename && frame_size) -do_video_stats(ost, frame_size); } av_frame_unref(ost->last_frame); @@ -1239,54 +1233,6 @@ error: exit_program(1); } -static double psnr(double d) -{ -return -10.0 * log10(d); -} - -static void do_video_stats(OutputStream *ost, int frame_size) -{ -AVCodecContext *enc; -int frame_number; -double ti1, bitrate, avg_bitrate; - -/* this is executed just the first time do_video_stats is called */ -if (!vstats_file) { -vstats_file = fopen(vstats_filename, "w"); -if (!vstats_file) { -perror("fopen"); -exit_program(1); -} -} - -enc = ost->enc_ctx; -if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { -frame_number = ost->st->nb_frames; -if (vstats_version <= 1) { -fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, -ost->quality / (float)FF_QP2LAMBDA); -} else { -fprintf(vstats_file, "out= %2d st= %2d frame= %5d q= %2.1f ", ost->file_index, ost->index, frame_number, -ost->quality / (float)FF_QP2LAMBDA); -} - -if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR)) -fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0))); - -fprintf(vstats_file,"f_size= %6d ", frame_size); -/* compute pts value */ -ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base); -if (ti1 < 0.01) -ti1 = 0.01; - -bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; -avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0; -fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", - (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); -fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type)); -} -} - static void finish_output_stream(OutputStream *ost) { OutputFile *of = output_files[ost->file_index]; @@ -1773,7 +1719,6 @@ static void flush_encoders(void) for (;;) { const char *desc = NULL; AVPacket *pkt = ost->pkt; -int pkt_size; switch (enc->codec_type) { case AVMEDIA_TYPE_AUDIO: @@ -1817,11 +1762,7 @@ static void flush_encoders(void) continue; } av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); -pkt_size = pkt->size; output_packet(of, pkt, ost, 0); -if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) { -do_video_stats(ost, pkt_size); -} } } } diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index c6bbc653b8..604f0145e3 100644 --- a/fftools/ffmpeg
[FFmpeg-devel] [PATCH 17/49] fftools/ffmpeg: refactor the code checking for bitexact output
Figure out earlier whether the output stream/file should be bitexact and store this information in a flag in OutputFile/OutputStream. Stop accessing the muxer in set_encoder_id(), which will become forbidden in future commits. --- fftools/ffmpeg.c | 21 + fftools/ffmpeg.h | 2 ++ fftools/ffmpeg_opt.c | 27 ++- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 252b14a710..dfd57d2d03 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -2870,37 +2870,18 @@ static int init_output_stream_streamcopy(OutputStream *ost) static void set_encoder_id(OutputFile *of, OutputStream *ost) { -const AVDictionaryEntry *e; - uint8_t *encoder_string; int encoder_string_len; -int format_flags = 0; -int codec_flags = ost->enc_ctx->flags; if (av_dict_get(ost->st->metadata, "encoder", NULL, 0)) return; -e = av_dict_get(of->opts, "fflags", NULL, 0); -if (e) { -const AVOption *o = av_opt_find(of->ctx, "fflags", NULL, 0, 0); -if (!o) -return; -av_opt_eval_flags(of->ctx, o, e->value, &format_flags); -} -e = av_dict_get(ost->encoder_opts, "flags", NULL, 0); -if (e) { -const AVOption *o = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0); -if (!o) -return; -av_opt_eval_flags(ost->enc_ctx, o, e->value, &codec_flags); -} - encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2; encoder_string = av_mallocz(encoder_string_len); if (!encoder_string) exit_program(1); -if (!(format_flags & AVFMT_FLAG_BITEXACT) && !(codec_flags & AV_CODEC_FLAG_BITEXACT)) +if (!of->bitexact && !ost->bitexact) av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); else av_strlcpy(encoder_string, "Lavc ", encoder_string_len); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index d0ddaeaeff..ec0d454fcc 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -493,6 +493,7 @@ typedef struct OutputStream { int top_field_first; int rotate_overridden; int autoscale; +int bitexact; int bits_per_raw_sample; double rotate_override_value; @@ -591,6 +592,7 @@ typedef struct OutputFile { int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units int shortest; +int bitexact; } OutputFile; extern InputStream **input_streams; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 4a41ebc736..780c11903b 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -1437,6 +1437,22 @@ static int choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *o return 0; } +static int check_opt_bitexact(void *ctx, const AVDictionary *opts, + const char *opt_name, int flag) +{ +const AVDictionaryEntry *e = av_dict_get(opts, opt_name, NULL, 0); + +if (e) { +const AVOption *o = av_opt_find(ctx, opt_name, NULL, 0, 0); +int val = 0; +if (!o) +return 0; +av_opt_eval_flags(ctx, o, e->value, &val); +return !!(val & flag); +} +return 0; +} + static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index) { OutputStream *ost; @@ -1529,8 +1545,13 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e } -if (o->bitexact) +if (o->bitexact) { ost->enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT; +ost->bitexact= 1; +} else { +ost->bitexact= check_opt_bitexact(ost->enc_ctx, ost->encoder_opts, "flags", + AV_CODEC_FLAG_BITEXACT); +} MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st); if (time_base) { @@ -2339,6 +2360,10 @@ static int open_output_file(OptionsContext *o, const char *filename) if (o->bitexact) { oc->flags|= AVFMT_FLAG_BITEXACT; +of->bitexact = 1; +} else { +of->bitexact = check_opt_bitexact(oc, of->opts, "fflags", + AVFMT_FLAG_BITEXACT); } /* create streams for all unlabeled output pads */ -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 20/49] fftools/ffmpeg: move the mux queue into muxer private data
The muxing queue currently lives in OutputStream, which is a very large struct storing the state for both encoding and muxing. The muxing queue is only used by the code in ffmpeg_mux, so it makes sense to restrict it to that file. This makes the first step towards reducing the scope of OutputStream. --- fftools/ffmpeg.c | 7 fftools/ffmpeg.h | 9 - fftools/ffmpeg_mux.c | 87 +--- fftools/ffmpeg_opt.c | 9 - 4 files changed, 73 insertions(+), 39 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index a9a62eb8c3..b240bbd984 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -593,13 +593,6 @@ static void ffmpeg_cleanup(int ret) avcodec_free_context(&ost->enc_ctx); avcodec_parameters_free(&ost->ref_par); -if (ost->muxing_queue) { -AVPacket *pkt; -while (av_fifo_read(ost->muxing_queue, &pkt, 1) >= 0) -av_packet_free(&pkt); -av_fifo_freep2(&ost->muxing_queue); -} - av_freep(&output_streams[i]); } #if HAVE_THREADS diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 8e34ae0702..f0c3a3de7c 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -558,15 +558,6 @@ typedef struct OutputStream { int max_muxing_queue_size; -/* the packets are buffered here until the muxer is ready to be initialized */ -AVFifo *muxing_queue; - -/* - * The size of the AVPackets' buffers in queue. - * Updated when a packet is either pushed or pulled from the queue. - */ -size_t muxing_queue_data_size; - /* Threshold after which max_muxing_queue_size will be in effect */ size_t muxing_queue_data_threshold; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 9dd5e8b076..33cea56c62 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -32,7 +32,20 @@ #include "libavformat/avformat.h" #include "libavformat/avio.h" +typedef struct MuxStream { +/* the packets are buffered here until the muxer is ready to be initialized */ +AVFifo *muxing_queue; + +/* + * The size of the AVPackets' buffers in queue. + * Updated when a packet is either pushed or pulled from the queue. + */ +size_t muxing_queue_data_size; +} MuxStream; + struct Muxer { +MuxStream *streams; + /* filesize limit expressed in bytes */ int64_t limit_filesize; int64_t final_filesize; @@ -55,6 +68,7 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, { AVFormatContext *s = of->ctx; AVStream *st = ost->st; +MuxStream *ms = &of->mux->streams[st->index]; int ret; /* @@ -76,10 +90,10 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, if (!of->mux->header_written) { AVPacket *tmp_pkt; /* the muxer is not initialized yet, buffer the packet */ -if (!av_fifo_can_write(ost->muxing_queue)) { -size_t cur_size = av_fifo_can_read(ost->muxing_queue); +if (!av_fifo_can_write(ms->muxing_queue)) { +size_t cur_size = av_fifo_can_read(ms->muxing_queue); unsigned int are_we_over_size = -(ost->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold; +(ms->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold; size_t limit= are_we_over_size ? ost->max_muxing_queue_size : SIZE_MAX; size_t new_size = FFMIN(2 * cur_size, limit); @@ -89,7 +103,7 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, ost->file_index, ost->st->index); exit_program(1); } -ret = av_fifo_grow2(ost->muxing_queue, new_size - cur_size); +ret = av_fifo_grow2(ms->muxing_queue, new_size - cur_size); if (ret < 0) exit_program(1); } @@ -100,8 +114,8 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, if (!tmp_pkt) exit_program(1); av_packet_move_ref(tmp_pkt, pkt); -ost->muxing_queue_data_size += tmp_pkt->size; -av_fifo_write(ost->muxing_queue, &tmp_pkt, 1); +ms->muxing_queue_data_size += tmp_pkt->size; +av_fifo_write(ms->muxing_queue, &tmp_pkt, 1); return; } @@ -283,15 +297,16 @@ int of_check_init(OutputFile *of) /* flush the muxing queues */ for (i = 0; i < of->ctx->nb_streams; i++) { +MuxStream *ms = &of->mux->streams[i]; OutputStream *ost = output_streams[of->ost_index + i]; AVPacket *pkt; /* try to improve muxing time_base (only possible if nothing has been written yet) */ -if (!av_fifo_can_read(ost->muxing_queue)) +if (!av_fifo_can_read(ms->muxing_queue)) ost->mux_timebase = ost->st->time_base; -while (av_fifo_read(ost->muxing_queue, &pkt, 1) >= 0) { -
[FFmpeg-devel] [PATCH 19/49] fftools/ffmpeg: do not log to the muxer context
All other logging goes to NULL context. --- fftools/ffmpeg.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index b9ecbf4739..a9a62eb8c3 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -2960,7 +2960,6 @@ static void init_encoder_time_base(OutputStream *ost, AVRational default_time_ba { InputStream *ist = get_input_stream(ost); AVCodecContext *enc_ctx = ost->enc_ctx; -AVFormatContext *oc; if (ost->enc_timebase.num > 0) { enc_ctx->time_base = ost->enc_timebase; @@ -2973,8 +2972,9 @@ static void init_encoder_time_base(OutputStream *ost, AVRational default_time_ba return; } -oc = output_files[ost->file_index]->ctx; -av_log(oc, AV_LOG_WARNING, "Input stream data not available, using default time base\n"); +av_log(NULL, AV_LOG_WARNING, + "Input stream data for output stream #%d:%d not available, " + "using default time base\n", ost->file_index, ost->index); } enc_ctx->time_base = default_time_base; @@ -2986,7 +2986,6 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) AVCodecContext *enc_ctx = ost->enc_ctx; AVCodecContext *dec_ctx = NULL; OutputFile *of = output_files[ost->file_index]; -AVFormatContext *oc = of->ctx; int ret; set_encoder_id(output_files[ost->file_index], ost); @@ -3049,8 +3048,9 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) if ( av_q2d(enc_ctx->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR || (video_sync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS{ -av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n" - "Please consider specifying a lower framerate, a different muxer or -vsync 2\n"); +av_log(NULL, AV_LOG_WARNING, "Frame rate in output stream #%d:%d very high for a muxer not efficiently supporting it.\n" + "Please consider specifying a lower framerate, a different muxer or -vsync 2\n", + ost->file_index, ost->index); } enc_ctx->width = av_buffersink_get_w(ost->filter->filter); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 18/49] fftools/ffmpeg: access output file chapters through a wrapper
Avoid accessing the muxer context directly, as this will become forbidden in future commits. --- fftools/ffmpeg.c | 15 +-- fftools/ffmpeg.h | 2 ++ fftools/ffmpeg_mux.c | 7 +++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index dfd57d2d03..b9ecbf4739 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -2915,12 +2915,15 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost, *next++ = 0; if (!memcmp(p, "chapters", 8)) { - -AVFormatContext *avf = output_files[ost->file_index]->ctx; +OutputFile *of = output_files[ost->file_index]; +AVChapter * const *ch; +unsigned intnb_ch; int j; -if (avf->nb_chapters > INT_MAX - size || -!(pts = av_realloc_f(pts, size += avf->nb_chapters - 1, +ch = of_get_chapters(of, &nb_ch); + +if (nb_ch > INT_MAX - size || +!(pts = av_realloc_f(pts, size += nb_ch - 1, sizeof(*pts { av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); @@ -2929,8 +2932,8 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost, t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0; t = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base); -for (j = 0; j < avf->nb_chapters; j++) { -AVChapter *c = avf->chapters[j]; +for (j = 0; j < nb_ch; j++) { +const AVChapter *c = ch[j]; av_assert1(index < size); pts[index++] = av_rescale_q(c->start, c->time_base, avctx->time_base) + t; diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index ec0d454fcc..8e34ae0702 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -700,5 +700,7 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue); int of_finished(OutputFile *of); int64_t of_filesize(OutputFile *of); +AVChapter * const * +of_get_chapters(OutputFile *of, unsigned int *nb_chapters); #endif /* FFTOOLS_FFMPEG_H */ diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 927d9228b7..9dd5e8b076 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -395,3 +395,10 @@ int64_t of_filesize(OutputFile *of) return ret; } + +AVChapter * const * +of_get_chapters(OutputFile *of, unsigned int *nb_chapters) +{ +*nb_chapters = of->ctx->nb_chapters; +return of->ctx->chapters; +} -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 08/49] fftools/ffmpeg: move freeing the output file to ffmpeg_mux.c
--- fftools/ffmpeg.c | 14 ++ fftools/ffmpeg.h | 1 + fftools/ffmpeg_mux.c | 17 + 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index cc7855a4cc..69d1949103 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -565,19 +565,9 @@ static void ffmpeg_cleanup(int ret) av_freep(&subtitle_out); /* close files */ -for (i = 0; i < nb_output_files; i++) { -OutputFile *of = output_files[i]; -AVFormatContext *s; -if (!of) -continue; -s = of->ctx; -if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE)) -avio_closep(&s->pb); -avformat_free_context(s); -av_dict_free(&of->opts); +for (i = 0; i < nb_output_files; i++) +of_close(&output_files[i]); -av_freep(&output_files[i]); -} for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 4425b7a874..ff8ebbfab5 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -690,6 +690,7 @@ int hwaccel_decode_init(AVCodecContext *avctx); /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); +void of_close(OutputFile **pof); void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 5348eef01d..3cdaa494d7 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -311,3 +311,20 @@ int of_write_trailer(OutputFile *of) return 0; } + +void of_close(OutputFile **pof) +{ +OutputFile *of = *pof; +AVFormatContext *s; + +if (!of) +return; + +s = of->ctx; +if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE)) +avio_closep(&s->pb); +avformat_free_context(s); +av_dict_free(&of->opts); + +av_freep(pof); +} -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 05/49] fftools/ffmpeg: store the output file index in OutputFile
Use it to simplify check_init_output_file(). Will allow further simplifications in the following commits. --- fftools/ffmpeg.c | 10 +- fftools/ffmpeg.h | 2 ++ fftools/ffmpeg_opt.c | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 29b01f9d93..bc700052b6 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -2947,7 +2947,7 @@ static int compare_int64(const void *a, const void *b) } /* open the muxer when all the streams are initialized */ -static int check_init_output_file(OutputFile *of, int file_index) +static int check_init_output_file(OutputFile *of) { int ret, i; @@ -2962,13 +2962,13 @@ static int check_init_output_file(OutputFile *of, int file_index) av_log(NULL, AV_LOG_ERROR, "Could not write header for output file #%d " "(incorrect codec parameters ?): %s\n", - file_index, av_err2str(ret)); + of->index, av_err2str(ret)); return ret; } //assert_avoptions(of->opts); of->header_written = 1; -av_dump_format(of->ctx, file_index, of->ctx->url, 1); +av_dump_format(of->ctx, of->index, of->ctx->url, 1); nb_output_dumped++; if (sdp_filename || want_sdp) { @@ -3571,7 +3571,7 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, ost->initialized = 1; -ret = check_init_output_file(output_files[ost->file_index], ost->file_index); +ret = check_init_output_file(output_files[ost->file_index]); if (ret < 0) return ret; @@ -3674,7 +3674,7 @@ static int transcode_init(void) for (i = 0; i < nb_output_files; i++) { oc = output_files[i]->ctx; if (oc->oformat->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) { -ret = check_init_output_file(output_files[i], i); +ret = check_init_output_file(output_files[i]); if (ret < 0) goto dump_format; } diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 04369df139..0eee6f4da8 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -577,6 +577,8 @@ typedef struct OutputStream { } OutputStream; typedef struct OutputFile { +int index; + AVFormatContext *ctx; AVDictionary *opts; int ost_index; /* index of the first stream in output_streams */ diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 8e217af4ab..daecba9e57 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2314,6 +2314,7 @@ static int open_output_file(OptionsContext *o, const char *filename) of = ALLOC_ARRAY_ELEM(output_files, nb_output_files); +of->index = nb_output_files - 1; of->ost_index = nb_output_streams; of->recording_time = o->recording_time; of->start_time = o->start_time; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 07/49] fftools/ffmpeg: move writing the trailer to ffmpeg_mux.c
--- fftools/ffmpeg.c | 16 +++- fftools/ffmpeg.h | 1 + fftools/ffmpeg_mux.c | 21 + 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 47724f7231..cc7855a4cc 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -4450,19 +4450,9 @@ static int transcode(void) /* write the trailer if needed */ for (i = 0; i < nb_output_files; i++) { -os = output_files[i]->ctx; -if (!output_files[i]->header_written) { -av_log(NULL, AV_LOG_ERROR, - "Nothing was written into output file %d (%s), because " - "at least one of its streams received no packets.\n", - i, os->url); -continue; -} -if ((ret = av_write_trailer(os)) < 0) { -av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", os->url, av_err2str(ret)); -if (exit_on_error) -exit_program(1); -} +ret = of_write_trailer(output_files[i]); +if (ret < 0 && exit_on_error) +exit_program(1); } /* dump report by using the first video and audio streams */ diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index cb475bb690..4425b7a874 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -689,6 +689,7 @@ int hwaccel_decode_init(AVCodecContext *avctx); /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of); +int of_write_trailer(OutputFile *of); void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 92d8a8c088..5348eef01d 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -290,3 +290,24 @@ int of_check_init(OutputFile *of) return 0; } + +int of_write_trailer(OutputFile *of) +{ +int ret; + +if (!of->header_written) { +av_log(NULL, AV_LOG_ERROR, + "Nothing was written into output file %d (%s), because " + "at least one of its streams received no packets.\n", + of->index, of->ctx->url); +return AVERROR(EINVAL); +} + +ret = av_write_trailer(of->ctx); +if (ret < 0) { +av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", of->ctx->url, av_err2str(ret)); +return ret; +} + +return 0; +} -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 10/49] fftools/ffmpeg_mux: add private muxer context
Move header_written into it, which is not (and should not be) used by any code outside of ffmpeg_mux. In the future this context will contain more muxer-private state that should not be visible to other code. --- fftools/ffmpeg.h | 6 -- fftools/ffmpeg_mux.c | 26 ++ fftools/ffmpeg_opt.c | 6 ++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 9f0c093e34..3db03e0cfe 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -576,9 +576,12 @@ typedef struct OutputStream { int64_t error[4]; } OutputStream; +typedef struct Muxer Muxer; + typedef struct OutputFile { int index; +Muxer*mux; const AVOutputFormat *format; AVFormatContext *ctx; @@ -589,8 +592,6 @@ typedef struct OutputFile { uint64_t limit_filesize; /* filesize limit expressed in bytes */ int shortest; - -int header_written; } OutputFile; extern InputStream **input_streams; @@ -689,6 +690,7 @@ int hw_device_setup_for_filter(FilterGraph *fg); int hwaccel_decode_init(AVCodecContext *avctx); +int of_muxer_init(OutputFile *of); /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 3cdaa494d7..84c94e46be 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -32,6 +32,10 @@ #include "libavformat/avformat.h" #include "libavformat/avio.h" +struct Muxer { +int header_written; +}; + static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others) { int i; @@ -64,7 +68,7 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, ost->frame_number++; } -if (!of->header_written) { +if (!of->mux->header_written) { AVPacket *tmp_pkt; /* the muxer is not initialized yet, buffer the packet */ if (!av_fifo_can_write(ost->muxing_queue)) { @@ -195,7 +199,7 @@ static int print_sdp(void) AVFormatContext **avc; for (i = 0; i < nb_output_files; i++) { -if (!output_files[i]->header_written) +if (!output_files[i]->mux->header_written) return 0; } @@ -259,7 +263,7 @@ int of_check_init(OutputFile *of) return ret; } //assert_avoptions(of->opts); -of->header_written = 1; +of->mux->header_written = 1; av_dump_format(of->ctx, of->index, of->ctx->url, 1); nb_output_dumped++; @@ -295,7 +299,7 @@ int of_write_trailer(OutputFile *of) { int ret; -if (!of->header_written) { +if (!of->mux->header_written) { av_log(NULL, AV_LOG_ERROR, "Nothing was written into output file %d (%s), because " "at least one of its streams received no packets.\n", @@ -326,5 +330,19 @@ void of_close(OutputFile **pof) avformat_free_context(s); av_dict_free(&of->opts); +av_freep(&of->mux); + av_freep(pof); } + +int of_muxer_init(OutputFile *of) +{ +Muxer *mux = av_mallocz(sizeof(*mux)); + +if (!mux) +return AVERROR(ENOMEM); + +of->mux = mux; + +return 0; +} diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 47e8b9b7bd..fff230eafc 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2921,6 +2921,12 @@ loop_end: exit_program(1); } +err = of_muxer_init(of); +if (err < 0) { +av_log(NULL, AV_LOG_FATAL, "Error initializing internal muxing state\n"); +exit_program(1); +} + return 0; } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 09/49] fftools/ffmpeg: store output format separately from the muxer context
Allows accessing it without going through the muxer context. This will be useful in the following commits, where the muxer context will be hidden. --- fftools/ffmpeg.c | 18 ++ fftools/ffmpeg.h | 2 ++ fftools/ffmpeg_opt.c | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 69d1949103..a85ed18b08 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -2789,9 +2789,9 @@ static int init_output_stream_streamcopy(OutputStream *ost) if (!codec_tag) { unsigned int codec_tag_tmp; -if (!of->ctx->oformat->codec_tag || -av_codec_get_id (of->ctx->oformat->codec_tag, par_src->codec_tag) == par_src->codec_id || -!av_codec_get_tag2(of->ctx->oformat->codec_tag, par_src->codec_id, &codec_tag_tmp)) +if (!of->format->codec_tag || +av_codec_get_id (of->format->codec_tag, par_src->codec_tag) == par_src->codec_id || +!av_codec_get_tag2(of->format->codec_tag, par_src->codec_id, &codec_tag_tmp)) codec_tag = par_src->codec_tag; } @@ -2809,7 +2809,7 @@ static int init_output_stream_streamcopy(OutputStream *ost) else ost->st->avg_frame_rate = ist->st->avg_frame_rate; -ret = avformat_transfer_internal_stream_timing_info(of->ctx->oformat, ost->st, ist->st, copy_tb); +ret = avformat_transfer_internal_stream_timing_info(of->format, ost->st, ist->st, copy_tb); if (ret < 0) return ret; @@ -3011,7 +3011,8 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) InputStream *ist = get_input_stream(ost); AVCodecContext *enc_ctx = ost->enc_ctx; AVCodecContext *dec_ctx = NULL; -AVFormatContext *oc = output_files[ost->file_index]->ctx; +OutputFile *of = output_files[ost->file_index]; +AVFormatContext *oc = of->ctx; int ret; set_encoder_id(output_files[ost->file_index], ost); @@ -3072,7 +3073,8 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) if (!(enc_ctx->time_base.num && enc_ctx->time_base.den)) enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter); if ( av_q2d(enc_ctx->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH - && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR || (video_sync_method == VSYNC_AUTO && !(oc->oformat->flags & AVFMT_VARIABLE_FPS{ + && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR || + (video_sync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS{ av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n" "Please consider specifying a lower framerate, a different muxer or -vsync 2\n"); } @@ -3405,7 +3407,7 @@ static int transcode_init(void) /* write headers for files with no streams */ for (i = 0; i < nb_output_files; i++) { oc = output_files[i]->ctx; -if (oc->oformat->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) { +if (output_files[i]->format->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) { ret = of_check_init(output_files[i]); if (ret < 0) goto dump_format; @@ -4615,7 +4617,7 @@ int main(int argc, char **argv) } for (i = 0; i < nb_output_files; i++) { -if (strcmp(output_files[i]->ctx->oformat->name, "rtp")) +if (strcmp(output_files[i]->format->name, "rtp")) want_sdp = 0; } diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index ff8ebbfab5..9f0c093e34 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -579,6 +579,8 @@ typedef struct OutputStream { typedef struct OutputFile { int index; +const AVOutputFormat *format; + AVFormatContext *ctx; AVDictionary *opts; int ost_index; /* index of the first stream in output_streams */ diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index daecba9e57..47e8b9b7bd 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2332,6 +2332,7 @@ static int open_output_file(OptionsContext *o, const char *filename) } of->ctx = oc; +of->format = oc->oformat; if (o->recording_time != INT64_MAX) oc->duration = o->recording_time; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 25/49] fftools/ffmpeg_mux: drop a useless check and reduce indentation
do_video_stats() is only ever called for video. --- fftools/ffmpeg_mux.c | 42 -- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 5facc9b1fc..059beabaf3 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -72,31 +72,29 @@ static void do_video_stats(OutputStream *ost, int frame_size) } enc = ost->enc_ctx; -if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { -frame_number = ost->st->nb_frames; -if (vstats_version <= 1) { -fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, -ost->quality / (float)FF_QP2LAMBDA); -} else { -fprintf(vstats_file, "out= %2d st= %2d frame= %5d q= %2.1f ", ost->file_index, ost->index, frame_number, -ost->quality / (float)FF_QP2LAMBDA); -} +frame_number = ost->st->nb_frames; +if (vstats_version <= 1) { +fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, +ost->quality / (float)FF_QP2LAMBDA); +} else { +fprintf(vstats_file, "out= %2d st= %2d frame= %5d q= %2.1f ", ost->file_index, ost->index, frame_number, +ost->quality / (float)FF_QP2LAMBDA); +} -if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR)) -fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0))); +if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR)) +fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0))); -fprintf(vstats_file,"f_size= %6d ", frame_size); -/* compute pts value */ -ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base); -if (ti1 < 0.01) -ti1 = 0.01; +fprintf(vstats_file,"f_size= %6d ", frame_size); +/* compute pts value */ +ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base); +if (ti1 < 0.01) +ti1 = 0.01; -bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; -avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0; -fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", - (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); -fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type)); -} +bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; +avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0; +fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", + (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); +fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type)); } static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others) -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 28/49] fftools/ffmpeg_mux: merge variable declaration and initialization
--- fftools/ffmpeg_mux.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 8e0e278e4f..b7140fca5e 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -58,7 +58,7 @@ static int want_sdp = 1; static void do_video_stats(OutputStream *ost, const AVPacket *pkt) { -AVCodecContext *enc; +AVCodecContext *enc = ost->enc_ctx; int frame_number; double ti1, bitrate, avg_bitrate; @@ -71,7 +71,6 @@ static void do_video_stats(OutputStream *ost, const AVPacket *pkt) } } -enc = ost->enc_ctx; frame_number = ost->packets_written - 1; if (vstats_version <= 1) { fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 12/49] fftools/ffmpeg: fix the type of limit_filesize
The option is parsed as INT64 (signed). It is also compared to the output of avio_tell(), which is also int64_t. --- fftools/ffmpeg.h | 4 ++-- fftools/ffmpeg_opt.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index fa7b202ae6..d76f4266d6 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -147,7 +147,7 @@ typedef struct OptionsContext { int64_t recording_time; int64_t stop_time; -uint64_t limit_filesize; +int64_t limit_filesize; float mux_preload; float mux_max_delay; int shortest; @@ -589,7 +589,7 @@ typedef struct OutputFile { int ost_index; /* index of the first stream in output_streams */ int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units -uint64_t limit_filesize; /* filesize limit expressed in bytes */ +int64_t limit_filesize; /* filesize limit expressed in bytes */ int shortest; } OutputFile; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index fff230eafc..4e601f1cf8 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -228,7 +228,7 @@ static void init_options(OptionsContext *o) o->start_time = AV_NOPTS_VALUE; o->start_time_eof = AV_NOPTS_VALUE; o->recording_time = INT64_MAX; -o->limit_filesize = UINT64_MAX; +o->limit_filesize = INT64_MAX; o->chapters_input_file = INT_MAX; o->accurate_seek = 1; o->thread_queue_size = -1; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 26/49] fftools/ffmpeg_mux: stop using AVStream.nb_frames in do_video_stats()
Its use for muxing is not documented, in practice it is incremented per each packet successfully passed to the muxer's write_packet(). Since there is a lot of indirection between ffmpeg submitting a packet to the muxer and it actually being written (e.g. the interleaving queue), using nb_frames to count packets sent to the muxer is incorrect. Use OutputStream.packets_written instead. --- fftools/ffmpeg_mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 059beabaf3..49703ed727 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -72,7 +72,7 @@ static void do_video_stats(OutputStream *ost, int frame_size) } enc = ost->enc_ctx; -frame_number = ost->st->nb_frames; +frame_number = ost->packets_written - 1; if (vstats_version <= 1) { fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, ost->quality / (float)FF_QP2LAMBDA); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 23/49] fftools/ffmpeg: move output file opts into private context
It is private to the muxer, no reason to access it from outside. --- fftools/ffmpeg.h | 3 +-- fftools/ffmpeg_mux.c | 9 ++--- fftools/ffmpeg_opt.c | 12 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 5f002521ab..c6bbc653b8 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -577,7 +577,6 @@ typedef struct OutputFile { const AVOutputFormat *format; AVFormatContext *ctx; -AVDictionary *opts; int ost_index; /* index of the first stream in output_streams */ int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units @@ -681,7 +680,7 @@ int hw_device_setup_for_filter(FilterGraph *fg); int hwaccel_decode_init(AVCodecContext *avctx); -int of_muxer_init(OutputFile *of, int64_t limit_filesize); +int of_muxer_init(OutputFile *of, AVDictionary *opts, int64_t limit_filesize); /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 2b85d55504..f301b8a66a 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -46,6 +46,8 @@ typedef struct MuxStream { struct Muxer { MuxStream *streams; +AVDictionary *opts; + /* filesize limit expressed in bytes */ int64_t limit_filesize; int64_t final_filesize; @@ -294,7 +296,7 @@ int of_check_init(OutputFile *of) return 0; } -ret = avformat_write_header(of->ctx, &of->opts); +ret = avformat_write_header(of->ctx, &of->mux->opts); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could not write header for output file #%d " @@ -387,6 +389,7 @@ static void mux_free(Muxer **pmux, int nb_streams) av_fifo_freep2(&ms->muxing_queue); } av_freep(&mux->streams); +av_dict_free(&mux->opts); av_freep(pmux); } @@ -406,12 +409,11 @@ void of_close(OutputFile **pof) if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE)) avio_closep(&s->pb); avformat_free_context(s); -av_dict_free(&of->opts); av_freep(pof); } -int of_muxer_init(OutputFile *of, int64_t limit_filesize) +int of_muxer_init(OutputFile *of, AVDictionary *opts, int64_t limit_filesize) { Muxer *mux = av_mallocz(sizeof(*mux)); int ret = 0; @@ -437,6 +439,7 @@ int of_muxer_init(OutputFile *of, int64_t limit_filesize) } mux->limit_filesize = limit_filesize; +mux->opts = opts; if (strcmp(of->format->name, "rtp")) want_sdp = 0; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index a9944e637d..adad46de5f 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2306,7 +2306,7 @@ static int open_output_file(OptionsContext *o, const char *filename) OutputFile *of; OutputStream *ost; InputStream *ist; -AVDictionary *unused_opts = NULL; +AVDictionary *unused_opts = NULL, *format_opts = NULL; const AVDictionaryEntry *e = NULL; if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) { @@ -2331,7 +2331,7 @@ static int open_output_file(OptionsContext *o, const char *filename) of->recording_time = o->recording_time; of->start_time = o->start_time; of->shortest = o->shortest; -av_dict_copy(&of->opts, o->g->format_opts, 0); +av_dict_copy(&format_opts, o->g->format_opts, 0); if (!strcmp(filename, "-")) filename = "pipe:"; @@ -2353,7 +2353,7 @@ static int open_output_file(OptionsContext *o, const char *filename) oc->flags|= AVFMT_FLAG_BITEXACT; of->bitexact = 1; } else { -of->bitexact = check_opt_bitexact(oc, of->opts, "fflags", +of->bitexact = check_opt_bitexact(oc, format_opts, "fflags", AVFMT_FLAG_BITEXACT); } @@ -2734,7 +2734,7 @@ loop_end: /* open the file */ if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, &oc->interrupt_callback, - &of->opts)) < 0) { + &format_opts)) < 0) { print_error(filename, err); exit_program(1); } @@ -2742,7 +2742,7 @@ loop_end: assert_file_overwrite(filename); if (o->mux_preload) { -av_dict_set_int(&of->opts, "preload", o->mux_preload*AV_TIME_BASE, 0); +av_dict_set_int(&format_opts, "preload", o->mux_preload*AV_TIME_BASE, 0); } oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE); @@ -2936,7 +2936,7 @@ loop_end: exit_program(1); } -err = of_muxer_init(of, o->limit_filesize); +err = of_muxer_init(of, format_opts, o->limit_filesize); if (err < 0) { av_log(NULL, AV_LOG_FATAL, "Error initializing internal
[FFmpeg-devel] [PATCH 29/49] fftools/ffmpeg_mux: move processing AV_PKT_DATA_QUALITY_STATS to do_video_stats()
This is a more appropriate place for this code, since the values we read from AV_PKT_DATA_QUALITY_STATS side data are primarily written into video stats. Rename the function to update_video_stats() to better reflect its new purpose. --- fftools/ffmpeg_mux.c | 37 +++-- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index b7140fca5e..ccfe31e09a 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -56,13 +56,28 @@ struct Muxer { static int want_sdp = 1; -static void do_video_stats(OutputStream *ost, const AVPacket *pkt) +static void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) { +const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, +NULL); AVCodecContext *enc = ost->enc_ctx; int frame_number; double ti1, bitrate, avg_bitrate; -/* this is executed just the first time do_video_stats is called */ +ost->quality = sd ? AV_RL32(sd) : -1; +ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE; + +for (int i = 0; i < FF_ARRAY_ELEMS(ost->error); i++) { +if (sd && i < sd[5]) +ost->error[i] = AV_RL64(sd + 8 + 8 * i); +else +ost->error[i] = -1; +} + +if (!write_vstats) +return; + +/* this is executed just the first time update_video_stats is called */ if (!vstats_file) { vstats_file = fopen(vstats_filename, "w"); if (!vstats_file) { @@ -155,19 +170,6 @@ static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) pkt->pts = pkt->dts = AV_NOPTS_VALUE; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { -int i; -uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, - NULL); -ost->quality = sd ? AV_RL32(sd) : -1; -ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE; - -for (i = 0; ierror); i++) { -if (sd && i < sd[5]) -ost->error[i] = AV_RL64(sd + 8 + 8*i); -else -ost->error[i] = -1; -} - if (ost->frame_rate.num && ost->is_cfr) { if (pkt->duration > 0) av_log(NULL, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n"); @@ -219,9 +221,8 @@ static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) ost->data_size += pkt->size; ost->packets_written++; -if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && -ost->encoding_needed && vstats_filename) -do_video_stats(ost, pkt); +if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) +update_video_stats(ost, pkt, !!vstats_filename); pkt->stream_index = ost->index; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 35/49] fftools/ffmpeg: use the sync queues to handle -frames
Same issues apply to it as to -shortest. Changes the results of the following tests: - matroska-flac-extradata-update The test reencodes two input FLAC streams into three output FLAC streams. The last output stream is limited to 8 frames. The current code results in the first two output streams having 12 frames, after this commit all three streams have 8 frames and are the same length. This new result is better, since it is predictable. - mkv-1242 The test streamcopies one video and one audio stream, video is limited to 11 frames. The new result shortens the audio stream so that it is not longer than the video. --- fftools/ffmpeg.c | 6 -- fftools/ffmpeg_mux.c | 10 +- fftools/ffmpeg_opt.c | 18 +++--- fftools/sync_queue.c | 13 + fftools/sync_queue.h | 7 +++ tests/ref/fate/matroska-flac-extradata-update | 16 +--- tests/ref/fate/mkv-1242 | 3 --- 7 files changed, 41 insertions(+), 32 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 8674f52047..e46554ddf4 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3412,12 +3412,6 @@ static int need_output(void) if (ost->finished || of_finished(of)) continue; -if (ost->frame_number >= ost->max_frames) { -int j; -for (j = 0; j < of->ctx->nb_streams; j++) -close_output_stream(output_streams[of->ost_index + j]); -continue; -} return 1; } diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 69f01448b8..11d5a0a885 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -273,19 +273,11 @@ void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) if (!eof) { /* - * Audio encoders may split the packets -- #frames in != #packets out. - * But there is no reordering, so we can limit the number of output packets - * by simply dropping them here. * Counting encoded video frames needs to be done separately because of * reordering, see do_video_out(). */ -if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) { -if (ost->frame_number >= ost->max_frames) { -av_packet_unref(pkt); -return; -} +if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) ost->frame_number++; -} } if (ost->sq_idx_mux >= 0) { diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 8884a5f9ed..ac0b4fc7d8 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2304,6 +2304,7 @@ static int init_complex_filters(void) static int setup_sync_queues(OutputFile *of, AVFormatContext *oc) { int nb_av_enc = 0, nb_interleaved = 0; +int limit_frames = 0, limit_frames_av_enc = 0; #define IS_AV_ENC(ost, type) \ (ost->encoding_needed && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) @@ -2318,14 +2319,19 @@ static int setup_sync_queues(OutputFile *of, AVFormatContext *oc) nb_interleaved += IS_INTERLEAVED(type); nb_av_enc += IS_AV_ENC(ost, type); + +limit_frames|= ost->max_frames < INT64_MAX; +limit_frames_av_enc |= (ost->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); } -if (!(nb_interleaved > 1 && of->shortest)) +if (!((nb_interleaved > 1 && of->shortest) || + (nb_interleaved > 0 && limit_frames))) return 0; -/* if we have more than one encoded audio/video streams, then we +/* if we have more than one encoded audio/video streams, or at least + * one encoded audio/video stream is frame-limited, then we * synchronize them before encoding */ -if (nb_av_enc > 1) { +if ((of->shortest && nb_av_enc > 1) || limit_frames_av_enc) { of->sq_encode = sq_alloc(SYNC_QUEUE_FRAMES); if (!of->sq_encode) return AVERROR(ENOMEM); @@ -2344,6 +2350,9 @@ static int setup_sync_queues(OutputFile *of, AVFormatContext *oc) ost->sq_frame = av_frame_alloc(); if (!ost->sq_frame) return AVERROR(ENOMEM); + +if (ost->max_frames != INT64_MAX) +sq_limit_frames(of->sq_encode, ost->sq_idx_encode, ost->max_frames); } } @@ -2364,6 +2373,9 @@ static int setup_sync_queues(OutputFile *of, AVFormatContext *oc) ost->sq_idx_mux = sq_add_stream(of->sq_mux); if (ost->sq_idx_mux < 0) return ost->sq_idx_mux; + +if (ost->max_frames != INT64_MAX) +sq_limit_frames(of->sq_mux, ost->sq_idx_mux, ost->max_frames); } } diff --git a/fftools/sync_queue.c b/fftools/sync_queue.c index cdf6a32cae..8bfdcbab4
[FFmpeg-devel] [PATCH 36/49] fftools/ffmpeg: stop using OutputStream.frame_number in print_report()
This field means different things for video encoding (number of frames emitted to the encoding sync queue/encoder by the video sync code) and for everything else (number of packets sent to the muxer sync queue). Print the value of packets_written instead, which means the same thing for all kinds of streams. It is also more consistent with the code below, which prints PSNR from the last muxed packet. --- fftools/ffmpeg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index e46554ddf4..53b3657ec9 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1531,7 +1531,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) { float fps; -frame_number = ost->frame_number; +frame_number = ost->packets_written; fps = t > 1 ? frame_number / t : 0; av_bprintf(&buf, "frame=%5d fps=%3.*f q=%3.1f ", frame_number, fps < 9.95, fps, q); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 38/49] fftools/ffmpeg: make the muxer AVFormatContext private to ffmpeg_mux.c
Since the muxer will operate in a separate thread in the future, the muxer context should not be accessed from the outside. --- fftools/ffmpeg.c| 4 +-- fftools/ffmpeg.h| 6 ++-- fftools/ffmpeg_filter.c | 6 ++-- fftools/ffmpeg_mux.c| 80 + fftools/ffmpeg_opt.c| 6 ++-- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 701baa3a28..7e9ac943de 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1442,9 +1442,9 @@ static void print_final_stats(int64_t total_size) uint64_t total_packets = 0, total_size = 0; av_log(NULL, AV_LOG_VERBOSE, "Output file #%d (%s):\n", - i, of->ctx->url); + i, of->url); -for (j = 0; j < of->ctx->nb_streams; j++) { +for (j = 0; j < of->nb_streams; j++) { OutputStream *ost = output_streams[of->ost_index + j]; enum AVMediaType type = ost->enc_ctx->codec_type; diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 962867b783..2ba58b492f 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -583,11 +583,12 @@ typedef struct OutputFile { Muxer*mux; const AVOutputFormat *format; +const char *url; SyncQueue *sq_encode; SyncQueue *sq_mux; -AVFormatContext *ctx; +int nb_streams; int ost_index; /* index of the first stream in output_streams */ int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units @@ -696,7 +697,8 @@ int hw_device_setup_for_filter(FilterGraph *fg); int hwaccel_decode_init(AVCodecContext *avctx); -int of_muxer_init(OutputFile *of, AVDictionary *opts, int64_t limit_filesize); +int of_muxer_init(OutputFile *of, AVFormatContext *fc, + AVDictionary *opts, int64_t limit_filesize); /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 0845c631a5..122b17686a 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -603,11 +603,11 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, if (ost->apad && of->shortest) { int i; -for (i=0; ictx->nb_streams; i++) -if (of->ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) +for (i = 0; i < of->nb_streams; i++) +if (output_streams[of->ost_index + i]->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) break; -if (ictx->nb_streams) { +if (i < of->nb_streams) { AUTO_INSERT_FILTER("-apad", "apad", ost->apad); } } diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 1d8827277d..0a8bdc36d9 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -49,6 +49,8 @@ typedef struct MuxStream { } MuxStream; struct Muxer { +AVFormatContext *fc; + MuxStream *streams; AVDictionary *opts; @@ -167,7 +169,7 @@ static int queue_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) { MuxStream *ms = &of->mux->streams[ost->index]; -AVFormatContext *s = of->ctx; +AVFormatContext *s = of->mux->fc; AVStream *st = ost->st; int ret; @@ -311,8 +313,8 @@ static int print_sdp(void) if (!avc) exit_program(1); for (i = 0, j = 0; i < nb_output_files; i++) { -if (!strcmp(output_files[i]->ctx->oformat->name, "rtp")) { -avc[j] = output_files[i]->ctx; +if (!strcmp(output_files[i]->format->name, "rtp")) { +avc[j] = output_files[i]->mux->fc; j++; } } @@ -350,15 +352,16 @@ fail: /* open the muxer when all the streams are initialized */ int of_check_init(OutputFile *of) { +AVFormatContext *fc = of->mux->fc; int ret, i; -for (i = 0; i < of->ctx->nb_streams; i++) { +for (i = 0; i < fc->nb_streams; i++) { OutputStream *ost = output_streams[of->ost_index + i]; if (!ost->initialized) return 0; } -ret = avformat_write_header(of->ctx, &of->mux->opts); +ret = avformat_write_header(fc, &of->mux->opts); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could not write header for output file #%d " @@ -369,7 +372,7 @@ int of_check_init(OutputFile *of) //assert_avoptions(of->opts); of->mux->header_written = 1; -av_dump_format(of->ctx, of->index, of->ctx->url, 1); +av_dump_format(fc, of->index, fc->url, 1); nb_output_dumped++; if (sdp_filename || want_sdp) { @@ -381,7 +384,7 @@ int of_check_init(OutputFile *of) } /* flush the muxing queues */ -for (i = 0; i < of->ctx->nb
[FFmpeg-devel] [PATCH 37/49] fftools/ffmpeg: only set OutputStream.frame_number for video encoding
It is unused otherwise. Rename the field to vsync_frame_number to better reflect its current purpose. --- fftools/ffmpeg.c | 10 +- fftools/ffmpeg.h | 3 ++- fftools/ffmpeg_mux.c | 11 --- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 53b3657ec9..701baa3a28 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1108,7 +1108,7 @@ static void do_video_out(OutputFile *of, switch (ost->vsync_method) { case VSYNC_VSCFR: -if (ost->frame_number == 0 && delta0 >= 0.5) { +if (ost->vsync_frame_number == 0 && delta0 >= 0.5) { av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0)); delta = duration; delta0 = 0; @@ -1116,7 +1116,7 @@ static void do_video_out(OutputFile *of, } case VSYNC_CFR: // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c -if (frame_drop_threshold && delta < frame_drop_threshold && ost->frame_number) { +if (frame_drop_threshold && delta < frame_drop_threshold && ost->vsync_frame_number) { nb_frames = 0; } else if (delta < -1.1) nb_frames = 0; @@ -1146,7 +1146,7 @@ static void do_video_out(OutputFile *of, * But there may be reordering, so we can't throw away frames on encoder * flush, we need to limit them here, before they go into encoder. */ -nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); +nb_frames = FFMIN(nb_frames, ost->max_frames - ost->vsync_frame_number); nb0_frames = FFMIN(nb0_frames, nb_frames); memmove(ost->last_nb0_frames + 1, @@ -1158,7 +1158,7 @@ static void do_video_out(OutputFile *of, nb_frames_drop++; av_log(NULL, AV_LOG_VERBOSE, "*** dropping frame %d from stream %d at ts %"PRId64"\n", - ost->frame_number, ost->st->index, ost->last_frame->pts); + ost->vsync_frame_number, ost->st->index, ost->last_frame->pts); } if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) { if (nb_frames > dts_error_threshold * 30) { @@ -1255,7 +1255,7 @@ static void do_video_out(OutputFile *of, av_frame_remove_side_data(in_picture, AV_FRAME_DATA_A53_CC); ost->sync_opts++; -ost->frame_number++; +ost->vsync_frame_number++; } av_frame_unref(ost->last_frame); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index dfda6ccbe9..962867b783 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -457,7 +457,8 @@ typedef struct OutputStream { int source_index;/* InputStream index */ AVStream *st;/* stream in the output file */ int encoding_needed; /* true if encoding needed for this stream */ -int frame_number; +/* number of frames emitted by the video-encoding sync code */ +int vsync_frame_number; /* input pts and corresponding output pts for A/V sync */ struct InputStream *sync_ist; /* input stream to sync against */ diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 11d5a0a885..1d8827277d 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -269,17 +269,6 @@ static void submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) { -AVStream *st = ost->st; - -if (!eof) { -/* - * Counting encoded video frames needs to be done separately because of - * reordering, see do_video_out(). - */ -if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) -ost->frame_number++; -} - if (ost->sq_idx_mux >= 0) { int ret = sq_send(of->sq_mux, ost->sq_idx_mux, SQPKT(eof ? NULL: pkt)); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 31/49] fftools/ffmpeg: reuse the encoding code for flushing encoders
--- fftools/ffmpeg.c | 72 1 file changed, 18 insertions(+), 54 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 662a5d22b1..adf69cb43e 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -826,12 +826,12 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) AVCodecContext *enc = ost->enc_ctx; AVPacket *pkt = ost->pkt; const char *type_desc = av_get_media_type_string(enc->codec_type); +const char*action = frame ? "encode" : "flush"; int ret; +if (frame) { ost->frames_encoded++; -update_benchmark(NULL); - if (debug_ts) { av_log(NULL, AV_LOG_INFO, "encoder <- type:%s " "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", @@ -839,9 +839,12 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), enc->time_base.num, enc->time_base.den); } +} + +update_benchmark(NULL); ret = avcodec_send_frame(enc, frame); -if (ret < 0) { +if (ret < 0 && !(ret == AVERROR_EOF && !frame)) { av_log(NULL, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", type_desc); return ret; @@ -849,15 +852,20 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) while (1) { ret = avcodec_receive_packet(enc, pkt); -update_benchmark("encode_%s %d.%d", type_desc, +update_benchmark("%s_%s %d.%d", action, type_desc, ost->file_index, ost->index); -if (ret == AVERROR(EAGAIN)) +if (ret == AVERROR(EAGAIN)) { +av_assert0(frame); // should never happen during flushing return 0; -else if (ret < 0) { +} else if (ret < 0 && ret != AVERROR_EOF) { av_log(NULL, AV_LOG_ERROR, "%s encoding failed\n", type_desc); return ret; } +if (ret == AVERROR_EOF) { +output_packet(of, pkt, ost, 1); +return ret; +} else { if (debug_ts) { av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " @@ -881,6 +889,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) } output_packet(of, pkt, ost, 0); +} /* if two pass, output log */ if (ost->logfile && enc->stats_out) @@ -1696,54 +1705,9 @@ static void flush_encoders(void) if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO) continue; -for (;;) { -const char *desc = NULL; -AVPacket *pkt = ost->pkt; - -switch (enc->codec_type) { -case AVMEDIA_TYPE_AUDIO: -desc = "audio"; -break; -case AVMEDIA_TYPE_VIDEO: -desc = "video"; -break; -default: -av_assert0(0); -} - -update_benchmark(NULL); - -while ((ret = avcodec_receive_packet(enc, pkt)) == AVERROR(EAGAIN)) { -ret = avcodec_send_frame(enc, NULL); -if (ret < 0) { -av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", - desc, - av_err2str(ret)); -exit_program(1); -} -} - -update_benchmark("flush_%s %d.%d", desc, ost->file_index, ost->index); -if (ret < 0 && ret != AVERROR_EOF) { -av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", - desc, - av_err2str(ret)); -exit_program(1); -} -if (ost->logfile && enc->stats_out) { -fprintf(ost->logfile, "%s", enc->stats_out); -} -if (ret == AVERROR_EOF) { -output_packet(of, pkt, ost, 1); -break; -} -if (ost->finished & MUXER_FINISHED) { -av_packet_unref(pkt); -continue; -} -av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); -output_packet(of, pkt, ost, 0); -} +ret = encode_frame(of, ost, NULL); +if (ret != AVERROR_EOF) +exit_program(1); } } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 30/49] fftools/ffmpeg: share the code encoding a single frame between video and audio
--- fftools/ffmpeg.c | 136 --- 1 file changed, 58 insertions(+), 78 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 68e720d889..662a5d22b1 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -821,63 +821,93 @@ static int init_output_stream_wrapper(OutputStream *ost, AVFrame *frame, return ret; } -static void do_audio_out(OutputFile *of, OutputStream *ost, - AVFrame *frame) +static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) { -AVCodecContext *enc = ost->enc_ctx; -AVPacket *pkt = ost->pkt; +AVCodecContext *enc = ost->enc_ctx; +AVPacket *pkt = ost->pkt; +const char *type_desc = av_get_media_type_string(enc->codec_type); int ret; -adjust_frame_pts_to_encoder_tb(of, ost, frame); - -if (!check_recording_time(ost)) -return; - -if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0) -frame->pts = ost->sync_opts; -ost->sync_opts = frame->pts + frame->nb_samples; -ost->samples_encoded += frame->nb_samples; ost->frames_encoded++; update_benchmark(NULL); + if (debug_ts) { -av_log(NULL, AV_LOG_INFO, "encoder <- type:audio " +av_log(NULL, AV_LOG_INFO, "encoder <- type:%s " "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", + type_desc, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), enc->time_base.num, enc->time_base.den); } ret = avcodec_send_frame(enc, frame); -if (ret < 0) -goto error; +if (ret < 0) { +av_log(NULL, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", + type_desc); +return ret; +} while (1) { ret = avcodec_receive_packet(enc, pkt); +update_benchmark("encode_%s %d.%d", type_desc, + ost->file_index, ost->index); if (ret == AVERROR(EAGAIN)) -break; -if (ret < 0) -goto error; +return 0; +else if (ret < 0) { +av_log(NULL, AV_LOG_ERROR, "%s encoding failed\n", type_desc); +return ret; +} -update_benchmark("encode_audio %d.%d", ost->file_index, ost->index); +if (debug_ts) { +av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " + "duration:%s duration_time:%s\n", + type_desc, + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), + av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); +} av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); if (debug_ts) { -av_log(NULL, AV_LOG_INFO, "encoder -> type:audio " +av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " "duration:%s duration_time:%s\n", + type_desc, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); } output_packet(of, pkt, ost, 0); + +/* if two pass, output log */ +if (ost->logfile && enc->stats_out) +fprintf(ost->logfile, "%s", enc->stats_out); } -return; -error: -av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n"); -exit_program(1); +av_assert0(0); +} + +static void do_audio_out(OutputFile *of, OutputStream *ost, + AVFrame *frame) +{ +int ret; + +adjust_frame_pts_to_encoder_tb(of, ost, frame); + +if (!check_recording_time(ost)) +return; + +if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0) +frame->pts = ost->sync_opts; +ost->sync_opts = frame->pts + frame->nb_samples; +ost->samples_encoded += frame->nb_samples; + +ret = encode_frame(of, ost, frame); +if (ret < 0) +exit_program(1); } static void do_subtitle_out(OutputFile *of, @@ -969,7 +999,6 @@ static void do_video_out(OutputFile *of, AVFrame *next_picture) { int ret; -AVPacket *pkt = ost->pkt; AVCodecContext *enc = ost->enc_ctx; AVRational frame_rate; int nb_frames, nb0_frames, i; @@ -1168,57 +1197,13 @@ static void do_video_out(OutputFile *of, av_log(NULL, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time); } -update_benchmark(NULL); -if (debug_ts) { -av_log(NULL, AV_LOG_INFO, "encoder <- type:video " - "frame_pts:%s frame_pts
[FFmpeg-devel] [PATCH 34/49] fftools/ffmpeg: rework -shortest implementation
The -shortest option (which finishes the output file at the time the shortest stream ends) is currently implemented by faking the -t option when an output stream ends. This approach is fragile, since it depends on the frames/packets being processed in a specific order. E.g. there are currently some situations in which the output file length will depend unpredictably on unrelated factors like encoder delay. More importantly, the present work aiming at splitting various ffmpeg components into different threads will make this approach completely unworkable, since the frames/packets will arrive in effectively random order. This commit introduces a "sync queue", which is essentially a collection of FIFOs, one per stream. Frames/packets are submitted to these FIFOs and are then released for further processing (encoding or muxing) when it is ensured that the frame in question will not make its stream get ahead of the other streams (the logic is similar to libavformat's interleaving queue). These sync queues are then used for encoding and/or muxing when the -shortest option is specifierd. This commit changes the results of the copy-shortest[12] tests, where the last audio frame is now gone. This is correct, since it actually outlasts the last video frame. --- fftools/Makefile | 1 + fftools/ffmpeg.c | 144 +++--- fftools/ffmpeg.h | 14 +- fftools/ffmpeg_mux.c | 88 ++--- fftools/ffmpeg_opt.c | 80 fftools/sync_queue.c | 346 ++ fftools/sync_queue.h | 93 + tests/ref/fate/copy-shortest1 | 1 - tests/ref/fate/copy-shortest2 | 1 - 9 files changed, 712 insertions(+), 56 deletions(-) create mode 100644 fftools/sync_queue.c create mode 100644 fftools/sync_queue.h diff --git a/fftools/Makefile b/fftools/Makefile index 81ad6c4f4f..f015df6846 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -14,6 +14,7 @@ OBJS-ffmpeg += \ fftools/ffmpeg_hw.o \ fftools/ffmpeg_mux.o\ fftools/ffmpeg_opt.o\ +fftools/sync_queue.o\ define DOFFTOOL OBJS-$(1) += fftools/cmdutils.o fftools/opt_common.o fftools/$(1).o $(OBJS-$(1)-yes) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 07d1fc8a5d..8674f52047 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -104,6 +104,7 @@ #include "ffmpeg.h" #include "cmdutils.h" +#include "sync_queue.h" #include "libavutil/avassert.h" @@ -570,6 +571,7 @@ static void ffmpeg_cleanup(int ret) av_bsf_free(&ost->bsf_ctx); av_frame_free(&ost->filtered_frame); +av_frame_free(&ost->sq_frame); av_frame_free(&ost->last_frame); av_packet_free(&ost->pkt); av_dict_free(&ost->encoder_opts); @@ -690,13 +692,10 @@ static void update_benchmark(const char *fmt, ...) static void close_output_stream(OutputStream *ost) { OutputFile *of = output_files[ost->file_index]; -AVRational time_base = ost->stream_copy ? ost->mux_timebase : ost->enc_ctx->time_base; - ost->finished |= ENCODER_FINISHED; -if (of->shortest) { -int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, time_base, AV_TIME_BASE_Q); -of->recording_time = FFMIN(of->recording_time, end); -} + +if (ost->sq_idx_encode >= 0) +sq_send(of->sq_encode, ost->sq_idx_encode, SQFRAME(NULL)); } /* @@ -715,17 +714,22 @@ static void output_packet(OutputFile *of, AVPacket *pkt, { int ret = 0; +if (!eof && pkt->dts != AV_NOPTS_VALUE) +ost->last_mux_dts = av_rescale_q(pkt->dts, ost->mux_timebase, AV_TIME_BASE_Q); + /* apply the output bitstream filters */ if (ost->bsf_ctx) { ret = av_bsf_send_packet(ost->bsf_ctx, eof ? NULL : pkt); if (ret < 0) goto finish; while ((ret = av_bsf_receive_packet(ost->bsf_ctx, pkt)) >= 0) -of_submit_packet(of, pkt, ost); +of_submit_packet(of, pkt, ost, 0); +if (ret == AVERROR_EOF) +of_submit_packet(of, pkt, ost, 1); if (ret == AVERROR(EAGAIN)) ret = 0; -} else if (!eof) -of_submit_packet(of, pkt, ost); +} else +of_submit_packet(of, pkt, ost, eof); finish: if (ret < 0 && ret != AVERROR_EOF) { @@ -895,6 +899,52 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) av_assert0(0); } +static int submit_encode_frame(OutputFile *of, OutputStream *ost, + AVFrame *frame) +{ +int ret; + +if (ost->sq_idx_encode < 0) +return encode_frame(of, ost, frame); + +if (frame) { +ret = av_frame_ref(ost->sq_frame, frame); +if (ret < 0) +return ret; +frame = ost->sq_frame; +} + +ret = sq_send(of->sq_encode, ost->sq_idx_encode, + SQFRAME(frame)); +if (ret < 0) { +if (frame) +av_frame_unref(fr
[FFmpeg-devel] [PATCH 32/49] fftools/ffmpeg: reindent after previous commit
--- fftools/ffmpeg.c | 56 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index adf69cb43e..e0f15c0f61 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -830,15 +830,15 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) int ret; if (frame) { -ost->frames_encoded++; +ost->frames_encoded++; -if (debug_ts) { -av_log(NULL, AV_LOG_INFO, "encoder <- type:%s " - "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", - type_desc, - av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), - enc->time_base.num, enc->time_base.den); -} +if (debug_ts) { +av_log(NULL, AV_LOG_INFO, "encoder <- type:%s " + "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", + type_desc, + av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), + enc->time_base.num, enc->time_base.den); +} } update_benchmark(NULL); @@ -866,29 +866,29 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) output_packet(of, pkt, ost, 1); return ret; } else { -if (debug_ts) { -av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " - "duration:%s duration_time:%s\n", - type_desc, - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), - av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); -} +if (debug_ts) { +av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " + "duration:%s duration_time:%s\n", + type_desc, + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), + av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); +} -av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); +av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); -if (debug_ts) { -av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " - "duration:%s duration_time:%s\n", - type_desc, - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), - av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); -} +if (debug_ts) { +av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " + "duration:%s duration_time:%s\n", + type_desc, + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), + av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); +} -output_packet(of, pkt, ost, 0); +output_packet(of, pkt, ost, 0); } /* if two pass, output log */ -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 41/49] fftools/ffmpeg_mux: return errors from write_packet()
--- fftools/ffmpeg_mux.c | 17 ++--- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 69af2c8d46..37ae61fee8 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -166,7 +166,7 @@ static int queue_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) return 0; } -static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) +static int write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) { MuxStream *ms = &of->mux->streams[ost->index]; AVFormatContext *s = of->mux->fc; @@ -211,10 +211,8 @@ static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) av_log(s, loglevel, "Non-monotonous DTS in output stream " "%d:%d; previous: %"PRId64", current: %"PRId64"; ", ost->file_index, ost->st->index, ms->last_mux_dts, pkt->dts); -if (exit_on_error) { -av_log(NULL, AV_LOG_FATAL, "aborting.\n"); -exit_program(1); -} +if (exit_on_error) +return AVERROR(EINVAL); av_log(s, loglevel, "changing to %"PRId64". This may result " "in incorrect timestamps in the output file.\n", max); @@ -250,7 +248,10 @@ static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) print_error("av_interleaved_write_frame()", ret); main_return_code = 1; close_all_output_streams(ost, MUXER_FINISHED | ENCODER_FINISHED, ENCODER_FINISHED); +return ret; } + +return 0; } static int submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) @@ -258,7 +259,7 @@ static int submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) int ret; if (of->mux->header_written) { -write_packet(of, ost, pkt); +return write_packet(of, ost, pkt); } else { /* the muxer is not initialized yet, buffer the packet */ ret = queue_packet(of, ost, pkt); @@ -401,8 +402,10 @@ int of_check_init(OutputFile *of) while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0) { ms->muxing_queue_data_size -= pkt->size; -write_packet(of, ost, pkt); +ret = write_packet(of, ost, pkt); av_packet_free(&pkt); +if (ret < 0) +return ret; } } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 39/49] fftools/ffmpeg_mux: return errors from of_submit_packet()
--- fftools/ffmpeg.c | 54 +++- fftools/ffmpeg.h | 2 +- fftools/ffmpeg_mux.c | 12 ++ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 7e9ac943de..9987b15888 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -712,6 +712,7 @@ static void close_output_stream(OutputStream *ost) static void output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) { +const char *err_msg; int ret = 0; if (!eof && pkt->dts != AV_NOPTS_VALUE) @@ -719,25 +720,46 @@ static void output_packet(OutputFile *of, AVPacket *pkt, /* apply the output bitstream filters */ if (ost->bsf_ctx) { +int bsf_eof = 0; + ret = av_bsf_send_packet(ost->bsf_ctx, eof ? NULL : pkt); -if (ret < 0) -goto finish; -while ((ret = av_bsf_receive_packet(ost->bsf_ctx, pkt)) >= 0) -of_submit_packet(of, pkt, ost, 0); -if (ret == AVERROR_EOF) -of_submit_packet(of, pkt, ost, 1); -if (ret == AVERROR(EAGAIN)) -ret = 0; -} else -of_submit_packet(of, pkt, ost, eof); +if (ret < 0) { +err_msg = "submitting a packet for bitstream filtering"; +goto fail; +} -finish: -if (ret < 0 && ret != AVERROR_EOF) { -av_log(NULL, AV_LOG_ERROR, "Error applying bitstream filters to an output " - "packet for stream #%d:%d.\n", ost->file_index, ost->index); -if(exit_on_error) -exit_program(1); +while (!bsf_eof) { +ret = av_bsf_receive_packet(ost->bsf_ctx, pkt); +if (ret == AVERROR(EAGAIN)) +return; +else if (ret == AVERROR_EOF) +bsf_eof = 1; +else if (ret < 0) { +err_msg = "applying bitstream filters to a packet"; +goto fail; +} + +ret = of_submit_packet(of, pkt, ost, ret == AVERROR_EOF); +if (ret < 0) +goto mux_fail; +} +} else { +ret = of_submit_packet(of, pkt, ost, eof); +if (ret < 0) +goto mux_fail; } + +return; + +mux_fail: +err_msg = "submitting a packet to the muxer"; + +fail: +av_log(NULL, AV_LOG_ERROR, "Error %s for output stream #%d:%d.\n", + err_msg, ost->file_index, ost->index); +if (exit_on_error) +exit_program(1); + } static int check_recording_time(OutputStream *ost) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 2ba58b492f..fef66c2325 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -704,7 +704,7 @@ int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); void of_close(OutputFile **pof); -void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof); +int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof); int of_finished(OutputFile *of); int64_t of_filesize(OutputFile *of); AVChapter * const * diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 0a8bdc36d9..3ea7636380 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -269,7 +269,7 @@ static void submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) } } -void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) +int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) { if (ost->sq_idx_mux >= 0) { int ret = sq_send(of->sq_mux, ost->sq_idx_mux, @@ -278,22 +278,24 @@ void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) av_packet_unref(pkt); if (ret == AVERROR_EOF) { ost->finished |= MUXER_FINISHED; -return; +return 0; } else -exit_program(1); +return ret; } while (1) { ret = sq_receive(of->sq_mux, -1, SQPKT(pkt)); if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) -return; +return 0; else if (ret < 0) -exit_program(1); +return ret; submit_packet(of, pkt, output_streams[of->ost_index + ret]); } } else if (!eof) submit_packet(of, pkt, ost); + +return 0; } static int print_sdp(void) -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 27/49] fftools/ffmpeg_mux: stop using av_stream_get_end_pts() in do_video_stats()
It retrieves libavformat's internal dts value (contrary to the function's name), which is not necessary here because we can access the packet directly. --- fftools/ffmpeg_mux.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 49703ed727..8e0e278e4f 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -56,7 +56,7 @@ struct Muxer { static int want_sdp = 1; -static void do_video_stats(OutputStream *ost, int frame_size) +static void do_video_stats(OutputStream *ost, const AVPacket *pkt) { AVCodecContext *enc; int frame_number; @@ -84,13 +84,13 @@ static void do_video_stats(OutputStream *ost, int frame_size) if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR)) fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0))); -fprintf(vstats_file,"f_size= %6d ", frame_size); +fprintf(vstats_file,"f_size= %6d ", pkt->size); /* compute pts value */ -ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base); +ti1 = pkt->dts * av_q2d(ost->st->time_base); if (ti1 < 0.01) ti1 = 0.01; -bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; +bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0; avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0; fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); @@ -222,7 +222,7 @@ static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed && vstats_filename) -do_video_stats(ost, pkt->size); +do_video_stats(ost, pkt); pkt->stream_index = ost->index; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 45/49] fftools/ffmpeg: stop using av_stream_get_end_pts()
It retrieves some muxer's internal timestamp with under-defined semantics. Continuing to use this value would also require synchronization once the muxer is moved to a separate thread. Replace the value with last_mux_dts. --- fftools/ffmpeg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 9987b15888..0cab73ad7a 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1604,9 +1604,8 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti vid = 1; } /* compute min output value */ -if (av_stream_get_end_pts(ost->st) != AV_NOPTS_VALUE) { -pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st), - ost->st->time_base, AV_TIME_BASE_Q)); +if (ost->last_mux_dts != AV_NOPTS_VALUE) { +pts = FFMAX(pts, ost->last_mux_dts); if (copy_ts) { if (copy_ts_first_pts == AV_NOPTS_VALUE && pts > 1) copy_ts_first_pts = pts; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 33/49] fftools/ffmpeg: use refcounted packets for encoded subtitles
--- fftools/ffmpeg.c | 25 - 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index e0f15c0f61..07d1fc8a5d 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -141,8 +141,6 @@ unsigned nb_output_dumped = 0; static BenchmarkTimeStamps current_time; AVIOContext *progress_avio = NULL; -static uint8_t *subtitle_out; - InputStream **input_streams = NULL; intnb_input_streams = 0; InputFile **input_files = NULL; @@ -559,8 +557,6 @@ static void ffmpeg_cleanup(int ret) } av_freep(&filtergraphs); -av_freep(&subtitle_out); - /* close files */ for (i = 0; i < nb_output_files; i++) of_close(&output_files[i]); @@ -924,7 +920,7 @@ static void do_subtitle_out(OutputFile *of, AVSubtitle *sub) { int subtitle_out_max_size = 1024 * 1024; -int subtitle_out_size, nb, i; +int subtitle_out_size, nb, i, ret; AVCodecContext *enc; AVPacket *pkt = ost->pkt; int64_t pts; @@ -938,14 +934,6 @@ static void do_subtitle_out(OutputFile *of, enc = ost->enc_ctx; -if (!subtitle_out) { -subtitle_out = av_malloc(subtitle_out_max_size); -if (!subtitle_out) { -av_log(NULL, AV_LOG_FATAL, "Failed to allocate subtitle_out\n"); -exit_program(1); -} -} - /* Note: DVB subtitle need one packet to draw them and one other packet to clear them */ /* XXX: signal it in the codec context ? */ @@ -965,6 +953,12 @@ static void do_subtitle_out(OutputFile *of, if (!check_recording_time(ost)) return; +ret = av_new_packet(pkt, subtitle_out_max_size); +if (ret < 0) { +av_log(NULL, AV_LOG_FATAL, "Failed to allocate subtitle encode buffer\n"); +exit_program(1); +} + sub->pts = pts; // start_display_time is required to be 0 sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q); @@ -975,8 +969,7 @@ static void do_subtitle_out(OutputFile *of, ost->frames_encoded++; -subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out, -subtitle_out_max_size, sub); +subtitle_out_size = avcodec_encode_subtitle(enc, pkt->data, pkt->size, sub); if (i == 1) sub->num_rects = save_num_rects; if (subtitle_out_size < 0) { @@ -984,8 +977,6 @@ static void do_subtitle_out(OutputFile *of, exit_program(1); } -av_packet_unref(pkt); -pkt->data = subtitle_out; pkt->size = subtitle_out_size; pkt->pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->mux_timebase); pkt->duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->mux_timebase); -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 46/49] fftools/ffmpeg: do not write the output file header from init_output_stream()
--- fftools/ffmpeg.c | 4 - fftools/ffmpeg.h | 2 - fftools/ffmpeg_mux.c | 186 ++- 3 files changed, 96 insertions(+), 96 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 0cab73ad7a..2dff41e57f 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3230,10 +3230,6 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, ost->initialized = 1; -ret = of_check_init(output_files[ost->file_index]); -if (ret < 0) -return ret; - return ret; } diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index fef66c2325..14b98909d0 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -699,8 +699,6 @@ int hwaccel_decode_init(AVCodecContext *avctx); int of_muxer_init(OutputFile *of, AVFormatContext *fc, AVDictionary *opts, int64_t limit_filesize); -/* open the muxer when all the streams are initialized */ -int of_check_init(OutputFile *of); int of_write_trailer(OutputFile *of); void of_close(OutputFile **pof); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 2fd131d1bc..6ca9a51dd6 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -63,6 +63,59 @@ struct Muxer { static int want_sdp = 1; +static int print_sdp(void) +{ +char sdp[16384]; +int i; +int j, ret; +AVIOContext *sdp_pb; +AVFormatContext **avc; + +for (i = 0; i < nb_output_files; i++) { +if (!output_files[i]->mux->header_written) +return 0; +} + +avc = av_malloc_array(nb_output_files, sizeof(*avc)); +if (!avc) +return AVERROR(ENOMEM); +for (i = 0, j = 0; i < nb_output_files; i++) { +if (!strcmp(output_files[i]->format->name, "rtp")) { +avc[j] = output_files[i]->mux->fc; +j++; +} +} + +if (!j) { +av_log(NULL, AV_LOG_ERROR, "No output streams in the SDP.\n"); +ret = AVERROR(EINVAL); +goto fail; +} + +ret = av_sdp_create(avc, j, sdp, sizeof(sdp)); +if (ret < 0) +goto fail; + +if (!sdp_filename) { +printf("SDP:\n%s\n", sdp); +fflush(stdout); +} else { +ret = avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL); +if (ret < 0) { +av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename); +goto fail; +} + +avio_print(sdp_pb, sdp); +avio_closep(&sdp_pb); +av_freep(&sdp_filename); +} + +fail: +av_freep(&avc); +return ret; +} + static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) { const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, @@ -273,92 +326,8 @@ static int submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) return ret; } -int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) -{ -if (ost->sq_idx_mux >= 0) { -int ret = sq_send(of->sq_mux, ost->sq_idx_mux, - SQPKT(eof ? NULL: pkt)); -if (ret < 0) { -av_packet_unref(pkt); -if (ret == AVERROR_EOF) { -ost->finished |= MUXER_FINISHED; -return 0; -} else -return ret; -} - -while (1) { -ret = sq_receive(of->sq_mux, -1, SQPKT(pkt)); -if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) -return 0; -else if (ret < 0) -return ret; - -ret = submit_packet(of, pkt, output_streams[of->ost_index + ret]); -if (ret < 0) -return ret; -} -} else if (!eof) -return submit_packet(of, pkt, ost); - -return 0; -} - -static int print_sdp(void) -{ -char sdp[16384]; -int i; -int j, ret; -AVIOContext *sdp_pb; -AVFormatContext **avc; - -for (i = 0; i < nb_output_files; i++) { -if (!output_files[i]->mux->header_written) -return 0; -} - -avc = av_malloc_array(nb_output_files, sizeof(*avc)); -if (!avc) -return AVERROR(ENOMEM); -for (i = 0, j = 0; i < nb_output_files; i++) { -if (!strcmp(output_files[i]->format->name, "rtp")) { -avc[j] = output_files[i]->mux->fc; -j++; -} -} - -if (!j) { -av_log(NULL, AV_LOG_ERROR, "No output streams in the SDP.\n"); -ret = AVERROR(EINVAL); -goto fail; -} - -ret = av_sdp_create(avc, j, sdp, sizeof(sdp)); -if (ret < 0) -goto fail; - -if (!sdp_filename) { -printf("SDP:\n%s\n", sdp); -fflush(stdout); -} else { -ret = avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL); -if (ret < 0) { -av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename); -goto fail; -} - -avio_print(sdp_pb, sdp); -avio_closep(&sdp
[FFmpeg-devel] [PATCH 40/49] fftools/ffmpeg_mux: return errors from submit_packet()
--- fftools/ffmpeg_mux.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 3ea7636380..69af2c8d46 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -253,7 +253,7 @@ static void write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) } } -static void submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) +static int submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) { int ret; @@ -264,9 +264,11 @@ static void submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) ret = queue_packet(of, ost, pkt); if (ret < 0) { av_packet_unref(pkt); -exit_program(1); +return ret; } } + +return 0; } int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) @@ -290,10 +292,12 @@ int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) else if (ret < 0) return ret; -submit_packet(of, pkt, output_streams[of->ost_index + ret]); +ret = submit_packet(of, pkt, output_streams[of->ost_index + ret]); +if (ret < 0) +return ret; } } else if (!eof) -submit_packet(of, pkt, ost); +return submit_packet(of, pkt, ost); return 0; } -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 47/49] fftools/ffmpeg: depend on threads
ffmpeg will be switched to a fully threaded architecture, starting with muxers. --- configure| 2 +- fftools/ffmpeg.c | 20 fftools/ffmpeg.h | 2 -- fftools/ffmpeg_opt.c | 2 -- 4 files changed, 1 insertion(+), 25 deletions(-) diff --git a/configure b/configure index e4d36aa639..4888b136a4 100755 --- a/configure +++ b/configure @@ -3796,7 +3796,7 @@ avfilter_extralibs="pthreads_extralibs" avutil_extralibs="d3d11va_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vdpau_x11_extralibs" # programs -ffmpeg_deps="avcodec avfilter avformat" +ffmpeg_deps="avcodec avfilter avformat threads" ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter hflip_filter null_filter transpose_filter trim_filter vflip_filter" diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 2dff41e57f..9dfbc4216a 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -162,9 +162,7 @@ static struct termios oldtty; static int restore_tty; #endif -#if HAVE_THREADS static void free_input_threads(void); -#endif /* sub2video hack: Convert subtitles to video with alpha to insert them in filter graphs. @@ -592,9 +590,7 @@ static void ffmpeg_cleanup(int ret) av_freep(&output_streams[i]); } -#if HAVE_THREADS free_input_threads(); -#endif for (i = 0; i < nb_input_files; i++) { avformat_close_input(&input_files[i]->ctx); av_packet_free(&input_files[i]->pkt); @@ -3601,7 +3597,6 @@ static int check_keyboard_interaction(int64_t cur_time) return 0; } -#if HAVE_THREADS static void *input_thread(void *arg) { InputFile *f = arg; @@ -3719,7 +3714,6 @@ static int get_input_packet_mt(InputFile *f, AVPacket **pkt) f->non_blocking ? AV_THREAD_MESSAGE_NONBLOCK : 0); } -#endif static int get_input_packet(InputFile *f, AVPacket **pkt) { @@ -3742,10 +3736,8 @@ static int get_input_packet(InputFile *f, AVPacket **pkt) } } -#if HAVE_THREADS if (f->thread_queue_size) return get_input_packet_mt(f, pkt); -#endif *pkt = f->pkt; return av_read_frame(f->ctx, *pkt); } @@ -3885,15 +3877,11 @@ static int process_input(int file_index) avcodec_flush_buffers(avctx); } } -#if HAVE_THREADS free_input_thread(file_index); -#endif ret = seek_to_start(ifile, is); -#if HAVE_THREADS thread_ret = init_input_thread(file_index); if (thread_ret < 0) return thread_ret; -#endif if (ret < 0) av_log(NULL, AV_LOG_WARNING, "Seek to start failed.\n"); else @@ -4133,11 +4121,9 @@ static int process_input(int file_index) process_input_packet(ist, pkt, 0); discard_packet: -#if HAVE_THREADS if (ifile->thread_queue_size) av_packet_free(&pkt); else -#endif av_packet_unref(pkt); return 0; @@ -4324,10 +4310,8 @@ static int transcode(void) timer_start = av_gettime_relative(); -#if HAVE_THREADS if ((ret = init_input_threads()) < 0) goto fail; -#endif while (!received_sigterm) { int64_t cur_time= av_gettime_relative(); @@ -4352,9 +4336,7 @@ static int transcode(void) /* dump report by using the output first video and audio streams */ print_report(0, timer_start, cur_time); } -#if HAVE_THREADS free_input_threads(); -#endif /* at the end of stream, we must flush the decoder buffers */ for (i = 0; i < nb_input_streams; i++) { @@ -4412,9 +4394,7 @@ static int transcode(void) ret = 0; fail: -#if HAVE_THREADS free_input_threads(); -#endif if (output_streams) { for (i = 0; i < nb_output_streams; i++) { diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 14b98909d0..407342462f 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -423,13 +423,11 @@ typedef struct InputFile { AVPacket *pkt; -#if HAVE_THREADS AVThreadMessageQueue *in_thread_queue; pthread_t thread; /* thread reading from this file */ int non_blocking; /* reading packets from the thread should not block */ int joined; /* the thread has been joined */ int thread_queue_size; /* maximum number of queued packets */ -#endif } InputFile; enum forced_keyframes_const { diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index a86255e409..9bf22f6932 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -1305,9 +1305,7 @@ static int open_input_file(OptionsContext *o, const char *filename) f->pkt = av_packet_alloc(); if (!f->pkt) exit_program(1); -#if HAVE_THREADS f->thread_queue_size = o->thread_queue_size; -#endif /* check if all codec options have been used */ unused_opts = strip_specifiers(o->g->codec_opts); -- 2.34.1
[FFmpeg-devel] [PATCH 43/49] fftools/ffmpeg_mux: return errors from update_video_stats()
--- fftools/ffmpeg_mux.c | 15 ++- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 2cdbd5feef..087009e0eb 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -63,7 +63,7 @@ struct Muxer { static int want_sdp = 1; -static void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) +static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) { const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, NULL); @@ -82,14 +82,14 @@ static void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write } if (!write_vstats) -return; +return 0; /* this is executed just the first time update_video_stats is called */ if (!vstats_file) { vstats_file = fopen(vstats_filename, "w"); if (!vstats_file) { perror("fopen"); -exit_program(1); +return AVERROR(errno); } } @@ -116,6 +116,8 @@ static void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type)); + +return 0; } static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others) @@ -227,8 +229,11 @@ static int write_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) ost->data_size += pkt->size; ost->packets_written++; -if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) -update_video_stats(ost, pkt, !!vstats_filename); +if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) { +ret = update_video_stats(ost, pkt, !!vstats_filename); +if (ret < 0) +return ret; +} pkt->stream_index = ost->index; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 42/49] fftools/ffmpeg_mux: simplify submit_packet()
--- fftools/ffmpeg_mux.c | 16 ++-- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 37ae61fee8..2cdbd5feef 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -258,18 +258,14 @@ static int submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) { int ret; -if (of->mux->header_written) { +if (of->mux->header_written) return write_packet(of, ost, pkt); -} else { -/* the muxer is not initialized yet, buffer the packet */ -ret = queue_packet(of, ost, pkt); -if (ret < 0) { -av_packet_unref(pkt); -return ret; -} -} -return 0; +/* the muxer is not initialized yet, buffer the packet */ +ret = queue_packet(of, ost, pkt); +if (ret < 0) +av_packet_unref(pkt); +return ret; } int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof) -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 48/49] fftools: add a multistream thread-safe queue
It is similar to AVThreadMessageQueue, but supports multiple streams, each with its own EOF state. --- fftools/Makefile | 1 + fftools/thread_queue.c | 232 + fftools/thread_queue.h | 37 +++ 3 files changed, 270 insertions(+) create mode 100644 fftools/thread_queue.c create mode 100644 fftools/thread_queue.h diff --git a/fftools/Makefile b/fftools/Makefile index f015df6846..b0de4f4c61 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -15,6 +15,7 @@ OBJS-ffmpeg += \ fftools/ffmpeg_mux.o\ fftools/ffmpeg_opt.o\ fftools/sync_queue.o\ +fftools/thread_queue.o \ define DOFFTOOL OBJS-$(1) += fftools/cmdutils.o fftools/opt_common.o fftools/$(1).o $(OBJS-$(1)-yes) diff --git a/fftools/thread_queue.c b/fftools/thread_queue.c new file mode 100644 index 00..9ec02ca772 --- /dev/null +++ b/fftools/thread_queue.c @@ -0,0 +1,232 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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, + * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/error.h" +#include "libavutil/fifo.h" +#include "libavutil/mem.h" +#include "libavutil/thread.h" + +#include "thread_queue.h" + +enum { +FINISHED_SEND = (1 << 0), +FINISHED_RECV = (1 << 1), +}; + +typedef struct ThreadQueueStream { +AVFifo *fifo; +int finished; +} ThreadQueueStream; + +struct ThreadQueue { +ThreadQueueStream *streams; +unsigned intnb_streams; + +void (*elem_free)(void *); + +pthread_mutex_t lock; +pthread_cond_t cond; +}; + +void tq_free(ThreadQueue **ptq) +{ +ThreadQueue *tq = *ptq; + +if (!tq) +return; + +for (unsigned int i = 0; i < tq->nb_streams; i++) { +ThreadQueueStream *st = &tq->streams[i]; + +if (st->fifo && tq->elem_free) { +void *elem; +while (av_fifo_read(st->fifo, &elem, 1) >= 0) +tq->elem_free(elem); +} +av_fifo_freep2(&tq->streams[i].fifo); +} +av_freep(&tq->streams); + +pthread_cond_destroy(&tq->cond); +pthread_mutex_destroy(&tq->lock); + +av_freep(ptq); +} + +ThreadQueue *tq_alloc(unsigned int nb_streams, + size_t nb_elems, size_t elem_size, + void (*elem_free)(void *)) +{ +ThreadQueue *tq; +int ret; + +tq = av_mallocz(sizeof(*tq)); +if (!tq) +return NULL; + +tq->elem_free = elem_free; + +ret = pthread_cond_init(&tq->cond, NULL); +if (ret) { +av_freep(&tq); +return NULL; +} + +ret = pthread_mutex_init(&tq->lock, NULL); +if (ret) { +pthread_cond_destroy(&tq->cond); +av_freep(&tq); +return NULL; +} + +tq->streams = av_calloc(nb_streams, sizeof(*tq->streams)); +if (!tq->streams) +goto fail; +tq->nb_streams = nb_streams; + +for (unsigned int i = 0; i < nb_streams; i++) { +ThreadQueueStream *st = &tq->streams[i]; + +st->fifo = av_fifo_alloc2(nb_elems, elem_size, 0); +if (!st->fifo) +goto fail; +} + +return tq; +fail: +tq_free(&tq); +return NULL; +} + +int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data) +{ +ThreadQueueStream *st; +int ret; + +av_assert0(stream_idx < tq->nb_streams); +st = &tq->streams[stream_idx]; + +pthread_mutex_lock(&tq->lock); + +if (st->finished & FINISHED_SEND) { +ret = AVERROR(EINVAL); +goto finish; +} + +while (!(st->finished & FINISHED_RECV) && !av_fifo_can_write(st->fifo)) +pthread_cond_wait(&tq->cond, &tq->lock); + +if (st->finished & FINISHED_RECV) +ret = AVERROR_EOF; +else { +ret = av_fifo_write(st->fifo, data, 1); +if (ret >= 0) +pthread_cond_broadcast(&tq->cond); +} + +finish: +pthread_mutex_unlock(&tq->lock); + +return ret; +} + +static int receive_locked(ThreadQueue *tq, int *stream_idx, + void *data) +{ +unsigned int nb_finished = 0; + +for (unsigned int i = 0; i < tq->nb_streams; i++) { +ThreadQueueStream *st = &tq->streams[i]; + +if (av_fifo_read(st->fifo, data, 1) >= 0) { +*stream_idx = i; +return 0; +
[FFmpeg-devel] [PATCH 44/49] fftools/ffmpeg_mux: do not call exit_program() in print_sdp()
Return an error instead, as is already done in other places in this function. --- fftools/ffmpeg_mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 087009e0eb..2fd131d1bc 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -319,7 +319,7 @@ static int print_sdp(void) avc = av_malloc_array(nb_output_files, sizeof(*avc)); if (!avc) -exit_program(1); +return AVERROR(ENOMEM); for (i = 0, j = 0; i < nb_output_files; i++) { if (!strcmp(output_files[i]->format->name, "rtp")) { avc[j] = output_files[i]->mux->fc; -- 2.34.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 49/49] fftools/ffmpeg: move each muxer to a separate thread
--- fftools/ffmpeg.c | 38 +++-- fftools/ffmpeg.h | 7 +- fftools/ffmpeg_mux.c | 197 +++ 3 files changed, 178 insertions(+), 64 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 9dfbc4216a..8ea27d3422 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1286,10 +1286,7 @@ static void finish_output_stream(OutputStream *ost) OutputFile *of = output_files[ost->file_index]; ost->finished = ENCODER_FINISHED; -if (ost->sq_idx_mux >= 0) -sq_send(of->sq_mux, ost->sq_idx_mux, SQPKT(NULL)); -else -ost->finished |= MUXER_FINISHED; +output_packet(of, ost->pkt, ost, 1); } /** @@ -3421,9 +3418,8 @@ static int need_output(void) for (i = 0; i < nb_output_streams; i++) { OutputStream *ost= output_streams[i]; -OutputFile *of = output_files[ost->file_index]; -if (ost->finished || of_finished(of)) +if (ost->finished) continue; return 1; @@ -4269,26 +4265,6 @@ static int transcode_step(void) return reap_filters(0); } -static void flush_sync_queues_mux(void) -{ -/* mark all queue inputs as done */ -for (int i = 0; i < nb_output_streams; i++) { -OutputStream *ost = output_streams[i]; -OutputFile *of = output_files[ost->file_index]; -if (ost->sq_idx_mux >= 0) -sq_send(of->sq_mux, ost->sq_idx_mux, SQPKT(NULL)); -} - -/* encode all packets remaining in the sync queues */ -for (int i = 0; i < nb_output_streams; i++) { -OutputStream *ost = output_streams[i]; -OutputFile *of = output_files[ost->file_index]; - -if (!(ost->finished & MUXER_FINISHED)) -output_packet(of, ost->pkt, ost, 1); -} -} - /* * The following code is the main loop of the file converter */ @@ -4310,6 +4286,12 @@ static int transcode(void) timer_start = av_gettime_relative(); +for (i = 0; i < nb_output_files; i++) { +ret = of_thread_start(output_files[i]); +if (ret < 0) +goto fail; +} + if ((ret = init_input_threads()) < 0) goto fail; @@ -4346,7 +4328,9 @@ static int transcode(void) } } flush_encoders(); -flush_sync_queues_mux(); + +for (i = 0; i < nb_output_files; i++) +of_thread_stop(output_files[i]); term_exit(); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 407342462f..c4a5c2a0a2 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -583,6 +583,8 @@ typedef struct OutputFile { const AVOutputFormat *format; const char *url; +AVThreadMessageQueue *mux_queue; + SyncQueue *sq_encode; SyncQueue *sq_mux; @@ -697,11 +699,14 @@ int hwaccel_decode_init(AVCodecContext *avctx); int of_muxer_init(OutputFile *of, AVFormatContext *fc, AVDictionary *opts, int64_t limit_filesize); + +int of_thread_start(OutputFile *of); +void of_thread_stop(OutputFile *of); + int of_write_trailer(OutputFile *of); void of_close(OutputFile **pof); int of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof); -int of_finished(OutputFile *of); int64_t of_filesize(OutputFile *of); AVChapter * const * of_get_chapters(OutputFile *of, unsigned int *nb_chapters); diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 6ca9a51dd6..f99dd5ec3e 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -16,17 +16,20 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include "ffmpeg.h" #include "sync_queue.h" +#include "thread_queue.h" #include "libavutil/fifo.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/mem.h" #include "libavutil/timestamp.h" +#include "libavutil/thread.h" #include "libavcodec/packet.h" @@ -46,18 +49,24 @@ typedef struct MuxStream { /* dts of the last packet sent to the muxer, in the stream timebase * used for making up missing dts values */ int64_t last_mux_dts; + +/* data (a real or a flush packet) was received for this stream */ +int got_data; } MuxStream; struct Muxer { AVFormatContext *fc; +pthread_tthread; +ThreadQueue *tq; + MuxStream *streams; AVDictionary *opts; /* filesize limit expressed in bytes */ int64_t limit_filesize; -int64_t final_filesize; +atomic_int_least64_t last_filesize; int header_written; }; @@ -221,13 +230,32 @@ static int queue_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt) return 0; } +static int64_t filesize(AVIOContext *pb) +{ +int64_t ret = -1; + +if (pb) { +ret = avio_size(pb); +if (ret <= 0) // FIXME improve avio_size() so it works with non seekable output too +ret = avio_tell(pb); +} + +return ret; +} + static int write_packet(OutputFile *of, OutputSt
Re: [FFmpeg-devel] [EXT] [PATCH v5 7/7] avcodec/v4l2_m2m_dec: setup capture queue before enqueue the first frame
> From: Andriy Gelman > Sent: Monday, April 4, 2022 6:29 AM > To: Ming Qian > Cc: FFmpeg development discussions and patches de...@ffmpeg.org> > Subject: Re: [FFmpeg-devel] [EXT] [PATCH v5 7/7] avcodec/v4l2_m2m_dec: > setup capture queue before enqueue the first frame > > Caution: EXT Email > > Hi Ming, > > Sorry for the late reply. > > On Tue, 29. Mar 06:51, Ming Qian wrote: > > > From: Andriy Gelman [mailto:andriy.gel...@gmail.com] > > > Sent: Saturday, March 26, 2022 11:43 PM > > > To: FFmpeg development discussions and patches > > > > > > Cc: Ming Qian > > > Subject: Re: [FFmpeg-devel] [EXT] [PATCH v5 7/7] > avcodec/v4l2_m2m_dec: > > > setup capture queue before enqueue the first frame > > > > > > Caution: EXT Email > > > > > > Hi Ming, > > > > > > On Mon, 21. Mar 07:27, Ming Qian wrote: > > > > Hi Andriy, > > > > > > > > What do you think of this patch? > > > > > > > > The Initialization flow defined in > > > linux/Documentation/userspace-api/media/v4l/dev-decoder.rst > > > > 1. Set the coded format on OUTPUT via VIDIOC_S_FMT(). > > > > 2. Allocate source (bytestream) buffers via VIDIOC_REQBUFS() on > OUTPUT. > > > > 3. Start streaming on the OUTPUT queue via VIDIOC_STREAMON(). > > > > 4. This step only applies to coded formats that contain resolution > > > information in the stream. Continue queuing/dequeuing bytestream > > > buffers to/from the OUTPUT queue via VIDIOC_QBUF() and > > > VIDIOC_DQBUF(). The buffers will be processed and returned to the > > > client in order, until required metadata to configure the CAPTURE > > > queue are found. This is indicated by the decoder sending a > > > V4L2_EVENT_SOURCE_CHANGE event with changes set to > V4L2_EVENT_SRC_CH_RESOLUTION. > > > > Note: A client capable of acquiring stream parameters from > > > > the > > > bytestream on its own may attempt to set the width and height of the > > > OUTPUT format to non-zero values matching the coded size of the > > > stream, skip this step and continue with the Capture Setup sequence. > > > > > > > > 5. Continue with the Capture Setup sequence. > > > > > > > > In ffmpeg's implementation, ffmpeg will set non-zero width and > > > > height > > > on output queue, so the step 4 should be skipped, and setup the > > > capture queue directly. > > > > So the flow should be: > > > > 1. Set the coded format and valid resolution on OUTPUT via > VIDIOC_S_FMT(). > > > > 2. Allocate source (bytestream) buffers via VIDIOC_REQBUFS() on > OUTPUT. > > > > 3. Start streaming on the OUTPUT queue via VIDIOC_STREAMON(). > > > > 5. Continue with the Capture Setup sequence. > > > > > > > > And this patch is just following the above flow. > > > > > > > > Ming > > > > > > The v4 version didn't work for me on odroid xu4 > > > > https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fffm > > > > peg.o%2F&data=04%7C01%7Cming.qian%40nxp.com%7Cfa858e4a13434 > ee727 > > > > 3508da15c1695b%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C6378 > 4621 > > > > 7684591813%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIj > oiV2luM > > > > zIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=wl%2BZaEBNIPZ > TOyv > > > 7dgmnHhSQyAs37PjZCkvhwPL%2B6xg%3D&reserved=0 > > > rg%2Fpipermail%2Fffmpeg-devel%2F2022- > January%2F290679.html&dat > > > > a=04%7C01%7Cming.qian%40nxp.com%7Cca988d592253473cbac408da0f3f4 > > > 801%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637839061704 > > > > 093567%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2 > l > > > > uMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=I80bpE70S6JI > > > 8A%2BaXQGq4JyxL0eBbtLN58p5SpqlA6s%3D&reserved=0 > > > > > > I haven't had time retest but don't think anything has changed. > > > > > > -- > > > Andriy > > > > Hi Andriy, > > I check the S5P MFC Video Codec driver, and indeed it requires the > > client > enqueue the output buffer which contains the sequence header. And in > vidioc_g_fmt(), driver will block and wait until the header is parsed. > > And indeed my patch will not work on it. > > But it seems don't meet the specification. > > For S5P MFC, the step 4 can't be skipped, and the client should wait the > V4L2_EVENT_SOURCE_CHANGE event before the step 5 setting up capture > queue. > > The ffmpeg v4l2 decoder don't skip step 4, but also doesn't wait the > V4L2_EVENT_SOURCE_CHANGE event. > > > > > So in current, we should make it work on more devices instead of more > spec? > > Personally I'd prefer not to break users. Odroid xu4 is a popular board afaik. > But I'm also not the maintainer of v4l2m2m. > > IMO it would be better the fix the problem in the driver first. > Hi Andriy, Thanks for your reply. Maybe I can try to work on the driver first. Ming. > > > > The Initialization flow defined in linux/Documentation/userspace- > api/media/v4l/dev-decoder.rst > > 1. Set the coded format on OUTPUT via VIDIOC_S_FMT(). > > 2. Allocate source (bytestream) buffers via VIDIOC_REQBUFS() on > OUTPUT. > > 3. Start stre
Re: [FFmpeg-devel] [PATCH] avfilter/alimiter: Remove the delay introduced by lookahead buffer
On Wed, Mar 30, 2022 at 11:05 PM Wang Cao wrote: > The change essentially removes the delay introduces by lookahead buffer. > The valid audio data in the internal buffer is also flushed to ensure > the integrity of output. > > This adds extra delay, and complicates current code a lot. > Signed-off-by: Wang Cao > --- > doc/filters.texi | 2 - > libavfilter/af_alimiter.c | 97 +- > tests/ref/fate/filter-alimiter | 518 - > 3 files changed, 344 insertions(+), 273 deletions(-) > > Thanks a lot for your time to review my patch. I have made "zero_delay" > option to default. Now the output samples will only be written after the > lookahead buffer is full. We also uses "request_frame" to flush the > internal buffers so that all valid input audio samples are written. > > diff --git a/doc/filters.texi b/doc/filters.texi > index d70ac3e237..5d1adf88e1 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -1943,8 +1943,6 @@ aiir=z=1.3057 0 0 0:p=1.3057 2.3892 2.1860 1:f=sf:r=d > > The limiter prevents an input signal from rising over a desired threshold. > This limiter uses lookahead technology to prevent your signal from > distorting. > -It means that there is a small delay after the signal is processed. Keep > in mind > -that the delay it produces is the attack time you set. > > The filter accepts the following options: > > diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c > index 133f98f165..e1fcf98574 100644 > --- a/libavfilter/af_alimiter.c > +++ b/libavfilter/af_alimiter.c > @@ -30,6 +30,7 @@ > > #include "audio.h" > #include "avfilter.h" > +#include "bufferqueue.h" > #include "formats.h" > #include "internal.h" > > @@ -55,6 +56,13 @@ typedef struct AudioLimiterContext { > int *nextpos; > double *nextdelta; > > +int total_samples_to_flush; > +int lookahead_buffer_full; > + > +struct FFBufQueue output_frame_queue; > +int output_sample_pos; > +int output_frame_pos; > + > double delta; > int nextiter; > int nextlen; > @@ -129,6 +137,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame > *in) > AVFrame *out; > double *buf; > int n, c, i; > +int can_free_input_frame = 0; > +double peak = 0; > > if (av_frame_is_writable(in)) { > out = in; > @@ -138,12 +148,23 @@ static int filter_frame(AVFilterLink *inlink, > AVFrame *in) > av_frame_free(&in); > return AVERROR(ENOMEM); > } > +can_free_input_frame = 1; > av_frame_copy_props(out, in); > } > -dst = (double *)out->data[0]; > + > +if (ff_bufqueue_is_full(&s->output_frame_queue)) { > +// In the runtime, the total number of frames in the queue is > bounded by > +// attack_time, sample rate and frame size. > +return AVERROR_BUG; > +} > + > +ff_bufqueue_add(ctx, &s->output_frame_queue, out); > > for (n = 0; n < in->nb_samples; n++) { > -double peak = 0; > +out = ff_bufqueue_peek(&s->output_frame_queue, > s->output_frame_pos); > +dst = (double *)out->data[0]; > +dst += s->output_sample_pos * channels; > +peak = 0; > > for (c = 0; c < channels; c++) { > double sample = src[c] * level_in; > @@ -213,8 +234,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame > *in) > > s->att += s->delta; > > -for (c = 0; c < channels; c++) > -dst[c] = buf[c] * s->att; > +// Checks lookahead buffer (s->buffer) has been filled > +if (!s->lookahead_buffer_full && (s->pos + channels) % > buffer_size == 0) { > +s->lookahead_buffer_full = 1; > +} > +if (s->lookahead_buffer_full) { > +for (c = 0; c < channels; c++) { > +dst[c] = buf[c] * s->att; > +dst[c] = av_clipd(dst[c], -limit, limit) * level * > level_out; > +} > +s->output_sample_pos++; > +if (s->output_sample_pos == out->nb_samples) { > +s->output_frame_pos++; > +s->output_sample_pos = 0; > +} > +} > > if ((s->pos + channels) % buffer_size == nextpos[s->nextiter]) { > if (s->auto_release) { > @@ -261,18 +295,55 @@ static int filter_frame(AVFilterLink *inlink, > AVFrame *in) > if (s->delta != 0. && fabs(s->delta) < 0.01) > s->delta = 0.; > > -for (c = 0; c < channels; c++) > -dst[c] = av_clipd(dst[c], -limit, limit) * level * level_out; > - > s->pos = (s->pos + channels) % buffer_size; > src += channels; > -dst += channels; > } > - > -if (in != out) > +if (can_free_input_frame) { > av_frame_free(&in); > +} > > -return ff_filter_frame(outlink, out); > +if (s->output_frame_pos > 0) { > +s->output_frame_pos--; > +out = ff_bufqueue_get(&s->output_fram
Re: [FFmpeg-devel] [PATCH] avfilter/alimiter: Add "flush_buffer" option to flush the remaining valid data to the output
On Sun, Mar 27, 2022 at 11:41 PM Marton Balint wrote: > > > On Sat, 26 Mar 2022, Wang Cao wrote: > > > The change in the commit will add some samples to the end of the audio > > stream. The intention is to add a "zero_delay" option eventually to not > > have the delay in the begining the output from alimiter due to > > lookahead. > > I was very much suprised to see that the alimiter filter actually delays > the audio - as in extra samples are inserted in the beginning and some > samples are cut in the end. This trashes A-V sync, so it is a bug IMHO. > > So unless somebody has some valid usecase for the legacy way of operation > I'd just simply change it to be "zero delay" without any additional user > option, in a single patch. > This is done by this patch in very complicated way and also it really should be optional. Something like in af_ladspa is more reasonable. > > Regards, > Marton > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
As I posted a patch on Apr. 3rd, you should use "desc_end" rather than "p_end" for get16() or get8() to parse each descriptor. On 2022/04/04 18:53, Jan Ekström wrote: From: Jan Ekström Additionally, they should not be probed, as this is essentially various types of binary data. Signed-off-by: Jan Ekström --- libavformat/mpegts.c| 48 + tests/fate/mpegts.mak | 3 ++ tests/ref/fate/mpegts-probe-sdt-data-stream | 14 ++ 3 files changed, 65 insertions(+) create mode 100644 tests/ref/fate/mpegts-probe-sdt-data-stream diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index da77b50669..3788faf848 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2512,6 +2512,13 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } p = desc_list_end; + +if (!ts->pkt && (stream_type >= 0x80 && stream_type <= 0xFF) && +st->codecpar->codec_id == AV_CODEC_ID_NONE) +// if we are reading headers, and still have a user private stream +// with no proper codec set, do not stop reading at PMT. Data +// streams are marked within SDT. +ts->stop_parse = 0; } if (!ts->pids[pcr_pid]) @@ -2691,6 +2698,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (val < 0) return; for (;;) { +struct Program *program = NULL; sid = get16(&p, p_end); if (sid < 0) break; @@ -2704,6 +2712,15 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len desc_list_end = p + desc_list_len; if (desc_list_end > p_end) break; + +program = get_program(ts, sid); + +if (!ts->pkt && program && program->pmt_found) +// if during header reading we have already received a PMT for +// this program and now have received an SDT for it, stop further +// reading at this point. +ts->stop_parse = 2; + for (;;) { desc_tag = get8(&p, desc_list_end); if (desc_tag < 0) @@ -2736,6 +2753,37 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len av_free(name); av_free(provider_name); break; +case 0x64: /* ETSI data broadcast descriptor; EN 300 468 6.2.11 */ +{ +AVStream *st = NULL; +FFStream *sti = NULL; + +uint16_t data_broadcast_id = get16(&p, p_end); // TS 101 162 s/p_end/desc_end/ +uint8_t component_tag = get8(&p, p_end); s/p_end/desc_end/ +if (!component_tag) +// no stream mapping according to component_tag +break; + +av_log(ts->stream, AV_LOG_TRACE, + "data broadcast id: %d, component tag: %d\n", + data_broadcast_id, component_tag); + +if (!program) +break; + +st = find_matching_stream(ts, 0, sid, component_tag + 1, 0, + program); +if (!st) +break; + +sti = ffstream(st); + +st->codecpar->codec_type = AVMEDIA_TYPE_DATA; +st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; +sti->request_probe = sti->need_parsing = 0; +sti->need_context_update = 1; +break; +} default: break; } diff --git a/tests/fate/mpegts.mak b/tests/fate/mpegts.mak index bbcbfc47b2..ae21ee87d0 100644 --- a/tests/fate/mpegts.mak +++ b/tests/fate/mpegts.mak @@ -19,6 +19,9 @@ FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS) += fate-mpegts-probe-pmt-merge fate-mpegts-probe-pmt-merge: SRC = $(TARGET_SAMPLES)/mpegts/pmtchange.ts fate-mpegts-probe-pmt-merge: CMD = run $(PROBE_CODEC_NAME_COMMAND) -merge_pmt_versions 1 -i "$(SRC)" +FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS, MP2) += fate-mpegts-probe-sdt-data-stream +fate-mpegts-probe-sdt-data-stream: SRC = $(TARGET_SAMPLES)/mpegts/mpegts_sdt_data_stream.ts +fate-mpegts-probe-sdt-data-stream: CMD = run $(PROBE_CODEC_NAME_COMMAND) -i "$(SRC)" FATE_SAMPLES_FFPROBE += $(FATE_MPEGTS_PROBE-yes) diff --git a/tests/ref/fate/mpegts-probe-sdt-data-stream b/tests/ref/fate/mpegts-probe-sdt-data-stream new file mode 100644 index 00..0b8e90962f --- /dev/null +++ b/tests/ref/fate/mpegts-probe-sdt-data-stream @@ -0,0 +1,14 @@ +[PROGRAM] +[STREAM] +codec_name=mp2 +[/STREAM] +[STREAM] +codec_name=bin_data +[/STREAM] +[/PROGRAM] +[STREAM] +codec_name=mp2 +[/STREAM] +[STREAM] +codec_name=bin_data +
Re: [FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
... and, it is better to check broken packet. On 2022/04/05 1:04, TADANO Tokumei wrote: As I posted a patch on Apr. 3rd, you should use "desc_end" rather than "p_end" for get16() or get8() to parse each descriptor. On 2022/04/04 18:53, Jan Ekström wrote: From: Jan Ekström Additionally, they should not be probed, as this is essentially various types of binary data. Signed-off-by: Jan Ekström --- libavformat/mpegts.c | 48 + tests/fate/mpegts.mak | 3 ++ tests/ref/fate/mpegts-probe-sdt-data-stream | 14 ++ 3 files changed, 65 insertions(+) create mode 100644 tests/ref/fate/mpegts-probe-sdt-data-stream diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index da77b50669..3788faf848 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2512,6 +2512,13 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } p = desc_list_end; + + if (!ts->pkt && (stream_type >= 0x80 && stream_type <= 0xFF) && + st->codecpar->codec_id == AV_CODEC_ID_NONE) + // if we are reading headers, and still have a user private stream + // with no proper codec set, do not stop reading at PMT. Data + // streams are marked within SDT. + ts->stop_parse = 0; } if (!ts->pids[pcr_pid]) @@ -2691,6 +2698,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (val < 0) return; for (;;) { + struct Program *program = NULL; sid = get16(&p, p_end); if (sid < 0) break; @@ -2704,6 +2712,15 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len desc_list_end = p + desc_list_len; if (desc_list_end > p_end) break; + + program = get_program(ts, sid); + + if (!ts->pkt && program && program->pmt_found) + // if during header reading we have already received a PMT for + // this program and now have received an SDT for it, stop further + // reading at this point. + ts->stop_parse = 2; + for (;;) { desc_tag = get8(&p, desc_list_end); if (desc_tag < 0) @@ -2736,6 +2753,37 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len av_free(name); av_free(provider_name); break; + case 0x64: /* ETSI data broadcast descriptor; EN 300 468 6.2.11 */ + { + AVStream *st = NULL; + FFStream *sti = NULL; + + uint16_t data_broadcast_id = get16(&p, p_end); // TS 101 162 s/p_end/desc_end/ if (data_broadcast_id < 0) break; + uint8_t component_tag = get8(&p, p_end); s/p_end/desc_end/ + if (!component_tag) if (component_tag <= 0) + // no stream mapping according to component_tag + break; + + av_log(ts->stream, AV_LOG_TRACE, + "data broadcast id: %d, component tag: %d\n", + data_broadcast_id, component_tag); + + if (!program) + break; + + st = find_matching_stream(ts, 0, sid, component_tag + 1, 0, + program); + if (!st) + break; + + sti = ffstream(st); + + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; + sti->request_probe = sti->need_parsing = 0; + sti->need_context_update = 1; + break; + } default: break; } diff --git a/tests/fate/mpegts.mak b/tests/fate/mpegts.mak index bbcbfc47b2..ae21ee87d0 100644 --- a/tests/fate/mpegts.mak +++ b/tests/fate/mpegts.mak @@ -19,6 +19,9 @@ FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS) += fate-mpegts-probe-pmt-merge fate-mpegts-probe-pmt-merge: SRC = $(TARGET_SAMPLES)/mpegts/pmtchange.ts fate-mpegts-probe-pmt-merge: CMD = run $(PROBE_CODEC_NAME_COMMAND) -merge_pmt_versions 1 -i "$(SRC)" +FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS, MP2) += fate-mpegts-probe-sdt-data-stream +fate-mpegts-probe-sdt-data-stream: SRC = $(TARGET_SAMPLES)/mpegts/mpegts_sdt_data_stream.ts +fate-mpegts-probe-sdt-data-stream: CMD = run $(PROBE_CODEC_NAME_COMMAND) -i "$(SRC)" FATE_SAMPLES_FFPROBE += $(FATE_MPEGTS_PROBE-yes) diff --git a/tests/ref/fate/mpegts-probe-sdt-data-stream b/tests/ref/fate/mpegts-probe-sdt-data-stream new file mode 100644 index 00..0b8e90962f --- /dev/null +++ b/tests/ref/fate/
Re: [FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
Ah, the variables should be int. On 2022/04/05 1:16, TADANO Tokumei wrote: ... and, it is better to check broken packet. On 2022/04/05 1:04, TADANO Tokumei wrote: As I posted a patch on Apr. 3rd, you should use "desc_end" rather than "p_end" for get16() or get8() to parse each descriptor. On 2022/04/04 18:53, Jan Ekström wrote: From: Jan Ekström Additionally, they should not be probed, as this is essentially various types of binary data. Signed-off-by: Jan Ekström --- libavformat/mpegts.c | 48 + tests/fate/mpegts.mak | 3 ++ tests/ref/fate/mpegts-probe-sdt-data-stream | 14 ++ 3 files changed, 65 insertions(+) create mode 100644 tests/ref/fate/mpegts-probe-sdt-data-stream diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index da77b50669..3788faf848 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2512,6 +2512,13 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } p = desc_list_end; + + if (!ts->pkt && (stream_type >= 0x80 && stream_type <= 0xFF) && + st->codecpar->codec_id == AV_CODEC_ID_NONE) + // if we are reading headers, and still have a user private stream + // with no proper codec set, do not stop reading at PMT. Data + // streams are marked within SDT. + ts->stop_parse = 0; } if (!ts->pids[pcr_pid]) @@ -2691,6 +2698,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (val < 0) return; for (;;) { + struct Program *program = NULL; sid = get16(&p, p_end); if (sid < 0) break; @@ -2704,6 +2712,15 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len desc_list_end = p + desc_list_len; if (desc_list_end > p_end) break; + + program = get_program(ts, sid); + + if (!ts->pkt && program && program->pmt_found) + // if during header reading we have already received a PMT for + // this program and now have received an SDT for it, stop further + // reading at this point. + ts->stop_parse = 2; + for (;;) { desc_tag = get8(&p, desc_list_end); if (desc_tag < 0) @@ -2736,6 +2753,37 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len av_free(name); av_free(provider_name); break; + case 0x64: /* ETSI data broadcast descriptor; EN 300 468 6.2.11 */ + { + AVStream *st = NULL; + FFStream *sti = NULL; + + uint16_t data_broadcast_id = get16(&p, p_end); // TS 101 162 s/p_end/desc_end/ int data_broadcast_id = get16(&p, desc_end); if (data_broadcast_id < 0) break; + uint8_t component_tag = get8(&p, p_end); s/p_end/desc_end/ int component_tag = get8(&p, desc_end); + if (!component_tag) if (component_tag <= 0) + // no stream mapping according to component_tag + break; + + av_log(ts->stream, AV_LOG_TRACE, + "data broadcast id: %d, component tag: %d\n", + data_broadcast_id, component_tag); + + if (!program) + break; + + st = find_matching_stream(ts, 0, sid, component_tag + 1, 0, + program); + if (!st) + break; + + sti = ffstream(st); + + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; + sti->request_probe = sti->need_parsing = 0; + sti->need_context_update = 1; + break; + } default: break; } diff --git a/tests/fate/mpegts.mak b/tests/fate/mpegts.mak index bbcbfc47b2..ae21ee87d0 100644 --- a/tests/fate/mpegts.mak +++ b/tests/fate/mpegts.mak @@ -19,6 +19,9 @@ FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS) += fate-mpegts-probe-pmt-merge fate-mpegts-probe-pmt-merge: SRC = $(TARGET_SAMPLES)/mpegts/pmtchange.ts fate-mpegts-probe-pmt-merge: CMD = run $(PROBE_CODEC_NAME_COMMAND) -merge_pmt_versions 1 -i "$(SRC)" +FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS, MP2) += fate-mpegts-probe-sdt-data-stream +fate-mpegts-probe-sdt-data-stream: SRC = $(TARGET_SAMPLES)/mpegts/mpegts_sdt_data_stream.ts +fate-mpegts-probe-sdt-data-stream: CMD = run $(PROBE_CODEC_NAME_COMMAND) -i "$(SRC)" FATE_SAMPLES_F
Re: [FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
On Mon, Apr 4, 2022 at 7:04 PM TADANO Tokumei wrote: > > As I posted a patch on Apr. 3rd, you should use "desc_end" rather than "p_end" > for get16() or get8() to parse each descriptor. > Yes, I had noticed and planned to look into those patches, but did not have the time to do that yet. Also FYI, this mailing list utilizes bottom posting, not top posting. Jan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/mpegts: set data broadcast streams as such
On Mon, Apr 4, 2022 at 7:32 PM TADANO Tokumei wrote: > > Ah, the variables should be int. > > On 2022/04/05 1:16, TADANO Tokumei wrote: > > ... and, it is better to check broken packet. > > Yes. I guess I'll swap those for ints, although I like having the original unsigned sizes :) . I think alternatively it could be checked whether there is enough data before hand, since the only error seems to be if there is not enough data available. In this case it would be three bytes I think, 16+8 bits. Jan ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avfilter/alimiter: Add "flush_buffer" option to flush the remaining valid data to the output
On Mon, 4 Apr 2022, Paul B Mahol wrote: On Sun, Mar 27, 2022 at 11:41 PM Marton Balint wrote: On Sat, 26 Mar 2022, Wang Cao wrote: The change in the commit will add some samples to the end of the audio stream. The intention is to add a "zero_delay" option eventually to not have the delay in the begining the output from alimiter due to lookahead. I was very much suprised to see that the alimiter filter actually delays the audio - as in extra samples are inserted in the beginning and some samples are cut in the end. This trashes A-V sync, so it is a bug IMHO. So unless somebody has some valid usecase for the legacy way of operation I'd just simply change it to be "zero delay" without any additional user option, in a single patch. This is done by this patch in very complicated way and also it really should be optional. But why does it make sense to keep the current (IMHO buggy) operational mode which adds silence in the beginning and trims the end? I understand that the original implementation worked like this, but libavfilter has packet timestamps and N:M filtering so there is absolutely no reason to use an 1:1 implementation and live with its limitations. Regards, Marton ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] FFmpeg 4.4.2
Hi I intend to do a 4.4.2 release from the release/4.4 branch in the next days as its high time to make a new release with all the bugfixes so if you want to backport something please do so after that the other releases branches which are still on downstreams should follow as i have time thx -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Homeopathy is like voting while filling the ballot out with transparent ink. Sometimes the outcome one wanted occurs. Rarely its worse than filling out a ballot properly. signature.asc Description: PGP signature ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] ffmpeg: document -d option
Quoting Stefano Sabatini (2022-04-03 17:27:06) > Option was added in commit 39aafa5ee90e10382e. > > Fix trac issue: http://trac.ffmpeg.org/ticket/1698 > --- > doc/ffmpeg.texi | 12 > fftools/ffmpeg_opt.c | 3 +++ > 2 files changed, 15 insertions(+) Does this option do anything useful? Shouldn't it rather be removed? -- Anton Khirnov ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2 1/4] avutil: add ambient viewing environment metadata side data
On Mon, Mar 28, 2022 at 08:41:08PM +0800, lance.lmw...@gmail.com wrote: > From: Limin Wang > > Signed-off-by: Limin Wang > --- > libavutil/frame.c | 1 + > libavutil/frame.h | 6 + > libavutil/mastering_display_metadata.c | 23 + > libavutil/mastering_display_metadata.h | 45 > ++ > 4 files changed, 75 insertions(+) > > diff --git a/libavutil/frame.c b/libavutil/frame.c > index fbb869f..8882da2 100644 > --- a/libavutil/frame.c > +++ b/libavutil/frame.c > @@ -815,6 +815,7 @@ const char *av_frame_side_data_name(enum > AVFrameSideDataType type) > case AV_FRAME_DATA_DETECTION_BBOXES:return "Bounding boxes > for object detection and classification"; > case AV_FRAME_DATA_DOVI_RPU_BUFFER: return "Dolby Vision RPU > Data"; > case AV_FRAME_DATA_DOVI_METADATA: return "Dolby Vision > Metadata"; > +case AV_FRAME_DATA_AMBIENT_VIEWING_ENV: return "Ambient Viewing > Environment"; > } > return NULL; > } > diff --git a/libavutil/frame.h b/libavutil/frame.h > index 33fac20..f7b1d4e 100644 > --- a/libavutil/frame.h > +++ b/libavutil/frame.h > @@ -209,6 +209,12 @@ enum AVFrameSideDataType { > * volume transform - CUVA 005.1-2021. > */ > AV_FRAME_DATA_DYNAMIC_HDR_VIVID, > + > +/** > + * ambient viewing environment for a video frame, as described by > + * the AVAmbientViewingEnvMetadata. > + */ > +AV_FRAME_DATA_AMBIENT_VIEWING_ENV, > }; > > enum AVActiveFormatDescription { > diff --git a/libavutil/mastering_display_metadata.c > b/libavutil/mastering_display_metadata.c > index 6069347..ba1c80f 100644 > --- a/libavutil/mastering_display_metadata.c > +++ b/libavutil/mastering_display_metadata.c > @@ -64,3 +64,26 @@ AVContentLightMetadata > *av_content_light_metadata_create_side_data(AVFrame *fram > > return (AVContentLightMetadata *)side_data->data; > } > + > +AVAmbientViewingEnvMetadata *av_ambient_viewing_env_metadata_alloc(size_t > *size) > +{ > +AVAmbientViewingEnvMetadata *metadata = av_mallocz(sizeof(*metadata)); > + > +if (size) > +*size = sizeof(*metadata); > + > +return metadata; > +} > + > +AVAmbientViewingEnvMetadata > *av_ambient_viewing_env_metadata_create_side_data(AVFrame *frame) > +{ > +AVFrameSideData *side_data = av_frame_new_side_data(frame, > +AV_FRAME_DATA_AMBIENT_VIEWING_ENV, > +sizeof(AVAmbientViewingEnvMetadata)); > +if (!side_data) > +return NULL; > + > +memset(side_data->data, 0, sizeof(AVAmbientViewingEnvMetadata)); > + > +return (AVAmbientViewingEnvMetadata *)side_data->data; > +} > diff --git a/libavutil/mastering_display_metadata.h > b/libavutil/mastering_display_metadata.h > index c23b07c..d7598c1 100644 > --- a/libavutil/mastering_display_metadata.h > +++ b/libavutil/mastering_display_metadata.h > @@ -125,4 +125,49 @@ AVContentLightMetadata > *av_content_light_metadata_alloc(size_t *size); > */ > AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame > *frame); > > +/** > + * The characteristics of the nominal ambient viewing environment for > + * the display of the associated video content. > + * To be used as payload of a AVFrameSideData the appropriate type. > + * > + * @note The struct should be allocated with > av_ambient_viewing_env_metadata_alloc() > + * and its size is not a part of the public ABI. > + */ > +typedef struct AVAmbientViewingEnvMetadata { > +/** > + * specifies the environmental illuminance of the ambient viewing > + * environment in units of 0.0001 lux. > + * ambient_illuminance shall not be equal to 0. > + */ > +uint32_t ambient_illuminance; > +/** > + * specify the normalized x and y chromaticity coordinates, respectively, > + * of the environmental ambient light in the nominal viewing environment, > + * according to the CIE 1931 definition of x and y as specified in ISO > + * 11664-1 (see also ISO 11664-3 and CIE 15), in normalized increments of > + * 0.2. The values of ambient_light_x and ambient_light_y shall be in > + * the range of 0 to 5 > + */ > +uint16_t ambient_light_x; > +uint16_t ambient_light_y; > +} AVAmbientViewingEnvMetadata; > + > +/** > + * Allocate an AVAmbientViewingEnvMetadata structure and set its fields to > + * default values. The resulting struct can be freed using av_freep(). > + * > + * @return An AVAmbientViewingEnvMetadata filled with default values or NULL > + * on failure. > + */ > +AVAmbientViewingEnvMetadata *av_ambient_viewing_env_metadata_alloc(size_t > *size); > + > +/** > + * Allocate a complete AVAmbientViewingEnvMetadata and add it to the frame. > + * > + * @param frame The frame which side data is added to. > + * > + * @return The AVAmbientViewingEnvMetadata structure to be filled by caller. > + */ > +AVAmbientViewingEnvMeta
[FFmpeg-devel] [PATCH] libavcodec/hevcdec: detect non-conformant missing refs
For cases which prefer rejecting broken bitstreams. --- libavcodec/hevc_refs.c | 15 --- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c index fe18ca2b1d..7ea70e301b 100644 --- a/libavcodec/hevc_refs.c +++ b/libavcodec/hevc_refs.c @@ -426,7 +426,7 @@ static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc) /* add a reference with the given poc to the list and mark it as used in DPB */ static int add_candidate_ref(HEVCContext *s, RefPicList *list, - int poc, int ref_flag, uint8_t use_msb) + int poc, int ref_flag, uint8_t use_msb, int maybe_missing) { HEVCFrame *ref = find_ref_idx(s, poc, use_msb); @@ -434,6 +434,9 @@ static int add_candidate_ref(HEVCContext *s, RefPicList *list, return AVERROR_INVALIDDATA; if (!ref) { +if ((s->avctx->err_recognition & AV_EF_COMPLIANT) && !maybe_missing) +return AVERROR_INVALIDDATA; + ref = generate_missing_ref(s, poc); if (!ref) return AVERROR(ENOMEM); @@ -476,6 +479,7 @@ int ff_hevc_frame_rps(HEVCContext *s) for (i = 0; i < short_rps->num_delta_pocs; i++) { int poc = s->poc + short_rps->delta_poc[i]; int list; +int maybe_missing; if (!short_rps->used[i]) list = ST_FOLL; @@ -484,7 +488,10 @@ int ff_hevc_frame_rps(HEVCContext *s) else list = ST_CURR_AFT; -ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF, 1); +maybe_missing = list != ST_CURR_BEF && list != ST_CURR_AFT; + +ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF, 1, +maybe_missing); if (ret < 0) goto fail; } @@ -493,8 +500,10 @@ int ff_hevc_frame_rps(HEVCContext *s) for (i = 0; i < long_rps->nb_refs; i++) { int poc = long_rps->poc[i]; int list = long_rps->used[i] ? LT_CURR : LT_FOLL; +int maybe_missing = list != LT_CURR; -ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF, long_rps->poc_msb_present[i]); +ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF, long_rps->poc_msb_present[i], +maybe_missing); if (ret < 0) goto fail; } -- 2.35.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".