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