コード例 #1
0
ファイル: h264.c プロジェクト: r1k/vlc
/*****************************************************************************
 * 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;
}
コード例 #2
0
ファイル: mft.c プロジェクト: IAPark/vlc
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;
}
コード例 #3
0
ファイル: h264.c プロジェクト: IAPark/vlc
/*****************************************************************************
 * 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;
}