summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/ffmpeg/A06-h264-recovery-point.patch55
-rw-r--r--libhb/bd.c2
-rw-r--r--libhb/decavcodec.c27
-rw-r--r--libhb/internal.h1
-rw-r--r--libhb/scan.c31
-rw-r--r--libhb/stream.c128
6 files changed, 128 insertions, 116 deletions
diff --git a/contrib/ffmpeg/A06-h264-recovery-point.patch b/contrib/ffmpeg/A06-h264-recovery-point.patch
new file mode 100644
index 000000000..8b1531444
--- /dev/null
+++ b/contrib/ffmpeg/A06-h264-recovery-point.patch
@@ -0,0 +1,55 @@
+diff --git a/libavcodec/h264.c b/libavcodec/h264.c
+index d047448..e96a129 100644
+--- a/libavcodec/h264.c
++++ b/libavcodec/h264.c
+@@ -3654,9 +3654,18 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size){
+ if((err = decode_slice_header(hx, h)))
+ break;
+
++ if (h->sei_recovery_frame_cnt >= 0) {
++ h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) %
++ (1 << h->sps.log2_max_frame_num);
++ }
++
+ s->current_picture_ptr->key_frame |=
+- (hx->nal_unit_type == NAL_IDR_SLICE) ||
+- (h->sei_recovery_frame_cnt >= 0);
++ (hx->nal_unit_type == NAL_IDR_SLICE);
++
++ if (h->recovery_frame == h->frame_num) {
++ s->current_picture_ptr->key_frame |= 1;
++ h->recovery_frame = -1;
++ }
+
+ if (h->current_slice == 1) {
+ if(!(s->flags2 & CODEC_FLAG2_CHUNKS)) {
+diff --git a/libavcodec/h264.h b/libavcodec/h264.h
+index 122a54a..cd044b0 100644
+--- a/libavcodec/h264.h
++++ b/libavcodec/h264.h
+@@ -575,6 +575,13 @@ typedef struct H264Context{
+ * frames.
+ */
+ int sei_recovery_frame_cnt;
++ /**
++ * recovery_frame is the frame_num at which the next frame should
++ * be fully constructed.
++ *
++ * Set to -1 when not expecting a recovery point.
++ */
++ int recovery_frame;
+
+ int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag
+ int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag
+diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
+index 4f52bbe..8d3c40b 100644
+--- a/libavcodec/h264_sei.c
++++ b/libavcodec/h264_sei.c
+@@ -38,6 +38,7 @@ static const uint8_t sei_num_clock_ts_table[9]={
+ };
+
+ void ff_h264_reset_sei(H264Context *h) {
++ h->recovery_frame = -1;
+ h->sei_recovery_frame_cnt = -1;
+ h->sei_dpb_output_delay = 0;
+ h->sei_cpb_removal_delay = -1;
diff --git a/libhb/bd.c b/libhb/bd.c
index 3adf765a1..93ca20d02 100644
--- a/libhb/bd.c
+++ b/libhb/bd.c
@@ -529,6 +529,7 @@ int hb_bd_seek_pts( hb_bd_t * d, uint64_t pts )
{
bd_seek_time(d->bd, pts);
d->next_chap = bd_get_current_chapter( d->bd ) + 1;
+ hb_ts_stream_reset(d->stream);
return 1;
}
@@ -537,6 +538,7 @@ int hb_bd_seek_chapter( hb_bd_t * d, int c )
int64_t pos;
d->next_chap = c;
pos = bd_seek_chapter( d->bd, c - 1 );
+ hb_ts_stream_reset(d->stream);
return 1;
}
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index fcd3ce032..478934b3b 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -93,6 +93,7 @@ struct hb_work_private_s
struct SwsContext *sws_context; // if we have to rescale or convert color space
hb_downmix_t *downmix;
int cadence[12];
+ int wait_for_keyframe;
};
static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts );
@@ -170,6 +171,7 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
w->private_data = pv;
+ pv->wait_for_keyframe = 60;
pv->job = job;
if ( job )
pv->title = job->title;
@@ -702,8 +704,9 @@ static void checkCadence( int * cadence, uint16_t flags, int64_t start )
* until enough packets have been decoded so that the timestamps can be
* correctly rewritten, if this is necessary.
*/
-static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size, int sequence, int64_t pts, int64_t dts )
+static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequence, int64_t pts, int64_t dts )
{
+ hb_work_private_t *pv = w->private_data;
int got_picture, oldlevel = 0;
AVFrame frame;
AVPacket avp;
@@ -727,6 +730,23 @@ static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size, int sequ
{
av_log_set_level( oldlevel );
}
+ if( got_picture && pv->wait_for_keyframe > 0 )
+ {
+ // Libav is inconsistant about how it flags keyframes. For many
+ // codecs it simply sets frame.key_frame. But for others, it only
+ // sets frame.pict_type. And for yet others neither gets set at all
+ // (qtrle).
+ int key = frame.key_frame ||
+ ( w->codec_param != CODEC_ID_H264 &&
+ ( frame.pict_type == AV_PICTURE_TYPE_I ||
+ frame.pict_type == 0 ) );
+ if( !key )
+ {
+ pv->wait_for_keyframe--;
+ return 0;
+ }
+ pv->wait_for_keyframe = 0;
+ }
if( got_picture )
{
uint16_t flags = 0;
@@ -894,14 +914,14 @@ static void decodeVideo( hb_work_object_t *w, uint8_t *data, int size, int seque
if ( pout_len > 0 )
{
- decodeFrame( pv, pout, pout_len, sequence, parser_pts, parser_dts );
+ decodeFrame( w, pout, pout_len, sequence, parser_pts, parser_dts );
}
} while ( pos < size );
/* the stuff above flushed the parser, now flush the decoder */
if ( size <= 0 )
{
- while ( decodeFrame( pv, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE ) )
+ while ( decodeFrame( w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE ) )
{
}
flushDelayQueue( pv );
@@ -1303,6 +1323,7 @@ static void decavcodecvFlush( hb_work_object_t *w )
avcodec_flush_buffers( pv->context );
}
}
+ pv->wait_for_keyframe = 60;
}
hb_work_object_t hb_decavcodecv =
diff --git a/libhb/internal.h b/libhb/internal.h
index 2d137dde8..6f6420a56 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -265,7 +265,6 @@ 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_stream_recovery_count( hb_stream_t * );
hb_buffer_t * hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt );
diff --git a/libhb/scan.c b/libhb/scan.c
index 3582f7d64..73b39e376 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -569,25 +569,6 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
vid_decoder->flush( vid_decoder );
hb_buffer_t * vid_buf = NULL;
- int vidskip = 0;
-
- if ( title->flags & HBTF_NO_IDR )
- {
- // title doesn't have IDR frames so we decode but drop one second's
- // worth of frames to allow the decoder to converge.
- if ( ! title->rate_base )
- {
- vidskip = 30;
- }
- else
- {
- vidskip = (double)title->rate / (double)title->rate_base + 0.5;
- }
- // If it's a BD, we can relax this a bit. Since seeks will
- // at least get us to a recovery point.
- if (data->bd || title->type == HB_FF_STREAM_TYPE)
- vidskip = 2;
- }
for( j = 0; j < 10240 ; j++ )
{
@@ -626,9 +607,6 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
goto skip_preview;
}
- int count = hb_stream_recovery_count( data->stream );
- if ( count )
- vidskip = count - 1;
}
else
{
@@ -646,15 +624,6 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
if( buf_es->id == title->video_id && vid_buf == NULL )
{
vid_decoder->work( vid_decoder, &buf_es, &vid_buf );
- // we're dropping frames to get the video decoder in sync
- // when the video stream doesn't contain IDR frames
- while (vid_buf && --vidskip >= 0)
- {
- hb_buffer_t * next = vid_buf->next;
- vid_buf->next = NULL;
- hb_buffer_close( &vid_buf );
- vid_buf = next;
- }
}
else if( ! AllAudioOK( title ) )
{
diff --git a/libhb/stream.c b/libhb/stream.c
index d9252550d..f77e03c9a 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -149,7 +149,6 @@ struct hb_stream_s
int packetsize; /* Transport Stream packet size */
int 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 */
@@ -189,8 +188,6 @@ struct hb_stream_s
#define TS_HAS_PCR (1 << 0) // at least one PCR seen
#define TS_HAS_RAP (1 << 1) // Random Access Point bit seen
#define TS_HAS_RSEI (1 << 2) // "Restart point" SEI seen
- int recovery_frames;
-
char *path;
FILE *file_handle;
@@ -272,6 +269,7 @@ static int ffmpeg_seek( hb_stream_t *stream, float frac );
static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts );
static inline unsigned int bits_get(bitbuf_t *bb, int bits);
static inline void bits_init(bitbuf_t *bb, uint8_t* buf, int bufsize, int clear);
+static inline unsigned int bits_peek(bitbuf_t *bb, int bits);
static inline int bits_eob(bitbuf_t *bb);
static inline int bits_read_ue(bitbuf_t *bb );
static void pes_add_audio_to_title(hb_stream_t *s, int i, hb_title_t *t, int sort);
@@ -983,8 +981,13 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title )
// lot of data before finding the PCR.
if ( title->job )
{
+ /* BD has PCRs, but the BD index always points to a packet
+ * after a PCR packet, so we will not see the initial PCR
+ * after any seek. So don't set the flag that causes us
+ * to drop packets till we see a PCR. */
+ //d->ts_flags = TS_HAS_RAP | TS_HAS_PCR;
+
// BD PCR PID is specified to always be 0x1001
- d->ts_flags = TS_HAS_RAP | TS_HAS_PCR;
update_ts_streams( d, 0x1001, 0, -1, P, NULL );
}
@@ -1246,28 +1249,11 @@ static int isRecoveryPoint( const uint8_t *buf, int len )
break;
}
- if ( ii + size + 1 > nal_len )
- {
- // Is it an SEI recovery point?
- if ( type == 6 )
- {
- // Recovery point found, but can't parse the entire NAL.
- // So return an arbitrary recovery_frames count.
- recovery_frames = 3;
- }
- break;
- }
-
- // Is it an SEI recovery point?
- if ( type == 6 )
+ if( type == 6 )
{
- bitbuf_t bb;
- bits_init(&bb, nal+ii, size, 0);
- int count = bits_read_ue( &bb );
- recovery_frames = count + 3;
+ recovery_frames = 1;
break;
}
-
ii += size;
}
@@ -1332,6 +1318,11 @@ static int isIframe( hb_stream_t *stream, const uint8_t *buf, int len )
{
// we found a start code - remove the ref_idc from the nal type
uint8_t nal_type = strid & 0x1f;
+ if ( nal_type == 0x01 )
+ {
+ // Found slice and no recovery point
+ return 0;
+ }
if ( nal_type == 0x05 )
{
// h.264 IDR picture start
@@ -1826,20 +1817,20 @@ int hb_stream_seek( hb_stream_t * stream, float f )
// forwards to the next transport stream packet.
hb_ts_stream_reset(stream);
align_to_next_packet(stream);
- if ( stream->has_IDRs )
+ if ( !stream->has_IDRs )
{
- // the stream has IDRs so look for one.
- stream->need_keyframe = 1;
+ // the stream has no IDRs so don't look for one.
+ stream->need_keyframe = 0;
}
}
else if ( stream->hb_stream_type == program )
{
hb_ps_stream_reset(stream);
skip_to_next_pack( stream );
- if ( stream->has_IDRs )
+ if ( !stream->has_IDRs )
{
- // the stream has IDRs so look for one.
- stream->need_keyframe = 1;
+ // the stream has no IDRs so don't look for one.
+ stream->need_keyframe = 0;
}
}
@@ -3393,9 +3384,8 @@ static hb_buffer_t * hb_ps_stream_decode( hb_stream_t *stream )
{
// we're looking for the first video frame because we're
// doing random access during 'scan'
- if ( buf->type == VIDEO_BUF )
- stream->recovery_frames = isIframe( stream, buf->data, buf->size );
- if ( buf->type != VIDEO_BUF || !stream->recovery_frames )
+ if ( buf->type != VIDEO_BUF ||
+ !isIframe( stream, buf->data, buf->size ) )
{
// not the video stream or didn't find an I frame
// but we'll only wait 255 video frames for an I frame.
@@ -4320,21 +4310,6 @@ static void hb_ts_stream_find_pids(hb_stream_t *stream)
}
-static void fwrite64( hb_buffer_t * buf, void *data, int len )
-{
- if ( len > 0 )
- {
- int pos = buf->size;
- if ( pos + len > buf->alloc )
- {
- int size = MAX(buf->alloc * 2, pos + len);
- hb_buffer_realloc(buf, size);
- }
- memcpy( &(buf->data[pos]), data, len );
- buf->size += len;
- }
-}
-
// convert a PES PTS or DTS to an int64
static int64_t pes_timestamp( const uint8_t *buf )
{
@@ -4360,7 +4335,7 @@ static hb_buffer_t * generate_output_data(hb_stream_t *stream, int curstream)
return NULL;
}
- uint8_t *tdat = b->data;
+ uint8_t *tdat = b->data + pes_info.header_len;
int size = b->size - pes_info.header_len;
if ( size <= 0 )
@@ -4369,8 +4344,27 @@ static hb_buffer_t * generate_output_data(hb_stream_t *stream, int curstream)
return NULL;
}
- // Check all substreams to see if this packet matches
int pes_idx;
+ pes_idx = stream->ts.list[curstream].pes_list;
+ if( stream->need_keyframe )
+ {
+ // we're looking for the first video frame because we're
+ // doing random access during 'scan'
+ int kind = stream->pes.list[pes_idx].stream_kind;
+ if( kind != V || !isIframe( stream, tdat, size ) )
+ {
+ // not the video stream or didn't find an I frame
+ // but we'll only wait 255 video frames for an I frame.
+ if ( kind != V || ++stream->need_keyframe < 512 )
+ {
+ b->size = 0;
+ return NULL;
+ }
+ }
+ stream->need_keyframe = 0;
+ }
+
+ // Check all substreams to see if this packet matches
for ( pes_idx = stream->ts.list[curstream].pes_list; pes_idx != -1;
pes_idx = stream->pes.list[pes_idx].next )
{
@@ -4393,8 +4387,6 @@ static hb_buffer_t * generate_output_data(hb_stream_t *stream, int curstream)
buf = tmp;
}
- buf->size = 0;
-
buf->id = get_id( &stream->pes.list[pes_idx] );
switch (stream->pes.list[pes_idx].stream_kind)
{
@@ -4450,8 +4442,7 @@ static hb_buffer_t * generate_output_data(hb_stream_t *stream, int curstream)
buf->start = pes_info.pts;
buf->renderOffset = pes_info.dts;
}
-
- fwrite64( buf, tdat + pes_info.header_len, size );
+ memcpy( buf->data, tdat, size );
}
b->size = 0;
@@ -4473,13 +4464,6 @@ static void hb_ts_stream_append_pkt(hb_stream_t *stream, int idx, const uint8_t
stream->ts.list[idx].buf->size += len;
}
-int hb_stream_recovery_count( hb_stream_t *stream )
-{
- int count = stream->recovery_frames;
- stream->recovery_frames = 0;
- return count;
-}
-
/***********************************************************************
* hb_ts_stream_decode
***********************************************************************
@@ -4646,25 +4630,7 @@ hb_buffer_t * hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt )
return NULL;
}
- if ( stream->need_keyframe && video_index >= 0 )
- {
- // we're looking for the first video frame because we're
- // doing random access during 'scan'
- if ( curstream == video_index )
- stream->recovery_frames = ts_isIframe( stream, pkt, adapt_len );
- if ( curstream != video_index || !stream->recovery_frames )
- {
- // not the video stream or didn't find an I frame
- // but we'll only wait 255 video frames for an I frame.
- if ( curstream != video_index || ++stream->need_keyframe < 512 )
- {
- return NULL;
- }
- }
- stream->need_keyframe = 0;
- }
-
- // If we were skipping a bad packet, start fresh on this new PES packet..
+ // If we were skipping a bad packet, start fresh on this new PES packet
if (stream->ts.list[curstream].skipbad == 1)
{
stream->ts.list[curstream].skipbad = 0;
@@ -4776,7 +4742,7 @@ void hb_ts_stream_reset(hb_stream_t *stream)
stream->ts.list[i].continuity = -1;
}
- stream->need_keyframe = 0;
+ stream->need_keyframe = 1;
stream->ts.found_pcr = 0;
stream->ts.pcr_out = 0;
@@ -4792,7 +4758,7 @@ void hb_ts_stream_reset(hb_stream_t *stream)
void hb_ps_stream_reset(hb_stream_t *stream)
{
- stream->need_keyframe = 0;
+ stream->need_keyframe = 1;
stream->pes.found_scr = 0;
stream->pes.scr = -1;