All pastes #1014966 Raw Edit

Van is godly

public text v1 · immutable
#1014966 ·published 2008-05-11 18:40 UTC
rendered paste body
Index: libhb/detelecine.c
===================================================================
--- libhb/detelecine.c	(revision 1457)
+++ libhb/detelecine.c	(working copy)
@@ -1,5 +1,5 @@
 #include "hb.h"
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 #include "mpeg2dec/mpeg2.h"
 
 /*
Index: libhb/reader.c
===================================================================
--- libhb/reader.c	(revision 1457)
+++ libhb/reader.c	(working copy)
@@ -47,6 +47,19 @@
                            HB_NORMAL_PRIORITY );
 }
 
+static void push_buf( hb_reader_t *r, hb_fifo_t *fifo, hb_buffer_t *buf )
+{
+    while( !*r->die && !r->job->done && hb_fifo_is_full( fifo ) )
+    {
+        /*
+         * Loop until the incoming fifo is reaqdy to receive
+         * this buffer.
+         */
+        hb_snooze( 50 );
+    }
+    hb_fifo_push( fifo, buf );
+}
+
 /***********************************************************************
  * ReaderFunc
  ***********************************************************************
@@ -57,7 +70,6 @@
     hb_reader_t  * r = _r;
     hb_fifo_t   ** fifos;
     hb_buffer_t  * buf;
-    hb_buffer_t  * buf_old;
     hb_list_t    * list;
     int            n;
     int            chapter = -1;
@@ -172,7 +184,7 @@
                 if ( buf->id == 0xE0 && buf->start != -1 )
                 {
                     r->saw_video = 1;
-                    r->demux.scr_offset = buf->start;
+                    r->demux.scr_offset = buf->renderOffset;
                     hb_log( "reader: first SCR %llu scr_offset %llu",
                             r->demux.last_scr, r->demux.scr_offset );
                 }
@@ -190,34 +202,21 @@
                        everything after this sees a continuous clock with 0
                        being the time of the first video packet. */
                     buf->start -= r->demux.scr_offset;
+                    buf->renderOffset -= r->demux.scr_offset;
                 }
                 buf->sequence = r->sequence++;
-                for( n = 0; fifos[n] != NULL; n++)
+                /* if there are mutiple output fifos, send a copy of the
+                 * buffer down all but the first (we have to not ship the
+                 * original buffer or we'll race with the thread that's
+                 * consuming the buffer & inject garbage into the data stream). */
+                for( n = 1; fifos[n] != NULL; n++)
                 {
-                    if( n != 0 )
-                    {
-                        /*
-                         * Replace the buffer with a new copy of itself for when
-                         * it is being sent down multiple fifos.
-                         */
-                        buf_old = buf;
-                        buf = hb_buffer_init(buf_old->size);
-                        memcpy( buf->data, buf_old->data, buf->size );
-                        hb_buffer_copy_settings( buf, buf_old );
-                    }
-
-                    while( !*r->die && !r->job->done &&
-                           hb_fifo_is_full( fifos[n] ) )
-                    {
-                        /*
-                         * Loop until the incoming fifo is reaqdy to receive
-                         * this buffer.
-                         */
-                        hb_snooze( 50 );
-                    }
-
-                    hb_fifo_push( fifos[n], buf );
+                    hb_buffer_t *buf_copy = hb_buffer_init( buf->size );
+                    hb_buffer_copy_settings( buf_copy, buf );
+                    memcpy( buf_copy->data, buf->data, buf->size );
+                    push_buf( r, fifos[n], buf_copy );
                 }
+                push_buf( r, fifos[0], buf );
             }
             else
             {
Index: libhb/deca52.c
===================================================================
--- libhb/deca52.c	(revision 1457)
+++ libhb/deca52.c	(working copy)
@@ -38,9 +38,11 @@
 
 };
 
-int  deca52Init( hb_work_object_t *, hb_job_t * );
-int  deca52Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
-void deca52Close( hb_work_object_t * );
+static int  deca52Init( hb_work_object_t *, hb_job_t * );
+static int  deca52Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+static void deca52Close( hb_work_object_t * );
+static int deca52BSInfo( hb_work_object_t * , const hb_buffer_t *,
+                         hb_work_info_t * );
 
 hb_work_object_t hb_deca52 =
 {
@@ -48,7 +50,9 @@
     "AC3 decoder",
     deca52Init,
     deca52Work,
-    deca52Close
+    deca52Close,
+    0,
+    deca52BSInfo
 };
 
 /***********************************************************************
@@ -85,7 +89,7 @@
  ***********************************************************************
  * Allocate the work object, initialize liba52
  **********************************************************************/
-int deca52Init( hb_work_object_t * w, hb_job_t * job )
+static int deca52Init( hb_work_object_t * w, hb_job_t * job )
 {
     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
     hb_audio_t * audio = w->audio;
@@ -119,7 +123,7 @@
  ***********************************************************************
  * Free memory
  **********************************************************************/
-void deca52Close( hb_work_object_t * w )
+static void deca52Close( hb_work_object_t * w )
 {
     hb_work_private_t * pv = w->private_data;
     a52_free( pv->state );
@@ -134,7 +138,7 @@
  * Add the given buffer to the data we already have, and decode as much
  * as we can
  **********************************************************************/
-int deca52Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
+static int deca52Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
                 hb_buffer_t ** buf_out )
 {
     hb_work_private_t * pv = w->private_data;
@@ -276,3 +280,82 @@
     return buf;
 }
 
+static int deca52BSInfo( hb_work_object_t *w, const hb_buffer_t *b,
+                         hb_work_info_t *info )
+{
+    int i, rate, bitrate, flags;
+
+    memset( info, 0, sizeof(*info) );
+
+    /* since AC3 frames don't line up with MPEG ES frames scan the
+     * entire frame for an AC3 sync pattern.  */
+    for ( i = 0; i < b->size - 7; ++i )
+    {
+        if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) != 0 )
+        {
+            break;
+        }
+    }
+    if ( i >= b->size - 7 )
+    {
+        /* didn't find AC3 sync */
+        return 0;
+    }
+
+    info->name = "AC-3";
+    info->rate = rate;
+    info->rate_base = 1;
+    info->bitrate = bitrate;
+    info->flags = flags;
+    if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY )
+    {
+        info->flags |= AUDIO_F_DOLBY;
+    }
+
+    switch( flags & A52_CHANNEL_MASK )
+    {
+        /* mono sources */
+        case A52_MONO:
+        case A52_CHANNEL1:
+        case A52_CHANNEL2:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_MONO;
+            break;
+        /* stereo input */
+        case A52_CHANNEL:
+        case A52_STEREO:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
+            break;
+        /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */
+        case A52_DOLBY:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_DOLBY;
+            break;
+        /* 3F/2R input */
+        case A52_3F2R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_3F2R;
+            break;
+        /* 3F/1R input */
+        case A52_3F1R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_3F1R;
+            break;
+        /* other inputs */
+        case A52_3F:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_3F;
+            break;
+        case A52_2F1R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_2F1R;
+            break;
+        case A52_2F2R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_2F2R;
+            break;
+        /* unknown */
+        default:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
+    }
+
+    if (flags & A52_LFE)
+    {
+        info->channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;
+    }
+
+    return 1;
+}
Index: libhb/decmpeg2.c
===================================================================
--- libhb/decmpeg2.c	(revision 1457)
+++ libhb/decmpeg2.c	(working copy)
@@ -25,15 +25,13 @@
 #define BTB_PROG 64
 #define TB_PROG 128
 #define TBT_PROG 256
-int cadence[12];
-int flag = 0;
+static int cadence[12];
+static int flag = 0;
 
 /**********************************************************************
  * hb_libmpeg2_t
- **********************************************************************
- * A convenient libmpeg wrapper, used both here and in scan.c
  *********************************************************************/
-struct hb_libmpeg2_s
+typedef struct hb_libmpeg2_s
 {
     mpeg2dec_t         * libmpeg2;
     const mpeg2_info_t * info;
@@ -47,14 +45,14 @@
     int                  look_for_break;    /* need gop start to add chap break */
     uint32_t             nframes;           /* number of frames we've decoded */
     int64_t              last_pts;
-};
+} hb_libmpeg2_t;
 
 /**********************************************************************
  * hb_libmpeg2_init
  **********************************************************************
  *
  *********************************************************************/
-hb_libmpeg2_t * hb_libmpeg2_init()
+static hb_libmpeg2_t * hb_libmpeg2_init()
 {
     hb_libmpeg2_t * m = calloc( sizeof( hb_libmpeg2_t ), 1 );
 
@@ -70,7 +68,7 @@
  **********************************************************************
  *
  *********************************************************************/
-int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
+static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
                         hb_list_t * list_raw )
 {
     mpeg2_state_t   state;
@@ -312,7 +310,7 @@
  **********************************************************************
  *
  *********************************************************************/
-void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, int * height,
+static void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, int * height,
                         int * rate, int *aspect_ratio )
 {
     *width  = m->width;
@@ -334,19 +332,12 @@
     *aspect_ratio = m->aspect_ratio;
 }
 
-int hb_libmpeg2_clear_aspect_ratio( hb_libmpeg2_t * m )
-{
-    int ar = m->aspect_ratio;
-    m->aspect_ratio = 0;
-    return ar;
-}
-
 /**********************************************************************
  * hb_libmpeg2_close
  **********************************************************************
  *
  *********************************************************************/
