On Thu, 14 Feb 2013 23:12:52 +0100, Janne Grunau <[email protected]> wrote:
> On 2013-02-13 19:48:32 +0100, Anton Khirnov wrote:
> > ---
> > libavcodec/avcodec.h | 123 +++++++++-
> > libavcodec/internal.h | 49 ++--
> > libavcodec/options.c | 4 +-
> > libavcodec/options_table.h | 1 +
> > libavcodec/pthread.c | 2 -
> > libavcodec/utils.c | 578
> > +++++++++++++++++++++++++++-----------------
> > libavcodec/version.h | 3 +
> > 7 files changed, 505 insertions(+), 255 deletions(-)
> >
> > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> > index 4dde26c..589b750 100644
> > --- a/libavcodec/avcodec.h
> > +++ b/libavcodec/avcodec.h
> > @@ -823,6 +823,7 @@ typedef struct AVPanScan{
> > #define FF_QSCALE_TYPE_H264 2
> > #define FF_QSCALE_TYPE_VP56 3
> >
> > +#if FF_API_GET_BUFFER
> > #define FF_BUFFER_TYPE_INTERNAL 1
> > #define FF_BUFFER_TYPE_USER 2 ///< direct rendering buffers (image is
> > (de)allocated by user)
> > #define FF_BUFFER_TYPE_SHARED 4 ///< Buffer from somewhere else; don't
> > deallocate image (data/base), all other tables are not shared.
> > @@ -832,6 +833,12 @@ typedef struct AVPanScan{
> > #define FF_BUFFER_HINTS_READABLE 0x02 // Codec will read from buffer.
> > #define FF_BUFFER_HINTS_PRESERVE 0x04 // User must not alter buffer
> > content.
> > #define FF_BUFFER_HINTS_REUSABLE 0x08 // Codec will reuse the buffer
> > (update).
> > +#endif
> > +
> > +/**
> > + * The decoder will keep a reference to the frame and may reuse it later.
> > + */
> > +#define AV_GET_BUFFER_FLAG_REF (1 << 0)
> >
> > /**
> > * @defgroup lavc_packet AVPacket
> > @@ -1859,6 +1866,7 @@ typedef struct AVCodecContext {
> > */
> > enum AVSampleFormat request_sample_fmt;
> >
> > +#if FF_API_GET_BUFFER
> > /**
> > * Called at the beginning of each frame to get a buffer for it.
> > *
> > @@ -1918,7 +1926,10 @@ typedef struct AVCodecContext {
> > *
> > * - encoding: unused
> > * - decoding: Set by libavcodec, user can override.
> > + *
> > + * @deprecated use get_buffer2()
> > */
> > + attribute_deprecated
> > int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic);
> >
> > /**
> > @@ -1929,7 +1940,10 @@ typedef struct AVCodecContext {
> > * but not by more than one thread at once, so does not need to be
> > reentrant.
> > * - encoding: unused
> > * - decoding: Set by libavcodec, user can override.
> > + *
> > + * @deprecated custom freeing callbacks should be set from
> > get_buffer2()
> > */
> > + attribute_deprecated
> > void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic);
> >
> > /**
> > @@ -1944,8 +1958,100 @@ typedef struct AVCodecContext {
> > * - encoding: unused
> > * - decoding: Set by libavcodec, user can override.
> > */
> > + attribute_deprecated
> > int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic);
> > +#endif
> >
> > + /**
> > + * This callback is called at the beginning of each frame to get data
> > + * buffer(s) for it. There may be one contiguous buffer for all the
> > data or
> > + * there may be a buffer per each data plane or anything in between.
> > Each
> > + * buffer must be reference-counted using the AVBuffer API.
> > + *
> > + * The following fields will be set in the frame before this callback
> > is
> > + * called:
> > + * - format
> > + * - width, height (video only)
> > + * - sample_rate, channel_layout, nb_samples (audio only)
> > + * Their values may differ from the corresponding values in
> > + * AVCodecContext. This callback must use the frame values, not the
> > codec
> > + * context values, to calculate the required buffer size.
> > + *
> > + * This callback must fill the following fields in the frame:
> > + * - data[]
> > + * - linesize[]
> > + * - extended_data:
> > + * * if the data is planar audio with more than 8 channels, then this
> > + * callback must allocate and fill extended_data to contain all
> > pointers
> > + * to all data planes. data[] must hold as many pointers as it can.
> > + * extended_data must be allocated with av_malloc() and will be
> > freed in
> > + * av_frame_unref().
> > + * * otherwise exended_data must point to data
> > + * - buf[] must contain references to the buffers that contain the
> > frame
> > + * data.
> > + * - extended_buf and nb_extended_buf must be allocated with
> > av_malloc() by
> > + * this callback and filled with the extra buffers if there are more
> > + * buffers than buf[] can hold. extended_buf will be freed in
> > + * av_frame_unref().
> > + *
> > + * If CODEC_CAP_DR1 is not set then get_buffer2() must call
> > + * avcodec_default_get_buffer2() instead of providing buffers
> > allocated by
> > + * some other means.
> > + *
> > + * Each data plane must be aligned to the maximum required by the
> > target
> > + * CPU.
> > + *
> > + * @see avcodec_default_get_buffer2()
> > + *
> > + * Video:
> > + *
> > + * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be
> > reused
> > + * (read and/or written to if it is writable) later by libavcodec.
> > + *
> > + * If CODEC_FLAG_EMU_EDGE is not set in s->flags, the buffer must
> > contain an
> > + * edge of the size returned by avcodec_get_edge_width() on all sides
> > + *
> > + * avcodec_align_dimensions2() should be used to find the required
> > width and
> > + * height, as they normally need to be rounded up to the next multiple
> > of 16.
> > + *
> > + * If frame multithreading is used and thread_safe_callbacks is set,
> > + * this callback may be called from a different thread, but not from
> > more
> > + * than one at once. Does not need to be reentrant.
>
> Are you sure the last part is true? It's probably true since we have to
> guarantee that get_buffer is always called before finish_setup for
> non-thread safe callbacks but it seems to be an odd and unecessary
> limitation. Who writes thread-safe but not reentrant safe functions?
>
Well..I simply copied that part from get_buffer() docs. And nothing changed in
the way that code works.
> > + *
> > + * @see avcodec_align_dimensions2()
> > + *
> > + * Audio:
> > + *
> > + * Decoders request a buffer of a particular size by setting
> > + * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may,
> > + * however, utilize only part of the buffer by setting
> > AVFrame.nb_samples
> > + * to a smaller value in the output frame.
> > + *
> > + * As a convenience, av_samples_get_buffer_size() and
> > + * av_samples_fill_arrays() in libavutil may be used by custom
> > get_buffer2()
> > + * functions to find the required data size and to fill data pointers
> > and
> > + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio
> > + * since all planes must be the same size.
> > + *
> > + * @see av_samples_get_buffer_size(), av_samples_fill_arrays()
> > + *
> > + * - encoding: unused
> > + * - decoding: Set by libavcodec, user can override.
> > + */
> > + int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int
> > flags);
>
> ahem, you have to extend AVCodecContext at the end for ABI compatibility
>
> > +
> > + /**
> > + * If non-zero, the decoded audio and video frames returned from
> > + * avcodec_decode_video2() and avcodec_decode_audio4() are
> > reference-counted
> > + * and are valid indefinitely. The caller must free them with
> > + * av_frame_unref() when they are not needed anymore.
> > + * Otherwise, the decoded frames must not be freed by the caller and
> > are
> > + * only valid until the next decode call.
> > + *
> > + * - encoding: unused
> > + * - decoding: set by the caller before avcodec_open2().
> > + */
> > + int refcounted_frames;
> >
> > /* - encoding parameters */
> > float qcompress; ///< amount of qscale change between easy & hard
> > scenes (0.0-1.0)
> > @@ -3208,9 +3314,18 @@ AVCodec *avcodec_find_decoder(enum AVCodecID id);
> > */
> > AVCodec *avcodec_find_decoder_by_name(const char *name);
> >
> > -int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic);
> > -void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic);
> > -int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic);
> > +#if FF_API_GET_BUFFER
> > +attribute_deprecated int avcodec_default_get_buffer(AVCodecContext *s,
> > AVFrame *pic);
> > +attribute_deprecated void avcodec_default_release_buffer(AVCodecContext
> > *s, AVFrame *pic);
> > +attribute_deprecated int avcodec_default_reget_buffer(AVCodecContext *s,
> > AVFrame *pic);
> > +#endif
> > +
> > +/**
> > + * The default callback for AVCodecContext.get_buffer2(). It is made
> > public so
> > + * it can be called by custom get_buffer2() implementations for decoders
> > without
> > + * CODEC_CAP_DR1 set.
> > + */
> > +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int
> > flags);
> >
> > /**
> > * Return the amount of padding in pixels which the get_buffer callback
> > must
> > @@ -4141,8 +4256,6 @@ int avcodec_fill_audio_frame(AVFrame *frame, int
> > nb_channels,
> > */
> > void avcodec_flush_buffers(AVCodecContext *avctx);
> >
> > -void avcodec_default_free_buffers(AVCodecContext *s);
> > -
>
> removing a public exported function without major bump
>
There is a major bump. I'm adding a field to AVPacket in TEP Part I, 06/10; so
we have to bump lavc, lavf and lavd.
> > @@ -402,54 +341,156 @@ static int video_get_buffer(AVCodecContext *s,
> > AVFrame *pic)
> > size[i] = picture.data[i + 1] - picture.data[i];
> > size[i] = tmpsize - (picture.data[i] - picture.data[0]);
> >
> > - memset(buf->base, 0, sizeof(buf->base));
> > - memset(buf->data, 0, sizeof(buf->data));
> > -
> > - for (i = 0; i < 4 && size[i]; i++) {
> > - const int h_shift = i == 0 ? 0 : h_chroma_shift;
> > - const int v_shift = i == 0 ? 0 : v_chroma_shift;
> > + for (i = 0; i < 4; i++) {
> > + av_buffer_pool_uninit(&pool->pools[i]);
> > + pool->linesize[i] = picture.linesize[i];
> > + if (size[i]) {
> > + pool->pools[i] = av_buffer_pool_init(size[i], NULL);
> > + if (!pool->pools[i])
> > + return AVERROR(ENOMEM);
> > + }
> > + }
> > + pool->format = frame->format;
> > + pool->width = frame->width;
> > + pool->height = frame->height;
> >
> > - buf->linesize[i] = picture.linesize[i];
> > + break;
> > + }
> > + case AVMEDIA_TYPE_AUDIO: {
> > + int ch =
> > av_get_channel_layout_nb_channels(frame->channel_layout);
> > + int planar = av_sample_fmt_is_planar(frame->format);
> > + int planes = planar ? ch : 1;
> > +
> > + if (pool->format == frame->format && pool->planes == planes &&
> > + pool->channels == ch && frame->nb_samples == pool->samples)
> > + return 0;
> > +
> > + av_buffer_pool_uninit(&pool->pools[0]);
> > + ret = av_samples_get_buffer_size(&pool->linesize[0], ch,
> > + frame->nb_samples, frame->format,
> > 0);
> > + if (ret < 0)
> > + return AVERROR(EINVAL);
> >
> > - buf->base[i] = av_malloc(size[i] + 16); //FIXME 16
> > - if (buf->base[i] == NULL)
> > - return -1;
> > + pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL);
> > + if (!pool->pools[0])
> > + return AVERROR(ENOMEM);
> >
> > - // no edge if EDGE EMU or not planar YUV
> > - if ((s->flags & CODEC_FLAG_EMU_EDGE) || !size[2])
> > - buf->data[i] = buf->base[i];
> > - else
> > - buf->data[i] = buf->base[i] + FFALIGN((buf->linesize[i] *
> > EDGE_WIDTH >> v_shift) + (pixel_size * EDGE_WIDTH >> h_shift),
> > stride_align[i]);
> > + pool->format = frame->format;
> > + pool->planes = planes;
> > + pool->channels = ch;
> > + pool->samples = frame->nb_samples;
> > + break;
> > }
> > - for (; i < AV_NUM_DATA_POINTERS; i++) {
> > - buf->base[i] = buf->data[i] = NULL;
> > - buf->linesize[i] = 0;
> > + default: av_assert0(0);
>
> if you want to leave the assert in av_assert0(avctx->codec_type ==
> AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO) would be nicer
>
I really fail to see why...using av_assert0(0) as the 'never happens' case in
switch() is pretty standard in our code.
> > + }
> > + return 0;
> > +}
> > +
> > +static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
> > +{
> > + FramePool *pool = avctx->internal->pool;
> > + int planes = pool->planes;
> > + int i;
> > +
> > + if (planes > AV_NUM_DATA_POINTERS) {
> > + frame->extended_data = av_mallocz(planes *
> > sizeof(*frame->extended_data));
> > + frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS;
> > + frame->extended_buf = av_mallocz(frame->nb_extended_buf *
> > + sizeof(*frame->extended_buf));
> > + if (!frame->extended_data || !frame->extended_buf) {
> > + av_freep(&frame->extended_data);
> > + av_freep(&frame->extended_buf);
> > + return AVERROR(ENOMEM);
> > }
> > - if (size[1] && !size[2])
> > - avpriv_set_systematic_pal2((uint32_t *)buf->data[1],
> > s->pix_fmt);
> > - buf->width = s->width;
> > - buf->height = s->height;
> > - buf->pix_fmt = s->pix_fmt;
> > + } else
> > + frame->extended_data = frame->data;
> > +
> > + for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) {
> > + frame->buf[i] = av_buffer_alloc_pool(pool->pools[0]);
> > + if (!frame->buf[i])
> > + goto fail;
> > + frame->extended_data[i] = frame->data[i] = frame->buf[i]->data;
> > + }
> > + for (i = 0; i < frame->nb_extended_buf; i++) {
> > + frame->extended_buf[i] = av_buffer_alloc_pool(pool->pools[0]);
> > + if (!frame->extended_buf[i])
> > + goto fail;
> > + frame->extended_data[i + AV_NUM_DATA_POINTERS] =
> > frame->extended_buf[i]->data;
> > }
> >
> > - for (i = 0; i < AV_NUM_DATA_POINTERS; i++) {
> > - pic->base[i] = buf->base[i];
> > - pic->data[i] = buf->data[i];
> > - pic->linesize[i] = buf->linesize[i];
> > + if (avctx->debug & FF_DEBUG_BUFFERS)
> > + av_log(avctx, AV_LOG_DEBUG, "default_get_buffer called on frame
> > %p", frame);
> > +
> > + return 0;
> > +fail:
> > + av_frame_unref(frame);
> > + return AVERROR(ENOMEM);
> > +}
> > +
> > +static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
> > +{
> > + FramePool *pool = s->internal->pool;
> > + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format);
> > + int pixel_size = desc->comp[0].step_minus1 + 1;
> > + int h_chroma_shift, v_chroma_shift;
> > + int i;
> > +
> > + if (pic->data[0] != NULL) {
> > + av_log(s, AV_LOG_ERROR, "pic->data[0]!=NULL in
> > avcodec_default_get_buffer\n");
> > + return -1;
> > }
> > +
> > + memset(pic->data, 0, sizeof(pic->data));
> > pic->extended_data = pic->data;
> > - avci->buffer_count++;
> > +
> > + av_pix_fmt_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift,
> > &v_chroma_shift);
> > +
> > + for (i = 0; i < 4 && pool->pools[i]; i++) {
> > + const int h_shift = i == 0 ? 0 : h_chroma_shift;
> > + const int v_shift = i == 0 ? 0 : v_chroma_shift;
> > +
> > + pic->linesize[i] = pool->linesize[i];
> > +
> > + pic->buf[i] = av_buffer_alloc_pool(pool->pools[i]);
> > + if (!pic->buf[i])
> > + goto fail;
> > +
> > + // no edge if EDGE EMU or not planar YUV
>
> that's probably not a good idea and it would needed to be documented
> somewhere else.
This is also just copied from the current code. Besides, we should really
consider getting read of non-emu edge completely.
> > +void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic)
> > +{
> > + av_assert0(0);
> > +}
> > +
> > +int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic)
> > +{
> > + av_assert0(0);
> > +}
>
> a nasty way of deprecating external functions.
> avcodec_default_release_buffer() is used third party code. I only
> checked mythtv.
Ok, changed it to av_frame_unref(pic) locally. I kept the assert for reget
though, since I cnt't see why whould it ever be called now.
--
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel