]> git.sesse.net Git - vlc/blobdiff - modules/codec/dirac.c
Spell "separate"
[vlc] / modules / codec / dirac.c
index cb5d8b543613f7651947a4d0f29e92389486562e..ef0ad318aa2215d13f9fe21f2c7ac28e1a2eb00d 100644 (file)
@@ -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@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
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <limits.h>
+#include <assert.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-"
 
-static const char *ppsz_enc_options[] = {
-    "quality", NULL
+#define ENC_QUALITY_FACTOR "quality"
+#define ENC_QUALITY_FACTOR_TEXT N_("Constant quality factor")
+#define ENC_QUALITY_FACTOR_LONGTEXT N_("If bitrate=0, use this value for constant quality")
+
+#define ENC_TARGETRATE "bitrate"
+#define ENC_TARGETRATE_TEXT N_("CBR bitrate (kbps)")
+#define ENC_TARGETRATE_LONGTEXT N_("A value > 0 enables constant bitrate mode")
+
+#define ENC_LOSSLESS "lossless"
+#define ENC_LOSSLESS_TEXT N_("Enable lossless coding")
+#define ENC_LOSSLESS_LONGTEXT N_("Lossless coding ignores bitrate and quality settings, " \
+                                 "allowing for perfect reproduction of the original")
+
+#define ENC_PREFILTER "prefilter"
+#define ENC_PREFILTER_TEXT N_("Prefilter")
+#define ENC_PREFILTER_LONGTEXT N_("Enable adaptive prefiltering")
+static const char *const enc_prefilter_list[] =
+  { "none", "cwm", "rectlp", "diaglp" };
+static const char *const enc_prefilter_list_text[] =
+  { N_("none"), N_("Centre Weighted Median"),
+    N_("Rectangular Linear Phase"), N_("Diagonal Linear Phase") };
+
+#define ENC_PREFILTER_STRENGTH "prefilter-strength"
+#define ENC_PREFILTER_STRENGTH_TEXT N_("Amount of prefiltering")
+#define ENC_PREFILTER_STRENGTH_LONGTEXT N_("Higher value implies more prefiltering")
+
+#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_L1SEP "l1-sep"
+#define ENC_L1SEP_TEXT N_("Distance between 'P' frames")
+#define ENC_L1SEP_LONGTEXT ENC_L1SEP_TEXT
+
+#define ENC_L1NUM "num-l1"
+#define ENC_L1NUM_TEXT N_("Number of 'P' frames per GOP")
+#define ENC_L1NUM_LONGTEXT ENC_L1NUM_TEXT
+
+#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"),
+  };
+
+#define ENC_MCBLK_WIDTH "mc-blk-width"
+#define ENC_MCBLK_WIDTH_TEXT N_("Width of motion compensation blocks")
+#define ENC_MCBLK_WIDTH_LONGTEXT ""
+
+#define ENC_MCBLK_HEIGHT "mc-blk-height"
+#define ENC_MCBLK_HEIGHT_TEXT N_("Height of motion compensation blocks")
+#define ENC_MCBLK_HEIGHT_LONGTEXT ""
+
+/* also known as XBSEP and YBSEP */
+#define ENC_MCBLK_OVERLAP "mc-blk-overlap"
+#define ENC_MCBLK_OVERLAP_TEXT N_("Block overlap (%)")
+#define ENC_MCBLK_OVERLAP_LONGTEXT N_("Amount that each motion block should " \
+                                       "be overlapped by its neighbours")
+
+/* advanced option only */
+#define ENC_MCBLK_XBLEN "mc-blk-xblen"
+#define ENC_MCBLK_XBLEN_TEXT N_("xblen")
+#define ENC_MCBLK_XBLEN_LONGTEXT N_("Total horizontal block length including overlaps")
+
+/* advanded option only */
+#define ENC_MCBLK_YBLEN "mc-blk-yblen"
+#define ENC_MCBLK_YBLEN_TEXT N_("yblen")
+#define ENC_MCBLK_YBLEN_LONGTEXT N_("Total vertical block length including overlaps")
+
+#define ENC_MVPREC "mv-prec"
+#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" };
+
+#define ENC_ME_SIMPLESEARCH "me-simple-search"
+#define ENC_ME_SIMPLESEARCH_TEXT N_("Simple ME search area x:y")
+#define ENC_ME_SIMPLESEARCH_LONGTEXT N_("(Not recommended) Perform a simple (non hierarchical " \
+                                        "block matching motion vector search with search range " \
+                                        "of +/-x, +/-y")
+
+#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 "dwt-intra"
+#define ENC_DWTINTRA_TEXT N_("Intra picture DWT filter")
+#define ENC_DWTINTRA_LONGTEXT ENC_DWTINTRA_TEXT
+
+#define ENC_DWTINTER "dwt-inter"
+#define ENC_DWTINTER_TEXT N_("Inter picture DWT filter")
+#define ENC_DWTINTER_LONGTEXT ENC_DWTINTER_TEXT
+
+#define ENC_DWTDEPTH "dwt-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 "multi-quant"
+#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_SPARTITION "spartition"
+#define ENC_SPARTITION_TEXT N_("Enable spatial partitioning")
+#define ENC_SPARTITION_LONGTEXT ENC_SPARTITION_TEXT
+
+#define ENC_NOAC "noac"
+#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_CPD "cpd"
+#define ENC_CPD_TEXT N_("cycles per degree")
+#define ENC_CPD_LONGTEXT ENC_CPD_TEXT
+
+static const char *const ppsz_enc_options[] = {
+    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_OVERLAP,
+    ENC_MVPREC, ENC_ME_SIMPLESEARCH, ENC_ME_COMBINED,
+    ENC_DWTINTRA, ENC_DWTINTER, ENC_DWTDEPTH,
+    ENC_MULTIQUANT, ENC_SPARTITION, ENC_NOAC,
+    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();
-    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_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();
+
+vlc_module_begin()
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_VCODEC )
+    set_description( N_("Dirac video encoder using dirac-research library") )
+    set_shortname( "Dirac" )
+    set_capability( "encoder", 100 )
+    set_callbacks( OpenEncoder, CloseEncoder )
+
+    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(-1, 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(-1, INT_MAX);
+
+    add_integer( ENC_CFG_PREFIX ENC_L1NUM, -1, NULL,
+                 ENC_L1NUM_TEXT, ENC_L1NUM_LONGTEXT, false )
+    change_integer_range(-1, 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 )
+    change_integer_range(-1, INT_MAX);
+
+    add_integer( ENC_CFG_PREFIX ENC_MCBLK_HEIGHT, -1, NULL,
+                 ENC_MCBLK_HEIGHT, ENC_MCBLK_HEIGHT_LONGTEXT, false )
+    change_integer_range(-1, INT_MAX);
+
+    add_integer( ENC_CFG_PREFIX ENC_MCBLK_OVERLAP, -1, NULL,
+                 ENC_MCBLK_OVERLAP_TEXT, ENC_MCBLK_OVERLAP_LONGTEXT, false )
+    change_integer_range(-1, 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(-1, 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(-1, 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
+
+    add_integer( ENC_CFG_PREFIX ENC_DWTINTRA, -1, NULL,
+                 ENC_DWTINTRA_TEXT, ENC_DWTINTRA_LONGTEXT, false )
+    change_integer_range(-1, 6);
+
+    add_integer( ENC_CFG_PREFIX ENC_DWTINTER, -1, NULL,
+                 ENC_DWTINTER_TEXT, ENC_DWTINTER_LONGTEXT, false )
+    change_integer_range(-1, 6);
+
+    add_integer( ENC_CFG_PREFIX ENC_DWTDEPTH, -1, NULL,
+                 ENC_DWTDEPTH_TEXT, ENC_DWTDEPTH_LONGTEXT, false )
+    change_integer_range(-1, 4);
+
+    /* advanced option only */
+    /* NB, unforunately vlc doesn't have a concept of 'dont care' */
+    add_integer( ENC_CFG_PREFIX ENC_MULTIQUANT, -1, NULL,
+                 ENC_MULTIQUANT_TEXT, ENC_MULTIQUANT_LONGTEXT, true )
+    change_integer_range(-1, 1);
+
+    /* advanced option only */
+    /* NB, unforunately vlc doesn't have a concept of 'dont care' */
+    add_integer( ENC_CFG_PREFIX ENC_SPARTITION, -1, NULL,
+                 ENC_SPARTITION_TEXT, ENC_SPARTITION_LONGTEXT, true )
+    change_integer_range(-1, 1);
+
+    add_bool( ENC_CFG_PREFIX ENC_NOAC, false, NULL,
+              ENC_NOAC_TEXT, ENC_NOAC_LONGTEXT, false )
+
+    /* advanced option only */
+    add_float( ENC_CFG_PREFIX ENC_CPD, -1, NULL,
+               ENC_CPD_TEXT, ENC_CPD_LONGTEXT, true )
+    change_integer_range(-1, INT_MAX);
+vlc_module_end()
 
 /*****************************************************************************
- * OpenDecoder: probe the decoder and return score
+ * picture_pts_t : store pts alongside picture number, not carried through
+ * encoder
  *****************************************************************************/
-static int OpenDecoder( vlc_object_t *p_this )
+struct picture_pts_t
 {
-    decoder_t *p_dec = (decoder_t*)p_this;
-    decoder_sys_t *p_sys;
-    dirac_decoder_t *p_dirac;
-
-    if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','r','a','c') )
-    {
-        return VLC_EGENERIC;
-    }
+   bool b_empty;      /* entry is invalid */
+   uint32_t u_pnum;  /* dirac picture number */
+   mtime_t i_pts;    /* associated pts */
+};
 
-    /* Initialise the dirac decoder */
-    if( !(p_dirac = dirac_decoder_init(0)) ) return VLC_EGENERIC;
+/*****************************************************************************
+ * encoder_sys_t : dirac encoder descriptor
+ *****************************************************************************/
+#define PTS_TLB_SIZE 256
+struct encoder_sys_t
+{
+    dirac_encoder_t *p_dirac;
+    dirac_encoder_context_t ctx;
+    bool b_auto_field_coding;
 
-    /* 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;
+    uint8_t *p_buffer_in;
+    int i_buffer_in;
+    uint32_t i_input_picnum;
+    block_fifo_t *p_dts_fifo;
 
-    p_sys->p_dirac = p_dirac;
+    int i_buffer_out;
+    uint8_t *p_buffer_out;
+    block_t *p_chain;
 
-    /* Set output properties */
-    p_dec->fmt_out.i_cat = VIDEO_ES;
-    p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');
+    struct picture_pts_t pts_tlb[PTS_TLB_SIZE];
+    mtime_t i_pts_offset;
+    mtime_t i_field_time;
+};
 
-    /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+static struct
+{
+    unsigned int i_height;
+    int i_approx_fps;
+    VideoFormat i_vf;
+} dirac_format_guess[] = {
+    /* Important: Keep this list ordered in ascending picture height */
+    {1, 0, VIDEO_FORMAT_CUSTOM},
+    {120, 15, VIDEO_FORMAT_QSIF525},
+    {144, 12, VIDEO_FORMAT_QCIF},
+    {240, 15, VIDEO_FORMAT_SIF525},
+    {288, 12, VIDEO_FORMAT_CIF},
+    {480, 30, VIDEO_FORMAT_SD_480I60},
+    {480, 15, VIDEO_FORMAT_4SIF525},
+    {576, 12, VIDEO_FORMAT_4CIF},
+    {576, 25, VIDEO_FORMAT_SD_576I50},
+    {720, 50, VIDEO_FORMAT_HD_720P50},
+    {720, 60, VIDEO_FORMAT_HD_720P60},
+    {1080, 24, VIDEO_FORMAT_DIGI_CINEMA_2K24},
+    {1080, 25, VIDEO_FORMAT_HD_1080I50},
+    {1080, 30, VIDEO_FORMAT_HD_1080I60},
+    {1080, 50, VIDEO_FORMAT_HD_1080P50},
+    {1080, 60, VIDEO_FORMAT_HD_1080P60},
+    {2160, 24, VIDEO_FORMAT_DIGI_CINEMA_4K24},
+    {2160, 50, VIDEO_FORMAT_UHDTV_4K50},
+    {2160, 60, VIDEO_FORMAT_UHDTV_4K60},
+    {3840, 50, VIDEO_FORMAT_UHDTV_8K50},
+    {3840, 60, VIDEO_FORMAT_UHDTV_8K60},
+    {0, 0, 0},
+};
 
-    return VLC_SUCCESS;
+/*****************************************************************************
+ * ResetPTStlb: Purge all entries in @p_dec@'s PTS-tlb
+ *****************************************************************************/
+static void ResetPTStlb( encoder_t *p_enc )
+{
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    for( int i=0; i<PTS_TLB_SIZE; i++)
+    {
+        p_sys->pts_tlb[i].b_empty = true;
+    }
 }
 
-static void FreeFrameBuffer( dirac_decoder_t *p_dirac )
+/*****************************************************************************
+ * 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 )
 {
-    if( p_dirac->fbuf )
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    for( int i=0; i<PTS_TLB_SIZE; i++ )
     {
-        int i;
-        for( i = 0; i < 3; i++ )
+        if( p_sys->pts_tlb[i].b_empty )
         {
-            free( p_dirac->fbuf->buf[i] );
-            p_dirac->fbuf->buf[i] = 0;
+            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 );
 }
 
 /*****************************************************************************
- * GetNewPicture: Get a new picture from the vout and copy the decoder output
+ * GetPicturePTS: Retrieve the PTS value for a particular picture number
  *****************************************************************************/
-static picture_t *GetNewPicture( decoder_t *p_dec )
+static mtime_t GetPicturePTS( encoder_t *p_enc, uint32_t u_pnum )
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    picture_t *p_pic;
-    int i_plane;
+    encoder_sys_t *p_sys = p_enc->p_sys;
 
-    switch( p_sys->p_dirac->src_params.chroma )
+    for( int i=0; i<PTS_TLB_SIZE; i++ )
     {
-    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;
+        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;
+        }
     }
 
-    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;
+    msg_Err( p_enc, "Could not retrieve PTS for picture %u", u_pnum );
+    return 0;
+}
+
+/*****************************************************************************
+ * 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;
 
-    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;
+    if( p_enc->fmt_out.i_codec != VLC_CODEC_DIRAC &&
+        !p_enc->b_force )
+    {
+        return VLC_EGENERIC;
+    }
 
-    /* Get a new picture */
-    p_pic = p_dec->pf_vout_buffer_new( p_dec );
+    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;
+    }
 
-    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;
+    /* Allocate the memory needed to store the decoder's structure */
+    if( ( p_sys = calloc( 1, sizeof(*p_sys) ) ) == NULL )
+        return VLC_ENOMEM;
 
-    p_pic->i_nb_fields = 2;
+    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;
 
-    /* Copy picture stride by stride */
-    for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
+    if( ( p_sys->p_dts_fifo = block_FifoNew() ) == NULL )
     {
-        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;
+        CloseEncoder( p_this );
+        return VLC_ENOMEM;
+    }
 
-        i_width = p_pic->p[i_plane].i_visible_pitch;
-        i_dst_stride = p_pic->p[i_plane].i_pitch;
+    ResetPTStlb( p_enc );
 
-        for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ )
+    /* guess the video format based upon number of lines and picture height */
+    int i = 0;
+    VideoFormat guessed_video_fmt = 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( dirac_format_guess[i].i_height > p_enc->fmt_in.video.i_height )
         {
-            vlc_memcpy( p_dst, p_src, i_width );
-            p_src += i_width;
-            p_dst += i_dst_stride;
+            guessed_video_fmt = dirac_format_guess[i-1].i_vf;
+            break;
         }
-    }
+        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 );
 
-    return p_pic;
-}
+    dirac_encoder_context_init( &p_sys->ctx, guessed_video_fmt );
 
-/*****************************************************************************
- * CloseDecoder: decoder destruction
- *****************************************************************************/
-static void CloseDecoder( vlc_object_t *p_this )
-{
-    decoder_t *p_dec = (decoder_t *)p_this;
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    /* 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.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;
+    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->ctx.src_params.pix_asr.numerator = u_asr_num;
+    p_sys->ctx.src_params.pix_asr.denominator = u_asr_den;
 
-    FreeFrameBuffer( p_sys->p_dirac );
-    dirac_decoder_close( p_sys->p_dirac );
-    free( p_sys );
-}
+    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
 
-/****************************************************************************
- * DecodeBlock: the whole thing
- ****************************************************************************
- * This function must be fed with complete frames.
- ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    dirac_decoder_state_t state;
-    picture_t *p_pic;
-    block_t *p_block;
+    psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_CHROMAFMT );
+    if( !psz_tmp )
+        goto error;
+    else if( !strcmp( psz_tmp, "420" ) ) {
+        p_enc->fmt_in.i_codec = VLC_CODEC_I420;
+        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( psz_tmp, "422" ) ) {
+        p_enc->fmt_in.i_codec = VLC_CODEC_I422;
+        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( psz_tmp, "444" ) ) {
+        p_enc->fmt_in.i_codec = VLC_CODEC_I444;
+        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;
+    }
+    else {
+        msg_Err( p_enc, "Invalid chroma format: %s", psz_tmp );
+        free( psz_tmp );
+        goto error;
+    }
+    free( psz_tmp );
 
-    if( !pp_block || !*pp_block ) return NULL;
+    p_sys->ctx.enc_params.qf = var_GetFloat( p_enc, ENC_CFG_PREFIX ENC_QUALITY_FACTOR );
 
-    p_block = *pp_block;
+    /* use bitrate from sout-transcode-vb in kbps */
+    p_sys->ctx.enc_params.trate = p_enc->fmt_out.i_bitrate / 1000;
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_TARGETRATE );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.trate = i_tmp;
+    p_enc->fmt_out.i_bitrate = p_sys->ctx.enc_params.trate * 1000;
 
-    while( 1 )
-    {
-        state = dirac_parse( p_sys->p_dirac );
+    p_sys->ctx.enc_params.lossless = var_GetBool( p_enc, ENC_CFG_PREFIX ENC_LOSSLESS );
 
-        switch( state )
-        {
-        case STATE_BUFFER:
-            if( !p_block->i_buffer )
-            {
-                block_Release( p_block );
-                return NULL;
-            }
+    psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_PREFILTER );
+    if( !psz_tmp )
+        goto error;
+    else if( !strcmp( psz_tmp, "none" ) ) {
+        p_sys->ctx.enc_params.prefilter = NO_PF;
+    }
+    else if( !strcmp( psz_tmp, "cwm" ) ) {
+        p_sys->ctx.enc_params.prefilter = CWM;
+    }
+    else if( !strcmp( psz_tmp, "rectlp" ) ) {
+        p_sys->ctx.enc_params.prefilter = RECTLP;
+    }
+    else if( !strcmp( psz_tmp, "diaglp" ) ) {
+        p_sys->ctx.enc_params.prefilter = DIAGLP;
+    }
+    else {
+        msg_Err( p_enc, "Invalid prefilter: %s", psz_tmp );
+        free( psz_tmp );
+        goto error;
+    }
+    free( psz_tmp );
 
-            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_sys->ctx.enc_params.prefilter_strength =
+        var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_PREFILTER_STRENGTH );
 
-            p_block->i_buffer = 0;
-            break;
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_L1SEP );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.L1_sep = i_tmp;
 
-        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;
-        }
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_L1NUM );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.num_L1 = i_tmp;
 
-        case STATE_SEQUENCE_END:
-            msg_Dbg( p_dec, "SEQUENCE_END" );
-            FreeFrameBuffer( p_sys->p_dirac );
-            break;
+    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;
+        p_sys->ctx.enc_params.picture_coding_mode = 0;
+    }
+    else if( !strcmp( psz_tmp, "field" ) ) {
+        p_sys->b_auto_field_coding = false;
+        p_sys->ctx.enc_params.picture_coding_mode = 1;
+    }
+    else {
+        msg_Err( p_enc, "Invalid codingmode: %s", psz_tmp );
+        free( psz_tmp );
+        goto error;
+    }
+    free( psz_tmp );
 
-        case STATE_PICTURE_START:
-            msg_Dbg( p_dec, "PICTURE_START: frame_type=%i frame_num=%d",
-                     p_sys->p_dirac->frame_params.ftype,
-                     p_sys->p_dirac->frame_params.fnum );
-            break;
+    psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_MVPREC );
+    if( !psz_tmp )
+        goto error;
+    else if( !strcmp( psz_tmp, "1" ) ) {
+        p_sys->ctx.enc_params.mv_precision = MV_PRECISION_PIXEL;
+    }
+    else if( !strcmp( psz_tmp, "1/2" ) ) {
+        p_sys->ctx.enc_params.mv_precision = MV_PRECISION_HALF_PIXEL;
+    }
+    else if( !strcmp( psz_tmp, "1/4" ) ) {
+        p_sys->ctx.enc_params.mv_precision = MV_PRECISION_QUARTER_PIXEL;
+    }
+    else if( !strcmp( psz_tmp, "1/8" ) ) {
+        p_sys->ctx.enc_params.mv_precision = MV_PRECISION_EIGHTH_PIXEL;
+    }
+    else {
+        msg_Err( p_enc, "Invalid mv-prec: %s", psz_tmp );
+        free( psz_tmp );
+        goto error;
+    }
+    free( psz_tmp );
 
-        case STATE_PICTURE_AVAIL:
-            msg_Dbg( p_dec, "PICTURE_AVAI : frame_type=%i frame_num=%d",
-                     p_sys->p_dirac->frame_params.ftype,
-                     p_sys->p_dirac->frame_params.fnum );
+    /*
+     * {x,y}b{len,sep} must be multiples of 4
+     */
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MCBLK_WIDTH );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.xbsep = i_tmp / 4 * 4;
+
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MCBLK_HEIGHT );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.ybsep = i_tmp / 4 * 4;
+
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MCBLK_OVERLAP );
+    if( i_tmp > -1 ) {
+        p_sys->ctx.enc_params.xblen = p_sys->ctx.enc_params.xbsep * (100 + i_tmp) / 400 * 4;
+        p_sys->ctx.enc_params.yblen = p_sys->ctx.enc_params.ybsep * (100 + i_tmp) / 400 * 4;
+    }
 
-            /* 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;
+    /*
+     * {x,y}blen >= {x,y}bsep
+     * {x,y}blen <= 2* {x,y}bsep
+     */
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MCBLK_XBLEN );
+    if( i_tmp > -1 ) {
+        int xblen = __MAX( i_tmp, p_sys->ctx.enc_params.xbsep );
+        xblen = __MIN( xblen, 2 * p_sys->ctx.enc_params.xbsep );
+        p_sys->ctx.enc_params.xblen = xblen;
+    }
 
-        case STATE_INVALID:
-            msg_Dbg( p_dec, "STATE_INVALID" );
-            break;
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MCBLK_YBLEN );
+    if( i_tmp > -1 ) {
+        int yblen = __MAX( i_tmp, p_sys->ctx.enc_params.ybsep );
+        yblen = __MIN( yblen, 2 * p_sys->ctx.enc_params.ybsep );
+        p_sys->ctx.enc_params.yblen = yblen;
+    }
 
-        default:
-            break;
+    psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX ENC_ME_SIMPLESEARCH );
+    if( !psz_tmp )
+        goto error;
+    if( *psz_tmp != '\0' ) {
+        /* of the form [0-9]+:[0-9]+ */
+        char *psz_start = psz_tmp;
+        char *psz_end = psz_tmp;
+        p_sys->ctx.enc_params.x_range_me = strtol(psz_start, &psz_end, 10);
+        if( *psz_end != ':'  || psz_end == psz_start ) {
+            msg_Err( p_enc, "Invalid simple search range: %s", psz_tmp );
+            free( psz_tmp );
+            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", psz_tmp );
+            free( psz_tmp );
+            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", psz_tmp );
+            free( psz_tmp );
+            goto error;
+        }
+        p_sys->ctx.enc_params.full_search = 1;
     }
+    free( psz_tmp );
 
-    /* Never reached */
-    return NULL;
-}
+#if DIRAC_RESEARCH_VERSION_ATLEAST(1,0,1)
+    p_sys->ctx.enc_params.combined_me = var_GetBool( p_enc, ENC_CFG_PREFIX ENC_ME_COMBINED );
+#endif
 
-/*****************************************************************************
- * encoder_sys_t : dirac encoder descriptor
- *****************************************************************************/
-#define ENC_BUFSIZE 1024*1024
-struct encoder_sys_t
-{
-    /*
-     * Dirac properties
-     */
-    dirac_encoder_t *p_dirac;
-    dirac_encoder_context_t ctx;
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_DWTINTRA );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.intra_wlt_filter = i_tmp;
 
-    uint8_t *p_buffer_in;
-    int i_buffer_in;
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_DWTINTER );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.inter_wlt_filter = i_tmp;
 
-    uint8_t p_buffer_out[ENC_BUFSIZE];
-};
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_DWTDEPTH );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.wlt_depth = i_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;
-    vlc_value_t val;
-    float f_quality;
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_MULTIQUANT );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.multi_quants = i_tmp;
 
-    if( p_enc->fmt_out.i_codec != VLC_FOURCC('d','r','a','c') &&
-        !p_enc->b_force )
-    {
-        return VLC_EGENERIC;
-    }
+    i_tmp = var_GetInteger( p_enc, ENC_CFG_PREFIX ENC_SPARTITION );
+    if( i_tmp > -1 )
+        p_sys->ctx.enc_params.spatial_partition = i_tmp;
 
