예제 #1
0
파일: timecode.c 프로젝트: IAPark/vlc
static int Control (demux_t *demux, int query, va_list args)
{
    demux_sys_t *sys = demux->p_sys;

    switch (query)
    {
        case DEMUX_GET_POSITION:
            *va_arg (args, float *) = 0.f;
            break;

        case DEMUX_GET_LENGTH:
            *va_arg (args, int64_t *) = INT64_C(0);
            break;

        case DEMUX_GET_TIME:
            *va_arg (args, int64_t *) = date_Get (&sys->date);
            break;

        case DEMUX_SET_TIME:
            date_Set (&sys->date, va_arg (args, int64_t));
            break;

        case DEMUX_SET_NEXT_DEMUX_TIME:
        {
            const mtime_t pts = va_arg (args, int64_t );

            if (sys->next_time == VLC_TS_INVALID) /* first invocation? */
            {
                date_Set (&sys->date, pts);
                date_Decrement (&sys->date, 1);
            }
            sys->next_time = pts;
            break;
        }

        case DEMUX_GET_PTS_DELAY:
        {
            int64_t *v = va_arg (args, int64_t *);
            *v = INT64_C(1000) * var_InheritInteger (demux, "live-caching");
            break;
        }

        case DEMUX_CAN_PAUSE:
        case DEMUX_CAN_CONTROL_PACE:
        case DEMUX_CAN_SEEK:
            *va_arg (args, bool *) = true;
            break;

        default:
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}
예제 #2
0
파일: dirac.c 프로젝트: AsamQi/vlc
/* backdate the list [p_block .. p_block->p_next where p_next == p_last] */
static void dirac_BackdateDTS( block_t *p_block, block_t *p_last, date_t *p_dts )
{
    /* Transverse p_last backwards.  (no p_prev anymore) */
    block_t **pp_array = NULL;
    int n = block_ChainToArray( p_block, &pp_array );
    while( n ) if( pp_array[--n] == p_last ) break;
    /* want to start at p_last->p_prev */
    while( n-- )
    {
        if( pp_array[n]->i_flags & DIRAC_NON_DATED )
            continue;
        if( pp_array[n]->i_dts <= VLC_TS_INVALID )
            pp_array[n]->i_dts = date_Decrement( p_dts, 1 );
    }
    free( pp_array );
}
예제 #3
0
파일: dirac.c 프로젝트: AsamQi/vlc
/* backdate the list [p_block .. p_block->p_next where p_next == p_last] */
static void dirac_BackdatePTS( block_t *p_block, block_t *p_last, date_t *p_pts, uint32_t u_pts_picnum )
{
    /* Transverse p_last backwards.  (no p_prev anymore) */
    block_t **pp_array = NULL;
    int n = block_ChainToArray( p_block, &pp_array );
    while( n ) if( pp_array[--n] == p_last ) break;
    /* want to start at p_last->p_prev */
    while( n-- )
    {
        if( pp_array[n]->i_flags & DIRAC_NON_DATED )
            continue;
        if( pp_array[n]->i_dts > VLC_TS_INVALID )
            continue;
        dirac_block_encap_t *dbe = dirac_GetBlockEncap( pp_array[n] );
        int32_t u_pic_num = dbe ? dbe->u_picture_number : 0;
        int32_t i_dist = u_pic_num - u_pts_picnum;
        date_t pts = *p_pts;
        if( i_dist >= 0 )
            pp_array[n]->i_pts = date_Increment( &pts, i_dist );
        else
            pp_array[n]->i_pts = date_Decrement( &pts, -i_dist );
    }
    free( pp_array );
}
예제 #4
0
파일: dirac.c 프로젝트: AsamQi/vlc
/**
 * dirac_TimeGenPush:
 * @p_dec: vlc object
 * @p_block_in: whole encapsulation unit to generate timestamps for
 *
 * Returns:
 *  0: everything ok
 *  1: EOS occurred, please flush and reset
 *  2: picture number discontinuity, please flush and reset
 */
static int dirac_TimeGenPush( decoder_t *p_dec, block_t *p_block_in )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    dirac_block_encap_t *p_dbe;

    if( p_block_in->i_flags & BLOCK_FLAG_END_OF_SEQUENCE )
    {
        /* NB, this test occurs after the timegen push, so as to
         * push the block into the output queue */
        return 1;
    }

    if( p_block_in->i_flags & DIRAC_NON_DATED )
    {
        /* no picture found, which means p_block_in is a non-dated EU,
         * do not try and put a date on it */
        return 0;
    }

    p_dbe = dirac_GetBlockEncap( p_block_in );
    uint32_t u_picnum = p_dbe ? p_dbe->u_picture_number : 0;
    /*
     * Simple DTS regeneration:
     *  - DTS values linearly increase in stream order.
     *  - Every time a DTS occurs at the input, sync to it
     *    - If this is the first DTS seen, backdate all the previous ones that are undated
     *  - If a DTS is missing, guess that it increases by one picture period
     *  - If never seen DTS, don't do anything
     */
    /*
     * Simple PTS regeneration
     *  - PTS values do not linearly increase in stream order.
     *  - Every time a PTS occurs at the input, sync to it and record picture number
     *  - If a PTS is missing, guess that it differs by the product of picture
     *    period and difference between picture number of sync point and current picture
     *  - If this is the first PTS seen, backdate all previous ones that are undated
     *  - If never seen PTS, don't do anything
     */
    /*
     * Stage 1, sync to input timestamps, backdate timestamps for old
     * EUs that are in the outqueue with missing dates
     */
    if( p_block_in->i_dts > VLC_TS_INVALID )
    do {
        /* if timestamps exist, sync to them */
        if( p_sys->b_dts )
            break;
        /* first dts seen, backdate any packets in outqueue */
        p_sys->b_dts = true;
        date_t dts = p_sys->dts;
        dirac_BackdateDTS( p_sys->p_outqueue, p_block_in, &dts );
    } while( 0 );

    if( p_block_in->i_pts > VLC_TS_INVALID )
    do {
        /* if timestamps exist, sync to them */
        p_sys->u_pts_picnum = u_picnum;
        p_sys->i_pts = p_block_in->i_pts;
        if( p_sys->b_pts )
            break;
        /* first pts seen, backdate any packets in outqueue */
        p_sys->b_pts = true;
        date_t pts = p_sys->dts;
        date_Set( &pts, p_sys->i_pts );
        dirac_BackdatePTS( p_sys->p_outqueue, p_block_in, &pts, p_sys->u_pts_picnum );
    } while( 0 );

    /*
     * Stage 2, don't attempt to forwards interpolate timestamps for
     * blocks if the picture rates aren't known
     */
    if( !p_sys->b_seen_seq_hdr )
    {
        return 0;
    }

    /*
     * Stage 3, for block_in, interpolate any missing timestamps
     */
    if( p_sys->b_dts && p_block_in->i_dts <= VLC_TS_INVALID )
    {
        /* dts has previously been seen, but not this time, interpolate */
        p_block_in->i_dts = date_Increment( &p_sys->dts, 1 );
    }

    if( p_sys->b_pts && p_block_in->i_pts <= VLC_TS_INVALID )
    {
        /* pts has previously been seen, but not this time, interpolate */
        date_t pts = p_sys->dts;
        date_Set( &pts, p_sys->i_pts );
        int32_t i_dist = u_picnum - p_sys->u_pts_picnum;
        if( i_dist >= 0 )
            p_block_in->i_pts = date_Increment( &pts, i_dist );
        else
            p_block_in->i_pts = date_Decrement( &pts, -i_dist );
    }

    /* If pts and dts have been seen, there is no need to simulate operation
     * of the decoder reorder buffer */
    /* If neither have been seen, there is little point in simulating */
    if( p_sys->b_dts == p_sys->b_pts )
        return 0;

    if( !p_sys->p_out_dts )
        p_sys->p_out_dts = p_sys->p_outqueue;

    /* model the reorder buffer */
    block_t *p_block = dirac_Reorder( p_dec, p_block_in, u_picnum );
    if( !p_block )
        return 0;

    /* A future ehancement is to stop modeling the reorder buffer as soon as
     * the first packet is output -- interpolate the past and freewheel for
     * the future */

    p_dbe = dirac_GetBlockEncap( p_block );
    u_picnum = p_dbe ? p_dbe->u_picture_number : 0;
    if( p_sys->b_tg_last_picnum )
    {
        if( dirac_PictureNbeforeM( u_picnum, p_sys->u_tg_last_picnum ) )
        {
            msg_Warn( p_dec, "stream jumped? %d < %d: resetting"
                    , u_picnum, p_sys->u_tg_last_picnum );
            /* pictures only emerge from the reorder buffer in sequence
             * if a stream suddenly jumped backwards without a signaling
             * a discontinuity, some pictures will get stuck in the RoB.
             * flush the RoB. */
            /* this could be a bit less indiscriminate */
            p_dbe = dirac_GetBlockEncap( p_sys->p_outqueue );
            uint32_t u_prev_parse_offset = p_dbe ? p_dbe->u_last_next_offset : 0;
            block_ChainRelease( p_sys->p_outqueue );
            p_sys->p_outqueue = dirac_EmitEOS( p_dec, u_prev_parse_offset );
            if( p_sys->p_outqueue )
                p_sys->p_outqueue->i_flags = BLOCK_FLAG_DISCONTINUITY | DIRAC_NON_DATED;
            /* return 2, so as not to reset the b_dts flags -- needed if
             * using the rawdirac demuxer with broken stream */
            return 2;
        }
    }
    p_sys->b_tg_last_picnum = true;
    p_sys->u_tg_last_picnum = u_picnum;

    if( !p_sys->b_pts )
    {
        /* some demuxers (eg, AVI) will provide a series of fake dts values,
         * which are actually inorder pts values (ie, what should be seen at
         * the output of a decoder.  A main reason for simulating the reorder
         * buffer is to turn the inorder fakedts into an out-of-order pts */
        p_block->i_pts = p_sys->p_out_dts->i_dts;
        p_sys->p_out_dts->i_dts = VLC_TS_INVALID;
    }

    /* If pts was copied from dts, the dts needs to be corrected to account for reordering*/
    /* If dts has never been seen, the same needs to happen */
    p_sys->p_out_dts->i_dts = p_block->i_pts - p_sys->i_pts_offset;

    /* move dts pointer */
    if( p_sys->p_out_dts )
        p_sys->p_out_dts = p_sys->p_out_dts->p_next;

    return 0;
}
예제 #5
0
파일: h264.c 프로젝트: IAPark/vlc
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;
}