1 /*****************************************************************************
2 * vpx.c: libvpx decoder (VP8/VP9) module
3 *****************************************************************************
4 * Copyright (C) 2013 Rafaël Carré
6 * Authors: Rafaël Carré <funman@videolanorg>
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.
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.
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 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_codec.h>
34 #include <vpx/vpx_decoder.h>
35 #include <vpx/vp8dx.h>
38 # include <vpx/vpx_encoder.h>
39 # include <vpx/vp8cx.h>
42 /****************************************************************************
44 ****************************************************************************/
45 static const char *const ppsz_sout_options
[] = { "quality-mode", NULL
};
46 static int OpenDecoder(vlc_object_t
*);
47 static void CloseDecoder(vlc_object_t
*);
49 static int OpenEncoder(vlc_object_t
*);
50 static void CloseEncoder(vlc_object_t
*);
51 static block_t
*Encode(encoder_t
*p_enc
, picture_t
*p_pict
);
53 #define QUALITY_MODE_TEXT N_("Quality mode")
54 #define QUALITY_MODE_LONGTEXT N_("Quality setting which will determine max encoding time\n" \
55 " - 0: Good quality\n"\
60 /*****************************************************************************
62 *****************************************************************************/
66 set_description(N_("WebM video decoder"))
67 set_capability("decoder", 100)
68 set_callbacks(OpenDecoder
, CloseDecoder
)
69 set_category(CAT_INPUT
)
70 set_subcategory(SUBCAT_INPUT_VCODEC
)
74 set_capability("encoder", 60)
75 set_description(N_("WebM video encoder"))
76 set_callbacks(OpenEncoder
, CloseEncoder
)
77 # define ENC_CFG_PREFIX "sout-vpx-"
78 add_integer( ENC_CFG_PREFIX
"quality-mode", VPX_DL_GOOD_QUALITY
, QUALITY_MODE_TEXT
,
79 QUALITY_MODE_LONGTEXT
, true )
80 change_integer_range( 0, 2 )
84 static void vpx_err_msg(vlc_object_t
*this, struct vpx_codec_ctx
*ctx
,
87 const char *error
= vpx_codec_error(ctx
);
88 const char *detail
= vpx_codec_error_detail(ctx
);
90 detail
= "no specific information";
91 msg_Err(this, msg
, error
, detail
);
94 #define VPX_ERR(this, ctx, msg) vpx_err_msg(VLC_OBJECT(this), ctx, msg ": %s (%s)")
96 /*****************************************************************************
97 * decoder_sys_t: libvpx decoder descriptor
98 *****************************************************************************/
101 struct vpx_codec_ctx ctx
;
104 /****************************************************************************
105 * Decode: the whole thing
106 ****************************************************************************/
107 static picture_t
*Decode(decoder_t
*dec
, block_t
**pp_block
)
109 struct vpx_codec_ctx
*ctx
= &dec
->p_sys
->ctx
;
111 if( !pp_block
|| !*pp_block
)
113 block_t
*block
= *pp_block
;
115 if (block
->i_flags
& (BLOCK_FLAG_CORRUPTED
)) {
116 block_Release(block
);
120 /* Associate packet PTS with decoded frame */
121 mtime_t
*pkt_pts
= malloc(sizeof(*pkt_pts
));
123 block_Release(block
);
128 *pkt_pts
= block
->i_pts
;
131 err
= vpx_codec_decode(ctx
, block
->p_buffer
, block
->i_buffer
, pkt_pts
, 0);
133 block_Release(block
);
136 if (err
!= VPX_CODEC_OK
) {
138 VPX_ERR(dec
, ctx
, "Failed to decode frame");
142 const void *iter
= NULL
;
143 struct vpx_image
*img
= vpx_codec_get_frame(ctx
, &iter
);
149 /* fetches back the PTS */
150 pkt_pts
= img
->user_priv
;
151 mtime_t pts
= *pkt_pts
;
154 if (img
->fmt
!= VPX_IMG_FMT_I420
) {
155 msg_Err(dec
, "Unsupported output colorspace %d", img
->fmt
);
159 video_format_t
*v
= &dec
->fmt_out
.video
;
161 if (img
->d_w
!= v
->i_visible_width
|| img
->d_h
!= v
->i_visible_height
) {
162 v
->i_visible_width
= img
->d_w
;
163 v
->i_visible_height
= img
->d_h
;
166 if( !dec
->fmt_in
.video
.i_sar_num
|| !dec
->fmt_in
.video
.i_sar_den
)
168 if( !dec
->fmt_out
.video
.i_sar_num
|| !dec
->fmt_out
.video
.i_sar_den
)
170 dec
->fmt_out
.video
.i_sar_num
= 1;
171 dec
->fmt_out
.video
.i_sar_den
= 1;
175 picture_t
*pic
= decoder_NewPicture(dec
);
179 for (int plane
= 0; plane
< pic
->i_planes
; plane
++ ) {
180 uint8_t *src
= img
->planes
[plane
];
181 uint8_t *dst
= pic
->p
[plane
].p_pixels
;
182 int src_stride
= img
->stride
[plane
];
183 int dst_stride
= pic
->p
[plane
].i_pitch
;
185 int size
= __MIN( src_stride
, dst_stride
);
186 for( int line
= 0; line
< pic
->p
[plane
].i_visible_lines
; line
++ ) {
187 memcpy( dst
, src
, size
);
193 pic
->b_progressive
= true; /* codec does not support interlacing */
199 /*****************************************************************************
200 * OpenDecoder: probe the decoder
201 *****************************************************************************/
202 static int OpenDecoder(vlc_object_t
*p_this
)
204 decoder_t
*dec
= (decoder_t
*)p_this
;
205 const struct vpx_codec_iface
*iface
;
208 switch (dec
->fmt_in
.i_codec
)
210 #ifdef ENABLE_VP8_DECODER
212 iface
= &vpx_codec_vp8_dx_algo
;
216 #ifdef ENABLE_VP9_DECODER
218 iface
= &vpx_codec_vp9_dx_algo
;
226 decoder_sys_t
*sys
= malloc(sizeof(*sys
));
231 struct vpx_codec_dec_cfg deccfg
= {
232 .threads
= __MIN(vlc_GetCPUCount(), 16)
235 msg_Dbg(p_this
, "VP%d: using libvpx version %s (build options %s)",
236 vp_version
, vpx_codec_version_str(), vpx_codec_build_config());
238 if (vpx_codec_dec_init(&sys
->ctx
, iface
, &deccfg
, 0) != VPX_CODEC_OK
) {
239 VPX_ERR(p_this
, &sys
->ctx
, "Failed to initialize decoder");
241 return VLC_EGENERIC
;;
244 dec
->pf_decode_video
= Decode
;
246 dec
->fmt_out
.i_cat
= VIDEO_ES
;
247 dec
->fmt_out
.video
.i_width
= dec
->fmt_in
.video
.i_width
;
248 dec
->fmt_out
.video
.i_height
= dec
->fmt_in
.video
.i_height
;
249 dec
->fmt_out
.i_codec
= VLC_CODEC_I420
;
254 /*****************************************************************************
255 * CloseDecoder: decoder destruction
256 *****************************************************************************/
257 static void CloseDecoder(vlc_object_t
*p_this
)
259 decoder_t
*dec
= (decoder_t
*)p_this
;
260 decoder_sys_t
*sys
= dec
->p_sys
;
263 const void *iter
= NULL
;
265 struct vpx_image
*img
= vpx_codec_get_frame(&sys
->ctx
, &iter
);
268 free(img
->user_priv
);
271 vpx_codec_destroy(&sys
->ctx
);
278 /*****************************************************************************
279 * encoder_sys_t: libvpx encoder descriptor
280 *****************************************************************************/
283 struct vpx_codec_ctx ctx
;
286 /*****************************************************************************
287 * OpenEncoder: probe the encoder
288 *****************************************************************************/
289 static int OpenEncoder(vlc_object_t
*p_this
)
291 encoder_t
*p_enc
= (encoder_t
*)p_this
;
292 encoder_sys_t
*p_sys
;
294 /* Allocate the memory needed to store the encoder's structure */
295 p_sys
= malloc(sizeof(*p_sys
));
298 p_enc
->p_sys
= p_sys
;
300 const struct vpx_codec_iface
*iface
;
303 switch (p_enc
->fmt_out
.i_codec
)
305 #ifdef ENABLE_VP8_ENCODER
307 iface
= &vpx_codec_vp8_cx_algo
;
311 #ifdef ENABLE_VP9_ENCODER
313 iface
= &vpx_codec_vp9_cx_algo
;
322 struct vpx_codec_enc_cfg enccfg
= {};
323 vpx_codec_enc_config_default(iface
, &enccfg
, 0);
324 enccfg
.g_threads
= __MIN(vlc_GetCPUCount(), 4);
325 enccfg
.g_w
= p_enc
->fmt_in
.video
.i_visible_width
;
326 enccfg
.g_h
= p_enc
->fmt_in
.video
.i_visible_height
;
328 msg_Dbg(p_this
, "VP%d: using libvpx version %s (build options %s)",
329 vp_version
, vpx_codec_version_str(), vpx_codec_build_config());
331 struct vpx_codec_ctx
*ctx
= &p_sys
->ctx
;
332 if (vpx_codec_enc_init(ctx
, iface
, &enccfg
, 0) != VPX_CODEC_OK
) {
333 VPX_ERR(p_this
, ctx
, "Failed to initialize encoder");
338 p_enc
->pf_encode_video
= Encode
;
339 p_enc
->fmt_in
.i_codec
= VLC_CODEC_I420
;
340 config_ChainParse(p_enc
, ENC_CFG_PREFIX
, ppsz_sout_options
, p_enc
->p_cfg
);
345 /****************************************************************************
346 * Encode: the whole thing
347 ****************************************************************************/
348 static block_t
*Encode(encoder_t
*p_enc
, picture_t
*p_pict
)
350 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
351 struct vpx_codec_ctx
*ctx
= &p_sys
->ctx
;
353 if (!p_pict
) return NULL
;
355 vpx_image_t img
= {};
356 unsigned i_w
= p_enc
->fmt_in
.video
.i_visible_width
;
357 unsigned i_h
= p_enc
->fmt_in
.video
.i_visible_height
;
359 /* Create and initialize the vpx_image */
360 if (!vpx_img_alloc(&img
, VPX_IMG_FMT_I420
, i_w
, i_h
, 1)) {
361 VPX_ERR(p_enc
, ctx
, "Failed to allocate image");
364 for (int plane
= 0; plane
< p_pict
->i_planes
; plane
++) {
365 uint8_t *src
= p_pict
->p
[plane
].p_pixels
;
366 uint8_t *dst
= img
.planes
[plane
];
367 int src_stride
= p_pict
->p
[plane
].i_pitch
;
368 int dst_stride
= img
.stride
[plane
];
370 int size
= __MIN(src_stride
, dst_stride
);
371 for (int line
= 0; line
< p_pict
->p
[plane
].i_visible_lines
; line
++)
373 memcpy(dst
, src
, size
);
380 /* Deadline (in ms) to spend in encoder */
381 int quality
= VPX_DL_GOOD_QUALITY
;
382 switch (var_GetInteger(p_enc
, ENC_CFG_PREFIX
"quality-mode")) {
384 quality
= VPX_DL_REALTIME
;
387 quality
= VPX_DL_BEST_QUALITY
;
393 vpx_codec_err_t res
= vpx_codec_encode(ctx
, &img
, p_pict
->date
, 1,
395 if (res
!= VPX_CODEC_OK
) {
396 VPX_ERR(p_enc
, ctx
, "Failed to encode frame");
400 const vpx_codec_cx_pkt_t
*pkt
= NULL
;
401 vpx_codec_iter_t iter
= NULL
;
402 block_t
*p_out
= NULL
;
403 while ((pkt
= vpx_codec_get_cx_data(ctx
, &iter
)) != NULL
)
405 if (pkt
->kind
== VPX_CODEC_CX_FRAME_PKT
)
407 int keyframe
= pkt
->data
.frame
.flags
& VPX_FRAME_IS_KEY
;
408 block_t
*p_block
= block_Alloc(pkt
->data
.frame
.sz
);
410 memcpy(p_block
->p_buffer
, pkt
->data
.frame
.buf
, pkt
->data
.frame
.sz
);
411 p_block
->i_dts
= p_block
->i_pts
= pkt
->data
.frame
.pts
;
413 p_block
->i_flags
|= BLOCK_FLAG_TYPE_I
;
414 block_ChainAppend(&p_out
, p_block
);
421 /*****************************************************************************
422 * CloseEncoder: encoder destruction
423 *****************************************************************************/
424 static void CloseEncoder(vlc_object_t
*p_this
)
426 encoder_t
*p_enc
= (encoder_t
*)p_this
;
427 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
428 if (vpx_codec_destroy(&p_sys
->ctx
))
429 VPX_ERR(p_this
, &p_sys
->ctx
, "Failed to destroy codec");
433 #endif /* ENABLE_SOUT */