From: Anuradha Suraparaju Date: Fri, 19 Aug 2011 01:29:48 +0000 (+1000) Subject: Add Dirac encoding support using the Schroedinger library X-Git-Tag: 1.2.0-pre1~1145 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=8d9ba243b86401365f83d196123ff440ebc6a664;p=vlc Add Dirac encoding support using the Schroedinger library Modified-by and Signed-off-by: Jean-Baptiste Kempf --- diff --git a/NEWS b/NEWS index a9532b5b2f..29d38c5012 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,8 @@ Codecs: * Support for 9bits and 10bits H.264/AVC decoding * Support for Lagarith Lossless video codec * Support for 20-bits PCM and DAT-12 (digital magnetic tapes) from RTP + * New module for Dirac encoding, using the faster libschroedinger + The Schroedinger module should be prefered to the Dirac one Demuxers: * New images demuxer supporting jpeg, png, targa, xcf, git, tiff, bmp, pcx, lbm diff --git a/configure.ac b/configure.ac index 693c386604..fd9fc91401 100644 --- a/configure.ac +++ b/configure.ac @@ -2879,7 +2879,7 @@ PKG_ENABLE_MODULES_VLC([DIRAC], [], [dirac >= 0.10.0], [dirac encoder], [auto]) dnl dnl schroedinger decoder plugin (for dirac format video) dnl -PKG_ENABLE_MODULES_VLC([SCHROEDINGER], [], [schroedinger-1.0 >= 1.0.6], [dirac decoder using schroedinger], [auto]) +PKG_ENABLE_MODULES_VLC([SCHROEDINGER], [], [schroedinger-1.0 >= 1.0.10], [dirac decoder and encoder using schroedinger], [auto]) dnl dnl PNG decoder module diff --git a/modules/codec/schroedinger.c b/modules/codec/schroedinger.c index c84d09bd23..bc1e1c259d 100644 --- a/modules/codec/schroedinger.c +++ b/modules/codec/schroedinger.c @@ -3,10 +3,11 @@ * (http://www.bbc.co.uk/rd/projects/dirac/index.shtml) * (http://diracvideo.org) ***************************************************************************** - * Copyright (C) 2008-2010 the VideoLAN team + * Copyright (C) 2008-2011 the VideoLAN team * * Authors: Jonathan Rosser * David Flynn + * Anuradha Suraparaju * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +27,16 @@ /***************************************************************************** * Preamble *****************************************************************************/ + #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include + #include #include -#include -#include +#include /* decoder_DeletePicture */ #include @@ -42,6 +45,316 @@ *****************************************************************************/ static int OpenDecoder ( vlc_object_t * ); static void CloseDecoder ( vlc_object_t * ); +static int OpenEncoder ( vlc_object_t * ); +static void CloseEncoder ( vlc_object_t * ); + +#define ENC_CFG_PREFIX "sout-schro-" + +#define ENC_CHROMAFMT "chroma-fmt" +#define ENC_CHROMAFMT_TEXT N_("Chroma format") +#define ENC_CHROMAFMT_LONGTEXT N_("Picking chroma format will force a " \ + "conversion of the video into that format") +static const char *const enc_chromafmt_list[] = + { "420", "422", "444" }; +static const char *const enc_chromafmt_list_text[] = + { N_("4:2:0"), N_("4:2:2"), N_("4:4:4") }; + +#define ENC_RATE_CONTROL "rate-control" +#define ENC_RATE_CONTROL_TEXT N_("Rate control method") +#define ENC_RATE_CONTROL_LONGTEXT N_("Method used to encode the video sequence") + +static const char *enc_rate_control_list[] = { + "constant_noise_threshold", + "constant_bitrate", + "low_delay", + "lossless", + "constant_lambda", + "constant_error", + "constant_quality" +}; + +static const char *enc_rate_control_list_text[] = { + N_("Constant noise threshold mode"), + N_("Constant bitrate mode (CBR)"), + N_("Low Delay mode"), + N_("Lossless mode"), + N_("Constant lambda mode"), + N_("Constant error mode"), + N_("Constant quality mode") +}; + +#define ENC_GOP_STRUCTURE "gop-structure" +#define ENC_GOP_STRUCTURE_TEXT N_("GOP structure") +#define ENC_GOP_STRUCTURE_LONGTEXT N_("GOP structure used to encode the video sequence") + +static const char *enc_gop_structure_list[] = { + "adaptive", + "intra_only", + "backref", + "chained_backref", + "biref", + "chained_biref" +}; + +static const char *enc_gop_structure_list_text[] = { + N_("No fixed gop structure. A picture can be intra or inter and refer to previous or future pictures."), + N_("I-frame only sequence"), + N_("Inter pictures refere to previous pictures only"), + N_("Inter pictures refere to previous pictures only"), + N_("Inter pictures can refer to previous or future pictures"), + N_("Inter pictures can refer to previous or future pictures") +}; + +#define ENC_QUALITY "quality" +#define ENC_QUALITY_TEXT N_("Constant quality factor") +#define ENC_QUALITY_LONGTEXT N_("Quality factor to use in constant quality mode") + +#define ENC_NOISE_THRESHOLD "noise-threshold" +#define ENC_NOISE_THRESHOLD_TEXT N_("Noise Threshold") +#define ENC_NOISE_THRESHOLD_LONGTEXT N_("Noise threshold to use in constant noise threshold mode") + +#define ENC_BITRATE "bitrate" +#define ENC_BITRATE_TEXT N_("CBR bitrate (kbps)") +#define ENC_BITRATE_LONGTEXT N_("Target bitrate in kbps when encoding in constant bitrate mode") + +#define ENC_MAX_BITRATE "max-bitrate" +#define ENC_MAX_BITRATE_TEXT N_("Maximum bitrate (kbps)") +#define ENC_MAX_BITRATE_LONGTEXT N_("Maximum bitrate in kbps when encoding in constant bitrate mode") + +#define ENC_MIN_BITRATE "min-bitrate" +#define ENC_MIN_BITRATE_TEXT N_("Minimum bitrate (kbps)") +#define ENC_MIN_BITRATE_LONGTEXT N_("Minimum bitrate in kbps when encoding in constant bitrate mode") + +#define ENC_AU_DISTANCE "gop-length" +#define ENC_AU_DISTANCE_TEXT N_("GOP length") +#define ENC_AU_DISTANCE_LONGTEXT N_("Number of pictures between successive sequenence headers i.e. length of the group of pictures") + + +#define ENC_PREFILTER "filtering" +#define ENC_PREFILTER_TEXT N_("Prefilter") +#define ENC_PREFILTER_LONGTEXT N_("Enable adaptive prefiltering") + +static const char *enc_filtering_list[] = { + "none", + "center_weighted_median", + "gaussian", + "add_noise", + "adaptive_gaussian", + "lowpass" +}; + +static const char *enc_filtering_list_text[] = { + N_("No pre-filtering"), + N_("Centre Weighted Median"), + N_("Gaussian Low Pass Filter"), + N_("Add Noise"), + N_("Gaussian Adaptive Low Pass Filter"), + N_("Low Pass Ffilter"), +}; + +#define ENC_PREFILTER_STRENGTH "filter-value" +#define ENC_PREFILTER_STRENGTH_TEXT N_("Amount of prefiltering") +#define ENC_PREFILTER_STRENGTH_LONGTEXT N_("Higher value implies more prefiltering") + +#define ENC_CODINGMODE "coding-mode" +#define ENC_CODINGMODE_TEXT N_("Picture coding mode") +#define ENC_CODINGMODE_LONGTEXT N_("Field coding is where interlaced fields are coded" \ + " separately as opposed to a pseudo-progressive frame") +static const char *const enc_codingmode_list[] = + { "auto", "progressive", "field" }; +static const char *const enc_codingmode_list_text[] = + { N_("auto - let encoder decide based upon input (Best)"), + N_("force coding frame as single picture"), + N_("force coding frame as separate interlaced fields"), + }; + +/* advanced option only */ +#define ENC_MCBLK_SIZE "motion-block-size" +#define ENC_MCBLK_SIZE_TEXT N_("Size of motion compensation blocks") + +static const char *enc_block_size_list[] = { + "automatic", + "small", + "medium", + "large" +}; +static const char *const enc_block_size_list_text[] = + { N_("automatic - let encoder decide based upon input (Best)"), + N_("small - use small motion compensation blocks"), + N_("medium - use medium motion compensation blocks"), + N_("large - use large motion compensation blocks"), + }; + +/* advanced option only */ +#define ENC_MCBLK_OVERLAP "motion-block-overlap" +#define ENC_MCBLK_OVERLAP_TEXT N_("Overlap of motion compensation blocks") + +static const char *enc_block_overlap_list[] = { + "automatic", + "none", + "partial", + "full" +}; +static const char *const enc_block_overlap_list_text[] = + { N_("automatic - let encoder decide based upon input (Best)"), + N_("none - Motion compensation blocks do not overlap"), + N_("partial - Motion compensation blocks only partially overlap"), + N_("full - Motion compensation blocks fully overlap"), + }; + + +#define ENC_MVPREC "mv-precision" +#define ENC_MVPREC_TEXT N_("Motion Vector precision") +#define ENC_MVPREC_LONGTEXT N_("Motion Vector precision in pels") +static const char *const enc_mvprec_list[] = + { "1", "1/2", "1/4", "1/8" }; + +/* advanced option only */ +#define ENC_ME_COMBINED "me-combined" +#define ENC_ME_COMBINED_TEXT N_("Three component motion estimation") +#define ENC_ME_COMBINED_LONGTEXT N_("Use chroma as part of the motion estimation process") + +#define ENC_DWTINTRA "intra-wavelet" +#define ENC_DWTINTRA_TEXT N_("Intra picture DWT filter") + +#define ENC_DWTINTER "inter-wavelet" +#define ENC_DWTINTER_TEXT N_("Inter picture DWT filter") + +static const char *enc_wavelet_list[] = { + "desl_dubuc_9_7", + "le_gall_5_3", + "desl_dubuc_13_7", + "haar_0", + "haar_1", + "fidelity", + "daub_9_7" +}; + +static const char *enc_wavelet_list_text[] = { + "Deslauriers-Dubuc (9,7)", + "LeGall (5,3)", + "Deslauriers-Dubuc (13,7)", + "Haar with no shift", + "Haar with single shift per level", + "Fidelity filter", + "Daubechies (9,7) integer approximation" +}; + +#define ENC_DWTDEPTH "transform-depth" +#define ENC_DWTDEPTH_TEXT N_("Number of DWT iterations") +#define ENC_DWTDEPTH_LONGTEXT N_("Also known as DWT levels") + + +/* advanced option only */ +#define ENC_MULTIQUANT "enable-multiquant" +#define ENC_MULTIQUANT_TEXT N_("Enable multiple quantizers") +#define ENC_MULTIQUANT_LONGTEXT N_("Enable multiple quantizers per subband (one per codeblock)") + +/* advanced option only */ +#define ENC_NOAC "enable-noarith" +#define ENC_NOAC_TEXT N_("Disable arithmetic coding") +#define ENC_NOAC_LONGTEXT N_("Use variable length codes instead, useful for very high bitrates") + +/* visual modelling */ +/* advanced option only */ +#define ENC_PWT "perceptual-weighting" +#define ENC_PWT_TEXT N_("perceptual weighting method") + +static const char *enc_perceptual_weighting_list[] = { + "none", + "ccir959", + "moo", + "manos_sakrison" +}; + +/* advanced option only */ +#define ENC_PDIST "perceptual-distance" +#define ENC_PDIST_TEXT N_("perceptual distance") +#define ENC_PDIST_LONGTEXT N_("perceptual distance to calculate perceptual weight") + +/* advanced option only */ +#define ENC_HSLICES "horiz-slices" +#define ENC_HSLICES_TEXT N_("Horizontal slices per frame") +#define ENC_HSLICES_LONGTEXT N_("Number of horizontal slices per frame in low delay mode") + +/* advanced option only */ +#define ENC_VSLICES "vert-slices" +#define ENC_VSLICES_TEXT N_("Vertical slices per frame") +#define ENC_VSLICES_LONGTEXT N_("Number of vertical slices per frame in low delay mode") + +/* advanced option only */ +#define ENC_SCBLK_SIZE "codeblock-size" +#define ENC_SCBLK_SIZE_TEXT N_("Size of code blocks in each subband") + +static const char *enc_codeblock_size_list[] = { + "automatic", + "small", + "medium", + "large", + "full" +}; +static const char *const enc_codeblock_size_list_text[] = + { N_("automatic - let encoder decide based upon input (Best)"), + N_("small - use small code blocks"), + N_("medium - use medium sized code blocks"), + N_("large - use large code blocks"), + N_("full - One code block per subband"), + }; + +/* advanced option only */ +#define ENC_ME_HIERARCHICAL "enable-hierarchical-me" +#define ENC_ME_HIERARCHICAL_TEXT N_("Enable hierarchical Motion Estimation") + +/* advanced option only */ +#define ENC_ME_DOWNSAMPLE_LEVELS "downsample-levels" +#define ENC_ME_DOWNSAMPLE_LEVELS_TEXT N_("Number of levels of downsampling") +#define ENC_ME_DOWNSAMPLE_LEVELS_LONGTEXT N_("Number of levels of downsampling in hierarchical motion estimation mode") + +/* advanced option only */ +#define ENC_ME_GLOBAL_MOTION "enable-global-me" +#define ENC_ME_GLOBAL_MOTION_TEXT N_("Enable Global Motion Estimation") + +/* advanced option only */ +#define ENC_ME_PHASECORR "enable-phasecorr-me" +#define ENC_ME_PHASECORR_TEXT N_("Enable Phase Correlation Estimation") + +/* advanced option only */ +#define ENC_SCD "enable-scd" +#define ENC_SCD_TEXT N_("Enable Scene Change Detection") + +/* advanced option only */ +#define ENC_FORCE_PROFILE "force-profile" +#define ENC_FORCE_PROFILE_TEXT N_("Force Profile") + +static const char *enc_profile_list[] = { + "auto", + "vc2_low_delay", + "vc2_simple", + "vc2_main", + "main" +}; + +static const char *const enc_profile_list_text[] = + { N_("automatic - let encoder decide based upon input (Best)"), + N_("VC2 Low Delay Profile"), + N_("VC2 Simple Profile"), + N_("VC2 Main Profile"), + N_("Main Profile"), + }; + +static const char *const const ppsz_enc_options[] = { + ENC_RATE_CONTROL, ENC_GOP_STRUCTURE, ENC_QUALITY, ENC_NOISE_THRESHOLD, ENC_BITRATE, + ENC_MIN_BITRATE, ENC_MAX_BITRATE, ENC_AU_DISTANCE, ENC_CHROMAFMT, + ENC_PREFILTER, ENC_PREFILTER_STRENGTH, ENC_CODINGMODE, ENC_MCBLK_SIZE, + ENC_MCBLK_OVERLAP, ENC_MVPREC, ENC_ME_COMBINED, ENC_DWTINTRA, ENC_DWTINTER, + ENC_DWTDEPTH, ENC_MULTIQUANT, ENC_NOAC, ENC_PWT, ENC_PDIST, ENC_HSLICES, + ENC_VSLICES, ENC_SCBLK_SIZE, ENC_ME_HIERARCHICAL, ENC_ME_DOWNSAMPLE_LEVELS, + ENC_ME_GLOBAL_MOTION, ENC_ME_PHASECORR, ENC_SCD, ENC_FORCE_PROFILE, + NULL +}; + + +/* Module declaration */ vlc_module_begin () set_category( CAT_INPUT ) @@ -51,8 +364,163 @@ vlc_module_begin () set_capability( "decoder", 200 ) set_callbacks( OpenDecoder, CloseDecoder ) add_shortcut( "schroedinger" ) + + /* encoder */ + add_submodule() + set_section( N_("Encoding") , NULL ) + set_description( N_("Dirac video encoder using libschroedinger") ) + set_capability( "encoder", 110 ) + set_callbacks( OpenEncoder, CloseEncoder ) + add_shortcut( "schroedinger", "schro" ) + + add_string( ENC_CFG_PREFIX ENC_RATE_CONTROL, NULL, + ENC_RATE_CONTROL_TEXT, ENC_RATE_CONTROL_LONGTEXT, false ) + change_string_list( enc_rate_control_list, enc_rate_control_list_text, 0 ); + + add_float( ENC_CFG_PREFIX ENC_QUALITY, -1., + ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, false ) + change_float_range(-1., 10.); + + add_float( ENC_CFG_PREFIX ENC_NOISE_THRESHOLD, -1., + ENC_NOISE_THRESHOLD_TEXT, ENC_NOISE_THRESHOLD_LONGTEXT, false ) + change_float_range(-1., 100.); + + add_integer( ENC_CFG_PREFIX ENC_BITRATE, -1, + ENC_BITRATE_TEXT, ENC_BITRATE_LONGTEXT, false ) + change_integer_range(-1, INT_MAX); + + add_integer( ENC_CFG_PREFIX ENC_MAX_BITRATE, -1, + ENC_MAX_BITRATE_TEXT, ENC_MAX_BITRATE_LONGTEXT, false ) + change_integer_range(-1, INT_MAX); + + add_integer( ENC_CFG_PREFIX ENC_MIN_BITRATE, -1, + ENC_MIN_BITRATE_TEXT, ENC_MIN_BITRATE_LONGTEXT, false ) + change_integer_range(-1, INT_MAX); + + add_string( ENC_CFG_PREFIX ENC_GOP_STRUCTURE, NULL, + ENC_GOP_STRUCTURE_TEXT, ENC_GOP_STRUCTURE_LONGTEXT, false ) + change_string_list( enc_gop_structure_list, enc_gop_structure_list_text, 0 ); + + add_integer( ENC_CFG_PREFIX ENC_AU_DISTANCE, -1, + ENC_AU_DISTANCE_TEXT, ENC_AU_DISTANCE_LONGTEXT, false ) + change_integer_range(-1, INT_MAX); + + add_string( ENC_CFG_PREFIX ENC_CHROMAFMT, "420", + ENC_CHROMAFMT_TEXT, ENC_CHROMAFMT_LONGTEXT, false ) + change_string_list( enc_chromafmt_list, enc_chromafmt_list_text, 0 ); + + add_string( ENC_CFG_PREFIX ENC_CODINGMODE, "auto", + ENC_CODINGMODE_TEXT, ENC_CODINGMODE_LONGTEXT, false ) + change_string_list( enc_codingmode_list, enc_codingmode_list_text, 0 ); + + add_string( ENC_CFG_PREFIX ENC_MVPREC, NULL, + ENC_MVPREC_TEXT, ENC_MVPREC_LONGTEXT, false ) + change_string_list( enc_mvprec_list, enc_mvprec_list, 0 ); + + /* advanced option only */ + add_string( ENC_CFG_PREFIX ENC_MCBLK_SIZE, NULL, + ENC_MCBLK_SIZE_TEXT, ENC_MCBLK_SIZE_TEXT, true ) + change_string_list( enc_block_size_list, enc_block_size_list_text, 0 ); + + + /* advanced option only */ + add_string( ENC_CFG_PREFIX ENC_MCBLK_OVERLAP, NULL, + ENC_MCBLK_OVERLAP_TEXT, ENC_MCBLK_OVERLAP_TEXT, true ) + change_string_list( enc_block_overlap_list, enc_block_overlap_list_text, 0 ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_ME_COMBINED, -1, + ENC_ME_COMBINED_TEXT, ENC_ME_COMBINED_LONGTEXT, true ) + change_integer_range(-1, 1 ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_ME_HIERARCHICAL, -1, + ENC_ME_HIERARCHICAL_TEXT, ENC_ME_HIERARCHICAL_TEXT, true ) + change_integer_range(-1, 1 ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_ME_DOWNSAMPLE_LEVELS, -1, + ENC_ME_DOWNSAMPLE_LEVELS_TEXT, ENC_ME_DOWNSAMPLE_LEVELS_LONGTEXT, true ) + change_integer_range(-1, 8 ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_ME_GLOBAL_MOTION, -1, + ENC_ME_GLOBAL_MOTION_TEXT, ENC_ME_GLOBAL_MOTION_TEXT, true ) + change_integer_range(-1, 1 ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_ME_PHASECORR, -1, + ENC_ME_PHASECORR_TEXT, ENC_ME_PHASECORR_TEXT, true ) + change_integer_range(-1, 1 ); + + add_string( ENC_CFG_PREFIX ENC_DWTINTRA, NULL, + ENC_DWTINTRA_TEXT, ENC_DWTINTRA_TEXT, false ) + change_string_list( enc_wavelet_list, enc_wavelet_list_text, 0 ); + + add_string( ENC_CFG_PREFIX ENC_DWTINTER, NULL, + ENC_DWTINTER_TEXT, ENC_DWTINTER_TEXT, false ) + change_string_list( enc_wavelet_list, enc_wavelet_list_text, 0 ); + + add_integer( ENC_CFG_PREFIX ENC_DWTDEPTH, -1, + ENC_DWTDEPTH_TEXT, ENC_DWTDEPTH_LONGTEXT, false ) + change_integer_range(-1, SCHRO_LIMIT_ENCODER_TRANSFORM_DEPTH ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_MULTIQUANT, -1, + ENC_MULTIQUANT_TEXT, ENC_MULTIQUANT_LONGTEXT, true ) + change_integer_range(-1, 1 ); + + /* advanced option only */ + add_string( ENC_CFG_PREFIX ENC_SCBLK_SIZE, NULL, + ENC_SCBLK_SIZE_TEXT, ENC_SCBLK_SIZE_TEXT, true ) + change_string_list( enc_codeblock_size_list, enc_codeblock_size_list_text, 0 ); + + add_string( ENC_CFG_PREFIX ENC_PREFILTER, NULL, + ENC_PREFILTER_TEXT, ENC_PREFILTER_LONGTEXT, false ) + change_string_list( enc_filtering_list, enc_filtering_list_text, 0 ); + + add_float( ENC_CFG_PREFIX ENC_PREFILTER_STRENGTH, -1., + ENC_PREFILTER_STRENGTH_TEXT, ENC_PREFILTER_STRENGTH_LONGTEXT, false ) + change_float_range(-1., 100.0); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_SCD, -1, + ENC_SCD_TEXT, ENC_SCD_TEXT, true ) + change_integer_range(-1, 1 ); + + /* advanced option only */ + add_string( ENC_CFG_PREFIX ENC_PWT, NULL, + ENC_PWT_TEXT, ENC_PWT_TEXT, true ) + change_string_list( enc_perceptual_weighting_list, enc_perceptual_weighting_list, 0 ); + + /* advanced option only */ + add_float( ENC_CFG_PREFIX ENC_PDIST, -1, + ENC_PDIST_TEXT, ENC_PDIST_LONGTEXT, true ) + change_float_range(-1., 100.); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_NOAC, -1, + ENC_NOAC_TEXT, ENC_NOAC_LONGTEXT, true ) + change_integer_range(-1, 1 ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_HSLICES, -1, + ENC_HSLICES_TEXT, ENC_HSLICES_LONGTEXT, true ) + change_integer_range(-1, INT_MAX ); + + /* advanced option only */ + add_integer( ENC_CFG_PREFIX ENC_VSLICES, -1, + ENC_VSLICES_TEXT, ENC_VSLICES_LONGTEXT, true ) + change_integer_range(-1, INT_MAX ); + + /* advanced option only */ + add_string( ENC_CFG_PREFIX ENC_FORCE_PROFILE, NULL, + ENC_FORCE_PROFILE_TEXT, ENC_FORCE_PROFILE_TEXT, true ) + change_string_list( enc_profile_list, enc_profile_list_text, 0 ); + vlc_module_end () + /***************************************************************************** * Local prototypes *****************************************************************************/ @@ -392,3 +860,742 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) } } } + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static block_t *Encode( encoder_t *p_enc, picture_t *p_pict ); + + +/***************************************************************************** + * picture_pts_t : store pts alongside picture number, not carried through + * encoder + *****************************************************************************/ +struct picture_pts_t +{ + mtime_t i_pts; /* associated pts */ + uint32_t u_pnum; /* dirac picture number */ + bool b_empty; /* entry is invalid */ +}; + +/***************************************************************************** + * encoder_sys_t : Schroedinger encoder descriptor + *****************************************************************************/ +#define SCHRO_PTS_TLB_SIZE 256 +struct encoder_sys_t +{ + /* + * Schro properties + */ + SchroEncoder *p_schro; + SchroVideoFormat *p_format; + int started; + bool b_auto_field_coding; + + uint32_t i_input_picnum; + block_fifo_t *p_dts_fifo; + + block_t *p_chain; + + struct picture_pts_t pts_tlb[SCHRO_PTS_TLB_SIZE]; + mtime_t i_pts_offset; + mtime_t i_field_time; + + bool b_eos_signalled; + bool b_eos_pulled; +}; + +static struct +{ + unsigned int i_height; + int i_approx_fps; + SchroVideoFormatEnum i_vf; +} schro_format_guess[] = { + /* Important: Keep this list ordered in ascending picture height */ + {1, 0, SCHRO_VIDEO_FORMAT_CUSTOM}, + {120, 15, SCHRO_VIDEO_FORMAT_QSIF}, + {144, 12, SCHRO_VIDEO_FORMAT_QCIF}, + {240, 15, SCHRO_VIDEO_FORMAT_SIF}, + {288, 12, SCHRO_VIDEO_FORMAT_CIF}, + {480, 30, SCHRO_VIDEO_FORMAT_SD480I_60}, + {480, 15, SCHRO_VIDEO_FORMAT_4SIF}, + {576, 12, SCHRO_VIDEO_FORMAT_4CIF}, + {576, 25, SCHRO_VIDEO_FORMAT_SD576I_50}, + {720, 50, SCHRO_VIDEO_FORMAT_HD720P_50}, + {720, 60, SCHRO_VIDEO_FORMAT_HD720P_60}, + {1080, 24, SCHRO_VIDEO_FORMAT_DC2K_24}, + {1080, 25, SCHRO_VIDEO_FORMAT_HD1080I_50}, + {1080, 30, SCHRO_VIDEO_FORMAT_HD1080I_60}, + {1080, 50, SCHRO_VIDEO_FORMAT_HD1080P_50}, + {1080, 60, SCHRO_VIDEO_FORMAT_HD1080P_60}, + {2160, 24, SCHRO_VIDEO_FORMAT_DC4K_24}, + {0, 0, 0}, +}; + +/***************************************************************************** + * ResetPTStlb: Purge all entries in @p_enc@'s PTS-tlb + *****************************************************************************/ +static void ResetPTStlb( encoder_t *p_enc ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + for( int i = 0; i < SCHRO_PTS_TLB_SIZE; i++ ) + { + p_sys->pts_tlb[i].b_empty = true; + } +} + + +/***************************************************************************** + * StorePicturePTS: Store the PTS value for a particular picture number + *****************************************************************************/ +static void StorePicturePTS( encoder_t *p_enc, uint32_t u_pnum, mtime_t i_pts ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + + for( int i = 0; ipts_tlb[i].b_empty ) + { + p_sys->pts_tlb[i].u_pnum = u_pnum; + p_sys->pts_tlb[i].i_pts = i_pts; + p_sys->pts_tlb[i].b_empty = false; + + return; + } + } + + msg_Err( p_enc, "Could not store PTS %"PRId64" for frame %u", i_pts, u_pnum ); +} + +/***************************************************************************** + * GetPicturePTS: Retrieve the PTS value for a particular picture number + *****************************************************************************/ +static mtime_t GetPicturePTS( encoder_t *p_enc, uint32_t u_pnum ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + + for( int i = 0; i < SCHRO_PTS_TLB_SIZE; i++ ) + { + if( !p_sys->pts_tlb[i].b_empty && + p_sys->pts_tlb[i].u_pnum == u_pnum ) + { + p_sys->pts_tlb[i].b_empty = true; + return p_sys->pts_tlb[i].i_pts; + } + } + + msg_Err( p_enc, "Could not retrieve PTS for picture %u", u_pnum ); + return 0; +} + +static inline bool SchroSetEnum( const encoder_t *p_enc, int i_list_size, const char *list[], + const char *psz_name, const char *psz_name_text, const char *psz_value) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + if( list && psz_name_text && psz_name && psz_value ) { + for( int i = 0; i < i_list_size; ++i ) { + if( strcmp( list[i], psz_value ) ) + continue; + schro_encoder_setting_set_double( p_sys->p_schro, psz_name, i ); + return true; + } + msg_Err( p_enc, "Invalid %s: %s", psz_name_text, psz_value ); + } + return false; +} + +static bool SetEncChromaFormat( encoder_t *p_enc, uint32_t i_codec ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + + switch( i_codec ) { + case VLC_CODEC_I420: + p_enc->fmt_in.i_codec = i_codec; + p_enc->fmt_in.video.i_bits_per_pixel = 12; + p_sys->p_format->chroma_format = SCHRO_CHROMA_420; + break; + case VLC_CODEC_I422: + p_enc->fmt_in.i_codec = i_codec; + p_enc->fmt_in.video.i_bits_per_pixel = 16; + p_sys->p_format->chroma_format = SCHRO_CHROMA_422; + break; + case VLC_CODEC_I444: + p_enc->fmt_in.i_codec = i_codec; + p_enc->fmt_in.video.i_bits_per_pixel = 24; + p_sys->p_format->chroma_format = SCHRO_CHROMA_444; + break; + default: + return false; + } + + return true; +} + +#define SCHRO_SET_FLOAT(psz_name, pschro_name) \ + f_tmp = var_GetFloat( p_enc, ENC_CFG_PREFIX psz_name ); \ + if( f_tmp >= 0.0 ) \ + schro_encoder_setting_set_double( p_sys->p_schro, pschro_name, f_tmp ); + +#define SCHRO_SET_INTEGER(psz_name, pschro_name, ignore_val) \ + i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX psz_name ); \ + if( i_tmp > ignore_val ) \ + schro_encoder_setting_set_double( p_sys->p_schro, pschro_name, i_tmp ); + +#define SCHRO_SET_ENUM(list, psz_name, psz_name_text, pschro_name) \ + psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX psz_name ); \ + if( !psz_tmp ) \ + goto error; \ + else if ( *psz_tmp != '\0' ) { \ + int i_list_size = ARRAY_SIZE(list); \ + if( !SchroSetEnum( p_enc, i_list_size, list, pschro_name, psz_name_text, psz_tmp ) ) { \ + free( psz_tmp ); \ + goto error; \ + } \ + } \ + free( psz_tmp ); + +/***************************************************************************** + * OpenEncoder: probe the encoder and return score + *****************************************************************************/ +static int OpenEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys = p_enc->p_sys; + int i_tmp; + float f_tmp; + char *psz_tmp; + + if( p_enc->fmt_out.i_codec != VLC_CODEC_DIRAC && + !p_enc->b_force ) + { + return VLC_EGENERIC; + } + + if( !p_enc->fmt_in.video.i_frame_rate || !p_enc->fmt_in.video.i_frame_rate_base || + !p_enc->fmt_in.video.i_height || !p_enc->fmt_in.video.i_width ) + { + msg_Err( p_enc, "Framerate and picture dimensions must be non-zero" ); + return VLC_EGENERIC; + } + + /* Allocate the memory needed to store the decoder's structure */ + if( ( p_sys = calloc( 1, sizeof( *p_sys ) ) ) == NULL ) + return VLC_ENOMEM; + + p_enc->p_sys = p_sys; + p_enc->pf_encode_video = Encode; + p_enc->fmt_out.i_codec = VLC_CODEC_DIRAC; + p_enc->fmt_out.i_cat = VIDEO_ES; + + if( ( p_sys->p_dts_fifo = block_FifoNew() ) == NULL ) + { + CloseEncoder( p_this ); + return VLC_ENOMEM; + } + + ResetPTStlb( p_enc ); + + /* guess the video format based upon number of lines and picture height */ + int i = 0; + SchroVideoFormatEnum guessed_video_fmt = SCHRO_VIDEO_FORMAT_CUSTOM; + /* Pick the dirac_video_format in this order of preference: + * 1. an exact match in frame height and an approximate fps match + * 2. the previous preset with a smaller number of lines. + */ + do + { + if( schro_format_guess[i].i_height > p_enc->fmt_in.video.i_height ) + { + guessed_video_fmt = schro_format_guess[i-1].i_vf; + break; + } + if( schro_format_guess[i].i_height != p_enc->fmt_in.video.i_height ) + continue; + int src_fps = p_enc->fmt_in.video.i_frame_rate / p_enc->fmt_in.video.i_frame_rate_base; + int delta_fps = abs( schro_format_guess[i].i_approx_fps - src_fps ); + if( delta_fps > 2 ) + continue; + + guessed_video_fmt = schro_format_guess[i].i_vf; + break; + } while( schro_format_guess[++i].i_height ); + + schro_init(); + p_sys->p_schro = schro_encoder_new(); + if( !p_sys->p_schro ) { + msg_Err( p_enc, "Failed to initialize libschroedinger encoder" ); + return VLC_EGENERIC; + } + schro_encoder_set_packet_assembly( p_sys->p_schro, true ); + + if( !( p_sys->p_format = schro_encoder_get_video_format( p_sys->p_schro ) ) ) { + msg_Err( p_enc, "Failed to get Schroedigner video format" ); + schro_encoder_free( p_sys->p_schro ); + return VLC_EGENERIC; + } + + /* initialise the video format parameters to the guessed format */ + schro_video_format_set_std_video_format( p_sys->p_format, guessed_video_fmt ); + + /* constants set from the input video format */ + p_sys->p_format->width = p_enc->fmt_in.video.i_width; + p_sys->p_format->height = p_enc->fmt_in.video.i_height; + p_sys->p_format->frame_rate_numerator = p_enc->fmt_in.video.i_frame_rate; + p_sys->p_format->frame_rate_denominator = p_enc->fmt_in.video.i_frame_rate_base; + unsigned u_asr_num, u_asr_den; + vlc_ureduce( &u_asr_num, &u_asr_den, + p_enc->fmt_in.video.i_sar_num, + p_enc->fmt_in.video.i_sar_den, 0 ); + p_sys->p_format->aspect_ratio_numerator = u_asr_num; + p_sys->p_format->aspect_ratio_denominator = u_asr_den; + + config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); + + SCHRO_SET_ENUM(enc_rate_control_list, ENC_RATE_CONTROL, ENC_RATE_CONTROL_TEXT, "rate_control") + + SCHRO_SET_ENUM(enc_gop_structure_list, ENC_GOP_STRUCTURE, ENC_GOP_STRUCTURE_TEXT, "gop_structure") + + psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_CHROMAFMT ); + if( !psz_tmp ) + goto error; + else { + uint32_t i_codec; + if( !strcmp( psz_tmp, "420" ) ) { + i_codec = VLC_CODEC_I420; + } + else if( !strcmp( psz_tmp, "422" ) ) { + i_codec = VLC_CODEC_I422; + } + else if( !strcmp( psz_tmp, "444" ) ) { + i_codec = VLC_CODEC_I444; + } + else { + msg_Err( p_enc, "Invalid chroma format: %s", psz_tmp ); + free( psz_tmp ); + goto error; + } + SetEncChromaFormat( p_enc, i_codec ); + } + free( psz_tmp ); + + SCHRO_SET_FLOAT(ENC_QUALITY, "quality") + + SCHRO_SET_FLOAT(ENC_NOISE_THRESHOLD, "noise_threshold") + + /* use bitrate from sout-transcode-vb in kbps */ + i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_BITRATE ); + if( i_tmp > -1 ) + schro_encoder_setting_set_double( p_sys->p_schro, "bitrate", i_tmp * 1000 ); + else + schro_encoder_setting_set_double( p_sys->p_schro, "bitrate", p_enc->fmt_out.i_bitrate ); + + p_enc->fmt_out.i_bitrate = schro_encoder_setting_get_double( p_sys->p_schro, "bitrate" ); + + i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MIN_BITRATE ); + if( i_tmp > -1 ) + schro_encoder_setting_set_double( p_sys->p_schro, "min_bitrate", i_tmp * 1000 ); + + i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MAX_BITRATE ); + if( i_tmp > -1 ) + schro_encoder_setting_set_double( p_sys->p_schro, "max_bitrate", i_tmp * 1000 ); + + SCHRO_SET_INTEGER(ENC_AU_DISTANCE, "au_distance", -1) + + SCHRO_SET_ENUM(enc_filtering_list, ENC_PREFILTER, ENC_PREFILTER_TEXT, "filtering") + + SCHRO_SET_FLOAT(ENC_PREFILTER_STRENGTH, "filter_value") + + + psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_CODINGMODE ); + if( !psz_tmp ) + goto error; + else if( !strcmp( psz_tmp, "auto" ) ) { + p_sys->b_auto_field_coding = true; + } + else if( !strcmp( psz_tmp, "progressive" ) ) { + p_sys->b_auto_field_coding = false; + schro_encoder_setting_set_double( p_sys->p_schro, "interlaced_coding", false); + } + else if( !strcmp( psz_tmp, "field" ) ) { + p_sys->b_auto_field_coding = false; + schro_encoder_setting_set_double( p_sys->p_schro, "interlaced_coding", true); + } + else { + msg_Err( p_enc, "Invalid codingmode: %s", psz_tmp ); + free( psz_tmp ); + goto error; + } + free( psz_tmp ); + + SCHRO_SET_ENUM(enc_block_size_list, ENC_MCBLK_SIZE, ENC_MCBLK_SIZE_TEXT, "motion_block_size") + + SCHRO_SET_ENUM(enc_block_overlap_list, ENC_MCBLK_OVERLAP, ENC_MCBLK_OVERLAP_TEXT, "motion_block_overlap") + + psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_MVPREC ); + if( !psz_tmp ) + goto error; + else if( *psz_tmp != '\0') { + if( !strcmp( psz_tmp, "1" ) ) { + schro_encoder_setting_set_double( p_sys->p_schro, "mv_precision", 0 ); + } + else if( !strcmp( psz_tmp, "1/2" ) ) { + schro_encoder_setting_set_double( p_sys->p_schro, "mv_precision", 1 ); + } + else if( !strcmp( psz_tmp, "1/4" ) ) { + schro_encoder_setting_set_double( p_sys->p_schro, "mv_precision", 2 ); + } + else if( !strcmp( psz_tmp, "1/8" ) ) { + schro_encoder_setting_set_double( p_sys->p_schro, "mv_precision", 3 ); + } + else { + msg_Err( p_enc, "Invalid mv_precision: %s", psz_tmp ); + free( psz_tmp ); + goto error; + } + } + free( psz_tmp ); + + SCHRO_SET_INTEGER(ENC_ME_COMBINED, "enable_chroma_me", -1) + + SCHRO_SET_ENUM(enc_wavelet_list, ENC_DWTINTRA, ENC_DWTINTRA_TEXT, "intra_wavelet") + + SCHRO_SET_ENUM(enc_wavelet_list, ENC_DWTINTER, ENC_DWTINTER_TEXT, "inter_wavelet") + + SCHRO_SET_INTEGER(ENC_DWTDEPTH, "transform_depth", -1) + + SCHRO_SET_INTEGER(ENC_MULTIQUANT, "enable_multiquant", -1) + + SCHRO_SET_INTEGER(ENC_NOAC, "enable_noarith", -1) + + SCHRO_SET_ENUM(enc_perceptual_weighting_list, ENC_PWT, ENC_PWT_TEXT, "perceptual_weighting") + + SCHRO_SET_FLOAT(ENC_PDIST, "perceptual_distance") + + SCHRO_SET_INTEGER(ENC_HSLICES, "horiz_slices", -1) + + SCHRO_SET_INTEGER(ENC_VSLICES, "vert_slices", -1) + + SCHRO_SET_ENUM(enc_codeblock_size_list, ENC_SCBLK_SIZE, ENC_SCBLK_SIZE_TEXT, "codeblock_size") + + SCHRO_SET_INTEGER(ENC_ME_HIERARCHICAL, "enable_hierarchical_estimation", -1) + + SCHRO_SET_INTEGER(ENC_ME_DOWNSAMPLE_LEVELS, "downsample_levels", 1) + + SCHRO_SET_INTEGER(ENC_ME_GLOBAL_MOTION, "enable_global_motion", -1) + + SCHRO_SET_INTEGER(ENC_ME_PHASECORR, "enable_phasecorr_estimation", -1) + + SCHRO_SET_INTEGER(ENC_SCD, "enable_scene_change_detection", -1) + + SCHRO_SET_ENUM(enc_profile_list, ENC_FORCE_PROFILE, ENC_FORCE_PROFILE_TEXT, "force_profile") + + p_sys->started = 0; + + return VLC_SUCCESS; +error: + CloseEncoder( p_this ); + return VLC_EGENERIC; +} + + +struct enc_picture_free_t +{ + picture_t *p_pic; + encoder_t *p_enc; +}; + +/***************************************************************************** + * EncSchroFrameFree: schro_frame callback to release the associated picture_t + * When schro_encoder_reset() is called there will be pictures in the + * encoding pipeline that need to be released rather than displayed. + *****************************************************************************/ +static void EncSchroFrameFree( SchroFrame *frame, void *priv ) +{ + struct enc_picture_free_t *p_free = priv; + + if( !p_free ) + return; + + picture_Release( p_free->p_pic ); + free( p_free ); + (void)frame; +} + +/***************************************************************************** + * CreateSchroFrameFromPic: wrap a picture_t in a SchroFrame + *****************************************************************************/ +static SchroFrame *CreateSchroFrameFromInputPic( encoder_t *p_enc, picture_t *p_pic ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + SchroFrame *p_schroframe = schro_frame_new(); + struct enc_picture_free_t *p_free; + + if( !p_schroframe ) + return NULL; + + if( !p_pic ) + return NULL; + + p_schroframe->format = SCHRO_FRAME_FORMAT_U8_420; + if( p_sys->p_format->chroma_format == SCHRO_CHROMA_422 ) + { + p_schroframe->format = SCHRO_FRAME_FORMAT_U8_422; + } + else if( p_sys->p_format->chroma_format == SCHRO_CHROMA_444 ) + { + p_schroframe->format = SCHRO_FRAME_FORMAT_U8_444; + } + + p_schroframe->width = p_sys->p_format->width; + p_schroframe->height = p_sys->p_format->height; + + p_free = malloc( sizeof( *p_free ) ); + if( unlikely( p_free == NULL ) ) { + schro_frame_unref( p_schroframe ); + return NULL; + } + + p_free->p_pic = p_pic; + p_free->p_enc = p_enc; + schro_frame_set_free_callback( p_schroframe, EncSchroFrameFree, p_free ); + + for( int i=0; i<3; i++ ) + { + p_schroframe->components[i].width = p_pic->p[i].i_visible_pitch; + p_schroframe->components[i].stride = p_pic->p[i].i_pitch; + p_schroframe->components[i].height = p_pic->p[i].i_visible_lines; + p_schroframe->components[i].length = + p_pic->p[i].i_pitch * p_pic->p[i].i_lines; + p_schroframe->components[i].data = p_pic->p[i].p_pixels; + + if( i!=0 ) + { + p_schroframe->components[i].v_shift = + SCHRO_FRAME_FORMAT_V_SHIFT( p_schroframe->format ); + p_schroframe->components[i].h_shift = + SCHRO_FRAME_FORMAT_H_SHIFT( p_schroframe->format ); + } + } + + return p_schroframe; +} + +/* Attempt to find dirac picture number in an encapsulation unit */ +static int ReadDiracPictureNumber( uint32_t *p_picnum, block_t *p_block ) +{ + uint32_t u_pos = 4; + /* protect against falling off the edge */ + while( u_pos + 13 < p_block->i_buffer ) + { + /* find the picture startcode */ + if( p_block->p_buffer[u_pos] & 0x08 ) + { + *p_picnum = GetDWBE( p_block->p_buffer + u_pos + 9 ); + return 1; + } + /* skip to the next dirac data unit */ + uint32_t u_npo = GetDWBE( p_block->p_buffer + u_pos + 1 ); + assert( u_npo <= UINT32_MAX - u_pos ); + if( u_npo == 0 ) + u_npo = 13; + u_pos += u_npo; + } + return 0; +} + + +static block_t *Encode( encoder_t *p_enc, picture_t *p_pic ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + block_t *p_block, *p_output_chain = NULL; + SchroFrame *p_frame; + bool b_go = true; + + if( !p_pic ) { + if( !p_sys->started || p_sys->b_eos_pulled ) + return NULL; + + if( !p_sys->b_eos_signalled ) { + p_sys->b_eos_signalled = 1; + schro_encoder_end_of_stream( p_sys->p_schro ); + } + } else { + /* we only know if the sequence is interlaced when the first + * picture arrives, so final setup is done here */ + /* XXX todo, detect change of interlace */ + p_sys->p_format->interlaced = !p_pic->b_progressive; + p_sys->p_format->top_field_first = p_pic->b_top_field_first; + + if( p_sys->b_auto_field_coding ) + schro_encoder_setting_set_double( p_sys->p_schro, "interlaced_coding", !p_pic->b_progressive ); + } + + if( !p_sys->started ) { + date_t date; + + if( p_pic->format.i_chroma != p_enc->fmt_in.i_codec ) { + char chroma_in[5], chroma_out[5]; + vlc_fourcc_to_char( p_pic->format.i_chroma, chroma_in ); + chroma_in[4] = '\0'; + chroma_out[4] = '\0'; + vlc_fourcc_to_char( p_enc->fmt_in.i_codec, chroma_out ); + msg_Warn( p_enc, "Resetting chroma from %s to %s", chroma_out, chroma_in ); + if( !SetEncChromaFormat( p_enc, p_pic->format.i_chroma ) ) { + msg_Err( p_enc, "Could not reset chroma format to %s", chroma_in ); + return NULL; + } + } + + date_Init( &date, p_enc->fmt_in.video.i_frame_rate, p_enc->fmt_in.video.i_frame_rate_base ); + /* FIXME - Unlike dirac-research codec Schro doesn't have a function that returns the delay in pics yet. + * Use a default of 1 + */ + date_Increment( &date, 1 ); + p_sys->i_pts_offset = date_Get( &date ); + if( schro_encoder_setting_get_double( p_sys->p_schro, "interlaced_coding" ) > 0.0 ) { + date_Set( &date, 0 ); + date_Increment( &date, 1); + p_sys->i_field_time = date_Get( &date ) / 2; + } + + schro_video_format_set_std_signal_range( p_sys->p_format, SCHRO_SIGNAL_RANGE_8BIT_VIDEO ); + schro_encoder_set_video_format( p_sys->p_schro, p_sys->p_format ); + schro_encoder_start( p_sys->p_schro ); + p_sys->started = 1; + } + + if( !p_sys->b_eos_signalled ) { + /* create a schro frame from the input pic and load */ + /* Increase ref count by 1 so that the picture is not freed until + Schro finishes with it */ + picture_Hold( p_pic ); + + p_frame = CreateSchroFrameFromInputPic( p_enc, p_pic ); + if( !p_frame ) + return NULL; + schro_encoder_push_frame( p_sys->p_schro, p_frame ); + + + /* store pts in a lookaside buffer, so that the same pts may + * be used for the picture in coded order */ + StorePicturePTS( p_enc, p_sys->i_input_picnum, p_pic->date ); + p_sys->i_input_picnum++; + + /* store dts in a queue, so that they appear in order in + * coded order */ + p_block = block_New( p_enc, 1 ); + if( !p_block ) + return NULL; + p_block->i_dts = p_pic->date - p_sys->i_pts_offset; + block_FifoPut( p_sys->p_dts_fifo, p_block ); + p_block = NULL; + + /* for field coding mode, insert an extra value into both the + * pts lookaside buffer and dts queue, offset to correspond + * to a one field delay. */ + if( schro_encoder_setting_get_double( p_sys->p_schro, "interlaced_coding" ) > 0.0 ) { + StorePicturePTS( p_enc, p_sys->i_input_picnum, p_pic->date + p_sys->i_field_time ); + p_sys->i_input_picnum++; + + p_block = block_New( p_enc, 1 ); + if( !p_block ) + return NULL; + p_block->i_dts = p_pic->date - p_sys->i_pts_offset + p_sys->i_field_time; + block_FifoPut( p_sys->p_dts_fifo, p_block ); + p_block = NULL; + } + } + + do + { + SchroStateEnum state; + state = schro_encoder_wait( p_sys->p_schro ); + switch( state ) + { + case SCHRO_STATE_NEED_FRAME: + b_go = false; + break; + case SCHRO_STATE_AGAIN: + break; + case SCHRO_STATE_END_OF_STREAM: + p_sys->b_eos_pulled = 1; + b_go = false; + break; + case SCHRO_STATE_HAVE_BUFFER: + { + SchroBuffer *p_enc_buf; + uint32_t u_pic_num; + int i_presentation_frame; + p_enc_buf = schro_encoder_pull( p_sys->p_schro, &i_presentation_frame ); + p_block = block_New( p_enc, p_enc_buf->length ); + if( !p_block ) + return NULL; + + memcpy( p_block->p_buffer, p_enc_buf->data, p_enc_buf->length ); + schro_buffer_unref( p_enc_buf ); + + /* Presence of a Sequence header indicates a seek point */ + if( 0 == p_block->p_buffer[4] ) + { + p_block->i_flags |= BLOCK_FLAG_TYPE_I; + + if( !p_enc->fmt_out.p_extra ) { + const uint8_t eos[] = { 'B','B','C','D',0x10,0,0,0,13,0,0,0,0 }; + uint32_t len = GetDWBE( p_block->p_buffer + 5 ); + /* if it hasn't been done so far, stash a copy of the + * sequence header for muxers such as ogg */ + /* The OggDirac spec advises that a Dirac EOS DataUnit + * is appended to the sequence header to allow guard + * against poor streaming servers */ + /* XXX, should this be done using the packetizer ? */ + p_enc->fmt_out.p_extra = malloc( len + sizeof( eos ) ); + if( !p_enc->fmt_out.p_extra ) + return NULL; + memcpy( p_enc->fmt_out.p_extra, p_block->p_buffer, len ); + memcpy( (uint8_t*)p_enc->fmt_out.p_extra + len, eos, sizeof( eos ) ); + SetDWBE( (uint8_t*)p_enc->fmt_out.p_extra + len + 10, len ); + p_enc->fmt_out.i_extra = len + sizeof( eos ); + } + } + + if( ReadDiracPictureNumber( &u_pic_num, p_block ) ) { + block_t *p_dts_block = block_FifoGet( p_sys->p_dts_fifo ); + p_block->i_dts = p_dts_block->i_dts; + p_block->i_pts = GetPicturePTS( p_enc, u_pic_num ); + block_Release( p_dts_block ); + block_ChainAppend( &p_output_chain, p_block ); + } else { + /* End of sequence */ + block_ChainAppend( &p_output_chain, p_block ); + } + break; + } + default: + break; + } + } while( b_go ); + + return p_output_chain; +} + +/***************************************************************************** + * CloseEncoder: Schro encoder destruction + *****************************************************************************/ +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; + + /* Free the encoder resources */ + if( p_sys->p_schro ) + schro_encoder_free( p_sys->p_schro ); + + free( p_sys->p_format ); + + if( p_sys->p_dts_fifo ) + block_FifoRelease( p_sys->p_dts_fifo ); + + block_ChainRelease( p_sys->p_chain ); + + free( p_sys ); +}