-void hb_libmpeg2_close( hb_libmpeg2_t ** _m )
+static void hb_libmpeg2_close( hb_libmpeg2_t ** _m )
 {
     hb_libmpeg2_t * m = *_m;
 
@@ -372,7 +363,7 @@
  **********************************************************************
  *
  *********************************************************************/
-int decmpeg2Init( hb_work_object_t * w, hb_job_t * job )
+static int decmpeg2Init( hb_work_object_t * w, hb_job_t * job )
 {
     hb_work_private_t * pv;
 
@@ -392,7 +383,7 @@
  **********************************************************************
  *
  *********************************************************************/
-int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
+static int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
                    hb_buffer_t ** buf_out )
 {
     hb_work_private_t * pv = w->private_data;
@@ -441,21 +432,51 @@
  **********************************************************************
  *
  *********************************************************************/
-void decmpeg2Close( hb_work_object_t * w )
+static void decmpeg2Close( hb_work_object_t * w )
 {
     hb_work_private_t * pv = w->private_data;
-    hb_log( "mpeg2 done: %d frames", pv->libmpeg2->nframes );
+
+    // don't log during scan
+    if ( pv->libmpeg2->job )
+    {
+        hb_log( "mpeg2 done: %d frames", pv->libmpeg2->nframes );
+    }
     hb_list_close( &pv->list );
     hb_libmpeg2_close( &pv->libmpeg2 );
     free( pv );
 }
 
+static int decmpeg2Info( hb_work_object_t *w, hb_work_info_t *info )
+{
+    hb_work_private_t *pv = w->private_data;
+
+    if ( pv && pv->libmpeg2 )
+    {
+        int aspect;
+        hb_libmpeg2_t *m = pv->libmpeg2;
+
+        hb_libmpeg2_info( m, &info->width, &info->height, &info->rate_base,
+                          &aspect );
+
+        info->aspect = (double)aspect;
+        info->rate = 27000000;
+
+        info->bitrate = m->info->sequence->byte_rate * 8;
+        info->profile = m->info->sequence->profile_level_id >> 4;
+        info->level = m->info->sequence->profile_level_id & 0xf;
+        info->name = "mpeg2";
+        return 1;
+    }
+    return 0;
+}
+
 hb_work_object_t hb_decmpeg2 =
 {
     WORK_DECMPEG2,
     "MPEG-2 decoder (libmpeg2)",
     decmpeg2Init,
     decmpeg2Work,
-    decmpeg2Close
+    decmpeg2Close,
+    decmpeg2Info
 };
 
Index: libhb/denoise.c
===================================================================
--- libhb/denoise.c	(revision 1457)
+++ libhb/denoise.c	(working copy)
@@ -17,7 +17,7 @@
 */
 
 #include "hb.h"
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 #include "mpeg2dec/mpeg2.h"
 
 #define HQDN3D_SPATIAL_LUMA_DEFAULT    4.0f
Index: libhb/hb.c
===================================================================
--- libhb/hb.c	(revision 1457)
+++ libhb/hb.c	(working copy)
@@ -1,7 +1,7 @@
 #include "hb.h"
 
-#include "ffmpeg/avcodec.h"
-#include "ffmpeg/swscale.h"
+#include "libavcodec/avcodec.h"
+#include "libswscale/swscale.h"
 
 struct hb_handle_s
 {
@@ -124,7 +124,6 @@
     /* libavcodec */
     avcodec_init();
     avcodec_register_all();
-    av_register_codec_parser( &mpegaudio_parser);
 
     /* Start library thread */
     hb_log( "hb_init: starting libhb thread" );
@@ -220,6 +219,7 @@
 	hb_register( &hb_deca52 );
 	hb_register( &hb_decdca );
 	hb_register( &hb_decavcodec );
+	hb_register( &hb_decavcodecv );
 	hb_register( &hb_declpcm );
 	hb_register( &hb_encfaac );
 	hb_register( &hb_enclame );
Index: libhb/encavcodec.c
===================================================================
--- libhb/encavcodec.c	(revision 1457)
+++ libhb/encavcodec.c	(working copy)
@@ -6,7 +6,7 @@
 
 #include "hb.h"
 
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 
 struct hb_work_private_s
 {
Index: libhb/demuxmpeg.c
===================================================================
--- libhb/demuxmpeg.c	(revision 1457)
+++ libhb/demuxmpeg.c	(working copy)
@@ -6,7 +6,7 @@
 
 #include "hb.h"
 
-/* Basic MPEG demuxer, only works with DVDs (2048 bytes packets) */
+/* Basic MPEG demuxer */
 
 int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state )
 {
@@ -91,7 +91,7 @@
         int      pes_header_d_length;
         int      pes_header_end;
         int      has_pts;
-        int64_t  pts = -1;
+        int64_t  pts = -1, dts = -1;
 
         pos               += 3;               /* packet_start_code_prefix */
         id           = d[pos];
@@ -109,7 +109,7 @@
             continue;
         }
 
-        has_pts             = ( ( d[pos+1] >> 6 ) & 0x2 ) ? 1 : 0;
+        has_pts            = d[pos+1] >> 6;
         pos               += 2;               /* Required headers */
 
         pes_header_d_length  = d[pos];
@@ -118,11 +118,23 @@
 
         if( has_pts )
         {
-            pts = ( ( ( (uint64_t) d[pos] >> 1 ) & 0x7 ) << 30 ) +
+            pts = ( (uint64_t)(d[pos] & 0xe ) << 29 ) +
                   ( d[pos+1] << 22 ) +
                   ( ( d[pos+2] >> 1 ) << 15 ) +
                   ( d[pos+3] << 7 ) +
                   ( d[pos+4] >> 1 );
+            if ( has_pts & 1 )
+            {
+                dts = ( (uint64_t)(d[pos+5] & 0xe ) << 29 ) +
+                      ( d[pos+6] << 22 ) +
+                      ( ( d[pos+7] >> 1 ) << 15 ) +
+                      ( d[pos+8] << 7 ) +
+                      ( d[pos+9] >> 1 );
+            }
+            else
+            {
+                dts = pts;
+            }
         }
 
         pos = pes_header_end;
@@ -153,6 +165,7 @@
 
         buf_es->id       = id;
         buf_es->start    = pts;
+        buf_es->renderOffset = dts;
         buf_es->stop     = -1;
         if (id == 0xE0) {
             // Consume a chapter break, and apply it to the ES.
Index: libhb/stream.c
===================================================================
--- libhb/stream.c	(revision 1457)
+++ libhb/stream.c	(working copy)
@@ -7,11 +7,76 @@
 #include "hb.h"
 #include "lang.h"
 #include "a52dec/a52.h"
+#include "libavcodec/avcodec.h"
 
 #include <string.h>
 
 #define min(a, b) a < b ? a : b
 
+/*
+ * This table defines how ISO MPEG stream type codes map to HandBrake
+ * codecs. It is indexed by the 8 bit stream type and contains the codec
+ * worker object id and a parameter for that worker proc (ignored except
+ * for the ffmpeg-based codecs in which case it is the ffmpeg codec id).
+ *
+ * Entries with a worker proc id of 0 or a kind of 'U' indicate that HB
+ * doesn't handle the stream type.
+ */
+typedef struct {
+    enum { U, A, V } kind; /* unknown / audio / video */
+    int codec;          /* HB worker object id of codec */
+    int codec_param;    /* param for codec (usually ffmpeg codec id) */
+    const char* name;   /* description of type */
+} stream2codec_t;
+
+#define st(id, kind, codec, codec_param, name) \
+ [id] = { kind, codec, codec_param, name }
+
+static const stream2codec_t st2codec[256] = {
+    st(0x01, V, WORK_DECMPEG2,     0,              "MPEG1"),
+    st(0x02, V, WORK_DECMPEG2,     0,              "MPEG2"),
+    st(0x03, A, HB_ACODEC_MPGA,    CODEC_ID_MP2,   "MPEG1"),
+    st(0x04, A, HB_ACODEC_MPGA,    CODEC_ID_MP2,   "MPEG2"),
+    st(0x05, U, 0,                 0,              "ISO 13818-1 private section"),
+    st(0x06, U, 0,                 0,              "ISO 13818-1 PES private data"),
+    st(0x07, U, 0,                 0,              "ISO 13522 MHEG"),
+    st(0x08, U, 0,                 0,              "ISO 13818-1 DSM-CC"),
+    st(0x09, U, 0,                 0,              "ISO 13818-1 auxiliary"),
+    st(0x0a, U, 0,                 0,              "ISO 13818-6 encap"),
+    st(0x0b, U, 0,                 0,              "ISO 13818-6 DSM-CC U-N msgs"),
+    st(0x0c, U, 0,                 0,              "ISO 13818-6 Stream descriptors"),
+    st(0x0d, U, 0,                 0,              "ISO 13818-6 Sections"),
+    st(0x0e, U, 0,                 0,              "ISO 13818-1 auxiliary"),
+    st(0x0f, A, HB_ACODEC_MPGA,    CODEC_ID_AAC,   "ISO 13818-7 AAC Audio"),
+    st(0x10, V, WORK_DECAVCODECV,  CODEC_ID_MPEG4, "MPEG4"),
+    st(0x11, A, HB_ACODEC_MPGA,    CODEC_ID_AAC,   "MPEG4 LATM AAC"),
+    st(0x12, U, 0,                 0,              "MPEG4 generic"),
+
+    st(0x14, U, 0,                 0,              "ISO 13818-6 DSM-CC download"),
+
+    st(0x1b, V, WORK_DECAVCODECV,  CODEC_ID_H264,  "H.264"),
+
+    st(0x80, U, 0,                 0,              "DigiCipher II Video"),
+    st(0x81, A, HB_ACODEC_AC3,     0,              "AC-3"),
+    st(0x82, A, HB_ACODEC_DCA,     0,              "HDMV DTS"),
+    st(0x83, A, HB_ACODEC_LPCM,    0,              "LPCM"),
+    st(0x84, U, 0,                 0,              "SDDS"),
+    st(0x85, U, 0,                 0,              "ATSC Program ID"),
+    st(0x86, U, 0,                 0,              "SCTE 35 splice info"),
+    st(0x87, A, 0,                 0,              "E-AC-3"),
+
+    st(0x8a, A, HB_ACODEC_DCA,     0,              "DTS"),
+
+    st(0x91, A, HB_ACODEC_AC3,     0,              "AC-3"),
+    st(0x92, U, 0,                 0,              "Subtitle"),
+
+    st(0x94, U, 0,                 0,              "SDDS"),
+    st(0xa0, U, 0,                 0,              "MSCODEC"),
+            
+    st(0xea, V, WORK_DECAVCODECV, CODEC_ID_VC1,    "VC-1"),
+};
+#undef st
+
 typedef enum {
     hb_stream_type_unknown = 0,
     transport,
@@ -557,6 +622,10 @@
             stream->ts_audio_pids[stream->ts_number_audio_pids++] =
                 stream->pmt_info.PCR_PID;
         }
+
+        // set up the video codec to use for this title
+        aTitle->video_codec = st2codec[stream->ts_stream_type[0]].codec;
+        aTitle->video_codec_param = st2codec[stream->ts_stream_type[0]].codec_param;
 	}
     else
     {
@@ -992,65 +1061,52 @@
     buf = hb_ts_stream_getPEStype(stream, stream->ts_audio_pids[aud_pid_index]);
 
     /* check that we found a PES header */
+    uint8_t stype = 0;
     if (buf && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)
     {
-        if (buf[3] == 0xbd)
+        // 0xbd is the normal container for AC3/DCA/PCM/etc. 0xfd indicates an
+        // extended stream id (ISO 13818-1(2007)). If we cared about the
+        // real id we'd have to look inside the PES extension to find it.
+        // But since we remap stream id's when we generate PS packets from
+        // the TS packets we can just ignore the actual id.
+        if ( buf[3] == 0xbd || buf[3] == 0xfd )
         {
             audio->id = 0x80bd | (aud_pid_index << 8);
-            audio->config.in.codec = HB_ACODEC_AC3;
-            hb_log("transport stream pid 0x%x (type 0x%x) is AC-3 audio id 0x%x",
-                   stream->ts_audio_pids[aud_pid_index],
-                   stream->ts_stream_type[1 + aud_pid_index],
-                   audio->id);
-            stream->ts_stream_type[1 + aud_pid_index] = 0x81;
-            stream->ts_streamid[1 + aud_pid_index] = 0xbd;
-        }
-        else if (buf[3] == 0xfd)
-        {
-            /* XXX Extended stream id (ISO 13818-1(2000) Amd 2) - we have to look
-             * inside the PES extension to find out the real stream id then
-             * figure out what the heck it means. For now we just use the stream
-             * type if one was specified. */
-            const char *atype = 0;
-            switch (stream->ts_stream_type[1 + aud_pid_index])
+            stype = stream->ts_stream_type[1 + aud_pid_index];
+            if ( st2codec[stype].kind == U )
             {
-                case 0x81: // AC-3
-                    atype = "AC-3";
-                    audio->config.in.codec = HB_ACODEC_AC3;
-                    break;
-                case 0x82: // HDMV DTS
-                case 0x8a: // DTS
-                    atype = "DTS";
-                    audio->config.in.codec = HB_ACODEC_DCA;
-                    break;
-                case 0x83: // LPCM
-                    atype = "PCM";
-                    audio->config.in.codec = HB_ACODEC_LPCM;
-                    break;
+                // XXX assume unknown stream types are AC-3 (if they're not
+                // audio we'll find that out during the scan but if they're
+                // some other type of audio we'll end up ignoring them).
+                stype = 0x81;
+                stream->ts_stream_type[1 + aud_pid_index] = 0x81;
             }
-            audio->id = 0x80bd | (aud_pid_index << 8);
             stream->ts_streamid[1 + aud_pid_index] = 0xbd;
-            hb_log("transport stream pid 0x%x (type 0x%x) is %s audio id 0x%x",
-                   stream->ts_audio_pids[aud_pid_index],
-                   stream->ts_stream_type[1 + aud_pid_index], atype, audio->id);
         }
         else if ((buf[3] & 0xe0) == 0xc0)
         {
-            audio->id = buf[3] | aud_pid_index;
-            audio->config.in.codec = HB_ACODEC_MPGA;
-            hb_log("transport stream pid 0x%x (type 0x%x) is MPEG audio id 0x%x",
-                   stream->ts_audio_pids[aud_pid_index],
-                   stream->ts_stream_type[1 + aud_pid_index],
-                   audio->id);
-            stream->ts_stream_type[1 + aud_pid_index] = 0x03;
-            stream->ts_streamid[1 + aud_pid_index] = buf[3];
+            audio->id = 0xc0 | aud_pid_index;
+            stype = stream->ts_stream_type[1 + aud_pid_index];
+            if ( st2codec[stype].kind == U )
+            {
+                // XXX assume unknown stream types are MPEG audio
+                stype = 0x03;
+                stream->ts_stream_type[1 + aud_pid_index] = 0x03;
+            }
         }
     }
-    fseeko(stream->file_handle, cur_pos, SEEK_SET);
-    if ( audio->config.in.codec )
+    // if we found an audio stream type & HB has a codec that can decode it
+    // finish configuring the audio so we'll add it to the title's list.
+    if ( st2codec[stype].kind == A && st2codec[stype].codec )
     {
+        stream->ts_streamid[1 + aud_pid_index] = audio->id;
+        audio->config.in.codec = st2codec[stype].codec;
+        audio->config.in.codec_param = st2codec[stype].codec_param;
 		set_audio_description( audio,
                   lang_for_code( stream->a52_info[aud_pid_index].lang_code ) );
+        hb_log("transport stream pid 0x%x (type 0x%x) is %s audio id 0x%x",
+               stream->ts_audio_pids[aud_pid_index],
+               stype, st2codec[stype].name, audio->id);
     }
     else
     {
@@ -1058,6 +1114,7 @@
                 stream->ts_audio_pids[aud_pid_index],
                 stream->ts_stream_type[1 + aud_pid_index]);
 	}
+    fseeko(stream->file_handle, cur_pos, SEEK_SET);
     return audio;
 }
 
@@ -1294,54 +1351,9 @@
     }
 }
 
-static const char * stream_type_name (uint8_t stream_type)
+static const char *stream_type_name (uint8_t stream_type)
 {
-    switch( stream_type )
-    {
-    case 0x01: return("ISO 11172 (MPEG1) Video");
-    case 0x02: return("ISO 13818-2 (MPEG2) Video");
-    case 0x03: return("ISO 11172 (MPEG1) Audio");
-    case 0x04: return("ISO 13818-3 (MPEG2) Audio");
-    case 0x05: return("ISO 13818-1 private section");
-    case 0x06: return("ISO 13818-1 PES private data");
-    case 0x07: return("ISO 13522 MHEG");
-    case 0x08: return("ISO 13818-1 DSM-CC");
-    case 0x09: return("ISO 13818-1 auxiliary");
-    case 0x0a: return("ISO 13818-6 multi-protocol encap");
-    case 0x0b: return("ISO 13818-6 DSM-CC U-N msgs");
-    case 0x0c: return("ISO 13818-6 Stream descriptors");
-    case 0x0d: return("ISO 13818-6 Sections");
-    case 0x0e: return("ISO 13818-1 auxiliary");
-    case 0x0f: return("ISO 13818-7 AAC Audio");
-    case 0x10: return("MPEG4 Video");
-    case 0x11: return("MPEG4 Audio");
-    case 0x12: return("MPEG4 generic");
-
-    case 0x14: return("ISO 13818-6 DSM-CC download");
-
-    case 0x1b: return("H.264 Video");
-
-    case 0x80: return("DigiCipher II Video");
-    case 0x81: return("A52/AC-3 Audio");
-    case 0x82: return("HDMV DTS Audio");
-    case 0x83: return("LPCM Audio");
-    case 0x84: return("SDDS Audio");
-    case 0x85: return("ATSC Program ID");
-    case 0x86: return("SCTE 35 splice info");
-    case 0x87: return("ATSC E-AC-3");
-
-    case 0x8a: return("DTS Audio");
-
-    case 0x91: return("A52b/AC-3 Audio");
-    case 0x92: return("Subtitle");
-
-    case 0x94: return("SDDS Audio");
-    case 0xa0: return("MSCODEC Video");
-        
-    case 0xea: return("VC-1 Video");
-
-    default:   return("Unknown");
-    }
+    return st2codec[stream_type].name? st2codec[stream_type].name : "Unknown";
 }
 
 int decode_program_map(hb_stream_t* stream)
@@ -1393,8 +1405,7 @@
         }
 
 
