libvpxdec.c 13.2 KB
Newer Older
James Zern's avatar
James Zern committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Copyright (c) 2010, Google, Inc.
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
23
 * VP8/9 decoder support via libvpx
James Zern's avatar
James Zern committed
24 25 26
 */

#define VPX_CODEC_DISABLE_COMPAT 1
27
#include <vpx/vpx_decoder.h>
28
#include <vpx/vpx_frame_buffer.h>
29
#include <vpx/vp8dx.h>
James Zern's avatar
James Zern committed
30

31
#include "libavutil/common.h"
32
#include "libavutil/imgutils.h"
33
#include "libavutil/intreadwrite.h"
James Zern's avatar
James Zern committed
34
#include "avcodec.h"
35
#include "internal.h"
36
#include "libvpx.h"
37
#include "profiles.h"
James Zern's avatar
James Zern committed
38

39
typedef struct VPxDecoderContext {
James Zern's avatar
James Zern committed
40
    struct vpx_codec_ctx decoder;
41
    struct vpx_codec_ctx decoder_alpha;
42 43
    AVBufferPool *pool;
    size_t pool_size;
44
    int has_alpha_channel;
45
} VPxContext;
James Zern's avatar
James Zern committed
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

static int get_frame_buffer(void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb)
{
    VPxContext *ctx = priv;
    AVBufferRef *buf;

    if (min_size > ctx->pool_size) {
        av_buffer_pool_uninit(&ctx->pool);
        /* According to the libvpx docs the buffer must be zeroed out. */
        ctx->pool = av_buffer_pool_init(min_size, av_buffer_allocz);
        if (!ctx->pool) {
            ctx->pool_size = 0;
            return AVERROR(ENOMEM);
        }
        ctx->pool_size = min_size;
    }

    buf = av_buffer_pool_get(ctx->pool);
    if (!buf)
        return AVERROR(ENOMEM);

    fb->priv = buf;
    fb->size = ctx->pool_size;
    fb->data = buf->data;

    return 0;
}

static int release_frame_buffer(void *priv, vpx_codec_frame_buffer_t *fb)
{
    AVBufferRef *buf = fb->priv;
    av_buffer_unref(&buf);
    return 0;
}

Luca Barbato's avatar
Luca Barbato committed
82
static av_cold int vpx_init(AVCodecContext *avctx,
83 84
                            struct vpx_codec_ctx* decoder,
                            const struct vpx_codec_iface *iface)
James Zern's avatar
James Zern committed
85 86
{
    struct vpx_codec_dec_cfg deccfg = {
87
        .threads = FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 16)
James Zern's avatar
James Zern committed
88 89 90 91 92
    };

    av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
    av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());

93 94
    if (vpx_codec_dec_init(decoder, iface, &deccfg, 0) != VPX_CODEC_OK) {
        const char *error = vpx_codec_error(decoder);
James Zern's avatar
James Zern committed
95 96 97 98 99
        av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n",
               error);
        return AVERROR(EINVAL);
    }

100 101 102
    if (avctx->codec_id == AV_CODEC_ID_VP9)
        vpx_codec_set_frame_buffer_functions(decoder, get_frame_buffer, release_frame_buffer, avctx->priv_data);

James Zern's avatar
James Zern committed
103 104 105
    return 0;
}

106
// returns 0 on success, AVERROR_INVALIDDATA otherwise
107 108
static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img,
                       int has_alpha_channel)
