[FFmpeg-devel] [PATCH] ffprobe: add -codec:<media_spec> option
Maryla Ustarroz
maryla at google.com
Tue Jul 29 16:15:55 EEST 2025
On Mon, Jul 28, 2025 at 10:07 PM Stefano Sabatini <stefasab at gmail.com> wrote:
>
> Hi, sorry for the slow reply.
>
> On date Tuesday 2025-06-10 17:02:05 +0200, ffmpeg-devel Mailing List wrote:
> > From: Maryla Ustarroz-Calonge <maryla at google.com>
> > Subject: [PATCH] ffprobe: add -codec:<media_spec> option
> > Date: Tue, 10 Jun 2025 17:02:05 +0200
> > To: ffmpeg-devel at ffmpeg.org
> > X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog
> >
> > opt_codec() is mostly copied over from ffplay.c
> >
> > Signed-off-by: Maryla Ustarroz-Calonge <maryla at google.com>
> > ---
> > Changelog | 2 +-
> > fftools/ffprobe.c | 114 +++++++++++++++++++++++++++++++++++++++++-----
> > 2 files changed, 103 insertions(+), 13 deletions(-)
> >
> > diff --git a/Changelog b/Changelog
> > index 4217449438..ae73611222 100644
> > --- a/Changelog
> > +++ b/Changelog
> > @@ -18,7 +18,7 @@ version <next>:
> > - APV encoding support through a libopenapv wrapper
> > - VVC decoder supports all content of SCC (Screen Content Coding):
> > IBC (Inter Block Copy), Palette Mode and ACT (Adaptive Color Transform
> > -
> > +- ffprobe -codec option
> >
> > version 7.1:
> > - Raw Captions with Time (RCWT) closed caption demuxer
> > diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
> > index 1346ed33c5..0124ce114c 100644
> > --- a/fftools/ffprobe.c
> > +++ b/fftools/ffprobe.c
> > @@ -36,6 +36,7 @@
> > #include "libavutil/ambient_viewing_environment.h"
> > #include "libavutil/avassert.h"
> > #include "libavutil/avstring.h"
> > +#include "libavutil/avutil.h"
> > #include "libavutil/bprint.h"
> > #include "libavutil/channel_layout.h"
> > #include "libavutil/display.h"
> > @@ -130,6 +131,11 @@ static int use_byte_value_binary_prefix = 0;
> > static int use_value_sexagesimal_format = 0;
> > static int show_private_data = 1;
> >
> > +static const char *audio_codec_name = NULL;
> > +static const char *data_codec_name = NULL;
> > +static const char *subtitle_codec_name = NULL;
> > +static const char *video_codec_name = NULL;
> > +
> > #define SHOW_OPTIONAL_FIELDS_AUTO -1
> > #define SHOW_OPTIONAL_FIELDS_NEVER 0
> > #define SHOW_OPTIONAL_FIELDS_ALWAYS 1
> > @@ -2284,6 +2290,64 @@ static void show_error(AVTextFormatContext *tfc, int err)
> > avtext_print_section_footer(tfc);
> > }
> >
> > +static int get_decoder_by_name(const char *codec_name, const AVCodec **codec)
> > +{
> > + if (codec_name == NULL)
> > + return 0;
> > +
> > + *codec = avcodec_find_decoder_by_name(codec_name);
> > + if (*codec == NULL) {
> > + av_log(NULL, AV_LOG_ERROR,
> > + "No codec could be found with name '%s'\n", codec_name);
>
> > + return AVERROR(EINVAL);;
>
> nit: drop duplicated ;
Thank you for the review.
This is already fixed in v2 of the patch.
https://ffmpeg.org/pipermail/ffmpeg-devel/2025-June/345891.html
V2 also adds a shorter -c:<media_specifier> version of the flag, as
suggested by Marvin.
> > + }
> > + return 0;
> > +}
> > +
> > +static int set_decoders(AVFormatContext *fmt_ctx)
> > +{
> > + int ret;
> > + ret = get_decoder_by_name(audio_codec_name, &fmt_ctx->audio_codec);
> > + if (ret < 0) return ret;
> > + ret = get_decoder_by_name(data_codec_name, &fmt_ctx->data_codec);
> > + if (ret < 0) return ret;
> > + ret = get_decoder_by_name(subtitle_codec_name, &fmt_ctx->subtitle_codec);
> > + if (ret < 0) return ret;
> > + ret = get_decoder_by_name(video_codec_name, &fmt_ctx->video_codec);
> > + if (ret < 0) return ret;
> > + return 0;
> > +}
> > +
> > +static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream *stream)
> > +{
> > + const AVCodec *codec = NULL;
> > + switch (stream->codecpar->codec_type) {
> > + case AVMEDIA_TYPE_VIDEO: codec = fmt_ctx->video_codec; break;
> > + case AVMEDIA_TYPE_AUDIO: codec = fmt_ctx->audio_codec; break;
> > + case AVMEDIA_TYPE_SUBTITLE: codec = fmt_ctx->subtitle_codec; break;
> > + case AVMEDIA_TYPE_DATA: codec = fmt_ctx->data_codec; break;
> > + }
> > +
> > + if (codec != NULL)
> > + return codec;
> > +
> > + if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
> > + av_log(NULL, AV_LOG_WARNING,
> > + "Failed to probe codec for input stream %d\n", stream->index);
> > + return NULL;
> > + }
> > +
> > + codec = avcodec_find_decoder(stream->codecpar->codec_id);
> > + if (codec == NULL) {
> > + av_log(NULL, AV_LOG_WARNING,
> > + "Unsupported codec with id %d for input stream %d\n",
> > + stream->codecpar->codec_id, stream->index);
> > + return NULL;
> > + }
> > +
> > + return codec;
> > +}
> > +
> > static int open_input_file(InputFile *ifile, const char *filename,
> > const char *print_filename)
> > {
> > @@ -2296,6 +2360,9 @@ static int open_input_file(InputFile *ifile, const char *filename,
> > if (!fmt_ctx)
> > return AVERROR(ENOMEM);
> >
> > + err = set_decoders(fmt_ctx);
> > + if (err < 0)
> > + return err;
> > if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
> > av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
> > scan_all_pmts_set = 1;
> > @@ -2350,20 +2417,10 @@ static int open_input_file(InputFile *ifile, const char *filename,
> >
> > ist->st = stream;
> >
> > - if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
> > - av_log(NULL, AV_LOG_WARNING,
> > - "Failed to probe codec for input stream %d\n",
> > - stream->index);
> > + codec = get_decoder_for_stream(fmt_ctx, stream);
> > + if (!codec)
> > continue;
> > - }
> >
> > - codec = avcodec_find_decoder(stream->codecpar->codec_id);
> > - if (!codec) {
> > - av_log(NULL, AV_LOG_WARNING,
> > - "Unsupported codec with id %d for input stream %d\n",
> > - stream->codecpar->codec_id, stream->index);
> > - continue;
> > - }
> > {
> > AVDictionary *opts;
> >
> > @@ -2510,6 +2567,10 @@ end:
> > av_freep(&selected_streams);
> > av_freep(&streams_with_closed_captions);
> > av_freep(&streams_with_film_grain);
> > + av_freep(&audio_codec_name);
> > + av_freep(&data_codec_name);
> > + av_freep(&subtitle_codec_name);
> > + av_freep(&video_codec_name);
> >
> > return ret;
> > }
> > @@ -2964,6 +3025,34 @@ static int opt_sections(void *optctx, const char *opt, const char *arg)
> > return 0;
> > }
> >
> > +static int opt_codec(void *optctx, const char *opt, const char *arg)
> > +{
> > + const char *spec = strchr(opt, ':');
> > + const char **name;
> > + if (!spec) {
> > + av_log(NULL, AV_LOG_ERROR,
> > + "No media specifier was specified for '%s' in option '%s'. Use -%s:<media_spec>\n",
> > + arg, opt, opt);
> > + return AVERROR(EINVAL);
> > + }
> > + spec++;
> > +
> > + switch (spec[0]) {
> > + case 'a' : name = &audio_codec_name; break;
> > + case 'd' : name = &data_codec_name; break;
> > + case 's' : name = &subtitle_codec_name; break;
> > + case 'v' : name = &video_codec_name; break;
> > + default:
> > + av_log(NULL, AV_LOG_ERROR,
> > + "Invalid media specifier '%s' in option '%s'. Must be one of: v, a, s, d\n", spec, opt);
> > + return AVERROR(EINVAL);
> > + }
> > +
> > + av_freep(name);
> > + *name = av_strdup(arg);
> > + return *name ? 0 : AVERROR(ENOMEM);
> > +}
> > +
>
> Not super happy that this is duplicated but I see no sane way to
> factorize it.
>
> > static int opt_show_versions(void *optctx, const char *opt, const char *arg)
> > {
> > mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
> > @@ -3039,6 +3128,7 @@ static const OptionDef real_options[] = {
> > { "print_filename", OPT_TYPE_FUNC, OPT_FUNC_ARG, {.func_arg = opt_print_filename}, "override the printed input filename", "print_file"},
> > { "find_stream_info", OPT_TYPE_BOOL, OPT_INPUT | OPT_EXPERT, { &find_stream_info },
> > "read and decode the streams to fill missing information with heuristics" },
> > + { "codec", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
> > { NULL, },
> > };
>
> Please also add an update for the docs and a short explanation of the
> use case in the commit log.
In v2 I added a line to the changelog and also updated ffprobe.texi
When you say "commit log", do you mean the changelog? Or the patch description?
I can add the following wherever is appropriate:
"Useful when different decoders have different capabilities, or to
test a specific decoder".
>
> Thanks.
More information about the ffmpeg-devel
mailing list