st(0x1b, V, WORK_DECAVCODECV, CODEC_ID_H264, "H.264"),
- st(0x80, U, 0, 0, "DigiCipher II Video"),
+ //st(0x80, U, 0, 0, "DigiCipher II Video"),
se(0x81, A, HB_ACODEC_AC3, 0, "AC-3"),
se(0x82, A, HB_ACODEC_DCA, 0, "HDMV DTS"),
st(0x83, A, HB_ACODEC_LPCM, 0, "LPCM"),
uint8_t *fwrite_buf; /* PS buffer (set by hb_ts_stream_decode) */
uint8_t *fwrite_buf_orig; /* PS buffer start (set by hb_ts_stream_decode) */
+ uint8_t need_keyframe;
+
/*
* Stuff before this point is dynamic state updated as we read the
* stream. Stuff after this point is stream description state that
AVFormatContext *ffmpeg_ic;
AVPacket *ffmpeg_pkt;
double ffmpeg_tsconv[MAX_STREAMS];
+ uint8_t ffmpeg_video_id;
struct {
int lang_code;
// We need to drop the current decoder output and move
// forwards to the next transport stream packet.
hb_ts_stream_reset(src_stream);
+ src_stream->need_keyframe = ( f != 0 );
}
else if ( src_stream->hb_stream_type == program )
{
// Get pointer length - only valid in packets with a start flag
int pointer_len = 0;
- if (start && stream->pmt_info.reading)
- {
- // We just finished a bunch of packets - parse the program map details
- int decode_ok = 0;
- if (stream->pmt_info.tablebuf[0] == 0x02)
- decode_ok = decode_program_map(stream);
- free(stream->pmt_info.tablebuf);
- stream->pmt_info.tablebuf = NULL;
- stream->pmt_info.tablepos = 0;
- stream->pmt_info.reading = 0;
- if (decode_ok)
- return decode_ok;
- }
if (start)
{
memcpy(stream->pmt_info.tablebuf + stream->pmt_info.tablepos, buf + 4 + adapt_len + pointer_len, amount_to_copy);
stream->pmt_info.tablepos += amount_to_copy;
}
+ if (stream->pmt_info.tablepos > 3)
+ {
+ // We have enough to check the section length
+ int length;
+ length = ((stream->pmt_info.tablebuf[1] << 8) +
+ stream->pmt_info.tablebuf[2]) & 0xFFF;
+ if (stream->pmt_info.tablepos > length + 1)
+ {
+ // We just finished a bunch of packets - parse the program map details
+ int decode_ok = 0;
+ if (stream->pmt_info.tablebuf[0] == 0x02)
+ decode_ok = decode_program_map(stream);
+ free(stream->pmt_info.tablebuf);
+ stream->pmt_info.tablebuf = NULL;
+ stream->pmt_info.tablepos = 0;
+ stream->pmt_info.reading = 0;
+ if (decode_ok)
+ return decode_ok;
+ }
+
+ }
return 0;
}
for (;;)
{
const uint8_t *buf = next_packet( stream );
+
if ( buf == NULL )
{
hb_log("hb_ts_stream_find_pids - end of file");
// on the first pat entry for which we find a matching program map PID. The ideal solution would
// be to build a title choice popup from the PAT program number details and then select from
// their - but right now the API's not capable of that.
- if (pid == stream->pat_info[pat_index].program_map_PID)
+ if (stream->pat_info[pat_index].program_number != 0 &&
+ pid == stream->pat_info[pat_index].program_map_PID)
{
if (build_program_map(buf, stream) > 0)
break;
// h.264 IDR picture start
return 1;
+ if ( stream->packetsize == 192 )
+ {
+ // m2ts files have idr frames so keep looking for one
+ continue;
+ }
+
+ // h226 in ts files (ATSC or DVB video) often seem to be
+ // missing IDR frames so look for at least an I
if ( nal_type == 0x01 )
{
// h.264 slice: has to be start MB 0 & type I (2, 4, 7 or 9)
{
if ( !stream->ts_foundfirst[0] )
{
- if ( !isIframe( stream, buf, adapt_len ) )
+ if ( stream->need_keyframe )
{
- // didn't find an I frame
- continue;
+ if ( !isIframe( stream, buf, adapt_len ) )
+ {
+ // didn't find an I frame
+ continue;
+ }
+ stream->need_keyframe = 0;
}
stream->ts_foundfirst[0] = 1;
}
stream->frames = 0;
stream->errors = 0;
+ stream->need_keyframe = 0;
stream->last_error_frame = -10000;
stream->last_error_count = 0;
// indexed its stream so we need to remap them so they point
// to this stream.
ffmpeg_remap_stream( stream, title );
- ffmpeg_seek( stream, 0. );
av_log_set_level( AV_LOG_ERROR );
}
else
title->video_codec == 0 )
{
title->video_id = i;
+ stream->ffmpeg_video_id = i;
// We have to use the 'internal' avcodec decoder because
// it needs to share the codec context from this video
static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )
{
int err;
+ again:
if ( ( err = av_read_frame( stream->ffmpeg_ic, stream->ffmpeg_pkt )) < 0 )
{
// XXX the following conditional is to handle avi files that
{
if ( stream->ffmpeg_pkt->size > buf->alloc )
{
+ // 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 );
}
buf->size = stream->ffmpeg_pkt->size;
}
buf->id = stream->ffmpeg_pkt->stream_index;
+ if ( buf->id == stream->ffmpeg_video_id )
+ {
+ if ( stream->need_keyframe &&
+ stream->ffmpeg_ic->streams[stream->ffmpeg_video_id]->codec->codec_id ==
+ CODEC_ID_VC1 )
+ {
+ // XXX the VC1 codec doesn't seek to key frames so to get previews
+ // we do it ourselves here. The decoder gets messed up if it
+ // doesn't get a SEQ header first so we consider that to be a key frame.
+ uint8_t *pkt = stream->ffmpeg_pkt->data;
+ if ( pkt[0] || pkt[1] || pkt[2] != 1 || pkt[3] != 0x0f )
+ {
+ 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.
{
AVFormatContext *ic = stream->ffmpeg_ic;
int64_t pos = (double)ic->duration * (double)frac;
- av_seek_frame( ic, -1, pos, pos? 0 : AVSEEK_FLAG_BACKWARD );
+ if ( pos )
+ {
+ av_seek_frame( ic, -1, pos, 0 );
+ stream->need_keyframe = 1;
+ }
+ else
+ {
+ av_seek_frame( ic, -1, pos, AVSEEK_FLAG_BACKWARD );
+ }
return 1;
}