-        if (stream->ts_number_video_pids == 0 &&
-            ( stream_type == 0x02 || stream_type == 0x10 || stream_type == 0x1B ) )
+        if (stream->ts_number_video_pids == 0 && st2codec[stream_type].kind == V )
         {
             stream->ts_video_pids[0] = elementary_PID;
             stream->ts_stream_type[0] = stream_type;
@@ -1765,7 +1776,7 @@
     int len;
 
     // we always ship a PACK header plus all the data in our demux buf.
-    // AC3 audio also always needs it substream header.
+    // AC3 audio also always needs its substream header.
     len = 14 + stream->ts_pos[curstream];
     if ( stream->ts_stream_type[curstream] == 0x81)
     {
@@ -1876,37 +1887,82 @@
     stream->ts_pos[curstream] = 0;
 }
 
-static int isIframe( const uint8_t *buf, int adapt_len )
+static int isIframe( hb_stream_t *stream, const uint8_t *buf, int adapt_len )
 {
-    // Look for the Group of Pictures packet
+    // For mpeg2: look for a gop start or i-frame picture start
+    // for h.264: look for idr nal type or a slice header for an i-frame
+    // for vc1:   ???
     int i;
     uint32_t strid = 0;
 
-    for (i = 4 + adapt_len; i < 188; i++)
+
+    if ( stream->ts_stream_type[0] <= 2 )
     {
-        strid = (strid << 8) | buf[i];
-        switch ( strid )
+        // This section of the code handles MPEG-1 and MPEG-2 video streams
+        for (i = 13 + adapt_len; i < 188; i++)
         {
-            case 0x000001B8: // group_start_code (GOP header)
-            case 0x000001B3: // sequence_header code
-                return 1;
+            strid = (strid << 8) | buf[i];
+            if ( ( strid >> 8 ) == 1 )
+            {
+                // we found a start code
+                uint8_t id = strid;
+                switch ( id )
+                {
+                    case 0xB8: // group_start_code (GOP header)
+                    case 0xB3: // sequence_header code
+                        return 1;
 
-            case 0x00000100: // picture_start_code
-                // picture_header, let's see if it's an I-frame
-                if (i<185)
+                    case 0x00: // picture_start_code
+                        // picture_header, let's see if it's an I-frame
+                        if (i<185)
+                        {
+                            // check if picture_coding_type == 1
+                            if ((buf[i+2] & (0x7 << 3)) == (1 << 3))
+                            {
+                                // found an I-frame picture
+                                return 1;
+                            }
+                        }
+                        break;
+                }
+            }
+        }
+        // didn't find an I-frame
+        return 0;
+    }
+    if ( stream->ts_stream_type[0] == 0x1b )
+    {
+        // we have an h.264 stream 
+        for (i = 13 + adapt_len; i < 188; i++)
+        {
+            strid = (strid << 8) | buf[i];
+            if ( ( strid >> 8 ) == 1 )
+            {
+                // we found a start code - remove the ref_idc from the nal type
+                uint8_t nal_type = strid & 0x1f;
+                if ( nal_type == 0x05 )
+                    // h.264 IDR picture start
+                    return 1;
+
+                if ( nal_type == 0x01 )
                 {
-                    // check if picture_coding_type == 1
-                    if ((buf[i+2] & (0x7 << 3)) == (1 << 3))
+                    // h.264 slice: has to be start MB 0 & type I (2, 4, 7 or 9)
+                    uint8_t id = buf[i+1];
+                    if ( ( id >> 4 ) == 0x0b || ( id >> 2 ) == 0x25 ||
+                         id == 0x88 || id == 0x8a )
                     {
-                        // found an I-frame picture
                         return 1;
                     }
                 }
-                break;
+            }
         }
+        // didn't find an I-frame
+        return 0;
     }
-    // didn't find an I frame
-    return 0;
+
+    // we don't understand the stream type so just say "yes" otherwise
+    // we'll discard all the video.
+    return 1;
 }
 
 /***********************************************************************
@@ -2034,7 +2090,7 @@
 			{
                 // video skips to an iframe after a bad packet to minimize
                 // screen corruption
-                if ( curstream == 0 && !isIframe( buf, adapt_len ) )
+                if ( curstream == 0 && !isIframe( stream, buf, adapt_len ) )
                 {
                     continue;
                 }
@@ -2047,8 +2103,7 @@
             {
                 if ( !stream->ts_foundfirst[0] )
                 {
-                    if ( stream->ts_stream_type[0] == 2 &&
-                         !isIframe( buf, adapt_len ) )
+                    if ( !isIframe( stream, buf, adapt_len ) )
                     {
                         // didn't find an I frame
                         continue;
Index: libhb/hb.h
===================================================================
--- libhb/hb.h	(revision 1457)
+++ libhb/hb.h	(working copy)
@@ -29,6 +29,7 @@
 hb_register( &hb_deca52 ); \
 hb_register( &hb_decdca ); \
 hb_register( &hb_decavcodec ); \
+hb_register( &hb_decavcodecv ); \
 hb_register( &hb_declpcm ); \
 hb_register( &hb_encfaac ); \
 hb_register( &hb_enclame ); \
@@ -45,6 +46,7 @@
 hb_register( &hb_deca52 ); \
 hb_register( &hb_decdca ); \
 hb_register( &hb_decavcodec ); \
+hb_register( &hb_decavcodecv ); \
 hb_register( &hb_declpcm ); \
 hb_register( &hb_encfaac ); \
 
Index: libhb/deblock.c
===================================================================
--- libhb/deblock.c	(revision 1457)
+++ libhb/deblock.c	(working copy)
@@ -17,7 +17,7 @@
 */
 
 #include "hb.h"
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 #include "mpeg2dec/mpeg2.h"
 
 #define PP7_QP_DEFAULT    0
Index: libhb/decdca.c
===================================================================
--- libhb/decdca.c	(revision 1457)
+++ libhb/decdca.c	(working copy)
@@ -35,9 +35,11 @@
 
 };
 
-int  decdcaInit( hb_work_object_t *, hb_job_t * );
-int  decdcaWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
-void decdcaClose( hb_work_object_t * );
+static int  decdcaInit( hb_work_object_t *, hb_job_t * );
+static int  decdcaWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+static void decdcaClose( hb_work_object_t * );
+static int  decdcaBSInfo( hb_work_object_t *, const hb_buffer_t *,
+                          hb_work_info_t * );
 
 hb_work_object_t hb_decdca =
 {
@@ -45,7 +47,9 @@
     "DCA decoder",
     decdcaInit,
     decdcaWork,
-    decdcaClose
+    decdcaClose,
+    0,
+    decdcaBSInfo
 };
 
 /***********************************************************************
@@ -58,7 +62,7 @@
  ***********************************************************************
  * Allocate the work object, initialize libdca
  **********************************************************************/
-int decdcaInit( hb_work_object_t * w, hb_job_t * job )
+static int decdcaInit( hb_work_object_t * w, hb_job_t * job )
 {
     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
     hb_audio_t * audio = w->audio;
@@ -88,7 +92,7 @@
  ***********************************************************************
  * Free memory
  **********************************************************************/
-void decdcaClose( hb_work_object_t * w )
+static void decdcaClose( hb_work_object_t * w )
 {
     hb_work_private_t * pv = w->private_data;
     dca_free( pv->state );
@@ -103,7 +107,7 @@
  * Add the given buffer to the data we already have, and decode as much
  * as we can
  **********************************************************************/
-int decdcaWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+static int decdcaWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
                 hb_buffer_t ** buf_out )
 {
     hb_work_private_t * pv = w->private_data;
@@ -214,3 +218,85 @@
     return buf;
 }
 
+
+static int decdcaBSInfo( hb_work_object_t *w, const hb_buffer_t *b,
+                         hb_work_info_t *info )
+{
+    int i, flags, rate, bitrate, frame_length;
+    dca_state_t * state = dca_init( 0 );
+
+    memset( info, 0, sizeof(*info) );
+
+    /* since DCA frames don't line up with MPEG ES frames scan the
+     * entire frame for an DCA sync pattern.  */
+    for ( i = 0; i < b->size - 7; ++i )
+    {
+        if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate,
+                          &frame_length ) )
+        {
+            break;
+        }
+    }
+    if ( i >= b->size - 7 )
+    {
+        /* didn't find DCA sync */
+        return 0;
+    }
+
+    info->name = "DCA";
+    info->rate = rate;
+    info->rate_base = 1;
+    info->bitrate = bitrate;
+    info->flags = flags;
+
+    if ( ( flags & DCA_CHANNEL_MASK) == DCA_DOLBY )
+    {
+        info->flags |= AUDIO_F_DOLBY;
+    }
+
+    switch( flags & DCA_CHANNEL_MASK )
+    {
+        /* mono sources */
+        case DCA_MONO:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_MONO;
+            break;
+        /* stereo input */
+        case DCA_CHANNEL:
+        case DCA_STEREO:
+        case DCA_STEREO_SUMDIFF:
+        case DCA_STEREO_TOTAL:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
+            break;
+        /* 3F/2R input */
+        case DCA_3F2R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_3F2R;
+            break;
+        /* 3F/1R input */
+        case DCA_3F1R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_3F1R;
+            break;
+        /* other inputs */
+        case DCA_3F:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_3F;
+            break;
+        case DCA_2F1R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_2F1R;
+            break;
+        case DCA_2F2R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_2F2R;
+            break;
+        case DCA_4F2R:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_4F2R;
+            break;
+        /* unknown */
+        default:
+            info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
+    }
+
+    if (flags & DCA_LFE)
+    {
+        info->channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;
+    }
+
+    return 1;
+}
Index: libhb/declpcm.c
===================================================================
--- libhb/declpcm.c	(revision 1457)
+++ libhb/declpcm.c	(working copy)
@@ -27,9 +27,11 @@
 };
 
 static hb_buffer_t * Decode( hb_work_object_t * w );
-int  declpcmInit( hb_work_object_t *, hb_job_t * );
-int  declpcmWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
-void declpcmClose( hb_work_object_t * );
+static int  declpcmInit( hb_work_object_t *, hb_job_t * );
+static int  declpcmWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+static void declpcmClose( hb_work_object_t * );
+static int  declpcmBSInfo( hb_work_object_t *, const hb_buffer_t *,
+                           hb_work_info_t * );
 
 hb_work_object_t hb_declpcm =
 {
@@ -37,11 +39,19 @@
     "LPCM decoder",
     declpcmInit,
     declpcmWork,
-    declpcmClose
+    declpcmClose,
+    0,
+    declpcmBSInfo
 };
 
 static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 };
 static const int hdr2samplesize[] = { 16, 20, 24, 16 };
+static const int hdr2layout[] = {
+        HB_INPUT_CH_LAYOUT_MONO,   HB_INPUT_CH_LAYOUT_STEREO,
+        HB_INPUT_CH_LAYOUT_2F1R,   HB_INPUT_CH_LAYOUT_2F2R,
+        HB_INPUT_CH_LAYOUT_3F2R,   HB_INPUT_CH_LAYOUT_4F2R,
+        HB_INPUT_CH_LAYOUT_STEREO, HB_INPUT_CH_LAYOUT_STEREO,
+};
 
 static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in )
 {
@@ -103,7 +113,7 @@
     pv->next_pts = in->start;
 }
 
-int declpcmInit( hb_work_object_t * w, hb_job_t * job )
+static int declpcmInit( hb_work_object_t * w, hb_job_t * job )
 {
     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
     w->private_data = pv;
@@ -119,7 +129,7 @@
  * to DVD PES boundaries, this routine has to reconstruct then extract the audio
  * frames. Because of the arbitrary alignment, it can output zero, one or two buf's.
  */
-int declpcmWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+static int declpcmWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
                  hb_buffer_t ** buf_out )
 {
     hb_work_private_t * pv = w->private_data;
@@ -225,7 +235,7 @@
     return out;
 }
 
-void declpcmClose( hb_work_object_t * w )
+static void declpcmClose( hb_work_object_t * w )
 {
     if ( w->private_data )
     {
@@ -233,3 +243,24 @@
         w->private_data = 0;
     }
 }
+
+static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b,
+                          hb_work_info_t *info )
+{
+    int nchannels  = ( b->data[4] & 7 ) + 1;
+    int sample_size = hdr2samplesize[b->data[4] >> 6];
+
+    int rate = hdr2samplerate[ ( b->data[4] >> 4 ) & 0x3 ];
+    int bitrate = rate * sample_size * nchannels;
+
+    memset( info, 0, sizeof(*info) );
+
+    info->name = "LPCM";
+    info->rate = rate;
+    info->rate_base = 1;
+    info->bitrate = bitrate;
+    info->flags = ( b->data[3] << 16 ) | ( b->data[4] << 8 ) | b->data[5];
+    info->channel_layout = hdr2layout[nchannels - 1];
+
+    return 1;
+}
Index: libhb/sync.c
===================================================================
--- libhb/sync.c	(revision 1457)
+++ libhb/sync.c	(working copy)
@@ -8,7 +8,7 @@
 #include <stdio.h>
 
 #include "samplerate.h"
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 
 #ifdef INT64_MIN
 #undef INT64_MIN /* Because it isn't defined correctly in Zeta */
Index: libhb/deinterlace.c
===================================================================
--- libhb/deinterlace.c	(revision 1457)
+++ libhb/deinterlace.c	(working copy)
@@ -17,7 +17,7 @@
 */
 
 #include "hb.h"
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 #include "mpeg2dec/mpeg2.h"
 
 #define SUPPRESS_AV_LOG
Index: libhb/render.c
===================================================================
--- libhb/render.c	(revision 1457)
+++ libhb/render.c	(working copy)
@@ -6,8 +6,8 @@
 
 #include "hb.h"
 
