rendered paste bodyIndex: 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 {