tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

get_buffer.c (9530B)


      1 /*
      2 * The default get_buffer2() implementation
      3 *
      4 * This file is part of FFmpeg.
      5 *
      6 * FFmpeg is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * FFmpeg is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with FFmpeg; if not, write to the Free Software
     18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     19 */
     20 
     21 #include <stdint.h>
     22 
     23 #include "libavutil/avassert.h"
     24 #include "libavutil/avutil.h"
     25 #include "libavutil/buffer.h"
     26 #include "libavutil/frame.h"
     27 #include "libavutil/hwcontext.h"
     28 #include "libavutil/imgutils.h"
     29 #include "libavutil/mem.h"
     30 #include "libavutil/samplefmt.h"
     31 #include "libavutil/version.h"
     32 
     33 #include "avcodec.h"
     34 #include "internal.h"
     35 #include "libavutil/refstruct.h"
     36 
     37 typedef struct FramePool {
     38    /**
     39     * Pools for each data plane. For audio all the planes have the same size,
     40     * so only pools[0] is used.
     41     */
     42    AVBufferPool *pools[4];
     43 
     44    /*
     45     * Pool parameters
     46     */
     47    int format;
     48    int width, height;
     49    int stride_align[AV_NUM_DATA_POINTERS];
     50    int linesize[4];
     51    int planes;
     52    int channels;
     53    int samples;
     54 } FramePool;
     55 
     56 static void frame_pool_free(AVRefStructOpaque unused, void *obj)
     57 {
     58    FramePool *pool = obj;
     59    int i;
     60 
     61    for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
     62        av_buffer_pool_uninit(&pool->pools[i]);
     63 }
     64 
     65 static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
     66 {
     67    FramePool *pool = avctx->internal->pool;
     68    int i, ret;
     69 
     70    if (pool && pool->format == frame->format) {
     71        if (avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
     72            pool->width == frame->width && pool->height == frame->height)
     73            return 0;
     74        if (avctx->codec_type == AVMEDIA_TYPE_AUDIO &&
     75            pool->channels == frame->ch_layout.nb_channels &&
     76            frame->nb_samples == pool->samples)
     77            return 0;
     78    }
     79 
     80    pool = av_refstruct_alloc_ext(sizeof(*pool), 0, NULL, frame_pool_free);
     81    if (!pool)
     82        return AVERROR(ENOMEM);
     83 
     84    switch (avctx->codec_type) {
     85    case AVMEDIA_TYPE_VIDEO: {
     86        int linesize[4];
     87        int w = frame->width;
     88        int h = frame->height;
     89        int unaligned;
     90        ptrdiff_t linesize1[4];
     91        size_t size[4];
     92 
     93        avcodec_align_dimensions2(avctx, &w, &h, pool->stride_align);
     94 
     95        do {
     96            // NOTE: do not align linesizes individually, this breaks e.g. assumptions
     97            // that linesize[0] == 2*linesize[1] in the MPEG-encoder for 4:2:2
     98            ret = av_image_fill_linesizes(linesize, avctx->pix_fmt, w);
     99            if (ret < 0)
    100                goto fail;
    101            // increase alignment of w for next try (rhs gives the lowest bit set in w)
    102            w += w & ~(w - 1);
    103 
    104            unaligned = 0;
    105            for (i = 0; i < 4; i++)
    106                unaligned |= linesize[i] % pool->stride_align[i];
    107        } while (unaligned);
    108 
    109        for (i = 0; i < 4; i++)
    110            linesize1[i] = linesize[i];
    111        ret = av_image_fill_plane_sizes(size, avctx->pix_fmt, h, linesize1);
    112        if (ret < 0)
    113            goto fail;
    114 
    115        for (i = 0; i < 4; i++) {
    116            pool->linesize[i] = linesize[i];
    117            if (size[i]) {
    118                if (size[i] > INT_MAX - (16 + STRIDE_ALIGN - 1)) {
    119                    ret = AVERROR(EINVAL);
    120                    goto fail;
    121                }
    122                pool->pools[i] = av_buffer_pool_init(size[i] + 16 + STRIDE_ALIGN - 1,
    123                                                     CONFIG_MEMORY_POISONING ?
    124                                                        NULL :
    125                                                        av_buffer_allocz);
    126                if (!pool->pools[i]) {
    127                    ret = AVERROR(ENOMEM);
    128                    goto fail;
    129                }
    130            }
    131        }
    132        pool->format = frame->format;
    133        pool->width  = frame->width;
    134        pool->height = frame->height;
    135 
    136        break;
    137        }
    138    case AVMEDIA_TYPE_AUDIO: {
    139        ret = av_samples_get_buffer_size(&pool->linesize[0],
    140                                         frame->ch_layout.nb_channels,
    141                                         frame->nb_samples, frame->format, 0);
    142        if (ret < 0)
    143            goto fail;
    144 
    145        pool->pools[0] = av_buffer_pool_init(pool->linesize[0],
    146                                             CONFIG_MEMORY_POISONING ?
    147                                                NULL :
    148                                                av_buffer_allocz);
    149        if (!pool->pools[0]) {
    150            ret = AVERROR(ENOMEM);
    151            goto fail;
    152        }
    153 
    154        pool->format     = frame->format;
    155        pool->channels   = frame->ch_layout.nb_channels;
    156        pool->samples = frame->nb_samples;
    157        pool->planes     = av_sample_fmt_is_planar(pool->format) ? pool->channels : 1;
    158        break;
    159        }
    160    default: av_assert0(0);
    161    }
    162 
    163    av_refstruct_unref(&avctx->internal->pool);
    164    avctx->internal->pool = pool;
    165 
    166    return 0;
    167 fail:
    168    av_refstruct_unref(&pool);
    169    return ret;
    170 }
    171 
    172 static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
    173 {
    174    FramePool *pool = avctx->internal->pool;
    175    int planes = pool->planes;
    176    int i;
    177 
    178    frame->linesize[0] = pool->linesize[0];
    179 
    180    if (planes > AV_NUM_DATA_POINTERS) {
    181        frame->extended_data = av_calloc(planes, sizeof(*frame->extended_data));
    182        frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS;
    183        frame->extended_buf  = av_calloc(frame->nb_extended_buf,
    184                                          sizeof(*frame->extended_buf));
    185        if (!frame->extended_data || !frame->extended_buf) {
    186            av_freep(&frame->extended_data);
    187            av_freep(&frame->extended_buf);
    188            return AVERROR(ENOMEM);
    189        }
    190    } else {
    191        frame->extended_data = frame->data;
    192        av_assert0(frame->nb_extended_buf == 0);
    193    }
    194 
    195    for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) {
    196        frame->buf[i] = av_buffer_pool_get(pool->pools[0]);
    197        if (!frame->buf[i])
    198            goto fail;
    199        frame->extended_data[i] = frame->data[i] = frame->buf[i]->data;
    200    }
    201    for (i = 0; i < frame->nb_extended_buf; i++) {
    202        frame->extended_buf[i] = av_buffer_pool_get(pool->pools[0]);
    203        if (!frame->extended_buf[i])
    204            goto fail;
    205        frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data;
    206    }
    207 
    208    if (avctx->debug & FF_DEBUG_BUFFERS)
    209        av_log(avctx, AV_LOG_DEBUG, "default_get_buffer called on frame %p", frame);
    210 
    211    return 0;
    212 fail:
    213    av_frame_unref(frame);
    214    return AVERROR(ENOMEM);
    215 }
    216 
    217 static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
    218 {
    219    FramePool *pool = s->internal->pool;
    220    int i;
    221 
    222    if (pic->data[0] || pic->data[1] || pic->data[2] || pic->data[3]) {
    223        av_log(s, AV_LOG_ERROR, "pic->data[*]!=NULL in avcodec_default_get_buffer\n");
    224        return -1;
    225    }
    226 
    227    memset(pic->data, 0, sizeof(pic->data));
    228    pic->extended_data = pic->data;
    229 
    230    for (i = 0; i < 4 && pool->pools[i]; i++) {
    231        pic->linesize[i] = pool->linesize[i];
    232 
    233        pic->buf[i] = av_buffer_pool_get(pool->pools[i]);
    234        if (!pic->buf[i])
    235            goto fail;
    236 
    237        pic->data[i] = pic->buf[i]->data;
    238    }
    239    for (; i < AV_NUM_DATA_POINTERS; i++) {
    240        pic->data[i] = NULL;
    241        pic->linesize[i] = 0;
    242    }
    243 
    244    if (s->debug & FF_DEBUG_BUFFERS)
    245        av_log(s, AV_LOG_DEBUG, "default_get_buffer called on pic %p\n", pic);
    246 
    247    return 0;
    248 fail:
    249    av_frame_unref(pic);
    250    return AVERROR(ENOMEM);
    251 }
    252 
    253 int avcodec_default_get_buffer2(AVCodecContext *avctx, AVFrame *frame, int flags)
    254 {
    255    int ret;
    256 
    257    if (avctx->hw_frames_ctx) {
    258        ret = av_hwframe_get_buffer(avctx->hw_frames_ctx, frame, 0);
    259        if (ret == AVERROR(ENOMEM)) {
    260            AVHWFramesContext *frames_ctx =
    261                (AVHWFramesContext*)avctx->hw_frames_ctx->data;
    262            if (frames_ctx->initial_pool_size > 0 &&
    263                !avctx->internal->warned_on_failed_allocation_from_fixed_pool) {
    264                av_log(avctx, AV_LOG_WARNING, "Failed to allocate a %s/%s "
    265                       "frame from a fixed pool of hardware frames.\n",
    266                       av_get_pix_fmt_name(frames_ctx->format),
    267                       av_get_pix_fmt_name(frames_ctx->sw_format));
    268                av_log(avctx, AV_LOG_WARNING, "Consider setting "
    269                       "extra_hw_frames to a larger value "
    270                       "(currently set to %d, giving a pool size of %d).\n",
    271                       avctx->extra_hw_frames, frames_ctx->initial_pool_size);
    272                avctx->internal->warned_on_failed_allocation_from_fixed_pool = 1;
    273            }
    274        }
    275        frame->width  = avctx->coded_width;
    276        frame->height = avctx->coded_height;
    277        return ret;
    278    }
    279 
    280    if ((ret = update_frame_pool(avctx, frame)) < 0)
    281        return ret;
    282 
    283    switch (avctx->codec_type) {
    284    case AVMEDIA_TYPE_VIDEO:
    285        return video_get_buffer(avctx, frame);
    286    case AVMEDIA_TYPE_AUDIO:
    287        return audio_get_buffer(avctx, frame);
    288    default:
    289        return -1;
    290    }
    291 }