libvpxdec.c 4.91 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 23 24 25 26
/*
 * 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
 * VP8 decoder support via libvpx
 */

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

30
#include "libavutil/common.h"
31
#include "libavutil/imgutils.h"
James Zern's avatar
James Zern committed
32 33 34 35 36 37
#include "avcodec.h"

typedef struct VP8DecoderContext {
    struct vpx_codec_ctx decoder;
} VP8Context;

Luca Barbato's avatar
Luca Barbato committed
38 39
static av_cold int vpx_init(AVCodecContext *avctx,
                            const struct vpx_codec_iface *iface)
James Zern's avatar
James Zern committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
{
    VP8Context *ctx = avctx->priv_data;
    struct vpx_codec_dec_cfg deccfg = {
        /* token partitions+1 would be a decent choice */
        .threads = FFMIN(avctx->thread_count, 16)
    };

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

    if (vpx_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != VPX_CODEC_OK) {
        const char *error = vpx_codec_error(&ctx->decoder);
        av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n",
               error);
        return AVERROR(EINVAL);
    }

57
    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
James Zern's avatar
James Zern committed
58 59 60 61
    return 0;
}

static int vp8_decode(AVCodecContext *avctx,
62
                      void *data, int *got_frame, AVPacket *avpkt)
James Zern's avatar
James Zern committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
{
    VP8Context *ctx = avctx->priv_data;
    AVFrame *picture = data;
    const void *iter = NULL;
    struct vpx_image *img;

    if (vpx_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL, 0) !=
        VPX_CODEC_OK) {
        const char *error  = vpx_codec_error(&ctx->decoder);
        const char *detail = vpx_codec_error_detail(&ctx->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;
    }

    if ((img = vpx_codec_get_frame(&ctx->decoder, &iter))) {
        if (img->fmt != VPX_IMG_FMT_I420) {
            av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d)\n",
                   img->fmt);
            return AVERROR_INVALIDDATA;
        }

        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);
91
            if (av_image_check_size(img->d_w, img->d_h, 0, avctx))
James Zern's avatar
James Zern committed
92 93 94 95 96 97 98 99 100 101 102
                return AVERROR_INVALIDDATA;
            avcodec_set_dimensions(avctx, img->d_w, img->d_h);
        }
        picture->data[0]     = img->planes[0];
        picture->data[1]     = img->planes[1];
        picture->data[2]     = img->planes[2];
        picture->data[3]     = NULL;
        picture->linesize[0] = img->stride[0];
        picture->linesize[1] = img->stride[1];
        picture->linesize[2] = img->stride[2];
        picture->linesize[3] = 0;
103
        *got_frame           = 1;
James Zern's avatar
James Zern committed
104 105 106 107 108 109 110 111 112 113 114
    }
    return avpkt->size;
}

static av_cold int vp8_free(AVCodecContext *avctx)
{
    VP8Context *ctx = avctx->priv_data;
    vpx_codec_destroy(&ctx->decoder);
    return 0;
}

115 116 117 118 119 120 121
#if CONFIG_LIBVPX_VP8_DECODER
static av_cold int vp8_init(AVCodecContext *avctx)
{
    return vpx_init(avctx, &vpx_codec_vp8_dx_algo);
}

AVCodec ff_libvpx_vp8_decoder = {
122 123
    .name           = "libvpx",
    .type           = AVMEDIA_TYPE_VIDEO,
124
    .id             = AV_CODEC_ID_VP8,
125 126 127 128
    .priv_data_size = sizeof(VP8Context),
    .init           = vp8_init,
    .close          = vp8_free,
    .decode         = vp8_decode,
129 130
    .capabilities   = CODEC_CAP_AUTO_THREADS,
    .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP8"),
James Zern's avatar
James Zern committed
131
};
132
#endif /* CONFIG_LIBVPX_VP8_DECODER */
Luca Barbato's avatar
Luca Barbato committed
133

134
#if CONFIG_LIBVPX_VP9_DECODER
Luca Barbato's avatar
Luca Barbato committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
static av_cold int vp9_init(AVCodecContext *avctx)
{
    return vpx_init(avctx, &vpx_codec_vp9_dx_algo);
}

AVCodec ff_libvpx_vp9_decoder = {
    .name           = "libvpx-vp9",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_VP9,
    .priv_data_size = sizeof(VP8Context),
    .init           = vp9_init,
    .close          = vp8_free,
    .decode         = vp8_decode,
    .capabilities   = CODEC_CAP_AUTO_THREADS | CODEC_CAP_EXPERIMENTAL,
    .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP9"),
};
151
#endif /* CONFIG_LIBVPX_VP9_DECODER */