]> git.sesse.net Git - ffmpeg/blob - libavcodec/libvpxdec.c
Merge commit 'e05e5920a4e1f1f15cc8a7c843159d519f6ec18e'
[ffmpeg] / libavcodec / libvpxdec.c
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 #define VPX_CODEC_DISABLE_COMPAT 1
27 #include <vpx/vpx_decoder.h>
28 #include <vpx/vp8dx.h>
29
30 #include "libavutil/common.h"
31 #include "libavutil/imgutils.h"
32 #include "libavutil/intreadwrite.h"
33 #include "avcodec.h"
34 #include "internal.h"
35 #include "libvpx.h"
36 #include "profiles.h"
37
38 typedef struct VPxDecoderContext {
39     struct vpx_codec_ctx decoder;
40     struct vpx_codec_ctx decoder_alpha;
41     int has_alpha_channel;
42 } VPxContext;
43
44 static av_cold int vpx_init(AVCodecContext *avctx,
45                             const struct vpx_codec_iface *iface,
46                             int is_alpha_decoder)
47 {
48     VPxContext *ctx = avctx->priv_data;
49     struct vpx_codec_dec_cfg deccfg = {
50         /* token partitions+1 would be a decent choice */
51         .threads = FFMIN(avctx->thread_count, 16)
52     };
53
54     av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
55     av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
56
57     if (vpx_codec_dec_init(
58             is_alpha_decoder ? &ctx->decoder_alpha : &ctx->decoder,
59             iface, &deccfg, 0) != VPX_CODEC_OK) {
60         const char *error = vpx_codec_error(&ctx->decoder);
61         av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n",
62                error);
63         return AVERROR(EINVAL);
64     }
65
66     return 0;
67 }
68
69 // returns 0 on success, AVERROR_INVALIDDATA otherwise
70 static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img,
71                        int has_alpha_channel)
72 {
73     static const enum AVColorSpace colorspaces[8] = {
74         AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M,
75         AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB,
76     };
77 #if VPX_IMAGE_ABI_VERSION >= 4
78     static const enum AVColorRange color_ranges[] = {
79         AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG
80     };
81     avctx->color_range = color_ranges[img->range];
82 #endif
83     avctx->colorspace = colorspaces[img->cs];
84     if (avctx->codec_id == AV_CODEC_ID_VP8 && img->fmt != VPX_IMG_FMT_I420)
85         return AVERROR_INVALIDDATA;
86     switch (img->fmt) {
87     case VPX_IMG_FMT_I420:
88         if (avctx->codec_id == AV_CODEC_ID_VP9)
89             avctx->profile = FF_PROFILE_VP9_0;
90         avctx->pix_fmt =
91             has_alpha_channel ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
92         return 0;
93 #if CONFIG_LIBVPX_VP9_DECODER
94     case VPX_IMG_FMT_I422:
95         avctx->profile = FF_PROFILE_VP9_1;
96         avctx->pix_fmt = AV_PIX_FMT_YUV422P;
97         return 0;
98     case VPX_IMG_FMT_I440:
99         avctx->profile = FF_PROFILE_VP9_1;
100         avctx->pix_fmt = AV_PIX_FMT_YUV440P;
101         return 0;
102     case VPX_IMG_FMT_I444:
103         avctx->profile = FF_PROFILE_VP9_1;
104         avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
105                          AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P;
106         return 0;
107     case VPX_IMG_FMT_I42016:
108         avctx->profile = FF_PROFILE_VP9_2;
109         if (img->bit_depth == 10) {
110             avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
111             return 0;
112         } else if (img->bit_depth == 12) {
113             avctx->pix_fmt = AV_PIX_FMT_YUV420P12;
114             return 0;
115         } else {
116             return AVERROR_INVALIDDATA;
117         }
118     case VPX_IMG_FMT_I42216:
119         avctx->profile = FF_PROFILE_VP9_3;
120         if (img->bit_depth == 10) {
121             avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
122             return 0;
123         } else if (img->bit_depth == 12) {
124             avctx->pix_fmt = AV_PIX_FMT_YUV422P12;
125             return 0;
126         } else {
127             return AVERROR_INVALIDDATA;
128         }
129     case VPX_IMG_FMT_I44016:
130         avctx->profile = FF_PROFILE_VP9_3;
131         if (img->bit_depth == 10) {
132             avctx->pix_fmt = AV_PIX_FMT_YUV440P10;
133             return 0;
134         } else if (img->bit_depth == 12) {
135             avctx->pix_fmt = AV_PIX_FMT_YUV440P12;
136             return 0;
137         } else {
138             return AVERROR_INVALIDDATA;
139         }
140     case VPX_IMG_FMT_I44416:
141         avctx->profile = FF_PROFILE_VP9_3;
142         if (img->bit_depth == 10) {
143             avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
144                              AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10;
145             return 0;
146         } else if (img->bit_depth == 12) {
147             avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ?
148                              AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12;
149             return 0;
150         } else {
151             return AVERROR_INVALIDDATA;
152         }
153 #endif
154     default:
155         return AVERROR_INVALIDDATA;
156     }
157 }
158
159 static int decode_frame(AVCodecContext *avctx, vpx_codec_ctx_t *decoder,
160                         uint8_t *data, uint32_t data_sz)
161 {
162     if (vpx_codec_decode(decoder, data, data_sz, NULL, 0) != VPX_CODEC_OK) {
163         const char *error  = vpx_codec_error(decoder);
164         const char *detail = vpx_codec_error_detail(decoder);
165
166         av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error);
167         if (detail) {
168             av_log(avctx, AV_LOG_ERROR, "  Additional information: %s\n",
169                    detail);
170         }
171         return AVERROR_INVALIDDATA;
172     }
173     return 0;
174 }
175
176 static int vpx_decode(AVCodecContext *avctx,
177                       void *data, int *got_frame, AVPacket *avpkt)
178 {
179     VPxContext *ctx = avctx->priv_data;
180     AVFrame *picture = data;
181     const void *iter = NULL;
182     const void *iter_alpha = NULL;
183     struct vpx_image *img, *img_alpha;
184     int ret;
185     uint8_t *side_data = NULL;
186     int side_data_size = 0;
187
188     ret = decode_frame(avctx, &ctx->decoder, avpkt->data, avpkt->size);
189     if (ret)
190         return ret;
191
192     side_data = av_packet_get_side_data(avpkt,
193                                         AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
194                                         &side_data_size);
195     if (side_data_size > 1) {
196         const uint64_t additional_id = AV_RB64(side_data);
197         side_data += 8;
198         side_data_size -= 8;
199         if (additional_id == 1) {  // 1 stands for alpha channel data.
200             if (!ctx->has_alpha_channel) {
201                 ctx->has_alpha_channel = 1;
202                 ret = vpx_init(avctx,
203 #if CONFIG_LIBVPX_VP8_DECODER && CONFIG_LIBVPX_VP9_DECODER
204                                (avctx->codec_id == AV_CODEC_ID_VP8) ?
205                                &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
206 #elif CONFIG_LIBVPX_VP8_DECODER
207                                &vpx_codec_vp8_dx_algo,
208 #else
209                                &vpx_codec_vp9_dx_algo,
210 #endif
211                                1);
212                 if (ret)
213                     return ret;
214             }
215             ret = decode_frame(avctx, &ctx->decoder_alpha, side_data,
216                                side_data_size);
217             if (ret)
218                 return ret;
219         }
220     }
221
222     if ((img = vpx_codec_get_frame(&ctx->decoder, &iter)) &&
223         (!ctx->has_alpha_channel ||
224          (img_alpha = vpx_codec_get_frame(&ctx->decoder_alpha, &iter_alpha)))) {
225         uint8_t *planes[4];
226         int linesizes[4];
227
228         if (img->d_w > img->w || img->d_h > img->h) {
229             av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed storage %dx%d\n",
230                    img->d_w, img->d_h, img->w, img->h);
231             return AVERROR_EXTERNAL;
232         }
233
234         if ((ret = set_pix_fmt(avctx, img, ctx->has_alpha_channel)) < 0) {
235             av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n",
236                    img->fmt, img->bit_depth);
237             return ret;
238         }
239
240         if ((int) img->d_w != avctx->width || (int) img->d_h != avctx->height) {
241             av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n",
242                    avctx->width, avctx->height, img->d_w, img->d_h);
243             ret = ff_set_dimensions(avctx, img->d_w, img->d_h);
244             if (ret < 0)
245                 return ret;
246         }
247         if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
248             return ret;
249
250         planes[0] = img->planes[VPX_PLANE_Y];
251         planes[1] = img->planes[VPX_PLANE_U];
252         planes[2] = img->planes[VPX_PLANE_V];
253         planes[3] =
254             ctx->has_alpha_channel ? img_alpha->planes[VPX_PLANE_Y] : NULL;
255         linesizes[0] = img->stride[VPX_PLANE_Y];
256         linesizes[1] = img->stride[VPX_PLANE_U];
257         linesizes[2] = img->stride[VPX_PLANE_V];
258         linesizes[3] =
259             ctx->has_alpha_channel ? img_alpha->stride[VPX_PLANE_Y] : 0;
260         av_image_copy(picture->data, picture->linesize, (const uint8_t**)planes,
261                       linesizes, avctx->pix_fmt, img->d_w, img->d_h);
262         *got_frame           = 1;
263     }
264     return avpkt->size;
265 }
266
267 static av_cold int vpx_free(AVCodecContext *avctx)
268 {
269     VPxContext *ctx = avctx->priv_data;
270     vpx_codec_destroy(&ctx->decoder);
271     if (ctx->has_alpha_channel)
272         vpx_codec_destroy(&ctx->decoder_alpha);
273     return 0;
274 }
275
276 #if CONFIG_LIBVPX_VP8_DECODER
277 static av_cold int vp8_init(AVCodecContext *avctx)
278 {
279     return vpx_init(avctx, &vpx_codec_vp8_dx_algo, 0);
280 }
281
282 AVCodec ff_libvpx_vp8_decoder = {
283     .name           = "libvpx",
284     .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP8"),
285     .type           = AVMEDIA_TYPE_VIDEO,
286     .id             = AV_CODEC_ID_VP8,
287     .priv_data_size = sizeof(VPxContext),
288     .init           = vp8_init,
289     .close          = vpx_free,
290     .decode         = vpx_decode,
291     .capabilities   = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1,
292     .wrapper_name   = "libvpx",
293 };
294 #endif /* CONFIG_LIBVPX_VP8_DECODER */
295
296 #if CONFIG_LIBVPX_VP9_DECODER
297 static av_cold int vp9_init(AVCodecContext *avctx)
298 {
299     return vpx_init(avctx, &vpx_codec_vp9_dx_algo, 0);
300 }
301
302 AVCodec ff_libvpx_vp9_decoder = {
303     .name           = "libvpx-vp9",
304     .long_name      = NULL_IF_CONFIG_SMALL("libvpx VP9"),
305     .type           = AVMEDIA_TYPE_VIDEO,
306     .id             = AV_CODEC_ID_VP9,
307     .priv_data_size = sizeof(VPxContext),
308     .init           = vp9_init,
309     .close          = vpx_free,
310     .decode         = vpx_decode,
311     .capabilities   = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1,
312     .init_static_data = ff_vp9_init_static,
313     .profiles       = NULL_IF_CONFIG_SMALL(ff_vp9_profiles),
314     .wrapper_name   = "libvpx",
315 };
316 #endif /* CONFIG_LIBVPX_VP9_DECODER */