-#include "ffmpeg/avcodec.h"
-#include "ffmpeg/swscale.h"
+#include "libavcodec/avcodec.h"
+#include "libswscale/swscale.h"
 
 struct hb_work_private_s
 {
Index: libhb/decavcodec.c
===================================================================
--- libhb/decavcodec.c	(revision 1457)
+++ libhb/decavcodec.c	(working copy)
@@ -6,11 +6,13 @@
 
 #include "hb.h"
 
-#include "ffmpeg/avcodec.h"
+#include "libavcodec/avcodec.h"
 
-int  decavcodecInit( hb_work_object_t *, hb_job_t * );
-int  decavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
-void decavcodecClose( hb_work_object_t * );
+static int  decavcodecInit( hb_work_object_t *, hb_job_t * );
+static int  decavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+static void decavcodecClose( hb_work_object_t * );
+static int decavcodecInfo( hb_work_object_t *, hb_work_info_t * );
+static int decavcodecBSInfo( hb_work_object_t *, const hb_buffer_t *, hb_work_info_t * );
 
 hb_work_object_t hb_decavcodec =
 {
@@ -18,25 +20,32 @@
     "MPGA decoder (libavcodec)",
     decavcodecInit,
     decavcodecWork,
-    decavcodecClose
+    decavcodecClose,
+    decavcodecInfo,
+    decavcodecBSInfo
 };
 
 struct hb_work_private_s
 {
-    hb_job_t       * job;
-
-    AVCodecContext * context;
-    int64_t          pts_last;
+    hb_job_t             *job;
+    AVCodecContext       *context;
     AVCodecParserContext *parser;
+    hb_list_t            *list;
+    int64_t              pts_next;  // next pts we expect to generate
+    int64_t              pts;       // (video) pts passing from parser to decoder
+    int64_t              chap_time; // time of next chap mark (if new_chap != 0)
+    int                  new_chap;
+    int                  nframes;
 };
 
 
+
 /***********************************************************************
  * hb_work_decavcodec_init
  ***********************************************************************
  *
  **********************************************************************/
-int decavcodecInit( hb_work_object_t * w, hb_job_t * job )
+static int decavcodecInit( hb_work_object_t * w, hb_job_t * job )
 {
     AVCodec * codec;
 
@@ -45,12 +54,15 @@
 
     pv->job   = job;
 
-    codec = avcodec_find_decoder( CODEC_ID_MP2 );
-    pv->parser = av_parser_init(CODEC_ID_MP2);
+    int codec_id = w->codec_param;
+    /*XXX*/
+    if ( codec_id == 0 )
+        codec_id = CODEC_ID_MP2;
+    codec = avcodec_find_decoder( codec_id );
+    pv->parser = av_parser_init( codec_id );
 
     pv->context = avcodec_alloc_context();
     avcodec_open( pv->context, codec );
-    pv->pts_last = -1;
 
     return 0;
 }
@@ -60,11 +72,15 @@
  ***********************************************************************
  *
  **********************************************************************/
-void decavcodecClose( hb_work_object_t * w )
+static void decavcodecClose( hb_work_object_t * w )
 {
     hb_work_private_t * pv = w->private_data;
     av_parser_close(pv->parser);
     avcodec_close( pv->context );
+    if ( pv->list )
+    {
+        hb_list_close( &pv->list );
+    }
 }
 
 /***********************************************************************
@@ -72,7 +88,7 @@
  ***********************************************************************
  *
  **********************************************************************/
-int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+static int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
                     hb_buffer_t ** buf_out )
 {
     hb_work_private_t * pv = w->private_data;
@@ -85,28 +101,24 @@
 
     *buf_out = NULL;
 
-    if( in->start < 0 ||
-        ( pv->pts_last > 0 &&
-          in->start > pv->pts_last &&
-          in->start - pv->pts_last < 5000 ) ) /* Hacky */
-    {
-        cur = pv->pts_last;
-    }
-    else
-    {
-        cur = in->start;
-    }
+    cur = ( in->start < 0 )? pv->pts_next : in->start;
 
     pos = 0;
     while( pos < in->size )
     {
-        len = av_parser_parse(pv->parser, pv->context,&parser_output_buffer,&parser_output_buffer_len,in->data + pos,in->size - pos,cur,cur);
-
+        len = av_parser_parse( pv->parser, pv->context,
+                               &parser_output_buffer, &parser_output_buffer_len,
+                               in->data + pos, in->size - pos, cur, cur );
         out_size = 0;
         uncompressed_len = 0;
         if (parser_output_buffer_len)
-          uncompressed_len = avcodec_decode_audio( pv->context, buffer, &out_size,
-                                    parser_output_buffer, parser_output_buffer_len );
+        {
+            out_size = sizeof(buffer);
+            uncompressed_len = avcodec_decode_audio2( pv->context, buffer,
+                                                      &out_size,
+                                                      parser_output_buffer,
+                                                      parser_output_buffer_len );
+        }
         if( out_size )
         {
             short * s16;
@@ -152,8 +164,331 @@
         pos += len;
     }
 
-    pv->pts_last = cur;
+    pv->pts_next = cur;
 
     return HB_WORK_OK;
 }
 
+static int decavcodecInfo( hb_work_object_t *w, hb_work_info_t *info )
+{
+    hb_work_private_t *pv = w->private_data;
+
+    memset( info, 0, sizeof(*info) );
+
+    if ( pv && pv->context )
+    {
+        AVCodecContext *context = pv->context;
+        info->bitrate = context->bit_rate;
+        info->rate = context->time_base.num;
+        info->rate_base = context->time_base.den;
+        info->profile = context->profile;
+        info->level = context->level;
+        return 1;
+    }
+    return 0;
+}
+
+static int decavcodecBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
+                             hb_work_info_t *info )
+{
+    hb_work_private_t *pv = w->private_data;
+
+    memset( info, 0, sizeof(*info) );
+
+    if ( pv && pv->context )
+    {
+        return decavcodecInfo( w, info );
+    }
+    // XXX
+    // We should parse the bitstream to find its parameters but for right
+    // now we just return dummy values if there's a codec that will handle it.
+    AVCodec *codec = avcodec_find_decoder( w->codec_param? w->codec_param :
+                                                           CODEC_ID_MP2 );
+    if ( codec )
+    {
+        static char codec_name[64];
+
+        info->name =  strncpy( codec_name, codec->name, sizeof(codec_name)-1 );
+        info->bitrate = 384000;
+        info->rate = 48000;
+        info->rate_base = 1;
+        info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
+        return 1;
+    }
+    return -1;
+}
+
+/* -------------------------------------------------------------
+ * General purpose video decoder using libavcodec
+ */
+
+static uint8_t *copy_plane( uint8_t *dst, uint8_t* src, int dstride, int sstride,
+                            int h )
+{
+    if ( dstride == sstride )
+    {
+        memcpy( dst, src, dstride * h );
+        return dst + dstride * h;
+    }
+    int lbytes = dstride <= sstride? dstride : sstride;
+    while ( --h >= 0 )
+    {
+        memcpy( dst, src, lbytes );
+        src += sstride;
+        dst += dstride;
+    }
+    return dst;
+}
+
+/* Note: assumes frame format is PIX_FMT_YUV420P */
+static hb_buffer_t *copy_frame( AVCodecContext *context, AVFrame *frame )
+{
+    int w = context->width, h = context->height;
+    hb_buffer_t *buf = hb_buffer_init( w * h * 3 / 2 );
+    uint8_t *dst = buf->data;
+
+    dst = copy_plane( dst, frame->data[0], w, frame->linesize[0], h );
+    w >>= 1; h >>= 1;
+    dst = copy_plane( dst, frame->data[1], w, frame->linesize[1], h );
+    dst = copy_plane( dst, frame->data[2], w, frame->linesize[2], h );
+
+    return buf;
+}
+
+static int get_frame_buf( AVCodecContext *context, AVFrame *frame )
+{
+    hb_work_private_t *pv = context->opaque;
+    int64_t pts = pv->pts;
+    pv->pts = -1;
+    frame->pts = pts;
+
+    return avcodec_default_get_buffer( context, frame );
+}
+
+static void log_chapter( hb_work_private_t *pv, int chap_num, int64_t pts )
+{
+    hb_chapter_t *c = hb_list_item( pv->job->title->list_chapter, chap_num - 1 );
+    hb_log( "%s: \"%s\" (%d) at frame %u time %lld", pv->context->codec->name,
+            c->title, chap_num, pv->nframes, pts );
+}
+
+static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
+{
+    int got_picture;
+    AVFrame frame;
+
+    int len = avcodec_decode_video( pv->context, &frame, &got_picture, data, size );
+    if ( len < 0 )
+    {
+        hb_log( "avcodec_decode_video err %d", len );
+        return 0;
+    }
+    if( got_picture )
+    {
+        // ffmpeg makes it hard to attach a pts to a frame. if the MPEG ES
+        // packet had a pts we handed it to av_parser_parse (if the packet had
+        // no pts we set it to -1 but before the parse we can't distinguish between
+        // the start of a video frame with no pts & an intermediate packet of
+        // some frame which never has a pts). we hope that when parse returns
+        // the frame to us the pts we originally handed it will be in parser->pts.
+        // we put this pts into pv->pts so that when a avcodec_decode_video
+        // finally gets around to allocating an AVFrame to hold the decoded
+        // frame we can stuff that pts into the frame. if all of these relays
+        // worked at this point frame.pts should hold the frame's pts from the
+        // original data stream or -1 if it didn't have one. in the latter case
+        // we generate the next pts in sequence for it.
+        int64_t pts = frame.pts;
+        if ( pts < 0 )
+        {
+            pts = pv->pts_next;
+        }
+        double frame_dur = (double) pv->context->time_base.num /
+                           (double) pv->context->time_base.den * 90000.;
+        frame_dur += frame.repeat_pict * frame_dur * 0.5;
+        pv->pts_next = (double)pts + frame_dur;
+
+        hb_buffer_t *buf = copy_frame( pv->context, &frame );
+        buf->start = pts;
+
+        if ( pv->new_chap && buf->start >= pv->chap_time )
+        {
+            buf->new_chap = pv->new_chap;
+            pv->new_chap = 0;
+            pv->chap_time = 0;
+            if ( pv->job )
+            {
+                log_chapter( pv, buf->new_chap, buf->start );
+            }
+        }
+        else if ( pv->job && pv->nframes == 0 )
+        {
+            log_chapter( pv, pv->job->chapter_start, buf->start );
+        }
+        hb_list_add( pv->list, buf );
+        ++pv->nframes;
+    }
+    return got_picture;
+}
+
+static void decodeVideo( hb_work_private_t *pv, uint8_t *data, int size,
+                         int64_t pts, int64_t dts )
+{
+    /*
+     * The following loop is a do..while because we need to handle both
+     * data & the flush at the end (signaled by size=0). At the end there's
+     * generally a frame in the parser & one or more frames in the decoder
+     * (depending on the bframes setting).
+     */
+    int pos = 0;
+    do {
+        uint8_t *pout;
+        int pout_len;
+        int len = av_parser_parse( pv->parser, pv->context, &pout, &pout_len,
+                                   data + pos, size - pos, pts, dts );
+        pos += len;
+
+        if ( pout_len > 0 )
+        {
+            pv->pts = pv->parser->pts;
+            decodeFrame( pv, pout, pout_len );
+        }
+    } while ( pos < size );
+
+    /* the stuff above flushed the parser, now flush the decoder */
+    while ( size == 0 && decodeFrame( pv, NULL, 0 ) )
+    {
+    }
+}
+
+static hb_buffer_t *link_buf_list( hb_work_private_t *pv )
+{
+    hb_buffer_t *head = hb_list_item( pv->list, 0 );
+
+    if ( head )
+    {
+        hb_list_rem( pv->list, head );
+
+        hb_buffer_t *last = head, *buf;
+
+        while ( ( buf = hb_list_item( pv->list, 0 ) ) != NULL )
+        {
+            hb_list_rem( pv->list, buf );
+            last->next = buf;
+            last = buf;
+        }
+    }
+    return head;
+}
+
+
+static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
+{
+
+    hb_work_private_t *pv = calloc( 1, sizeof( hb_work_private_t ) );
+    w->private_data = pv;
+    pv->job   = job;
+    pv->list = hb_list_init();
+
+    int codec_id = w->codec_param;
+    pv->parser = av_parser_init( codec_id );
+    pv->context = avcodec_alloc_context2( CODEC_TYPE_VIDEO );
+
+    /* we have to wrap ffmpeg's get_buffer to be able to set the pts (?!) */
+    pv->context->opaque = pv;
+    pv->context->get_buffer = get_frame_buf;
+
+    AVCodec *codec = avcodec_find_decoder( codec_id );
+    avcodec_open( pv->context, codec );
+
+    return 0;
+}
+
+static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+                            hb_buffer_t ** buf_out )
+{
+    hb_work_private_t *pv = w->private_data;
+    hb_buffer_t *in = *buf_in;
+    int64_t pts = -1;
+    int64_t dts = pts;
+
+    *buf_in = NULL;
+
+    /* if we got an empty buffer signaling end-of-stream send it downstream */
+    if ( in->size == 0 )
+    {
+        decodeVideo( pv, in->data, in->size, pts, dts );
+        hb_list_add( pv->list, in );
+        *buf_out = link_buf_list( pv );
+        hb_log( "%s done: %d frames", pv->context->codec->name, pv->nframes );
+        return HB_WORK_DONE;
+    }
+
+    if( in->start >= 0 )
+    {
+        pts = in->start;
+        dts = in->renderOffset;
+    }
+    if ( in->new_chap )
+    {
+        pv->new_chap = in->new_chap;
+        pv->chap_time = pts >= 0? pts : pv->pts_next;
+    }
+    decodeVideo( pv, in->data, in->size, pts, dts );
+    hb_buffer_close( &in );
+    *buf_out = link_buf_list( pv );
+    return HB_WORK_OK;
+}
+
+static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
+{
+    hb_work_private_t *pv = w->private_data;
+
+    memset( info, 0, sizeof(*info) );
+
+    if ( pv && pv->context )
+    {
+        AVCodecContext *context = pv->context;
+        info->bitrate = context->bit_rate;
+        info->width = context->width;
+        info->height = context->height;
+
+        /* ffmpeg gives the frame rate in frames per second while HB wants
+         * it in units of the 27MHz MPEG clock. */
+        info->rate = 27000000;
+        info->rate_base = (int64_t)context->time_base.num * 27000000LL /
+                          context->time_base.den;
+
+        /* ffmpeg returns the Pixel Aspect Ratio (PAR). Handbrake wants the
+         * Display Aspect Ratio so we convert by scaling by the Storage
+         * Aspect Ratio (w/h). We do the calc in floating point to get the
+         * rounding right. We round in the second decimal digit because we
+         * scale the (integer) aspect by 9 to preserve the 1st digit.  */
+        info->aspect = ( (double)context->sample_aspect_ratio.num * 
+                         (double)context->width /
+                         (double)context->sample_aspect_ratio.den /
+                         (double)context->height + 0.05 ) * HB_ASPECT_BASE;
+
+        info->profile = context->profile;
+        info->level = context->level;
+        info->name = context->codec->name;
+        return 1;
+    }
+    return 0;
+}
+
+static int decavcodecvBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
+                             hb_work_info_t *info )
+{
+    return 0;
+}
+
+hb_work_object_t hb_decavcodecv =
+{
+    WORK_DECAVCODECV,
+    "Video decoder (libavcodec)",
+    decavcodecvInit,
+    decavcodecvWork,
+    decavcodecClose,
+    decavcodecvInfo,
+    decavcodecvBSInfo
+};
Index: libhb/internal.h
===================================================================
--- libhb/internal.h	(revision 1457)
+++ libhb/internal.h	(working copy)
@@ -97,24 +97,11 @@
                             volatile int * die, int * error, hb_job_t ** job );
 hb_thread_t  * hb_reader_init( hb_job_t * );
 hb_thread_t  * hb_muxer_init( hb_job_t * );
