Exemplo n.º 1
0
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************/
static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    uint8_t p_header[DTS_HEADER_SIZE];
    uint8_t *p_buf;
    block_t *p_out_buffer;

    if( !pp_block || !*pp_block )
        return NULL;

    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
    {
        if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
        {
            p_sys->i_state = STATE_NOSYNC;
            block_BytestreamEmpty( &p_sys->bytestream );
        }
        date_Set( &p_sys->end_date, 0 );
        block_Release( *pp_block );
        return NULL;
    }

    if( !date_Get( &p_sys->end_date ) && (*pp_block)->i_pts <= VLC_TS_INVALID )
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( *pp_block );
        return NULL;
    }

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

    while( 1 )
    {
        switch( p_sys->i_state )
        {
        case STATE_NOSYNC:
            /* Look for sync code - should be 0x7ffe8001 */
            while( block_PeekBytes( &p_sys->bytestream, p_header, 6 )
                   == VLC_SUCCESS )
            {
                if( SyncCode( p_header ) == VLC_SUCCESS )
                {
                    p_sys->i_state = STATE_SYNC;
                    break;
                }
                block_SkipByte( &p_sys->bytestream );
            }
            if( p_sys->i_state != STATE_SYNC )
            {
                block_BytestreamFlush( &p_sys->bytestream );

                /* Need more data */
                return NULL;
            }

        case STATE_SYNC:
            /* New frame, set the Presentation Time Stamp */
            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
            if( p_sys->i_pts > VLC_TS_INVALID &&
                p_sys->i_pts != date_Get( &p_sys->end_date ) )
            {
                date_Set( &p_sys->end_date, p_sys->i_pts );
            }
            p_sys->i_state = STATE_HEADER;

        case STATE_HEADER:
            /* Get DTS frame header (DTS_HEADER_SIZE bytes) */
            if( block_PeekBytes( &p_sys->bytestream, p_header,
                                 DTS_HEADER_SIZE ) != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }

            /* Check if frame is valid and get frame info */
            p_sys->i_frame_size = SyncInfo( p_header,
                                            &p_sys->b_dts_hd,
                                            &p_sys->i_channels,
                                            &p_sys->i_channels_conf,
                                            &p_sys->i_rate,
                                            &p_sys->i_bit_rate,
                                            &p_sys->i_frame_length );
            if( !p_sys->i_frame_size )
            {
                msg_Dbg( p_dec, "emulated sync word" );
                block_SkipByte( &p_sys->bytestream );
                p_sys->i_state = STATE_NOSYNC;
                break;
            }
            p_sys->i_state = STATE_NEXT_SYNC;

        case STATE_NEXT_SYNC:
            /* TODO: If pp_block == NULL, flush the buffer without checking the
             * next sync word */

            /* Check if next expected frame contains the sync word */
            if( block_PeekOffsetBytes( &p_sys->bytestream,
                                       p_sys->i_frame_size, p_header, 6 )
                != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }

            if( p_sys->b_packetizer &&
                p_header[0] == 0 && p_header[1] == 0 )
            {
                /* DTS wav files and audio CD's use stuffing */
                p_sys->i_state = STATE_SEND_DATA;
                break;
            }

            if( SyncCode( p_header ) != VLC_SUCCESS )
            {
                msg_Dbg( p_dec, "emulated sync word "
                         "(no sync on following frame): %2.2x%2.2x%2.2x%2.2x",
                         (int)p_header[0], (int)p_header[1],
                         (int)p_header[2], (int)p_header[3] );
                p_sys->i_state = STATE_NOSYNC;
                block_SkipByte( &p_sys->bytestream );
                break;
            }
            p_sys->i_state = STATE_SEND_DATA;
            break;

        case STATE_GET_DATA:
            /* Make sure we have enough data.
             * (Not useful if we went through NEXT_SYNC) */
            if( block_WaitBytes( &p_sys->bytestream,
                                 p_sys->i_frame_size ) != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }
            p_sys->i_state = STATE_SEND_DATA;

        case STATE_SEND_DATA:
            if( p_sys->b_dts_hd  )
            {
                /* Ignore DTS-HD */
                block_SkipBytes( &p_sys->bytestream, p_sys->i_frame_size );
                p_sys->i_state = STATE_NOSYNC;
                break;
            }

            if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) )
            {
                //p_dec->b_error = true;
                return NULL;
            }

            /* Copy the whole frame into the buffer. When we reach this point
             * we already know we have enough data available. */
            block_GetBytes( &p_sys->bytestream,
                            p_buf, __MIN( p_sys->i_frame_size, p_out_buffer->i_buffer ) );

            /* Make sure we don't reuse the same pts twice */
            if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
                p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID;

            p_sys->i_state = STATE_NOSYNC;

            /* So p_block doesn't get re-added several times */
            *pp_block = block_BytestreamPop( &p_sys->bytestream );

            return p_out_buffer;
        }
    }

    return NULL;
}
Exemplo n.º 2
0
/***
 * 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 syncronise 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_New( p_dec, 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;
}
Exemplo n.º 3
0
Arquivo: a52.c Projeto: robUx4/vlc
static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    uint8_t p_header[VLC_A52_HEADER_SIZE];
    block_t *p_out_buffer;

    block_t *p_block = pp_block ? *pp_block : NULL;

    if( p_block )
    {
        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
        {
            /* First always drain complete blocks before discontinuity */
            block_t *p_drain = PacketizeBlock( p_dec, NULL );
            if(p_drain)
                return p_drain;

            PacketizeFlush( p_dec );

            if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
            {
                block_Release( p_block );
                return NULL;
            }
        }

        if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID)
        {
            /* We've just started the stream, wait for the first PTS. */
            block_Release( p_block );
            return NULL;
        }

        block_BytestreamPush( &p_sys->bytestream, p_block );
    }

    while( 1 )
    {
        switch( p_sys->i_state )
        {
        case STATE_NOSYNC:
            while( block_PeekBytes( &p_sys->bytestream, p_header, 2 )
                   == VLC_SUCCESS )
            {
                if( p_header[0] == 0x0b && p_header[1] == 0x77 )
                {
                    p_sys->i_state = STATE_SYNC;
                    break;
                }
                block_SkipByte( &p_sys->bytestream );
            }
            if( p_sys->i_state != STATE_SYNC )
            {
                block_BytestreamFlush( &p_sys->bytestream );

                /* Need more data */
                return NULL;
            }

        case STATE_SYNC:
            /* New frame, set the Presentation Time Stamp */
            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
            if( p_sys->i_pts > VLC_TS_INVALID &&
                p_sys->i_pts != date_Get( &p_sys->end_date ) )
            {
                date_Set( &p_sys->end_date, p_sys->i_pts );
            }
            p_sys->i_state = STATE_HEADER;

        case STATE_HEADER:
            /* Get A/52 frame header (VLC_A52_HEADER_SIZE bytes) */
            if( block_PeekBytes( &p_sys->bytestream, p_header,
                                 VLC_A52_HEADER_SIZE ) != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }

            /* Check if frame is valid and get frame info */
            vlc_a52_header_t a52;
            if( vlc_a52_header_Parse( &a52, p_header, VLC_A52_HEADER_SIZE ) )
            {
                msg_Dbg( p_dec, "emulated sync word" );
                block_SkipByte( &p_sys->bytestream );
                p_sys->i_state = STATE_NOSYNC;
                break;
            }

            if( a52.b_eac3 && a52.eac3.strmtyp != EAC3_STRMTYP_INDEPENDENT )
            {
                /* Use the channel configuration of the independent stream */
                p_sys->frame.i_samples = a52.i_samples;
                p_sys->frame.i_size = a52.i_size;
            }
            else
                p_sys->frame = a52;

            p_sys->i_state = STATE_NEXT_SYNC;

        case STATE_NEXT_SYNC:
            /* Check if next expected frame contains the sync word */
            if( block_PeekOffsetBytes( &p_sys->bytestream,
                                       p_sys->frame.i_size, p_header, 2 )
                != VLC_SUCCESS )
            {
                if( p_block == NULL ) /* drain */
                {
                    p_sys->i_state = STATE_SEND_DATA;
                    break;
                }
                /* Need more data */
                return NULL;
            }

            if( p_header[0] == 0 && p_header[1] == 0 )
            {
                /* A52 wav files and audio CD's use stuffing */
                p_sys->i_state = STATE_GET_DATA;
                break;
            }

            if( p_header[0] != 0x0b || p_header[1] != 0x77 )
            {
                msg_Dbg( p_dec, "emulated sync word "
                         "(no sync on following frame)" );
                p_sys->i_state = STATE_NOSYNC;
                block_SkipByte( &p_sys->bytestream );
                break;
            }
            p_sys->i_state = STATE_SEND_DATA;
            break;

        case STATE_GET_DATA:
            /* Make sure we have enough data.
             * (Not useful if we went through NEXT_SYNC) */
            if( block_WaitBytes( &p_sys->bytestream,
                                 p_sys->frame.i_size ) != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }
            p_sys->i_state = STATE_SEND_DATA;

        case STATE_SEND_DATA:
            if( !(p_out_buffer = GetOutBuffer( p_dec )) )
            {
                //p_dec->b_error = true;
                return NULL;
            }

            /* Copy the whole frame into the buffer. When we reach this point
             * we already know we have enough data available. */
            block_GetBytes( &p_sys->bytestream, p_out_buffer->p_buffer,
                            __MIN( p_sys->frame.i_size, p_out_buffer->i_buffer ) );

            /* Make sure we don't reuse the same pts twice */
            if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
                p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID;

            if( p_sys->b_discontuinity )
            {
                p_out_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
                p_sys->b_discontuinity = false;
            }

            /* So p_block doesn't get re-added several times */
            if( pp_block )
                *pp_block = block_BytestreamPop( &p_sys->bytestream );

            p_sys->i_state = STATE_NOSYNC;

            return p_out_buffer;
        }
    }
}