]> git.sesse.net Git - vlc/blob - modules/codec/vpx.c
vpx: fix leak
[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         free(pkt_pts);
108         return NULL;
109     }
110
111     /* fetches back the PTS */
112     pkt_pts = img->user_priv;
113     mtime_t pts = *pkt_pts;
114     free(pkt_pts);
115
116     if (img->fmt != VPX_IMG_FMT_I420) {
117         msg_Err(dec, "Unsupported output colorspace %d", img->fmt);
118         return NULL;
119     }
120
121     video_format_t *v = &dec->fmt_out.video;
122
123     if (img->d_w != v->i_visible_width || img->d_h != v->i_visible_height) {
124         v->i_visible_width = img->d_w;
125         v->i_visible_height = img->d_h;
126     }
127
128     picture_t *pic = decoder_NewPicture(dec);
129     if (!pic)
130         return NULL;
131
132     for (int plane = 0; plane < pic->i_planes; plane++ ) {
133         uint8_t *src = img->planes[plane];
134         uint8_t *dst = pic->p[plane].p_pixels;
135         int src_stride = img->stride[plane];
136         int dst_stride = pic->p[plane].i_pitch;
137
138         int size = __MIN( src_stride, dst_stride );
139         for( int line = 0; line < pic->p[plane].i_visible_lines; line++ ) {
140             memcpy( dst, src, size );
141             src += src_stride;
142             dst += dst_stride;
143         }
144     }
145
146     pic->b_progressive = true; /* codec does not support interlacing */
147     pic->date = pts;
148
149     return pic;
150 }
151
152 /*****************************************************************************
153  * Open: probe the decoder
154  *****************************************************************************/
155 static int Open(vlc_object_t *p_this)
156 {
157     decoder_t *dec = (decoder_t *)p_this;
158     const struct vpx_codec_iface *iface;
159     int vp_version;
160
161     switch (dec->fmt_in.i_codec)
162     {
163 #ifdef ENABLE_VP8_DECODER
164     case VLC_CODEC_VP8:
165         iface = &vpx_codec_vp8_dx_algo;
166         vp_version = 8;
167         break;
168 #endif
169 #ifdef ENABLE_VP9_DECODER
170     case VLC_CODEC_VP9:
171         iface = &vpx_codec_vp9_dx_algo;
172         vp_version = 9;
173         break;
174 #endif
175     default:
176         return VLC_EGENERIC;
177     }
178
179     decoder_sys_t *sys = malloc(sizeof(*sys));
180     if (!sys)
181         return VLC_ENOMEM;
182     dec->p_sys = sys;
183
184     struct vpx_codec_dec_cfg deccfg = {
185         .threads = __MIN(vlc_GetCPUCount(), 16)
186     };
187
188     msg_Dbg(p_this, "VP%d: using libvpx version %s (build options %s)", 
189         vp_version, vpx_codec_version_str(), vpx_codec_build_config());
190
191     if (vpx_codec_dec_init(&sys->ctx, iface, &deccfg, 0) != VPX_CODEC_OK) {
192         const char *error = vpx_codec_error(&sys->ctx);
193         msg_Err(p_this, "Failed to initialize decoder: %s\n", error);
194         free(sys);
195         return VLC_EGENERIC;;
196     }
197
198     dec->pf_decode_video = Decode;
199
200     dec->fmt_out.i_cat = VIDEO_ES;
201     dec->fmt_out.video.i_width = dec->fmt_in.video.i_width;
202     dec->fmt_out.video.i_height = dec->fmt_in.video.i_height;
203     dec->fmt_out.i_codec = VLC_CODEC_I420;
204     dec->b_need_packetized = true;
205
206     return VLC_SUCCESS;
207 }
208
209 /*****************************************************************************
210  * Close: decoder destruction
211  *****************************************************************************/
212 static void Close(vlc_object_t *p_this)
213 {
214     decoder_t *dec = (decoder_t *)p_this;
215     decoder_sys_t *sys = dec->p_sys;
216
217     /* Free our PTS */
218     const void *iter = NULL;
219     for (;;) {
220         struct vpx_image *img = vpx_codec_get_frame(&sys->ctx, &iter);
221         if (!img)
222             break;
223         free(img->user_priv);
224     }
225
226     vpx_codec_destroy(&sys->ctx);
227
228     free(sys);
229 }