+hb_work_object_t * hb_get_work( int );
+hb_work_object_t * hb_codec_decoder( int );
+hb_work_object_t * hb_codec_encoder( int );
 
 /***********************************************************************
- * libmpeg2 wrapper
- ***********************************************************************
- * It is exported here because it is used at several places
- **********************************************************************/
-typedef struct   hb_libmpeg2_s hb_libmpeg2_t;
-
-hb_libmpeg2_t  * hb_libmpeg2_init();
-int              hb_libmpeg2_decode( hb_libmpeg2_t *,
-                                      hb_buffer_t * es_buf,
-                                      hb_list_t * raw_list );
-void             hb_libmpeg2_info( hb_libmpeg2_t * m, int * width,
-                                    int * height, int * rate, int * aspect_ratio );
-void             hb_libmpeg2_close( hb_libmpeg2_t ** );
-int              hb_libmpeg2_clear_aspect_ratio( hb_libmpeg2_t * );
-
-/***********************************************************************
  * mpegdemux.c
  **********************************************************************/
 typedef struct {
@@ -213,6 +200,7 @@
     WORK_DECA52,
     WORK_DECDCA,
     WORK_DECAVCODEC,
+    WORK_DECAVCODECV,
     WORK_DECLPCM,
     WORK_ENCFAAC,
     WORK_ENCLAME,
Index: libhb/work.c
===================================================================
--- libhb/work.c	(revision 1457)
+++ libhb/work.c	(working copy)
@@ -70,19 +70,44 @@
     free( work );
 }
 
-static hb_work_object_t * getWork( int id )
+hb_work_object_t * hb_get_work( int id )
 {
     hb_work_object_t * w;
     for( w = hb_objects; w; w = w->next )
     {
         if( w->id == id )
         {
-            return w;
+            hb_work_object_t *wc = malloc( sizeof(*w) );
+            *wc = *w;
+            return wc;
         }
     }
     return NULL;
 }
 
+hb_work_object_t * hb_codec_decoder( int codec )
+{
+    switch( codec )
+    {
+        case HB_ACODEC_AC3:  return hb_get_work( WORK_DECA52 );
+        case HB_ACODEC_DCA:  return hb_get_work( WORK_DECDCA );
+        case HB_ACODEC_MPGA: return hb_get_work( WORK_DECAVCODEC );
+        case HB_ACODEC_LPCM: return hb_get_work( WORK_DECLPCM );
+    }
+    return NULL;
+}
+
+hb_work_object_t * hb_codec_encoder( int codec )
+{
+    switch( codec )
+    {
+        case HB_ACODEC_FAAC:   return hb_get_work( WORK_ENCFAAC );
+        case HB_ACODEC_LAME:   return hb_get_work( WORK_ENCLAME );
+        case HB_ACODEC_VORBIS: return hb_get_work( WORK_ENCVORBIS );
+    }
+    return NULL;
+}
+
 /**
  * Job initialization rountine.
  * Initializes fifos.
@@ -99,10 +124,6 @@
     hb_title_t    * title;
     int             i, j;
     hb_work_object_t * w;
-
-    /* FIXME: This feels really hackish, anything better? */
-    hb_work_object_t * audio_w = NULL;
-    hb_work_object_t * sub_w = NULL;
     hb_work_object_t * final_w = NULL;
 
     hb_audio_t   * audio;
@@ -234,17 +255,19 @@
     job->fifo_mpeg4  = hb_fifo_init( FIFO_CPU_MULT * cpu_count );
 
     /* Synchronization */
-    hb_list_add( job->list_work, ( w = getWork( WORK_SYNC ) ) );
+    hb_list_add( job->list_work, ( w = hb_get_work( WORK_SYNC ) ) );
     w->fifo_in  = NULL;
     w->fifo_out = NULL;
 
     /* Video decoder */
-    hb_list_add( job->list_work, ( w = getWork( WORK_DECMPEG2 ) ) );
+    int vcodec = title->video_codec? title->video_codec : WORK_DECMPEG2;
+    hb_list_add( job->list_work, ( w = hb_get_work( vcodec ) ) );
+    w->codec_param = title->video_codec_param;
     w->fifo_in  = job->fifo_mpeg2;
     w->fifo_out = job->fifo_raw;
 
     /* Video renderer */
-    hb_list_add( job->list_work, ( w = getWork( WORK_RENDER ) ) );
+    hb_list_add( job->list_work, ( w = hb_get_work( WORK_RENDER ) ) );
     w->fifo_in  = job->fifo_sync;
     w->fifo_out = job->fifo_render;
     if ( job->indepth_scan )
@@ -262,21 +285,21 @@
     {
         case HB_VCODEC_FFMPEG:
             hb_log( " + encoder FFmpeg" );
-            w = getWork( WORK_ENCAVCODEC );
+            w = hb_get_work( WORK_ENCAVCODEC );
             break;
         case HB_VCODEC_XVID:
             hb_log( " + encoder XviD" );
-            w = getWork( WORK_ENCXVID );
+            w = hb_get_work( WORK_ENCXVID );
             break;
         case HB_VCODEC_X264:
             hb_log( " + encoder x264" );
             if( job->x264opts != NULL && *job->x264opts != '\0' )
                 hb_log( "   + x264 options: %s", job->x264opts);
-            w = getWork( WORK_ENCX264 );
+            w = hb_get_work( WORK_ENCX264 );
             break;
         case HB_VCODEC_THEORA:
             hb_log( " + encoder Theora" );
-            w = getWork( WORK_ENCTHEORA );
+            w = hb_get_work( WORK_ENCTHEORA );
             break;
     }
     w->fifo_in  = job->fifo_render;
@@ -338,20 +361,10 @@
                  * Don't add threads for subtitles when we are scanning, unless
                  * looking for forced subtitles.
                  */
-                if( sub_w != NULL )
-                {
-                    /*
-                     * Need to copy the prior subtitle structure so that we
-                     * don't overwrite the fifos.
-                     */
-                    sub_w = calloc( sizeof( hb_work_object_t ), 1 );
-                    sub_w = memcpy( sub_w, w, sizeof( hb_work_object_t ));
-                } else {
-                    w = sub_w = getWork( WORK_DECSUB );
-                }
-                hb_list_add( job->list_work, sub_w );
-                sub_w->fifo_in  = subtitle->fifo_in;
-                sub_w->fifo_out = subtitle->fifo_raw;
+                w = hb_get_work( WORK_DECSUB );
+                w->fifo_in  = subtitle->fifo_in;
+                w->fifo_out = subtitle->fifo_raw;
+                hb_list_add( job->list_work, w );
             }
         }
     }
@@ -541,79 +554,42 @@
         /*
          * Audio Decoder Thread
          */
-        switch( audio->config.in.codec )
+        if ( ( w = hb_codec_decoder( audio->config.in.codec ) ) == NULL )
         {
-            case HB_ACODEC_AC3:
-                w = getWork( WORK_DECA52 );
-                break;
-            case HB_ACODEC_DCA:
-                w = getWork( WORK_DECDCA );
-                break;
-            case HB_ACODEC_MPGA:
-                w = getWork( WORK_DECAVCODEC );
-                break;
-            case HB_ACODEC_LPCM:
-                w = getWork( WORK_DECLPCM );
-                break;
-            default:
-                /* Invalid input codec */
-                hb_error("Invalid input codec: %d", audio->config.in.codec);
-                *job->die = 1;
-                goto cleanup;
+            hb_error("Invalid input codec: %d", audio->config.in.codec);
+            *job->die = 1;
+            goto cleanup;
         }
-        w->fifo_in       = audio->priv.fifo_in;
-        w->fifo_out      = audio->priv.fifo_raw;
-        w->config        = &audio->priv.config;
-        w->audio         = audio;
+        w->fifo_in  = audio->priv.fifo_in;
+        w->fifo_out = audio->priv.fifo_raw;
+        w->config   = &audio->priv.config;
+        w->audio    = audio;
+        w->codec_param = audio->config.in.codec_param;
 
-        /* FIXME: This feels really hackish, anything better? */
-        audio_w = calloc( sizeof( hb_work_object_t ), 1 );
-        audio_w = memcpy( audio_w, w, sizeof( hb_work_object_t ));
+        hb_list_add( job->list_work, w );
 
-        hb_list_add( job->list_work, audio_w );
-
         /*
          * Audio Encoder Thread
          */
-        switch( audio->config.out.codec )
+        if( audio->config.out.codec != HB_ACODEC_AC3 )
         {
-            case HB_ACODEC_FAAC:
-                w = getWork( WORK_ENCFAAC );
-                break;
-            case HB_ACODEC_LAME:
-                w = getWork( WORK_ENCLAME );
-                break;
-            case HB_ACODEC_VORBIS:
-                w = getWork( WORK_ENCVORBIS );
-                break;
-            case HB_ACODEC_AC3:
-                break;
-            case HB_ACODEC_DCA:    /* These are all invalid output codecs. */
-            default:
+            /*
+             * Add the encoder thread if not doing AC-3 pass through
+             */
+            if ( ( w = hb_codec_encoder( audio->config.out.codec ) ) == NULL )
+            {
                 hb_error("Invalid audio codec: %#x", audio->config.out.codec);
                 w = NULL;
                 *job->die = 1;
                 goto cleanup;
-        }
+            }
+            w->fifo_in  = audio->priv.fifo_sync;
+            w->fifo_out = audio->priv.fifo_out;
+            w->config   = &audio->priv.config;
+            w->audio    = audio;
 
-        if( audio->config.out.codec != HB_ACODEC_AC3 )
-        {
-            /*
-             * Add the encoder thread if not doing AC-3 pass through
-             */
-            w->fifo_in       = audio->priv.fifo_sync;
-            w->fifo_out      = audio->priv.fifo_out;
-            w->config        = &audio->priv.config;
-            w->audio         = audio;
-
-            /* FIXME: This feels really hackish, anything better? */
-            audio_w = calloc( sizeof( hb_work_object_t ), 1 );
-            audio_w = memcpy( audio_w, w, sizeof( hb_work_object_t ));
-
-            hb_list_add( job->list_work, audio_w );
+            hb_list_add( job->list_work, w );
         }
-
-
     }
 
     /* Init read & write threads */
@@ -655,6 +631,7 @@
     }
     hb_list_rem( job->list_work, w );
     w->close( w );
+    free( w );
     job->done = 1;
 
 cleanup:
@@ -662,23 +639,12 @@
     while( ( w = hb_list_item( job->list_work, 0 ) ) )
     {
         hb_list_rem( job->list_work, w );
-        if( w != NULL && w->thread != NULL )
+        if( w->thread != NULL )
         {
             hb_thread_close( &w->thread );
             w->close( w );
         }
-
-        /* FIXME: This feels really hackish, anything better? */
-        if ( w->id == WORK_DECA52 ||
-             w->id == WORK_DECDCA ||
-             w->id == WORK_DECLPCM ||
-             w->id == WORK_ENCFAAC ||
-             w->id == WORK_ENCLAME ||
-             w->id == WORK_ENCVORBIS )
-        {
-            free( w );
-            w = NULL;
-        }
+        free( w );
     }
 
     hb_list_close( &job->list_work );
@@ -831,7 +797,7 @@
 }
 
 /**
- * Performs the work objects specific work function.
+ * Performs the work object's specific work function.
  * Loops calling work function for associated work object. Sleeps when fifo is full.
  * Monitors work done indicator.
  * Exits loop when work indiactor is set.
Index: libhb/fifo.c
===================================================================
--- libhb/fifo.c	(revision 1457)
+++ libhb/fifo.c	(working copy)
@@ -14,53 +14,63 @@
 struct hb_fifo_s
 {
     hb_lock_t    * lock;
-    int            capacity;
-    int            size;
-    int            buffer_size;
+    uint32_t       capacity;
+    uint32_t       size;
+    uint32_t       buffer_size;
     hb_buffer_t  * first;
     hb_buffer_t  * last;
 };
 
-#define MAX_BUFFER_POOLS  15
-#define BUFFER_POOL_MAX_ELEMENTS 2048
+/* we round the requested buffer size up to the next power of 2 so there can
+ * be at most 32 possible pools when the size is a 32 bit int. To avoid a lot
+ * of slow & error-prone run-time checking we allow for all 32. */
+#define MAX_BUFFER_POOLS  32
+/* the buffer pool only exists to avoid the two malloc and two free calls that
+ * it would otherwise take to allocate & free a buffer. but we don't want to
+ * tie up a lot of memory in the pool because this allocator isn't as general
+ * as malloc so memory tied up here puts more pressure on the malloc pool.
+ * A pool of 16 elements will avoid 94% of the malloc/free calls without wasting
+ * too much memory. */
+#define BUFFER_POOL_MAX_ELEMENTS 32
 
 struct hb_buffer_pools_s
 {
-    int entries;
-    int allocated;
-    hb_fifo_t *pool[MAX_BUFFER_POOLS];
+    int64_t allocated;
     hb_lock_t *lock;
-};
+    hb_fifo_t *pool[MAX_BUFFER_POOLS];
+} buffers;
 
