/** * Do the actual work with the new sample. * @param p_filter: filter object * @param p_in_buf: input buffer */ static block_t *DoWork(filter_t *p_filter, block_t *p_in_buf) { block_t *block = block_Duplicate(p_in_buf); if (likely(block != NULL)) block_FifoPut(p_filter->p_sys->fifo, block); return p_in_buf; }
void GrabVBI (demux_t *p_demux, vlc_v4l2_vbi_t *vbi) { vbi_capture_buffer *sliced_bytes; struct timeval timeout= {0,0}; /* poll */ int canc = vlc_savecancel (); int r = vbi_capture_pull_sliced (vbi->cap, &sliced_bytes, &timeout); switch (r) { case -1: msg_Err (p_demux, "error reading VBI: %m"); case 0: /* nothing avail */ break; case 1: /* got data */ { int n_lines = sliced_bytes->size / sizeof(vbi_sliced); if (!n_lines) break; int sliced_size = 2; /* Number of bytes per sliced line */ int size = (sliced_size + 1) * n_lines; block_t *p_block = block_Alloc (size); if (unlikely(p_block == NULL)) break; uint8_t* data = p_block->p_buffer; vbi_sliced *sliced_array = sliced_bytes->data; for (int field = 0; field < n_lines; field++) { *data = field; data++; memcpy(data, sliced_array[field].data, sliced_size); data += sliced_size; } p_block->i_pts = mdate(); for (unsigned i = 0; i < VBI_NUM_CC_STREAMS; i++) { if (vbi->es[i] == NULL) continue; block_t *dup = block_Duplicate(p_block); if (likely(dup != NULL)) es_out_Send(p_demux->out, vbi->es[i], dup); } block_Release(p_block); } } vlc_restorecancel (canc); }
static void *DemuxThread( void *p_data ) { demux_t *p_demux = (demux_t *) p_data; demux_sys_t *p_sys = p_demux->p_sys; vlc_tick_t i_next_frame_date = vlc_tick_now() + p_sys->i_frame_interval; int i_status; for(;;) { p_sys->i_cancel_state = vlc_savecancel(); i_status = WaitForMessage( p_sys->p_client, p_sys->i_frame_interval ); vlc_restorecancel( p_sys->i_cancel_state ); /* Ensure we're not building frames too fast */ /* as WaitForMessage takes only a maximum wait */ vlc_tick_wait( i_next_frame_date ); i_next_frame_date += p_sys->i_frame_interval; if ( i_status > 0 ) { p_sys->p_client->frameBuffer = p_sys->p_block->p_buffer; p_sys->i_cancel_state = vlc_savecancel(); i_status = HandleRFBServerMessage( p_sys->p_client ); vlc_restorecancel( p_sys->i_cancel_state ); if ( ! i_status ) { msg_Warn( p_demux, "Cannot get announced data. Server closed ?" ); es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; return NULL; } else { block_t *p_block = block_Duplicate( p_sys->p_block ); if ( p_block ) /* drop frame/content if no next block */ { p_sys->p_block->i_dts = p_sys->p_block->i_pts = vlc_tick_now(); es_out_SetPCR( p_demux->out, p_sys->p_block->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_sys->p_block ); p_sys->p_block = p_block; } } } } return NULL; }
static int Demux(demux_t *demux) { demux_sys_t *sys = demux->p_sys; if (!sys->data) return 0; mtime_t deadline; const mtime_t pts_first = sys->pts_origin + date_Get(&sys->pts); if (sys->pts_next > VLC_TS_INVALID) { deadline = sys->pts_next; } else if (sys->is_realtime) { deadline = mdate(); const mtime_t max_wait = CLOCK_FREQ / 50; if (deadline + max_wait < pts_first) { es_out_Control(demux->out, ES_OUT_SET_PCR, deadline); /* That's ugly, but not yet easily fixable */ mwait(deadline + max_wait); return 1; } } else { deadline = 1 + pts_first; } for (;;) { const mtime_t pts = sys->pts_origin + date_Get(&sys->pts); if (sys->duration >= 0 && pts >= sys->pts_origin + sys->duration) return 0; if (pts >= deadline) return 1; block_t *data = block_Duplicate(sys->data); if (!data) return -1; data->i_dts = data->i_pts = VLC_TS_0 + pts; es_out_Control(demux->out, ES_OUT_SET_PCR, data->i_pts); es_out_Send(demux->out, sys->es, data); date_Increment(&sys->pts, 1); } }
/***************************************************************************** * Send: *****************************************************************************/ static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id, block_t *p_buffer ) { sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_t *p_dup_stream; int i_stream; /* Loop through the linked list of buffers */ while( p_buffer ) { block_t *p_next = p_buffer->p_next; p_buffer->p_next = NULL; for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ ) { p_dup_stream = p_sys->pp_streams[i_stream]; if( id->pp_ids[i_stream] ) { block_t *p_dup = block_Duplicate( p_buffer ); if( p_dup ) sout_StreamIdSend( p_dup_stream, id->pp_ids[i_stream], p_dup ); } } if( i_stream < p_sys->i_nb_streams && id->pp_ids[i_stream] ) { p_dup_stream = p_sys->pp_streams[i_stream]; sout_StreamIdSend( p_dup_stream, id->pp_ids[i_stream], p_buffer ); } else { block_Release( p_buffer ); } p_buffer = p_next; } return VLC_SUCCESS; }
/***************************************************************************** * Demux: *****************************************************************************/ static void *DemuxThread( void *p_data ) { demux_t *p_demux = (demux_t *) p_data; demux_sys_t *p_sys = p_demux->p_sys; p_sys->i_starttime = vlc_tick_now(); vlc_tick_t i_next_frame_date = vlc_tick_now() + p_sys->i_frame_interval; int i_ret; for(;;) { i_ret = 0; p_sys->i_cancel_state = vlc_savecancel(); if ( freerdp_shall_disconnect( p_sys->p_instance ) ) { vlc_restorecancel( p_sys->i_cancel_state ); msg_Warn( p_demux, "RDP server closed session" ); es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; return NULL; } struct { void* pp_rfds[RDP_MAX_FD]; /* Declared by rdp */ void* pp_wfds[RDP_MAX_FD]; int i_nbr; int i_nbw; struct pollfd ufds[RDP_MAX_FD]; } fds; fds.i_nbr = fds.i_nbw = 0; if ( freerdp_get_fds( p_sys->p_instance, fds.pp_rfds, &fds.i_nbr, fds.pp_wfds, &fds.i_nbw ) != true ) { vlc_restorecancel( p_sys->i_cancel_state ); msg_Err( p_demux, "cannot get FDS" ); } else if ( (fds.i_nbr + fds.i_nbw) > 0 && p_sys->es ) { vlc_restorecancel( p_sys->i_cancel_state ); int i_count = 0; for( int i = 0; i < fds.i_nbr; i++ ) { fds.ufds[ i_count ].fd = (long) fds.pp_rfds[ i ]; fds.ufds[ i_count ].events = POLLIN ; fds.ufds[ i_count++ ].revents = 0; } for( int i = 0; i < fds.i_nbw && i_count < RDP_MAX_FD; i++ ) { /* may be useless */ fds.ufds[ i_count ].fd = (long) fds.pp_wfds[ i ]; fds.ufds[ i_count ].events = POLLOUT; fds.ufds[ i_count++ ].revents = 0; } i_ret = poll( fds.ufds, i_count, p_sys->i_frame_interval * 1000/2 ); } else { vlc_restorecancel( p_sys->i_cancel_state ); } vlc_tick_wait( i_next_frame_date ); i_next_frame_date += p_sys->i_frame_interval; if ( i_ret >= 0 ) { /* Do the rendering */ p_sys->i_cancel_state = vlc_savecancel(); freerdp_check_fds( p_sys->p_instance ); vlc_restorecancel( p_sys->i_cancel_state ); block_t *p_block = block_Duplicate( p_sys->p_block ); if (likely( p_block && p_sys->p_block )) { p_sys->p_block->i_dts = p_sys->p_block->i_pts = vlc_tick_now() - p_sys->i_starttime; es_out_SetPCR( p_demux->out, p_sys->p_block->i_pts ); es_out_Send( p_demux->out, p_sys->es, p_sys->p_block ); p_sys->p_block = p_block; } } } return NULL; }
/***************************************************************************** * ParseMPEGBlock: Re-assemble fragments into a block containing a picture *****************************************************************************/ static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic = NULL; /* * Check if previous picture is finished */ if( ( p_sys->b_frame_slice && (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) ) && p_sys->p_seq == NULL ) { /* We have a picture but without a sequence header we can't * do anything */ msg_Dbg( p_dec, "waiting for sequence start" ); if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame ); p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; p_sys->b_frame_slice = false; } else if( p_sys->b_frame_slice && (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) ) { const bool b_eos = p_frag->p_buffer[3] == 0xb7; mtime_t i_duration; if( b_eos ) { block_ChainLastAppend( &p_sys->pp_last, p_frag ); p_frag = NULL; } p_pic = block_ChainGather( p_sys->p_frame ); if( b_eos ) p_pic->i_flags |= BLOCK_FLAG_END_OF_SEQUENCE; i_duration = (mtime_t)( 1000000 * p_sys->i_frame_rate_base / p_sys->i_frame_rate ); if( !p_sys->b_seq_progressive && p_sys->i_picture_structure != 0x03 ) { i_duration /= 2; } if( p_sys->b_seq_progressive ) { if( p_sys->i_top_field_first == 0 && p_sys->i_repeat_first_field == 1 ) { i_duration *= 2; } else if( p_sys->i_top_field_first == 1 && p_sys->i_repeat_first_field == 1 ) { i_duration *= 3; } } else { if( p_sys->i_picture_structure == 0x03 ) { if( p_sys->i_progressive_frame && p_sys->i_repeat_first_field ) { i_duration += i_duration / 2; } } } if( p_sys->b_low_delay || p_sys->i_picture_type == 0x03 ) { /* Trivial case (DTS == PTS) */ /* Correct interpolated dts when we receive a new pts/dts */ if( p_sys->i_pts > VLC_TS_INVALID ) p_sys->i_interpolated_dts = p_sys->i_pts; if( p_sys->i_dts > VLC_TS_INVALID ) p_sys->i_interpolated_dts = p_sys->i_dts; } else { /* Correct interpolated dts when we receive a new pts/dts */ if(p_sys->i_last_ref_pts > VLC_TS_INVALID && !p_sys->b_second_field) p_sys->i_interpolated_dts = p_sys->i_last_ref_pts; if( p_sys->i_dts > VLC_TS_INVALID ) p_sys->i_interpolated_dts = p_sys->i_dts; if( !p_sys->b_second_field ) p_sys->i_last_ref_pts = p_sys->i_pts; } p_pic->i_dts = p_sys->i_interpolated_dts; p_sys->i_interpolated_dts += i_duration; /* Set PTS only if we have a B frame or if it comes from the stream */ if( p_sys->i_pts > VLC_TS_INVALID ) { p_pic->i_pts = p_sys->i_pts; } else if( p_sys->i_picture_type == 0x03 ) { p_pic->i_pts = p_pic->i_dts; } else { p_pic->i_pts = VLC_TS_INVALID; } switch ( p_sys->i_picture_type ) { case 0x01: p_pic->i_flags |= BLOCK_FLAG_TYPE_I; break; case 0x02: p_pic->i_flags |= BLOCK_FLAG_TYPE_P; break; case 0x03: p_pic->i_flags |= BLOCK_FLAG_TYPE_B; break; } p_pic->i_length = p_sys->i_interpolated_dts - p_pic->i_dts; #if 0 msg_Dbg( p_dec, "pic: type=%d dts=%"PRId64" pts-dts=%"PRId64, p_sys->i_picture_type, p_pic->i_dts, p_pic->i_pts - p_pic->i_dts); #endif /* Reset context */ p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; p_sys->b_frame_slice = false; if( p_sys->i_picture_structure != 0x03 ) { p_sys->b_second_field = !p_sys->b_second_field; } else { p_sys->b_second_field = 0; } /* CC */ p_sys->b_cc_reset = true; p_sys->i_cc_pts = p_pic->i_pts; p_sys->i_cc_dts = p_pic->i_dts; p_sys->i_cc_flags = p_pic->i_flags; } if( !p_pic && p_sys->b_cc_reset ) { p_sys->b_cc_reset = false; cc_Flush( &p_sys->cc ); } if( !p_frag ) return p_pic; /* * Check info of current fragment */ if( p_frag->p_buffer[3] == 0xb8 ) { /* Group start code */ if( p_sys->p_seq && p_sys->i_seq_old > p_sys->i_frame_rate/p_sys->i_frame_rate_base ) { /* Useful for mpeg1: repeat sequence header every second */ block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_seq ) ); if( p_sys->p_ext ) { block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_ext ) ); } p_sys->i_seq_old = 0; } } else if( p_frag->p_buffer[3] == 0xb3 && p_frag->i_buffer >= 8 ) { /* Sequence header code */ static const int code_to_frame_rate[16][2] = { { 1, 1 }, /* invalid */ { 24000, 1001 }, { 24, 1 }, { 25, 1 }, { 30000, 1001 }, { 30, 1 }, { 50, 1 }, { 60000, 1001 }, { 60, 1 }, /* Unofficial 15fps from Xing*/ { 15, 1001 }, /* Unofficial economy rates from libmpeg3 */ { 5000, 1001 }, { 1000, 1001 }, { 12000, 1001 }, { 15000, 1001 }, { 1, 1 }, { 1, 1 } /* invalid */ }; if( p_sys->p_seq ) block_Release( p_sys->p_seq ); if( p_sys->p_ext ) block_Release( p_sys->p_ext ); p_sys->p_seq = block_Duplicate( p_frag ); p_sys->i_seq_old = 0; p_sys->p_ext = NULL; p_dec->fmt_out.video.i_width = ( p_frag->p_buffer[4] << 4)|(p_frag->p_buffer[5] >> 4 ); p_dec->fmt_out.video.i_height = ( (p_frag->p_buffer[5]&0x0f) << 8 )|p_frag->p_buffer[6]; p_sys->i_aspect_ratio_info = p_frag->p_buffer[7] >> 4; /* TODO: MPEG1 aspect ratio */ p_sys->i_frame_rate = code_to_frame_rate[p_frag->p_buffer[7]&0x0f][0]; p_sys->i_frame_rate_base = code_to_frame_rate[p_frag->p_buffer[7]&0x0f][1]; p_dec->fmt_out.video.i_frame_rate = p_sys->i_frame_rate; p_dec->fmt_out.video.i_frame_rate_base = p_sys->i_frame_rate_base; p_sys->b_seq_progressive = true; p_sys->b_low_delay = true; if ( !p_sys->b_inited ) { msg_Dbg( p_dec, "size %dx%d fps=%.3f", p_dec->fmt_out.video.i_width, p_dec->fmt_out.video.i_height, p_sys->i_frame_rate / (float)p_sys->i_frame_rate_base ); p_sys->b_inited = 1; } } else if( p_frag->p_buffer[3] == 0xb5 )
/***************************************************************************** * Open: probe the packetizer and return score * When opening after demux, the packetizer is only loaded AFTER the decoder * That means that what you set in fmt_out is ignored by the decoder in this special case *****************************************************************************/ static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'h', '2', '6', '4') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'H', '2', '6', '4') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'V', 'S', 'S', 'H') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'v', 's', 's', 'h') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'D', 'A', 'V', 'C') && ( p_dec->fmt_in.i_codec != VLC_FOURCC( 'a', 'v', 'c', '1') || p_dec->fmt_in.i_extra < 7 ) ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL ) { msg_Err( p_dec, "out of memory" ); return VLC_EGENERIC; } p_sys->i_state = STATE_NOSYNC; p_sys->i_offset = 0; p_sys->startcode[0] = 0; p_sys->startcode[1] = 0; p_sys->startcode[2] = 0; p_sys->startcode[3] = 1; p_sys->bytestream = block_BytestreamInit( p_dec ); p_sys->b_slice = VLC_FALSE; p_sys->p_frame = NULL; p_sys->b_sps = VLC_FALSE; p_sys->b_pps = VLC_FALSE; p_sys->p_sps = 0; p_sys->p_pps = 0; p_sys->b_header= VLC_FALSE; p_sys->slice.i_nal_type = -1; p_sys->slice.i_nal_ref_idc = -1; p_sys->slice.i_idr_pic_id = -1; p_sys->slice.i_frame_num = -1; p_sys->slice.i_frame_type = 0; p_sys->slice.i_pic_parameter_set_id = -1; p_sys->slice.i_field_pic_flag = 0; p_sys->slice.i_bottom_field_flag = -1; p_sys->slice.i_pic_order_cnt_lsb = -1; p_sys->slice.i_delta_pic_order_cnt_bottom = -1; /* Setup properties */ es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->fmt_out.i_codec = VLC_FOURCC( 'h', '2', '6', '4' ); if( p_dec->fmt_in.i_codec == VLC_FOURCC( 'a', 'v', 'c', '1' ) ) { /* This type of stream is produced by mp4 and matroska * when we want to store it in another streamformat, you need to convert * The fmt_in.p_extra should ALWAYS contain the avcC * The fmt_out.p_extra should contain all the SPS and PPS with 4 byte startcodes */ uint8_t *p = &((uint8_t*)p_dec->fmt_in.p_extra)[4]; int i_sps, i_pps; int i; /* Parse avcC */ p_sys->i_avcC_length_size = 1 + ((*p++)&0x03); /* Read SPS */ i_sps = (*p++)&0x1f; for( i = 0; i < i_sps; i++ ) { int i_length = GetWBE( p ); block_t *p_sps = nal_get_annexeb( p_dec, p + 2, i_length ); p_sys->p_sps = block_Duplicate( p_sps ); p_sps->i_pts = p_sps->i_dts = mdate(); ParseNALBlock( p_dec, p_sps ); p += 2 + i_length; } /* Read PPS */ i_pps = *p++; for( i = 0; i < i_pps; i++ ) { int i_length = GetWBE( p ); block_t *p_pps = nal_get_annexeb( p_dec, p + 2, i_length ); p_sys->p_pps = block_Duplicate( p_pps ); p_pps->i_pts = p_pps->i_dts = mdate(); ParseNALBlock( p_dec, p_pps ); p += 2 + i_length; } msg_Dbg( p_dec, "avcC length size=%d, sps=%d, pps=%d", p_sys->i_avcC_length_size, i_sps, i_pps ); /* FIXME: FFMPEG isn't happy at all if you leave this */ if( p_dec->fmt_out.i_extra ) free( p_dec->fmt_out.p_extra ); p_dec->fmt_out.i_extra = 0; p_dec->fmt_out.p_extra = NULL; /* Set the new extradata */ p_dec->fmt_out.i_extra = p_sys->p_pps->i_buffer + p_sys->p_sps->i_buffer; p_dec->fmt_out.p_extra = (uint8_t*)malloc( p_dec->fmt_out.i_extra ); memcpy( (uint8_t*)p_dec->fmt_out.p_extra, p_sys->p_sps->p_buffer, p_sys->p_sps->i_buffer); memcpy( (uint8_t*)p_dec->fmt_out.p_extra+p_sys->p_sps->i_buffer, p_sys->p_pps->p_buffer, p_sys->p_pps->i_buffer); p_sys->b_header = VLC_TRUE; /* Set callback */ p_dec->pf_packetize = PacketizeAVC1; } else { /* This type of stream contains data with 3 of 4 byte startcodes * The fmt_in.p_extra MAY contain SPS/PPS with 4 byte startcodes * The fmt_out.p_extra should be the same */ /* Set callback */ p_dec->pf_packetize = Packetize; /* */ if( p_dec->fmt_in.i_extra > 0 ) { block_t *p_init = block_New( p_dec, p_dec->fmt_in.i_extra ); block_t *p_pic; memcpy( p_init->p_buffer, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); while( ( p_pic = Packetize( p_dec, &p_init ) ) ) { /* Should not occur because we should only receive SPS/PPS */ block_Release( p_pic ); } } } return VLC_SUCCESS; }
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->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 && p_sys->b_sps && p_sys->b_pps; if( b_sps_pps_i || p_sys->b_frame_sps || p_sys->b_frame_pps ) { block_t *p_head = NULL; if( p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD ) { p_head = p_sys->p_frame; p_sys->p_frame = p_sys->p_frame->p_next; } block_t *p_list = NULL; for( int i = 0; i < SPS_MAX && (b_sps_pps_i || p_sys->b_frame_sps); i++ ) { if( p_sys->pp_sps[i] ) block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_sps[i] ) ); } for( int i = 0; i < PPS_MAX && (b_sps_pps_i || p_sys->b_frame_pps); i++ ) { if( p_sys->pp_pps[i] ) block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_pps[i] ) ); } if( b_sps_pps_i && p_list ) p_sys->b_header = true; if( p_head ) p_head->p_next = p_list; else p_head = p_list; block_ChainAppend( &p_head, p_sys->p_frame ); p_pic = block_ChainGather( p_head ); } else { p_pic = block_ChainGather( p_sys->p_frame ); } p_pic->i_dts = p_sys->i_frame_dts; p_pic->i_pts = p_sys->i_frame_pts; 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; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->b_frame_sps = false; p_sys->b_frame_pps = false; p_sys->b_slice = false; /* CC */ p_sys->i_cc_pts = p_pic->i_pts; p_sys->i_cc_dts = p_pic->i_dts; p_sys->i_cc_flags = p_pic->i_flags; p_sys->cc = p_sys->cc_next; cc_Flush( &p_sys->cc_next ); return p_pic; }
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->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 && p_sys->b_sps && p_sys->b_pps; if( b_sps_pps_i || p_sys->b_frame_sps || p_sys->b_frame_pps ) { block_t *p_head = NULL; if( p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD ) { p_head = p_sys->p_frame; p_sys->p_frame = p_sys->p_frame->p_next; if( p_sys->p_frame == NULL ) p_sys->pp_frame_last = &p_sys->p_frame; p_head->p_next = NULL; } block_t *p_list = NULL; block_t **pp_list_tail = &p_list; for( int i = 0; i <= H264_SPS_ID_MAX && (b_sps_pps_i || p_sys->b_frame_sps); i++ ) { if( p_sys->pp_sps[i] ) block_ChainLastAppend( &pp_list_tail, block_Duplicate( p_sys->pp_sps[i] ) ); } for( int i = 0; i < H264_PPS_ID_MAX && (b_sps_pps_i || p_sys->b_frame_pps); i++ ) { if( p_sys->pp_pps[i] ) block_ChainLastAppend( &pp_list_tail, block_Duplicate( p_sys->pp_pps[i] ) ); } if( b_sps_pps_i && p_list ) p_sys->b_header = true; if( p_list ) block_ChainAppend( &p_head, p_list ); if( p_sys->p_frame ) block_ChainAppend( &p_head, p_sys->p_frame ); p_pic = block_ChainGather( p_head ); } else { p_pic = block_ChainGather( p_sys->p_frame ); } unsigned i_num_clock_ts = 2; if( p_sys->b_frame_mbs_only == 0 ) { if( p_sys->b_pic_struct_present_flag && p_sys->i_pic_struct < 9 ) { const uint8_t rgi_numclock[9] = { 1, 1, 1, 2, 2, 3, 3, 2, 3 }; i_num_clock_ts = rgi_numclock[ p_sys->i_pic_struct ]; } else if( p_sys->slice.i_field_pic_flag ) /* See D-1 and E-6 */ { i_num_clock_ts = 1; } } if( p_sys->i_time_scale && p_pic->i_length == 0 ) { p_pic->i_length = CLOCK_FREQ * i_num_clock_ts * p_sys->i_num_units_in_tick / p_sys->i_time_scale; } mtime_t i_field_pts_diff = -1; if( p_sys->b_frame_mbs_only == 0 && p_sys->b_pic_struct_present_flag ) { switch( p_sys->i_pic_struct ) { /* Top and Bottom field slices */ case 1: case 2: if( !p_sys->b_even_frame ) { p_pic->i_flags |= (p_sys->i_pic_struct == 1) ? BLOCK_FLAG_TOP_FIELD_FIRST : BLOCK_FLAG_BOTTOM_FIELD_FIRST; } else if( p_pic->i_pts <= VLC_TS_INVALID && p_sys->i_prev_pts > VLC_TS_INVALID && p_pic->i_length ) { /* interpolate from even frame */ i_field_pts_diff = p_pic->i_length; } p_sys->b_even_frame = !p_sys->b_even_frame; break; /* Each of the following slices contains multiple fields */ case 3: p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; p_sys->b_even_frame = false; break; case 4: p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; p_sys->b_even_frame = false; break; case 5: p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; break; case 6: p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; break; default: p_sys->b_even_frame = false; break; } } /* set dts/pts to current block timestamps */ p_pic->i_dts = p_sys->i_frame_dts; p_pic->i_pts = p_sys->i_frame_pts; /* Fixup missing timestamps after split (multiple AU/block)*/ if( p_pic->i_dts <= VLC_TS_INVALID ) p_pic->i_dts = p_sys->i_prev_dts; /* PTS Fixup, interlaced fields (multiple AU/block) */ if( p_pic->i_pts <= VLC_TS_INVALID && p_sys->i_time_scale ) { mtime_t i_pts_delay = CLOCK_FREQ * p_sys->i_dpb_output_delay * p_sys->i_num_units_in_tick / p_sys->i_time_scale; p_pic->i_pts = p_pic->i_dts + i_pts_delay; if( i_field_pts_diff >= 0 ) p_pic->i_pts += i_field_pts_diff; } /* save for next pic fixups */ p_sys->i_prev_dts = p_pic->i_dts; p_sys->i_prev_pts = p_pic->i_pts; 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; /* reset after output */ p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->i_dpb_output_delay = 0; p_sys->slice.i_frame_type = 0; p_sys->p_frame = NULL; p_sys->pp_frame_last = &p_sys->p_frame; p_sys->b_frame_sps = false; p_sys->b_frame_pps = false; p_sys->b_slice = false; /* CC */ cc_storage_commit( p_sys->p_ccs, p_pic ); return p_pic; }
/* ParseIDU: parse an Independent Decoding Unit */ static block_t *ParseIDU( 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; const idu_type_t idu = (const idu_type_t)(p_frag->p_buffer[3]); // sunqueen modify *pb_used_ts = false; if( !p_sys->b_sequence_header && idu != IDU_TYPE_SEQUENCE_HEADER ) { msg_Warn( p_dec, "waiting for sequence header" ); block_Release( p_frag ); return NULL; } if( p_sys->b_sequence_header && !p_sys->b_entry_point && idu != IDU_TYPE_ENTRY_POINT ) { msg_Warn( p_dec, "waiting for entry point" ); block_Release( p_frag ); return NULL; } /* TODO we do not gather ENTRY_POINT and SEQUENCE_DATA user data * But It should not be a problem for decoder */ /* Do we have completed a frame */ p_pic = NULL; if( p_sys->b_frame && idu != IDU_TYPE_FRAME_USER_DATA && idu != IDU_TYPE_FIELD && idu != IDU_TYPE_FIELD_USER_DATA && idu != IDU_TYPE_SLICE && idu != IDU_TYPE_SLICE_USER_DATA && idu != IDU_TYPE_END_OF_SEQUENCE ) { /* Prepend SH and EP on I */ if( p_sys->p_frame->i_flags & BLOCK_FLAG_TYPE_I ) { block_t *p_list = block_Duplicate( p_sys->sh.p_sh ); block_ChainAppend( &p_list, block_Duplicate( p_sys->ep.p_ep ) ); block_ChainAppend( &p_list, p_sys->p_frame ); p_list->i_flags = p_sys->p_frame->i_flags; p_sys->p_frame = p_list; } /* */ p_pic = block_ChainGather( p_sys->p_frame ); p_pic->i_dts = p_sys->i_frame_dts; p_pic->i_pts = p_sys->i_frame_pts; /* */ if( p_pic->i_dts > VLC_TS_INVALID ) p_sys->i_interpolated_dts = p_pic->i_dts; /* We can interpolate dts/pts only if we have a frame rate */ if( p_dec->fmt_out.video.i_frame_rate != 0 && p_dec->fmt_out.video.i_frame_rate_base != 0 ) { if( p_sys->i_interpolated_dts > VLC_TS_INVALID ) p_sys->i_interpolated_dts += INT64_C(1000000) * p_dec->fmt_out.video.i_frame_rate_base / p_dec->fmt_out.video.i_frame_rate; //msg_Dbg( p_dec, "-------------- XXX0 dts=%"PRId64" pts=%"PRId64" interpolated=%"PRId64, // p_pic->i_dts, p_pic->i_pts, p_sys->i_interpolated_dts ); if( p_pic->i_dts <= VLC_TS_INVALID ) p_pic->i_dts = p_sys->i_interpolated_dts; if( p_pic->i_pts <= VLC_TS_INVALID ) { if( !p_sys->sh.b_has_bframe || (p_pic->i_flags & BLOCK_FLAG_TYPE_B ) ) p_pic->i_pts = p_pic->i_dts; /* TODO compute pts for other case */ } } //msg_Dbg( p_dec, "-------------- dts=%"PRId64" pts=%"PRId64, p_pic->i_dts, p_pic->i_pts ); /* Reset context */ p_sys->b_frame = false; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; } /* */ if( p_sys->i_frame_dts <= VLC_TS_INVALID && p_sys->i_frame_pts <= VLC_TS_INVALID ) { p_sys->i_frame_dts = p_frag->i_dts; p_sys->i_frame_pts = p_frag->i_pts; *pb_used_ts = true; } /* We will add back SH and EP on I frames */ block_t *p_release = NULL; if( idu != IDU_TYPE_SEQUENCE_HEADER && idu != IDU_TYPE_ENTRY_POINT ) block_ChainLastAppend( &p_sys->pp_last, p_frag ); else p_release = p_frag; /* Parse IDU */ if( idu == IDU_TYPE_SEQUENCE_HEADER ) { es_format_t *p_es = &p_dec->fmt_out; bs_t s; int i_profile; uint8_t ridu[32]; int i_ridu = sizeof(ridu); /* */ if( p_sys->sh.p_sh ) block_Release( p_sys->sh.p_sh ); p_sys->sh.p_sh = block_Duplicate( p_frag ); /* Extract the raw IDU */ DecodeRIDU( ridu, &i_ridu, &p_frag->p_buffer[4], p_frag->i_buffer - 4 ); /* Auto detect VC-1_SPMP_PESpacket_PayloadFormatHeader (SMPTE RP 227) for simple/main profile * TODO find a test case and valid it */ if( i_ridu > 4 && (ridu[0]&0x80) == 0 ) /* for advanced profile, the first bit is 1 */ { video_format_t *p_v = &p_dec->fmt_in.video; const size_t i_potential_width = GetWBE( &ridu[0] ); const size_t i_potential_height = GetWBE( &ridu[2] ); if( i_potential_width >= 2 && i_potential_width <= 8192 && i_potential_height >= 2 && i_potential_height <= 8192 ) { if( ( p_v->i_width <= 0 && p_v->i_height <= 0 ) || ( p_v->i_width == i_potential_width && p_v->i_height == i_potential_height ) ) { static const uint8_t startcode[4] = { 0x00, 0x00, 0x01, IDU_TYPE_SEQUENCE_HEADER }; p_es->video.i_width = i_potential_width; p_es->video.i_height = i_potential_height; /* Remove it */ p_frag->p_buffer += 4; p_frag->i_buffer -= 4; memcpy( p_frag->p_buffer, startcode, sizeof(startcode) ); } } } /* Parse it */ bs_init( &s, ridu, i_ridu ); i_profile = bs_read( &s, 2 ); if( i_profile == 3 ) { const int i_level = bs_read( &s, 3 ); /* Advanced profile */ p_sys->sh.b_advanced_profile = true; p_sys->sh.b_range_reduction = false; p_sys->sh.b_has_bframe = true; bs_skip( &s, 2+3+5+1 ); // chroma format + frame rate Q + bit rate Q + postprocflag p_es->video.i_width = 2*bs_read( &s, 12 )+2; p_es->video.i_height = 2*bs_read( &s, 12 )+2; if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "found sequence header for advanced profile level L%d resolution %dx%d", i_level, p_es->video.i_width, p_es->video.i_height); bs_skip( &s, 1 );// pulldown p_sys->sh.b_interlaced = bs_read( &s, 1 ); bs_skip( &s, 1 );// frame counter p_sys->sh.b_frame_interpolation = bs_read( &s, 1 ); bs_skip( &s, 1 ); // Reserved bs_skip( &s, 1 ); // Psf if( bs_read( &s, 1 ) ) /* Display extension */ { const int i_display_width = bs_read( &s, 14 )+1; const int i_display_height = bs_read( &s, 14 )+1; p_es->video.i_sar_num = i_display_width * p_es->video.i_height; p_es->video.i_sar_den = i_display_height * p_es->video.i_width; if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "display size %dx%d", i_display_width, i_display_height ); if( bs_read( &s, 1 ) ) /* Pixel aspect ratio (PAR/SAR) */ { static const int p_ar[16][2] = { { 0, 0}, { 1, 1}, {12,11}, {10,11}, {16,11}, {40,33}, {24,11}, {20,11}, {32,11}, {80,33}, {18,11}, {15,11}, {64,33}, {160,99},{ 0, 0}, { 0, 0} }; int i_ar = bs_read( &s, 4 ); unsigned i_ar_w, i_ar_h; if( i_ar == 15 ) { i_ar_w = bs_read( &s, 8 ); i_ar_h = bs_read( &s, 8 ); } else { i_ar_w = p_ar[i_ar][0]; i_ar_h = p_ar[i_ar][1]; } vlc_ureduce( &i_ar_w, &i_ar_h, i_ar_w, i_ar_h, 0 ); if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "aspect ratio %d:%d", i_ar_w, i_ar_h ); } } if( bs_read( &s, 1 ) ) /* Frame rate */ { int i_fps_num = 0; int i_fps_den = 0; if( bs_read( &s, 1 ) ) { i_fps_num = bs_read( &s, 16 )+1; i_fps_den = 32; } else { const int i_nr = bs_read( &s, 8 ); const int i_dn = bs_read( &s, 4 ); switch( i_nr ) { case 1: i_fps_num = 24000; break; case 2: i_fps_num = 25000; break; case 3: i_fps_num = 30000; break; case 4: i_fps_num = 50000; break; case 5: i_fps_num = 60000; break; case 6: i_fps_num = 48000; break; case 7: i_fps_num = 72000; break; } switch( i_dn ) { case 1: i_fps_den = 1000; break; case 2: i_fps_den = 1001; break; } } if( i_fps_num != 0 && i_fps_den != 0 ) vlc_ureduce( &p_es->video.i_frame_rate, &p_es->video.i_frame_rate_base, i_fps_num, i_fps_den, 0 ); if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "frame rate %d/%d", p_es->video.i_frame_rate, p_es->video.i_frame_rate_base ); } } else { /* Simple and main profile */ p_sys->sh.b_advanced_profile = false; p_sys->sh.b_interlaced = false; if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "found sequence header for %s profile", i_profile == 0 ? "simple" : "main" ); bs_skip( &s, 2+3+5+1+1+ // reserved + frame rate Q + bit rate Q + loop filter + reserved 1+1+1+1+2+ // multiresolution + reserved + fast uv mc + extended mv + dquant 1+1+1+1 ); // variable size transform + reserved + overlap + sync marker p_sys->sh.b_range_reduction = bs_read( &s, 1 ); if( bs_read( &s, 3 ) > 0 ) p_sys->sh.b_has_bframe = true; else p_sys->sh.b_has_bframe = false; bs_skip( &s, 2 ); // quantizer p_sys->sh.b_frame_interpolation = bs_read( &s, 1 ); } p_sys->b_sequence_header = true; BuildExtraData( p_dec ); } else if( idu == IDU_TYPE_ENTRY_POINT ) { if( p_sys->ep.p_ep ) block_Release( p_sys->ep.p_ep ); p_sys->ep.p_ep = block_Duplicate( p_frag ); if( !p_sys->b_entry_point ) msg_Dbg( p_dec, "found entry point" ); p_sys->b_entry_point = true; BuildExtraData( p_dec ); } else if( idu == IDU_TYPE_FRAME ) { bs_t s; uint8_t ridu[8]; int i_ridu = sizeof(ridu); /* Extract the raw IDU */ DecodeRIDU( ridu, &i_ridu, &p_frag->p_buffer[4], p_frag->i_buffer - 4 ); /* Parse it + interpolate pts/dts if possible */ bs_init( &s, ridu, i_ridu ); if( p_sys->sh.b_advanced_profile ) { int i_fcm = 0; if( p_sys->sh.b_interlaced ) { if( bs_read( &s, 1 ) ) { if( bs_read( &s, 1 ) ) i_fcm = 1; /* interlaced field */ else i_fcm = 2; /* interlaced frame */ } } if( i_fcm == 1 ) /*interlaced field */ { /* XXX for mixed I/P we should check reference usage before marking them I (too much work) */ switch( bs_read( &s, 3 ) ) { case 0: /* II */ case 1: /* IP */ case 2: /* PI */ p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; break; case 3: /* PP */ p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; break; case 4: /* BB */ case 5: /* BBi */ case 6: /* BiB */ case 7: /* BiBi */ p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; break; } } else { if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; else if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; else if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; else if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; /* Bi */ else p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; /* P Skip */ } } else { if( p_sys->sh.b_frame_interpolation ) bs_skip( &s, 1 ); // interpolate bs_skip( &s, 2 ); // frame count if( p_sys->sh.b_range_reduction ) bs_skip( &s, 1 ); // range reduction if( bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; else if( !p_sys->sh.b_has_bframe || bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; else p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; } p_sys->b_frame = true; } if( p_release ) block_Release( p_release ); return p_pic; }
static block_t *OutputPicture( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic = NULL; block_t **pp_pic_last = &p_pic; if( unlikely(!p_sys->p_frame) ) { assert( p_sys->p_frame ); return NULL; } /* Bind matched/referred PPS and SPS */ const h264_picture_parameter_set_t *p_pps = p_sys->p_active_pps; const h264_sequence_parameter_set_t *p_sps = p_sys->p_active_sps; if( !p_pps || !p_sps ) { DropStoredNAL( p_sys ); return NULL; } if( !p_sys->b_recovered && p_sys->i_recoveryfnum == UINT_MAX && p_sys->i_recovery_frame_cnt == UINT_MAX && p_sys->slice.type == H264_SLICE_TYPE_I ) { /* No way to recover using SEI, just sync on I Slice */ p_sys->b_recovered = true; } bool b_need_sps_pps = p_sys->slice.type == H264_SLICE_TYPE_I && p_sys->p_active_pps && p_sys->p_active_sps; /* Handle SEI recovery */ if ( !p_sys->b_recovered && p_sys->i_recovery_frame_cnt != UINT_MAX && p_sys->i_recoveryfnum == UINT_MAX ) { p_sys->i_recoveryfnum = p_sys->slice.i_frame_num + p_sys->i_recovery_frame_cnt; b_need_sps_pps = true; /* SPS/PPS must be inserted for SEI recovery */ msg_Dbg( p_dec, "Recovering using SEI, prerolling %u reference pics", p_sys->i_recovery_frame_cnt ); } if( p_sys->i_recoveryfnum != UINT_MAX ) { assert(p_sys->b_recovered == false); const unsigned maxFrameNum = 1 << (p_sps->i_log2_max_frame_num + 4); if( (p_sys->i_recoveryfnum > maxFrameNum && (unsigned)p_sys->slice.i_frame_num <= maxFrameNum / 2 && (unsigned)p_sys->slice.i_frame_num >= p_sys->i_recoveryfnum % maxFrameNum ) || (unsigned)p_sys->slice.i_frame_num >= p_sys->i_recoveryfnum ) { p_sys->i_recoveryfnum = UINT_MAX; p_sys->b_recovered = true; msg_Dbg( p_dec, "Recovery from SEI recovery point complete" ); } } /* Gather PPS/SPS if required */ block_t *p_xpsnal = NULL; block_t **pp_xpsnal_tail = &p_xpsnal; if( b_need_sps_pps || p_sys->b_new_sps || p_sys->b_new_pps ) { for( int i = 0; i <= H264_SPS_ID_MAX && (b_need_sps_pps || p_sys->b_new_sps); i++ ) { if( p_sys->sps[i].p_block ) block_ChainLastAppend( &pp_xpsnal_tail, block_Duplicate( p_sys->sps[i].p_block ) ); } for( int i = 0; i < H264_PPS_ID_MAX && (b_need_sps_pps || p_sys->b_new_pps); i++ ) { if( p_sys->pps[i].p_block ) block_ChainLastAppend( &pp_xpsnal_tail, block_Duplicate( p_sys->pps[i].p_block ) ); } } /* Now rebuild NAL Sequence, inserting PPS/SPS if any */ if( p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD ) { block_t *p_au = p_sys->p_frame; p_sys->p_frame = p_au->p_next; p_au->p_next = NULL; p_au->i_flags &= ~BLOCK_FLAG_PRIVATE_AUD; block_ChainLastAppend( &pp_pic_last, p_au ); } if( p_xpsnal ) block_ChainLastAppend( &pp_pic_last, p_xpsnal ); if( p_sys->p_sei ) block_ChainLastAppend( &pp_pic_last, p_sys->p_sei ); assert( p_sys->p_frame ); if( p_sys->p_frame ) block_ChainLastAppend( &pp_pic_last, p_sys->p_frame ); /* Reset chains, now empty */ p_sys->p_frame = NULL; p_sys->pp_frame_last = &p_sys->p_frame; p_sys->p_sei = NULL; p_sys->pp_sei_last = &p_sys->p_sei; p_pic = block_ChainGather( p_pic ); if( !p_pic ) return NULL; /* for PTS Fixup, interlaced fields (multiple AU/block) */ int tFOC = 0, bFOC = 0, PictureOrderCount = 0; h264_compute_poc( p_sps, &p_sys->slice, &p_sys->pocctx, &PictureOrderCount, &tFOC, &bFOC ); unsigned i_num_clock_ts = h264_get_num_ts( p_sps, &p_sys->slice, p_sys->i_pic_struct, tFOC, bFOC ); if( p_sps->frame_mbs_only_flag == 0 && p_sps->vui.b_pic_struct_present_flag ) { switch( p_sys->i_pic_struct ) { /* Top and Bottom field slices */ case 1: case 2: p_pic->i_flags |= BLOCK_FLAG_SINGLE_FIELD; p_pic->i_flags |= (!p_sys->slice.i_bottom_field_flag) ? BLOCK_FLAG_TOP_FIELD_FIRST : BLOCK_FLAG_BOTTOM_FIELD_FIRST; break; /* Each of the following slices contains multiple fields */ case 3: p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; break; case 4: p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; break; case 5: p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; break; case 6: p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; break; default: break; } } /* set dts/pts to current block timestamps */ p_pic->i_dts = p_sys->i_frame_dts; p_pic->i_pts = p_sys->i_frame_pts; /* Fixup missing timestamps after split (multiple AU/block)*/ if( p_pic->i_dts <= VLC_TS_INVALID ) p_pic->i_dts = date_Get( &p_sys->dts ); if( p_sys->slice.type == H264_SLICE_TYPE_I ) p_sys->prevdatedpoc.pts = VLC_TS_INVALID; if( p_pic->i_pts == VLC_TS_INVALID ) { if( p_sys->prevdatedpoc.pts > VLC_TS_INVALID && date_Get( &p_sys->dts ) != VLC_TS_INVALID ) { date_t pts = p_sys->dts; date_Set( &pts, p_sys->prevdatedpoc.pts ); int diff = tFOC - p_sys->prevdatedpoc.num; if( diff > 0 ) date_Increment( &pts, diff ); else date_Decrement( &pts, -diff ); p_pic->i_pts = date_Get( &pts ); } /* In case there's no PTS at all */ else if( p_sys->slice.i_nal_ref_idc == 0 && p_sys->slice.type == H264_SLICE_TYPE_B ) { p_pic->i_pts = p_pic->i_dts; } else if( p_sys->slice.type == H264_SLICE_TYPE_I && date_Get( &p_sys->dts ) != VLC_TS_INVALID ) { /* Hell no PTS on IDR. We're totally blind */ date_t pts = p_sys->dts; date_Increment( &pts, 2 ); p_pic->i_pts = date_Get( &pts ); } } if( p_pic->i_pts > VLC_TS_INVALID ) { p_sys->prevdatedpoc.pts = p_pic->i_pts; p_sys->prevdatedpoc.num = PictureOrderCount; } if( p_pic->i_length == 0 ) { if( p_sps->vui.i_time_scale ) { p_pic->i_length = CLOCK_FREQ * i_num_clock_ts * p_sps->vui.i_num_units_in_tick / p_sps->vui.i_time_scale; } else { date_t next = p_sys->dts; date_Increment( &next, i_num_clock_ts ); p_pic->i_length = date_Get( &next ) - date_Get( &p_sys->dts ); } } #if 0 msg_Err(p_dec, "F/BOC %d/%d POC %d %d rec %d flags %x ref%d fn %d fp %d %d pts %ld len %ld", tFOC, bFOC, PictureOrderCount, p_sys->slice.type, p_sys->b_recovered, p_pic->i_flags, p_sys->slice.i_nal_ref_idc, p_sys->slice.i_frame_num, p_sys->slice.i_field_pic_flag, p_pic->i_pts - p_pic->i_dts, p_pic->i_pts % (100*CLOCK_FREQ), p_pic->i_length); #endif /* save for next pic fixups */ if( date_Get( &p_sys->dts ) != VLC_TS_INVALID ) { if( p_sys->i_next_block_flags & BLOCK_FLAG_DISCONTINUITY ) date_Set( &p_sys->dts, VLC_TS_INVALID ); else date_Increment( &p_sys->dts, i_num_clock_ts ); } if( p_pic ) { p_pic->i_flags |= p_sys->i_next_block_flags; p_sys->i_next_block_flags = 0; } switch( p_sys->slice.type ) { case H264_SLICE_TYPE_P: p_pic->i_flags |= BLOCK_FLAG_TYPE_P; break; case H264_SLICE_TYPE_B: p_pic->i_flags |= BLOCK_FLAG_TYPE_B; break; case H264_SLICE_TYPE_I: p_pic->i_flags |= BLOCK_FLAG_TYPE_I; default: break; } if( !p_sys->b_recovered ) { if( p_sys->i_recoveryfnum != UINT_MAX ) /* recovering from SEI */ p_pic->i_flags |= BLOCK_FLAG_PREROLL; else p_pic->i_flags |= BLOCK_FLAG_DROP; } p_pic->i_flags &= ~BLOCK_FLAG_PRIVATE_AUD; /* reset after output */ p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->i_dpb_output_delay = 0; p_sys->i_pic_struct = UINT8_MAX; p_sys->i_recovery_frame_cnt = UINT_MAX; p_sys->slice.type = H264_SLICE_TYPE_UNKNOWN; p_sys->p_sei = NULL; p_sys->pp_sei_last = &p_sys->p_sei; p_sys->b_new_sps = false; p_sys->b_new_pps = false; p_sys->b_slice = false; /* CC */ cc_storage_commit( p_sys->p_ccs, p_pic ); return p_pic; }
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->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 && p_sys->b_sps && p_sys->b_pps; if( b_sps_pps_i || p_sys->b_frame_sps || p_sys->b_frame_pps ) { block_t *p_head = NULL; if( p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD ) { p_head = p_sys->p_frame; p_sys->p_frame = p_sys->p_frame->p_next; } block_t *p_list = NULL; for( int i = 0; i < SPS_MAX && (b_sps_pps_i || p_sys->b_frame_sps); i++ ) { if( p_sys->pp_sps[i] ) block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_sps[i] ) ); } for( int i = 0; i < PPS_MAX && (b_sps_pps_i || p_sys->b_frame_pps); i++ ) { if( p_sys->pp_pps[i] ) block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_pps[i] ) ); } if( b_sps_pps_i && p_list ) p_sys->b_header = true; if( p_head ) p_head->p_next = p_list; else p_head = p_list; block_ChainAppend( &p_head, p_sys->p_frame ); p_pic = block_ChainGather( p_head ); } else { p_pic = block_ChainGather( p_sys->p_frame ); } p_pic->i_dts = p_sys->i_frame_dts; p_pic->i_pts = p_sys->i_frame_pts; 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; if( p_sys->b_frame_mbs_only == 0 && p_sys->b_pic_struct_present_flag ) { switch( p_sys->i_pic_struct ) { case 1: if( p_sys->i_fields_dts == 2 ) p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; else p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; break; case 3: case 5: p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; break; case 2: if( p_sys->i_fields_dts == 2 ) p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; else p_pic->i_flags |= BLOCK_FLAG_TOP_FIELD_FIRST; break; case 4: case 6: p_pic->i_flags |= BLOCK_FLAG_BOTTOM_FIELD_FIRST; break; default: break; } } p_sys->i_fields_dts -= (1 + p_sys->b_frame_mbs_only); if( p_sys->i_fields_dts <= 0 ) { p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; } else if( p_sys->b_timing_info_present_flag && p_sys->i_time_scale ) { p_sys->i_frame_pts += CLOCK_FREQ * p_sys->i_num_units_in_tick / p_sys->i_time_scale; } else p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->slice.i_frame_type = 0; p_sys->p_frame = NULL; p_sys->b_frame_sps = false; p_sys->b_frame_pps = false; p_sys->b_slice = false; /* CC */ p_sys->i_cc_pts = p_pic->i_pts; p_sys->i_cc_dts = p_pic->i_dts; p_sys->i_cc_flags = p_pic->i_flags; p_sys->cc = p_sys->cc_next; cc_Flush( &p_sys->cc_next ); return p_pic; }