diff options
Diffstat (limited to 'libhb/demuxmpeg.c')
-rw-r--r-- | libhb/demuxmpeg.c | 411 |
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 }; |