示例#1
0
/****************************************************************************
 * 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;

    block_BytestreamPush( &p_sys->bytestream, *pp_block );

    for( ;; )
    {
        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;
                }

                /* Get the new fragment and set the pts/dts */
                p_pic = block_New( p_dec, p_sys->i_offset +1 );
                p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
                p_pic->i_dts = p_sys->bytestream.p_block->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 */
                if( !( p_pic = ParseNALBlock( p_dec, p_pic ) ) )
                {
                    p_sys->i_state = STATE_NOSYNC;
                    break;
                }
#if 0
                msg_Dbg( p_dec, "pts="I64Fd" dts="I64Fd,
                         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;
        }
    }
}
示例#2
0
/*****************************************************************************
 * Packetize:
 *****************************************************************************/
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 == NULL || *pp_block == NULL )
    {
        return NULL;
    }

    if( (*pp_block)->i_flags & BLOCK_FLAG_DISCONTINUITY )
    {
        p_sys->i_state = STATE_NOSYNC;
        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 = VLC_FALSE;
        block_Release( *pp_block );
        return NULL;
    }

    block_BytestreamPush( &p_sys->bytestream, *pp_block );

    while( 1 )
    {
        switch( p_sys->i_state )
        {

        case STATE_NOSYNC:
            if( block_FindStartcodeFromOffset( &p_sys->bytestream,
                    &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS )
            {
                p_sys->i_state = STATE_NEXT_SYNC;
            }

            if( p_sys->i_offset )
            {
                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:
            /* TODO: If p_block == NULL, flush the buffer without checking the
             * next sync word */

            /* Find the next startcode */
            if( block_FindStartcodeFromOffset( &p_sys->bytestream,
                    &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }

            /* Get the new fragment and set the pts/dts */
            p_pic = block_New( p_dec, p_sys->i_offset );
            block_BytestreamFlush( &p_sys->bytestream );
            p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
            p_pic->i_dts = p_sys->bytestream.p_block->i_dts;

            block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
                            p_pic->i_buffer );

            /* don't reuse the same timestamps several times */
            if( p_pic->i_buffer >= 4 && p_pic->p_buffer[3] == 0x00 )
            {
                /* We have a picture start code */
                p_sys->bytestream.p_block->i_pts = 0;
                p_sys->bytestream.p_block->i_dts = 0;
            }

            p_sys->i_offset = 0;

            /* Get picture if any */
            if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) )
            {
                p_sys->i_state = STATE_NOSYNC;
                break;
            }

            /* We've just started the stream, wait for the first PTS.
             * We discard here so we can still get the sequence header. */
            if( p_sys->i_dts <= 0 && p_sys->i_pts <= 0 &&
                p_sys->i_interpolated_dts <= 0 )
            {
                msg_Dbg( p_dec, "need a starting pts/dts" );
                p_sys->i_state = STATE_NOSYNC;
                block_Release( p_pic );
                break;
            }

            /* When starting the stream we can have the first frame with
             * a null DTS (i_interpolated_pts is initialized to 0) */
            if( !p_pic->i_dts ) p_pic->i_dts = p_pic->i_pts;

            /* 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;
        }
    }
}
示例#3
0
文件: dirac.c 项目: AsamQi/vlc
/***
 * Bytestream synchronizer
 * maps [Bytes] -> DataUnit
 */
static block_t *dirac_DoSync( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    parse_info_t pu;

    static const uint8_t p_parsecode[4] = {'B','B','C','D'};
    do {
        switch( p_sys->i_state )
        {
        case NOT_SYNCED:
        {
            if( VLC_SUCCESS !=
                block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_parsecode, 4 ) )
            {
                /* p_sys->i_offset will have been set to:
                 *   end of bytestream - amount of prefix found
                 * can resume search from this point when more data arrives */
                return NULL;
            }
            /* candidate parse_code_prefix has been found at p_sys->i_offset */
            if( VLC_SUCCESS != block_PeekOffsetBytes( &p_sys->bytestream, p_sys->i_offset + 12, NULL, 0 ) )
            {
                /* insufficient data has been accumulated to fully extract
                 * a parse_info header. exit for now in the hope of more
                 * data later to retry at exactly the same point */
                return NULL;
            }
            p_sys->i_state = TRY_SYNC;
            break; /* candidate found, try to sync */
        }
        case SYNCED: /* -> TRY_SYNC | NOT_SYNCED */
            /* sanity: can only reach this after having extracted a DU,
             * which causes data to be consumed and local i_offset to be reset */
            assert( p_sys->i_offset == 0 );
            if( VLC_SUCCESS != block_PeekOffsetBytes( &p_sys->bytestream, 12, NULL, 0 ) )
            {
                /* insufficient data has been accumulated to fully extract
                 * a parse_info header, retry later */
                return NULL;
            }
            if( !dirac_UnpackParseInfo( &pu, &p_sys->bytestream, 0 )
             || !pu.u_next_offset || (p_sys->u_last_npo != pu.u_prev_offset) )
            {
                /* !a: not a valid parse info.
                 * !pu.u_next_offset: don't know the length of the data unit
                 *                    search for the next one that points back
                 *                    to this one to determine length.
                 * (p_sys->u_last_npo != pu.u_prev_offset): some desync
                 */
                p_sys->i_state = NOT_SYNCED;
                break;
            }
            if( pu.u_next_offset > 1024*1024 )
            {
                /* sanity check for erronious hugs next_parse_offsets
                 * (eg, 2^32-1) that would cause a very long wait
                 * and large space consumption: fall back to try sync */
                p_sys->i_state = TRY_SYNC;
                break;
            }
            /* check that the start of the next data unit is avaliable */
            if( VLC_SUCCESS !=
                block_PeekOffsetBytes( &p_sys->bytestream, pu.u_next_offset + 12, NULL, 0 ) )
            {
                return NULL; /* retry later */
            }
            /* attempt to synchronise backwards from pu.u_next_offset */
            p_sys->i_offset = pu.u_next_offset;
            /* fall through */
        case TRY_SYNC: /* -> SYNCED | NOT_SYNCED */
        {
            if( !p_sys->i_offset )
                goto sync_fail; /* if a is at start of bytestream, b can't be in buffer */

            parse_info_t pu_a;
            bool a = dirac_UnpackParseInfo( &pu_a, &p_sys->bytestream, p_sys->i_offset );
            if( !a || (pu_a.u_prev_offset > p_sys->i_offset) )
                goto sync_fail; /* b lies beyond start of bytestream: can't sync */

            if( !pu_a.u_prev_offset )
            {
                if( p_sys->i_state == TRY_SYNC )
                {
                    goto sync_fail; /* can't find different pu_b from pu_a */
                }
                /* state == SYNCED: already know where pu_b is.
                 * pu_a has probably been inserted by something that doesn't
                 * know what the last next_parse_offset was */
                pu_a.u_prev_offset = pu.u_next_offset;
            }

            parse_info_t *pu_b = &pu;
            bool b = dirac_UnpackParseInfo( pu_b, &p_sys->bytestream, p_sys->i_offset - pu_a.u_prev_offset );
            if( !b || (pu_b->u_next_offset && pu_a.u_prev_offset != pu_b->u_next_offset) )
            {
                /* if pu_b->u_next_offset = 0, have to assume we've synced, ie,
                 * just rely on finding a valid pu_b from pu_a. */
                goto sync_fail;
            }
            p_sys->u_last_npo = pu_b->u_next_offset;
            if( !pu_b->u_next_offset ) pu_b->u_next_offset = pu_a.u_prev_offset;
            /* offset was pointing at pu_a, rewind to point at pu_b */
            p_sys->i_offset -= pu_a.u_prev_offset;
            p_sys->i_state = SYNCED;
            break;
        }
sync_fail:
            if( p_sys->i_state == SYNCED ) p_sys->i_offset = 0;
            p_sys->i_offset++;
            p_sys->i_state = NOT_SYNCED;
            break; /* find somewhere else to try again */
        default:;
        }
    } while( SYNCED != p_sys->i_state );

    /*
     * synced, attempt to extract a data unit
     */

    /* recover any timestamps from the data that is about to be flushed */
    dirac_RecoverTimestamps( p_dec, p_sys->i_offset );

    /* flush everything up to the start of the DU */
    block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
    block_BytestreamFlush( &p_sys->bytestream );
    p_sys->i_offset = 0;

    /* setup the data unit buffer */
    block_t *p_block = block_Alloc( pu.u_next_offset );
    if( !p_block )
        return NULL;

    p_block->i_pts = p_sys->i_sync_pts;
    p_block->i_dts = p_sys->i_sync_dts;
    p_sys->i_sync_pts = p_sys->i_sync_dts = VLC_TS_INVALID;

    /* recover any new timestamps from the data that is about to be consumed */
    dirac_RecoverTimestamps( p_dec, p_sys->i_offset );

    block_GetBytes( &p_sys->bytestream, p_block->p_buffer, p_block->i_buffer );

    /* save parse offset in private area for later use */
    dirac_block_encap_t *p_dbe = dirac_NewBlockEncap( &p_block );
    if( p_dbe ) p_dbe->u_last_next_offset = pu.u_next_offset;

    return p_block;
}
示例#4
0
文件: h264.c 项目: sdelmas/SDesk
/****************************************************************************
 * Packetize: the whole thing
 ****************************************************************************/
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;

    block_BytestreamPush( &p_sys->bytestream, *pp_block );

    for( ;; )
    {
        switch( p_sys->i_state )
        {
        case STATE_NOSYNC:
            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 )
            {
                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 startcode */
            if( block_FindStartcodeFromOffset( &p_sys->bytestream,
                                               &p_sys->i_offset, p_sys->startcode, 3 ) != VLC_SUCCESS)
            {
                if( block_FindStartcodeFromOffset( &p_sys->bytestream,
                                                   &p_sys->i_offset, p_sys->startcode+1, 3 ) !=
                        VLC_SUCCESS )
                {
                    /* Need more data */
                    return NULL;
                }
            }

            /* Get the new fragment and set the pts/dts */
            p_pic = block_New( p_dec, p_sys->i_offset );
            p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
            p_pic->i_dts = p_sys->bytestream.p_block->i_dts;

            block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
                            p_pic->i_buffer );

            p_sys->i_offset = 0;

            /* Parse the NAL */
            if( !( p_pic = ParseNALBlock( p_dec, p_pic ) ) )
            {
                p_sys->i_state = STATE_NOSYNC;
                break;
            }

            /* 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;
        }
    }
}