Commit 33778d4d authored by Steinar H. Gunderson's avatar Steinar H. Gunderson Committed by Jean-Baptiste Kempf

Support H.264 SEI recovery points.

H.264 SEI recovery points are put at frames in the stream that are not
(necessarily) keyframes, but that mark “if you decode the next N frames, you
will have a [perfectly or approximately] valid picture no matter what your
starting point was”. In particular, this is needed to decode streams encoded
with Periodic Intra Refresh (e.g. --sout-x264-intra-refresh true), at least if
you don't see the beginning of the stream, e.g. tuning into a multicast stream.
This may also help with some kinds of streams from AVCHD cameras that use
similar techniques.

One could argue that this functionality should live inside libavcodec instead,
but given that VLC does its own H.264 depacketization, this seems to be the
best place. I've tested it with streaming over UDP, and it seems to work fine.
Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent cb6f956a
......@@ -101,6 +101,7 @@ struct decoder_sys_t
bool b_pps;
block_t *pp_sps[SPS_MAX];
block_t *pp_pps[PPS_MAX];
int i_recovery_frames; /* -1 = no recovery */
/* avcC data */
int i_avcC_length_size;
......@@ -217,6 +218,7 @@ static int Open( vlc_object_t *p_this )
p_sys->pp_sps[i] = NULL;
for( i = 0; i < PPS_MAX; i++ )
p_sys->pp_pps[i] = NULL;
p_sys->i_recovery_frames = -1;
p_sys->slice.i_nal_type = -1;
p_sys->slice.i_nal_ref_idc = -1;
......@@ -714,7 +716,18 @@ static block_t *OutputPicture( decoder_t *p_dec )
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_pic;
if( !p_sys->b_header && p_sys->slice.i_frame_type != BLOCK_FLAG_TYPE_I)
if ( !p_sys->b_header && p_sys->i_recovery_frames != -1 )
{
if( p_sys->i_recovery_frames == 0 )
{
msg_Dbg( p_dec, "Recovery from SEI recovery point complete" );
p_sys->b_header = true;
}
--p_sys->i_recovery_frames;
}
if( !p_sys->b_header && p_sys->i_recovery_frames == -1 &&
p_sys->slice.i_frame_type != BLOCK_FLAG_TYPE_I)
return NULL;
const bool b_sps_pps_i = p_sys->slice.i_frame_type == BLOCK_FLAG_TYPE_I &&
......@@ -760,6 +773,8 @@ static block_t *OutputPicture( decoder_t *p_dec )
p_pic->i_length = 0; /* FIXME */
p_pic->i_flags |= p_sys->slice.i_frame_type;
p_pic->i_flags &= ~BLOCK_FLAG_PRIVATE_AUD;
if( !p_sys->b_header )
p_pic->i_flags |= BLOCK_FLAG_PREROLL;
p_sys->slice.i_frame_type = 0;
p_sys->p_frame = NULL;
......@@ -1176,6 +1191,27 @@ static void ParseSei( decoder_t *p_dec, block_t *p_frag )
cc_Extract( &p_sys->cc_next, true, &p_t35[3], i_t35 - 3 );
}
}
/* Look for SEI recovery point */
if( i_type == 6 )
{
bs_t s;
const int i_rec = i_size;
const uint8_t *p_rec = &pb_dec[i_used];
bs_init( &s, p_rec, i_rec );
int i_recovery_frames = bs_read_ue( &s );
//bool b_exact_match = bs_read( &s, 1 );
//bool b_broken_link = bs_read( &s, 1 );
//int i_changing_slice_group = bs_read( &s, 2 );
if( !p_sys->b_header )
{
msg_Dbg( p_dec, "Seen SEI recovery point, %d recovery frames", i_recovery_frames );
if ( p_sys->i_recovery_frames == -1 || i_recovery_frames < p_sys->i_recovery_frames )
p_sys->i_recovery_frames = i_recovery_frames;
}
}
i_used += i_size;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment