/***************************************************************************** * 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; int i; const bool b_avc = (p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'a', 'v', 'c', '1' )); if( p_dec->fmt_in.i_codec != VLC_CODEC_H264 ) return VLC_EGENERIC; if( b_avc && 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 ) { return VLC_ENOMEM; } p_sys->p_ccs = cc_storage_new(); if( unlikely(!p_sys->p_ccs) ) { free( p_dec->p_sys ); return VLC_ENOMEM; } packetizer_Init( &p_sys->packetizer, p_h264_startcode, sizeof(p_h264_startcode), startcode_FindAnnexB, p_h264_startcode, 1, 5, PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); p_sys->b_slice = false; 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_header= false; p_sys->b_sps = false; p_sys->b_pps = false; for( i = 0; i <= H264_SPS_ID_MAX; i++ ) p_sys->pp_sps[i] = NULL; for( i = 0; i <= H264_PPS_ID_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; 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; p_sys->b_timing_info_present_flag = false; p_sys->b_pic_struct_present_flag = false; p_sys->b_cpb_dpb_delays_present_flag = false; p_sys->i_cpb_removal_delay_length_minus1 = 0; p_sys->i_dpb_output_delay_length_minus1 = 0; p_sys->b_even_frame = false; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->i_prev_dts = VLC_TS_INVALID; p_sys->i_prev_pts = VLC_TS_INVALID; p_sys->i_dpb_output_delay = 0; /* Setup properties */ es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->fmt_out.i_codec = VLC_CODEC_H264; p_dec->fmt_out.b_packetized = true; if( b_avc ) { /* 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 */ if( h264_isavcC( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ) ) { free( p_dec->fmt_out.p_extra ); size_t i_size; p_dec->fmt_out.p_extra = h264_avcC_to_AnnexB_NAL( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_size, &p_sys->i_avcC_length_size ); p_dec->fmt_out.i_extra = i_size; p_sys->b_header = !!p_dec->fmt_out.i_extra; if(!p_dec->fmt_out.p_extra) { msg_Err( p_dec, "Invalid AVC extradata"); Close( p_this ); return VLC_EGENERIC; } } else { msg_Err( p_dec, "Invalid or missing AVC extradata"); Close( p_this ); return VLC_EGENERIC; } /* 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_out.i_extra > 0 ) { packetizer_Header( &p_sys->packetizer, p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); } if( b_avc ) { if( !p_sys->b_sps || !p_sys->b_pps ) { msg_Err( p_dec, "Invalid or missing SPS %d or PPS %d in AVC extradata", p_sys->b_sps, p_sys->b_pps ); Close( p_this ); return VLC_EGENERIC; } msg_Dbg( p_dec, "Packetizer fed with AVC, nal length size=%d", p_sys->i_avcC_length_size ); } /* CC are the same for H264/AVC in T35 sections (ETSI TS 101 154) */ p_dec->pf_get_cc = GetCc; p_dec->pf_flush = PacketizeFlush; return VLC_SUCCESS; }
static int InitializeMFT(decoder_t *p_dec) { decoder_sys_t *p_sys = p_dec->p_sys; HRESULT hr; IMFAttributes *attributes = NULL; hr = IMFTransform_GetAttributes(p_sys->mft, &attributes); if (hr != E_NOTIMPL && FAILED(hr)) goto error; if (SUCCEEDED(hr)) { UINT32 is_async = false; hr = IMFAttributes_GetUINT32(attributes, &MF_TRANSFORM_ASYNC, &is_async); if (hr != MF_E_ATTRIBUTENOTFOUND && FAILED(hr)) goto error; p_sys->is_async = is_async; if (p_sys->is_async) { hr = IMFAttributes_SetUINT32(attributes, &MF_TRANSFORM_ASYNC_UNLOCK, true); if (FAILED(hr)) goto error; hr = IMFTransform_QueryInterface(p_sys->mft, &IID_IMFMediaEventGenerator, (void**)&p_sys->event_generator); if (FAILED(hr)) goto error; } } DWORD input_streams_count; DWORD output_streams_count; hr = IMFTransform_GetStreamCount(p_sys->mft, &input_streams_count, &output_streams_count); if (FAILED(hr)) goto error; if (input_streams_count != 1 || output_streams_count != 1) { msg_Err(p_dec, "MFT decoder should have 1 input stream and 1 output stream."); goto error; } hr = IMFTransform_GetStreamIDs(p_sys->mft, 1, &p_sys->input_stream_id, 1, &p_sys->output_stream_id); if (hr == E_NOTIMPL) { /* * This is not an error, it happens if: * - there is a fixed number of streams. * AND * - streams are numbered consecutively from 0 to N-1. */ p_sys->input_stream_id = 0; p_sys->output_stream_id = 0; } else if (FAILED(hr)) goto error; if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type)) goto error; if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type)) goto error; /* * The input type was not set by the previous call to * SetInputType, try again after setting the output type. */ if (!p_sys->input_type) if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type) || !p_sys->input_type) goto error; /* This call can be a no-op for some MFT decoders, but it can potentially reduce starting time. */ hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, (ULONG_PTR)0); if (FAILED(hr)) goto error; /* This event is required for asynchronous MFTs, optional otherwise. */ hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, (ULONG_PTR)0); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_codec == VLC_CODEC_H264) { /* It's not an error if the following call fails. */ IMFAttributes_SetUINT32(attributes, &CODECAPI_AVLowLatencyMode, true); if (p_dec->fmt_in.i_extra) { if (h264_isavcC((uint8_t*)p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra)) { size_t i_buf; uint8_t *buf = h264_avcC_to_AnnexB_NAL(p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_buf, &p_sys->nal_length_size); if(buf) { free(p_dec->fmt_in.p_extra); p_dec->fmt_in.p_extra = buf; p_dec->fmt_in.i_extra = i_buf; } } } } return VLC_SUCCESS; error: msg_Err(p_dec, "Error in InitializeMFT()"); DestroyMFT(p_dec); return VLC_EGENERIC; }
/***************************************************************************** * 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; int i; const bool b_avc = (p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'a', 'v', 'c', '1' )); if( p_dec->fmt_in.i_codec != VLC_CODEC_H264 ) return VLC_EGENERIC; if( b_avc && 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 ) { return VLC_ENOMEM; } p_sys->p_ccs = cc_storage_new(); if( unlikely(!p_sys->p_ccs) ) { free( p_dec->p_sys ); return VLC_ENOMEM; } packetizer_Init( &p_sys->packetizer, p_h264_startcode, sizeof(p_h264_startcode), startcode_FindAnnexB, p_h264_startcode, 1, 5, PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); p_sys->b_slice = false; 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_sys->b_new_sps = false; p_sys->b_new_pps = false; for( i = 0; i <= H264_SPS_ID_MAX; i++ ) { p_sys->sps[i].p_sps = NULL; p_sys->sps[i].p_block = NULL; } p_sys->p_active_sps = NULL; for( i = 0; i <= H264_PPS_ID_MAX; i++ ) { p_sys->pps[i].p_pps = NULL; p_sys->pps[i].p_block = NULL; } p_sys->p_active_pps = NULL; p_sys->i_recovery_frame_cnt = UINT_MAX; h264_slice_init( &p_sys->slice ); p_sys->i_next_block_flags = 0; p_sys->b_recovered = false; p_sys->i_recoveryfnum = UINT_MAX; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->i_dpb_output_delay = 0; /* POC */ h264_poc_context_init( &p_sys->pocctx ); p_sys->prevdatedpoc.pts = VLC_TS_INVALID; date_Init( &p_sys->dts, 30000 * 2, 1001 ); date_Set( &p_sys->dts, VLC_TS_INVALID ); /* Setup properties */ es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->fmt_out.i_codec = VLC_CODEC_H264; p_dec->fmt_out.b_packetized = true; if( p_dec->fmt_in.video.i_frame_rate_base && p_dec->fmt_in.video.i_frame_rate && p_dec->fmt_in.video.i_frame_rate <= UINT_MAX / 2 ) { date_Change( &p_sys->dts, p_dec->fmt_in.video.i_frame_rate * 2, p_dec->fmt_in.video.i_frame_rate_base ); } if( b_avc ) { /* 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 */ if( h264_isavcC( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ) ) { free( p_dec->fmt_out.p_extra ); size_t i_size; p_dec->fmt_out.p_extra = h264_avcC_to_AnnexB_NAL( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_size, &p_sys->i_avcC_length_size ); p_dec->fmt_out.i_extra = i_size; p_sys->b_recovered = !!p_dec->fmt_out.i_extra; if(!p_dec->fmt_out.p_extra) { msg_Err( p_dec, "Invalid AVC extradata"); Close( p_this ); return VLC_EGENERIC; } } else { msg_Err( p_dec, "Invalid or missing AVC extradata"); Close( p_this ); return VLC_EGENERIC; } /* 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_out.i_extra > 0 ) { packetizer_Header( &p_sys->packetizer, p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); } if( b_avc ) { /* FIXME: that's not correct for every AVC */ if( !p_sys->b_new_pps || !p_sys->b_new_sps ) { msg_Err( p_dec, "Invalid or missing SPS %d or PPS %d in AVC extradata", p_sys->b_new_sps, p_sys->b_new_pps ); Close( p_this ); return VLC_EGENERIC; } msg_Dbg( p_dec, "Packetizer fed with AVC, nal length size=%d", p_sys->i_avcC_length_size ); } /* CC are the same for H264/AVC in T35 sections (ETSI TS 101 154) */ p_dec->pf_get_cc = GetCc; p_dec->pf_flush = PacketizeFlush; return VLC_SUCCESS; }