summaryrefslogtreecommitdiffstats
path: root/libhb/demuxmpeg.c
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2011-04-22 14:51:59 +0000
committerjstebbins <[email protected]>2011-04-22 14:51:59 +0000
commit63a726b5e80d17083b0f8bf3e96c5749df45bc98 (patch)
treefd57fe76264f11a0fb6c20a7701e944de81b5466 /libhb/demuxmpeg.c
parent263b4ff38b4b4cb695e1b7a1e69571fd7e621145 (diff)
Add support for TrueHD and DTS-HD from BD sources
TrueHD and DTS-HD now show up in the audio list along side their AC-3 and DTS counterparts. Note that currently the DTS-HD decoder we are using (ffmpeg) discards the HD portion of the stream and onle decodes the DTS core portion. So there is no advantage yet to using the DTS-HD stream. In the future I would like to add DTS-HD passthru support and hopefully ffmpeg will improve their DTS-HD decoder. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3950 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/demuxmpeg.c')
-rw-r--r--libhb/demuxmpeg.c411
1 files changed, 229 insertions, 182 deletions
diff --git a/libhb/demuxmpeg.c b/libhb/demuxmpeg.c
index 763f3e31a..392736333 100644
--- a/libhb/demuxmpeg.c
+++ b/libhb/demuxmpeg.c
@@ -44,260 +44,307 @@ static inline void check_mpeg_scr( hb_psdemux_t *state, int64_t scr, int tol )
state->last_scr = scr;
}
-/* Basic MPEG demuxer */
-
-int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state )
+static inline void save_chap( hb_psdemux_t *state, hb_buffer_t *buf )
{
- hb_buffer_t * buf_es;
- int pos = 0;
-
-#define d (buf_ps->data)
-
- /* pack_header */
- if( d[pos] != 0 || d[pos+1] != 0 ||
- d[pos+2] != 0x1 || d[pos+3] != 0xBA )
+ if ( state && buf->new_chap )
{
- hb_log( "hb_demux_ps: not a PS packet (%02x%02x%02x%02x)",
- d[pos], d[pos+1], d[pos+2], d[pos+3] );
- return 0;
+ state->new_chap = buf->new_chap;
+ buf->new_chap = 0;
}
- pos += 4; /* pack_start_code */
+}
+static inline void restore_chap( hb_psdemux_t *state, hb_buffer_t *buf )
+{
if ( state )
{
- /* extract the system clock reference (scr) */
- int64_t scr = ((uint64_t)(d[pos] & 0x38) << 27) |
- ((uint64_t)(d[pos] & 0x03) << 28) |
- ((uint64_t)(d[pos+1]) << 20) |
- ((uint64_t)(d[pos+2] >> 3) << 15) |
- ((uint64_t)(d[pos+2] & 3) << 13) |
- ((uint64_t)(d[pos+3]) << 5) |
- (d[pos+4] >> 3);
- check_mpeg_scr( state, scr, 300 );
+ buf->new_chap = state->new_chap;
+ state->new_chap = 0;
}
+}
- pos += 9; /* pack_header */
- pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */
-
- /* system_header */
- if( d[pos] == 0 && d[pos+1] == 0 &&
- d[pos+2] == 0x1 && d[pos+3] == 0xBB )
- {
- int header_length;
+/* Basic MPEG demuxer */
- pos += 4; /* system_header_start_code */
- header_length = ( d[pos] << 8 ) + d[pos+1];
- pos += 2 + header_length;
- }
+void hb_demux_ps( hb_buffer_t * buf, hb_list_t * list_es, hb_psdemux_t* state )
+{
+ hb_buffer_t * buf_es;
+ int pos = 0;
- /* pes */
- while( pos + 6 < buf_ps->size &&
- d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 )
+ while ( buf )
{
- int id;
- int pes_packet_length;
- int pes_packet_end;
- int pes_header_d_length;
- int pes_header_end;
- int has_pts;
- int64_t pts = -1, dts = -1;
-
- pos += 3; /* packet_start_code_prefix */
- id = d[pos];
- pos += 1;
+ save_chap( state, buf );
+#define d (buf->data)
/* pack_header */
- if( id == 0xBA)
+ if( d[pos] != 0 || d[pos+1] != 0 ||
+ d[pos+2] != 0x1 || d[pos+3] != 0xBA )
{
- pos += 10 + (d[pos+9] & 7);
+ hb_log( "hb_demux_ps: not a PS packet (%02x%02x%02x%02x)",
+ d[pos], d[pos+1], d[pos+2], d[pos+3] );
+ hb_buffer_t *tmp = buf->next;
+ buf->next = NULL;
+ hb_buffer_close( &buf );
+ buf = tmp;
continue;
}
+ pos += 4; /* pack_start_code */
+
+ if ( state )
+ {
+ /* extract the system clock reference (scr) */
+ int64_t scr = ((uint64_t)(d[pos] & 0x38) << 27) |
+ ((uint64_t)(d[pos] & 0x03) << 28) |
+ ((uint64_t)(d[pos+1]) << 20) |
+ ((uint64_t)(d[pos+2] >> 3) << 15) |
+ ((uint64_t)(d[pos+2] & 3) << 13) |
+ ((uint64_t)(d[pos+3]) << 5) |
+ (d[pos+4] >> 3);
+ check_mpeg_scr( state, scr, 300 );
+ }
+
+ pos += 9; /* pack_header */
+ pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */
/* system_header */
- if( id == 0xBB )
+ if( d[pos] == 0 && d[pos+1] == 0 &&
+ d[pos+2] == 0x1 && d[pos+3] == 0xBB )
{
int header_length;
+ pos += 4; /* system_header_start_code */
header_length = ( d[pos] << 8 ) + d[pos+1];
pos += 2 + header_length;
- continue;
}
- pes_packet_length = ( d[pos] << 8 ) + d[pos+1];
- pos += 2; /* pes_packet_length */
- pes_packet_end = pos + pes_packet_length;
-
- if( id != 0xE0 && id != 0xBD &&
- ( id & 0xC0 ) != 0xC0 )
+ /* pes */
+ while( pos + 6 < buf->size &&
+ d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 )
{
- /* Not interesting */
- pos = pes_packet_end;
- continue;
- }
+ int id;
+ int pes_packet_length;
+ int pes_packet_end;
+ int pes_header_d_length;
+ int pes_header_end;
+ int has_pts;
+ int64_t pts = -1, dts = -1;
+
+ pos += 3; /* packet_start_code_prefix */
+ id = d[pos];
+ pos += 1;
+
+ /* pack_header */
+ if( id == 0xBA)
+ {
+ pos += 10 + (d[pos+9] & 7);
+ continue;
+ }
- has_pts = d[pos+1] >> 6;
- pos += 2; /* Required headers */
+ /* system_header */
+ if( id == 0xBB )
+ {
+ int header_length;
- pes_header_d_length = d[pos];
- pos += 1;
- pes_header_end = pos + pes_header_d_length;
+ header_length = ( d[pos] << 8 ) + d[pos+1];
+ pos += 2 + header_length;
+ continue;
+ }
- if( has_pts )
- {
- 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 )
+ pes_packet_length = ( d[pos] << 8 ) + d[pos+1];
+ pos += 2; /* pes_packet_length */
+ pes_packet_end = pos + pes_packet_length;
+
+ if( id != 0xE0 && id != 0xBD &&
+ ( id & 0xC0 ) != 0xC0 )
{
- 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 );
+ /* Not interesting */
+ pos = pes_packet_end;
+ continue;
}
- else
+
+ has_pts = d[pos+1] >> 6;
+ pos += 2; /* Required headers */
+
+ pes_header_d_length = d[pos];
+ pos += 1;
+ pes_header_end = pos + pes_header_d_length;
+
+ if( has_pts )
{
- dts = pts;
+ 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;
+ pos = pes_header_end;
- if( id == 0xBD )
- {
- id |= ( d[pos] << 8 );
- if( ( id & 0xF0FF ) == 0x80BD ) /* A52 */
+ if( id == 0xBD )
{
- pos += 4;
+ id |= ( d[pos] << 8 );
+ if( ( id & 0xF0FF ) == 0x80BD ) /* A52 */
+ {
+ pos += 4;
+ }
+ else if( ( id & 0xE0FF ) == 0x20BD || /* SPU */
+ ( id & 0xF0FF ) == 0xA0BD ) /* LPCM */
+ {
+ pos += 1;
+ }
}
- else if( ( id & 0xE0FF ) == 0x20BD || /* SPU */
- ( id & 0xF0FF ) == 0xA0BD ) /* LPCM */
+
+ /* Sanity check */
+ if( pos >= pes_packet_end )
{
- pos += 1;
+ pos = pes_packet_end;
+ continue;
}
- }
- /* Sanity check */
- if( pos >= pes_packet_end )
- {
- pos = pes_packet_end;
- continue;
- }
+ /* Here we hit we ES payload */
+ buf_es = hb_buffer_init( pes_packet_end - pos );
- /* Here we hit we ES payload */
- buf_es = hb_buffer_init( pes_packet_end - pos );
-
- 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.
- buf_es->new_chap = buf_ps->new_chap;
- buf_ps->new_chap = 0;
- }
- memcpy( buf_es->data, d + pos, pes_packet_end - pos );
+ buf_es->id = id;
+ buf_es->start = pts;
+ buf_es->renderOffset = dts;
+ buf_es->stop = -1;
+ if ( state && id == 0xE0)
+ {
+ // Consume a chapter break, and apply it to the ES.
+ restore_chap( state, buf_es );
+ }
+ memcpy( buf_es->data, d + pos, pes_packet_end - pos );
- hb_list_add( list_es, buf_es );
+ hb_list_add( list_es, buf_es );
- pos = pes_packet_end;
+ pos = pes_packet_end;
+ }
+ hb_buffer_t *tmp = buf->next;
+ buf->next = NULL;
+ hb_buffer_close( &buf );
+ buf = tmp;
}
-
#undef d
-
- return 1;
}
// mpeg transport stream demuxer. the elementary stream headers have been
-// stripped off and buf_ps has all the info gleaned from them: id is set,
+// stripped off and buf has all the info gleaned from them: id is set,
// start contains the pts (if any), renderOffset contains the dts (if any)
// and stop contains the pcr (if it changed).
-int hb_demux_ts( hb_buffer_t *buf_ps, hb_list_t *list_es, hb_psdemux_t *state )
+void hb_demux_ts( hb_buffer_t *buf, hb_list_t *list_es, hb_psdemux_t *state )
{
- if ( state )
+ while ( buf )
{
- if ( buf_ps->discontinuity )
+ save_chap( state, buf );
+ if ( state )
{
- // Buffer has been flagged as a discontinuity. This happens
- // when a blueray changes clips.
- ++state->scr_changes;
- state->last_scr = buf_ps->start;
- }
+ if ( buf->discontinuity )
+ {
+ // Buffer has been flagged as a discontinuity. This happens
+ // when a blueray changes clips.
+ ++state->scr_changes;
+ state->last_scr = buf->start;
+ }
- // we're keeping track of timing (i.e., not in scan)
- // check if there's a new pcr in this packet
- if ( buf_ps->stop >= 0 )
- {
- // we have a new pcr
- check_mpeg_scr( state, buf_ps->stop, 300 );
- buf_ps->stop = -1;
- }
- if ( buf_ps->start >= 0 )
- {
- // Program streams have an SCR in every PACK header so they
- // can't lose their clock reference. But the PCR in Transport
- // streams is typically on <.1% of the packets. If a PCR
- // packet gets lost and it marks a clock discontinuity then
- // the data following it will be referenced to the wrong
- // clock & introduce huge gaps or throw our A/V sync off.
- // We try to protect against that here by sanity checking
- // timestamps against the current reference clock and discarding
- // packets where the DTS is "too far" from its clock.
- int64_t fdelta = buf_ps->start - state->last_scr;
- if ( fdelta < -300 * 90000LL || fdelta > 300 * 90000LL )
+ // we're keeping track of timing (i.e., not in scan)
+ // check if there's a new pcr in this packet
+ if ( buf->pcr >= 0 )
{
- // packet too far behind or ahead of its clock reference
- ++state->dts_drops;
- return 1;
+ // we have a new pcr
+ check_mpeg_scr( state, buf->pcr, 300 );
+ buf->pcr = -1;
}
- if ( state->last_pts >= 0 )
+ if ( buf->start >= 0 )
{
- fdelta = buf_ps->start - state->last_pts;
- if ( fdelta < -5 * 90000LL || fdelta > 5 * 90000LL )
+ // Program streams have an SCR in every PACK header so they
+ // can't lose their clock reference. But the PCR in Transport
+ // streams is typically on <.1% of the packets. If a PCR
+ // packet gets lost and it marks a clock discontinuity then
+ // the data following it will be referenced to the wrong
+ // clock & introduce huge gaps or throw our A/V sync off.
+ // We try to protect against that here by sanity checking
+ // timestamps against the current reference clock and discarding
+ // packets where the DTS is "too far" from its clock.
+ int64_t fdelta = buf->start - state->last_scr;
+ if ( fdelta < -300 * 90000LL || fdelta > 300 * 90000LL )
+ {
+ // packet too far behind or ahead of its clock reference
+ ++state->dts_drops;
+ hb_buffer_t *tmp = buf->next;
+ buf->next = NULL;
+ hb_buffer_close( &buf );
+ buf = tmp;
+ continue;
+ }
+ if ( state->last_pts >= 0 )
{
- // Packet too far from last. This may be a NZ TV broadcast
- // as they like to change the PCR without sending a PCR
- // update. Since it may be a while until they actually tell
- // us the new PCR use the PTS as the PCR.
- ++state->scr_changes;
- state->last_scr = buf_ps->start;
+ fdelta = buf->start - state->last_pts;
+ if ( fdelta < -5 * 90000LL || fdelta > 5 * 90000LL )
+ {
+ // Packet too far from last. This may be a NZ TV broadcast
+ // as they like to change the PCR without sending a PCR
+ // update. Since it may be a while until they actually tell
+ // us the new PCR use the PTS as the PCR.
+ ++state->scr_changes;
+ state->last_scr = buf->start;
+ }
}
+ state->last_pts = buf->start;
+ }
+
+ if ( buf->type == VIDEO_BUF )
+ {
+ restore_chap( state, buf );
}
- state->last_pts = buf_ps->start;
}
- }
- hb_buffer_t *buf = hb_buffer_init( buf_ps->alloc );
- hb_buffer_swap_copy( buf_ps, buf );
- if (buf->type == VIDEO_BUF) {
- // Consume a chapter break
- buf_ps->new_chap = 0;
+ hb_buffer_t *tmp = buf->next;
+ buf->next = NULL;
+ hb_list_add( list_es, buf );
+ buf = tmp;
}
- hb_list_add( list_es, buf );
-
- 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 )
+void hb_demux_null( hb_buffer_t * buf, hb_list_t * list_es, hb_psdemux_t* state )
{
- // if we don't have a time offset yet, use this timestamp as the offset.
- if ( state && state->scr_changes == 0 &&
- ( buf_ps->start >= 0 || buf_ps->renderOffset >= 0 ) )
+ while ( buf )
{
- ++state->scr_changes;
- state->last_scr = buf_ps->start >= 0 ? buf_ps->start : buf_ps->renderOffset;
- }
+ save_chap( state, buf );
+ if ( state )
+ {
+ // if we don't have a time offset yet,
+ // use this timestamp as the offset.
+ if ( state->scr_changes == 0 &&
+ ( buf->start >= 0 || buf->renderOffset >= 0 ) )
+ {
+ ++state->scr_changes;
+ state->last_scr = buf->start >= 0 ? buf->start : buf->renderOffset;
+ }
- hb_buffer_t *buf = hb_buffer_init( buf_ps->alloc );
- hb_buffer_swap_copy( buf_ps, buf );
- hb_list_add( list_es, buf );
+ if ( buf->type == VIDEO_BUF )
+ {
+ restore_chap( state, buf );
+ }
+ }
- return 1;
+ hb_buffer_t *tmp = buf->next;
+ buf->next = NULL;
+ hb_list_add( list_es, buf );
+ buf = tmp;
+ }
}
const hb_muxer_t hb_demux[] = { hb_demux_ps, hb_demux_ts, hb_demux_null };