📄 h264.c
字号:
} return VLC_SUCCESS;}/***************************************************************************** * Close: clean up the packetizer *****************************************************************************/static void Close( vlc_object_t *p_this ){ decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys = p_dec->p_sys; int i; if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame ); for( i = 0; i < SPS_MAX; i++ ) { if( p_sys->pp_sps[i] ) block_Release( p_sys->pp_sps[i] ); } for( i = 0; i < PPS_MAX; i++ ) { if( p_sys->pp_pps[i] ) block_Release( p_sys->pp_pps[i] ); } block_BytestreamRelease( &p_sys->bytestream ); free( p_sys );}/**************************************************************************** * Packetize: the whole thing * Search for the startcodes 3 or more bytes * Feed ParseNALBlock ALWAYS with 4 byte startcode prepended NALs ****************************************************************************/static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ){ decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic; if( !pp_block || !*pp_block ) return NULL; if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) { p_sys->i_state = STATE_NOSYNC; block_BytestreamFlush( &p_sys->bytestream ); if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame ); p_sys->p_frame = NULL; p_sys->slice.i_frame_type = 0; p_sys->b_slice = false; } block_Release( *pp_block ); return NULL; } block_BytestreamPush( &p_sys->bytestream, *pp_block ); for( ;; ) { bool b_used_ts; switch( p_sys->i_state ) { case STATE_NOSYNC: /* Skip until 3 byte startcode 0 0 1 */ if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->startcode+1, 3 ) == VLC_SUCCESS) { p_sys->i_state = STATE_NEXT_SYNC; } if( p_sys->i_offset ) { /* skip the data */ block_SkipBytes( &p_sys->bytestream, p_sys->i_offset ); p_sys->i_offset = 0; block_BytestreamFlush( &p_sys->bytestream ); } if( p_sys->i_state != STATE_NEXT_SYNC ) { /* Need more data */ return NULL; } p_sys->i_offset = 1; /* To find next startcode */ case STATE_NEXT_SYNC: /* Find the next 3 byte startcode 0 0 1*/ if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->startcode+1, 3 ) != VLC_SUCCESS) { /* Need more data */ return NULL; } block_BytestreamFlush( &p_sys->bytestream ); /* Get the new fragment and set the pts/dts */ block_t *p_block_bytestream = p_sys->bytestream.p_block; p_pic = block_New( p_dec, p_sys->i_offset +1 ); p_pic->i_pts = p_block_bytestream->i_pts; p_pic->i_dts = p_block_bytestream->i_dts; /* Force 4 byte startcode 0 0 0 1 */ p_pic->p_buffer[0] = 0; block_GetBytes( &p_sys->bytestream, &p_pic->p_buffer[1], p_pic->i_buffer-1 ); /* Remove trailing 0 bytes */ while( p_pic->i_buffer && (!p_pic->p_buffer[p_pic->i_buffer-1] ) ) p_pic->i_buffer--; p_sys->i_offset = 0; /* Parse the NAL */ p_pic = ParseNALBlock( p_dec, &b_used_ts, p_pic ); if( b_used_ts ) { p_block_bytestream->i_dts = -1; p_block_bytestream->i_pts = -1; } if( !p_pic ) { p_sys->i_state = STATE_NOSYNC; break; }#if 0 msg_Dbg( p_dec, "pts=%"PRId64" dts=%"PRId64, p_pic->i_pts, p_pic->i_dts );#endif /* So p_block doesn't get re-added several times */ *pp_block = block_BytestreamPop( &p_sys->bytestream ); p_sys->i_state = STATE_NOSYNC; return p_pic; } }}/**************************************************************************** * PacketizeAVC1: Takes VCL blocks of data and creates annexe B type NAL stream * Will always use 4 byte 0 0 0 1 startcodes * Will prepend a SPS and PPS before each keyframe ****************************************************************************/static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block ){ decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; block_t *p_ret = NULL; uint8_t *p; if( !pp_block || !*pp_block ) return NULL; if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { block_Release( *pp_block ); return NULL; } p_block = *pp_block; *pp_block = NULL; for( p = p_block->p_buffer; p < &p_block->p_buffer[p_block->i_buffer]; ) { block_t *p_pic; bool b_dummy; int i_size = 0; int i; for( i = 0; i < p_sys->i_avcC_length_size; i++ ) { i_size = (i_size << 8) | (*p++); } if( i_size <= 0 || i_size > ( p_block->p_buffer + p_block->i_buffer - p ) ) { msg_Err( p_dec, "Broken frame : size %d is too big", i_size ); break; } block_t *p_part = CreateAnnexbNAL( p_dec, p, i_size ); if( !p_part ) break; p_part->i_dts = p_block->i_dts; p_part->i_pts = p_block->i_pts; /* Parse the NAL */ if( ( p_pic = ParseNALBlock( p_dec, &b_dummy, p_part ) ) ) { block_ChainAppend( &p_ret, p_pic ); } p += i_size; } block_Release( p_block ); return p_ret;}/**************************************************************************** * Helpers ****************************************************************************/static block_t *CreateAnnexbNAL( decoder_t *p_dec, const uint8_t *p, int i_size ){ block_t *p_nal; p_nal = block_New( p_dec, 4 + i_size ); if( !p_nal ) return NULL; /* Add start code */ p_nal->p_buffer[0] = 0x00; p_nal->p_buffer[1] = 0x00; p_nal->p_buffer[2] = 0x00; p_nal->p_buffer[3] = 0x01; /* Copy nalu */ memcpy( &p_nal->p_buffer[4], p, i_size ); VLC_UNUSED(p_dec); return p_nal;}static void CreateDecodedNAL( uint8_t **pp_ret, int *pi_ret, const uint8_t *src, int i_src ){ const uint8_t *end = &src[i_src]; uint8_t *dst = malloc( i_src ); *pp_ret = dst; if( dst ) { while( src < end ) { if( src < end - 3 && src[0] == 0x00 && src[1] == 0x00 && src[2] == 0x03 ) { *dst++ = 0x00; *dst++ = 0x00; src += 3; continue; } *dst++ = *src++; } } *pi_ret = dst - *pp_ret;}static inline int bs_read_ue( bs_t *s ){ int i = 0; while( bs_read1( s ) == 0 && s->p < s->p_end && i < 32 ) { i++; } return( ( 1 << i) - 1 + bs_read( s, i ) );}static inline int bs_read_se( bs_t *s ){ int val = bs_read_ue( s ); return val&0x01 ? (val+1)/2 : -(val/2);}/***************************************************************************** * ParseNALBlock: parses annexB type NALs * All p_frag blocks are required to start with 0 0 0 1 4-byte startcode *****************************************************************************/static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag ){ decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic = NULL; const int i_nal_ref_idc = (p_frag->p_buffer[4] >> 5)&0x03; const int i_nal_type = p_frag->p_buffer[4]&0x1f; const mtime_t i_frag_dts = p_frag->i_dts; const mtime_t i_frag_pts = p_frag->i_pts; if( p_sys->b_slice && ( !p_sys->b_sps || !p_sys->b_pps ) ) { block_ChainRelease( p_sys->p_frame ); msg_Warn( p_dec, "waiting for SPS/PPS" ); /* Reset context */ p_sys->slice.i_frame_type = 0; p_sys->p_frame = NULL; p_sys->b_slice = false; } if( ( !p_sys->b_sps || !p_sys->b_pps ) && i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR ) { p_sys->b_slice = true; /* Fragment will be discarded later on */ } else if( i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR ) { slice_t slice; bool b_new_picture; ParseSlice( p_dec, &b_new_picture, &slice, i_nal_ref_idc, i_nal_type, p_frag ); /* */ if( b_new_picture && p_sys->b_slice ) p_pic = OutputPicture( p_dec ); /* */ p_sys->slice = slice; p_sys->b_slice = true; } else if( i_nal_type == NAL_SPS ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); PutSPS( p_dec, p_frag ); /* Do not append the SPS because we will insert it on keyframes */ p_frag = NULL; } else if( i_nal_type == NAL_PPS ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); PutPPS( p_dec, p_frag ); /* Do not append the PPS because we will insert it on keyframes */ p_frag = NULL; } else if( i_nal_type == NAL_AU_DELIMITER || i_nal_type == NAL_SEI || ( i_nal_type >= 13 && i_nal_type <= 18 ) ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); /* TODO parse SEI for CC support */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -