vlc | branch: master | Tristan Matthews <[email protected]> | Sun Sep 21 05:35:06 2014 -0400| [e0a1923749a05cee886daba51902cd1f757608ba] | committer: Tristan Matthews
daala: add encoder > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e0a1923749a05cee886daba51902cd1f757608ba --- configure.ac | 2 +- modules/codec/daala.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2b2a815..eff4995 100644 --- a/configure.ac +++ b/configure.ac @@ -2745,7 +2745,7 @@ PKG_ENABLE_MODULES_VLC([THEORA], [], [ogg theoradec >= 1.0 theoraenc], [experime dnl dnl Daala decoder plugin dnl -PKG_ENABLE_MODULES_VLC([DAALA], [], [ogg daaladec], [experimental daala codec], [disabled]) +PKG_ENABLE_MODULES_VLC([DAALA], [], [ogg daaladec daalaenc], [experimental daala codec], [disabled]) dnl dnl schroedinger decoder plugin (for dirac format video) diff --git a/modules/codec/daala.c b/modules/codec/daala.c index 6a7851d..9d66d7a 100644 --- a/modules/codec/daala.c +++ b/modules/codec/daala.c @@ -38,6 +38,9 @@ #include <daala/codec.h> #include <daala/daaladec.h> +#ifdef ENABLE_SOUT +#include <daala/daalaenc.h> +#endif #include <limits.h> @@ -88,6 +91,22 @@ static picture_t *DecodePacket( decoder_t *, ogg_packet * ); static void ParseDaalaComments( decoder_t * ); static void daala_CopyPicture( picture_t *, od_img * ); +#ifdef ENABLE_SOUT +static int OpenEncoder( vlc_object_t *p_this ); +static void CloseEncoder( vlc_object_t *p_this ); +static block_t *Encode( encoder_t *p_enc, picture_t *p_pict ); +#endif + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define ENC_QUALITY_TEXT N_("Encoding quality") +#define ENC_QUALITY_LONGTEXT N_( \ + "Enforce a quality between 0 (lossless) and 511 (worst)." ) +#define ENC_KEYINT_TEXT N_("Keyframe interval") +#define ENC_KEYINT_LONGTEXT N_( \ + "Enforce a keyframe interval between 1 and 1000." ) + vlc_module_begin () set_category( CAT_INPUT ) set_subcategory( SUBCAT_INPUT_VCODEC ) @@ -102,8 +121,25 @@ vlc_module_begin () set_callbacks( OpenPacketizer, CloseDecoder ) add_shortcut( "daala" ) +#ifdef ENABLE_SOUT + add_submodule () + set_description( N_("Daala video encoder") ) + set_capability( "encoder", 150 ) + set_callbacks( OpenEncoder, CloseEncoder ) + add_shortcut( "daala" ) + +# define ENC_CFG_PREFIX "sout-daala-" + add_integer_with_range( ENC_CFG_PREFIX "quality", 30, 0, 511, + ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, false ) + add_integer_with_range( ENC_CFG_PREFIX "keyint", 256, 1, 1000, + ENC_KEYINT_TEXT, ENC_KEYINT_LONGTEXT, false ) +#endif vlc_module_end () +static const char *const ppsz_enc_options[] = { + "quality", "keyint", NULL +}; + /***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ @@ -506,3 +542,181 @@ static void daala_CopyPicture( picture_t *p_pic, } } } + +#ifdef ENABLE_SOUT +struct encoder_sys_t +{ + daala_info di; /* daala bitstream settings */ + daala_comment dc; /* daala comment header */ + daala_enc_ctx *dcx; /* daala context */ +}; + +static int OpenEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys; + ogg_packet header; + int status; + + if( p_enc->fmt_out.i_codec != VLC_CODEC_DAALA && + !p_enc->b_force ) + { + return VLC_EGENERIC; + } + + /* Allocate the memory needed to store the encoder's structure */ + p_sys = malloc( sizeof( encoder_sys_t ) ); + if( !p_sys ) + return VLC_ENOMEM; + p_enc->p_sys = p_sys; + + p_enc->pf_encode_video = Encode; + p_enc->fmt_in.i_codec = VLC_CODEC_I420; + p_enc->fmt_out.i_codec = VLC_CODEC_DAALA; + + config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); + + daala_info_init( &p_sys->di ); + + p_sys->di.pic_width = p_enc->fmt_in.video.i_visible_width; + p_sys->di.pic_height = p_enc->fmt_in.video.i_visible_height; + + /* 420 */ + p_sys->di.nplanes = 3; + for (int i = 0; i < p_sys->di.nplanes; i++) + { + p_sys->di.plane_info[i].ydec = + p_sys->di.plane_info[i].xdec = i > 0; + } + p_sys->di.frame_duration = 1; + + if( !p_enc->fmt_in.video.i_frame_rate || + !p_enc->fmt_in.video.i_frame_rate_base ) + { + p_sys->di.timebase_numerator = 25; + p_sys->di.timebase_denominator = 1; + } + else + { + p_sys->di.timebase_numerator = p_enc->fmt_in.video.i_frame_rate; + p_sys->di.timebase_denominator = p_enc->fmt_in.video.i_frame_rate_base; + } + + if( p_enc->fmt_in.video.i_sar_num > 0 && p_enc->fmt_in.video.i_sar_den > 0 ) + { + unsigned i_dst_num, i_dst_den; + vlc_ureduce( &i_dst_num, &i_dst_den, + p_enc->fmt_in.video.i_sar_num, + p_enc->fmt_in.video.i_sar_den, 0 ); + p_sys->di.pixel_aspect_numerator = i_dst_num; + p_sys->di.pixel_aspect_denominator = i_dst_den; + } + else + { + p_sys->di.pixel_aspect_numerator = 4; + p_sys->di.pixel_aspect_denominator = 3; + } + + p_sys->di.keyframe_rate = var_GetInteger( p_enc, ENC_CFG_PREFIX "keyint" ); + + daala_enc_ctx *dcx; + p_sys->dcx = dcx = daala_encode_create( &p_sys->di ); + if( !dcx ) + { + free( p_sys ); + return VLC_ENOMEM; + } + + daala_comment_init( &p_sys->dc ); + + int i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" ); + daala_encode_ctl( dcx, OD_SET_QUANT, &i_quality, sizeof(i_quality) ); + + /* Create and store headers */ + while( ( status = daala_encode_flush_header( dcx, &p_sys->dc, &header ) ) ) + { + if ( status < 0 ) + { + CloseEncoder( p_this ); + return VLC_EGENERIC; + } + if( xiph_AppendHeaders( &p_enc->fmt_out.i_extra, + &p_enc->fmt_out.p_extra, header.bytes, + header.packet ) ) + { + p_enc->fmt_out.i_extra = 0; + p_enc->fmt_out.p_extra = NULL; + } + } + return VLC_SUCCESS; +} + +static block_t *Encode( encoder_t *p_enc, picture_t *p_pict ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + ogg_packet oggpacket; + block_t *p_block; + od_img img; + + if( !p_pict ) return NULL; + + const int i_width = p_sys->di.pic_width; + const int i_height = p_sys->di.pic_height; + + /* Sanity check */ + if( p_pict->p[0].i_pitch < i_width || + p_pict->p[0].i_lines < i_height ) + { + msg_Err( p_enc, "frame is smaller than encoding size" + "(%ix%i->%ix%i) -> dropping frame", + p_pict->p[0].i_pitch, p_pict->p[0].i_lines, + i_width, i_height ); + return NULL; + } + + /* Daala is a one-frame-in, one-frame-out system. Submit a frame + * for compression and pull out the packet. */ + + img.nplanes = p_sys->di.nplanes; + img.width = i_width; + img.height = i_height; + for( int i = 0; i < img.nplanes; i++ ) + { + img.planes[i].data = p_pict->p[i].p_pixels; + img.planes[i].xdec = p_sys->di.plane_info[i].xdec; + img.planes[i].ydec = p_sys->di.plane_info[i].ydec; + img.planes[i].xstride = 1; + img.planes[i].ystride = (img.width + + (1 << img.planes[i].xdec) - 1) >> img.planes[i].xdec; + } + + if( daala_encode_img_in( p_sys->dcx, &img, 0 ) < 0 ) + { + msg_Warn( p_enc, "failed encoding a frame" ); + return NULL; + } + + daala_encode_packet_out( p_sys->dcx, 0, &oggpacket ); + + /* Ogg packet to block */ + p_block = block_Alloc( oggpacket.bytes ); + memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes ); + p_block->i_dts = p_block->i_pts = p_pict->date; + + if( daala_packet_iskeyframe( oggpacket.packet, oggpacket.bytes ) ) + p_block->i_flags |= BLOCK_FLAG_TYPE_I; + + return p_block; +} + +static void CloseEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys = p_enc->p_sys; + + daala_info_clear(&p_sys->di); + daala_comment_clear(&p_sys->dc); + daala_encode_free(p_sys->dcx); + free( p_sys ); +} +#endif _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
