[PATCH] ffprobe: implement -show_frames option
Stefano Sabatini
stefano.sabatini-lala
Sat Mar 12 19:14:42 CET 2011
---
ffprobe.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 238 insertions(+), 6 deletions(-)
diff --git a/ffprobe.c b/ffprobe.c
index d7362dd..66932ad 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -32,6 +32,8 @@ const char program_name[] = "FFprobe";
const int program_birth_year = 2007;
static int do_show_format = 0;
+static int do_show_frames = 0;
+static int do_read_packets = 0;
static int do_show_packets = 0;
static int do_show_streams = 0;
@@ -144,14 +146,228 @@ static void show_packet(AVFormatContext *fmt_ctx, AVPacket *pkt)
printf("[/PACKET]\n");
}
-static void show_packets(AVFormatContext *fmt_ctx)
+typedef struct FrameData {
+ struct AVStream *st; ///< the stream to which the frame belongs
+ void *frame; ///< the video frame, a samples buffer, a subtitle
+ int size; ///< the size of the (compressed) frame
+ int decoded_size; ///< the size of the decoded frame, 0 if meaningless/unused
+ int64_t pkt_pts;
+ int64_t pkt_dts;
+ int64_t pkt_duration;
+ int64_t pkt_pos;
+} FrameData;
+
+#define FILL_FRAME_DATA_FROM_PKT(frame_data, pkt) \
+ frame_data->pkt_pts = pkt->pts; \
+ frame_data->pkt_dts = pkt->dts; \
+ frame_data->pkt_duration = pkt->duration; \
+ frame_data->pkt_pos = pkt->pos; \
+
+/**
+ * This function is called when allocating the frame: in some cases
+ * the frame is not returned immediately, you have to wait for another
+ * call to avcodec_decode_video(), but we need to fill the frame_data
+ * struct with information from the current packet.
+ */
+static int ffprobe_get_buffer(AVCodecContext *codec_ctx, AVFrame *frame)
+{
+ AVStream *st = codec_ctx->opaque;
+ AVPacket *pkt;
+ FrameData *frame_data;
+ int ret = avcodec_default_get_buffer(codec_ctx, frame);
+ if (ret < 0)
+ return ret;
+
+ frame_data = av_malloc(sizeof(FrameData));
+ if (!frame_data)
+ return AVERROR(ENOMEM);
+
+ pkt = st->codec->pkt;
+ frame_data->st = st;
+ FILL_FRAME_DATA_FROM_PKT(frame_data, pkt);
+ frame_data->frame = frame;
+
+ frame->opaque = frame_data;
+ return ret;
+}
+
+static void ffprobe_release_buffer(AVCodecContext *codec_ctx, AVFrame *frame)
+{
+ FrameData *frame_data = (FrameData *)frame->opaque;
+ av_freep(&frame_data);
+ avcodec_default_release_buffer(codec_ctx, frame);
+}
+
+/**
+ * Decode packet, and return the extracted frame.
+ *
+ * @note A packet (for example an audio frame) may contain several
+ * frames. In order to extract *all* the frames from the input packet,
+ * you should call the function many times, until there is no frame to
+ * extract anymore and the return value is 0.
+ *
+ * @param frame_data_ptr pointer to the location where to put the
+ * frame_data, it is set to NULL if no frame could be decoded
+ * @return size of the decoded data, 0 if no frame could be extracted,
+ * a negative value in case of error
+ */
+static int decode_packet(AVFormatContext *fmt_ctx,
+ AVPacket *pkt,
+ FrameData **frame_data_ptr)
+{
+ int ret, got_frame = 0;
+ AVFrame frame;
+ AVSubtitle subtitle;
+ AVStream *st = fmt_ctx->streams[pkt->stream_index];
+ static unsigned int samples_buf_size = 0;
+ static int16_t *samples_buf = NULL;
+ FrameData *frame_data;
+
+ *frame_data_ptr = NULL;
+
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ samples_buf = av_fast_realloc(samples_buf, &samples_buf_size,
+ FFMAX(pkt->size * sizeof(*samples_buf),
+ AVCODEC_MAX_AUDIO_FRAME_SIZE));
+ if (!samples_buf)
+ return AVERROR(ENOMEM);
+ ret = avcodec_decode_audio3(st->codec, samples_buf, &samples_buf_size,
+ pkt);
+ if (ret < 0)
+ break;
+
+ if (samples_buf_size > 0) {
+ /* allocate a FrameData struct and fill it */
+ frame_data = av_malloc(sizeof(FrameData));
+ frame_data->st = st;
+ FILL_FRAME_DATA_FROM_PKT(frame_data, pkt);
+ frame_data->size = ret;
+ frame_data->frame = (void *)samples_buf;
+ frame_data->decoded_size = samples_buf_size;
+ *frame_data_ptr = frame_data;
+ } else {
+ *frame_data_ptr = NULL;
+ }
+ pkt->data += ret;
+ pkt->size -= ret;
+ break;
+
+ case AVMEDIA_TYPE_VIDEO:
+ got_frame = 0;
+ frame.opaque = NULL;
+ ret = avcodec_decode_video2(st->codec, &frame, &got_frame, pkt);
+ if (ret < 0)
+ break;
+ if (got_frame) {
+ if (frame.opaque) {
+ /* frame information was already stored in the frame by get_buffer */
+ *frame_data_ptr = (FrameData *)frame.opaque;
+ } else {
+ frame_data = av_malloc(sizeof(FrameData));
+ if (!frame_data)
+ return AVERROR(ENOMEM);
+ frame_data->st = st;
+ FILL_FRAME_DATA_FROM_PKT(frame_data, pkt);
+ frame_data->size = ret;
+ frame_data->frame = &frame;
+ *frame_data_ptr = frame_data;
+ }
+ }
+ pkt->data = NULL;
+ pkt->size = 0;
+ break;
+
+ case AVMEDIA_TYPE_SUBTITLE:
+ ret = avcodec_decode_subtitle2(st->codec, &subtitle, &got_frame, pkt);
+ if (ret < 0)
+ break;
+
+ if (got_frame) {
+ frame_data = av_malloc(sizeof(FrameData));
+ if (!frame_data)
+ return AVERROR(ENOMEM);
+ frame_data->st = st;
+ FILL_FRAME_DATA_FROM_PKT(frame_data, pkt);
+ frame_data->size = ret;
+ frame_data->frame = &subtitle;
+ *frame_data_ptr = frame_data;
+ }
+ pkt->data = NULL;
+ pkt->size = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void show_frame(AVFormatContext *fmt_ctx, FrameData *frame_data)
+{
+ AVStream *st = frame_data->st;
+ AVFrame *frame;
+ char val_str[128];
+
+ printf("[FRAME]\n");
+ printf("media_type=%s\n", media_type_string(st->codec->codec_type));
+
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ frame = (AVFrame *)frame_data->frame;
+ printf("pict_type=%c\n", av_get_pict_type_char(frame->pict_type));
+ printf("coded_picture_number=%d\n", frame->coded_picture_number);
+ printf("display_picture_number=%d\n", frame->display_picture_number);
+ printf("interlaced_frame=%d\n", frame->interlaced_frame);
+ printf("top_field_first=%d\n", frame->top_field_first);
+ printf("repeat_pict=%d\n", frame->repeat_pict);
+ printf("reference=%d\n", frame->reference);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ printf("nb_samples=%d\n",
+ frame_data->decoded_size * 8 / av_get_bits_per_sample_fmt(st->codec->sample_fmt));
+ break;
+
+ default:
+ break;
+ }
+
+ printf("stream_index=%d\n", st->index);
+ printf("size=%s\n", value_string(val_str, sizeof(val_str),
+ (double)frame_data->size, unit_byte_str));
+ printf("pkt_pts=%"PRId64"\n", frame_data->pkt_pts);
+ printf("pkt_pts_time=%s\n", time_value_string(val_str, sizeof(val_str),
+ frame_data->pkt_pts, &st->time_base));
+ printf("pkt_dts=%"PRId64"\n", frame_data->pkt_dts);
+ printf("pkt_dts_time=%s\n", time_value_string(val_str, sizeof(val_str),
+ frame_data->pkt_dts, &st->time_base));
+ printf("pkt_pos=%"PRId64"\n", frame_data->pkt_pos);
+ printf("pkt_duration=%s\n", time_value_string(val_str, sizeof(val_str),
+ frame_data->pkt_duration, &st->time_base));
+
+ printf("[/FRAME]\n");
+}
+
+static void read_packets(AVFormatContext *fmt_ctx)
{
AVPacket pkt;
+ FrameData *frame_data;
av_init_packet(&pkt);
- while (!av_read_frame(fmt_ctx, &pkt))
- show_packet(fmt_ctx, &pkt);
+ while (!av_read_frame(fmt_ctx, &pkt)) {
+ if (do_show_packets)
+ show_packet(fmt_ctx, &pkt);
+
+ if (do_show_frames) {
+ while (pkt.size && (decode_packet(fmt_ctx, &pkt, &frame_data) > 0 || frame_data)) {
+ if (frame_data)
+ show_frame(fmt_ctx, frame_data);
+ }
+ }
+ }
}
static void show_stream(AVFormatContext *fmt_ctx, int stream_idx)
@@ -291,6 +507,9 @@ static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
fprintf(stderr, "Error while opening codec for input stream %d\n",
stream->index);
}
+ stream->codec->opaque = stream;
+ stream->codec->get_buffer = ffprobe_get_buffer;
+ stream->codec->release_buffer = ffprobe_release_buffer;
}
*fmt_ctx_ptr = fmt_ctx;
@@ -305,8 +524,8 @@ static int probe_file(const char *filename)
if ((ret = open_input_file(&fmt_ctx, filename)))
return ret;
- if (do_show_packets)
- show_packets(fmt_ctx);
+ if (do_read_packets)
+ read_packets(fmt_ctx);
if (do_show_streams)
for (i = 0; i < fmt_ctx->nb_streams; i++)
@@ -365,6 +584,18 @@ static void opt_pretty(void)
use_value_sexagesimal_format = 1;
}
+static void opt_show_frames(void)
+{
+ do_read_packets = 1;
+ do_show_frames = 1;
+}
+
+static void opt_show_packets(void)
+{
+ do_read_packets = 1;
+ do_show_packets = 1;
+}
+
static const OptionDef options[] = {
#include "cmdutils_common_opts.h"
{ "f", HAS_ARG, {(void*)opt_format}, "force format", "format" },
@@ -377,7 +608,8 @@ static const OptionDef options[] = {
{ "pretty", 0, {(void*)&opt_pretty},
"prettify the format of displayed values, make it more human readable" },
{ "show_format", OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
- { "show_packets", OPT_BOOL, {(void*)&do_show_packets}, "show packets info" },
+ { "show_packets", 0, {(void*)opt_show_packets}, "show packets info" },
+ { "show_frames", 0, {(void*)opt_show_frames}, "show frames info" },
{ "show_streams", OPT_BOOL, {(void*)&do_show_streams}, "show streams info" },
{ "default", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
{ NULL, },
--
1.7.2.3
--TakKZr9L6Hm6aLOc--
More information about the ffmpeg-devel
mailing list