diff options
-rw-r--r-- | libhb/bd.c | 161 | ||||
-rw-r--r-- | libhb/common.h | 7 | ||||
-rw-r--r-- | libhb/decavcodec.c | 23 | ||||
-rw-r--r-- | libhb/demuxmpeg.c | 411 | ||||
-rw-r--r-- | libhb/dvd.c | 24 | ||||
-rw-r--r-- | libhb/dvd.h | 2 | ||||
-rw-r--r-- | libhb/dvdnav.c | 36 | ||||
-rw-r--r-- | libhb/fifo.c | 10 | ||||
-rw-r--r-- | libhb/internal.h | 18 | ||||
-rw-r--r-- | libhb/reader.c | 30 | ||||
-rw-r--r-- | libhb/scan.c | 24 | ||||
-rw-r--r-- | libhb/stream.c | 1244 |
12 files changed, 1189 insertions, 801 deletions
diff --git a/libhb/bd.c b/libhb/bd.c index 8eb68bcd2..3309d3f7e 100644 --- a/libhb/bd.c +++ b/libhb/bd.c @@ -72,6 +72,56 @@ int hb_bd_title_count( hb_bd_t * d ) return d->title_count; } +static void add_audio(int track, hb_list_t *list_audio, BLURAY_STREAM_INFO *bdaudio, int substream_type, uint32_t codec, uint32_t codec_param) +{ + hb_audio_t * audio; + iso639_lang_t * lang; + + audio = calloc( sizeof( hb_audio_t ), 1 ); + + audio->id = (substream_type << 16) | bdaudio->pid; + audio->config.in.stream_type = bdaudio->coding_type; + audio->config.in.substream_type = substream_type; + audio->config.in.codec = codec; + audio->config.in.codec_param = codec_param; + audio->config.lang.type = 0; + + lang = lang_for_code2( (char*)bdaudio->lang ); + + int stream_type = bdaudio->coding_type; + snprintf( audio->config.lang.description, + sizeof( audio->config.lang.description ), "%s (%s)", + strlen(lang->native_name) ? lang->native_name : lang->eng_name, + audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" : + ( audio->config.in.codec == HB_ACODEC_DCA ? "DTS" : + ( audio->config.in.codec == HB_ACODEC_MPGA ? + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_LPCM ? "BD LPCM" : + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_AC3PLUS ? "E-AC3" : + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_TRUHD ? "TrueHD" : + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_DTSHD ? "DTS-HD HRA" : + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER ? "DTS-HD MA" : + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_MPEG1 ? "MPEG1" : + ( stream_type == BLURAY_STREAM_TYPE_AUDIO_MPEG2 ? "MPEG2" : + "Unknown FFmpeg" + ) ) ) ) ) ) ) : "Unknown" + ) ) ); + + snprintf( audio->config.lang.simple, + sizeof( audio->config.lang.simple ), "%s", + strlen(lang->native_name) ? lang->native_name : + lang->eng_name ); + + snprintf( audio->config.lang.iso639_2, + sizeof( audio->config.lang.iso639_2 ), "%s", lang->iso639_2); + + hb_log( "bd: audio id=0x%x, lang=%s, 3cc=%s", audio->id, + audio->config.lang.description, audio->config.lang.iso639_2 ); + + audio->config.in.track = track; + hb_list_add( list_audio, audio ); + return; +} + static int bd_audio_equal( BLURAY_CLIP_INFO *a, BLURAY_CLIP_INFO *b ) { int ii, jj, equal; @@ -182,11 +232,11 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration ) title->video_id = bdvideo->pid; title->video_stream_type = bdvideo->coding_type; - hb_log( "bd: video id=%x, stream type=%s, format %s", title->video_id, + hb_log( "bd: video id=0x%x, stream type=%s, format %s", title->video_id, bdvideo->coding_type == BLURAY_STREAM_TYPE_VIDEO_MPEG1 ? "MPEG1" : bdvideo->coding_type == BLURAY_STREAM_TYPE_VIDEO_MPEG2 ? "MPEG2" : bdvideo->coding_type == BLURAY_STREAM_TYPE_VIDEO_VC1 ? "VC-1" : - bdvideo->coding_type == BLURAY_STREAM_TYPE_VIDEO_H264 ? "H264" : + bdvideo->coding_type == BLURAY_STREAM_TYPE_VIDEO_H264 ? "H.264" : "Unknown", bdvideo->format == BLURAY_VIDEO_FORMAT_480I ? "480i" : bdvideo->format == BLURAY_VIDEO_FORMAT_576I ? "576i" : @@ -227,7 +277,7 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration ) break; default: - hb_log( "scan: unknown video codec (%x)", + hb_log( "scan: unknown video codec (0x%x)", bdvideo->coding_type ); goto fail; } @@ -282,83 +332,61 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration ) // Add all the audios found in the above clip. for ( ii = 0; ii < ti->clips[audio_clip_index].audio_stream_count; ii++ ) { - hb_audio_t * audio; - iso639_lang_t * lang; BLURAY_STREAM_INFO * bdaudio; bdaudio = &ti->clips[audio_clip_index].audio_streams[ii]; - audio = calloc( sizeof( hb_audio_t ), 1 ); - audio->id = bdaudio->pid; - audio->config.in.stream_type = bdaudio->coding_type; switch( bdaudio->coding_type ) { - case BLURAY_STREAM_TYPE_AUDIO_AC3: case BLURAY_STREAM_TYPE_AUDIO_TRUHD: - audio->config.in.codec = HB_ACODEC_AC3; - audio->config.in.codec_param = 0; + // Add 2 audio tracks. One for TrueHD and one for AC-3 + add_audio(ii, title->list_audio, bdaudio, + HB_SUBSTREAM_BD_AC3, HB_ACODEC_AC3, 0); + add_audio(ii, title->list_audio, bdaudio, + HB_SUBSTREAM_BD_TRUEHD, HB_ACODEC_MPGA, CODEC_ID_TRUEHD); break; - case BLURAY_STREAM_TYPE_AUDIO_LPCM: - audio->config.in.codec = HB_ACODEC_MPGA; - audio->config.in.codec_param = CODEC_ID_PCM_BLURAY; + case BLURAY_STREAM_TYPE_AUDIO_DTS: + add_audio(ii, title->list_audio, bdaudio, 0, HB_ACODEC_DCA, 0); + break; + + case BLURAY_STREAM_TYPE_AUDIO_MPEG2: + case BLURAY_STREAM_TYPE_AUDIO_MPEG1: + add_audio(ii, title->list_audio, bdaudio, 0, + HB_ACODEC_MPGA, CODEC_ID_MP2); break; case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS: - audio->config.in.codec = HB_ACODEC_MPGA; - audio->config.in.codec_param = CODEC_ID_EAC3; + add_audio(ii, title->list_audio, bdaudio, 0, + HB_ACODEC_MPGA, CODEC_ID_EAC3); break; - case BLURAY_STREAM_TYPE_AUDIO_MPEG1: - case BLURAY_STREAM_TYPE_AUDIO_MPEG2: - audio->config.in.codec = HB_ACODEC_MPGA; - audio->config.in.codec_param = CODEC_ID_MP2; + case BLURAY_STREAM_TYPE_AUDIO_LPCM: + add_audio(ii, title->list_audio, bdaudio, 0, + HB_ACODEC_MPGA, CODEC_ID_PCM_BLURAY); + break; + + case BLURAY_STREAM_TYPE_AUDIO_AC3: + add_audio(ii, title->list_audio, bdaudio, 0, HB_ACODEC_AC3, 0); break; - case BLURAY_STREAM_TYPE_AUDIO_DTS: - case BLURAY_STREAM_TYPE_AUDIO_DTSHD: case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER: - audio->config.in.codec = HB_ACODEC_DCA; - audio->config.in.codec_param = 0; + case BLURAY_STREAM_TYPE_AUDIO_DTSHD: + // Add 2 audio tracks. One for DTS-HD and one for DTS + add_audio(ii, title->list_audio, bdaudio, HB_SUBSTREAM_BD_DTS, + HB_ACODEC_DCA, 0); + // DTS-HD is special. The substreams must be concatinated + // DTS-core followed by DTS-hd-extensions. Setting + // a substream id of 0 says use all substreams. + add_audio(ii, title->list_audio, bdaudio, 0, + HB_ACODEC_MPGA, CODEC_ID_DTS); break; default: - audio->config.in.codec = 0; hb_log( "scan: unknown audio pid 0x%x codec 0x%x", bdaudio->pid, bdaudio->coding_type ); break; } - - audio->config.lang.type = 0; - lang = lang_for_code2( (char*)bdaudio->lang ); - - snprintf( audio->config.lang.description, - sizeof( audio->config.lang.description ), "%s (%s)", - strlen(lang->native_name) ? lang->native_name : - lang->eng_name, - audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" : - ( audio->config.in.codec == HB_ACODEC_DCA ? "DTS" : - ( audio->config.in.codec == HB_ACODEC_MPGA ? - ( audio->config.in.codec_param == CODEC_ID_PCM_BLURAY ? "LPCM" : - ( audio->config.in.codec_param == CODEC_ID_EAC3 ? "E-AC3" : - ( audio->config.in.codec_param == CODEC_ID_MP2 ? "MPEG" : - "Unknown FFMpeg" - ) ) ) : "Unknown" - ) ) ); - - snprintf( audio->config.lang.simple, - sizeof( audio->config.lang.simple ), "%s", - strlen(lang->native_name) ? lang->native_name : - lang->eng_name ); - - snprintf( audio->config.lang.iso639_2, - sizeof( audio->config.lang.iso639_2 ), "%s", lang->iso639_2); - - hb_log( "bd: audio id=0x%x, lang=%s, 3cc=%s", audio->id, - audio->config.lang.description, audio->config.lang.iso639_2 ); - - audio->config.in.track = ii; - hb_list_add( title->list_audio, audio ); } /* Chapters */ @@ -507,20 +535,23 @@ int hb_bd_seek_chapter( hb_bd_t * d, int c ) *********************************************************************** * **********************************************************************/ -int hb_bd_read( hb_bd_t * d, hb_buffer_t * b ) +hb_buffer_t * hb_bd_read( hb_bd_t * d ) { int result; int error_count = 0; uint8_t buf[192]; BD_EVENT event; uint64_t pos; + hb_buffer_t * b; + uint8_t discontinuity; + int new_chap = 0; - b->discontinuity = 0; + discontinuity = 0; while ( 1 ) { if ( d->next_chap != d->chapter ) { - b->new_chap = d->chapter = d->next_chap; + new_chap = d->chapter = d->next_chap; } result = next_packet( d->bd, buf ); if ( result < 0 ) @@ -553,8 +584,8 @@ int hb_bd_read( hb_bd_t * d, hb_buffer_t * b ) break; case BD_EVENT_PLAYITEM: + discontinuity = 1; hb_deep_log(2, "bd: Playitem %u", event.param); - b->discontinuity = 1; break; default: @@ -562,13 +593,15 @@ int hb_bd_read( hb_bd_t * d, hb_buffer_t * b ) } } // buf+4 to skip the BD timestamp at start of packet - result = hb_ts_decode_pkt( d->stream, buf+4, b ); - if ( result ) + b = hb_ts_decode_pkt( d->stream, buf+4 ); + if ( b ) { - return 1; + b->discontinuity = discontinuity; + b->new_chap = new_chap; + return b; } } - return 0; + return NULL; } /*********************************************************************** diff --git a/libhb/common.h b/libhb/common.h index d05d26157..4844bd689 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -328,6 +328,11 @@ struct hb_job_s #define HB_ACODEC_DCA_PASS (HB_ACODEC_DCA | HB_ACODEC_PASS_FLAG) #define HB_ACODEC_ANY (HB_ACODEC_MASK | HB_ACODEC_PASS_FLAG) +#define HB_SUBSTREAM_BD_TRUEHD 0x72 +#define HB_SUBSTREAM_BD_AC3 0x76 +#define HB_SUBSTREAM_BD_DTSHD 0x72 +#define HB_SUBSTREAM_BD_DTS 0x71 + /* Audio Mixdown */ /* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */ #define HB_AMIXDOWN_DCA_FORMAT_MASK 0x00FFF000 @@ -410,7 +415,9 @@ struct hb_audio_config_s { int track; /* Input track number */ PRIVATE uint32_t codec; /* Input audio codec */ + PRIVATE uint32_t reg_desc; /* registration descriptor of source */ PRIVATE uint32_t stream_type; /* stream type from source stream */ + PRIVATE uint32_t substream_type; /* substream for multiplexed streams */ PRIVATE uint32_t codec_param; /* per-codec config info */ PRIVATE uint32_t version; /* Bitsream version */ PRIVATE uint32_t mode; /* Bitstream mode, codec dependent encoding */ diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 53e47c7b5..3bb0fe087 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -435,12 +435,9 @@ static int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { uint8_t *parser_output_buffer; int parser_output_buffer_len; - int64_t cur = pv->pts_next; + int64_t cur; - if ( in->start != -1 ) - { - cur = in->start; - } + cur = in->start; if ( pv->parser != NULL ) { @@ -1528,6 +1525,9 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat int pos = 0; int loop_limit = 256; + if ( pts != -1 ) + pv->pts_next = pts; + while ( pos < size ) { float *buffer = pv->buffer; @@ -1541,7 +1541,7 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat av_init_packet( &avp ); avp.data = data + pos; avp.size = size - pos; - avp.pts = pts; + avp.pts = pv->pts_next; avp.dts = AV_NOPTS_VALUE; int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; @@ -1600,17 +1600,12 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat nsamples = out_size / sizeof(hb_sample_t); } - if ( pts == AV_NOPTS_VALUE ) - { - pts = pv->pts_next; - } - hb_buffer_t * buf; - double pts_next = pts + nsamples * pv->duration; + double pts_next = pv->pts_next + nsamples * pv->duration; buf = downmixAudio( audio, pv, buffer, context->channels, nsamples ); if ( buf ) { - buf->start = pts; + buf->start = pv->pts_next; buf->stop = pts_next; hb_list_add( pv->list, buf ); } @@ -1625,7 +1620,7 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat buf = downmixAudio( ff_audio, ff_pv, buffer, context->channels, nsamples ); if ( buf ) { - buf->start = pts; + buf->start = pv->pts_next; buf->stop = pts_next; hb_list_add( ff_pv->list, buf ); } 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 }; diff --git a/libhb/dvd.c b/libhb/dvd.c index 2d18dee71..c5c052223 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -20,7 +20,7 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * d, int t, uint64_t min_du static int hb_dvdread_start( hb_dvd_t * d, hb_title_t *title, int chapter ); static void hb_dvdread_stop( hb_dvd_t * d ); static int hb_dvdread_seek( hb_dvd_t * d, float f ); -static int hb_dvdread_read( hb_dvd_t * d, hb_buffer_t * b ); +static hb_buffer_t * hb_dvdread_read( hb_dvd_t * d ); static int hb_dvdread_chapter( hb_dvd_t * d ); static int hb_dvdread_angle_count( hb_dvd_t * d ); static void hb_dvdread_set_angle( hb_dvd_t * d, int angle ); @@ -840,9 +840,10 @@ int is_nav_pack( unsigned char *buf ) *********************************************************************** * **********************************************************************/ -static int hb_dvdread_read( hb_dvd_t * e, hb_buffer_t * b ) +static hb_buffer_t * hb_dvdread_read( hb_dvd_t * e ) { hb_dvdread_t *d = &(e->dvdread); + hb_buffer_t *b = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); top: if( !d->pack_len ) { @@ -855,7 +856,10 @@ static int hb_dvdread_read( hb_dvd_t * e, hb_buffer_t * b ) // is probably invalid. Just return 'no data' & our caller // should check and discover we're at eof. if ( d->cell_cur > d->cell_end ) - return 0; + { + hb_buffer_close( &b ); + return NULL; + } for( ;; ) { @@ -896,7 +900,10 @@ static int hb_dvdread_read( hb_dvd_t * e, hb_buffer_t * b ) d->next_vobu, d->cell_next ); d->cell_cur = d->cell_next; if ( d->cell_cur > d->cell_end ) - return 0; + { + hb_buffer_close( &b ); + return NULL; + } d->in_cell = 0; d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector; FindNextCell( d ); @@ -994,7 +1001,8 @@ static int hb_dvdread_read( hb_dvd_t * e, hb_buffer_t * b ) if( ++error > 1024 ) { hb_log( "dvd: couldn't find a VOBU after 1024 blocks" ); - return 0; + hb_buffer_close( &b ); + return NULL; } (d->next_vobu)++; @@ -1099,7 +1107,7 @@ static int hb_dvdread_read( hb_dvd_t * e, hb_buffer_t * b ) d->block++; - return 1; + return b; } /*********************************************************************** @@ -1303,9 +1311,9 @@ int hb_dvd_seek( hb_dvd_t * d, float f ) return dvd_methods->seek(d, f); } -int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b ) +hb_buffer_t * hb_dvd_read( hb_dvd_t * d ) { - return dvd_methods->read(d, b); + return dvd_methods->read(d); } int hb_dvd_chapter( hb_dvd_t * d ) diff --git a/libhb/dvd.h b/libhb/dvd.h index 919d3ac8c..a6e8fc2d5 100644 --- a/libhb/dvd.h +++ b/libhb/dvd.h @@ -76,7 +76,7 @@ struct hb_dvd_func_s int (* start) ( hb_dvd_t *, hb_title_t *, int ); void (* stop) ( hb_dvd_t * ); int (* seek) ( hb_dvd_t *, float ); - int (* read) ( hb_dvd_t *, hb_buffer_t * ); + hb_buffer_t * (* read) ( hb_dvd_t * ); int (* chapter) ( hb_dvd_t * ); int (* angle_count) ( hb_dvd_t * ); void (* set_angle) ( hb_dvd_t *, int ); diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 764ebd8c0..d65b6abbb 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -22,7 +22,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * d, int t, uint64_t min_dur static int hb_dvdnav_start( hb_dvd_t * d, hb_title_t *title, int chapter ); static void hb_dvdnav_stop( hb_dvd_t * d ); static int hb_dvdnav_seek( hb_dvd_t * d, float f ); -static int hb_dvdnav_read( hb_dvd_t * d, hb_buffer_t * b ); +static hb_buffer_t * hb_dvdnav_read( hb_dvd_t * d ); static int hb_dvdnav_chapter( hb_dvd_t * d ); static void hb_dvdnav_close( hb_dvd_t ** _d ); static int hb_dvdnav_angle_count( hb_dvd_t * d ); @@ -1482,18 +1482,20 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f ) *********************************************************************** * **********************************************************************/ -static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) +static hb_buffer_t * hb_dvdnav_read( hb_dvd_t * e ) { hb_dvdnav_t * d = &(e->dvdnav); int result, event, len; int chapter = 0; int error_count = 0; + hb_buffer_t *b = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); while ( 1 ) { if (d->stopped) { - return 0; + hb_buffer_close( &b ); + return NULL; } result = dvdnav_get_next_block( d->dvdnav, b->data, &event, &len ); if ( result == DVDNAV_STATUS_ERR ) @@ -1503,13 +1505,15 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) { hb_error( "dvd: dvdnav_sector_search failed - %s", dvdnav_err_to_string(d->dvdnav) ); - return 0; + hb_buffer_close( &b ); + return NULL; } error_count++; if (error_count > 500) { hb_error("dvdnav: Error, too many consecutive read errors"); - return 0; + hb_buffer_close( &b ); + return NULL; } continue; } @@ -1525,7 +1529,7 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) b->new_chap = chapter; chapter = 0; error_count = 0; - return 1; + return b; case DVDNAV_NOP: /* @@ -1600,7 +1604,8 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) if (tt != d->title) { // Transition to another title signals that we are done. - return 0; + hb_buffer_close( &b ); + return NULL; } } break; @@ -1622,7 +1627,8 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) if (tt != d->title) { // Transition to another title signals that we are done. - return 0; + hb_buffer_close( &b ); + return NULL; } c = FindChapterIndex(d->list_chapter, pgcn, pgn); if (c != d->chapter) @@ -1631,13 +1637,15 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) { // Some titles end with a 'link' back to the beginning so // a transition to an earlier chapter means we're done. - return 0; + hb_buffer_close( &b ); + return NULL; } chapter = d->chapter = c; } else if ( cell_event->cellN <= d->cell ) { - return 0; + hb_buffer_close( &b ); + return NULL; } d->cell = cell_event->cellN; } @@ -1661,7 +1669,7 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) if (chapter > 1) b->new_chap = chapter; chapter = 0; - return 1; + return b; break; @@ -1678,13 +1686,15 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b ) * Playback should end here. */ d->stopped = 1; - return 0; + hb_buffer_close( &b ); + return NULL; default: break; } } - return 0; + hb_buffer_close( &b ); + return NULL; } /*********************************************************************** diff --git a/libhb/fifo.c b/libhb/fifo.c index 3f0d9ea86..232741e32 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -119,7 +119,13 @@ static hb_fifo_t *size_to_pool( int size ) hb_buffer_t * hb_buffer_init( int size ) { hb_buffer_t * b; - hb_fifo_t *buffer_pool = size_to_pool( size ); + // Certain libraries (hrm ffmpeg) expect buffers passed to them to + // end on certain alignments (ffmpeg is 8). So allocate some extra bytes. + // Note that we can't simply align the end of our buffer because + // sometimes we feed data to these libraries starting from arbitrary + // points within the buffer. + int alloc = size + 16; + hb_fifo_t *buffer_pool = size_to_pool( alloc ); if( buffer_pool ) { @@ -150,7 +156,7 @@ hb_buffer_t * hb_buffer_init( int size ) } b->size = size; - b->alloc = buffer_pool? buffer_pool->buffer_size : size; + b->alloc = buffer_pool ? buffer_pool->buffer_size : alloc; if (size) { diff --git a/libhb/internal.h b/libhb/internal.h index eec560efb..700084e78 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -69,6 +69,7 @@ struct hb_buffer_s int id; // ID of the track that the packet comes from int64_t start; // Video and subtitle packets: start time of frame/subtitle int64_t stop; // Video and subtitle packets: stop time of frame/subtitle + int64_t pcr; uint8_t discontinuity; int new_chap; // Video packets: if non-zero, is the index of the chapter whose boundary was crossed @@ -191,13 +192,14 @@ typedef struct { int64_t last_pts; /* last pts we saw */ int scr_changes; /* number of SCR discontinuities */ int dts_drops; /* number of drops because DTS too far from SCR */ + int new_chap; } hb_psdemux_t; -typedef int (*hb_muxer_t)(hb_buffer_t *, hb_list_t *, hb_psdemux_t*); +typedef void (*hb_muxer_t)(hb_buffer_t *, hb_list_t *, hb_psdemux_t*); -int hb_demux_ps( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); -int hb_demux_ss( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); -int hb_demux_null( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); +void hb_demux_ps( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); +void hb_demux_ts( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); +void hb_demux_null( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); extern const hb_muxer_t hb_demux[]; @@ -229,7 +231,7 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t *, int title, uint64_t min_duration ); int hb_dvd_start( hb_dvd_t *, hb_title_t *title, int chapter ); void hb_dvd_stop( hb_dvd_t * ); int hb_dvd_seek( hb_dvd_t *, float ); -int hb_dvd_read( hb_dvd_t *, hb_buffer_t * ); +hb_buffer_t * hb_dvd_read( hb_dvd_t * ); int hb_dvd_chapter( hb_dvd_t * ); int hb_dvd_is_break( hb_dvd_t * d ); void hb_dvd_close( hb_dvd_t ** ); @@ -245,7 +247,7 @@ void hb_bd_stop( hb_bd_t * d ); int hb_bd_seek( hb_bd_t * d, float f ); int hb_bd_seek_pts( hb_bd_t * d, uint64_t pts ); int hb_bd_seek_chapter( hb_bd_t * d, int chapter ); -int hb_bd_read( hb_bd_t * d, hb_buffer_t * b ); +hb_buffer_t * hb_bd_read( hb_bd_t * d ); int hb_bd_chapter( hb_bd_t * d ); void hb_bd_close( hb_bd_t ** _d ); void hb_bd_set_angle( hb_bd_t * d, int angle ); @@ -255,13 +257,13 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ); hb_stream_t * hb_stream_open( char * path, hb_title_t *title ); void hb_stream_close( hb_stream_t ** ); hb_title_t * hb_stream_title_scan( hb_stream_t *); -int hb_stream_read( hb_stream_t *, hb_buffer_t *); +hb_buffer_t * hb_stream_read( hb_stream_t * ); int hb_stream_seek( hb_stream_t *, float ); int hb_stream_seek_ts( hb_stream_t * stream, int64_t ts ); int hb_stream_seek_chapter( hb_stream_t *, int ); int hb_stream_chapter( hb_stream_t * ); -int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obuf ); +hb_buffer_t * hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt ); void * hb_ffmpeg_context( int codec_param ); diff --git a/libhb/reader.c b/libhb/reader.c index ec05a4798..037fe0931 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -256,13 +256,11 @@ static void ReaderFunc( void * _r ) return; } - hb_buffer_t *ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); if (r->bd) { if( !hb_bd_start( r->bd, r->title ) ) { hb_bd_close( &r->bd ); - hb_buffer_close( &ps ); return; } if ( r->job->start_at_preview ) @@ -312,7 +310,6 @@ static void ReaderFunc( void * _r ) if( !hb_dvd_start( r->dvd, r->title, start ) ) { hb_dvd_close( &r->dvd ); - hb_buffer_close( &ps ); return; } if (r->job->angle) @@ -341,13 +338,13 @@ static void ReaderFunc( void * _r ) // Find out what the first timestamp of the stream is // and then seek to the appropriate offset from it - if ( hb_stream_read( r->stream, ps ) ) + if ( ( buf = hb_stream_read( r->stream ) ) ) { - if ( ps->start > 0 ) + if ( buf->start > 0 ) { - pts_to_start += ps->start; - r->pts_to_start += ps->start; - r->job->pts_to_start += ps->start; + pts_to_start += buf->start; + r->pts_to_start += buf->start; + r->job->pts_to_start += buf->start; } } @@ -408,21 +405,21 @@ static void ReaderFunc( void * _r ) if (r->bd) { - if( !hb_bd_read( r->bd, ps ) ) + if( (buf = hb_bd_read( r->bd )) == NULL ) { break; } } else if (r->dvd) { - if( !hb_dvd_read( r->dvd, ps ) ) + if( (buf = hb_dvd_read( r->dvd )) == NULL ) { break; } } else if (r->stream) { - if ( !hb_stream_read( r->stream, ps ) ) + if ( (buf = hb_stream_read( r->stream )) == NULL ) { break; } @@ -431,11 +428,11 @@ static void ReaderFunc( void * _r ) // We will inspect the timestamps of each frame in sync // to skip from this seek point to the timestamp we // want to start at. - if ( ps->start > 0 && ps->start < r->job->pts_to_start ) + if ( buf->start > 0 && buf->start < r->job->pts_to_start ) { - r->job->pts_to_start -= ps->start; + r->job->pts_to_start -= buf->start; } - else if ( ps->start >= r->job->pts_to_start ) + else if ( buf->start >= r->job->pts_to_start ) { r->job->pts_to_start = 0; r->start_found = 1; @@ -465,7 +462,7 @@ static void ReaderFunc( void * _r ) hb_set_state( r->job->h, &state ); } - (hb_demux[r->title->demuxer])( ps, list, &r->demux ); + (hb_demux[r->title->demuxer])( buf, list, &r->demux ); while( ( buf = hb_list_item( list, 0 ) ) ) { @@ -486,7 +483,7 @@ static void ReaderFunc( void * _r ) // offset will get computed correctly. id_to_st( r, buf, 1 ); r->saw_video = 1; - hb_log( "reader: first SCR %"PRId64" id %d DTS %"PRId64, + hb_log( "reader: first SCR %"PRId64" id 0x%x DTS %"PRId64, r->demux.last_scr, buf->id, buf->renderOffset ); } else @@ -604,7 +601,6 @@ static void ReaderFunc( void * _r ) } hb_list_empty( &list ); - hb_buffer_close( &ps ); if (r->bd) { hb_bd_stop( r->bd ); diff --git a/libhb/scan.c b/libhb/scan.c index 7b563638a..247e25028 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -461,14 +461,13 @@ static void most_common_info( info_list_t *info_list, hb_work_info_t *info ) static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) { int i, npreviews = 0; - hb_buffer_t * buf_ps, * buf_es; + hb_buffer_t * buf, * buf_es; hb_list_t * list_es; int progressive_count = 0; int interlaced_preview_count = 0; info_list_t * info_list = calloc( data->preview_count+1, sizeof(*info_list) ); crop_record_t *crops = calloc( 1, sizeof(*crops) ); - buf_ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); list_es = hb_list_init(); hb_log( "scan: decoding previews for title %d", title->index ); @@ -563,7 +562,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) { if (data->bd) { - if( !hb_bd_read( data->bd, buf_ps ) ) + if( (buf = hb_bd_read( data->bd )) == NULL ) { if ( vid_buf ) { @@ -573,9 +572,9 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) goto skip_preview; } } - if (data->dvd) + else if (data->dvd) { - if( !hb_dvd_read( data->dvd, buf_ps ) ) + if( (buf = hb_dvd_read( data->dvd )) == NULL ) { if ( vid_buf ) { @@ -587,7 +586,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) } else if (data->stream) { - if ( !hb_stream_read(data->stream,buf_ps) ) + if ( (buf = hb_stream_read( data->stream )) == NULL ) { if ( vid_buf ) { @@ -597,7 +596,15 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) goto skip_preview; } } - (hb_demux[title->demuxer])(buf_ps, list_es, 0 ); + else + { + // Silence compiler warning + buf = NULL; + hb_error( "Error: This can't happen!" ); + goto skip_preview; + } + + (hb_demux[title->demuxer])(buf, list_es, 0 ); while( ( buf_es = hb_list_item( list_es, 0 ) ) ) { @@ -900,7 +907,6 @@ skip_preview: } } - hb_buffer_close( &buf_ps ); while( ( buf_es = hb_list_item( list_es, 0 ) ) ) { hb_list_rem( list_es, buf_es ); @@ -957,7 +963,7 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b ) if ( audio->priv.scan_cache == NULL ) audio->priv.scan_cache = hb_fifo_init( 16, 16 ); - if ( hb_fifo_size_bytes( audio->priv.scan_cache ) >= 4096 ) + if ( hb_fifo_size_bytes( audio->priv.scan_cache ) >= 16384 ) { hb_buffer_t * tmp; tmp = hb_fifo_get( audio->priv.scan_cache ); diff --git a/libhb/stream.c b/libhb/stream.c index f48edbe4c..899c49513 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -13,6 +13,7 @@ #include "lang.h" #include "a52dec/a52.h" #include "mp4v2/mp4v2.h" +#include "libbluray/bluray.h" #define min(a, b) a < b ? a : b @@ -56,33 +57,33 @@ static const stream2codec_t st2codec[256] = { st(0x0c, N, 0, 0, "ISO 13818-6 Stream descriptors"), st(0x0d, N, 0, 0, "ISO 13818-6 Sections"), st(0x0e, N, 0, 0, "ISO 13818-1 auxiliary"), - st(0x0f, A, HB_ACODEC_MPGA, CODEC_ID_AAC, "ISO 13818-7 AAC Audio"), + st(0x0f, A, HB_ACODEC_MPGA, CODEC_ID_AAC, "AAC"), st(0x10, V, WORK_DECAVCODECV, CODEC_ID_MPEG4, "MPEG4"), - st(0x11, A, HB_ACODEC_MPGA, CODEC_ID_AAC_LATM, "MPEG4 LATM AAC"), + st(0x11, A, HB_ACODEC_MPGA, CODEC_ID_AAC_LATM, "LATM AAC"), st(0x12, U, 0, 0, "MPEG4 generic"), st(0x14, N, 0, 0, "ISO 13818-6 DSM-CC download"), st(0x1b, V, WORK_DECAVCODECV, CODEC_ID_H264, "H.264"), - st(0x80, N, HB_ACODEC_MPGA, CODEC_ID_PCM_BLURAY, "DigiCipher II Video/LPCM"), - 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/TrueHD"), - st(0x84, A, 0, 0, "SDDS/EAC3"), - st(0x85, U, 0, 0, "ATSC Program ID/DTS-HD HRA"), + st(0x80, N, HB_ACODEC_MPGA, CODEC_ID_PCM_BLURAY, "Digicipher II Video"), + st(0x81, A, HB_ACODEC_AC3, 0, "AC3"), + st(0x82, A, HB_ACODEC_DCA, 0, "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, A, HB_ACODEC_DCA, 0, "DTS-HD MA"), - st(0x87, A, HB_ACODEC_MPGA, CODEC_ID_EAC3, "EAC3"), + st(0x87, A, HB_ACODEC_MPGA, CODEC_ID_EAC3, "E-AC3"), st(0x8a, A, HB_ACODEC_DCA, 0, "DTS"), - st(0x91, A, HB_ACODEC_AC3, 0, "AC-3"), + st(0x91, A, HB_ACODEC_AC3, 0, "AC3"), st(0x92, N, 0, 0, "Subtitle"), - st(0x94, A, 0, 0, "SDDS"), + st(0x94, U, 0, 0, "SDDS"), st(0xa0, V, 0, 0, "MSCODEC"), - st(0xea, V, WORK_DECAVCODECV, CODEC_ID_VC1, "VC1"), + st(0xea, V, WORK_DECAVCODECV, CODEC_ID_VC1, "VC-1"), }; #undef st @@ -95,8 +96,31 @@ typedef enum { } hb_stream_type_t; #define kMaxNumberDecodeStreams 32 +#define kMaxNumberDecodeSubStreams 2 #define kMaxNumberPMTStreams 32 +typedef struct { + hb_buffer_t *buf; + hb_buffer_t *extra_buf; + int8_t skipbad; + int8_t continuity; + uint8_t pkt_summary[8]; + int16_t pid; + + uint32_t format_id; +#define TS_FORMAT_ID_AC3 (('A' << 24) | ('C' << 16) | ('-' << 8) | '3') + uint8_t stream_type; + kind_t stream_kind; + int number_substreams; + uint8_t substream_type[kMaxNumberDecodeSubStreams]; + uint8_t current_substream; + struct { + int lang_code; + int flags; + int rate; + int bitrate; + } a52_info; +} hb_ts_stream_t; struct hb_stream_s { @@ -107,23 +131,19 @@ struct hb_stream_s int packetsize; /* Transport Stream packet size */ uint8_t need_keyframe; // non-zero if want to start at a keyframe + hb_buffer_t *fwrite_buf; /* PS buffer (set by hb_ts_stream_decode) */ + + int chapter; /* Chapter that we are currently in */ + int64_t chapter_end; /* HB time that the current chapter ends */ + uint8_t ts_found_pcr; // non-zero if we've found at least one input pcr int ts_pcr_out; // sequence number of most recent output pcr int ts_pcr_in; // sequence number of most recent input pcr int64_t ts_pcr; // most recent input pcr - int64_t ts_pcrhist[4]; // circular buffer of output pcrs + int64_t ts_pcr_current; // circular buffer of output pcrs uint8_t *ts_packet; /* buffer for one TS packet */ - hb_buffer_t *ts_buf[kMaxNumberDecodeStreams]; - int ts_pos[kMaxNumberDecodeStreams]; - int8_t ts_skipbad[kMaxNumberDecodeStreams]; - int8_t ts_streamcont[kMaxNumberDecodeStreams]; - uint8_t ts_pkt_summary[kMaxNumberDecodeStreams][8]; - - hb_buffer_t *fwrite_buf; /* PS buffer (set by hb_ts_stream_decode) */ - - int chapter; /* Chapter that we are currently in */ - int64_t chapter_end; /* HB time that the current chapter ends */ + hb_ts_stream_t ts[kMaxNumberDecodeStreams]; /* * Stuff before this point is dynamic state updated as we read the @@ -138,13 +158,6 @@ struct hb_stream_s #define TS_HAS_RSEI (1 << 2) // "Restart point" SEI seen uint8_t ts_IDRs; // # IDRs found during duration scan - int16_t ts_pids[kMaxNumberDecodeStreams]; - - uint32_t ts_format_id[kMaxNumberDecodeStreams]; -#define TS_FORMAT_ID_AC3 (('A' << 24) | ('C' << 16) | ('-' << 8) | '3') - uint8_t ts_stream_type[kMaxNumberDecodeStreams]; - kind_t ts_stream_kind[kMaxNumberDecodeStreams]; - uint8_t ts_multiplexed[kMaxNumberDecodeStreams]; char *path; FILE *file_handle; @@ -156,13 +169,6 @@ struct hb_stream_s double ffmpeg_tsconv[MAX_STREAMS]; uint8_t ffmpeg_video_id; - struct { - int lang_code; - int flags; - int rate; - int bitrate; - } a52_info[kMaxNumberDecodeStreams]; - struct { unsigned short program_number; @@ -198,17 +204,16 @@ struct hb_stream_s static void hb_stream_duration(hb_stream_t *stream, hb_title_t *inTitle); static void hb_ts_stream_init(hb_stream_t *stream); static void hb_ts_stream_find_pids(hb_stream_t *stream); -static int hb_ts_stream_decode(hb_stream_t *stream, hb_buffer_t *obuf); +static hb_buffer_t * hb_ts_stream_decode(hb_stream_t *stream); static void hb_ts_stream_reset(hb_stream_t *stream); -static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream, - int idx); +static void hb_ts_stream_set_audio_list(hb_list_t *list_audio, hb_stream_t *stream); static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title); static off_t align_to_next_packet(hb_stream_t *stream); static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title ); static void ffmpeg_close( hb_stream_t *d ); static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream ); -static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ); +static hb_buffer_t *ffmpeg_read( hb_stream_t *stream ); static int ffmpeg_seek( hb_stream_t *stream, float frac ); static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts ); @@ -293,7 +298,7 @@ static void ts_warn( hb_stream_t *stream, char *log, ... ) static kind_t ts_stream_kind( hb_stream_t *stream, int curstream ) { - return st2codec[stream->ts_stream_type[curstream]].kind; + return st2codec[stream->ts[curstream].stream_type].kind; } static int index_of_pid(hb_stream_t *stream, int pid) @@ -301,8 +306,12 @@ static int index_of_pid(hb_stream_t *stream, int pid) int i; for ( i = 0; i < stream->ts_number_pids; ++i ) - if ( pid == stream->ts_pids[i] ) + { + if ( pid == stream->ts[i].pid ) + { return i; + } + } return -1; } @@ -312,7 +321,7 @@ static int index_of_video(hb_stream_t *stream) int i; for ( i = 0; i < stream->ts_number_pids; ++i ) - if ( V == stream->ts_stream_kind[i] ) + if ( V == stream->ts[i].stream_kind ) return i; return -1; @@ -325,9 +334,8 @@ static void ts_err( hb_stream_t *stream, int curstream, char *log, ... ) ts_warn_helper( stream, log, args ); va_end( args ); - stream->ts_skipbad[curstream] = 1; - stream->ts_pos[curstream] = 0; - stream->ts_streamcont[curstream] = -1; + stream->ts[curstream].skipbad = 1; + stream->ts[curstream].continuity = -1; } static int check_ps_sync(const uint8_t *buf) @@ -497,10 +505,12 @@ static void hb_stream_delete_dynamic( hb_stream_t *d ) } for (i = 0; i < kMaxNumberDecodeStreams; i++) { - if (d->ts_buf[i]) + if (d->ts[i].buf) { - hb_buffer_close(&(d->ts_buf[i])); - d->ts_buf[i] = NULL; + hb_buffer_close(&(d->ts[i].buf)); + hb_buffer_close(&(d->ts[i].extra_buf)); + d->ts[i].buf = NULL; + d->ts[i].extra_buf = NULL; } } } @@ -512,9 +522,39 @@ static void hb_stream_delete( hb_stream_t *d ) free( d ); } +static int find_substream( hb_ts_stream_t *ts, int substream ) +{ + int i, all_match = -1; + + if ( ts->number_substreams == 0 ) + return 0; + + for ( i = 0; i < ts->number_substreams; i++ ) + { + if ( ts->substream_type[i] == 0 ) + all_match = 0; + if ( ts->substream_type[i] == substream ) + { + return ts->substream_type[i]; + } + } + return all_match; +} + +static void remove_substream( hb_ts_stream_t *ts, int idx ) +{ + int i; + + for ( i = idx; i < ts->number_substreams-1; i++ ) + { + ts->substream_type[i] = ts->substream_type[i+1]; + } + ts->number_substreams--; +} + static int audio_inactive( hb_stream_t *stream, int idx ) { - int pid = stream->ts_pids[idx]; + int pid = stream->ts[idx].pid; if ( pid < 0 ) { @@ -527,20 +567,29 @@ static int audio_inactive( hb_stream_t *stream, int idx ) return 0; } - // see if we should make the stream inactive because scan.c didn't - // find a valid audio bitstream. - int i; - for ( i = 0; i < hb_list_count( stream->title->list_audio ); ++i ) + // Must go backwards thru the list of substreams because we may + // remove one which would shift the list down. + int j; + for ( j = stream->ts[idx].number_substreams - 1; j >= 0; j-- ) { - hb_audio_t *audio = hb_list_item( stream->title->list_audio, i ); - if ( audio->id == pid ) + int substream = stream->ts[idx].substream_type[j]; + + // see if we should make the stream inactive because scan.c didn't + // find a valid audio bitstream. + int i; + for ( i = 0; i < hb_list_count( stream->title->list_audio ); ++i ) { - return 0; + hb_audio_t *audio = hb_list_item( stream->title->list_audio, i ); + if ( audio->id == ((substream << 16) | pid) ) + { + return 0; + } } + remove_substream( &stream->ts[idx], j ); } // not in the title's audio list - declare the PID inactive - stream->ts_pids[idx] = -stream->ts_pids[idx]; + stream->ts[idx].pid = -stream->ts[idx].pid; return 1; } @@ -591,15 +640,17 @@ hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) int i; for ( i = 0; i < d->ts_number_pids; i++) { - if ( d->ts_stream_kind[i] == A && + if ( d->ts[i].stream_kind == A && audio_inactive( d, i ) ) { // this PID isn't wanted (we don't have a codec for it // or scan didn't find audio parameters) continue; } - d->ts_buf[i] = hb_buffer_init(d->packetsize); - d->ts_buf[i]->size = 0; + d->ts[i].buf = hb_buffer_init(d->packetsize); + d->ts[i].extra_buf = hb_buffer_init(d->packetsize); + d->ts[i].buf->size = 0; + d->ts[i].extra_buf->size = 0; } hb_stream_seek( d, 0. ); } @@ -651,14 +702,14 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ) hb_stream_t *d = calloc( sizeof( hb_stream_t ), 1 ); if ( d == NULL ) { - hb_log( "hb_bd_stream_open: can't allocate space for stream state" ); + hb_error( "hb_bd_stream_open: can't allocate space for stream state" ); return NULL; } for (ii = 0; ii < kMaxNumberDecodeStreams; ii++) { - d->ts_streamcont[ii] = -1; - d->ts_pids[ii] = -1; + d->ts[ii].continuity = -1; + d->ts[ii].pid = -1; } d->file_handle = NULL; @@ -667,55 +718,40 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ) d->ts_packet = NULL; d->ts_number_pids = 0; - d->ts_pids[0] = title->video_id; - d->ts_stream_type[0] = title->video_stream_type; - d->ts_stream_kind[0] = V; + d->ts[0].pid = title->video_id; + d->ts[0].stream_type = title->video_stream_type; + d->ts[0].stream_kind = V; + d->ts[0].substream_type[0] = 0; + d->ts[0].number_substreams = 1; d->ts_number_pids++; hb_audio_t * audio; for ( ii = 0; ( audio = hb_list_item( title->list_audio, ii ) ); ++ii ) { - d->ts_pids[d->ts_number_pids] = audio->id; - d->ts_stream_type[d->ts_number_pids] = audio->config.in.stream_type; - d->ts_stream_kind[d->ts_number_pids] = A; + int pid = audio->id & 0xFFFF; + int idx = index_of_pid( d, pid ); - if ( d->ts_stream_type[d->ts_number_pids] == 0x83 && - title->reg_desc == STR4_TO_UINT32("HDMV") ) + if ( idx < 0 ) { - // This is an interleaved TrueHD/AC-3 stream and the esid of - // the AC-3 is 0x76 - d->ts_multiplexed[d->ts_number_pids] = 0x76; - d->ts_stream_type[d->ts_number_pids] = 0x81; + // New pid + d->ts[d->ts_number_pids].pid = audio->id & 0xFFFF; + d->ts[d->ts_number_pids].stream_type = audio->config.in.stream_type; + d->ts[d->ts_number_pids].substream_type[0] = audio->config.in.substream_type; + d->ts[d->ts_number_pids].number_substreams = 1; + d->ts[d->ts_number_pids].stream_kind = A; + d->ts_number_pids++; } - if ( d->ts_stream_type[d->ts_number_pids] == 0x86 && - title->reg_desc == STR4_TO_UINT32("HDMV") ) + else if ( d->ts[idx].number_substreams < kMaxNumberDecodeSubStreams ) { - // This is an interleaved DTS-HD MA/DTS stream and the esid of - // the DTS is 0x71 - d->ts_multiplexed[d->ts_number_pids] = 0x71; - d->ts_stream_type[d->ts_number_pids] = 0x82; + d->ts[idx].substream_type[d->ts[idx].number_substreams] = + audio->config.in.substream_type; + d->ts[idx].number_substreams++; + d->ts[idx].stream_kind = A; } - if ( d->ts_stream_type[d->ts_number_pids] == 0x85 && - title->reg_desc == STR4_TO_UINT32("HDMV") ) + else { - // DTS-HD HRA audio in bluray has an stype of 0x85 - // which conflicts with ATSC Program ID - // To distinguish, Bluray streams have a reg_desc of HDMV - // This is an interleaved DTS-HD HRA/DTS stream and the esid of - // the DTS is 0x71 - d->ts_multiplexed[d->ts_number_pids] = 0x71; - d->ts_stream_type[d->ts_number_pids] = 0x82; + hb_error( "hb_bd_stream_open: Too many substreams. Dropping audio 0x%x.", audio->id ); } - if ( d->ts_stream_type[d->ts_number_pids] == 0x84 && - title->reg_desc == STR4_TO_UINT32("HDMV") ) - { - // EAC3 audio in bluray has an stype of 0x84 - // which conflicts with SDDS - // To distinguish, Bluray streams have a reg_desc of HDMV - d->ts_stream_type[d->ts_number_pids] = 0x87; - } - - d->ts_number_pids++; } d->ts_flags = TS_HAS_RAP; @@ -728,8 +764,10 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ) if ( index_of_pid( d, title->pcr_pid ) < 0 ) { // BD PCR PID is specified to always be 0x1001 - d->ts_pids[d->ts_number_pids] = 0x1001; - d->ts_stream_kind[d->ts_number_pids] = P; + d->ts[d->ts_number_pids].pid = 0x1001; + d->ts[d->ts_number_pids].stream_kind = P; + d->ts[d->ts_number_pids].number_substreams = 1; + d->ts[d->ts_number_pids].substream_type[0] = 0; d->ts_number_pids++; } } @@ -739,8 +777,10 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ) for ( ii = 0; ii < d->ts_number_pids; ii++ ) { - d->ts_buf[ii] = hb_buffer_init(d->packetsize); - d->ts_buf[ii]->size = 0; + d->ts[ii].buf = hb_buffer_init(d->packetsize); + d->ts[ii].extra_buf = hb_buffer_init(d->packetsize); + d->ts[ii].buf->size = 0; + d->ts[ii].extra_buf->size = 0; } return d; @@ -800,9 +840,9 @@ void hb_stream_close( hb_stream_t ** _d ) * of the media stream for HB. */ static void hb_stream_delete_entry(hb_stream_t *stream, int indx) { - if ( stream->ts_pids[indx] > 0 ) + if ( stream->ts[indx].pid > 0 ) { - stream->ts_pids[indx] = -stream->ts_pids[indx]; + stream->ts[indx].pid = -stream->ts[indx].pid; } } @@ -854,26 +894,21 @@ hb_title_t * hb_stream_title_scan(hb_stream_t *stream) { int i; - for (i=0; i < stream->ts_number_pids; i++) - { - hb_audio_t *audio = hb_ts_stream_set_audio_id_and_codec(stream, i); - if ( audio ) - { - hb_list_add( aTitle->list_audio, audio ); - } - } + hb_ts_stream_set_audio_list(aTitle->list_audio, stream); // make sure we're grabbing the PCR PID if ( index_of_pid( stream, stream->pmt_info.PCR_PID ) < 0 ) { - stream->ts_pids[stream->ts_number_pids] = stream->pmt_info.PCR_PID; - stream->ts_stream_kind[stream->ts_number_pids] = P; + stream->ts[stream->ts_number_pids].pid = stream->pmt_info.PCR_PID; + stream->ts[stream->ts_number_pids].stream_kind = P; + stream->ts[stream->ts_number_pids].number_substreams = 1; + stream->ts[stream->ts_number_pids].substream_type[0] = 0; stream->ts_number_pids++; } for (i = 0; i < stream->ts_number_pids; i++) { - kind_t kind = stream->ts_stream_kind[i]; + kind_t kind = stream->ts[i].stream_kind; if ( kind == N || kind == U ) { @@ -889,9 +924,11 @@ hb_title_t * hb_stream_title_scan(hb_stream_t *stream) return NULL; } - aTitle->video_id = stream->ts_pids[idx]; - aTitle->video_codec = st2codec[stream->ts_stream_type[idx]].codec; - aTitle->video_codec_param = st2codec[stream->ts_stream_type[idx]].codec_param; + stream->ts[idx].number_substreams = 1; + stream->ts[idx].substream_type[0] = 0; + aTitle->video_id = stream->ts[idx].pid; + aTitle->video_codec = st2codec[stream->ts[idx].stream_type].codec; + aTitle->video_codec_param = st2codec[stream->ts[idx].stream_type].codec_param; aTitle->demuxer = HB_MPEG2_TS_DEMUXER; if ( ( stream->ts_flags & TS_HAS_PCR ) == 0 ) @@ -981,7 +1018,7 @@ static int isIframe( hb_stream_t *stream, const uint8_t *buf, int adapt_len ) uint32_t strid = 0; - if ( stream->ts_stream_type[0] <= 2 ) + if ( stream->ts[0].stream_type <= 2 ) { // This section of the code handles MPEG-1 and MPEG-2 video streams for (i = 13 + adapt_len; i < 188; i++) @@ -1015,7 +1052,7 @@ static int isIframe( hb_stream_t *stream, const uint8_t *buf, int adapt_len ) // didn't find an I-frame return 0; } - if ( stream->ts_stream_type[0] == 0x1b ) + if ( stream->ts[0].stream_type == 0x1b ) { // we have an h.264 stream for (i = 13 + adapt_len; i < 188; i++) @@ -1033,7 +1070,7 @@ static int isIframe( hb_stream_t *stream, const uint8_t *buf, int adapt_len ) // didn't find an I-frame return 0; } - if ( stream->ts_stream_type[0] == 0xea ) + if ( stream->ts[0].stream_type == 0xea ) { // we have an vc1 stream for (i = 13 + adapt_len; i < 188; i++) @@ -1129,17 +1166,18 @@ static const uint8_t *hb_ts_stream_getPEStype(hb_stream_t *stream, uint32_t pid) static uint64_t hb_ps_stream_getVideoPTS(hb_stream_t *stream) { - hb_buffer_t *buf = hb_buffer_init(HB_DVD_READ_BUFFER_SIZE); + hb_buffer_t *buf; hb_list_t *list = hb_list_init(); // how many blocks we read while searching for a video PES header int blksleft = 1024; uint64_t pts = 0; - while (--blksleft >= 0 && hb_stream_read(stream, buf) == 1) + while (--blksleft >= 0 && (buf = hb_stream_read(stream)) != NULL) { hb_buffer_t *es; - // 'buf' contains an MPEG2 PACK - get a list of all it's elementary streams + // 'buf' contains an MPEG2 PACK - get a list of all it's + // elementary streams hb_demux_ps( buf, list, 0 ); while ( ( es = hb_list_item( list, 0 ) ) ) @@ -1160,7 +1198,6 @@ static uint64_t hb_ps_stream_getVideoPTS(hb_stream_t *stream) } } hb_list_empty( &list ); - hb_buffer_close(&buf); return pts; } @@ -1208,7 +1245,7 @@ static struct pts_pos hb_sample_pts(hb_stream_t *stream, uint64_t fpos) const uint8_t *buf; fseeko( stream->file_handle, fpos, SEEK_SET ); align_to_next_packet( stream ); - int pid = stream->ts_pids[index_of_video(stream)]; + int pid = stream->ts[index_of_video(stream)].pid; buf = hb_ts_stream_getPEStype( stream, pid ); if ( buf == NULL ) { @@ -1327,17 +1364,20 @@ static void hb_stream_duration(hb_stream_t *stream, hb_title_t *inTitle) *********************************************************************** * **********************************************************************/ -int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) +hb_buffer_t * hb_stream_read( hb_stream_t * src_stream ) { if ( src_stream->hb_stream_type == ffmpeg ) { - return ffmpeg_read( src_stream, b ); + return ffmpeg_read( src_stream ); } if ( src_stream->hb_stream_type == dvd_program ) { + hb_buffer_t *b = hb_buffer_init(HB_DVD_READ_BUFFER_SIZE); size_t amt_read = fread(b->data, HB_DVD_READ_BUFFER_SIZE, 1, src_stream->file_handle); - return (amt_read > 0); + if (amt_read <= 0) + hb_buffer_close( &b ); + return b; } if ( src_stream->hb_stream_type == program ) { @@ -1345,9 +1385,6 @@ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) // currently positioned at the start of a pack so read up to but // not including the start of the next, expanding the buffer // as necessary. - uint8_t *cp = b->data; - uint8_t *ep = cp + b->alloc; - uint32_t strt_code = -1; int c; // consume the first byte of the initial pack so we don't match on @@ -1355,6 +1392,11 @@ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) if ( ( c = getc( src_stream->file_handle ) ) == EOF ) return 0; + hb_buffer_t *b = hb_buffer_init(HB_DVD_READ_BUFFER_SIZE); + uint8_t *cp = b->data; + uint8_t *ep = cp + b->alloc; + uint32_t strt_code = -1; + *cp++ = c; flockfile( src_stream->file_handle ); @@ -1416,9 +1458,9 @@ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b ) // Only 3 of the 4 bytes read were added to the buffer. b->size -= 3; } - return 1; + return b; } - return hb_ts_stream_decode( src_stream, b ); + return hb_ts_stream_decode( src_stream ); } void ffmpeg_flush_stream_buffers( hb_stream_t *stream ) @@ -1555,7 +1597,36 @@ int hb_stream_seek_ts( hb_stream_t * stream, int64_t ts ) return -1; } -static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) +static const char *stream_type_name (uint32_t reg_desc, uint8_t stream_type) +{ + if ( reg_desc == STR4_TO_UINT32("HDMV") ) + { + // Names for streams we know about. + switch ( stream_type ) + { + case 0x80: + return "BD LPCM"; + + case 0x83: + return "TrueHD"; + + case 0x84: + return "E-AC3"; + + case 0x85: + return "DTS-HD HRA"; + + case 0x86: + return "DTS-HD MA"; + + default: + break; + } + } + return st2codec[stream_type].name ? st2codec[stream_type].name : "Unknown"; +} + +static void set_ts_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) { /* XXX * This is a duplicate of code in dvd.c - it should get factored out @@ -1566,16 +1637,63 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) const char *codec_name; AVCodecContext *cc; - if ( audio->config.in.codec == HB_ACODEC_FFMPEG && + // Names for streams we know about. + if ( audio->config.in.stream_type == 0x80 && + audio->config.in.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // LPCM audio in bluray have an stype of 0x80 + codec_name = "BD LPCM"; + } + else if ( audio->config.in.stream_type == 0x83 && + audio->config.in.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // This is an interleaved TrueHD/AC-3 stream and the esid of + // the AC-3 is 0x76 + if (audio->config.in.substream_type == HB_SUBSTREAM_BD_AC3) + codec_name = "AC3"; + else + codec_name = "TrueHD"; + } + else if ( audio->config.in.stream_type == 0x86 && + audio->config.in.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // This is an interleaved DTS-HD MA/DTS stream and the + // esid of the DTS is 0x71 + if (audio->config.in.substream_type == HB_SUBSTREAM_BD_DTS) + codec_name = "DTS"; + else + codec_name = "DTS-HD MA"; + } + else if ( audio->config.in.stream_type == 0x85 && + audio->config.in.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // DTS-HD HRA audio in bluray has an stype of 0x85 + // which conflicts with ATSC Program ID + // To distinguish, Bluray streams have a reg_desc of HDMV + // This is an interleaved DTS-HD HRA/DTS stream and the + // esid of the DTS is 0x71 + if (audio->config.in.substream_type == HB_SUBSTREAM_BD_DTS) + codec_name = "DTS"; + else + codec_name = "DTS-HD HRA"; + } + else if ( audio->config.in.stream_type == 0x84 && + audio->config.in.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // EAC3 audio in bluray has an stype of 0x84 + // which conflicts with SDDS + // To distinguish, Bluray streams have a reg_desc of HDMV + codec_name = "E-AC3"; + } + // For streams demuxed and decoded by ffmpeg, we have a cached context. + // Use it to get the name and profile information. Obtaining + // the profile requires that ffmpeg has already probed the stream. + else if ( audio->config.in.codec == HB_ACODEC_FFMPEG && ( cc = hb_ffmpeg_context( audio->config.in.codec_param ) ) && avcodec_find_decoder( cc->codec_id ) ) { AVCodec *codec = avcodec_find_decoder( cc->codec_id ); codec_name = codec->name; - if ( !strcmp( codec_name, "DCA" ) ) - { - codec_name = "DTS"; - } const char *profile_name; profile_name = av_get_profile_name( codec, cc->profile ); @@ -1584,6 +1702,13 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) codec_name = profile_name; } } + else if ( st2codec[audio->config.in.stream_type].kind == A ) + { + codec_name = stream_type_name(audio->config.in.reg_desc, + audio->config.in.stream_type); + } + // For streams demuxed by us and decoded by ffmpeg, we can lookup the + // decoder name. else if ( audio->config.in.codec == HB_ACODEC_MPGA && avcodec_find_decoder( audio->config.in.codec_param ) ) { @@ -1595,7 +1720,7 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) audio->config.in.codec == HB_ACODEC_DCA ? "DTS" : audio->config.in.codec == HB_ACODEC_MPGA ? "MPEG" : audio->config.in.codec == HB_ACODEC_LPCM ? "LPCM" : - audio->config.in.codec == HB_ACODEC_FFMPEG ? "FFMPEG" : + audio->config.in.codec == HB_ACODEC_FFMPEG ? "FFmpeg" : "Unknown"; } snprintf( audio->config.lang.description, @@ -1620,160 +1745,244 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) "%s", lang->iso639_2); } -static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream, - int idx) +static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) { - off_t cur_pos = ftello(stream->file_handle); - hb_audio_t *audio = NULL; - const uint8_t *buf; - kind_t kind; - uint8_t stype = 0; + /* XXX + * This is a duplicate of code in dvd.c - it should get factored out + * into a common routine. We probably should only be putting the lang + * code or a lang pointer into the audio config & let the common description + * formatting routine in scan.c do all the stuff below. + */ + const char *codec_name; + AVCodecContext *cc; - kind = stream->ts_stream_kind[idx]; + // For streams demuxed and decoded by ffmpeg, we have a cached context. + // Use it to get the name and profile information. Obtaining + // the profile requires that ffmpeg has already probed the stream. + if ( audio->config.in.codec == HB_ACODEC_FFMPEG && + ( cc = hb_ffmpeg_context( audio->config.in.codec_param ) ) && + avcodec_find_decoder( cc->codec_id ) ) + { + AVCodec *codec = avcodec_find_decoder( cc->codec_id ); + codec_name = codec->name; - if ( kind != A && kind != U && kind != N ) + const char *profile_name; + profile_name = av_get_profile_name( codec, cc->profile ); + if ( profile_name ) + { + codec_name = profile_name; + } + } + // For streams demuxed by us and decoded by ffmpeg, we can lookup the + // decoder name. + else if ( audio->config.in.codec == HB_ACODEC_MPGA && + avcodec_find_decoder( audio->config.in.codec_param ) ) { - // Not audio - return NULL; + codec_name = avcodec_find_decoder( audio->config.in.codec_param )->name; } - stype = stream->ts_stream_type[idx]; + else + { + codec_name = audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" : + audio->config.in.codec == HB_ACODEC_DCA ? "DTS" : + audio->config.in.codec == HB_ACODEC_MPGA ? "MPEG" : + audio->config.in.codec == HB_ACODEC_LPCM ? "LPCM" : + audio->config.in.codec == HB_ACODEC_FFMPEG ? "FFmpeg" : + "Unknown"; + } + snprintf( audio->config.lang.description, + sizeof( audio->config.lang.description ), "%s (%s)", + strlen(lang->native_name) ? lang->native_name : lang->eng_name, + codec_name ); - fseeko(stream->file_handle, 0, SEEK_SET); - align_to_next_packet(stream); + if (audio->config.in.codec == HB_ACODEC_FFMPEG) + { + 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) ); + } + + snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s", + strlen(lang->native_name) ? lang->native_name : lang->eng_name ); + snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ), + "%s", lang->iso639_2); +} - buf = hb_ts_stream_getPEStype(stream, stream->ts_pids[idx]); +static void add_audio(int track, hb_list_t *list_audio, hb_stream_t *stream, int substream_type, uint32_t codec, uint32_t codec_param ) +{ + hb_audio_t *audio; + hb_ts_stream_t *ts = &stream->ts[track]; - /* check that we found a PES header */ - if (buf && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) + audio = calloc( sizeof( hb_audio_t ), 1 ); + + audio->id = (substream_type << 16) | ts->pid; + audio->config.in.reg_desc = stream->pmt_info.reg_desc; + audio->config.in.stream_type = ts->stream_type; + audio->config.in.substream_type = substream_type; + + audio->config.in.codec = codec; + audio->config.in.codec_param = codec_param; + + set_ts_audio_description( audio, + lang_for_code( ts->a52_info.lang_code ) ); + + hb_log("transport stream pid 0x%x (type 0x%x substream 0x%x) audio 0x%x", + ts->pid, ts->stream_type, substream_type, audio->id); + + audio->config.in.track = track; + hb_list_add( list_audio, audio ); +} + +static void hb_ts_stream_set_audio_list( + hb_list_t *list_audio, + hb_stream_t *stream) +{ + off_t cur_pos; + const uint8_t *buf; + int i; + + cur_pos = ftello(stream->file_handle); + for ( i = 0; i < stream->ts_number_pids; i++ ) { - // 0xbd ("private stream 1") is the normal container for non-ISO - // media - AC3/DCA/PCM/etc. - if ( buf[3] == 0xbd ) + stream->ts[i].substream_type[0] = 0; + stream->ts[i].number_substreams = 1; + + if ( stream->ts[i].stream_type == 0x80 && + stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) { - if ( kind == U ) - { - // 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[idx] = 0x81; - kind = A; - } - if ( stype == 0x80 && - stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) - { - // LPCM audio in bluray have an stype of 0x80 - // 0x80 is used for other DigiCipher normally - // To distinguish, Bluray streams have a reg_desc of HDMV - kind = A; - } + // LPCM audio in bluray have an stype of 0x80 + // 0x80 is used for other DigiCipher normally + // To distinguish, Bluray streams have a reg_desc of HDMV + stream->ts[i].stream_kind = A; + add_audio(i, list_audio, stream, 0, + HB_ACODEC_MPGA, CODEC_ID_PCM_BLURAY ); + continue; } - else if ( buf[3] == 0xfd ) - { - // 0xfd indicates an extended stream id (ISO 13818-1(2007)). - // the blu ray consortium apparently forgot to read the portion - // of the MPEG spec that says one PID should map to one media - // stream and multiplexed multiple types of audio into one PID - // using the extended stream identifier of the PES header to - // distinguish them. So we have to check if that's happening and - // if so tell the runtime what esid we want. - if ( st2codec[stype].kind == A && stype == 0x83 && - stream->ts_format_id[idx] == TS_FORMAT_ID_AC3 ) - { - // This is an interleaved TrueHD/AC-3 stream and the esid of - // the AC-3 is 0x76 - stream->ts_multiplexed[idx] = 0x76; - stype = 0x81; - stream->ts_stream_type[idx] = 0x81; - kind = A; - } - if ( st2codec[stype].kind == A && stype == 0x86 ) - { - // This is an interleaved DTS-HD MA/DTS stream and the esid of - // the DTS is 0x71 - stream->ts_multiplexed[idx] = 0x71; - stype = 0x82; - stream->ts_stream_type[idx] = 0x82; - kind = A; - } - if ( stype == 0x85 && - stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) - { - // DTS-HD HRA audio in bluray has an stype of 0x85 - // which conflicts with ATSC Program ID - // To distinguish, Bluray streams have a reg_desc of HDMV - // This is an interleaved DTS-HD HRA/DTS stream and the esid of - // the DTS is 0x71 - stream->ts_multiplexed[idx] = 0x71; - stype = 0x82; - stream->ts_stream_type[idx] = 0x82; - kind = A; - } - if ( stype == 0x84 && - stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) - { - // EAC3 audio in bluray has an stype of 0x84 - // which conflicts with SDDS - // To distinguish, Bluray streams have a reg_desc of HDMV - stype = 0x87; - stream->ts_stream_type[idx] = 0x87; - kind = A; - } + + // The blu ray consortium apparently forgot to read the portion + // of the MPEG spec that says one PID should map to one media + // stream and multiplexed multiple types of audio into one PID + // using the extended stream identifier of the PES header to + // distinguish them. So we have to check if that's happening and + // if so tell the runtime what esid we want. + if ( stream->ts[i].stream_type == 0x83 && + stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // This is an interleaved TrueHD/AC-3 stream and the esid of + // the AC-3 is 0x76 + stream->ts[i].stream_kind = A; + stream->ts[i].substream_type[0] = HB_SUBSTREAM_BD_AC3; + add_audio(i, list_audio, stream, HB_SUBSTREAM_BD_AC3, + HB_ACODEC_AC3, 0 ); + stream->ts[i].substream_type[1] = HB_SUBSTREAM_BD_TRUEHD; + add_audio(i, list_audio, stream, HB_SUBSTREAM_BD_TRUEHD, + HB_ACODEC_MPGA, CODEC_ID_TRUEHD ); + stream->ts[i].number_substreams = 2; + continue; } - else if ((buf[3] & 0xe0) == 0xc0) + if ( stream->ts[i].stream_type == 0x86 && + stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) + { + // This is an interleaved DTS-HD MA/DTS stream and the + // esid of the DTS is 0x71 + stream->ts[i].stream_kind = A; + stream->ts[i].substream_type[0] = HB_SUBSTREAM_BD_DTS; + add_audio(i, list_audio, stream, HB_SUBSTREAM_BD_DTS, + HB_ACODEC_DCA, 0 ); + stream->ts[i].substream_type[1] = 0; + add_audio(i, list_audio, stream, 0, HB_ACODEC_MPGA, CODEC_ID_DTS ); + stream->ts[i].number_substreams = 2; + continue; + } + if ( stream->ts[i].stream_type == 0x85 && + stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) { - // 0xC0 - 0xCF are the normal containers for ISO-standard - // media (mpeg2 audio and mpeg4 AAC). - if ( st2codec[stype].kind == U ) - { - // XXX assume unknown stream types are MPEG audio - stype = 0x03; - stream->ts_stream_type[idx] = 0x03; - kind = A; - } + // DTS-HD HRA audio in bluray has an stype of 0x85 + // which conflicts with ATSC Program ID + // To distinguish, Bluray streams have a reg_desc of HDMV + // This is an interleaved DTS-HD HRA/DTS stream and the + // esid of the DTS is 0x71 + stream->ts[i].stream_kind = A; + stream->ts[i].substream_type[0] = HB_SUBSTREAM_BD_DTS; + add_audio(i, list_audio, stream, HB_SUBSTREAM_BD_DTS, + HB_ACODEC_DCA, 0 ); + stream->ts[i].substream_type[1] = 0; + add_audio(i, list_audio, stream, 0, HB_ACODEC_MPGA, CODEC_ID_DTS ); + stream->ts[i].number_substreams = 2; + continue; } - else + if ( stream->ts[i].stream_type == 0x84 && + stream->pmt_info.reg_desc == STR4_TO_UINT32("HDMV") ) { - stype = 0; - kind = N; + // EAC3 audio in bluray has an stype of 0x84 + // which conflicts with SDDS + // To distinguish, Bluray streams have a reg_desc of HDMV + stream->ts[i].stream_kind = A; + add_audio(i, list_audio, stream, 0, HB_ACODEC_MPGA, CODEC_ID_EAC3 ); + continue; } - } - // 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 ( kind == A && st2codec[stype].codec ) - { - audio = calloc( sizeof( hb_audio_t ), 1 ); + if ( stream->ts[i].stream_kind == A ) + { + add_audio(i, list_audio, stream, 0, + st2codec[stream->ts[i].stream_type].codec, + st2codec[stream->ts[i].stream_type].codec_param ); + continue; + } - stream->ts_stream_kind[idx] = A; - audio->id = stream->ts_pids[idx]; - 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[idx].lang_code ) ); - hb_log("transport stream pid 0x%x (type 0x%x) may be %s audio (id 0x%x)", - stream->ts_pids[idx], - stype, st2codec[stype].name, audio->id); + if ( stream->ts[i].stream_kind != U ) + { + // Not audio + continue; + } - } - else - { - if ( buf ) + // If we get here, we have a stream type that we are not yet + // sure about. Probe some data to see if it looks like + // a known stream type. + fseeko(stream->file_handle, 0, SEEK_SET); + align_to_next_packet(stream); + + buf = hb_ts_stream_getPEStype(stream, stream->ts[i].pid); + + /* check that we found a PES header */ + if (buf && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) { - hb_log("transport stream pid 0x%x (type 0x%x, substream 0x%x) " - "isn't audio", stream->ts_pids[idx], - stream->ts_stream_type[idx], buf[3]); + // 0xbd ("private stream 1") is the normal container for non-ISO + // media - AC3/DCA/PCM/etc. + if ( buf[3] == 0xbd ) + { + // 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). + add_audio(i, list_audio, stream, 0, HB_ACODEC_AC3, 0 ); + } + else if ((buf[3] & 0xe0) == 0xc0) + { + // XXX assume unknown stream types are MPEG audio + // 0xC0 - 0xCF are the normal containers for ISO-standard + // media (mpeg2 audio and mpeg4 AAC). + add_audio(i, list_audio, stream, 0, + HB_ACODEC_MPGA, CODEC_ID_MP2 ); + } + else + { + hb_log("transport stream pid 0x%x (type 0x%x, substream 0x%x) " + "isn't audio", stream->ts[i].pid, + stream->ts[i].stream_type, buf[3]); + } } else { hb_log("transport stream pid 0x%x (type 0x%x) isn't audio", - stream->ts_pids[idx], - stream->ts_stream_type[idx]); + stream->ts[i].pid, + stream->ts[i].stream_type); } - } - fseeko(stream->file_handle, cur_pos, SEEK_SET); - return audio; + fseeko(stream->file_handle, cur_pos, SEEK_SET); + } } static void add_audio_to_title(hb_title_t *title, int id) @@ -1812,7 +2021,7 @@ static void add_audio_to_title(hb_title_t *title, int id) static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title) { off_t cur_pos = ftello(stream->file_handle); - hb_buffer_t *buf = hb_buffer_init(HB_DVD_READ_BUFFER_SIZE); + hb_buffer_t *buf; hb_list_t *list = hb_list_init(); // how many blocks we read while searching for audio streams int blksleft = 4096; @@ -1826,11 +2035,12 @@ static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title) // audio at the beginning (particularly for vobs). hb_stream_seek(stream, 0.2f); - while (--blksleft >= 0 && hb_stream_read(stream, buf) == 1) + while (--blksleft >= 0 && (buf = hb_stream_read(stream)) != NULL) { hb_buffer_t *es; - // 'buf' contains an MPEG2 PACK - get a list of all it's elementary streams + // 'buf' contains an MPEG2 PACK - get a list of all it's + // elementary streams hb_demux_ps( buf, list, 0 ); while ( ( es = hb_list_item( list, 0 ) ) ) @@ -1853,7 +2063,6 @@ static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title) } } hb_list_empty( &list ); - hb_buffer_close(&buf); fseeko(stream->file_handle, cur_pos, SEEK_SET); } @@ -1869,8 +2078,10 @@ static void hb_ts_stream_init(hb_stream_t *stream) for (i=0; i < kMaxNumberDecodeStreams; i++) { - stream->ts_streamcont[i] = -1; - stream-> ts_pids[i] = -1; + stream->ts[i].continuity = -1; + stream->ts[i].pid = -1; + stream->ts[i].number_substreams = 1; + stream->ts[i].substream_type[0] = 0; } stream->ts_packet = malloc( stream->packetsize ); @@ -1880,8 +2091,10 @@ static void hb_ts_stream_init(hb_stream_t *stream) for (i = 0; i < stream->ts_number_pids; i++) { // demuxing buffer for TS to PS conversion - stream->ts_buf[i] = hb_buffer_init(stream->packetsize); - stream->ts_buf[i]->size = 0; + stream->ts[i].buf = hb_buffer_init(stream->packetsize); + stream->ts[i].extra_buf = hb_buffer_init(stream->packetsize); + stream->ts[i].buf->size = 0; + stream->ts[i].extra_buf->size = 0; } } @@ -2003,20 +2216,20 @@ static void decode_element_descriptors(hb_stream_t* stream, int esindx, switch (dp[0]) { case 5: // Registration descriptor - stream->ts_format_id[esindx] = (dp[2] << 24) | (dp[3] << 16) | + stream->ts[esindx].format_id = (dp[2] << 24) | (dp[3] << 16) | (dp[4] << 8) | dp[5]; break; case 10: // ISO_639_language descriptor - stream->a52_info[esindx].lang_code = lang_to_code(lang_for_code2((const char *)&dp[2])); + stream->ts[esindx].a52_info.lang_code = lang_to_code(lang_for_code2((const char *)&dp[2])); break; case 0x6a: // DVB AC-3 descriptor - stream->ts_stream_type[esindx] = 0x81; + stream->ts[esindx].stream_type = 0x81; break; case 0x7a: // DVB EAC-3 descriptor - stream->ts_stream_type[esindx] = 0x87; + stream->ts[esindx].stream_type = 0x87; break; default: @@ -2026,11 +2239,6 @@ static void decode_element_descriptors(hb_stream_t* stream, int esindx, } } -static const char *stream_type_name (uint8_t stream_type) -{ - return st2codec[stream_type].name? st2codec[stream_type].name : "Unknown"; -} - int decode_program_map(hb_stream_t* stream) { bitbuf_t bb; @@ -2113,14 +2321,16 @@ int decode_program_map(hb_stream_t* stream) i = stream->ts_number_pids; if (i < kMaxNumberDecodeStreams) { - stream->ts_pids[i] = elementary_PID; - stream->ts_stream_type[i] = stream_type; + stream->ts[i].pid = elementary_PID; + stream->ts[i].stream_type = stream_type; + stream->ts[i].number_substreams = 1; + stream->ts[i].substream_type[0] = 0; if (ES_info_length > 0) { decode_element_descriptors(stream, i, ES_info_buf, ES_info_length); } - stream->ts_stream_kind[i] = ts_stream_kind(stream, i); + stream->ts[i].stream_kind = ts_stream_kind(stream, i); ++stream->ts_number_pids; } } @@ -2380,40 +2590,42 @@ static void hb_ts_stream_find_pids(hb_stream_t *stream) int i; for (i=0; i < stream->ts_number_pids; i++) { - if ( stream->ts_stream_kind[i] == V ) + if ( stream->ts[i].stream_kind == V ) { hb_log( " 0x%x type %s (0x%x)", - stream->ts_pids[i], - stream_type_name(stream->ts_stream_type[i]), - stream->ts_stream_type[i]); + stream->ts[i].pid, + stream_type_name(stream->pmt_info.reg_desc, + stream->ts[i].stream_type), + stream->ts[i].stream_type); } } hb_log(" Audio PIDS : "); for (i = 0; i < stream->ts_number_pids; i++) { - if ( stream->ts_stream_kind[i] != V ) + if ( stream->ts[i].stream_kind != V ) { hb_log( " 0x%x type %s (0x%x)", - stream->ts_pids[i], - stream_type_name(stream->ts_stream_type[i]), - stream->ts_stream_type[i] ); + stream->ts[i].pid, + stream_type_name(stream->pmt_info.reg_desc, + stream->ts[i].stream_type), + stream->ts[i].stream_type ); } } } -static void fwrite64( hb_stream_t *stream, void *buf, int len ) +static void fwrite64( hb_buffer_t * buf, void *data, int len ) { if ( len > 0 ) { - int pos = stream->fwrite_buf->size; - if ( pos + len > stream->fwrite_buf->alloc ) + int pos = buf->size; + if ( pos + len > buf->alloc ) { - int size = MAX(stream->fwrite_buf->alloc * 2, pos + len); - hb_buffer_realloc(stream->fwrite_buf, size); + int size = MAX(buf->alloc * 2, pos + len); + hb_buffer_realloc(buf, size); } - memcpy( &(stream->fwrite_buf->data[pos]), buf, len ); - stream->fwrite_buf->size += len; + memcpy( &(buf->data[pos]), data, len ); + buf->size += len; } } @@ -2426,92 +2638,119 @@ static int64_t pes_timestamp( const uint8_t *pes ) return ts; } -static void generate_output_data(hb_stream_t *stream, int curstream) +static hb_buffer_t * generate_output_data(hb_stream_t *stream, int curstream) { - hb_buffer_t *buf = stream->fwrite_buf; - uint8_t *tdat = stream->ts_buf[curstream]->data; + hb_buffer_t *buf = NULL, *first = NULL; + int substream, i; - buf->id = stream->ts_pids[curstream]; - switch (stream->ts_stream_kind[curstream]) + for ( i = 0; i < stream->ts[curstream].number_substreams; i++ ) { - case A: - buf->type = AUDIO_BUF; - break; + substream = stream->ts[curstream].substream_type[i]; + if ( substream == 0 || + substream == stream->ts[curstream].current_substream ) + { + uint8_t *tdat = stream->ts[curstream].buf->data; + int hlen = tdat[8] + 9; + int size = stream->ts[curstream].buf->size - hlen; - case V: - buf->type = VIDEO_BUF; - break; + if ( size <= 0 ) + continue; - default: - buf->type = OTHER_BUF; - break; - } + if ( first == NULL ) + { + first = buf = hb_buffer_init( size ); + } + else + { + hb_buffer_t * tmp; + tmp = hb_buffer_init( size ); + buf->next = tmp; + buf = tmp; + } + buf->size = 0; - // check if this packet was referenced to an older pcr and if that - // pcr was significantly different than the one we're using now. - // (the reason for the uint cast on the pcr difference is that the - // difference is significant if it advanced by more than 200ms or if - // it went backwards by any amount. The negative numbers look like huge - // unsigned ints so the cast allows both conditions to be checked at once. - int bufpcr = stream->ts_buf[curstream]->cur; - int curpcr = stream->ts_pcr_out; - if ( bufpcr && bufpcr < curpcr && - (uint64_t)(stream->ts_pcrhist[curpcr & 3] - stream->ts_pcrhist[bufpcr & 3]) > 200*90LL ) - { - // we've sent up a new pcr but have a packet referenced to an - // old pcr and the difference was enough to trigger a discontinuity - // correction. smash the timestamps or we'll mess up the correction. - buf->start = -1; - buf->renderOffset = -1; - } - else - { - if ( stream->ts_pcr_out != stream->ts_pcr_in ) - { - // we have a new pcr - stream->ts_pcr_out = stream->ts_pcr_in; - buf->stop = stream->ts_pcr; - stream->ts_pcrhist[stream->ts_pcr_out & 3] = stream->ts_pcr; - } - else - { - buf->stop = -1; - } + buf->id = (substream << 16) | stream->ts[curstream].pid; + switch (stream->ts[curstream].stream_kind) + { + case A: + buf->type = AUDIO_BUF; + break; - // put the PTS & possible DTS into 'start' & 'renderOffset' then strip - // off the PES header. - if ( tdat[7] & 0xc0 ) - { - buf->start = pes_timestamp( tdat + 9 ); - buf->renderOffset = ( tdat[7] & 0x40 )? pes_timestamp( tdat + 14 ) : - buf->start; - } - else - { - buf->start = -1; - buf->renderOffset = -1; - } - } - int hlen = tdat[8] + 9; + case V: + buf->type = VIDEO_BUF; + break; + + default: + buf->type = OTHER_BUF; + break; + } + + // check if this packet was referenced to an older pcr and if that + // pcr was significantly different than the one we're using now. + // (the reason for the uint cast on the pcr difference is that the + // difference is significant if it advanced by more than 200ms or if + // it went backwards by any amount. The negative numbers look like huge + // unsigned ints so the cast allows both conditions to be checked at once. + int64_t bufpcr = stream->ts[curstream].buf->pcr; + int64_t curpcr = stream->ts_pcr_current; + if ( stream->ts[curstream].buf->cur < stream->ts_pcr_out && + bufpcr != -1 && curpcr != -1 && curpcr - bufpcr > 200*90LL ) + { + // we've sent up a new pcr but have a packet referenced to an + // old pcr and the difference was enough to trigger a discontinuity + // correction. smash the timestamps or we'll mess up the correction. + buf->start = -1; + buf->renderOffset = -1; + buf->stop = -1; + buf->pcr = -1; + } + else + { + if ( stream->ts_pcr_out != stream->ts_pcr_in ) + { + // we have a new pcr + stream->ts_pcr_out = stream->ts_pcr_in; + buf->pcr = stream->ts_pcr; + stream->ts_pcr_current = stream->ts_pcr; + } + else + { + buf->pcr = -1; + } - fwrite64( stream, tdat + hlen, stream->ts_pos[curstream] - hlen ); + // put the PTS & possible DTS into 'start' & 'renderOffset' then strip + // off the PES header. + if ( tdat[7] & 0xc0 ) + { + buf->start = pes_timestamp( tdat + 9 ); + buf->renderOffset = ( tdat[7] & 0x40 )? pes_timestamp( tdat + 14 ) : + buf->start; + } + else + { + buf->start = -1; + buf->renderOffset = -1; + } + } - stream->ts_pos[curstream] = 0; - stream->ts_buf[curstream]->size = 0; + fwrite64( buf, tdat + hlen, size ); + } + } + stream->ts[curstream].buf->size = 0; + return first; } static void hb_ts_stream_append_pkt(hb_stream_t *stream, int idx, const uint8_t *buf, int len) { - if (stream->ts_pos[idx] + len > stream->ts_buf[idx]->alloc) + if (stream->ts[idx].buf->size + len > stream->ts[idx].buf->alloc) { int size; - size = MAX(stream->ts_buf[idx]->alloc * 2, stream->ts_pos[idx] + len); - hb_buffer_realloc(stream->ts_buf[idx], size); + size = MAX(stream->ts[idx].buf->alloc * 2, stream->ts[idx].buf->size + len); + hb_buffer_realloc(stream->ts[idx].buf, size); } - memcpy(stream->ts_buf[idx]->data + stream->ts_pos[idx], buf, len); - stream->ts_pos[idx] += len; - stream->ts_buf[idx]->size += len; + memcpy(stream->ts[idx].buf->data + stream->ts[idx].buf->size, buf, len); + stream->ts[idx].buf->size += len; } /*********************************************************************** @@ -2519,18 +2758,15 @@ static void hb_ts_stream_append_pkt(hb_stream_t *stream, int idx, const uint8_t *********************************************************************** * **********************************************************************/ -int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obuf ) +hb_buffer_t * hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt ) { /* * stash the output buffer pointer in our stream so we don't have to * pass it & its original value to everything we call. */ - obuf->size = 0; - stream->fwrite_buf = obuf; - int video_index = index_of_video(stream); - int curstream; + hb_buffer_t *buf; /* This next section validates the packet */ @@ -2538,7 +2774,7 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu int pid = ((pkt[1] & 0x1F) << 8) | pkt[2]; if ( ( curstream = index_of_pid( stream, pid ) ) < 0 ) { - return 0; + return NULL; } // Get error @@ -2546,7 +2782,7 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu if (errorbit) { ts_err( stream, curstream, "packet error bit set"); - return 0; + return NULL; } // Get adaption header info @@ -2555,7 +2791,7 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu if (adaption == 0) { ts_err( stream, curstream, "adaptation code 0"); - return 0; + return NULL; } else if (adaption == 0x2) adapt_len = 184; @@ -2565,7 +2801,7 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu if (adapt_len > 184) { ts_err( stream, curstream, "invalid adapt len %d", adapt_len); - return 0; + return NULL; } } @@ -2595,10 +2831,9 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu // Unfortunately the HD Home Run appears to null out the PCR so if // we didn't detect a PCR during scan keep going and we'll use // the video stream DTS for the PCR. - if ( !stream->ts_found_pcr && ( stream->ts_flags & TS_HAS_PCR ) ) { - return 0; + return NULL; } // Get continuity @@ -2610,7 +2845,7 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu if ( (adaption & 0x01) != 0 ) { int continuity = (pkt[3] & 0xF); - if ( continuity == stream->ts_streamcont[curstream] ) + if ( continuity == stream->ts[curstream].continuity ) { // Spliced transport streams can have duplicate // continuity counts at the splice boundary. @@ -2629,50 +2864,60 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu { memset(&summary[2], 0, 6); } - if ( memcmp( summary, stream->ts_pkt_summary[curstream], 8 ) == 0 ) + if ( memcmp( summary, stream->ts[curstream].pkt_summary, 8 ) == 0 ) { // we got a duplicate packet (usually used to introduce // a PCR when one is needed). The only thing that can // change in the dup is the PCR which we grabbed above // so ignore the rest. - return 0; + return NULL; } } - if ( !start && (stream->ts_streamcont[curstream] != -1) && - !stream->ts_skipbad[curstream] && - (continuity != ( (stream->ts_streamcont[curstream] + 1) & 0xf ) ) ) + if ( !start && (stream->ts[curstream].continuity != -1) && + !stream->ts[curstream].skipbad && + (continuity != ( (stream->ts[curstream].continuity + 1) & 0xf ) ) ) { - ts_err( stream, curstream, "continuity error: got %d expected %d", + ts_err( stream, curstream, "continuity error: got %d expected %d", (int)continuity, - (stream->ts_streamcont[curstream] + 1) & 0xf ); - stream->ts_streamcont[curstream] = continuity; - return 0; + (stream->ts[curstream].continuity + 1) & 0xf ); + stream->ts[curstream].continuity = continuity; + return NULL; } - stream->ts_streamcont[curstream] = continuity; + stream->ts[curstream].continuity = continuity; // Save a summary of this packet for later duplicate // testing. The summary includes some header information // and payload bytes. Should be enough to detect // non-duplicates. - stream->ts_pkt_summary[curstream][0] = adaption; - stream->ts_pkt_summary[curstream][1] = adapt_len; + stream->ts[curstream].pkt_summary[0] = adaption; + stream->ts[curstream].pkt_summary[1] = adapt_len; if (adapt_len + 4 + 6 + 9 <= 188) { - memcpy(&stream->ts_pkt_summary[curstream][2], + memcpy(&stream->ts[curstream].pkt_summary[2], pkt+4+adapt_len+9, 6); } else { - memset(&stream->ts_pkt_summary[curstream][2], 0, 6); + memset(&stream->ts[curstream].pkt_summary[2], 0, 6); } } /* If we get here the packet is valid - process its data */ + if ( start ) { // Found a random access point (now we can start a frame/audio packet..) + // PES must begin with an mpeg start code + const uint8_t *pes = pkt + adapt_len + 4; + if ( pes[0] != 0x00 || pes[1] != 0x00 || pes[2] != 0x01 ) + { + ts_err( stream, curstream, "missing start code" ); + stream->ts[curstream].skipbad = 1; + return NULL; + } + if ( stream->need_keyframe ) { // we're looking for the first video frame because we're @@ -2683,16 +2928,16 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu // but we'll only wait 255 video frames for an I frame. if ( curstream != video_index || ++stream->need_keyframe ) { - return 0; + return NULL; } } stream->need_keyframe = 0; } // If we were skipping a bad packet, start fresh on this new PES packet.. - if (stream->ts_skipbad[curstream] == 1) + if (stream->ts[curstream].skipbad == 1) { - stream->ts_skipbad[curstream] = 0; + stream->ts[curstream].skipbad = 0; } if ( curstream == video_index ) @@ -2708,7 +2953,7 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu if ( pes[0] != 0x00 || pes[1] != 0x00 || pes[2] != 0x01 || ( pes[7] >> 6 ) == 0 ) { - return 0; + return NULL; } // if we have a dts use it otherwise use the pts stream->ts_pcr = pes_timestamp( pes + ( pes[7] & 0x40?14:9 ) ); @@ -2716,69 +2961,78 @@ int hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt, hb_buffer_t *obu } } - // if this is a multiplexed stream make sure this is the - // substream we want. - if ( stream->ts_multiplexed[curstream] ) + // the last byte of the header is the extension id. see if + // this could be a multiplexed stream + int substream = 0; + if ( pes[3] == 0xfd ) { - // PES must begin with an mpeg start code & contain - // a DTS or PTS. - const uint8_t *pes = pkt + adapt_len + 4; - if ( pes[0] != 0x00 || pes[1] != 0x00 || pes[2] != 0x01 || - pes[3] != 0xfd ) + int out_substream = 0; + substream = pes[pes[8]+8]; + out_substream = find_substream( &stream->ts[curstream], substream ); + if ( out_substream < 0 ) { - stream->ts_skipbad[curstream] = 1; - return 0; - } - // the last byte of the header is the extension id. see if - // it's the one we want. - if ( pes[pes[8]+8] != stream->ts_multiplexed[curstream] ) - { - stream->ts_skipbad[curstream] = 1; - return 0; + buf = NULL; + if ( stream->ts[curstream].buf->size ) + buf = generate_output_data(stream, curstream); + + stream->ts[curstream].skipbad = 1; + return buf; } } // If we have some data already on this stream, turn it into // a program stream packet. Then add the payload for this // packet to the current pid's buffer. - if ( stream->ts_pos[curstream] ) + if ( stream->ts[curstream].buf->size ) { // we have to ship the old packet before updating the pcr // since the packet we've been accumulating is referenced // to the old pcr. - generate_output_data(stream, curstream); + buf = generate_output_data(stream, curstream); - // remember the pcr that was in effect when we started - // this packet. - stream->ts_buf[curstream]->cur = stream->ts_pcr_in; - hb_ts_stream_append_pkt(stream, curstream, pkt + 4 + adapt_len, - 184 - adapt_len); - return 1; + if ( buf ) + { + // Output data is ready. + stream->ts[curstream].current_substream = substream; + + // remember the pcr that was in effect when we started + // this packet. + stream->ts[curstream].buf->cur = stream->ts_pcr_in; + stream->ts[curstream].buf->pcr = stream->ts_pcr; + hb_ts_stream_append_pkt(stream, curstream, pkt + 4 + adapt_len, + 184 - adapt_len); + return buf; + } } // remember the pcr that was in effect when we started this packet. - stream->ts_buf[curstream]->cur = stream->ts_pcr_in; + stream->ts[curstream].buf->cur = stream->ts_pcr_in; + stream->ts[curstream].buf->pcr = stream->ts_pcr; + stream->ts[curstream].current_substream = substream; } // Add the payload for this packet to the current buffer - if (!stream->ts_skipbad[curstream] && (184 - adapt_len) > 0) + if (!stream->ts[curstream].skipbad && (184 - adapt_len) > 0) { hb_ts_stream_append_pkt(stream, curstream, pkt + 4 + adapt_len, 184 - adapt_len); // see if we've hit the end of this PES packet - const uint8_t *pes = stream->ts_buf[curstream]->data; + const uint8_t *pes = stream->ts[curstream].buf->data; int len = ( pes[4] << 8 ) + pes[5] + 6; - if ( len > 6 && stream->ts_pos[curstream] == len && + if ( len > 6 && stream->ts[curstream].buf->size == len && pes[0] == 0x00 && pes[1] == 0x00 && pes[2] == 0x01 ) { - generate_output_data(stream, curstream); - return 1; + buf = generate_output_data(stream, curstream); + if ( buf ) + return buf; } } - return 0; + return NULL; } -static int hb_ts_stream_decode( hb_stream_t *stream, hb_buffer_t *obuf ) +static hb_buffer_t * hb_ts_stream_decode( hb_stream_t *stream ) { + hb_buffer_t * b; + // spin until we get a packet of data from some stream or hit eof while ( 1 ) { @@ -2788,15 +3042,16 @@ static int hb_ts_stream_decode( hb_stream_t *stream, hb_buffer_t *obuf ) // end of file - we didn't finish filling our ps write buffer // so just discard the remainder (the partial buffer is useless) hb_log("hb_ts_stream_decode - eof"); - return 0; + return NULL; } - if (hb_ts_decode_pkt( stream, buf, obuf )) + b = hb_ts_decode_pkt( stream, buf ); + if ( b ) { - return 1; + return b; } } - return 0; + return NULL; } static void hb_ts_stream_reset(hb_stream_t *stream) @@ -2805,9 +3060,12 @@ static void hb_ts_stream_reset(hb_stream_t *stream) for (i=0; i < kMaxNumberDecodeStreams; i++) { - stream->ts_pos[i] = 0; - stream->ts_skipbad[i] = 1; - stream->ts_streamcont[i] = -1; + if ( stream->ts[i].buf ) + stream->ts[i].buf->size = 0; + if ( stream->ts[i].extra_buf ) + stream->ts[i].extra_buf->size = 0; + stream->ts[i].skipbad = 1; + stream->ts[i].continuity = -1; } stream->need_keyframe = 0; @@ -2815,7 +3073,8 @@ static void hb_ts_stream_reset(hb_stream_t *stream) stream->ts_found_pcr = 0; stream->ts_pcr_out = 0; stream->ts_pcr_in = 0; - stream->ts_pcr = 0; + stream->ts_pcr = -1; + stream->ts_pcr_current = -1; stream->frames = 0; stream->errors = 0; @@ -3455,9 +3714,11 @@ static int ffmpeg_is_keyframe( hb_stream_t *stream ) return ( stream->ffmpeg_pkt->flags & PKT_FLAG_KEY ); } -static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) +static hb_buffer_t * ffmpeg_read( hb_stream_t *stream ) { int err; + hb_buffer_t * buf; + again: if ( ( err = av_read_frame( stream->ffmpeg_ic, stream->ffmpeg_pkt )) < 0 ) { @@ -3472,7 +3733,24 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) // sizes for the null frames these require. if ( err != AVERROR_NOMEM || stream->ffmpeg_pkt->size >= 0 ) // eof - return 0; + return NULL; + } + if ( stream->ffmpeg_pkt->stream_index == stream->ffmpeg_video_id ) + { + if ( stream->need_keyframe ) + { + // we've just done a seek (generally for scan or live preview) and + // want to start at a keyframe. Some ffmpeg codecs seek to a key + // frame but most don't. So we spin until we either get a keyframe + // or we've looked through 50 video frames without finding one. + if ( ! ffmpeg_is_keyframe( stream ) && ++stream->need_keyframe < 50 ) + { + av_free_packet( stream->ffmpeg_pkt ); + goto again; + } + stream->need_keyframe = 0; + } + ++stream->frames; } if ( stream->ffmpeg_pkt->size <= 0 ) { @@ -3484,44 +3762,22 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) // one byte if we're given a zero or negative size. We don't know // if the pkt data points anywhere reasonable so we just stick a // byte of zero in our outbound buf. - buf->size = 1; + buf = hb_buffer_init( 1 ); *buf->data = 0; } else { - if ( stream->ffmpeg_pkt->size > buf->alloc ) + // sometimes we get absurd sizes from ffmpeg + if ( stream->ffmpeg_pkt->size >= (1 << 25) ) { - // sometimes we get absurd sizes from ffmpeg - if ( stream->ffmpeg_pkt->size >= (1 << 25) ) - { - hb_log( "ffmpeg_read: pkt too big: %d bytes", stream->ffmpeg_pkt->size ); - av_free_packet( stream->ffmpeg_pkt ); - return ffmpeg_read( stream, buf ); - } - // need to expand buffer - hb_buffer_realloc( buf, stream->ffmpeg_pkt->size ); + hb_log( "ffmpeg_read: pkt too big: %d bytes", stream->ffmpeg_pkt->size ); + av_free_packet( stream->ffmpeg_pkt ); + return ffmpeg_read( stream ); } + buf = hb_buffer_init( stream->ffmpeg_pkt->size ); memcpy( buf->data, stream->ffmpeg_pkt->data, stream->ffmpeg_pkt->size ); - buf->size = stream->ffmpeg_pkt->size; } buf->id = stream->ffmpeg_pkt->stream_index; - if ( buf->id == stream->ffmpeg_video_id ) - { - if ( stream->need_keyframe ) - { - // we've just done a seek (generally for scan or live preview) and - // want to start at a keyframe. Some ffmpeg codecs seek to a key - // frame but most don't. So we spin until we either get a keyframe - // or we've looked through 50 video frames without finding one. - if ( ! ffmpeg_is_keyframe( stream ) && ++stream->need_keyframe < 50 ) - { - av_free_packet( stream->ffmpeg_pkt ); - goto again; - } - stream->need_keyframe = 0; - } - ++stream->frames; - } // if we haven't done it already, compute a conversion factor to go // from the ffmpeg timebase for the stream to HB's 90KHz timebase. @@ -3560,7 +3816,28 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) * either field. This is not a problem because the SSA decoder can extract this * information from the packet payload itself. */ - enum CodecID ffmpeg_pkt_codec = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_id; + enum CodecID ffmpeg_pkt_codec; + enum AVMediaType codec_type; + ffmpeg_pkt_codec = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_id; + codec_type = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_type; + switch ( codec_type ) + { + case CODEC_TYPE_VIDEO: + buf->type = VIDEO_BUF; + break; + + case CODEC_TYPE_AUDIO: + buf->type = AUDIO_BUF; + break; + + case CODEC_TYPE_SUBTITLE: + buf->type = SUBTITLE_BUF; + break; + + default: + buf->type = OTHER_BUF; + break; + } if ( ffmpeg_pkt_codec == CODEC_ID_TEXT ) { int64_t ffmpeg_pkt_duration = stream->ffmpeg_pkt->convergence_duration; int64_t buf_duration = av_to_hb_pts( ffmpeg_pkt_duration, tsconv ); @@ -3573,14 +3850,15 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) } /* - * Check to see whether this video buffer is on a chapter + * Check to see whether this buffer is on a chapter * boundary, if so mark it as such in the buffer then advance * chapter_end to the end of the next chapter. * If there are no chapters, chapter_end is always initialized to INT64_MAX * (roughly 3 million years at our 90KHz clock rate) so the test * below handles both the chapters & no chapters case. */ - if ( buf->id == stream->ffmpeg_video_id && buf->start >= stream->chapter_end ) + if ( stream->ffmpeg_pkt->stream_index == stream->ffmpeg_video_id && + buf->start >= stream->chapter_end ) { hb_chapter_t *chapter = hb_list_item( stream->title->list_chapter, stream->chapter+1 ); @@ -3599,7 +3877,7 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) buf->new_chap = 0; } av_free_packet( stream->ffmpeg_pkt ); - return 1; + return buf; } static int ffmpeg_seek( hb_stream_t *stream, float frac ) |