-struct hb_buffer_pools_s buffers;
 
 void hb_buffer_pool_init( void )
 {
-    hb_fifo_t *buffer_pool;
-    int size = 512;
-    int max_size = 32768;;
-
-    buffers.entries = 0;
     buffers.lock = hb_lock_init();
     buffers.allocated = 0;
 
-    while(size <= max_size) {
-        buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
-        buffer_pool->buffer_size = size;
-        size *= 2;
+    /* we allocate pools for sizes 2^10 through 2^25. requests larger than
+     * 2^25 will get passed through to malloc. */
+    int i;
+    for ( i = 10; i < 26; ++i )
+    {
+        buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
+        buffers.pool[i]->buffer_size = 1 << i;
     }
+    /* requests smaller than 2^10 are satisfied from the 2^10 pool. */
+    for ( i = 1; i < 10; ++i )
+    {
+        buffers.pool[i] = buffers.pool[10];
+    }
 }
 
 void hb_buffer_pool_free( void )
 {
     int i;
     int count;
-    int freed = 0;
+    int64_t freed = 0;
     hb_buffer_t *b;
 
     hb_lock(buffers.lock);
 
-    for( i = 0; i < buffers.entries; i++)
+    for( i = 10; i < 26; ++i)
     {
         count = 0;
         while( ( b = hb_fifo_get(buffers.pool[i]) ) )
@@ -69,70 +79,42 @@
             if( b->data )
             {
                 free( b->data );
-                b->data = NULL;
             }
             free( b );
             count++;
         }
-        hb_log("Freed %d buffers of size %d", count, buffers.pool[i]->buffer_size);
+        if ( count )
+        {
+            hb_log("Freed %d buffers of size %d", count,
+                    buffers.pool[i]->buffer_size);
+        }
     }
 
-    hb_log("Allocated %d bytes of buffers on this pass and Freed %d bytes, %d bytes leaked",
-           buffers.allocated, freed, buffers.allocated - freed);
+    hb_log("Allocated %lld bytes of buffers on this pass and Freed %lld bytes, "
+           "%lld bytes leaked", buffers.allocated, freed, buffers.allocated - freed);
     buffers.allocated = 0;
     hb_unlock(buffers.lock);
 }
 
-
-hb_buffer_t * hb_buffer_init( int size )
+static hb_fifo_t *size_to_pool( int size )
 {
-    hb_buffer_t * b;
     int i;
-    hb_fifo_t *buffer_pool = NULL;
-    uint8_t *data;
-    int b_alloc;
-    int resize = 0;
-
-    if( size > 0 )
+    for ( i = 0; i < 30; ++i )
     {
-        /*
-         * The buffer pools are allocated in increasing size
-         */
-        for( i = 0; i < buffers.entries; i++ )
+        if ( size <= (1 << i) )
         {
-            if( buffers.pool[i]->buffer_size >= size )
-            {
-                /*
-                 * This pool is big enough, but are there any buffers in it?
-                 */
-                if( hb_fifo_size( buffers.pool[i] ) )
-                {
-                    /*
-                     * We've found a matching buffer pool, with buffers.
-                     */
-                    buffer_pool = buffers.pool[i];
-                    resize =  buffers.pool[i]->buffer_size;
-                } else {
-                    /*
-                     * Buffer pool is empty,
-                     */
-                    if( resize ) {
-                        /*
-                         * This is the second time through, so break
-                         * out of here to avoid using too large a
-                         * buffer for a small job.
-                         */
-                        break;
-                    }
-                    resize =  buffers.pool[i]->buffer_size;
-                }
-            }
+            return buffers.pool[i];
         }
     }
-    /*
-     * Don't reuse the 0 size buffers, not much gain.
-     */
-    if( size != 0 && buffer_pool )
+    return NULL;
+}
+
+hb_buffer_t * hb_buffer_init( int size )
+{
+    hb_buffer_t * b;
+    hb_fifo_t *buffer_pool = size_to_pool( size );
+
+    if( buffer_pool )
     {
         b = hb_fifo_get( buffer_pool );
 
@@ -141,15 +123,10 @@
             /*
              * Zero the contents of the buffer, would be nice if we
              * didn't have to do this.
-             *
-            hb_log("Reused buffer size %d for size %d from pool %d depth %d",
-                   b->alloc, size, smallest_pool->buffer_size,
-                   hb_fifo_size(smallest_pool));
-            */
-            data = b->data;
-            b_alloc = b->alloc;
+             */
+            uint8_t *data = b->data;
             memset( b, 0, sizeof(hb_buffer_t) );
-            b->alloc = b_alloc;
+            b->alloc = buffer_pool->buffer_size;
             b->size = size;
             b->data = data;
             return( b );
@@ -166,152 +143,66 @@
     }
 
     b->size  = size;
+    b->alloc  = buffer_pool? buffer_pool->buffer_size : size;
 
-    if( resize )
+    if (size)
     {
-        size = resize;
-    }
-    b->alloc  = size;
-
-    /*
-    hb_log("Allocating new buffer of size %d for size %d",
-           b->alloc,
-           b->size);
-    */
-
-    if (!size)
-        return b;
 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
-    b->data  = malloc( b->alloc );
+        b->data  = malloc( b->alloc );
 #elif defined( SYS_CYGWIN )
-    /* FIXME */
-    b->data  = malloc( b->alloc + 17 );
+        /* FIXME */
+        b->data  = malloc( b->alloc + 17 );
 #else
-    b->data  = memalign( 16, b->alloc );
+        b->data  = memalign( 16, b->alloc );
 #endif
-
-    if( !b->data )
-    {
-        hb_log( "out of memory" );
-        free( b );
-        return NULL;
+        if( !b->data )
+        {
+            hb_log( "out of memory" );
+            free( b );
+            return NULL;
+        }
+        hb_lock(buffers.lock);
+        buffers.allocated += b->alloc;
+        hb_unlock(buffers.lock);
     }
-
-    buffers.allocated += b->alloc;
-
     return b;
 }
 
 void hb_buffer_realloc( hb_buffer_t * b, int size )
 {
-    /* No more alignment, but we don't care */
-    if( size < 2048 ) {
-        size = 2048;
+    if ( size > b->alloc )
+    {
+        uint32_t orig = b->alloc;
+        size = size_to_pool( size )->buffer_size;
+        b->data  = realloc( b->data, size );
+        b->alloc = size;
+
+        hb_lock(buffers.lock);
+        buffers.allocated += size - orig;
+        hb_unlock(buffers.lock);
     }
-    b->data  = realloc( b->data, size );
-    buffers.allocated -= b->alloc;
-    b->alloc = size;
-    buffers.allocated += b->alloc;
 }
 
 void hb_buffer_close( hb_buffer_t ** _b )
 {
     hb_buffer_t * b = *_b;
-    hb_fifo_t *buffer_pool = NULL;
-    int i;
+    hb_fifo_t *buffer_pool = size_to_pool( b->alloc );
 
-    /*
-     * Put the buffer into our free list in the matching buffer pool, if there is one.
-     */
-    if( b->alloc != 0 )
+    if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
     {
-        for( i = 0; i < buffers.entries; i++ )
-        {
-            if( b->alloc == buffers.pool[i]->buffer_size )
-            {
-                buffer_pool = buffers.pool[i];
-                break;
-            }
-        }
+        hb_fifo_push( buffer_pool, b );
+        return;
     }
-
-    if( buffer_pool )
+    /* either the pool is full or this size doesn't use a pool - free the buf */
+    if( b->data )
     {
-        if( !hb_fifo_is_full( buffer_pool ) )
-        {
-            if(b->data)
-            {
-                /*
-                hb_log("Putting a buffer of size %d on pool %d, depth %d",
-                       b->alloc,
-                       buffer_pool->buffer_size,
-                       hb_fifo_size(buffer_pool));
-                */
-                hb_fifo_push( buffer_pool, b );
-            } else {
-                free(b);
-            }
-        } else {
-            /*
-             * Got a load of these size ones already, free this buffer.
-             *
-            hb_log("Buffer pool for size %d full, freeing buffer", b->alloc);
-            */
-            if( b->data )
-            {
-                free( b->data );
-            }
-            buffers.allocated -= b->alloc;
-            free( b );
-        }
-    } else {
-        /*
-         * Need a new buffer pool for this size.
-         */
+        free( b->data );
         hb_lock(buffers.lock);
-        if ( b->alloc != 0 && buffers.entries < MAX_BUFFER_POOLS)
-        {
-            buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
-            buffer_pool->buffer_size = b->alloc;
-            hb_fifo_push( buffer_pool, b );
-            /*
-            hb_log("*** Allocated a new buffer pool for size %d [%d]", b->alloc,
-                   buffers.entries );
-            */
-        } else {
-            if( b->alloc != 0 )
-            {
-                for( i = buffers.entries-1; i >= 0; i-- )
-                {
-                    if( hb_fifo_size(buffers.pool[i]) == 0 )
-                    {
-                        /*
-                         * Reuse this pool as it is empty.
-                         */
-                        buffers.pool[i]->buffer_size = b->alloc;
-                        hb_fifo_push( buffers.pool[i], b );
-                        b = NULL;
-                        break;
-                    }
-                }
-            }
-
-            if( b )
-            {
-                if( b->data )
-                {
-                    free( b->data );
-                    b->data = NULL;
-                    buffers.allocated -= b->alloc;
-                }
-                free( b );
-            }
-        }
+        buffers.allocated -= b->alloc;
         hb_unlock(buffers.lock);
     }
-
+    free( b );
     *_b = NULL;
-
 }
 
 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
Index: libhb/scan.c
===================================================================
--- libhb/scan.c	(revision 1457)
+++ libhb/scan.c	(working copy)
@@ -237,16 +237,15 @@
 static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
 {
     int             i, npreviews = 0;
-    hb_buffer_t   * buf_ps, * buf_es, * buf_raw;
-    hb_list_t     * list_es, * list_raw;
-    hb_libmpeg2_t * mpeg2;
+    hb_buffer_t   * buf_ps, * buf_es;
+    hb_list_t     * list_es;
     int progressive_count = 0;
     int interlaced_preview_count = 0;
-    int last_ar = 0, ar16_count = 0, ar4_count = 0;
+    double last_ar = 0;
+    int ar16_count = 0, ar4_count = 0;
 
     buf_ps   = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
     list_es  = hb_list_init();
-    list_raw = hb_list_init();
 
     hb_log( "scan: decoding previews for title %d", title->index );
 
@@ -263,7 +262,7 @@
         {
           if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / 11.0 ) )
           {
-              goto error;
+              continue;
           }
         }
         else if (data->stream)
@@ -273,13 +272,17 @@
            * file and we need it to decode any previews. */
           if (!hb_stream_seek(data->stream, (float) i / 11.0 ) )
           {
-            goto error;
+              continue;
           }
         }
 
         hb_log( "scan: preview %d", i + 1 );
 
-        mpeg2 = hb_libmpeg2_init();
+        int vcodec = title->video_codec? title->video_codec : WORK_DECMPEG2;
+        hb_work_object_t *vid_decoder = hb_get_work( vcodec );
+        vid_decoder->codec_param = title->video_codec_param;
+        vid_decoder->init( vid_decoder, NULL );
+        hb_buffer_t * vid_buf = NULL;
 
         for( j = 0; j < 10240 ; j++ )
         {
@@ -304,78 +307,65 @@
             while( ( buf_es = hb_list_item( list_es, 0 ) ) )
             {
                 hb_list_rem( list_es, buf_es );
-                if( buf_es->id == 0xE0 && !hb_list_count( list_raw ) )
+                if( buf_es->id == 0xE0 && vid_buf == NULL )
                 {
-                    hb_libmpeg2_decode( mpeg2, buf_es, list_raw );
-                    int ar = hb_libmpeg2_clear_aspect_ratio( mpeg2 );
-                    if ( ar != 0 )
-                    {
-                        if ( ar != last_ar && last_ar != 0 )
-                        {
-                            hb_log( "aspect ratio changed from %d to %d",
-                                    last_ar, ar );
-                        }
-                        switch ( ar )
-                        {
-                            case HB_ASPECT_BASE * 4 / 3:
-                                ++ar4_count;
-                                break;
-                            case HB_ASPECT_BASE * 16 / 9:
-                                ++ar16_count;
-                                break;
-                            default:
-                                hb_log( "unknown aspect ratio %d", ar );
-                                /* if the aspect is closer to 4:3 use that
-                                 * otherwise use 16:9 */
-                                if ( ar < HB_ASPECT_BASE * 14 / 9 )
-                                {
-                                    ++ar4_count;
-                                }
-                                else
-                                {
-                                    ++ar16_count;
-                                }
-                                break;
-                        }
-                    }
-                    last_ar = ar;
+                    vid_decoder->work( vid_decoder, &buf_es, &vid_buf );
                 }
                 else if( ! AllAudioOK( title ) )
                 {
                     LookForAudio( title, buf_es );
                 }
-                hb_buffer_close( &buf_es );
-
-                if( hb_list_count( list_raw ) && AllAudioOK( title ) )
-                {
-                    /* We got a picture */
-                    break;
-                }
+                if ( buf_es )
+                    hb_buffer_close( &buf_es );
             }
 
-            if( hb_list_count( list_raw ) && AllAudioOK( title ) )
-            {
+            if( vid_buf && AllAudioOK( title ) )
                 break;
-            }
         }
 
-        if( !hb_list_count( list_raw ) )
+        if( ! vid_buf )
         {
             hb_log( "scan: could not get a decoded picture" );
             continue;
         }
 
         /* Get size and rate infos */
-        title->rate = 27000000;
-        int ar;
-        hb_libmpeg2_info( mpeg2, &title->width, &title->height,
-                          &title->rate_base, &ar );
 
-        /* if we found mostly 4:3 previews use that as the aspect ratio otherwise
-           use 16:9 */
-        title->aspect = ar4_count > ar16_count ?
-                            HB_ASPECT_BASE * 4 / 3 : HB_ASPECT_BASE * 16 / 9;
+        hb_work_info_t vid_info;
+        vid_decoder->info( vid_decoder, &vid_info );
+        vid_decoder->close( vid_decoder );
+        free( vid_decoder );
 
