[FFmpeg-devel] [PATCH] Per-frame metadata
Stefano Sabatini
stefano.sabatini-lala at poste.it
Thu Jun 16 14:37:15 CEST 2011
On date Friday 2011-06-10 20:47:51 +0200, Nicolas George encoded:
> Hi. After the recent move of the metadata API to libavutil, I rebased and
> reworked my proposal for per-frame metadata decoding:
>
> 1/5: Introduce av_size_mult and av_realloc_f
>
> This is very similar to the original proposal. The chunk with av_size_mult
> was ok-ed, but was later changed to return an AVERROR code rather than -1.
>
> I also learned in the meantime that BSD has a reallocf function, which is
> similar to the proposed av_realloc_f: it frees the memory if it fails, but
> it does not check for integer overflow.
>
> 2/5: Replace av_realloc by av_realloc_f when relevant
>
> Unchanged except for merge conflicts.
>
> 3/5: Introduce a metadata field in AVFrame
>
> It also introduces CODEC_FLAG2_FRAME_METADATA: per-frame metadata is only
> decoded if this flag is set. This avoids memory leaks if release_buffer does
> not free the metadata.
>
> 4/5: PNG: decode textual data (tEXt and zTXt chunks)
>
> Almost identical to the original proposal.
>
> 5/5: ffmpeg: dump per-frame metadata
>
> For testing purposes; I am not sure if we want it or not.
>
> Regards,
>
> --
> Nicolas George
> From d203796c069d88a8354cdd3513245ec247fc6b4b Mon Sep 17 00:00:00 2001
> From: Nicolas George <nicolas.george at normalesup.org>
> Date: Sun, 20 Mar 2011 19:39:20 +0100
> Subject: [PATCH 1/5] Introduce av_size_mult and av_realloc_f.
>
> av_size_mult helps checking for overflow when computing the size of a memory
> area.
>
> av_realloc_f helps avoiding memory-leaks in typical uses of realloc.
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> libavutil/mem.c | 15 +++++++++++++++
> libavutil/mem.h | 26 ++++++++++++++++++++++++++
> 2 files changed, 41 insertions(+), 0 deletions(-)
>
> diff --git a/libavutil/mem.c b/libavutil/mem.c
> index 87c2008..2e365f6 100644
> --- a/libavutil/mem.c
> +++ b/libavutil/mem.c
> @@ -143,6 +143,21 @@ void *av_realloc(void *ptr, size_t size)
> #endif
> }
>
> +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
Nit++: nb_elems and elem_size for readability/consistency.
> +{
> + size_t size;
> + void *r;
> +
> + if (av_size_mult(elsize, nelem, &size)) {
> + av_free(ptr);
> + return NULL;
> + }
> + r = av_realloc(ptr, size);
> + if (!r && size)
> + av_free(ptr);
> + return r;
> +}
> +
> void av_free(void *ptr)
> {
> #if CONFIG_MEMALIGN_HACK
> diff --git a/libavutil/mem.h b/libavutil/mem.h
> index 7c30e16..8876087 100644
> --- a/libavutil/mem.h
> +++ b/libavutil/mem.h
> @@ -27,6 +27,7 @@
> #define AVUTIL_MEM_H
>
> #include "attributes.h"
> +#include "error.h"
> #include "avutil.h"
>
> #if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C)
> @@ -87,6 +88,16 @@ void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1);
> void *av_realloc(void *ptr, size_t size) av_alloc_size(2);
>
> /**
> + * Allocate or reallocate a block of memory.
> + * This function does the same thing as av_realloc, except:
> + * - It takes two arguments and checks the result of the multiplication for
> + * integer overflow.
> + * - It frees the input block in case of failure, thus avoiding the memory
> + * leak with the classic "buf = realloc(buf); if (!buf) return -1;".
> + */
> +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize);
Nit: I prefer to avoid references to other functions, so the docs will
result auto-contained and won't require updates if the referred
function is changed.
> +
> +/**
> * Free a memory block which has been allocated with av_malloc(z)() or
> * av_realloc().
> * @param ptr Pointer to the memory block which should be freed.
> @@ -132,4 +143,19 @@ void av_freep(void *ptr);
> */
> void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem);
>
> +/**
> + * Multiply two size_t values checking for overflow.
> + * @return 0 if success, AVERROR(EINVAL) if overflow.
> + */
> +static inline int av_size_mult(size_t a, size_t b, size_t *r)
Maybe:
static inline int av_mult_size(size_t *r, size_t a, size_t b);
Mult is the verb and thus should be mentioned before (like in
"multiply size") since we are not adopting hierachi notation here, r
before a and b is consistent with the usual C notation:
foo(r, a, b) <=> r = a + b;
> +{
> + size_t t = a * b;
> + /* Hack inspired from glibc: only try the division if nelem and elsize
> + * are both greater than sqrt(SIZE_MAX). */
> + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
> + return AVERROR(EINVAL);
Dumb question... why not a simple:
if (b && a > SIZE_MAX / b)
return AVERROR(EINVAL);
?
Is avoiding a division worth the added obfuscation?
> + *r = t;
> + return 0;
> +}
> +
> #endif /* AVUTIL_MEM_H */
> --
> 1.7.5.3
>
> From 8970285e2e219dffa865c4d27ec20e4ab1beefc8 Mon Sep 17 00:00:00 2001
> From: Nicolas George <nicolas.george at normalesup.org>
> Date: Tue, 22 Mar 2011 21:39:00 +0100
> Subject: [PATCH 2/5] Replace av_realloc by av_realloc_f when relevant.
>
> Also mark with a visible comment "FIXME realloc failure" places where
> av_realloc seems to lack a proper test for failure.
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> cmdutils.c | 1 +
> ffmpeg.c | 3 ++-
> libavcodec/apedec.c | 1 +
> libavcodec/bitstream.c | 4 ++--
> libavcodec/eatgv.c | 2 ++
> libavcodec/flacdec.c | 1 +
> libavcodec/libdiracenc.c | 1 +
> libavcodec/libschroedingerenc.c | 1 +
> libavcodec/libvpxenc.c | 4 ++--
> libavcodec/resample.c | 1 +
> libavcodec/rv34.c | 1 +
> libavcodec/shorten.c | 1 +
> libavcodec/truemotion2.c | 1 +
> libavcodec/vmnc.c | 1 +
> libavcodec/vp56.c | 1 +
> libavcodec/zmbv.c | 1 +
> libavfilter/avfilter.c | 1 +
> libavformat/4xm.c | 5 +++--
> libavformat/asfenc.c | 1 +
> libavformat/avidec.c | 2 +-
> libavformat/avienc.c | 2 +-
> libavformat/aviobuf.c | 4 ++--
> libavformat/gxfenc.c | 10 ++++++----
> libavformat/matroskadec.c | 1 +
> libavformat/movenc.c | 2 +-
> libavformat/mxfdec.c | 1 +
> libavformat/mxfenc.c | 1 +
> libavformat/oggdec.c | 1 +
> libavformat/oggparsetheora.c | 1 +
> libavformat/oggparsevorbis.c | 1 +
> libavformat/rtmpproto.c | 3 +++
> libavformat/rtpdec_asf.c | 1 +
> libavformat/rtpdec_qt.c | 1 +
> libavformat/smacker.c | 1 +
> libavformat/utils.c | 2 ++
> libavutil/mem.c | 1 +
> 36 files changed, 51 insertions(+), 16 deletions(-)
[...]
Looks OK to me.
> From d64f9e8f097fb3e2240ea63a92eb7215bd608735 Mon Sep 17 00:00:00 2001
> From: Nicolas George <nicolas.george at normalesup.org>
> Date: Fri, 10 Jun 2011 19:53:32 +0200
> Subject: [PATCH 3/5] Introduce a metadata field in AVFrame.
>
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> libavcodec/avcodec.h | 9 +++++++++
> libavcodec/options.c | 1 +
> libavcodec/utils.c | 1 +
> 3 files changed, 11 insertions(+), 0 deletions(-)
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index ef539a2..ca5fdd6 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -30,6 +30,7 @@
> #include "libavutil/samplefmt.h"
> #include "libavutil/avutil.h"
> #include "libavutil/cpu.h"
> +#include "libavutil/dict.h"
>
> #include "libavcodec/version.h"
>
> @@ -619,6 +620,7 @@ typedef struct RcOverride{
> #define CODEC_FLAG2_PSY 0x00080000 ///< Use psycho visual optimizations.
> #define CODEC_FLAG2_SSIM 0x00100000 ///< Compute SSIM during encoding, error[] values are undefined.
> #define CODEC_FLAG2_INTRA_REFRESH 0x00200000 ///< Use periodic insertion of intra blocks instead of keyframes.
> +#define CODEC_FLAG2_FRAME_METADATA 0x00400000 ///< Decode per-frame metadata.
>
> /* Unsupported options :
> * Syntax Arithmetic coding (SAC)
> @@ -1038,6 +1040,13 @@ typedef struct AVPanScan{
> * - decoding: Read by user.\
> */\
> int format;\
> +\
> + /**
> + * per-frame metadata\
> + * - encoding: currently unused\
> + * - decoding: set by libavcodec if CODEC_FLAG2_FRAME_METADATA is set\
> + */\
> + AVDictionary *metadata;
>
>
> #define FF_QSCALE_TYPE_MPEG1 0
> diff --git a/libavcodec/options.c b/libavcodec/options.c
> index 78a7bc8..2c86dfd 100644
> --- a/libavcodec/options.c
> +++ b/libavcodec/options.c
> @@ -416,6 +416,7 @@ static const AVOption options[]={
> {"rc_lookahead", "specify number of frames to look ahead for frametype", OFFSET(rc_lookahead), FF_OPT_TYPE_INT, {.dbl = 40 }, 0, INT_MAX, V|E},
> {"ssim", "ssim will be calculated during encoding", 0, FF_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_SSIM }, INT_MIN, INT_MAX, V|E, "flags2"},
> {"intra_refresh", "use periodic insertion of intra blocks instead of keyframes", 0, FF_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_INTRA_REFRESH }, INT_MIN, INT_MAX, V|E, "flags2"},
> +{"frame_metadata", "decode per-frame metadata", 0, FF_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_FRAME_METADATA }, INT_MIN, INT_MAX, A|V|D, "flags2"},
decode_frame_metadata is clearer but longer and I have no better
ideas, so thic can stay...
> {"crf_max", "in crf mode, prevents vbv from lowering quality beyond this point", OFFSET(crf_max), FF_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, 0, 51, V|E},
> {"log_level_offset", "set the log level offset", OFFSET(log_level_offset), FF_OPT_TYPE_INT, {.dbl = 0 }, INT_MIN, INT_MAX },
> #if FF_API_FLAC_GLOBAL_OPTS
> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
> index 922decf..5020d2a 100644
> --- a/libavcodec/utils.c
> +++ b/libavcodec/utils.c
> @@ -388,6 +388,7 @@ void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){
> // pic->base[i]=NULL;
> }
> //printf("R%X\n", pic->opaque);
> + av_dict_free(&pic->metadata);
>
> if(s->debug&FF_DEBUG_BUFFERS)
> av_log(s, AV_LOG_DEBUG, "default_release_buffer called on pic %p, %d buffers used\n", pic, s->internal_buffer_count);
> --
> 1.7.5.3
>
> From 875b8f1dba58adc9f6dce3bc05e941a6009f6d1b Mon Sep 17 00:00:00 2001
> From: Nicolas George <nicolas.george at normalesup.org>
> Date: Fri, 10 Jun 2011 20:05:19 +0200
> Subject: [PATCH 4/5] PNG: decode textual data (tEXt and zTXt chunks).
>
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> libavcodec/pngdec.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 242 insertions(+), 0 deletions(-)
>
> diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
> index 05ba027..59a626c 100644
> --- a/libavcodec/pngdec.c
> +++ b/libavcodec/pngdec.c
> @@ -42,6 +42,134 @@ static const uint8_t png_pass_dsp_mask[NB_PASSES] = {
> 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff
> };
>
> +/*
> + * PNG tEXt and zTXt chunks are in ISO-8859-1.
> + */
> +
> +/**
> + * Converts text from ISO-8859-1 to UTF-8.
nit: Convert
> + * @param in input text in ISO-8859-1.
no need for the final dot (uncomplete sentence)
> + * @param size size of the input text.
no need for the final dot, size *in bytes* of the input text.
size_in is clearer (since we already have a size_out)
> + * @param size_out if not NULL, will be set to the size of the output.
> + * @return newly allocated buffer with the converted text, NUL-terminated;
> + NULL if the buffer could not be allocated.
Nit++: no need to the final point
> + */
> +static uint8_t *ff_iso88591_to_utf8(const uint8_t *in, size_t size,
> + size_t *size_out)
> +{
> + size_t extra = 0, i;
> + uint8_t c;
> + const uint8_t *p;
> + uint8_t *q, *out;
> +
> + if (size == SIZE_MAX) /* no room for terminating NUL anyway */
> + return NULL;
> + p = in;
> + for (i = 0; i < size; i++)
> + if (*(p++) >= 0x80)
> + extra++;
> + if (extra > SIZE_MAX - size - 1)
> + return NULL;
> + q = out = av_malloc(size + extra + 1);
> + for (i = 0; i < size; i++) {
> + c = *(in++);
> + if (c >= 0x80) {
> + *(q++) = 0xC0 | (c >> 6);
> + *(q++) = 0x80 | (c & 0x3F);
> + } else {
> + *(q++) = c;
> + }
> + }
> + *(q++) = 0;
> + if (size_out)
> + *size_out = size + extra;
> + return out;
> +}
> +
> +/**
> + * Grow an automatic buffer to a minimum size.
> + * This function is similar to ff_abuffer_grow except that it always
> + * reallocates the buffer, even if it is already large enough.
> + */
> +static void *ff_abuffer_grow_always(void *buf0, size_t elsize,
> + void *buf, size_t *size, size_t min_size)
> +{
> + size_t new_size = FFMAX(min_size, *size * 2);
> + size_t bytes;
> + void *nbuf;
> +
> + if (av_size_mult(elsize, new_size, &bytes))
> + return buf;
> + nbuf = av_realloc(buf == buf0 ? NULL : buf, bytes);
> + if (!nbuf)
> + return buf;
> + if (buf == buf0)
> + memcpy(nbuf, buf0, elsize * FFMIN(*size, new_size));
> + *size = new_size;
> + return nbuf;
> +}
> +
> +/**
> + * Grow an automatic buffer to a minimum size.
> + * An automatic buffer is a buffer that starts allocated on a stack as an
> + * automatic variable, and is enlarged on the heap if necessary.
> + * The typical declaration looks like that:
> + * struct foo buf0[128];
> + * struct foo *buf = buf0;
> + * size_t buf_size = FF_ARRAY_ELEMS(buf0);
Is this API really needed? Couldn't you always use the heap?
> + * This function ensures that the allocated size is at least min_size,
> + * reallocating the buffer if necessary.
> + * If the reallocation fails, the buffer is unchanged:
> + * the correct way to check for success is to compare size and min_size.
> + * @param buf0 original (on stack) buffer.
> + * @param elsize size of individual elements.
> + * @param buf current buffer.
> + * @param size current allocated size.
> + * @param min_size requested size.
> + * @return new buffer, or old one if failure.
> + */
> +static inline void *ff_abuffer_grow(void *buf0, size_t elsize,
> + void *buf, size_t *size, size_t min_size)
> +{
> + return *size >= min_size ? buf :
> + ff_abuffer_grow_always(buf0, elsize, buf, size, min_size);
> +}
> +
> +/**
> + * Free an automatic buffer.
> + * Calling this function is always safe.
> + */
> +static void ff_abuffer_free(void *buf0, void *buf)
> +{
> + if (buf != buf0)
> + av_free(buf);
> +}
> +
> +/**
> + * Finish an automatic buffer.
> + * This function ensures that the buffer is heap-allocated and shrinks it if
> + * necessary. The resulting memory area should be freed using av_free.
> + * @param buf0 original (on stack) buffer.
> + * @param elsize size of individual elements.
> + * @param buf current value.
> + * @param size requested size; must not be greater than the current
> + * allocated size.
> + * @return final value, or NULL if not possible.
> + * This function can only fail if the buffer is still on the stack: extra
> + * cleanup measures are not necessary.
> + */
> +static void *ff_abuffer_finish(void *buf0, size_t elsize,
> + void *buf, size_t size)
> +{
> + void *nbuf = av_realloc(buf == buf0 ? NULL : buf, elsize * size);
> + if (!nbuf)
> + return buf == buf0 ? NULL : buf;
> + if (buf == buf0)
> + memcpy(nbuf, buf0, elsize * size);
> + return nbuf;
> +}
> +
> +
> /* NOTE: we try to construct a good looking image at each pass. width
> is the original image width. We also do pixel format conversion at
> this stage */
> @@ -368,6 +496,55 @@ static int png_decode_idat(PNGDecContext *s, int length)
> return 0;
> }
>
> +/**
> + * Decode completely a zlib-compressed buffer.
> + * The buffer is additionnally converted from ISO-8859-1 to UTF-8.
> + * The calling function must have checked that the input bytestream is long
> + * enough.
> + */
> +static int png_decode_zbuf(PNGDecContext *s, int length,
> + uint8_t **buf_ret, size_t *size_ret)
> +{
> + int ret;
> + z_stream zstream;
> + uint8_t buf0[512], *buf = buf0, *utf8;
> + size_t buf_size = sizeof(buf0), out_size = 0, utf8_size = 0;
> +
> + zstream.zalloc = ff_png_zalloc;
> + zstream.zfree = ff_png_zfree;
> + zstream.opaque = NULL;
> + if (inflateInit(&zstream) != Z_OK)
> + return -1;
> + zstream.next_in = s->bytestream;
> + zstream.avail_in = length;
> +
> + while (zstream.avail_in > 0) {
> + buf = ff_abuffer_grow(buf0, 1, buf, &buf_size, out_size + 256);
> + zstream.next_out = buf + out_size;
> + zstream.avail_out = buf_size - 1 - out_size;
> + ret = inflate(&zstream, Z_PARTIAL_FLUSH);
> + if (ret != Z_OK && ret != Z_STREAM_END)
> + goto png_decode_zbuf_fail;
> + out_size = zstream.next_out - buf;
> + if (ret == Z_STREAM_END)
> + break;
> + }
> + inflateEnd(&zstream);
> + utf8 = ff_iso88591_to_utf8(buf, out_size, &utf8_size);
> + ff_abuffer_free(buf0, buf);
> + if (!utf8)
> + return -1;
> + *size_ret = utf8_size;
> + *buf_ret = utf8;
> + s->bytestream += length;
> + return 0;
> +png_decode_zbuf_fail:
> + inflateEnd(&zstream);
> + ff_abuffer_free(buf0, buf);
> + return -1;
> +}
> +
> +
> static int decode_frame(AVCodecContext *avctx,
> void *data, int *data_size,
> AVPacket *avpkt)
> @@ -380,6 +557,8 @@ static int decode_frame(AVCodecContext *avctx,
> uint8_t *crow_buf_base = NULL;
> uint32_t tag, length;
> int ret;
> + AVDictionary *metadata = NULL;
> +
Nit+++: superfluous empty line
>
> FFSWAP(AVFrame *, s->current_picture, s->last_picture);
> avctx->coded_frame= s->current_picture;
> @@ -567,6 +746,67 @@ static int decode_frame(AVCodecContext *avctx,
> s->bytestream += 4; /* crc */
> }
> break;
> + case MKTAG('t', 'E', 'X', 't'):
> + if (!(avctx->flags2 & CODEC_FLAG2_FRAME_METADATA))
> + goto skip_tag;
> + {
> + const uint8_t *keyword, *keyword_end;
> + uint8_t *data;
> + size_t data_size;
> + if (s->bytestream + length >= s->bytestream_end)
> + goto skip_tag;
> + keyword = s->bytestream;
> + keyword_end = memchr(keyword, 0, length);
> + if (!keyword_end ||
> + s->bytestream + length - keyword_end < 1) {
> + av_log(avctx, AV_LOG_ERROR, "Bogus textual data.\n");
> + goto skip_tag;
> + }
> + data_size = (s->bytestream + length) - (keyword_end + 1);
> + data = ff_iso88591_to_utf8(keyword_end + 1, data_size,
> + &data_size);
> + if (!data)
> + goto skip_tag;
> + s->bytestream += length;
> + s->bytestream += 4; /* crc */
> + av_dict_set(&metadata, keyword, data, AV_DICT_DONT_STRDUP_VAL);
> + }
> + break;
> + case MKTAG('z', 'T', 'X', 't'):
> + if (!(avctx->flags2 & CODEC_FLAG2_FRAME_METADATA))
> + goto skip_tag;
> + {
> + const uint8_t *keyword, *keyword_end;
> + uint8_t *data;
> + size_t data_size;
> + int method;
> + if (s->bytestream + length >= s->bytestream_end)
> + goto skip_tag;
> + keyword = s->bytestream;
> + keyword_end = memchr(keyword, 0, length);
> + if (!keyword_end ||
> + s->bytestream + length - keyword_end < 3) {
> + av_log(avctx, AV_LOG_ERROR, "Bogus textual data.\n");
> + goto skip_tag;
> + }
> + method = keyword_end[1];
> + length -= keyword_end + 2 - s->bytestream;
> + s->bytestream = keyword_end + 2;
> + if (method) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Unsupported compression method.\n");
> + goto skip_tag;
> + }
> + if (png_decode_zbuf(s, length, &data, &data_size) < 0) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Textual data decompression failed.\n");
> + goto skip_tag;
> + }
> + s->bytestream += 4; /* crc */
> + av_dict_set(&metadata, keyword, data, AV_DICT_DONT_STRDUP_VAL);
> + }
> + break;
> +
> case MKTAG('I', 'E', 'N', 'D'):
> if (!(s->state & PNG_ALLIMAGE))
> goto fail;
> @@ -597,6 +837,7 @@ static int decode_frame(AVCodecContext *avctx,
> }
> }
>
> + s->current_picture->metadata = metadata;
> *picture= *s->current_picture;
> *data_size = sizeof(AVFrame);
>
> @@ -610,6 +851,7 @@ static int decode_frame(AVCodecContext *avctx,
> return ret;
> fail:
> ret = -1;
> + av_dict_free(&metadata);
> goto the_end;
> }
>
> --
> 1.7.5.3
>
> From 106cf1e34f6db337fdb8a193f2139667d0cd11a2 Mon Sep 17 00:00:00 2001
> From: Nicolas George <nicolas.george at normalesup.org>
> Date: Fri, 10 Jun 2011 20:15:51 +0200
> Subject: [PATCH 5/5] ffmpeg: dump per-frame metadata.
>
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> ffmpeg.c | 12 ++++++++++++
> 1 files changed, 12 insertions(+), 0 deletions(-)
>
> diff --git a/ffmpeg.c b/ffmpeg.c
> index 48f979c..a249483 100644
> --- a/ffmpeg.c
> +++ b/ffmpeg.c
> @@ -1509,6 +1509,17 @@ static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_
> memset(buf, fill_char, size);
> }
>
> +static void dump_frame_metadata(AVCodecContext *ctx, AVDictionary *m)
> +{
> + AVDictionaryEntry *tag=NULL;
Nit+++: tag_=_NULL
"tag" is also a bit confusing ("entry" would be better)
> +
> + if (!m)
> + return;
> + av_log(ctx, AV_LOG_INFO, "Frame metadata:\n");
> + while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX)))
> + av_log(ctx, AV_LOG_INFO, " %-16s: %s\n", tag->key, tag->value);
> +}
> +
> /* pkt = NULL means EOF (needed to flush decoder buffers) */
> static int output_packet(AVInputStream *ist, int ist_index,
> AVOutputStream **ost_table, int nb_ostreams,
> @@ -1613,6 +1624,7 @@ static int output_packet(AVInputStream *ist, int ist_index,
> /* no picture yet */
> goto discard_packet;
> }
> + dump_frame_metadata(ist->st->codec, picture.metadata);
> ist->next_pts = ist->pts = picture.best_effort_timestamp;
> if (ist->st->codec->time_base.num != 0) {
> int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame;
> --
> 1.7.5.3
Please one patch per thread, and thanks for the work.
--
FFmpeg = Fantastic & Forgiving Majestic Proud Ecumenical God
More information about the ffmpeg-devel
mailing list