Skip to content

Commit

Permalink
Merge pull request #519 from jellyfin/ffprobe-first-vframe
Browse files Browse the repository at this point in the history
fftools/ffprobe: add only_first_vframe option to show first video frame info
  • Loading branch information
gnattu authored Jan 21, 2025
2 parents 5222ba3 + fce96f7 commit 9ba6e9a
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
126 changes: 126 additions & 0 deletions debian/patches/0085-add-first-vframe-only-to-ffprobe.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
Index: FFmpeg/fftools/ffprobe.c
===================================================================
--- FFmpeg.orig/fftools/ffprobe.c
+++ FFmpeg/fftools/ffprobe.c
@@ -146,6 +146,8 @@ static int show_private_data
#define SHOW_OPTIONAL_FIELDS_ALWAYS 1
static int show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;

+static int only_show_first_video_frame = 0;
+
static char *output_format;
static char *stream_specifier;
static char *show_data_hash;
@@ -3086,9 +3088,10 @@ static int read_interval_packets(WriterC
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
AVPacket *pkt = NULL;
AVFrame *frame = NULL;
- int ret = 0, i = 0, frame_count = 0;
+ int ret = 0, i = 0, frame_count = 0, nb_video_streams = 0;
int64_t start = -INT64_MAX, end = interval->end;
int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
+ unsigned char *checked_stream = NULL;

av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
log_read_interval(interval, NULL, AV_LOG_VERBOSE);
@@ -3127,12 +3130,51 @@ static int read_interval_packets(WriterC
ret = AVERROR(ENOMEM);
goto end;
}
+
+ if (only_show_first_video_frame) {
+ int si = 0;
+ checked_stream = av_calloc(nb_streams, sizeof(unsigned char));
+ if (!checked_stream) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ for (si = 0; si < nb_streams; si ++) {
+ AVCodecParameters *par = ifile->streams[si].st->codecpar;
+ if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
+ nb_video_streams++;
+ selected_streams[si] = 1;
+ }
+ }
+ }
while (!av_read_frame(fmt_ctx, pkt)) {
if (fmt_ctx->nb_streams > nb_streams) {
REALLOCZ_ARRAY_STREAM(nb_streams_frames, nb_streams, fmt_ctx->nb_streams);
REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
REALLOCZ_ARRAY_STREAM(selected_streams, nb_streams, fmt_ctx->nb_streams);
- nb_streams = fmt_ctx->nb_streams;
+
+ if (checked_stream) {
+ unsigned char *checked_stream_extended = NULL;
+ int si = 0;
+ checked_stream_extended = av_calloc(fmt_ctx->nb_streams, sizeof(unsigned char));
+ if (!checked_stream) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ memcpy(checked_stream_extended, checked_stream, nb_streams * sizeof(unsigned char));
+ av_freep(&checked_stream);
+ checked_stream = checked_stream_extended;
+
+ nb_video_streams = 0;
+ for (si = 0; si < fmt_ctx->nb_streams; si ++) {
+ AVCodecParameters *par = ifile->streams[si].st->codecpar;
+ if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
+ nb_video_streams++;
+ selected_streams[si] = 1;
+ }
+ }
+ }
+ nb_streams = (int)fmt_ctx->nb_streams;
}
if (selected_streams[pkt->stream_index]) {
AVRational tb = ifile->streams[pkt->stream_index].st->time_base;
@@ -3159,6 +3201,12 @@ static int read_interval_packets(WriterC
}

frame_count++;
+
+ if (only_show_first_video_frame) {
+ AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar;
+ if (par->codec_type != AVMEDIA_TYPE_VIDEO) continue;
+ }
+
if (do_read_packets) {
if (do_show_packets)
show_packet(w, ifile, pkt, i++);
@@ -3179,6 +3227,16 @@ static int read_interval_packets(WriterC

while (process_frame(w, ifile, frame, pkt, &packet_new) > 0);
}
+ if (only_show_first_video_frame) {
+ int nb_checked_streams = 0, si = 0;
+ checked_stream[pkt->stream_index] = 1;
+ for (si = 0; si < nb_streams; si ++) {
+ nb_checked_streams += checked_stream[si];
+ }
+ if (nb_checked_streams >= nb_video_streams) {
+ break;
+ }
+ }
}
av_packet_unref(pkt);
}
@@ -3196,6 +3254,9 @@ static int read_interval_packets(WriterC
end:
av_frame_free(&frame);
av_packet_free(&pkt);
+ if (checked_stream) {
+ av_freep(&checked_stream);
+ }
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
log_read_interval(interval, NULL, AV_LOG_ERROR);
@@ -4587,6 +4648,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" },
+ { "only_first_vframe", OPT_TYPE_BOOL, 0, { &only_show_first_video_frame }, "only show first video frame when show_frames is used" },
{ NULL, },
};

1 change: 1 addition & 0 deletions debian/patches/series
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@
0082-fix-ass-incorrect-null-copy.patch
0083-default-to-input-timebase-for-streamcopy.patch
0084-fix-a-race-condition-in-vaapi-csc-to-yuv420p.patch
0085-add-first-vframe-only-to-ffprobe.patch

0 comments on commit 9ba6e9a

Please sign in to comment.