-    /* Allocate the memory needed to store the decoder's structure */
-    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->ctx.enc_params.using_ac = !var_GetBool( p_enc, ENC_CFG_PREFIX ENC_NOAC );
 
-    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');
+    f_tmp = var_GetFloat( p_enc, ENC_CFG_PREFIX ENC_CPD );
+    if( f_tmp > -1 )
+        p_sys->ctx.enc_params.cpd = f_tmp;
 
-    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
+    /* Allocate the buffer for inputing frames into the encoder */
+    if( ( p_sys->p_buffer_in = malloc( p_sys->i_buffer_in ) ) == NULL )
+    {
+        CloseEncoder( p_this );
+        return VLC_ENOMEM;
+    }
 
-    dirac_encoder_context_init( &p_sys->ctx, VIDEO_FORMAT_CUSTOM );
-    /* */
-    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 );
-
-    /* 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 );
+    /* Set up output buffer */
+    /* Unfortunately it isn't possible to determine if the buffer
+     * is too small (and then reallocate it) */
+    p_sys->i_buffer_out = 4096 + p_sys->i_buffer_in;
+    if( ( p_sys->p_buffer_out = malloc( p_sys->i_buffer_out ) ) == NULL )
+    {
+        CloseEncoder( p_this );
+        return VLC_ENOMEM;
+    }
 
     return VLC_SUCCESS;
+error:
+    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 );
+        assert( u_npo <= UINT32_MAX - u_pos );
+        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) */
+    if( !p_pic ) return NULL;
+    /* 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" );
+            return NULL;
+        }
+        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_pts_offset( 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 );
+
+        /* picture_coding_mode = 1 == FIELD_CODING, two pictures are produced
+         * for each frame input. Calculate time between fields for offsetting
+         * the second field later. */
+        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++ )
     {
@@ -413,59 +842,120 @@ 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() error" );
+        return NULL;
+    }
 
-        msg_Dbg( p_enc, "dirac_encoder_load" );
+    /* 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( 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 );
+        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;
+    }
 
-        /* Retrieve encoded frames from encoder */
-        do
+    dirac_encoder_state_t state;
+    /* 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 = p_sys->i_buffer_out;
+        state = dirac_encoder_output( p_sys->p_dirac );
+        switch( state )
         {
-            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: {
+            uint32_t pic_num;
+
+            /* extract data from encoder temporary buffer. */
+            p_block = block_New( p_enc, p_sys->p_dirac->enc_buf.size );
+            if( !p_block )
+                return NULL;
+            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] )
             {
-            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;
+                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( p_sys->p_dirac->decoded_frame_avail )
+
+            if( ReadDiracPictureNumber( &pic_num, p_block ) )
             {
-                //locally decoded frame is available in
-                //encoder->dec_buf
-                //locally decoded frame parameters available
-                //in encoder->dec_fparams
+                /* 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;
             }
-            if( p_sys->p_dirac->instr_data_avail )
-            {
-                //Instrumentation data (motion vectors etc.)
-                //available in encoder->instr
+            break;
             }
 
-        } while( state == ENC_STATE_AVAIL );
-    }
-    else
-    {
-        msg_Dbg( p_enc, "dirac_encoder_load() error" );
-    }
+        case ENC_STATE_BUFFER:
+            break;
+        case ENC_STATE_INVALID:
+        default:
+            break;
+        }
+    } while( state == ENC_STATE_AVAIL );
 
-    return p_chain;
+    return p_output_chain;
 }
 
 /*****************************************************************************
@@ -476,12 +966,16 @@ 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: %i bits/sec",
-             p_sys->p_dirac->enc_seqstats.bit_rate );
-
     /* Free the encoder resources */
-    dirac_encoder_close( p_sys->p_dirac );
+    if( p_sys->p_dirac )
+        dirac_encoder_close( p_sys->p_dirac );
+
     free( p_sys->p_buffer_in );
+    free( p_sys->p_buffer_out );
+
+    if( p_sys->p_dts_fifo )
+        block_FifoRelease( p_sys->p_dts_fifo );
+    block_ChainRelease( p_sys->p_chain );
+
     free( p_sys );
 }