--- /dev/null
+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;
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 );
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;
* 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;
{
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;
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 );
avcodec_flush_buffers( pv->context );
}
}
+ pv->wait_for_keyframe = 60;
}
hb_work_object_t hb_decavcodecv =
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 */
#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;
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);
// 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 );
}
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;
}
{
// 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
// 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;
}
}
{
// 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.
}
-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 )
{
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 )
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 )
{
buf = tmp;
}
- buf->size = 0;
-
buf->id = get_id( &stream->pes.list[pes_idx] );
switch (stream->pes.list[pes_idx].stream_kind)
{
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;
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
***********************************************************************
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;
stream->ts.list[i].continuity = -1;
}
- stream->need_keyframe = 0;
+ stream->need_keyframe = 1;
stream->ts.found_pcr = 0;
stream->ts.pcr_out = 0;
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;