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

Reply via email to