libvpxdec.c 4.84 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
#include "avcodec.h"
33
#include "internal.h"
34
#include "libvpx.h"
James Zern's avatar
James Zern committed
35 36 37 38 39

typedef struct VP8DecoderContext {
    struct vpx_codec_ctx decoder;
} VP8Context;

Luca Barbato's avatar
Luca Barbato committed
40 41
static av_cold int vpx_init(AVCodecContext *avctx,
                            const struct vpx_codec_iface *iface)
James Zern's avatar
James Zern committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
{
    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);
    }

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

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

    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);
94 95 96
            ret = ff_set_dimensions(avctx, img->d_w, img->d_h);
            if (ret < 0)
                return ret;
James Zern's avatar
James Zern committed
97
        }
98 99
        if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
            return ret;
100
        av_image_copy(picture->data, picture->linesize, (const uint8_t **)img->planes,
101
                      img->stride, avctx->pix_fmt, img->d_w, img->d_h);
102
        *got_frame           = 1;
James Zern's avatar
James Zern committed
103 104 105 106 107 108 109 110 111 112 113
    }
    return avpkt->size;
}

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

114 115 116 117 118 119 120
#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 = {
121
    .name           = "libvpx",
122
    .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP8"),
123
    .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
    .capabilities   = CODEC_CAP_AUTO_THREADS | CODEC_CAP_DR1,
James Zern's avatar
James Zern committed
130
};
131
#endif /* CONFIG_LIBVPX_VP8_DECODER */
Luca Barbato's avatar
Luca Barbato committed
132

133
#if CONFIG_LIBVPX_VP9_DECODER
Luca Barbato's avatar
Luca Barbato committed
134 135 136 137 138 139 140
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",
141
    .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP9"),
Luca Barbato's avatar
Luca Barbato committed
142 143 144 145 146 147
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_VP9,
    .priv_data_size = sizeof(VP8Context),
    .init           = vp9_init,
    .close          = vp8_free,
    .decode         = vp8_decode,
148
    .capabilities   = CODEC_CAP_AUTO_THREADS | CODEC_CAP_DR1,
149
    .init_static_data = ff_vp9_init_static,
Luca Barbato's avatar
Luca Barbato committed
150
};
151
#endif /* CONFIG_LIBVPX_VP9_DECODER */