+        title->width = vid_info.width;
+        title->height = vid_info.height;
+        title->rate = vid_info.rate;
+        title->rate_base = vid_info.rate_base;
+        if ( vid_info.aspect != 0 )
+        {
+            if ( vid_info.aspect != last_ar && last_ar != 0 )
+            {
+                hb_log( "aspect ratio changed from %g to %g",
+                        last_ar, vid_info.aspect );
+            }
+            switch ( (int)vid_info.aspect )
+            {
+                case HB_ASPECT_BASE * 4 / 3:
+                    ++ar4_count;
+                    break;
+                case HB_ASPECT_BASE * 16 / 9:
+                    ++ar16_count;
+                    break;
+                default:
+                    hb_log( "unknown aspect ratio %g", vid_info.aspect );
+                    /* if the aspect is closer to 4:3 use that
+                     * otherwise use 16:9 */
+                    vid_info.aspect < HB_ASPECT_BASE * 14 / 9 ? ++ar4_count :
+                                                                ++ar16_count;
+                    break;
+            }
+            last_ar = vid_info.aspect;
+        }
+
         if( title->rate_base == 1126125 )
         {
             /* Frame FPS is 23.976 (meaning it's progressive), so
@@ -421,18 +411,14 @@
             title->crop[2] = title->crop[3] = title->width / 2;
         }
 
-        hb_libmpeg2_close( &mpeg2 );
-
         while( ( buf_es = hb_list_item( list_es, 0 ) ) )
         {
             hb_list_rem( list_es, buf_es );
             hb_buffer_close( &buf_es );
         }
 
-        buf_raw = hb_list_item( list_raw, 0 );
-
         /* Check preview for interlacing artifacts */
-        if( hb_detect_comb( buf_raw, title->width, title->height, 10, 30, 9 ) )
+        if( hb_detect_comb( vid_buf, title->width, title->height, 10, 30, 9 ) )
         {
             hb_log("Interlacing detected in preview frame %i", i);
             interlaced_preview_count++;
@@ -444,7 +430,7 @@
         file_preview = fopen( filename, "w" );
         if( file_preview )
         {
-            fwrite( buf_raw->data, title->width * title->height * 3 / 2,
+            fwrite( vid_buf->data, title->width * title->height * 3 / 2,
                     1, file_preview );
             fclose( file_preview );
         }
@@ -453,14 +439,14 @@
             hb_log( "scan: fopen failed (%s)", filename );
         }
 
-#define Y    buf_raw->data
+#define Y    vid_buf->data
 #define DARK 64
 
         /* Detect black borders */
 
         for( j = 0; j < title->width; j++ )
         {
-            for( k = 0; k < title->crop[0]; k++ )
+            for( k = 2; k < title->crop[0]; k++ )
                 if( Y[ k * title->width + j ] > DARK )
                 {
                     title->crop[0] = k;
@@ -493,13 +479,15 @@
         ++npreviews;
 
 skip_preview:
-        while( ( buf_raw = hb_list_item( list_raw, 0 ) ) )
-        {
-            hb_list_rem( list_raw, buf_raw );
-            hb_buffer_close( &buf_raw );
-        }
+        if ( vid_buf )
+            hb_buffer_close( &vid_buf );
     }
 
+    /* if we found mostly 4:3 previews use that as the aspect ratio otherwise
+       use 16:9 */
+    title->aspect = ar4_count > ar16_count ?
+                        HB_ASPECT_BASE * 4 / 3 : HB_ASPECT_BASE * 16 / 9;
+
     title->crop[0] = EVEN( title->crop[0] );
     title->crop[1] = EVEN( title->crop[1] );
     title->crop[2] = EVEN( title->crop[2] );
@@ -523,12 +511,6 @@
         title->detected_interlacing = 0;
     }
 
-    goto cleanup;
-
-error:
-    npreviews = 0;
-
-cleanup:
     hb_buffer_close( &buf_ps );
     while( ( buf_es = hb_list_item( list_es, 0 ) ) )
     {
@@ -536,236 +518,12 @@
         hb_buffer_close( &buf_es );
     }
     hb_list_close( &list_es );
-    while( ( buf_raw = hb_list_item( list_raw, 0 ) ) )
-    {
-        hb_list_rem( list_raw, buf_raw );
-        hb_buffer_close( &buf_raw );
-    }
-    hb_list_close( &list_raw );
     if (data->dvd)
       hb_dvd_stop( data->dvd );
 
     return npreviews;
 }
 
-static void update_audio_description( const char *codec, hb_audio_t *audio,
-                                      int is_dolby )
-{
-    hb_log( "scan: %s, rate=%dHz, bitrate=%d", codec, audio->config.in.samplerate,
-            audio->config.in.bitrate );
-
-    /* XXX */
-    if ( is_dolby )
-    {
-        strcat( audio->config.lang.description, " (Dolby Surround)" );
-        return;
-    }
-
-    char *desc = audio->config.lang.description +
-                    strlen( audio->config.lang.description );
-    sprintf( desc, " (%d.%d ch)",
-       HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->config.in.channel_layout) +
-       HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->config.in.channel_layout),
-       HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->config.in.channel_layout));
-}
-
-static int hb_setup_a52_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
-    int i, rate, bitrate, flags;
-
-    /* since AC3 frames don't line up with MPEG ES frames scan the
-     * entire frame for an AC3 sync pattern.  */
-    for ( i = 0; i < b->size - 7; ++i )
-    {
-        if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) != 0 )
-        {
-            break;
-        }
-    }
-    if ( i >= b->size - 7 )
-    {
-        /* didn't find AC3 sync */
-        return 0;
-    }
-
-    audio->config.in.samplerate = rate;
-    audio->config.in.bitrate = bitrate;
-
-    switch( flags & A52_CHANNEL_MASK )
-    {
-        /* mono sources */
-        case A52_MONO:
-        case A52_CHANNEL1:
-        case A52_CHANNEL2:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;
-            break;
-        /* stereo input */
-        case A52_CHANNEL:
-        case A52_STEREO:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
-            break;
-        /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */
-        case A52_DOLBY:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_DOLBY;
-            break;
-        /* 3F/2R input */
-        case A52_3F2R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;
-            break;
-        /* 3F/1R input */
-        case A52_3F1R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;
-            break;
-        /* other inputs */
-        case A52_3F:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;
-            break;
-        case A52_2F1R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;
-            break;
-        case A52_2F2R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;
-            break;
-        /* unknown */
-        default:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
-    }
-
-    if (flags & A52_LFE)
-    {
-        audio->config.in.channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;
-    }
-
-    /* store the AC3 flags for future reference
-     * This enables us to find out if we had a stereo or Dolby source later on
-     * Store the ac3 flags in the public ac3flags property too, so we can access
-     * it from the GUI
-     */
-    audio->config.flags.ac3 = audio->priv.config.a52.ac3flags = flags;
-    update_audio_description( "AC3", audio, (flags & A52_CHANNEL_MASK) == A52_DOLBY );
-    return 1;
-}
-
-static int hb_setup_dca_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
-    int i, flags, rate, bitrate, frame_length;
-    dca_state_t * state = dca_init( 0 );
-
-    /* since DCA frames don't line up with MPEG ES frames scan the
-     * entire frame for an DCA sync pattern.  */
-    for ( i = 0; i < b->size - 7; ++i )
-    {
-        if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate,
-                          &frame_length ) )
-        {
-            break;
-        }
-    }
-    if ( i >= b->size - 7 )
-    {
-        /* didn't find DCA sync */
-        return 0;
-    }
-
-    audio->config.in.samplerate = rate;
-    audio->config.in.bitrate = bitrate;
-    switch( flags & DCA_CHANNEL_MASK )
-    {
-        /* mono sources */
-        case DCA_MONO:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;
-            break;
-        /* stereo input */
-        case DCA_CHANNEL:
-        case DCA_STEREO:
-        case DCA_STEREO_SUMDIFF:
-        case DCA_STEREO_TOTAL:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
-            break;
-        /* 3F/2R input */
-        case DCA_3F2R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;
-            break;
-        /* 3F/1R input */
-        case DCA_3F1R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;
-            break;
-        /* other inputs */
-        case DCA_3F:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;
-            break;
-        case DCA_2F1R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;
-            break;
-        case DCA_2F2R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;
-            break;
-        case DCA_4F2R:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_4F2R;
-            break;
-        /* unknown */
-        default:
-            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
-    }
-
-    if (flags & DCA_LFE)
-    {
-        audio->config.in.channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;
-    }
-
-    /* store the DCA flags for future reference
-     * This enables us to find out if we had a stereo or Dolby source later on
-     * store the dca flags in the public dcaflags property too, so we can access
-     * it from the GUI
-     */
-    audio->config.flags.dca = audio->priv.config.dca.dcaflags = flags;
-    update_audio_description( "DCA", audio, (flags & DCA_CHANNEL_MASK) == DCA_DOLBY );
-    return 1;
-}
-
-static int hb_setup_pcm_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
-    // LPCM doesn't have a sync pattern like AC3 or DCA but every
-    // LPCM elementary stream packet starts with a 7 byte header
-    // giving the characteristics of the stream.
-    // See libhb/declpcm.c for a description of the LPCM header.
-
-    static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 };
-    static const int hdr2samplesize[] = { 16, 20, 24, 16 };
-    static const int hdr2layout[] = {
-            HB_INPUT_CH_LAYOUT_MONO,   HB_INPUT_CH_LAYOUT_STEREO,
-            HB_INPUT_CH_LAYOUT_2F1R,   HB_INPUT_CH_LAYOUT_2F2R,
-            HB_INPUT_CH_LAYOUT_3F2R,   HB_INPUT_CH_LAYOUT_4F2R,
-            HB_INPUT_CH_LAYOUT_STEREO, HB_INPUT_CH_LAYOUT_STEREO,
-    };
-
-    int nchannels  = ( b->data[4] & 7 ) + 1;
-    int sample_size = hdr2samplesize[b->data[4] >> 6];
-
-    int rate = hdr2samplerate[ ( b->data[4] >> 4 ) & 0x3 ];
-    int bitrate = rate * sample_size * nchannels;
-
-    audio->config.in.samplerate = rate;
-    audio->config.in.bitrate = bitrate;
-    audio->config.in.channel_layout = hdr2layout[nchannels - 1];
-    update_audio_description( "LPCM", audio, 0 );
-    return 1;
-}
-
-static int hb_setup_mpg_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
-    /* XXX
-     * This is a placeholder to get the audio sample rate set.
-     * It should be replaced by something that extracts the correct info from
-     * the mpeg audio bitstream.
-     */
-    audio->config.in.samplerate = 48000;
-    audio->config.in.bitrate = 384000;
-    audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
-    update_audio_description( "MPGA", audio, 0 );
-    return 1;
-}
-
 /*
  * This routine is called for every frame from a non-video elementary stream.
  * These are a mix of audio & subtitle streams, some of which we want & some
@@ -804,29 +562,64 @@
         return;
     }
 
-    switch ( audio->config.in.codec )
+    hb_work_object_t *w = hb_codec_decoder( audio->config.in.codec );
+
+    if ( w == NULL || w->bsinfo == NULL )
     {
-        case HB_ACODEC_AC3:
-            hb_setup_a52_audio( audio, b );
-            break;
+        hb_log( "Internal error in scan: unhandled audio type %d for id 0x%x",
+                audio->config.in.codec, audio->id );
+        goto drop_audio;
+    }
 
-        case HB_ACODEC_DCA:
-            hb_setup_dca_audio( audio, b );
-            break;
+    hb_work_info_t info;
+    w->audio = audio;
+    w->codec_param = audio->config.in.codec_param;
+    int ret = w->bsinfo( w, b, &info );
+    if ( ret < 0 )
+    {
+        hb_log( "no info on audio type %d/%d for id 0x%x",
+                audio->config.in.codec, audio->config.in.codec_param, audio->id );
+        goto drop_audio;
+    }
+    audio->config.in.samplerate = info.rate;
+    audio->config.in.bitrate = info.bitrate;
+    audio->config.in.channel_layout = info.channel_layout;
+    audio->config.flags.ac3 = info.flags;
 
-        case HB_ACODEC_LPCM:
-            hb_setup_pcm_audio( audio, b );
-            break;
+    // update the audio description string based on the info we found
+    if ( audio->config.flags.ac3 & AUDIO_F_DOLBY )
+    {
+        strcat( audio->config.lang.description, " (Dolby Surround)" );
+    }
+    else
+    {
+        int layout = audio->config.in.channel_layout;
+        char *desc = audio->config.lang.description +
+                        strlen( audio->config.lang.description );
+        sprintf( desc, " (%d.%d ch)",
+                 HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(layout) +
+                     HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(layout),
+                 HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(layout) );
+    }
 
-        case HB_ACODEC_MPGA:
-            hb_setup_mpg_audio( audio, b );
-            break;
+    hb_log( "scan: audio 0x%x: %s, rate=%dHz, bitrate=%d %s", audio->id,
+            info.name, audio->config.in.samplerate, audio->config.in.bitrate,
+            audio->config.lang.description );
+ 
+    free( w );
+    return;
 
-        default:
-            hb_log( "Internal error in scan: unhandled audio type %d for 0x%x",
-                    audio->config.in.codec, audio->id );
-            break;
-    }
+    // We get here if there's no hope of finding info on an audio bitstream,
+    // either because we don't have a decoder (or a decoder with a bitstream
+    // info proc) or because the decoder's info proc said that the stream
+    // wasn't something it could handle. Delete the item from the title's
+    // audio list so we won't keep reading packets while trying to get its
+    // bitstream info.
+ drop_audio:
+    if ( w )
+        free( w );
+
+    hb_list_rem( title->list_audio, audio );
 }
 
 /*
Index: libhb/common.h
===================================================================
--- libhb/common.h	(revision 1457)
+++ libhb/common.h	(working copy)
@@ -251,6 +251,7 @@
 #define HB_ACODEC_MPGA   0x001000
 #define HB_ACODEC_LPCM   0x002000
 #define HB_ACODEC_DCA    0x004000
+#define HB_ACODEC_AAC    0x008000
 
 /* Audio Mixdown */
 /* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */
@@ -329,8 +330,9 @@
     /* Input */
     struct
     {
-                int track;      /* Input track number */
-        PRIVATE uint32_t codec;      /* Input audio codec */
+        int track;                /* Input track number */
+        PRIVATE uint32_t codec;   /* Input audio codec */
+        PRIVATE uint32_t codec_param; /* per-codec config info */
         PRIVATE int samplerate; /* Input sample rate (Hz) */
         PRIVATE int bitrate;    /* Input bitrate (kbps) */
         PRIVATE int channel_layout;
@@ -345,6 +347,7 @@
         PRIVATE int ac3;    /* flags.ac3 is only set when the source audio format is HB_ACODEC_AC3 */
         PRIVATE int dca;    /* flags.dca is only set when the source audio format is HB_ACODEC_DCA */
     } flags;
+#define AUDIO_F_DOLBY (1 << 31)  /* set if source uses Dolby Surround */
 
     struct
     {
@@ -438,6 +441,8 @@
     int         rate_base;
     int         crop[4];
     int         detected_interlacing;
+    int         video_codec;            /* worker object id of video codec */
+    int         video_codec_param;      /* codec specific config */
 
     uint32_t    palette[16];
 
@@ -501,6 +506,27 @@
     } param;
 };
 