109
{
110 111 112 113
    static const enum AVColorSpace colorspaces[8] = {
        AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M,
        AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB,
    };
114 115 116 117 118 119
#if VPX_IMAGE_ABI_VERSION >= 4
    static const enum AVColorRange color_ranges[] = {
        AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG
    };
    avctx->color_range = color_ranges[img->range];
#endif
120
    avctx->colorspace = colorspaces[img->cs];
121 122 123
    if (avctx->codec_id == AV_CODEC_ID_VP8 && img->fmt != VPX_IMG_FMT_I420)
        return AVERROR_INVALIDDATA;
    switch (img->fmt) {
124
    case VPX_IMG_FMT_I420:
125 126
        if (avctx->codec_id == AV_CODEC_ID_VP9)
            avctx->profile = FF_PROFILE_VP9_0;
127 128
        avctx->pix_fmt =
            has_alpha_channel ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
129
        return 0;
130
#if CONFIG_LIBVPX_VP9_DECODER
131
    case VPX_IMG_FMT_I422:
132
        avctx->profile = FF_PROFILE_VP9_1;
133 134
        avctx->pix_fmt = AV_PIX_FMT_YUV422P;
        return 0;
135
    case VPX_IMG_FMT_I440:
136
        avctx->profile = FF_PROFILE_VP9_1;
137 138
        avctx->pix_fmt = AV_PIX_FMT_YUV440P;
        return 0;
139
    case VPX_IMG_FMT_I444:
140
        avctx->profile = FF_PROFILE_VP9_1;
141 142
        avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
                         AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P;
143 144
        return 0;
    case VPX_IMG_FMT_I42016:
145
        avctx->profile = FF_PROFILE_VP9_2;
146
        if (img->bit_depth == 10) {
147
            avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
148
            return 0;
149
        } else if (img->bit_depth == 12) {
150
            avctx->pix_fmt = AV_PIX_FMT_YUV420P12;
151
            return 0;
152 153 154 155
        } else {
            return AVERROR_INVALIDDATA;
        }
    case VPX_IMG_FMT_I42216:
156
        avctx->profile = FF_PROFILE_VP9_3;
157
        if (img->bit_depth == 10) {
158
            avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
159 160
            return 0;
        } else if (img->bit_depth == 12) {
161
            avctx->pix_fmt = AV_PIX_FMT_YUV422P12;
162 163 164 165
            return 0;
        } else {
            return AVERROR_INVALIDDATA;
        }
166
    case VPX_IMG_FMT_I44016:
167
        avctx->profile = FF_PROFILE_VP9_3;
168
        if (img->bit_depth == 10) {
169
            avctx->pix_fmt = AV_PIX_FMT_YUV440P10;
170 171
            return 0;
        } else if (img->bit_depth == 12) {
172
            avctx->pix_fmt = AV_PIX_FMT_YUV440P12;
173 174 175 176
            return 0;
        } else {
            return AVERROR_INVALIDDATA;
        }
177
    case VPX_IMG_FMT_I44416:
178
        avctx->profile = FF_PROFILE_VP9_3;
179
        if (img->bit_depth == 10) {
180
            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
181
                             AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10;
182 183
            return 0;
        } else if (img->bit_depth == 12) {
184
            avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
185
                             AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12;
186 187 188 189
            return 0;
        } else {
            return AVERROR_INVALIDDATA;
        }
190
#endif
191 192
    default:
        return AVERROR_INVALIDDATA;
193 194 195
    }
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
static int decode_frame(AVCodecContext *avctx, vpx_codec_ctx_t *decoder,
                        uint8_t *data, uint32_t data_sz)
{
    if (vpx_codec_decode(decoder, data, data_sz, NULL, 0) != VPX_CODEC_OK) {
        const char *error  = vpx_codec_error(decoder);
        const char *detail = vpx_codec_error_detail(decoder);

        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error);
        if (detail) {
            av_log(avctx, AV_LOG_ERROR, "  Additional information: %s\n",
                   detail);
        }
        return AVERROR_INVALIDDATA;
    }
    return 0;
}

213
static int vpx_decode(AVCodecContext *avctx,
214
                      void *data, int *got_frame, AVPacket *avpkt)
