[vlc-devel] [PATCH 2/2] codec/dirac: Add dirac encoding support using dirac-research (libdirac)
davidf+nntp at woaf.net
davidf+nntp at woaf.net
Sun Nov 9 16:36:18 CET 2008
From: David Flynn <davidf at woaf.net>
libdirac is currently a higher quality (albeit much slower) encoder than
libschroedinger. The intention is to port its algorithim to schro and
depricate the codebase.
This patch corrects previous attempts at doing an encoder module. It
takes into account:
- input PTS
- correctly forming output pts&dts (progressive and field coding modes)
- gathering dirac data units into encapsulation units
- encoder options
- simplified encoder options (block overlap)
- choosing of suitable parameters from input frame parameters
- OggDirac compliant stashing of headers in p_extra
Signed-off-by: David Flynn <davidf at rd.bbc.co.uk>
---
modules/codec/dirac.c | 1034 ++++++++++++++++++++++++++++++++++---------------
1 files changed, 729 insertions(+), 305 deletions(-)
diff --git a/modules/codec/dirac.c b/modules/codec/dirac.c
index bb37518..06cf3ed 100644
--- a/modules/codec/dirac.c
+++ b/modules/codec/dirac.c
@@ -1,11 +1,16 @@
/*****************************************************************************
- * dirac.c: Dirac decoder/encoder module making use of libdirac.
+ * dirac.c: Dirac encoder module making use of libdirac (dirac-research).
* (http://www.bbc.co.uk/rd/projects/dirac/index.shtml)
+ * ##
+ * ## NB, this is a temporary encoder only module until schroedinger
+ * ## offers superior encoding quality than dirac-research
+ * ##
*****************************************************************************
- * Copyright (C) 1999-2001 the VideoLAN team
+ * Copyright (C) 2004-2008 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin at videolan.org>
+ * Rewritten: David Flynn <davidf at rd.bbc.co.uk>
*
* 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
@@ -29,293 +34,397 @@
# include "config.h"
#endif
+#include <limits.h>
+
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_codec.h>
#include <vlc_sout.h>
#include <vlc_vout.h>
-#include <libdirac_decoder/dirac_parser.h>
#include <libdirac_encoder/dirac_encoder.h>
-/*****************************************************************************
- * decoder_sys_t : theora decoder descriptor
- *****************************************************************************/
-struct decoder_sys_t
-{
- /*
- * Dirac properties
- */
- dirac_decoder_t *p_dirac;
-};
+#ifndef DIRAC_RESEARCH_VERSION_ATLEAST
+# define DIRAC_RESEARCH_VERSION_ATLEAST(x,y,z) 0
+#endif
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static int OpenDecoder ( vlc_object_t * );
-static void CloseDecoder ( vlc_object_t * );
-static picture_t *DecodeBlock ( decoder_t *p_dec, block_t **pp_block );
-
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 );
#define ENC_CFG_PREFIX "sout-dirac-"
+#define ENC_QUALITY_FACTOR "quality"
+#define ENC_QUALITY_FACTOR_TEXT N_("quality factor (primarily for constant quality mode)")
+#define ENC_QUALITY_FACTOR_LONGTEXT N_("")
+
+#define ENC_TARGETRATE "bitrate"
+#define ENC_TARGETRATE_TEXT N_("target bit rate in kbps (setting this enables CBR mode)")
+#define ENC_TARGETRATE_LONGTEXT N_("")
+
+#define ENC_LOSSLESS "lossless"
+#define ENC_LOSSLESS_TEXT N_("enable lossless coding (ignores qf and tr)")
+#define ENC_LOSSLESS_LONGTEXT N_("")
+
+#define ENC_PREFILTER "prefilter"
+#define ENC_PREFILTER_TEXT N_("prefilter video")
+#define ENC_PREFILTER_LONGTEXT N_("")
+static const char *const enc_prefilter_list[] =
+ { "none", "cwm", "rectlp", "diaglp" };
+static const char *const enc_prefilter_list_text[] =
+ { N_("none"), N_("cwm"), N_("rectlp"), N_("diaglp") };
+
+#define ENC_PREFILTER_STRENGTH "prefilter-strength"
+#define ENC_PREFILTER_STRENGTH_TEXT N_("prefilter strength")
+#define ENC_PREFILTER_STRENGTH_LONGTEXT N_("")
+
+#define ENC_CHROMAFMT "chroma-fmt"
+#define ENC_CHROMAFMT_TEXT N_("Chroma format 444,422,420")
+#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_("420"), N_("422"), N_("444") };
+
+#define ENC_L1SEP "l1-sep"
+#define ENC_L1SEP_TEXT N_("Seperation between 'P-style' frames")
+#define ENC_L1SEP_LONGTEXT N_("")
+
+#define ENC_L1NUM "num-l1"
+#define ENC_L1NUM_TEXT N_("Ideal number of 'P-style' frames per GOP")
+#define ENC_L1NUM_LONGTEXT N_("")
+
+#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" \
+ " seperately 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 seperate interlaced fields"),
+ };
+
+#define ENC_MCBLK_WIDTH "mc-blk-width"
+#define ENC_MCBLK_WIDTH_TEXT N_("Width of motion compensation blocks")
+#define ENC_MCBLK_WIDTH_LONGTEXT N_("")
+
+#define ENC_MCBLK_HEIGHT "mc-blk-height"
+#define ENC_MCBLK_HEIGHT_TEXT N_("Height of motion compensation blocks")
+#define ENC_MCBLK_HEIGHT_LONGTEXT N_("")
+
+/* also known as XBSEP */
+#define ENC_MCBLK_HOVERLAP "mc-blk-hoverlap"
+#define ENC_MCBLK_HOVERLAP_TEXT N_("Percentage horizontal overlap between adjacent motion blocks")
+#define ENC_MCBLK_HOVERLAP_LONGTEXT N_("")
+
+/* also known as YBSEP */
+#define ENC_MCBLK_VOVERLAP "mc-blk-voverlap"
+#define ENC_MCBLK_VOVERLAP_TEXT N_("Percentage vertical overlap between adjacent motion blocks")
+#define ENC_MCBLK_VOVERLAP_LONGTEXT N_("")
+
+/* advanced option only */
+#define ENC_MCBLK_XBLEN "mc-blk-xblen"
+#define ENC_MCBLK_XBLEN_TEXT N_("xblen")
+#define ENC_MCBLK_XBLEN_LONGTEXT N_("")
+
+/* advanded option only */
+#define ENC_MCBLK_YBLEN "mc-blk-yblen"
+#define ENC_MCBLK_YBLEN_TEXT N_("yblen")
+#define ENC_MCBLK_YBLEN_LONGTEXT N_("")
+
+#define ENC_MVPREC "mv-prec"
+#define ENC_MVPREC_TEXT N_("motion vector precision 0,1,2,3,4")
+#define ENC_MVPREC_LONGTEXT N_("")
+static const char *const enc_mvprec_list[] =
+ { "1", "1/2", "1/4", "1/8" };
+
+#define ENC_ME_SIMPLESEARCH "me-simple-search"
+#define ENC_ME_SIMPLESEARCH_TEXT N_("Motion estimation with nonhierachical search area x:y")
+#define ENC_ME_SIMPLESEARCH_LONGTEXT N_("Perform a simple block matching motion vector search" \
+ " with search range of +/-x, +/-y (Not recommended)")
+
+#define ENC_ME_COMBINED "me-combined"
+#define ENC_ME_COMBINED_TEXT N_("Use chroma in motion estimation")
+#define ENC_ME_COMBINED_LONGTEXT N_("")
+
+#define ENC_DWTINTRA "dwt-intra"
+#define ENC_DWTINTRA_TEXT N_("dwt filter to use on intra pictures")
+#define ENC_DWTINTRA_LONGTEXT N_("")
+
+#define ENC_DWTINTER "dwt-inter"
+#define ENC_DWTINTER_TEXT N_("dwt filter to use on motion compensated pictures")
+#define ENC_DWTINTER_LONGTEXT N_("")
+
+#define ENC_DWTDEPTH "dwt-depth"
+#define ENC_DWTDEPTH_TEXT N_("number of dwt iterations")
+#define ENC_DWTDEPTH_LONGTEXT N_("")
+
+/* advanced option only */
+#define ENC_MULTIQUANT "multi-quant"
+#define ENC_MULTIQUANT_TEXT N_("enable quantizer per codeblock mode")
+#define ENC_MULTIQUANT_LONGTEXT N_("")
+
+/* advanced option only */
+#define ENC_SPARTITION "spartition"
+#define ENC_SPARTITION_TEXT N_("enable spatial partitioning (codeblocks)")
+#define ENC_SPARTITION_LONGTEXT N_("")
+
+#define ENC_VLC "vlc"
+#define ENC_VLC_TEXT N_("disable arithmetic coding where possible")
+#define ENC_VLC_LONGTEXT N_("")
+
+/* visual modelling */
+/* advanced option only */
+#define ENC_CPD "cpd"
+#define ENC_CPD_TEXT N_("cycles-per-degree")
+#define ENC_CPD_LONGTEXT N_("")
+
static const char *const ppsz_enc_options[] = {
- "quality", NULL
+ ENC_QUALITY_FACTOR, ENC_TARGETRATE, ENC_LOSSLESS,
+ ENC_PREFILTER, ENC_PREFILTER_STRENGTH,
+ ENC_CHROMAFMT, ENC_L1SEP, ENC_L1NUM, ENC_CODINGMODE,
+ ENC_MCBLK_WIDTH, ENC_MCBLK_HEIGHT, ENC_MCBLK_HOVERLAP, ENC_MCBLK_VOVERLAP,
+ ENC_MVPREC, ENC_ME_SIMPLESEARCH, ENC_ME_COMBINED,
+ ENC_DWTINTRA, ENC_DWTINTER, ENC_DWTDEPTH,
+ ENC_MULTIQUANT, ENC_SPARTITION, ENC_VLC,
+ ENC_CPD,
+ NULL
};
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
-#define ENC_QUALITY_TEXT N_("Encoding quality")
-#define ENC_QUALITY_LONGTEXT N_( \
- "Quality of the encoding between 1.0 (low) and 10.0 (high)." )
-vlc_module_begin ()
+vlc_module_begin()
set_category( CAT_INPUT )
set_subcategory( SUBCAT_INPUT_VCODEC )
- set_description( N_("Dirac video decoder") )
- set_capability( "decoder", 100 )
- set_callbacks( OpenDecoder, CloseDecoder )
- add_shortcut( "dirac" )
-
- add_submodule ()
- set_description( N_("Dirac video encoder") )
+ set_description( N_("Dirac video encoder using dirac-research library") )
set_capability( "encoder", 100 )
set_callbacks( OpenEncoder, CloseEncoder )
- add_float( ENC_CFG_PREFIX "quality", 7.0, NULL, ENC_QUALITY_TEXT,
- ENC_QUALITY_LONGTEXT, false );
-
-vlc_module_end ()
-/*****************************************************************************
- * OpenDecoder: probe the decoder and return score
- *****************************************************************************/
-static int OpenDecoder( vlc_object_t *p_this )
-{
- decoder_t *p_dec = (decoder_t*)p_this;
- decoder_sys_t *p_sys;
- dirac_decoder_t *p_dirac;
+ add_float( ENC_CFG_PREFIX ENC_QUALITY_FACTOR, 5.5, NULL,
+ ENC_QUALITY_FACTOR_TEXT, ENC_QUALITY_FACTOR_LONGTEXT, false );
+ change_float_range(0., 10.);
+
+ add_integer( ENC_CFG_PREFIX ENC_TARGETRATE, -1, NULL,
+ ENC_TARGETRATE_TEXT, ENC_TARGETRATE_LONGTEXT, false );
+ change_integer_range(0, INT_MAX);
+
+ add_bool( ENC_CFG_PREFIX ENC_LOSSLESS, false, NULL,
+ ENC_LOSSLESS_TEXT, ENC_LOSSLESS_LONGTEXT, false );
+
+ add_string( ENC_CFG_PREFIX ENC_PREFILTER, "diaglp", NULL,
+ ENC_PREFILTER_TEXT, ENC_PREFILTER_LONGTEXT, false );
+ change_string_list( enc_prefilter_list, enc_prefilter_list_text, 0 );
+
+ add_integer( ENC_CFG_PREFIX ENC_PREFILTER_STRENGTH, 1, NULL,
+ ENC_PREFILTER_STRENGTH_TEXT, ENC_PREFILTER_STRENGTH_LONGTEXT, false );
+ change_integer_range(0, 10);
+
+ add_string( ENC_CFG_PREFIX ENC_CHROMAFMT, "420", NULL,
+ ENC_CHROMAFMT_TEXT, ENC_CHROMAFMT_LONGTEXT, false );
+ change_string_list( enc_chromafmt_list, enc_chromafmt_list_text, 0 );
+
+ add_integer( ENC_CFG_PREFIX ENC_L1SEP, -1, NULL,
+ ENC_L1SEP_TEXT, ENC_L1SEP_LONGTEXT, false );
+ change_integer_range(0, INT_MAX);
+
+ add_integer( ENC_CFG_PREFIX ENC_L1NUM, -1, NULL,
+ ENC_L1NUM_TEXT, ENC_L1NUM_LONGTEXT, false );
+ change_integer_range(0, INT_MAX);
+
+ add_string( ENC_CFG_PREFIX ENC_CODINGMODE, "auto", NULL,
+ 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, "1/2", NULL,
+ ENC_MVPREC_TEXT, ENC_MVPREC_LONGTEXT, false );
+ change_string_list( enc_mvprec_list, enc_mvprec_list, 0 );
+
+ add_integer( ENC_CFG_PREFIX ENC_MCBLK_WIDTH, -1, NULL,
+ ENC_MCBLK_WIDTH_TEXT, ENC_MCBLK_WIDTH_LONGTEXT, false );
+ add_depricated_alias( ENC_CFG_PREFIX ENC_MCBLK_XBLEN );
+ change_integer_range(0, INT_MAX);
+
+ add_integer( ENC_CFG_PREFIX ENC_MCBLK_HEIGHT, -1, NULL,
+ ENC_MCBLK_HEIGHT, ENC_MCBLK_HEIGHT_LONGTEXT, false );
+ add_depricated_alias( ENC_CFG_PREFIX ENC_MCBLK_YBLEN );
+ change_integer_range(0, INT_MAX);
+
+ add_integer( ENC_CFG_PREFIX ENC_MCBLK_HOVERLAP, -1, NULL,
+ ENC_MCBLK_HOVERLAP_TEXT, ENC_MCBLK_HOVERLAP_LONGTEXT, false );
+ change_integer_range(0, 100);
+
+ add_integer( ENC_CFG_PREFIX ENC_MCBLK_VOVERLAP, -1, NULL,
+ ENC_MCBLK_VOVERLAP_TEXT, ENC_MCBLK_VOVERLAP_LONGTEXT, false );
+ change_integer_range(0, 100);
+
+ /* advanced option only */
+ add_integer( ENC_CFG_PREFIX ENC_MCBLK_XBLEN, -1, NULL,
+ ENC_MCBLK_XBLEN_TEXT, ENC_MCBLK_XBLEN_LONGTEXT, true );
+ change_integer_range(0, INT_MAX);
+ /* advanced option only */
+ add_integer( ENC_CFG_PREFIX ENC_MCBLK_YBLEN, -1, NULL,
+ ENC_MCBLK_YBLEN_TEXT, ENC_MCBLK_YBLEN_LONGTEXT, true );
+ change_integer_range(0, INT_MAX);
+
+ add_string( ENC_CFG_PREFIX ENC_ME_SIMPLESEARCH, "", NULL,
+ ENC_ME_SIMPLESEARCH_TEXT, ENC_ME_SIMPLESEARCH_LONGTEXT, false );
+
+#if DIRAC_RESEARCH_VERSION_ATLEAST(1,0,1)
+ add_bool( ENC_CFG_PREFIX ENC_ME_COMBINED, true, NULL,
+ ENC_ME_COMBINED_TEXT, ENC_ME_COMBINED_LONGTEXT, false );
+#endif
- if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','r','a','c') )
- {
- return VLC_EGENERIC;
- }
+ add_integer( ENC_CFG_PREFIX ENC_DWTINTRA, -1, NULL,
+ ENC_DWTINTRA_TEXT, ENC_DWTINTRA_LONGTEXT, false );
+ change_integer_range(0, 6);
- /* Initialise the dirac decoder */
- if( !(p_dirac = dirac_decoder_init(0)) ) return VLC_EGENERIC;
+ add_integer( ENC_CFG_PREFIX ENC_DWTINTER, -1, NULL,
+ ENC_DWTINTER_TEXT, ENC_DWTINTER_LONGTEXT, false );
+ change_integer_range(0, 6);
- /* Allocate the memory needed to store the decoder's structure */
- if( ( p_dec->p_sys = p_sys =
- (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
- return VLC_ENOMEM;
+ add_integer( ENC_CFG_PREFIX ENC_DWTDEPTH, -1, NULL,
+ ENC_DWTDEPTH_TEXT, ENC_DWTDEPTH_LONGTEXT, false );
+ change_integer_range(0, 4);
- p_sys->p_dirac = p_dirac;
+ /* advanced option only */
+ add_bool( ENC_CFG_PREFIX ENC_MULTIQUANT, -1, NULL,
+ ENC_MULTIQUANT_TEXT, ENC_MULTIQUANT_LONGTEXT, true );
- /* Set output properties */
- p_dec->fmt_out.i_cat = VIDEO_ES;
- p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');
+ /* advanced option only */
+ add_bool( ENC_CFG_PREFIX ENC_SPARTITION, -1, NULL,
+ ENC_SPARTITION_TEXT, ENC_SPARTITION_LONGTEXT, true );
- /* Set callbacks */
- p_dec->pf_decode_video = DecodeBlock;
+ add_bool( ENC_CFG_PREFIX ENC_VLC, false, NULL,
+ ENC_VLC_TEXT, ENC_VLC_LONGTEXT, false );
- return VLC_SUCCESS;
-}
+ /* advanced option only */
+ add_integer( ENC_CFG_PREFIX ENC_CPD, -1, NULL,
+ ENC_CPD_TEXT, ENC_CPD_LONGTEXT, true );
+ change_integer_range(0, INT_MAX);
+vlc_module_end()
-static void FreeFrameBuffer( dirac_decoder_t *p_dirac )
+/*****************************************************************************
+ * picture_pts_t : store pts alongside picture number, not carried through
+ * encoder
+ *****************************************************************************/
+struct picture_pts_t
{
- if( p_dirac->fbuf )
- {
- int i;
- for( i = 0; i < 3; i++ )
- {
- free( p_dirac->fbuf->buf[i] );
- p_dirac->fbuf->buf[i] = 0;
- }
- }
-}
+ int i_empty; /* entry is invalid */
+ uint32_t u_pnum; /* dirac picture number */
+ mtime_t i_pts; /* associated pts */
+};
/*****************************************************************************
- * GetNewPicture: Get a new picture from the vout and copy the decoder output
+ * encoder_sys_t : dirac encoder descriptor
*****************************************************************************/
-static picture_t *GetNewPicture( decoder_t *p_dec )
+#define ENC_BUFSIZE 1024*1024*10
+#define PTS_TLB_SIZE 32
+struct encoder_sys_t
{
- decoder_sys_t *p_sys = p_dec->p_sys;
- picture_t *p_pic;
- int i_plane;
-
- switch( p_sys->p_dirac->src_params.chroma )
- {
- case format420: p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0'); break;
- case format422: p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','2'); break;
- case format444: p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','4','4'); break; // XXX 0.6 ?
- default:
- p_dec->fmt_out.i_codec = 0;
- break;
- }
-
- p_dec->fmt_out.video.i_visible_width =
- p_dec->fmt_out.video.i_width = p_sys->p_dirac->src_params.width;
- p_dec->fmt_out.video.i_visible_height =
- p_dec->fmt_out.video.i_height = p_sys->p_dirac->src_params.height;
- p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
-
- p_dec->fmt_out.video.i_frame_rate =
- p_sys->p_dirac->src_params.frame_rate.numerator;
- p_dec->fmt_out.video.i_frame_rate_base =
- p_sys->p_dirac->src_params.frame_rate.denominator;
-
- /* Get a new picture */
- p_pic = decoder_NewPicture( p_dec );
-
- if( p_pic == NULL ) return NULL;
- p_pic->b_progressive = !p_sys->p_dirac->src_params.source_sampling;
- p_pic->b_top_field_first = p_sys->p_dirac->src_params.topfieldfirst;
-
- p_pic->i_nb_fields = 2;
+ dirac_encoder_t *p_dirac;
+ dirac_encoder_context_t ctx;
+ bool b_auto_field_coding;
- /* Copy picture stride by stride */
- for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
- {
- int i_line, i_width, i_dst_stride;
- uint8_t *p_src = p_sys->p_dirac->fbuf->buf[i_plane];
- uint8_t *p_dst = p_pic->p[i_plane].p_pixels;
+ uint8_t *p_buffer_in;
+ int i_buffer_in;
+ uint32_t i_input_picnum;
+ block_fifo_t *p_dts_fifo;
- i_width = p_pic->p[i_plane].i_visible_pitch;
- i_dst_stride = p_pic->p[i_plane].i_pitch;
+ uint8_t p_buffer_out[ENC_BUFSIZE];
+ block_t *p_chain;
- for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ )
- {
- vlc_memcpy( p_dst, p_src, i_width );
- p_src += i_width;
- p_dst += i_dst_stride;
- }
- }
+ struct picture_pts_t pts_tlb[PTS_TLB_SIZE];
+ mtime_t i_pts_offset;
+ mtime_t i_field_time;
+};
- return p_pic;
-}
+static struct {
+ unsigned int i_height;
+ int i_approx_fps;
+ VideoFormat i_vf;
+} dirac_format_guess[] = {
+ {120, 15, VIDEO_FORMAT_QSIF525},
+ {144, 12, VIDEO_FORMAT_QCIF},
+ {240, 15, VIDEO_FORMAT_SIF525},
+ {288, 12, VIDEO_FORMAT_CIF},
+ {480, 15, VIDEO_FORMAT_4SIF525},
+ {576, 12, VIDEO_FORMAT_4CIF},
+ {480, 30, VIDEO_FORMAT_SD_480I60},
+ {576, 25, VIDEO_FORMAT_SD_576I50},
+ {720, 60, VIDEO_FORMAT_HD_720P60},
+ {720, 50, VIDEO_FORMAT_HD_720P50},
+ {1080, 30, VIDEO_FORMAT_HD_1080I60},
+ {1080, 25, VIDEO_FORMAT_HD_1080I50},
+ {1080, 60, VIDEO_FORMAT_HD_1080P60},
+ {1080, 50, VIDEO_FORMAT_HD_1080P50},
+ {1080, 24, VIDEO_FORMAT_DIGI_CINEMA_2K24},
+ {2160, 24, VIDEO_FORMAT_DIGI_CINEMA_4K24},
+ {2160, 60, VIDEO_FORMAT_UHDTV_4K60},
+ {2160, 50, VIDEO_FORMAT_UHDTV_4K50},
+ {2160, 60, VIDEO_FORMAT_UHDTV_8K60},
+ {2160, 50, VIDEO_FORMAT_UHDTV_8K50},
+ {0, 0, 0},
+};
/*****************************************************************************
- * CloseDecoder: decoder destruction
+ * ResetPTStlb: Purge all entries in @p_dec@'s PTS-tlb
*****************************************************************************/
-static void CloseDecoder( vlc_object_t *p_this )
+static void ResetPTStlb( encoder_t *p_enc )
{
- decoder_t *p_dec = (decoder_t *)p_this;
- decoder_sys_t *p_sys = p_dec->p_sys;
-
- FreeFrameBuffer( p_sys->p_dirac );
- dirac_decoder_close( p_sys->p_dirac );
- free( p_sys );
+ encoder_sys_t *p_sys = p_enc->p_sys;
+ for( int i=0; i<PTS_TLB_SIZE; i++) {
+ p_sys->pts_tlb[i].i_empty = 1;
+ }
}
-/****************************************************************************
- * DecodeBlock: the whole thing
- ****************************************************************************
- * This function must be fed with complete frames.
- ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+/*****************************************************************************
+ * 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 )
{
- decoder_sys_t *p_sys = p_dec->p_sys;
- dirac_decoder_state_t state;
- picture_t *p_pic;
- block_t *p_block;
-
- if( !pp_block || !*pp_block ) return NULL;
-
- p_block = *pp_block;
-
- while( 1 )
- {
- state = dirac_parse( p_sys->p_dirac );
-
- switch( state )
- {
- case STATE_BUFFER:
- if( !p_block->i_buffer )
- {
- block_Release( p_block );
- return NULL;
- }
-
- msg_Dbg( p_dec, "STATE_BUFFER" );
- dirac_buffer( p_sys->p_dirac, p_block->p_buffer,
- p_block->p_buffer + p_block->i_buffer );
-
- p_block->i_buffer = 0;
- break;
-
- case STATE_SEQUENCE:
- {
- /* Initialize video output */
- uint8_t *buf[3];
-
- msg_Dbg( p_dec, "%dx%d, chroma %i, %f fps",
- p_sys->p_dirac->src_params.width,
- p_sys->p_dirac->src_params.height,
- p_sys->p_dirac->src_params.chroma,
- (float)p_sys->p_dirac->src_params.frame_rate.numerator/
- p_sys->p_dirac->src_params.frame_rate.denominator );
-
- FreeFrameBuffer( p_sys->p_dirac );
- buf[0] = malloc( p_sys->p_dirac->src_params.width *
- p_sys->p_dirac->src_params.height );
- buf[1] = malloc( p_sys->p_dirac->src_params.chroma_width *
- p_sys->p_dirac->src_params.chroma_height );
- buf[2] = malloc( p_sys->p_dirac->src_params.chroma_width *
- p_sys->p_dirac->src_params.chroma_height );
-
- dirac_set_buf( p_sys->p_dirac, buf, NULL );
- break;
- }
-
- case STATE_SEQUENCE_END:
- msg_Dbg( p_dec, "SEQUENCE_END" );
- FreeFrameBuffer( p_sys->p_dirac );
- break;
-
- case STATE_PICTURE_AVAIL:
- msg_Dbg( p_dec, "PICTURE_AVAIL : frame_num=%d",
- p_sys->p_dirac->frame_num );
+ encoder_sys_t *p_sys = p_enc->p_sys;
- /* Picture available for display */
- p_pic = GetNewPicture( p_dec );
- p_pic->date = p_block->i_pts > 0 ? p_block->i_pts : p_block->i_dts;
- p_pic->b_force = 1; // HACK
- return p_pic;
- break;
+ for( int i=0; i<PTS_TLB_SIZE; i++ ) {
+ if( p_sys->pts_tlb[i].i_empty ) {
- case STATE_INVALID:
- msg_Dbg( p_dec, "STATE_INVALID" );
- break;
+ p_sys->pts_tlb[i].u_pnum = u_pnum;
+ p_sys->pts_tlb[i].i_pts = i_pts;
+ p_sys->pts_tlb[i].i_empty = 0;
- default:
- break;
+ return;
}
}
- /* Never reached */
- return NULL;
+ msg_Err( p_enc, "Could not store PTS %"PRId64" for frame %u", i_pts, u_pnum );
}
/*****************************************************************************
- * encoder_sys_t : dirac encoder descriptor
+ * GetPicturePTS: Retrieve the PTS value for a particular picture number
*****************************************************************************/
-#define ENC_BUFSIZE 1024*1024
-struct encoder_sys_t
+static mtime_t GetPicturePTS( encoder_t *p_enc, uint32_t u_pnum )
{
- /*
- * Dirac properties
- */
- dirac_encoder_t *p_dirac;
- dirac_encoder_context_t ctx;
+ encoder_sys_t *p_sys = p_enc->p_sys;
- uint8_t *p_buffer_in;
- int i_buffer_in;
+ for( int i=0; i<PTS_TLB_SIZE; i++ ) {
+ if( (!p_sys->pts_tlb[i].i_empty) &&
+ (p_sys->pts_tlb[i].u_pnum == u_pnum)) {
- uint8_t p_buffer_out[ENC_BUFSIZE];
-};
+ p_sys->pts_tlb[i].i_empty = 1;
+ return p_sys->pts_tlb[i].i_pts;
+ }
+ }
+
+ msg_Err( p_enc, "Could not retrieve PTS for picture %u", u_pnum );
+ return 0;
+}
/*****************************************************************************
* OpenEncoder: probe the encoder and return score
@@ -325,7 +434,6 @@ 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;
vlc_value_t val;
- float f_quality;
if( p_enc->fmt_out.i_codec != VLC_FOURCC('d','r','a','c') &&
!p_enc->b_force )
@@ -337,58 +445,321 @@ static int OpenEncoder( vlc_object_t *p_this )
if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
return VLC_ENOMEM;
memset( p_sys, 0, sizeof(encoder_sys_t) );
- p_enc->p_sys = p_sys;
+ p_sys->p_dts_fifo = block_FifoNew();
+
+ p_enc->p_sys = p_sys;
p_enc->pf_encode_video = Encode;
- p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
- p_enc->fmt_in.video.i_bits_per_pixel = 12;
p_enc->fmt_out.i_codec = VLC_FOURCC('d','r','a','c');
+ p_enc->fmt_out.i_cat = VIDEO_ES;
+
+ ResetPTStlb( p_enc );
+
+ /* guess the video format based upon number of lines and picture height */
+ int i = 0;
+ VideoFormat guessed_video_fmt = VIDEO_FORMAT_CUSTOM;
+ do {
+ if( dirac_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( dirac_format_guess[i].i_approx_fps - src_fps );
+ if( delta_fps > 2 )
+ continue;
+
+ guessed_video_fmt = dirac_format_guess[i].i_vf;
+ break;
+ } while( dirac_format_guess[++i].i_height );
- config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
+ dirac_encoder_context_init( &p_sys->ctx, guessed_video_fmt );
- dirac_encoder_context_init( &p_sys->ctx, VIDEO_FORMAT_CUSTOM );
- /* */
+ /* constants set from the input video format */
p_sys->ctx.src_params.width = p_enc->fmt_in.video.i_width;
p_sys->ctx.src_params.height = p_enc->fmt_in.video.i_height;
- p_sys->ctx.src_params.chroma = format420;
- /* */
- p_sys->ctx.src_params.frame_rate.numerator =
- p_enc->fmt_in.video.i_frame_rate;
- p_sys->ctx.src_params.frame_rate.denominator =
- p_enc->fmt_in.video.i_frame_rate_base;
- p_sys->ctx.src_params.source_sampling = 0;
- p_sys->ctx.src_params.topfieldfirst = 0;
-
- var_Get( p_enc, ENC_CFG_PREFIX "quality", &val );
- f_quality = val.f_float;
- if( f_quality > 10 ) f_quality = 10;
- if( f_quality < 1 ) f_quality = 1;
- p_sys->ctx.enc_params.qf = f_quality;
-
- /* Initialise the encoder with the encoder context */
- p_sys->p_dirac = dirac_encoder_init( &p_sys->ctx, 0 );
+ p_sys->ctx.src_params.frame_rate.numerator = p_enc->fmt_in.video.i_frame_rate;
+ p_sys->ctx.src_params.frame_rate.denominator = p_enc->fmt_in.video.i_frame_rate_base;
+ vlc_ureduce( (unsigned*) &p_sys->ctx.src_params.pix_asr.numerator,
+ (unsigned*) &p_sys->ctx.src_params.pix_asr.denominator,
+ p_enc->fmt_in.video.i_height * p_enc->fmt_in.video.i_aspect,
+ p_enc->fmt_in.video.i_width * VOUT_ASPECT_FACTOR,
+ 0 );
+
+ config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_CHROMAFMT, &val );
+ if ( !val.psz_string ) {}
+ else if ( !strcmp( val.psz_string, "420" ) ) {
+ p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
+ p_enc->fmt_in.video.i_bits_per_pixel = 12;
+ p_sys->ctx.src_params.chroma = format420;
+ p_sys->i_buffer_in = p_enc->fmt_in.video.i_width * p_enc->fmt_in.video.i_height * 3 / 2;
+ }
+ else if ( !strcmp( val.psz_string, "422" ) ) {
+ p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','2');
+ p_enc->fmt_in.video.i_bits_per_pixel = 16;
+ p_sys->ctx.src_params.chroma = format422;
+ p_sys->i_buffer_in = p_enc->fmt_in.video.i_width * p_enc->fmt_in.video.i_height * 2;
+ }
+ else if ( !strcmp( val.psz_string, "444" ) ) {
+ p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','4','4');
+ p_enc->fmt_in.video.i_bits_per_pixel = 24;
+ p_sys->ctx.src_params.chroma = format444;
+ p_sys->i_buffer_in = p_enc->fmt_in.video.i_width * p_enc->fmt_in.video.i_height * 3;
+ }
+ if( val.psz_string )
+ free( val.psz_string );
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_QUALITY_FACTOR, &val );
+ p_sys->ctx.enc_params.qf = val.f_float;
+
+ /* use bitrate from sout-transcode-vb in kbps */
+ p_sys->ctx.enc_params.trate = p_enc->fmt_out.i_bitrate / 1000;
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_TARGETRATE, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.trate = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_LOSSLESS, &val );
+ p_sys->ctx.enc_params.lossless = val.b_bool;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_PREFILTER, &val );
+ if ( !val.psz_string ) {}
+ else if ( !strcmp( val.psz_string, "none" ) ) {
+ p_sys->ctx.enc_params.prefilter = NO_PF;
+ }
+ else if ( !strcmp( val.psz_string, "cwm" ) ) {
+ p_sys->ctx.enc_params.prefilter = CWM;
+ }
+ else if ( !strcmp( val.psz_string, "rectlp" ) ) {
+ p_sys->ctx.enc_params.prefilter = RECTLP;
+ }
+ else if ( !strcmp( val.psz_string, "diaglp" ) ) {
+ p_sys->ctx.enc_params.prefilter = DIAGLP;
+ }
+ if( val.psz_string )
+ free( val.psz_string );
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_PREFILTER_STRENGTH, &val );
+ p_sys->ctx.enc_params.prefilter_strength = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_L1SEP, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.L1_sep = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_L1NUM, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.num_L1 = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_CODINGMODE, &val );
+ if ( !val.psz_string ) {}
+ else if ( !strcmp( val.psz_string, "auto" ) ) {
+ p_sys->b_auto_field_coding = 1;
+ }
+ else if ( !strcmp( val.psz_string, "progressive" ) ) {
+ p_sys->b_auto_field_coding = 0;
+ p_sys->ctx.enc_params.picture_coding_mode = 0;
+ }
+ else if ( !strcmp( val.psz_string, "field" ) ) {
+ p_sys->b_auto_field_coding = 0;
+ p_sys->ctx.enc_params.picture_coding_mode = 1;
+ }
+ if( val.psz_string )
+ free( val.psz_string );
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MVPREC, &val );
+ if ( !val.psz_string ) {}
+ else if ( !strcmp( val.psz_string, "1" ) ) {
+ p_sys->ctx.enc_params.mv_precision = MV_PRECISION_PIXEL;
+ }
+ else if ( !strcmp( val.psz_string, "1/2" ) ) {
+ p_sys->ctx.enc_params.mv_precision = MV_PRECISION_HALF_PIXEL;
+ }
+ else if ( !strcmp( val.psz_string, "1/4" ) ) {
+ p_sys->ctx.enc_params.mv_precision = MV_PRECISION_QUARTER_PIXEL;
+ }
+ else if ( !strcmp( val.psz_string, "1/8" ) ) {
+ p_sys->ctx.enc_params.mv_precision = MV_PRECISION_EIGHTH_PIXEL;
+ }
+ if( val.psz_string )
+ free( val.psz_string );
+
+ /*
+ * {x,y}b{len,sep} must be multiples of 4
+ */
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MCBLK_WIDTH, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.xbsep = val.i_int / 4 * 4;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MCBLK_HEIGHT, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.ybsep = val.i_int / 4 * 4;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MCBLK_HOVERLAP, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.xblen = p_sys->ctx.enc_params.xbsep * (100 + val.i_int) / 400 * 4;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MCBLK_VOVERLAP, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.yblen = p_sys->ctx.enc_params.ybsep * (100 + val.i_int) / 400 * 4;
+
+ /*
+ * {x,y}blen >= {x,y}bsep
+ * {x,y}blen <= 2* {x,y}bsep
+ */
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MCBLK_XBLEN, &val );
+ if( val.i_int > -1 ) {
+ int xblen = __MAX( val.i_int, p_sys->ctx.enc_params.xbsep );
+ xblen = __MIN( xblen, 2 * p_sys->ctx.enc_params.xbsep );
+ p_sys->ctx.enc_params.xblen = xblen;
+ }
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MCBLK_YBLEN, &val );
+ if( val.i_int > -1 ) {
+ int yblen = __MAX( val.i_int, p_sys->ctx.enc_params.ybsep );
+ yblen = __MIN( yblen, 2 * p_sys->ctx.enc_params.ybsep );
+ p_sys->ctx.enc_params.yblen = yblen;
+ }
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_ME_SIMPLESEARCH, &val );
+ if( val.psz_string && *val.psz_string != '\0' ) {
+ /* of the form [0-9]+:[0-9]+ */
+ char *psz_start = val.psz_string;
+ char *psz_end = val.psz_string;
+ p_sys->ctx.enc_params.x_range_me = strtol(psz_start, &psz_end, 10);
+ if( *psz_end != ':' || psz_end == val.psz_string ) {
+ msg_Err( p_enc, "Invalid simple search range: %s", val.psz_string );
+ free( val.psz_string );
+ goto error;
+ }
+ psz_start = ++psz_end;
+ p_sys->ctx.enc_params.y_range_me = strtol(psz_start, &psz_end, 10);
+ if( *psz_end != '\0' || psz_end == psz_start ) {
+ msg_Err( p_enc, "Invalid simple search range: %s", val.psz_string );
+ free( val.psz_string );
+ goto error;
+ }
+ if( p_sys->ctx.enc_params.x_range_me < 0 ||
+ p_sys->ctx.enc_params.y_range_me < 0 )
+ {
+ msg_Err( p_enc, "Invalid negative simple search range: %s", val.psz_string );
+ free( val.psz_string );
+ goto error;
+ }
+ p_sys->ctx.enc_params.full_search = 1;
+ free( val.psz_string );
+ }
+
+#if DIRAC_RESEARCH_VERSION_ATLEAST(1,0,1)
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_ME_COMBINED, &val );
+ p_sys->ctx.enc_params.combined_me = val.b_bool;
+#endif
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_DWTINTRA, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.intra_wlt_filter = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_DWTINTER, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.inter_wlt_filter = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_DWTDEPTH, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.wlt_depth = val.i_int;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_MULTIQUANT, &val );
+ if( val.b_bool > -1 )
+ p_sys->ctx.enc_params.multi_quants = val.b_bool;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_SPARTITION, &val );
+ if( val.b_bool > -1 )
+ p_sys->ctx.enc_params.spatial_partition = val.b_bool;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_VLC, &val );
+ p_sys->ctx.enc_params.using_ac = !val.b_bool;
+
+ var_Get( p_enc, ENC_CFG_PREFIX ENC_CPD, &val );
+ if( val.i_int > -1 )
+ p_sys->ctx.enc_params.cpd = val.i_int;
/* Set the buffer size for the encoded picture */
- p_sys->i_buffer_in = p_enc->fmt_in.video.i_width *
- p_enc->fmt_in.video.i_height * 3 / 2;
p_sys->p_buffer_in = malloc( p_sys->i_buffer_in );
return VLC_SUCCESS;
+error:
+ if( p_sys )
+ CloseEncoder( p_this );
+ return VLC_EGENERIC;
+}
+
+/* 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 );
+ if (u_npo == 0)
+ u_npo = 13;
+ u_pos += u_npo;
+ }
+ return 0;
}
/****************************************************************************
* Encode: the whole thing
****************************************************************************
- * This function spits out ogg packets.
+ * This function spits out encapsulation units.
****************************************************************************/
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_chain = NULL;
+ block_t *p_block, *p_output_chain = NULL;
int i_plane, i_line, i_width, i_src_stride;
uint8_t *p_dst;
- /* Copy input picture in encoder input buffer (stride by stride) */
+ /* 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->ctx.src_params.topfieldfirst = p_pic->b_top_field_first;
+ p_sys->ctx.src_params.source_sampling = !p_pic->b_progressive;
+
+ if( p_sys->b_auto_field_coding )
+ p_sys->ctx.enc_params.picture_coding_mode = !p_pic->b_progressive;
+
+ if( !p_sys->p_dirac )
+ {
+ date_t date;
+ /* Initialise the encoder with the encoder context */
+ p_sys->p_dirac = dirac_encoder_init( &p_sys->ctx, 0 );
+ if( !p_sys->p_dirac )
+ {
+ msg_Err( p_enc, "Failed to initialize dirac encoder\n" );
+ p_enc->b_error = 1;
+ }
+ date_Init( &date, p_enc->fmt_in.video.i_frame_rate, p_enc->fmt_in.video.i_frame_rate_base );
+#if DIRAC_RESEARCH_VERSION_ATLEAST(1,0,2)
+ int i_delayinpics = dirac_encoder_ptsoffset( p_sys->p_dirac );
+ i_delayinpics /= p_sys->ctx.enc_params.picture_coding_mode + 1;
+ date_Increment( &date, i_delayinpics );
+#else
+ date_Increment( &date, 1 );
+#endif
+ p_sys->i_pts_offset = date_Get( &date );
+
+ if( 1 == p_sys->ctx.enc_params.picture_coding_mode ) {
+ date_Set( &date, 0 );
+ date_Increment( &date, 1 );
+ p_sys->i_field_time = date_Get( &date ) / 2;
+ }
+ }
+
+ /* Copy input picture into encoder input buffer (stride by stride) */
+ /* Would be lovely to just pass the picture in, but there is noway for the
+ * library to free it */
p_dst = p_sys->p_buffer_in;
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
@@ -406,59 +777,109 @@ static block_t *Encode( encoder_t *p_enc, picture_t *p_pic )
/* Load one frame of data into encoder */
if( dirac_encoder_load( p_sys->p_dirac, p_sys->p_buffer_in,
- p_sys->i_buffer_in ) >= 0 )
+ p_sys->i_buffer_in ) < 0 )
{
- dirac_encoder_state_t state;
-
- msg_Dbg( p_enc, "dirac_encoder_load" );
+ msg_Dbg( p_enc, "dirac_encoder_load() error" );
+ return NULL;
+ }
- /* Retrieve encoded frames from encoder */
- do
- {
- p_sys->p_dirac->enc_buf.buffer = p_sys->p_buffer_out;
- p_sys->p_dirac->enc_buf.size = ENC_BUFSIZE;
- state = dirac_encoder_output( p_sys->p_dirac );
- msg_Dbg( p_enc, "dirac_encoder_output: %i", state );
- switch( state )
- {
- case ENC_STATE_AVAIL:
- // Encoded frame available in encoder->enc_buf
- // Encoded frame params available in enccoder->enc_fparams
- // Encoded frame stats available in enccoder->enc_fstats
- p_block = block_New( p_enc, p_sys->p_dirac->enc_buf.size );
- memcpy( p_block->p_buffer, p_sys->p_dirac->enc_buf.buffer,
- p_sys->p_dirac->enc_buf.size );
- p_block->i_dts = p_block->i_pts = p_pic->date;
- block_ChainAppend( &p_chain, p_block );
-
- break;
- case ENC_STATE_BUFFER:
- break;
- case ENC_STATE_INVALID:
- default:
- break;
- }
- if( p_sys->p_dirac->decoded_frame_avail )
- {
- //locally decoded frame is available in
- //encoder->dec_buf
- //locally decoded frame parameters available
- //in encoder->dec_fparams
- }
- if( p_sys->p_dirac->instr_data_avail )
- {
- //Instrumentation data (motion vectors etc.)
- //available in encoder->instr
- }
-
- } while( state == ENC_STATE_AVAIL );
+ /* 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 );
+ 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( 1 == p_sys->ctx.enc_params.picture_coding_mode ) {
+ 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 );
+ 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;
}
- else
+
+ dirac_encoder_state_t state;
+ /* Retrieve encoded frames from encoder */
+ do
{
- msg_Dbg( p_enc, "dirac_encoder_load() error" );
- }
+ p_sys->p_dirac->enc_buf.buffer = p_sys->p_buffer_out;
+ p_sys->p_dirac->enc_buf.size = ENC_BUFSIZE;
+ state = dirac_encoder_output( p_sys->p_dirac );
+ switch( state )
+ {
+ case ENC_STATE_AVAIL: {
+ uint32_t pic_num;
+
+ /* extract data from encoder temporary buffer. */
+ p_block = block_New( p_enc, p_sys->p_dirac->enc_buf.size );
+ memcpy( p_block->p_buffer, p_sys->p_dirac->enc_buf.buffer,
+ p_sys->p_dirac->enc_buf.size );
+
+ /* if some flags were set for a previous block, prevent
+ * them from getting lost */
+ if( p_sys->p_chain )
+ p_block->i_flags |= p_sys->p_chain->i_flags;
+
+ /* store all extracted blocks in a chain and gather up when an
+ * entire encapsulation unit is avaliable (ends with a picture) */
+ block_ChainAppend( &p_sys->p_chain, p_block );
+
+ /* 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) );
+ memcpy( p_enc->fmt_out.p_extra, p_block->p_buffer, len);
+ memcpy( p_enc->fmt_out.p_extra + len, eos, sizeof(eos) );
+ SetDWBE( p_enc->fmt_out.p_extra + len + 10, len );
+ p_enc->fmt_out.i_extra = len + sizeof(eos);
+ }
+ }
+
+ if( ReadDiracPictureNumber( &pic_num, p_block ) ) {
+ /* Finding a picture terminates an ecapsulation unit, gather
+ * all data and output; use the next dts value queued up
+ * and find correct pts in the tlb */
+ p_block = block_FifoGet( p_sys->p_dts_fifo );
+ p_sys->p_chain->i_dts = p_block->i_dts;
+ p_sys->p_chain->i_pts = GetPicturePTS( p_enc, pic_num );
+ block_Release( p_block );
+ block_ChainAppend( &p_output_chain, block_ChainGather( p_sys->p_chain ) );
+ p_sys->p_chain = NULL;
+ } else {
+ p_block = NULL;
+ }
+ break;
+ }
+
+ case ENC_STATE_BUFFER:
+ break;
+ case ENC_STATE_INVALID:
+ default:
+ break;
+ }
+ } while( state == ENC_STATE_AVAIL );
- return p_chain;
+ return p_output_chain;
}
/*****************************************************************************
@@ -469,12 +890,15 @@ 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;
- msg_Dbg( p_enc, "resulting bit-rate: %lld bits/sec",
- p_sys->p_dirac->enc_seqstats.bit_rate );
-
/* Free the encoder resources */
- dirac_encoder_close( p_sys->p_dirac );
-
- free( p_sys->p_buffer_in );
+ if( p_sys->p_dirac )
+ dirac_encoder_close( p_sys->p_dirac );
+
+ if( p_sys->p_buffer_in )
+ free( p_sys->p_buffer_in );
+
+ block_FifoRelease( p_sys->p_dts_fifo );
+ block_ChainRelease( p_sys->p_chain );
+
free( p_sys );
}
--
1.5.6.5
More information about the vlc-devel
mailing list