[FFmpeg-devel] [PATCH] ffprobe: Stash and use width and height before opening the codec
Derek Buitenhuis
derek.buitenhuis at gmail.com
Fri Mar 1 16:41:34 CET 2013
Some codecs, such as VP6, will only have their correct width and
height set if a few frames have been decoded. This is accomplished
when we call avformat_find_stream_info(). However, we call
avcodec_open2() after this, which can possibly reset the width
and height in the decoder's context to an erroneous value.
Stash and propagate the width and height after calling
avformat_find_stream_info(), but before calling avcodec_open2().
Signed-off-by: Derek Buitenhuis <derek.buitenhuis at gmail.com>
---
ffprobe.c | 46 ++++++++++++++++++++++++++++++++++++----------
1 file changed, 36 insertions(+), 10 deletions(-)
diff --git a/ffprobe.c b/ffprobe.c
index f70c24c..f4074d4 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -1592,7 +1592,8 @@ static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
}
}
-static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
+static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx,
+ int stream_idx, int orig_width, int orig_height)
{
AVStream *stream = fmt_ctx->streams[stream_idx];
AVCodecContext *dec_ctx;
@@ -1641,8 +1642,8 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
switch (dec_ctx->codec_type) {
case AVMEDIA_TYPE_VIDEO:
- print_int("width", dec_ctx->width);
- print_int("height", dec_ctx->height);
+ print_int("width", orig_width);
+ print_int("height", orig_height);
print_int("has_b_frames", dec_ctx->has_b_frames);
sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
if (sar.den) {
@@ -1742,13 +1743,19 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
fflush(stdout);
}
-static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
+typedef struct Dimension {
+ int width;
+ int height;
+} Dimension;
+
+static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx,
+ Dimension *orig_dims)
{
int i;
writer_print_section_header(w, SECTION_ID_STREAMS);
for (i = 0; i < fmt_ctx->nb_streams; i++)
if (selected_streams[i])
- show_stream(w, fmt_ctx, i);
+ show_stream(w, fmt_ctx, i, orig_dims[i].width, orig_dims[i].height);
writer_print_section_footer(w);
}
@@ -1791,7 +1798,8 @@ static void show_error(WriterContext *w, int err)
writer_print_section_footer(w);
}
-static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
+static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename,
+ Dimension **orig_dims)
{
int err, i;
AVFormatContext *fmt_ctx = NULL;
@@ -1807,8 +1815,6 @@ static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
return AVERROR_OPTION_NOT_FOUND;
}
-
- /* fill the streams in the format context */
if ((err = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
print_error(filename, err);
return err;
@@ -1816,11 +1822,27 @@ static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
av_dump_format(fmt_ctx, 0, filename, 0);
+ /*
+ * Allocate our dimensions buffer.
+ * We need to stash the dimensions before we call avcodec_open2(),
+ * because some codecs require a few frames to be decoded before
+ * width and height are set properly, and avcodec_open2() can
+ * reset these values.
+ */
+ if (!(*orig_dims = av_mallocz(sizeof(**orig_dims) * fmt_ctx->nb_streams))) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not allocate temporary dimensions buffer.\n");
+ return AVERROR(ENOMEM);
+ }
+
/* bind a decoder to each input stream */
for (i = 0; i < fmt_ctx->nb_streams; i++) {
AVStream *stream = fmt_ctx->streams[i];
AVCodec *codec;
+ (*orig_dims)[i].width = stream->codec->width;
+ (*orig_dims)[i].height = stream->codec->height;
+
if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
av_log(NULL, AV_LOG_ERROR,
"Failed to probe codec for input stream %d\n",
@@ -1855,13 +1877,14 @@ static void close_input_file(AVFormatContext **ctx_ptr)
static int probe_file(WriterContext *wctx, const char *filename)
{
AVFormatContext *fmt_ctx;
+ Dimension *orig_dims;
int ret, i;
int section_id;
do_read_frames = do_show_frames || do_count_frames;
do_read_packets = do_show_packets || do_count_packets;
- ret = open_input_file(&fmt_ctx, filename);
+ ret = open_input_file(&fmt_ctx, filename, &orig_dims);
if (ret >= 0) {
nb_streams_frames = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_frames));
nb_streams_packets = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_packets));
@@ -1896,7 +1919,7 @@ static int probe_file(WriterContext *wctx, const char *filename)
writer_print_section_footer(wctx);
}
if (do_show_streams)
- show_streams(wctx, fmt_ctx);
+ show_streams(wctx, fmt_ctx, orig_dims);
if (do_show_format)
show_format(wctx, fmt_ctx);
@@ -1906,6 +1929,9 @@ static int probe_file(WriterContext *wctx, const char *filename)
av_freep(&nb_streams_packets);
av_freep(&selected_streams);
}
+
+ av_freep(&orig_dims);
+
return ret;
}
--
1.7.10.4
More information about the ffmpeg-devel
mailing list