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