]> git.sesse.net Git - vlc/blob - modules/codec/vpx.c
ac7d8d71569a5336fd4a2aa089dbe43d0da38218
[vlc] / modules / codec / vpx.c
1 /*****************************************************************************
2  * vpx.c: libvpx decoder (VP8/VP9) module
3  *****************************************************************************
4  * Copyright (C) 2013 Rafaël Carré
5  *
6  * Authors: Rafaël Carré <funman@videolanorg>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_codec.h>
33
34 #include <vpx/vpx_decoder.h>
35 #include <vpx/vp8dx.h>
36
37 /****************************************************************************
38  * Local prototypes
39  ****************************************************************************/
40 static int Open(vlc_object_t *);
41 static void Close(vlc_object_t *);
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46
47 vlc_module_begin ()
48     set_shortname("vpx")
49     set_description(N_("WebM video decoder"))
50     set_capability("decoder", 60)
51     set_callbacks(Open, Close)
52     set_category(CAT_INPUT)
53     set_subcategory(SUBCAT_INPUT_VCODEC)
54 vlc_module_end ()
55
56 /*****************************************************************************
57  * decoder_sys_t: libvpx decoder descriptor
58  *****************************************************************************/
59 struct decoder_sys_t
60 {
61     struct vpx_codec_ctx ctx;
62 };
63
64 /****************************************************************************
65  * Decode: the whole thing
66  ****************************************************************************/
67 static picture_t *Decode(decoder_t *dec, block_t **pp_block)
68 {
69     struct vpx_codec_ctx *ctx = &dec->p_sys->ctx;
70
71     block_t *block = *pp_block;
72     if (!block)
73         return NULL;
74
75     if (block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
76         return NULL;
77
78     /* Associate packet PTS with decoded frame */
79     mtime_t *pkt_pts = malloc(sizeof(*pkt_pts));
80     if (!pkt_pts) {
81         block_Release(block);
82         *pp_block = NULL;
83         return NULL;
84     }
85
86     *pkt_pts = block->i_pts;
87
88     vpx_codec_err_t err;
89     err = vpx_codec_decode(ctx, block->p_buffer, block->i_buffer, pkt_pts, 0);
90
91     block_Release(block);
92     *pp_block = NULL;
93
94     if (err != VPX_CODEC_OK) {
95         free(pkt_pts);
96         const char *error  = vpx_codec_error(ctx);
97         const char *detail = vpx_codec_error_detail(ctx);
98         if (!detail)
99             detail = "no specific information";
100         msg_Err(dec, "Failed to decode frame: %s (%s)", error, detail);
101         return NULL;
102     }
103
104     const void *iter = NULL;
105     struct vpx_image *img = vpx_codec_get_frame(ctx, &iter);
106     if (!img)
107         return NULL;
108
109     /* fetches back the PTS */
110     pkt_pts = img->user_priv;
111     mtime_t pts = *pkt_pts;
112     free(pkt_pts);
113
114     if (img->fmt != VPX_IMG_FMT_I420) {
115         msg_Err(dec, "Unsupported output colorspace %d", img->fmt);
116         return NULL;
117     }
118
119     video_format_t *v = &dec->fmt_out.video;
120
121     if (img->d_w != v->i_visible_width || img->d_h != v->i_visible_height) {
122         v->i_visible_width = img->d_w;
123         v->i_visible_height = img->d_h;
124     }
125
126     picture_t *pic = decoder_NewPicture(dec);
127     if (!pic)
128         return NULL;
129
130     for (int plane = 0; plane < pic->i_planes; plane++ ) {
131         uint8_t *src = img->planes[plane];
132         uint8_t *dst = pic->p[plane].p_pixels;
133         int src_stride = img->stride[plane];
134         int dst_stride = pic->p[plane].i_pitch;
135
136         int size = __MIN( src_stride, dst_stride );
137         for( int line = 0; line < pic->p[plane].i_visible_lines; line++ ) {
138             memcpy( dst, src, size );
139             src += src_stride;
140             dst += dst_stride;
141         }
142     }
143
144     pic->b_progressive = true; /* codec does not support interlacing */
145     pic->date = pts;
146
147     return pic;
148 }
149
150 /*****************************************************************************
151  * Open: probe the decoder
152  *****************************************************************************/
153 static int Open(vlc_object_t *p_this)
154 {
155     decoder_t *dec = (decoder_t *)p_this;
156     const struct vpx_codec_iface *iface;
157     int vp_version;
158
159     switch (dec->fmt_in.i_codec)
160     {
161 #ifdef ENABLE_VP8_DECODER
162     case VLC_CODEC_VP8:
163         iface = &vpx_codec_vp8_dx_algo;
164         vp_version = 8;
165         break;
166 #endif
167 #ifdef ENABLE_VP9_DECODER
168     case VLC_CODEC_VP9:
169         iface = &vpx_codec_vp9_dx_algo;
170         vp_version = 9;
171         break;
172 #endif
173     default:
174         return VLC_EGENERIC;
175     }
176
177     decoder_sys_t *sys = malloc(sizeof(*sys));
178     if (!sys)
179         return VLC_ENOMEM;
180     dec->p_sys = sys;
181
182     struct vpx_codec_dec_cfg deccfg = {
183         .threads = __MIN(vlc_GetCPUCount(), 16)
184     };
185
186     msg_Dbg(p_this, "VP%d: using libvpx version %s (build options %s)", 
187         vp_version, vpx_codec_version_str(), vpx_codec_build_config());
188
189     if (vpx_codec_dec_init(&sys->ctx, iface, &deccfg, 0) != VPX_CODEC_OK) {
190         const char *error = vpx_codec_error(&sys->ctx);
191         msg_Err(p_this, "Failed to initialize decoder: %s\n", error);
192         free(sys);
193         return VLC_EGENERIC;;
194     }
195
196     dec->pf_decode_video = Decode;
197
198     dec->fmt_out.i_cat = VIDEO_ES;
199     dec->fmt_out.video.i_width = dec->fmt_in.video.i_width;
200     dec->fmt_out.video.i_height = dec->fmt_in.video.i_height;
201     dec->fmt_out.i_codec = VLC_CODEC_I420;
202     dec->b_need_packetized = true;
203
204     return VLC_SUCCESS;
205 }
206
207 /*****************************************************************************
208  * Close: decoder destruction
209  *****************************************************************************/
210 static void Close(vlc_object_t *p_this)
211 {
212     decoder_t *dec = (decoder_t *)p_this;
213     decoder_sys_t *sys = dec->p_sys;
214
215     /* Free our PTS */
216     const void *iter = NULL;
217     for (;;) {
218         struct vpx_image *img = vpx_codec_get_frame(&sys->ctx, &iter);
219         if (!img)
220             break;
221         free(img->user_priv);
222     }
223
224     vpx_codec_destroy(&sys->ctx);
225
226     free(sys);
227 }