James Zern's avatar
James Zern committed
215
{
216
    VPxContext *ctx = avctx->priv_data;
James Zern's avatar
James Zern committed
217 218
    AVFrame *picture = data;
    const void *iter = NULL;
219 220
    const void *iter_alpha = NULL;
    struct vpx_image *img, *img_alpha;
221
    int ret;
222 223
    uint8_t *side_data = NULL;
    int side_data_size = 0;
James Zern's avatar
James Zern committed
224

225 226 227
    ret = decode_frame(avctx, &ctx->decoder, avpkt->data, avpkt->size);
    if (ret)
        return ret;
James Zern's avatar
James Zern committed
228

229 230 231
    side_data = av_packet_get_side_data(avpkt,
                                        AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
                                        &side_data_size);
232
    if (side_data_size >= 8) {
233 234 235 236 237 238 239
        const uint64_t additional_id = AV_RB64(side_data);
        side_data += 8;
        side_data_size -= 8;
        if (additional_id == 1) {  // 1 stands for alpha channel data.
            if (!ctx->has_alpha_channel) {
                ctx->has_alpha_channel = 1;
                ret = vpx_init(avctx,
240
                               &ctx->decoder_alpha,
241 242
#if CONFIG_LIBVPX_VP8_DECODER && CONFIG_LIBVPX_VP9_DECODER
                               (avctx->codec_id == AV_CODEC_ID_VP8) ?
243
                               &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo
244
#elif CONFIG_LIBVPX_VP8_DECODER
245
                               &vpx_codec_vp8_dx_algo
246
#else
247
                               &vpx_codec_vp9_dx_algo
248
#endif
249
                               );
250 251 252 253 254 255 256 257
                if (ret)
                    return ret;
            }
            ret = decode_frame(avctx, &ctx->decoder_alpha, side_data,
                               side_data_size);
            if (ret)
                return ret;
        }
James Zern's avatar
James Zern committed
258 259
    }

260 261 262 263 264
    if ((img = vpx_codec_get_frame(&ctx->decoder, &iter)) &&
        (!ctx->has_alpha_channel ||
         (img_alpha = vpx_codec_get_frame(&ctx->decoder_alpha, &iter_alpha)))) {
        uint8_t *planes[4];
        int linesizes[4];
265 266 267 268 269 270 271

        if (img->d_w > img->w || img->d_h > img->h) {
            av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed storage %dx%d\n",
                   img->d_w, img->d_h, img->w, img->h);
            return AVERROR_EXTERNAL;
        }

272
        if ((ret = set_pix_fmt(avctx, img, ctx->has_alpha_channel)) < 0) {
273 274 275
            av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n",
                   img->fmt, img->bit_depth);
            return ret;
James Zern's avatar
James Zern committed
276 277 278 279 280
        }

        if ((int) img->d_w != avctx->width || (int) img->d_h != avctx->height) {
            av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n",
                   avctx->width, avctx->height, img->d_w, img->d_h);
281 282 283
            ret = ff_set_dimensions(avctx, img->d_w, img->d_h);
            if (ret < 0)
                return ret;
James Zern's avatar
James Zern committed
284
        }
285

286 287 288 289 290
        if (ctx->has_alpha_channel &&
            (img->d_w != img_alpha->d_w ||
             img->d_h != img_alpha->d_h ||
             img->bit_depth != img_alpha->bit_depth)) {
            av_log(avctx, AV_LOG_ERROR,
291
                   "Video dimensions %dx%d@%dbpc differ from alpha dimensions %dx%d@%dbpc\n",
292 293 294 295 296
                   img->d_w, img->d_h, img->bit_depth,
                   img_alpha->d_w, img_alpha->d_h, img_alpha->bit_depth);
            return AVERROR_INVALIDDATA;
        }