+typedef struct hb_work_info_s
+{
+    const char *name;
+    int     profile;
+    int     level;
+    int     bitrate;
+    int     rate;
+    int     rate_base;
+    int     flags;
+    union {
+        struct {    // info only valid for video decoders
+            int     width;
+            int     height;
+            double  aspect;
+        };
+        struct {    // info only valid for audio decoders
+            int     channel_layout;
+        };
+    };
+} hb_work_info_t;
+
 struct hb_work_object_s
 {
     int                 id;
@@ -511,6 +537,18 @@
     int              (* work)  ( hb_work_object_t *, hb_buffer_t **,
                                  hb_buffer_t ** );
     void             (* close) ( hb_work_object_t * );
+    /* the info entry point is used by scan to get bitstream information
+     * during a decode (i.e., it should only be called after at least one
+     * call to the 'work' entry point). currently it's only called for
+     * video streams & can be null for other work objects. */
+    int              (* info)  ( hb_work_object_t *, hb_work_info_t * );
+    /* the bitstream info entry point is used by scan to get bitstream
+     * information from a buffer. it doesn't have to be called during a
+     * decode (it can be called even if init & work haven't been).
+     * currently it's only called for audio streams & can be null for
+     * other work objects. */
+    int              (* bsinfo)  ( hb_work_object_t *, const hb_buffer_t *, 
+                                   hb_work_info_t * );
 
     hb_fifo_t         * fifo_in;
     hb_fifo_t         * fifo_out;
@@ -524,6 +562,7 @@
     hb_thread_t       * thread;
     volatile int      * done;
     int                 status;
+    int                 codec_param;
 
     hb_work_object_t  * next;
 	int				  thread_sleep_interval;
@@ -541,6 +580,7 @@
 extern hb_work_object_t hb_deca52;
 extern hb_work_object_t hb_decdca;
 extern hb_work_object_t hb_decavcodec;
+extern hb_work_object_t hb_decavcodecv;
 extern hb_work_object_t hb_declpcm;
 extern hb_work_object_t hb_encfaac;
 extern hb_work_object_t hb_enclame;
Index: contrib/version_ffmpeg.txt
===================================================================
--- contrib/version_ffmpeg.txt	(revision 1457)
+++ contrib/version_ffmpeg.txt	(working copy)
@@ -1 +1 @@
-http://download.m0k.org/handbrake/contrib/ffmpeg-9816.tar.gz
+http://download.m0k.org/handbrake/contrib/ffmpeg-r13110.tar.gz
Index: contrib/Jamfile
===================================================================
--- contrib/Jamfile	(revision 1457)
+++ contrib/Jamfile	(working copy)
@@ -78,10 +78,10 @@
     cd `dirname $(>)` && CONTRIB=`pwd` &&
     rm -rf ffmpeg && (gzip -dc ffmpeg.tar.gz | tar xf -) &&
     cd ffmpeg && $(FFMPEG_PATCH) &&
-    ./configure --prefix=$CONTRIB --enable-gpl --enable-pthreads --enable-swscaler --disable-audio-beos --disable-shared --enable-static \
-        --disable-decoders --enable-decoder=mp2 --disable-parsers --enable-parser=mpegaudio \
-        --disable-encoders --enable-encoder=mpeg4 --enable-encoder=ac3 --enable-encoder=snow \
-        --disable-muxers --enable-muxer=ipod --disable-demuxers --disable-protocols --disable-bsfs &&
+    ./configure --prefix=$CONTRIB --enable-gpl --enable-pthreads --enable-swscale \
+        --disable-shared --enable-static --disable-encoders \
+        --enable-encoder=mpeg4 --enable-encoder=ac3 --enable-encoder=snow \
+        --disable-muxers --enable-muxer=ipod --disable-protocols --disable-bsfs &&
     $(MAKE) && $(MAKE) install &&
     $(STRIP) $CONTRIB/lib/libavcodec.a
 }
Index: contrib/patch-ffmpeg.patch
===================================================================
--- contrib/patch-ffmpeg.patch	(revision 1457)
+++ contrib/patch-ffmpeg.patch	(working copy)
@@ -1,28 +1,3 @@
-Index: configure
-===================================================================
---- configure	(revision 9814)
-+++ configure	(working copy)
-@@ -1095,7 +1095,7 @@
-       2.9-beos-991026*|2.9-beos-000224*) echo "R5/GG gcc"
-         mmx="no"
-         ;;
--      *20010315*) echo "BeBits gcc"
-+      *20010315*|2.95.3*) echo "BeBits gcc"
-         add_cflags "-fno-expensive-optimizations"
-         ;;
-     esac
-Index: libavformat/Makefile
-===================================================================
---- libavformat/Makefile	(revision 9814)
-+++ libavformat/Makefile	(working copy)
-@@ -69,6 +69,7 @@
- OBJS-$(CONFIG_IMAGE2PIPE_MUXER)          += img2.o
- OBJS-$(CONFIG_INGENIENT_DEMUXER)         += raw.o
- OBJS-$(CONFIG_IPMOVIE_DEMUXER)           += ipmovie.o
-+OBJS-$(CONFIG_IPOD_MUXER)                += movenc.o riff.o isom.o
- OBJS-$(CONFIG_M4V_DEMUXER)               += raw.o
- OBJS-$(CONFIG_M4V_MUXER)                 += raw.o
- OBJS-$(CONFIG_MATROSKA_DEMUXER)          += matroskadec.o matroska.o riff.o
 Index: libavformat/tcp.c
 ===================================================================
 --- libavformat/tcp.c	(revision 9814)
@@ -41,233 +16,3 @@
      }
      s->fd = fd;
      return 0;
-Index: libavformat/movenc.c
-===================================================================
---- libavformat/movenc.c	(revision 9814)
-+++ libavformat/movenc.c	(working copy)
-@@ -36,6 +36,7 @@
- #define MODE_PSP 3 // example working PSP command line:
- // ffmpeg -i testinput.avi  -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
- #define MODE_3G2 4
-+#define MODE_IPOD 5
- 
- typedef struct MOVIentry {
-     unsigned int flags, size;
-@@ -54,6 +55,7 @@
-     long        time;
-     int64_t     trackDuration;
-     long        sampleCount;
-+    long        sampleDuration;
-     long        sampleSize;
-     int         hasKeyframes;
-     int         hasBframes;
-@@ -572,6 +574,18 @@
-     return tag;
- }
- 
-+static int mov_write_colr_tag(ByteIOContext *pb)
-+{
-+	put_be32( pb, 0x12 );
-+	put_tag( pb, "colr" );
-+	put_tag( pb, "nclc" );
-+	put_be16( pb, 6 );
-+	put_be16( pb, 1 );
-+	put_be16( pb, 6 );
-+	put_be32( pb, 0 );
-+	return 0x12;
-+}
-+
- static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
- {
-     offset_t pos = url_ftell(pb);
-@@ -621,9 +635,22 @@
-         mov_write_d263_tag(pb);
-     else if(track->enc->codec_id == CODEC_ID_SVQ3)
-         mov_write_svq3_tag(pb);
--    else if(track->enc->codec_id == CODEC_ID_H264)
--        mov_write_avcc_tag(pb, track);
-+	else if(track->enc->codec_id == CODEC_ID_H264) {
-+		mov_write_avcc_tag(pb, track);
-+		if (track->mode == MODE_IPOD) {
-+			put_be32(pb, 0x1C); /* size ... reports as 28 in mp4box! */
-+			put_tag(pb, "uuid");
-+			put_be32(pb, 0x6B6840F2);
-+			put_be32(pb, 0x5F244FC5);
-+			put_be32(pb, 0xBA39A51B);
-+			put_be32(pb, 0xCF0323F3);
-+			put_be32(pb, 0x00000001);
-+			put_be32(pb, 0x0000039C); 
-+		}
-+	}
- 
-+	mov_write_colr_tag(pb);
-+
-     return updateSize (pb, pos);
- }
- 
-@@ -674,46 +701,18 @@
-     return atom_size;
- }
- 
-+/* TODO: */
- /* Time to sample atom */
- static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
- {
--    MOV_stts_t *stts_entries;
--    uint32_t entries = -1;
--    uint32_t atom_size;
--    int i;
--
--    if (track->enc->codec_type == CODEC_TYPE_AUDIO && !track->audio_vbr) {
--        stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
--        stts_entries[0].count = track->sampleCount;
--        stts_entries[0].duration = 1;
--        entries = 1;
--    } else {
--        stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */
--        for (i=0; i<track->entry; i++) {
--            int64_t duration = i + 1 == track->entry ?
--                track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */
--                track->cluster[i+1].dts - track->cluster[i].dts;
--            if (i && duration == stts_entries[entries].duration) {
--                stts_entries[entries].count++; /* compress */
--            } else {
--                entries++;
--                stts_entries[entries].duration = duration;
--                stts_entries[entries].count = 1;
--            }
--        }
--        entries++; /* last one */
--    }
--    atom_size = 16 + (entries * 8);
--    put_be32(pb, atom_size); /* size */
-+    put_be32(pb, 0x18); /* size */
-     put_tag(pb, "stts");
-     put_be32(pb, 0); /* version & flags */
--    put_be32(pb, entries); /* entry count */
--    for (i=0; i<entries; i++) {
--        put_be32(pb, stts_entries[i].count);
--        put_be32(pb, stts_entries[i].duration);
--    }
--    av_free(stts_entries);
--    return atom_size;
-+    put_be32(pb, 1); /* entry count */
-+
-+    put_be32(pb, track->sampleCount); /* sample count */
-+    put_be32(pb, track->sampleDuration); /* sample duration */
-+    return 0x18;
- }
- 
- static int mov_write_dref_tag(ByteIOContext *pb)
-@@ -911,6 +910,10 @@
-     /* Track width and height, for visual only */
-     if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
-         double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
-+		if (track->mode == MODE_IPOD) {
-+			/* FIXME , I do not believe this is needed, bad assumption */
-+			sample_aspect_ratio = 1;
-+		}
-         if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
-         put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
-         put_be32(pb, track->enc->height*0x10000);
-@@ -1322,6 +1325,8 @@
-     for (i=0; i<mov->nb_streams; i++) {
-         if(mov->tracks[i].entry <= 0) continue;
- 
-+        mov->tracks[i].trackDuration =
-+            (int64_t)mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
-         mov->tracks[i].time = mov->time;
-         mov->tracks[i].trackID = i+1;
-     }
-@@ -1369,6 +1374,8 @@
-         put_tag(pb, "MSNV");
-     else if ( mov->mode == MODE_MP4 )
-         put_tag(pb, "isom");
-+	else if ( mov->mode == MODE_IPOD )
-+        put_tag(pb, "isom");
-     else
-         put_tag(pb, "qt  ");
- 
-@@ -1380,6 +1387,8 @@
-         put_tag(pb, "3g2a");
-     else if ( mov->mode == MODE_PSP )
-         put_tag(pb, "MSNV");
-+	else if ( mov->mode == MODE_IPOD )
-+        put_tag(pb, "mp41");
-     else if ( mov->mode == MODE_MP4 )
-         put_tag(pb, "mp41");
-     else
-@@ -1466,7 +1475,8 @@
-         else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3G2;
-         else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
-         else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;
--
-+		else if (!strcmp("ipod", s->oformat->name)) mov->mode = MODE_IPOD;
-+		
-         mov_write_ftyp_tag(pb,s);
-         if ( mov->mode == MODE_PSP ) {
-             if ( s->nb_streams != 2 ) {
-@@ -1487,6 +1497,7 @@
-         if(st->codec->codec_type == CODEC_TYPE_VIDEO){
-             track->tag = mov_find_video_codec_tag(s, track);
-             track->timescale = st->codec->time_base.den;
-+            track->sampleDuration = st->codec->time_base.num;
-             av_set_pts_info(st, 64, 1, st->codec->time_base.den);
-             if (track->timescale > 100000)
-                 av_log(NULL, AV_LOG_WARNING,
-@@ -1496,6 +1507,7 @@
-         }else if(st->codec->codec_type == CODEC_TYPE_AUDIO){
-             track->tag = mov_find_audio_codec_tag(s, track);
-             track->timescale = st->codec->sample_rate;
-+            track->sampleDuration = st->codec->frame_size;
-             av_set_pts_info(st, 64, 1, st->codec->sample_rate);
-             if(!st->codec->frame_size){
-                 av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i);
-@@ -1675,6 +1687,21 @@
-     .flags = AVFMT_GLOBALHEADER,
- };
- #endif
-+#ifdef CONFIG_IPOD_MUXER
-+AVOutputFormat ipod_muxer = {
-+    "ipod",
-+    "ipod mp4 format",
-+    "application/mp4",
-+    "mp4,m4v,ipod",
-+    sizeof(MOVContext),
-+    CODEC_ID_AAC,
-+    CODEC_ID_MPEG4,
-+    mov_write_header,
-+    mov_write_packet,
-+    mov_write_trailer,
-+    .flags = AVFMT_GLOBALHEADER,
-+};
-+#endif
- #ifdef CONFIG_PSP_MUXER
- AVOutputFormat psp_muxer = {
-     "psp",
-Index: libavformat/allformats.c
-===================================================================
---- libavformat/allformats.c	(revision 9814)
-+++ libavformat/allformats.c	(working copy)
-@@ -89,6 +89,9 @@
-     REGISTER_MUXDEMUX(IMAGE2PIPE, image2pipe);
-     REGISTER_DEMUXER (INGENIENT, ingenient);
-     REGISTER_DEMUXER (IPMOVIE, ipmovie);
-+#ifdef CONFIG_IPOD_MUXER
-+    REGISTER_MUXER   (IPOD, ipod);
-+#endif
-     if (!ENABLE_NUT_DEMUXER) REGISTER_DEMUXER (LIBNUT, libnut);
-     REGISTER_MUXER   (LIBNUT, libnut);
-     REGISTER_MUXDEMUX(M4V, m4v);
-Index: libavformat/allformats.h
-===================================================================
---- libavformat/allformats.h	(revision 9814)
-+++ libavformat/allformats.h	(working copy)
-@@ -142,6 +142,7 @@
- extern AVOutputFormat image2pipe_muxer;
- extern AVOutputFormat image_muxer;
- extern AVOutputFormat imagepipe_muxer;
-+extern AVOutputFormat ipod_muxer;
- extern AVOutputFormat libnut_muxer;
- extern AVOutputFormat m4v_muxer;
- extern AVOutputFormat mjpeg_muxer;