tor-browser

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

libvpxdec.c (13590B)


      1 /*
      2 * Copyright (c) 2010, Google, Inc.
      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 /**
     22 * @file
     23 * VP8/9 decoder support via libvpx
     24 */
     25 
     26 #include "config_components.h"
     27 
     28 #define VPX_CODEC_DISABLE_COMPAT 1
     29 #include <vpx/vpx_decoder.h>
     30 #include <vpx/vpx_frame_buffer.h>
     31 #include <vpx/vp8dx.h>
     32 
     33 #include "libavutil/common.h"
     34 #include "libavutil/cpu.h"
     35 #include "libavutil/imgutils.h"
     36 #include "libavutil/intreadwrite.h"
     37 #include "avcodec.h"
     38 #include "codec_internal.h"
     39 #include "decode.h"
     40 #include "libvpx.h"
     41 #include "profiles.h"
     42 
     43 typedef struct VPxDecoderContext {
     44    struct vpx_codec_ctx decoder;
     45    struct vpx_codec_ctx decoder_alpha;
     46    AVBufferPool *pool;
     47    size_t pool_size;
     48    int has_alpha_channel;
     49 } VPxContext;
     50 
     51 
     52 static int get_frame_buffer(void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb)
     53 {
     54    VPxContext *ctx = priv;
     55    AVBufferRef *buf;
     56 
     57    if (min_size > ctx->pool_size) {
     58        av_buffer_pool_uninit(&ctx->pool);
     59        /* According to the libvpx docs the buffer must be zeroed out. */
     60        ctx->pool = av_buffer_pool_init(min_size, av_buffer_allocz);
     61        if (!ctx->pool) {
     62            ctx->pool_size = 0;
     63            return AVERROR(ENOMEM);
     64        }
     65        ctx->pool_size = min_size;
     66    }
     67 
     68    buf = av_buffer_pool_get(ctx->pool);
     69    if (!buf)
     70        return AVERROR(ENOMEM);
     71 
     72    fb->priv = buf;
     73    fb->size = ctx->pool_size;
     74    fb->data = buf->data;
     75 
     76    return 0;
     77 }
     78 
     79 static int release_frame_buffer(void *priv, vpx_codec_frame_buffer_t *fb)
     80 {
     81    AVBufferRef *buf = fb->priv;
     82    av_buffer_unref(&buf);
     83    return 0;
     84 }
     85 
     86 static av_cold int vpx_init(AVCodecContext *avctx,
     87                            struct vpx_codec_ctx* decoder,
     88                            const struct vpx_codec_iface *iface)
     89 {
     90    struct vpx_codec_dec_cfg deccfg = {
     91        .threads = FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), MAX_VPX_THREADS)
     92    };
     93 
     94    av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
     95    av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
     96 
     97    if (vpx_codec_dec_init(decoder, iface, &deccfg, 0) != VPX_CODEC_OK) {
     98        const char *error = vpx_codec_error(decoder);
     99        av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n",
    100               error);
    101        return AVERROR(EINVAL);
    102    }
    103 
    104    if (avctx->codec_id == AV_CODEC_ID_VP9)
    105        vpx_codec_set_frame_buffer_functions(decoder, get_frame_buffer, release_frame_buffer, avctx->priv_data);
    106 
    107    return 0;
    108 }
    109 
    110 // returns 0 on success, AVERROR_INVALIDDATA otherwise
    111 static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img,
    112                       int has_alpha_channel)
    113 {
    114    static const enum AVColorSpace colorspaces[8] = {
    115        AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M,
    116        AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB,
    117    };
    118 #if VPX_IMAGE_ABI_VERSION >= 4
    119    static const enum AVColorRange color_ranges[] = {
    120        AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG
    121    };
    122    avctx->color_range = color_ranges[img->range];
    123 #endif
    124    avctx->colorspace = colorspaces[img->cs];
    125    if (avctx->codec_id == AV_CODEC_ID_VP8 && img->fmt != VPX_IMG_FMT_I420)
    126        return AVERROR_INVALIDDATA;
    127    switch (img->fmt) {
    128    case VPX_IMG_FMT_I420:
    129        if (avctx->codec_id == AV_CODEC_ID_VP9)
    130            avctx->profile = AV_PROFILE_VP9_0;
    131        avctx->pix_fmt =
    132            has_alpha_channel ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
    133        return 0;
    134 #if CONFIG_LIBVPX_VP9_DECODER
    135    case VPX_IMG_FMT_I422:
    136        avctx->profile = AV_PROFILE_VP9_1;
    137        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
    138        return 0;
    139    case VPX_IMG_FMT_I440:
    140        avctx->profile = AV_PROFILE_VP9_1;
    141        avctx->pix_fmt = AV_PIX_FMT_YUV440P;
    142        return 0;
    143    case VPX_IMG_FMT_I444:
    144        avctx->profile = AV_PROFILE_VP9_1;
    145        avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
    146                         AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P;
    147        return 0;
    148    case VPX_IMG_FMT_I42016:
    149        avctx->profile = AV_PROFILE_VP9_2;
    150        if (img->bit_depth == 10) {
    151            avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
    152            return 0;
    153        } else if (img->bit_depth == 12) {
    154            avctx->pix_fmt = AV_PIX_FMT_YUV420P12;
    155            return 0;
    156        } else {
    157            return AVERROR_INVALIDDATA;
    158        }
    159    case VPX_IMG_FMT_I42216:
    160        avctx->profile = AV_PROFILE_VP9_3;
    161        if (img->bit_depth == 10) {
    162            avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
    163            return 0;
    164        } else if (img->bit_depth == 12) {
    165            avctx->pix_fmt = AV_PIX_FMT_YUV422P12;
    166            return 0;
    167        } else {
    168            return AVERROR_INVALIDDATA;
    169        }
    170    case VPX_IMG_FMT_I44016:
    171        avctx->profile = AV_PROFILE_VP9_3;
    172        if (img->bit_depth == 10) {
    173            avctx->pix_fmt = AV_PIX_FMT_YUV440P10;
    174            return 0;
    175        } else if (img->bit_depth == 12) {
    176            avctx->pix_fmt = AV_PIX_FMT_YUV440P12;
    177            return 0;
    178        } else {
    179            return AVERROR_INVALIDDATA;
    180        }
    181    case VPX_IMG_FMT_I44416:
    182        avctx->profile = AV_PROFILE_VP9_3;
    183        if (img->bit_depth == 10) {
    184            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
    185                             AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10;
    186            return 0;
    187        } else if (img->bit_depth == 12) {
    188            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
    189                             AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12;
    190            return 0;
    191        } else {
    192            return AVERROR_INVALIDDATA;
    193        }
    194 #endif
    195    default:
    196        return AVERROR_INVALIDDATA;
    197    }
    198 }
    199 
    200 static int decode_frame(AVCodecContext *avctx, vpx_codec_ctx_t *decoder,
    201                        const uint8_t *data, uint32_t data_sz)
    202 {
    203    if (vpx_codec_decode(decoder, data, data_sz, NULL, 0) != VPX_CODEC_OK) {
    204        const char *error  = vpx_codec_error(decoder);
    205        const char *detail = vpx_codec_error_detail(decoder);
    206 
    207        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error);
    208        if (detail) {
    209            av_log(avctx, AV_LOG_ERROR, "  Additional information: %s\n",
    210                   detail);
    211        }
    212        return AVERROR_INVALIDDATA;
    213    }
    214    return 0;
    215 }
    216 
    217 static int vpx_decode(AVCodecContext *avctx, AVFrame *picture,
    218                      int *got_frame, AVPacket *avpkt)
    219 {
    220    VPxContext *ctx = avctx->priv_data;
    221    const void *iter = NULL;
    222    const void *iter_alpha = NULL;
    223    struct vpx_image *img, *img_alpha;
    224    int ret;
    225    uint8_t *side_data = NULL;
    226    size_t side_data_size;
    227 
    228    ret = decode_frame(avctx, &ctx->decoder, avpkt->data, avpkt->size);
    229    if (ret)
    230        return ret;
    231 
    232    side_data = av_packet_get_side_data(avpkt,
    233                                        AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
    234                                        &side_data_size);
    235    if (side_data_size >= 8) {
    236        const uint64_t additional_id = AV_RB64(side_data);
    237        side_data += 8;
    238        side_data_size -= 8;
    239        if (additional_id == 1) {  // 1 stands for alpha channel data.
    240            if (!ctx->has_alpha_channel) {
    241                ctx->has_alpha_channel = 1;
    242                ret = vpx_init(avctx,
    243                               &ctx->decoder_alpha,
    244 #if CONFIG_LIBVPX_VP8_DECODER && CONFIG_LIBVPX_VP9_DECODER
    245                               (avctx->codec_id == AV_CODEC_ID_VP8) ?
    246                               vpx_codec_vp8_dx() : vpx_codec_vp9_dx()
    247 #elif CONFIG_LIBVPX_VP8_DECODER
    248                               vpx_codec_vp8_dx()
    249 #else
    250                               vpx_codec_vp9_dx()
    251 #endif
    252                               );
    253                if (ret)
    254                    return ret;
    255            }
    256            ret = decode_frame(avctx, &ctx->decoder_alpha, side_data,
    257                               side_data_size);
    258            if (ret)
    259                return ret;
    260        }
    261    }
    262 
    263    if ((img = vpx_codec_get_frame(&ctx->decoder, &iter)) &&
    264        (!ctx->has_alpha_channel ||
    265         (img_alpha = vpx_codec_get_frame(&ctx->decoder_alpha, &iter_alpha)))) {
    266        uint8_t *planes[4];
    267        int linesizes[4];
    268 
    269        if (img->d_w > img->w || img->d_h > img->h) {
    270            av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed storage %dx%d\n",
    271                   img->d_w, img->d_h, img->w, img->h);
    272            return AVERROR_EXTERNAL;
    273        }
    274 
    275        if ((ret = set_pix_fmt(avctx, img, ctx->has_alpha_channel)) < 0) {
    276            av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n",
    277                   img->fmt, img->bit_depth);
    278            return ret;
    279        }
    280 
    281        if ((int) img->d_w != avctx->width || (int) img->d_h != avctx->height) {
    282            av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n",
    283                   avctx->width, avctx->height, img->d_w, img->d_h);
    284            ret = ff_set_dimensions(avctx, img->d_w, img->d_h);
    285            if (ret < 0)
    286                return ret;
    287        }
    288 
    289        if (ctx->has_alpha_channel &&
    290            (img->d_w != img_alpha->d_w ||
    291             img->d_h != img_alpha->d_h ||
    292             img->bit_depth != img_alpha->bit_depth)) {
    293            av_log(avctx, AV_LOG_ERROR,
    294                   "Video dimensions %dx%d@%dbpc differ from alpha dimensions %dx%d@%dbpc\n",
    295                   img->d_w, img->d_h, img->bit_depth,
    296                   img_alpha->d_w, img_alpha->d_h, img_alpha->bit_depth);
    297            return AVERROR_INVALIDDATA;
    298        }
    299 
    300        planes[0] = img->planes[VPX_PLANE_Y];
    301        planes[1] = img->planes[VPX_PLANE_U];
    302        planes[2] = img->planes[VPX_PLANE_V];
    303        planes[3] =
    304            ctx->has_alpha_channel ? img_alpha->planes[VPX_PLANE_Y] : NULL;
    305        linesizes[0] = img->stride[VPX_PLANE_Y];
    306        linesizes[1] = img->stride[VPX_PLANE_U];
    307        linesizes[2] = img->stride[VPX_PLANE_V];
    308        linesizes[3] =
    309            ctx->has_alpha_channel ? img_alpha->stride[VPX_PLANE_Y] : 0;
    310 
    311        if (img->fb_priv && (!ctx->has_alpha_channel || img_alpha->fb_priv)) {
    312            ret = ff_decode_frame_props(avctx, picture);
    313            if (ret < 0)
    314                return ret;
    315            picture->buf[0] = av_buffer_ref(img->fb_priv);
    316            if (!picture->buf[0])
    317                return AVERROR(ENOMEM);
    318            if (ctx->has_alpha_channel) {
    319                picture->buf[1] = av_buffer_ref(img_alpha->fb_priv);
    320                if (!picture->buf[1])
    321                    return AVERROR(ENOMEM);
    322            }
    323            for (int i = 0; i < 4; i++) {
    324                picture->data[i] = planes[i];
    325                picture->linesize[i] = linesizes[i];
    326            }
    327        } else {
    328            if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
    329                return ret;
    330            av_image_copy2(picture->data, picture->linesize, planes,
    331                           linesizes, avctx->pix_fmt, img->d_w, img->d_h);
    332        }
    333        *got_frame           = 1;
    334    }
    335    return avpkt->size;
    336 }
    337 
    338 static av_cold int vpx_free(AVCodecContext *avctx)
    339 {
    340    VPxContext *ctx = avctx->priv_data;
    341    vpx_codec_destroy(&ctx->decoder);
    342    if (ctx->has_alpha_channel)
    343        vpx_codec_destroy(&ctx->decoder_alpha);
    344    av_buffer_pool_uninit(&ctx->pool);
    345    return 0;
    346 }
    347 
    348 #if CONFIG_LIBVPX_VP8_DECODER
    349 static av_cold int vp8_init(AVCodecContext *avctx)
    350 {
    351    VPxContext *ctx = avctx->priv_data;
    352    return vpx_init(avctx, &ctx->decoder, vpx_codec_vp8_dx());
    353 }
    354 
    355 const FFCodec ff_libvpx_vp8_decoder = {
    356    .p.name         = "libvpx",
    357    CODEC_LONG_NAME("libvpx VP8"),
    358    .p.type         = AVMEDIA_TYPE_VIDEO,
    359    .p.id           = AV_CODEC_ID_VP8,
    360    .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1,
    361    .p.wrapper_name = "libvpx",
    362    .priv_data_size = sizeof(VPxContext),
    363    .init           = vp8_init,
    364    .close          = vpx_free,
    365    FF_CODEC_DECODE_CB(vpx_decode),
    366    .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
    367                      FF_CODEC_CAP_AUTO_THREADS,
    368 };
    369 #endif /* CONFIG_LIBVPX_VP8_DECODER */
    370 
    371 #if CONFIG_LIBVPX_VP9_DECODER
    372 static av_cold int vp9_init(AVCodecContext *avctx)
    373 {
    374    VPxContext *ctx = avctx->priv_data;
    375    return vpx_init(avctx, &ctx->decoder, vpx_codec_vp9_dx());
    376 }
    377 
    378 const FFCodec ff_libvpx_vp9_decoder = {
    379    .p.name         = "libvpx-vp9",
    380    CODEC_LONG_NAME("libvpx VP9"),
    381    .p.type         = AVMEDIA_TYPE_VIDEO,
    382    .p.id           = AV_CODEC_ID_VP9,
    383    .p.capabilities = AV_CODEC_CAP_OTHER_THREADS,
    384    .p.profiles     = NULL_IF_CONFIG_SMALL(ff_vp9_profiles),
    385    .p.wrapper_name = "libvpx",
    386    .priv_data_size = sizeof(VPxContext),
    387    .init           = vp9_init,
    388    .close          = vpx_free,
    389    FF_CODEC_DECODE_CB(vpx_decode),
    390    .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
    391                      FF_CODEC_CAP_AUTO_THREADS,
    392 };
    393 #endif /* CONFIG_LIBVPX_VP9_DECODER */