297 298 299 300 301 302 303 304 305 306
        planes[0] = img->planes[VPX_PLANE_Y];
        planes[1] = img->planes[VPX_PLANE_U];
        planes[2] = img->planes[VPX_PLANE_V];
        planes[3] =
            ctx->has_alpha_channel ? img_alpha->planes[VPX_PLANE_Y] : NULL;
        linesizes[0] = img->stride[VPX_PLANE_Y];
        linesizes[1] = img->stride[VPX_PLANE_U];
        linesizes[2] = img->stride[VPX_PLANE_V];
        linesizes[3] =
            ctx->has_alpha_channel ? img_alpha->stride[VPX_PLANE_Y] : 0;
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331

        if (img->fb_priv && (!ctx->has_alpha_channel || img_alpha->fb_priv)) {
            ret = ff_decode_frame_props(avctx, picture);
            if (ret < 0)
                return ret;
            picture->buf[0] = av_buffer_ref(img->fb_priv);
            if (!picture->buf[0])
                return AVERROR(ENOMEM);
            if (ctx->has_alpha_channel) {
                picture->buf[1] = av_buffer_ref(img_alpha->fb_priv);
                if (!picture->buf[1]) {
                    av_frame_unref(picture);
                    return AVERROR(ENOMEM);
                }
            }
            for (int i = 0; i < 4; i++) {
                picture->data[i] = planes[i];
                picture->linesize[i] = linesizes[i];
            }
        } else {
            if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
                return ret;
            av_image_copy(picture->data, picture->linesize, (const uint8_t**)planes,
                          linesizes, avctx->pix_fmt, img->d_w, img->d_h);
        }
332
        *got_frame           = 1;
James Zern's avatar
James Zern committed
333 334 335 336
    }
    return avpkt->size;
}

337
static av_cold int vpx_free(AVCodecContext *avctx)
James Zern's avatar
James Zern committed
338
{
339
    VPxContext *ctx = avctx->priv_data;
James Zern's avatar
James Zern committed
340
    vpx_codec_destroy(&ctx->decoder);
341 342
    if (ctx->has_alpha_channel)
        vpx_codec_destroy(&ctx->decoder_alpha);
343
    av_buffer_pool_uninit(&ctx->pool);
James Zern's avatar
James Zern committed
344 345 346
    return 0;
}

347 348 349
#if CONFIG_LIBVPX_VP8_DECODER
static av_cold int vp8_init(AVCodecContext *avctx)
{
350 351
    VPxContext *ctx = avctx->priv_data;
    return vpx_init(avctx, &ctx->decoder, &vpx_codec_vp8_dx_algo);
352 353 354
}

AVCodec ff_libvpx_vp8_decoder = {
355
    .name           = "libvpx",
356
    .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP8"),
357
    .type           = AVMEDIA_TYPE_VIDEO,
358
    .id             = AV_CODEC_ID_VP8,
359
    .priv_data_size = sizeof(VPxContext),
360
    .init           = vp8_init,
361 362
    .close          = vpx_free,
    .decode         = vpx_decode,
363
    .capabilities   = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1,
364
    .wrapper_name   = "libvpx",
James Zern's avatar
James Zern committed
365
};
366
#endif /* CONFIG_LIBVPX_VP8_DECODER */
Luca Barbato's avatar
Luca Barbato committed
367

368
#if CONFIG_LIBVPX_VP9_DECODER
Luca Barbato's avatar
Luca Barbato committed
369 370
static av_cold int vp9_init(AVCodecContext *avctx)
{
371 372
    VPxContext *ctx = avctx->priv_data;
    return vpx_init(avctx, &ctx->decoder, &vpx_codec_vp9_dx_algo);
Luca Barbato's avatar
Luca Barbato committed
373 374 375 376
}

AVCodec ff_libvpx_vp9_decoder = {
    .name           = "libvpx-vp9",
377
    .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP9"),
Luca Barbato's avatar
Luca Barbato committed
378 379
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_VP9,
380
    .priv_data_size = sizeof(VPxContext),
Luca Barbato's avatar
Luca Barbato committed
381
    .init           = vp9_init,
382 383
    .close          = vpx_free,
    .decode         = vpx_decode,
384
    .capabilities   = AV_CODEC_CAP_AUTO_THREADS,
385
    .init_static_data = ff_vp9_init_static,
386
    .profiles       = NULL_IF_CONFIG_SMALL(ff_vp9_profiles),
387
    .wrapper_name   = "libvpx",
Luca Barbato's avatar
Luca Barbato committed
388
};
389
#endif /* CONFIG_LIBVPX_VP9_DECODER */