All pastes #1033363 Raw Edit

van's megapatch against 1471

public diff v1 · immutable
#1033363 ·published 2008-05-29 19:19 UTC
rendered paste body
Index: libhb/detelecine.c===================================================================--- libhb/detelecine.c	(revision 1472)+++ 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 1472)+++ 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;@@ -65,7 +77,7 @@      if( !( r->dvd = hb_dvd_init( r->title->dvd ) ) )     {-        if ( !( r->stream = hb_stream_open( r->title->dvd, 1 ) ) )+        if ( !( r->stream = hb_stream_open( r->title->dvd, r->title ) ) )         {           return;         }@@ -158,7 +170,14 @@             hb_set_state( r->job->h, &state );         } -        hb_demux_ps( r->ps, list, &r->demux );+        if ( r->title->demuxer == HB_NULL_DEMUXER )+        {+            hb_demux_null( r->ps, list, &r->demux );+        }+        else+        {+            hb_demux_ps( r->ps, list, &r->demux );+        }          while( ( buf = hb_list_item( list, 0 ) ) )         {@@ -169,10 +188,10 @@             {                 /* The first video packet defines 'time zero' so discard                    data until we get a video packet with a PTS */-                if ( buf->id == 0xE0 && buf->start != -1 )+                if ( buf->id == r->title->video_id && 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 +209,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             {@@ -262,7 +268,7 @@      memset(fifos, 0, sizeof(fifos)); -    if( id == 0xE0 )+    if( id == title->video_id )     {         if( job->indepth_scan )         {Index: libhb/deca52.c===================================================================--- libhb/deca52.c	(revision 1472)+++ 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/muxavi.c===================================================================--- libhb/muxavi.c	(revision 1472)+++ libhb/muxavi.c	(working copy)@@ -5,7 +5,7 @@    It may be used under the terms of the GNU General Public License. */  #include "hb.h"-#include "ffmpeg/avcodec.h"+#include "libavcodec/avcodec.h"  #define AVIF_HASINDEX  0x10 #define AVIIF_KEYFRAME 0x10Index: libhb/decmpeg2.c===================================================================--- libhb/decmpeg2.c	(revision 1472)+++ 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 1472)+++ 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.0fIndex: libhb/hb.c===================================================================--- libhb/hb.c	(revision 1472)+++ libhb/hb.c	(working copy)@@ -1,7 +1,8 @@ #include "hb.h" -#include "ffmpeg/avcodec.h"-#include "ffmpeg/swscale.h"+#include "libavcodec/avcodec.h"+#include "libavformat/avformat.h"+#include "libswscale/swscale.h"  struct hb_handle_s {@@ -122,9 +123,7 @@     h->pause_lock = hb_lock_init();      /* libavcodec */-    avcodec_init();-    avcodec_register_all();-    av_register_codec_parser( &mpegaudio_parser);+    av_register_all();      /* Start library thread */     hb_log( "hb_init: starting libhb thread" );@@ -220,6 +219,9 @@ 	hb_register( &hb_deca52 ); 	hb_register( &hb_decdca ); 	hb_register( &hb_decavcodec );+	hb_register( &hb_decavcodecv );+	hb_register( &hb_decavcodecvi );+	hb_register( &hb_decavcodecai ); 	hb_register( &hb_declpcm ); 	hb_register( &hb_encfaac ); 	hb_register( &hb_enclame );Index: libhb/encavcodec.c===================================================================--- libhb/encavcodec.c	(revision 1472)+++ 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 1472)+++ 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.@@ -170,3 +183,23 @@      return 1; }++// "null" demuxer (makes a copy of input buf & returns it in list)+// used when the reader for some format includes its own demuxer.+// for example, ffmpeg.+int hb_demux_null( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state )+{+    hb_buffer_t *buf = hb_buffer_init( buf_ps->size );++    // copy everything from the old to the new except the data ptr & alloc+    uint8_t *data = buf->data;+    int alloc = buf->alloc;+    *buf = *buf_ps;+    buf->data = data;+    buf->alloc = alloc;++    // now copy the data+    memcpy( buf->data, buf_ps->data, buf_ps->size );+    hb_list_add( list_es, buf );+    return 1;+}Index: libhb/stream.c===================================================================--- libhb/stream.c	(revision 1472)+++ libhb/stream.c	(working copy)@@ -7,16 +7,83 @@ #include "hb.h" #include "lang.h" #include "a52dec/a52.h"+#include "libavcodec/avcodec.h"+#include "libavformat/avformat.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_MPGA,    CODEC_ID_DTS,   "HDMV DTS"),+    st(0x83, A, HB_ACODEC_LPCM,    0,              "LPCM"),+    st(0x84, A, 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, A, 0,                 0,              "SDDS"),+    st(0xa0, V, 0,                 0,              "MSCODEC"),+            +    st(0xea, V, WORK_DECAVCODECV,  CODEC_ID_VC1,   "VC-1"),+};+#undef st+ typedef enum {     hb_stream_type_unknown = 0,     transport,     program,-    dvd_program+    dvd_program,+    ffmpeg } hb_stream_type_t;  #define kMaxNumberVideoPIDS 1@@ -65,8 +132,10 @@     char    *path;     FILE    *file_handle;     hb_stream_type_t hb_stream_type;-    int     opentype;+    hb_title_t *title; +    AVFormatContext *ffmpeg_ic;+     struct {         int lang_code;         int flags;@@ -116,6 +185,12 @@ static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title); static off_t align_to_next_packet(hb_stream_t *stream); +static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title );+static void ffmpeg_close( hb_stream_t *d );+static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream );+static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf );+static int ffmpeg_seek( hb_stream_t *stream, float frac );+ /*  * streams have a bunch of state that's learned during the scan. We don't  * want to throw away the state when scan does a close then relearn@@ -342,9 +417,8 @@  ***********************************************************************  *  **********************************************************************/-hb_stream_t * hb_stream_open( char *path, int opentype )+hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) {-     FILE *f = fopen( path, "r" );     if ( f == NULL )     {@@ -367,23 +441,15 @@      * (even if we have saved state, the stream may have changed).      */     hb_stream_t *ss = hb_stream_lookup( path );-    if ( opentype == 1 )+    if ( title && ss && ss->hb_stream_type != ffmpeg )     {-        /* opening to read - we must have saved state */-        if ( ss == NULL )-        {-            hb_log( "hb_stream_open: error: re-opening %s but no scan state", path );-            fclose( f );-            free( d );-            return NULL;-        }         /*          * copy the saved state since we might be encoding the same stream          * multiple times.          */         memcpy( d, ss, sizeof(*d) );         d->file_handle = f;-        d->opentype = opentype;+        d->title = title;         d->path = strdup( path );          if ( d->hb_stream_type == transport )@@ -410,11 +476,20 @@         hb_stream_state_delete( ss );     }     d->file_handle = f;-    d->opentype = opentype;+    d->title = title;     d->path = strdup( path );-    if (d->path != NULL &&  hb_stream_get_type( d ) != 0 )+    if (d->path != NULL )     {-        return d;+        if ( hb_stream_get_type( d ) != 0 )+        {+            return d;+        }+        fclose( d->file_handle );+		d->file_handle = NULL;+        if ( ffmpeg_open( d, title ) )+        {+            return d;+        }     }     fclose( d->file_handle );     if (d->path)@@ -434,17 +509,27 @@ void hb_stream_close( hb_stream_t ** _d ) {     hb_stream_t *stream = * _d;++    if ( stream->hb_stream_type == ffmpeg )+    {+        ffmpeg_close( stream );+        hb_stream_delete( stream );+        *_d = NULL;+        return;+    }+     if ( stream->frames )     {         hb_log( "stream: %d good frames, %d errors (%.0f%%)", stream->frames,                 stream->errors, (double)stream->errors * 100. /                 (double)stream->frames );     }+     /*      * if the stream was opened for a scan, cache the result, otherwise delete      * the state.      */-    if ( stream->opentype == 0 )+    if ( stream->title == NULL )     {         hb_stream_delete_dynamic( stream );         if ( stream_state_list == NULL )@@ -501,6 +586,9 @@  **********************************************************************/ hb_title_t * hb_stream_title_scan(hb_stream_t *stream) {+	if ( stream->hb_stream_type == ffmpeg )+        return ffmpeg_title_scan( stream );+     // 'Barebones Title'     hb_title_t *aTitle = hb_title_init( stream->path, 0 );     aTitle->index = 1;@@ -557,6 +645,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     {@@ -868,6 +960,10 @@  **********************************************************************/ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) {+	if ( src_stream->hb_stream_type == ffmpeg )+    {+        return ffmpeg_read( src_stream, b );+    }     if ( src_stream->hb_stream_type == dvd_program )     {         size_t amt_read = fread(b->data, HB_DVD_READ_BUFFER_SIZE, 1,@@ -931,6 +1027,10 @@  **********************************************************************/ int hb_stream_seek( hb_stream_t * src_stream, float f ) {+	if ( src_stream->hb_stream_type == ffmpeg )+    {+        return ffmpeg_seek( src_stream, f );+    }     off_t stream_size, cur_pos, new_pos;     double pos_ratio = f;     cur_pos = ftello( src_stream->file_handle );@@ -972,8 +1072,10 @@               sizeof( audio->config.lang.description ), "%s (%s)",               strlen(lang->native_name) ? lang->native_name : lang->eng_name,               audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" :-                  audio->config.in.codec == HB_ACODEC_DCA ? "DTS" :-                      audio->config.in.codec == HB_ACODEC_MPGA ? "MPEG" : "LPCM" );+              audio->config.in.codec == HB_ACODEC_DCA ? "DTS" :+              audio->config.in.codec == HB_ACODEC_MPGA ? "MPEG" : +              audio->config.in.codec == HB_ACODEC_LPCM ? "LPCM" : +              audio->config.in.codec == HB_ACODEC_FFMPEG ? "FFMPEG" : "Unknown");     snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s",               strlen(lang->native_name) ? lang->native_name : lang->eng_name );     snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ),@@ -992,65 +1094,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 +1147,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 +1384,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 +1438,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 +1809,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 +1920,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 +2123,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 +2136,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;@@ -2103,11 +2191,6 @@ 	} } -/***********************************************************************- * hb_ts_stream_reset- ***********************************************************************- *- **********************************************************************/ static void hb_ts_stream_reset(hb_stream_t *stream) { 	int i;@@ -2132,3 +2215,313 @@     align_to_next_packet(stream); } +// ------------------------------------------------------------------+// Support for reading media files via the ffmpeg libraries.++static void ffmpeg_add_codec( hb_stream_t *stream, int stream_index )+{+    // add a codec to the context here so it will be there when we+    // read the first packet.+    AVCodecContext *context = stream->ffmpeg_ic->streams[stream_index]->codec;+    AVCodec *codec = avcodec_find_decoder( context->codec_id );+    avcodec_open( context, codec );+}++// The ffmpeg stream reader / parser shares a lot of state with the +// decoder via a codec context kept inthe AVStream of the reader's+// AVFormatContext. Since decoding is done in a different thread we+// have to somehow pass this codec context to the decoder and we have+// to do it before the first packet is read (so we can't put the info+// in the buf we'll send downstream). Decoders don't have any way to+// get to the stream directly (they're not passed the title or job+// pointers during a scan) so this is a back door for the decoder to+// get the codec context. We just stick the stream pointer in the next+// slot an array of pointers maintained as a circular list then return+// the index into the list combined with the ffmpeg stream index as the+// codec_param that will be passed to the decoder init routine. We make+// the list 'big' (enough for 1024 simultaneously open ffmpeg streams)+// so that we don't have to do a complicated allocator or worry about+// deleting entries on close. +//+// Entries can only be added to this list during a scan and are never+// deleted so the list access doesn't require locking.+static hb_stream_t **ffmpeg_streams;    // circular list of stream pointers+static int ffmpeg_stream_cur;           // where we put the last stream pointer+#define ffmpeg_sl_bits (10)             // log2 stream list size (in entries)+#define ffmpeg_sl_size (1 << ffmpeg_sl_bits)++// add a stream to the list & return the appropriate codec_param to access it+static int ffmpeg_codec_param( hb_stream_t *stream, int stream_index )+{+    if ( !ffmpeg_streams )+    {+        ffmpeg_streams = calloc( ffmpeg_sl_size, sizeof(stream) );+    }++    // the title scan adds all the ffmpeg media streams at once so we+    // only add a new entry to our stream list if the stream is different+    // than last time.+    int slot = ffmpeg_stream_cur;+    if ( ffmpeg_streams[slot] != stream )+    {+        // new steam - it in the next slot of the stream list+        slot = ++ffmpeg_stream_cur & (ffmpeg_sl_size - 1);+        ffmpeg_streams[slot] = stream;+    }++    ffmpeg_add_codec( stream, stream_index );++    return ( stream_index << ffmpeg_sl_bits ) | slot;+}++// we're about to open 'title' to convert it - remap the stream associated+// with the video & audio codec params of the title to refer to 'stream'+// (the original scan stream was closed and no longer exists).+static void ffmpeg_remap_stream( hb_stream_t *stream, hb_title_t *title )+{+    // all the video & audio came from the same stream so remapping+    // the video's stream slot takes care of everything.+    int slot = title->video_codec_param & (ffmpeg_sl_size - 1);+    ffmpeg_streams[slot] = stream;++    // add codecs for all the streams used by the title+    ffmpeg_add_codec( stream, title->video_codec_param >> ffmpeg_sl_bits );++    int i;+    hb_audio_t *audio;+    for ( i = 0; ( audio = hb_list_item( title->list_audio, i ) ); ++i )+    {+        if ( audio->config.in.codec == HB_ACODEC_FFMPEG )+        {+            ffmpeg_add_codec( stream,+                              audio->config.in.codec_param >> ffmpeg_sl_bits );+        }+    }+}++void *hb_ffmpeg_context( int codec_param )+{+    int slot = codec_param & (ffmpeg_sl_size - 1);+    int stream_index = codec_param >> ffmpeg_sl_bits;+    return ffmpeg_streams[slot]->ffmpeg_ic->streams[stream_index]->codec;+}++void *hb_ffmpeg_avstream( int codec_param )+{+    int slot = codec_param & (ffmpeg_sl_size - 1);+    int stream_index = codec_param >> ffmpeg_sl_bits;+    return ffmpeg_streams[slot]->ffmpeg_ic->streams[stream_index];+}++static AVFormatContext *ffmpeg_deferred_close;++static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title )+{+    if ( ffmpeg_deferred_close )+    {+        av_close_input_file( ffmpeg_deferred_close );+        ffmpeg_deferred_close = NULL;+    }+    AVFormatContext *ic;++    if ( av_open_input_file( &ic, stream->path, NULL, 0, NULL ) < 0 )+    {+        return 0;+    }+    if ( av_find_stream_info( ic ) < 0 )+        goto fail;++    stream->ffmpeg_ic = ic;+    stream->hb_stream_type = ffmpeg;++    if ( title )+    {+        // we're opening for read. scan passed out codec params that+        // indexed its stream so we need to remap them so they point+        // to this stream.+        ffmpeg_remap_stream( stream, title );+        ffmpeg_seek( stream, 0. );+    }+    else+    {+        av_log_set_level( AV_LOG_INFO );+        dump_format( ic, 0, stream->path, 0 );+        av_log_set_level( AV_LOG_WARNING );++        // accept this file if it has at least one video stream we can decode+        int i;+        for (i = 0; i < ic->nb_streams; ++i )+        {+            if ( ic->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )+            {+                break;+            }+        }+        if ( i >= ic->nb_streams )+            goto fail;+    }+    return 1;++  fail:+    av_close_input_file( ic );+    return 0;+}++static void ffmpeg_close( hb_stream_t *d )+{+    // XXX since we're sharing the CodecContext with the downstream+    // decoder proc we can't close the stream. We need to reference count+    // this so we can close it when both are done with their instance but+    // for now just defer the close until the next stream open or close.+    if ( ffmpeg_deferred_close )+    {+        av_close_input_file( ffmpeg_deferred_close );+    }+    ffmpeg_deferred_close = d->ffmpeg_ic;+}++static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id )+{+    AVStream *st = stream->ffmpeg_ic->streams[id];+    AVCodecContext *codec = st->codec;++    // scan will ignore any audio without a bitrate. Since we've already+    // typed the audio in order to determine its codec we set up the audio+    // paramters here.+    if ( codec->bit_rate || codec->sample_rate )+    {+        static const int chan2layout[] = {+            HB_INPUT_CH_LAYOUT_MONO,  // We should allow no audio really.+            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,+        };++        hb_audio_t *audio = calloc( 1, sizeof(*audio) );;++        audio->id = id;+        audio->config.in.codec = HB_ACODEC_FFMPEG;+        audio->config.in.codec_param = ffmpeg_codec_param( stream, id );++        audio->config.in.bitrate = codec->bit_rate? codec->bit_rate : 1;+        audio->config.in.samplerate = codec->sample_rate;+        audio->config.in.channel_layout = chan2layout[codec->channels & 7];++        set_audio_description( audio, lang_for_code2( st->language ) );++        hb_list_add( title->list_audio, audio );+    }+}++static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream )+{+    AVFormatContext *ic = stream->ffmpeg_ic;++    // 'Barebones Title'+    hb_title_t *title = hb_title_init( stream->path, 0 );+    title->index = 1;++	// Copy part of the stream path to the title name+	char *sep = strrchr(stream->path, '/');+	if (sep)+		strcpy(title->name, sep+1);+	char *dot_term = strrchr(title->name, '.');+	if (dot_term)+		*dot_term = '\0';++    uint64_t dur = ic->duration * 90000 / AV_TIME_BASE;+    title->duration = dur;+    dur /= 90000;+    title->hours    = dur / 3600;+    title->minutes  = ( dur % 3600 ) / 60;+    title->seconds  = dur % 60;++    // One Chapter+    hb_chapter_t * chapter;+    chapter = calloc( sizeof( hb_chapter_t ), 1 );+    chapter->index = 1;+    chapter->duration = title->duration;+    chapter->hours = title->hours;+    chapter->minutes = title->minutes;+    chapter->seconds = title->seconds;+    hb_list_add( title->list_chapter, chapter );++    // set the title to decode the first video stream in the file+    title->demuxer = HB_NULL_DEMUXER;+    title->video_codec = 0;+    int i;+    for (i = 0; i < ic->nb_streams; ++i )+    {+        if ( ic->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO &&+             avcodec_find_decoder( ic->streams[i]->codec->codec_id ) &&+             title->video_codec == 0 )+        {+            title->video_id = i;++            // We have to use the 'internal' avcodec decoder because+            // it needs to share the codec context from this video+            // stream. The parser internal to av_read_frame+            // passes a bunch of state info to the decoder via the context.+            title->video_codec = WORK_DECAVCODECVI;+            title->video_codec_param = ffmpeg_codec_param( stream, i );+        }+        else if ( ic->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO &&+                  avcodec_find_decoder( ic->streams[i]->codec->codec_id ) )+        {+            add_ffmpeg_audio( title, stream, i );+        }+    }++    return title;+}++static int64_t av_to_hb_pts( int64_t pts, double conv_factor )+{+    if ( pts == AV_NOPTS_VALUE )+        return -1;+    return (int64_t)( (double)pts * conv_factor );+}++static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )+{+    AVPacket pkt;++    if ( av_read_frame( stream->ffmpeg_ic, &pkt ) < 0 )+    {+        return 0;+    }+    if ( pkt.size > buf->alloc )+    {+        // need to expand buffer+        hb_buffer_realloc( buf, pkt.size );+    }+    memcpy( buf->data, pkt.data, pkt.size );+    buf->id = pkt.stream_index;+    buf->size = pkt.size;+    // The timestamp logic in ffplay is to use the dts if there is one.+    // if not, use the pts if there is one. if not, set start of an+    // invalid value so one will be chosen from the frame rate. It+    // seems to me that this inverts the usual meaning of pts & dts+    // but presumably they know how their code works.+    int64_t pts = pkt.dts != AV_NOPTS_VALUE? pkt.dts :+                      pkt.pts != AV_NOPTS_VALUE? pkt.pts : -1;+    buf->start = av_to_hb_pts( pts,+                  av_q2d(stream->ffmpeg_ic->streams[pkt.stream_index]->time_base)*90000. );+    buf->renderOffset = av_to_hb_pts( pkt.pts,+                  av_q2d(stream->ffmpeg_ic->streams[pkt.stream_index]->time_base)*90000. );+    av_free_packet( &pkt );+    return 1;+}++static int ffmpeg_seek( hb_stream_t *stream, float frac )+{+    AVFormatContext *ic = stream->ffmpeg_ic;+    int64_t pos = (double)ic->duration * (double)frac;+    av_seek_frame( ic, -1, pos, pos? 0 : AVSEEK_FLAG_BACKWARD );+    return 1;+}Index: libhb/Makefile===================================================================--- libhb/Makefile	(revision 1472)+++ libhb/Makefile	(working copy)@@ -39,7 +39,7 @@ 		   ../contrib/lib/libsamplerate.a ../contrib/lib/libx264.a \ 		   ../contrib/lib/libxvidcore.a  ../contrib/lib/libmp4v2.a \ 		   ../contrib/lib/libmkv.a ../contrib/lib/libswscale.a \-		   ../contrib/lib/libtheora.a+		   ../contrib/lib/libtheora.a ../contrib/lib/libfaad.a  CFLAGS += -I../contrib/include -D__LIBHB__ -DUSE_PTHREAD -DHB_VERSION=\"$(HB_VERSION)\" -DHB_BUILD=$(HB_BUILD) $(SYSDEF) Index: libhb/hb.h===================================================================--- libhb/hb.h	(revision 1472)+++ libhb/hb.h	(working copy)@@ -29,6 +29,9 @@ hb_register( &hb_deca52 ); \ hb_register( &hb_decdca ); \ hb_register( &hb_decavcodec ); \+hb_register( &hb_decavcodecv ); \+hb_register( &hb_decavcodecvi ); \+hb_register( &hb_decavcodecai ); \ hb_register( &hb_declpcm ); \ hb_register( &hb_encfaac ); \ hb_register( &hb_enclame ); \@@ -45,6 +48,9 @@ hb_register( &hb_deca52 ); \ hb_register( &hb_decdca ); \ hb_register( &hb_decavcodec ); \+hb_register( &hb_decavcodecv ); \+hb_register( &hb_decavcodecvi ); \+hb_register( &hb_decavcodecai ); \ hb_register( &hb_declpcm ); \ hb_register( &hb_encfaac ); \ Index: libhb/deblock.c===================================================================--- libhb/deblock.c	(revision 1472)+++ 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    0Index: libhb/decdca.c===================================================================--- libhb/decdca.c	(revision 1472)+++ 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 1472)+++ 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 1472)+++ 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 1472)+++ 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_LOGIndex: libhb/render.c===================================================================--- libhb/render.c	(revision 1472)+++ 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 1472)+++ libhb/decavcodec.c	(working copy)@@ -6,11 +6,14 @@  #include "hb.h" -#include "ffmpeg/avcodec.h"+#include "libavcodec/avcodec.h"+#include "libavformat/avformat.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 +21,33 @@     "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;+    double               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;+    double               duration;  // frame duration (for video) };  + /***********************************************************************  * 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 +56,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 +74,21 @@  ***********************************************************************  *  **********************************************************************/-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->parser )+	{+		av_parser_close(pv->parser);+	}+    if ( pv->context && pv->context->codec )+    {+        avcodec_close( pv->context );+    }+    if ( pv->list )+    {+        hb_list_close( &pv->list );+    } }  /***********************************************************************@@ -72,7 +96,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 +109,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 +172,543 @@         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;+    frame->pts = pv->pts;+    pv->pts = -1;++    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;++    avcodec_decode_video( pv->context, &frame, &got_picture, data, size );+    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.+        double pts = frame.pts;+        if ( pts < 0 )+        {+            pts = pv->pts_next;+        }+        if ( pv->duration == 0 )+        {+            pv->duration = 90000. * pv->context->time_base.num /+                           pv->context->time_base.den;+        }+        double frame_dur = pv->duration;+        frame_dur += frame.repeat_pict * frame_dur * 0.5;+        pv->pts_next = 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;++		if( context->sample_aspect_ratio.num == 0 )+		{+			info->aspect = (double)context->width / (double)context->height * 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+};+++// This is a special decoder for ffmpeg streams. The ffmpeg stream reader+// includes a parser and passes information from the parser to the decoder+// via a codec context kept in the AVStream of the reader's AVFormatContext.+// We *have* to use that codec context to decode the stream or we'll get+// garbage. ffmpeg_title_scan put a cookie that can be used to get to that+// codec context in our codec_param.++// this routine gets the appropriate context pointer from the ffmpeg+// stream reader. it can't be called until we get the first buffer because+// we can't guarantee that reader will be called before the our init+// routine and if our init is called first we'll get a pointer to the+// old scan stream (which has already been closed).+static void init_ffmpeg_context( hb_work_object_t *w )+{+    hb_work_private_t *pv = w->private_data;+    pv->context = hb_ffmpeg_context( w->codec_param );++    // during scan the decoder gets closed & reopened which will+    // close the codec so reopen it if it's not there+    if ( ! pv->context->codec )+    {+        AVCodec *codec = avcodec_find_decoder( pv->context->codec_id );+        avcodec_open( pv->context, codec );+    }+    // set up our best guess at the frame duration.+    // the frame rate in the codec seems to be bogus but it's ok in the stream.+    AVStream *st = hb_ffmpeg_avstream( w->codec_param );+    AVRational tb = st->time_base;+    if ( st->r_frame_rate.den && st->r_frame_rate.num )+    {+        tb.num = st->r_frame_rate.den;+        tb.den = st->r_frame_rate.num;+    }+    pv->duration = 90000. * tb.num / tb.den;++    // 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;+}++static int decavcodecviInit( 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();++    return 0;+}++static int decavcodecviWork( hb_work_object_t * w, hb_buffer_t ** buf_in,+                             hb_buffer_t ** buf_out )+{+    hb_work_private_t *pv = w->private_data;+    if ( ! pv->context )+    {+        init_ffmpeg_context( w );+    }+    hb_buffer_t *in = *buf_in;+    int64_t pts = -1;++    *buf_in = NULL;++    /* if we got an empty buffer signaling end-of-stream send it downstream */+    if ( in->size == 0 )+    {+        /* flush any frames left in the decoder */+        while ( decodeFrame( pv, NULL, 0 ) )+        {+        }+        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 && pv->pts_next <= 0 )+    {+        pv->pts_next = in->start;+    }+#ifdef notyet+    // right now using ffmpeg's timestamps does more harm than good+    if( in->start >= 0 )+    {+        pts = in->start;+    }+    pv->pts = pts;+#endif+    if ( in->new_chap )+    {+        pv->new_chap = in->new_chap;+        pv->chap_time = pts >= 0? pts : pv->pts_next;+    }+    decodeFrame( pv, in->data, in->size );+    hb_buffer_close( &in );+    *buf_out = link_buf_list( pv );+    return HB_WORK_OK;+}++static int decavcodecviInfo( hb_work_object_t *w, hb_work_info_t *info )+{+    if ( decavcodecvInfo( w, info ) )+    {+        // the frame rate in the codec seems to be bogus but it's ok in the stream.+        AVStream *st = hb_ffmpeg_avstream( w->codec_param );+        AVRational tb;+        if ( st->r_frame_rate.den && st->r_frame_rate.num )+        {+            tb.num = st->r_frame_rate.den;+            tb.den = st->r_frame_rate.num;+        }+        else+        {+            tb = st->time_base;+        }++        // 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)tb.num * 27000000LL / tb.den;+        return 1;+    }+    return 0;+}++static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )+{+    AVCodecContext *context = pv->context;+    int pos = 0;++    while ( pos < size )+    {+        int16_t buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE];+        int out_size = sizeof(buffer);+        int len = avcodec_decode_audio2( context, buffer, &out_size,+                                         data + pos, size - pos );+        if ( len <= 0 )+        {+            return;+        }+        pos += len;+        if( out_size > 0 )+        {+            hb_buffer_t *buf = hb_buffer_init( 2 * out_size );++            double pts = pv->pts_next;+            buf->start = pts;+            out_size >>= 1;+            pts += out_size * pv->duration;+            buf->stop  = pts;+            pv->pts_next = pts;++            float *fl32 = (float *)buf->data;+            int i;+            for( i = 0; i < out_size; ++i )+            {+                fl32[i] = buffer[i];+            }+            hb_list_add( pv->list, buf );+        }+    }+}++static int decavcodecaiWork( hb_work_object_t *w, hb_buffer_t **buf_in,+                    hb_buffer_t **buf_out )+{+    hb_work_private_t *pv = w->private_data;+    if ( ! pv->context )+    {+        init_ffmpeg_context( w );+        pv->duration = 90000. /+                    (double)( pv->context->sample_rate * pv->context->channels );+    }+    hb_buffer_t *in = *buf_in;++    if ( in->start >= 0 &&+         ( pv->pts_next < 0 || ( in->start - pv->pts_next ) > 90*100 ) )+    {+        pv->pts_next = in->start;+    }+    decodeAudio( pv, in->data, in->size );+    *buf_out = link_buf_list( pv );++    return HB_WORK_OK;+}++hb_work_object_t hb_decavcodecvi =+{+    WORK_DECAVCODECVI,+    "Video decoder (ffmpeg streams)",+    decavcodecviInit,+    decavcodecviWork,+    decavcodecClose,+    decavcodecviInfo,+    decavcodecvBSInfo+};++hb_work_object_t hb_decavcodecai =+{+    WORK_DECAVCODECAI,+    "Audio decoder (ffmpeg streams)",+    decavcodecviInit,+    decavcodecaiWork,+    decavcodecClose,+    decavcodecInfo,+    decavcodecBSInfo+};Index: libhb/internal.h===================================================================--- libhb/internal.h	(revision 1472)+++ 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 {@@ -124,6 +111,7 @@ } hb_psdemux_t;  int hb_demux_ps( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * );+int hb_demux_null( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * );  /***********************************************************************  * dvd.c@@ -142,12 +130,15 @@ int          hb_dvd_is_break( hb_dvd_t * d ); void         hb_dvd_close( hb_dvd_t ** ); -hb_stream_t * hb_stream_open( char * path, int opentype );+hb_stream_t * hb_stream_open( char * path, hb_title_t *title ); void		 hb_stream_close( hb_stream_t ** ); hb_title_t * hb_stream_title_scan( hb_stream_t *); int          hb_stream_read( hb_stream_t *, hb_buffer_t *); int          hb_stream_seek( hb_stream_t *, float ); +void       * hb_ffmpeg_context( int codec_param );+void       * hb_ffmpeg_avstream( int codec_param );+ /***********************************************************************  * Work objects  **********************************************************************/@@ -213,6 +204,9 @@     WORK_DECA52,     WORK_DECDCA,     WORK_DECAVCODEC,+    WORK_DECAVCODECV,+    WORK_DECAVCODECVI,+    WORK_DECAVCODECAI,     WORK_DECLPCM,     WORK_ENCFAAC,     WORK_ENCLAME,Index: libhb/work.c===================================================================--- libhb/work.c	(revision 1472)+++ libhb/work.c	(working copy)@@ -70,19 +70,45 @@     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 );+        case HB_ACODEC_FFMPEG: return hb_get_work( WORK_DECAVCODECAI );+    }+    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 +125,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;@@ -250,17 +272,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 )@@ -278,21 +302,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;@@ -354,20 +378,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 );             }         }     }@@ -438,8 +452,10 @@          /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,            but this may change in the future, so they are separated for flexibility */-        int audioCodecsSupportMono = ( (audio->config.in.codec == HB_ACODEC_AC3 || audio->config.in.codec == HB_ACODEC_DCA) &&-            (audio->config.out.codec == HB_ACODEC_FAAC || audio->config.out.codec == HB_ACODEC_VORBIS) );+        int audioCodecsSupportMono = ( +            (audio->config.in.codec == HB_ACODEC_FFMPEG) ||+            ( (audio->config.in.codec == HB_ACODEC_AC3 || audio->config.in.codec == HB_ACODEC_DCA) &&+              (audio->config.out.codec == HB_ACODEC_FAAC || audio->config.out.codec == HB_ACODEC_VORBIS) ) );         int audioCodecsSupport6Ch =  ( (audio->config.in.codec == HB_ACODEC_AC3 || audio->config.in.codec == HB_ACODEC_DCA) &&             (audio->config.out.codec == HB_ACODEC_FAAC || audio->config.out.codec == HB_ACODEC_VORBIS)); @@ -557,79 +573,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 */@@ -671,6 +650,7 @@     }     hb_list_rem( job->list_work, w );     w->close( w );+    free( w );     job->done = 1;  cleanup:@@ -678,23 +658,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 );@@ -847,7 +816,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 1472)+++ 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 1472)+++ 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++ )         {@@ -299,83 +302,77 @@                   goto skip_preview;               }             }-            hb_demux_ps( buf_ps, list_es, 0 );+            if ( title->demuxer == HB_NULL_DEMUXER )+            {+                hb_demux_null( buf_ps, list_es, 0 );+            }+            else+            {+                hb_demux_ps( buf_ps, list_es, 0 );+            }              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 == title->video_id && 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 +418,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, 10, 30, 9 ) )+        if( hb_detect_comb( vid_buf->data, title->width, title->height, 10, 30, 9, 10, 30, 9 ) )         {             hb_log("Interlacing detected in preview frame %i", i);             interlaced_preview_count++;@@ -444,7 +437,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 +446,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 +486,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 +518,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 +525,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 +569,70 @@         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/0x%x for id 0x%x",+                audio->config.in.codec, audio->config.in.codec_param,+                audio->id );+        goto drop_audio;+    }+    if ( !info.bitrate )+    {+        /* didn't find any info */+        return;+    }+    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.c===================================================================--- libhb/common.c	(revision 1472)+++ libhb/common.c	(working copy)@@ -593,6 +593,9 @@     t->list_chapter  = hb_list_init();     t->list_subtitle = hb_list_init();     strcat( t->dvd, dvd );+    // default to decoding mpeg2+    t->video_id      = 0xE0;+    t->video_codec   = WORK_DECMPEG2;      return t; }Index: libhb/decomb.c===================================================================--- libhb/decomb.c	(revision 1472)+++ libhb/decomb.c	(working copy)@@ -6,7 +6,7 @@        The yadif algorithm was created by Michael Niedermayer. */ #include "hb.h"-#include "ffmpeg/avcodec.h"+#include "libavcodec/avcodec.h" #include "mpeg2dec/mpeg2.h"  #define SUPPRESS_AV_LOGIndex: libhb/common.h===================================================================--- libhb/common.h	(revision 1472)+++ 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_FFMPEG 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     {@@ -437,7 +440,11 @@     int         rate;     int         rate_base;     int         crop[4];+    enum { HB_MPEG2_DEMUXER = 0, HB_NULL_DEMUXER } demuxer;     int         detected_interlacing;+    int         video_id;               /* demuxer stream id for video */+    int         video_codec;            /* worker object id of video codec */+    int         video_codec_param;      /* codec specific config */      uint32_t    palette[16]; @@ -501,6 +508,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 +539,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 +564,7 @@     hb_thread_t       * thread;     volatile int      * done;     int                 status;+    int                 codec_param;      hb_work_object_t  * next; 	int				  thread_sleep_interval;@@ -541,6 +582,9 @@ 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_decavcodecvi;+extern hb_work_object_t hb_decavcodecai; extern hb_work_object_t hb_declpcm; extern hb_work_object_t hb_encfaac; extern hb_work_object_t hb_enclame;Index: macosx/Controller.mm===================================================================--- macosx/Controller.mm	(revision 1472)+++ macosx/Controller.mm	(working copy)@@ -3237,8 +3237,9 @@              as they are the only libraries able to do the mixdown to mono / conversion to 6-ch */             /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,              but this may change in the future, so they are separated for flexibility */-            int audioCodecsSupportMono = ((audio->in.codec == HB_ACODEC_AC3 ||-                                           audio->in.codec == HB_ACODEC_DCA) && acodec == HB_ACODEC_FAAC);+            int audioCodecsSupportMono = ((audio->in.codec == HB_ACODEC_FFMPEG) ||+                                          ((audio->in.codec == HB_ACODEC_AC3 ||+                                            audio->in.codec == HB_ACODEC_DCA) && acodec == HB_ACODEC_FAAC));             int audioCodecsSupport6Ch =  ((audio->in.codec == HB_ACODEC_AC3 ||                                            audio->in.codec == HB_ACODEC_DCA) && (acodec == HB_ACODEC_FAAC ||                                                                                  acodec == HB_ACODEC_VORBIS));Index: macosx/HandBrake.xcodeproj/project.pbxproj===================================================================--- macosx/HandBrake.xcodeproj/project.pbxproj	(revision 1472)+++ macosx/HandBrake.xcodeproj/project.pbxproj	(working copy)@@ -995,6 +995,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libtheora.a, 					../contrib/lib/libswscale.a,+					../contrib/lib/libfaad.a, 					"-ldl", 					"-flat_namespace", 					"-read_only_relocs",@@ -1060,6 +1061,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libtheora.a, 					../contrib/lib/libswscale.a,+					../contrib/lib/libfaad.a, 					"-ldl", 					"-flat_namespace", 					"-read_only_relocs",@@ -1123,6 +1125,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libtheora.a, 					../contrib/lib/libswscale.a,+					../contrib/lib/libfaad.a, 					"-ldl", 					"-flat_namespace", 					"-read_only_relocs",@@ -1216,6 +1219,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libswscale.a, 					../contrib/lib/libtheora.a,+					../contrib/lib/libfaad.a, 				); 				PRODUCT_NAME = HandBrake; 				SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;@@ -1262,6 +1266,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libswscale.a, 					../contrib/lib/libtheora.a,+					../contrib/lib/libfaad.a, 				); 				PREBINDING = NO; 				PRODUCT_NAME = HandBrakeCLI;@@ -1391,6 +1396,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libswscale.a, 					../contrib/lib/libtheora.a,+					../contrib/lib/libfaad.a, 				); 				PREBINDING = NO; 				PRODUCT_NAME = HandBrakeCLI;@@ -1434,6 +1440,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libswscale.a, 					../contrib/lib/libtheora.a,+					../contrib/lib/libfaad.a, 				); 				PREBINDING = NO; 				PRODUCT_NAME = HandBrakeCLI;@@ -1493,6 +1500,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libswscale.a, 					../contrib/lib/libtheora.a,+					../contrib/lib/libfaad.a, 				); 				PRODUCT_NAME = HandBrake; 				SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;@@ -1555,6 +1563,7 @@ 					../contrib/lib/libmkv.a, 					../contrib/lib/libswscale.a, 					../contrib/lib/libtheora.a,+					../contrib/lib/libfaad.a, 				); 				PRODUCT_NAME = HandBrake; 				SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;Index: contrib/version_ffmpeg.txt===================================================================--- contrib/version_ffmpeg.txt	(revision 1472)+++ 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.gzIndex: contrib/version_faad2.txt===================================================================--- contrib/version_faad2.txt	(revision 0)+++ contrib/version_faad2.txt	(revision 0)@@ -0,0 +1,2 @@+http://download.m0k.org/handbrake/contrib/faad2-2.6.1.tar.gz+http://download.m0k.org/handbrake/contrib/faad2-2.6.1.tar.gzIndex: contrib/Jamfile===================================================================--- contrib/Jamfile	(revision 1472)+++ contrib/Jamfile	(working copy)@@ -57,6 +57,23 @@ Wget   $(SUBDIR)/a52dec.tar.gz : $(SUBDIR)/version_a52dec.txt ; LibA52 $(SUBDIR)/lib/liba52.a  : $(SUBDIR)/a52dec.tar.gz ; +# FAAD2+rule LibFaad2+{+    Depends $(<) : $(>) ;+    Depends lib  : $(<) ;+}++actions LibFaad2+{+    cd `dirname $(>)` && CONTRIB=`pwd` &&+    rm -rf faad2 && (gzip -dc faad2.tar.gz | tar xf -) &&+    cd faad2 &&+    ./bootstrap && ./configure --prefix=$CONTRIB --cache-file=$CONTRIB/config.cache --disable-shared && $(MAKE) && $(MAKE) install+}+Wget     $(SUBDIR)/faad2.tar.gz    : $(SUBDIR)/version_faad2.txt ;+LibFaad2 $(SUBDIR)/lib/libfaad.a : $(SUBDIR)/faad2.tar.gz ;+ # libavcodec rule LibAvCodec {@@ -78,10 +95,13 @@     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 \+        --enable-libfaad \+        --disable-muxers --enable-muxer=ipod --disable-bsfs \+        --extra-cflags="-I$CONTRIB/include" \+        --extra-ldflags="-L$CONTRIB/lib" &&     $(MAKE) && $(MAKE) install &&     $(STRIP) $CONTRIB/lib/libavcodec.a }Index: contrib/patch-ffmpeg.patch===================================================================--- contrib/patch-ffmpeg.patch	(revision 1472)+++ 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;Index: Jamfile===================================================================--- Jamfile	(revision 1472)+++ Jamfile	(working copy)@@ -17,7 +17,7 @@           contrib/lib/libogg.a        contrib/lib/libsamplerate.a           contrib/lib/libx264.a       contrib/lib/libxvidcore.a           contrib/lib/libmkv.a        contrib/lib/libswscale.a-          contrib/lib/libtheora.a ;+          contrib/lib/libtheora.a     contrib/lib/libfaad.a ;  if $(OS) = UNKNOWN {