Пример #1
0
Файл: mft.c Проект: IAPark/vlc
static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    HRESULT hr;

    if (!p_block) /* No Drain */
        return VLCDEC_SUCCESS;

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

    /* Dequeue all pending media events. */
    while ((hr = DequeueMediaEvent(p_dec)) == S_OK)
        continue;
    if (hr != MF_E_NO_EVENTS_AVAILABLE && FAILED(hr))
        goto error;

    /* Drain the output stream of the MFT before sending the input packet. */
    if (p_sys->pending_output_events > 0)
    {
        p_sys->pending_output_events -= 1;
        if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
            goto error;
    }

    /* Poll the MFT and return decoded frames until the input stream is ready. */
    while (p_sys->pending_input_events == 0)
    {
        hr = DequeueMediaEvent(p_dec);
        if (hr == MF_E_NO_EVENTS_AVAILABLE)
        {
            /* Sleep for 1 ms to avoid excessive polling. */
            Sleep(1);
            continue;
        }
        if (FAILED(hr))
            goto error;

        if (p_sys->pending_output_events > 0)
        {
            p_sys->pending_output_events -= 1;
            if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
                goto error;
            break;
        }
    }

    p_sys->pending_input_events -= 1;
    if (ProcessInputStream(p_dec, p_sys->input_stream_id, p_block))
        goto error;

    block_Release(p_block);

    return VLCDEC_SUCCESS;

error:
    msg_Err(p_dec, "Error in DecodeAsync()");
    block_Release(p_block);
    return VLCDEC_SUCCESS;
}
Пример #2
0
/*****************************************************************************
 * DecodeVideo: Called to decode one or more frames
 *****************************************************************************/
picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    AVCodecContext *p_context = p_sys->p_context;
    int b_drawpicture;
    int b_null_size = false;
    block_t *p_block;

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

    if( !p_context->extradata_size && p_dec->fmt_in.i_extra )
    {
        ffmpeg_InitCodec( p_dec );
        if( p_sys->b_delayed_open )
        {
            if( ffmpeg_OpenCodec( p_dec ) )
                msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
        }
    }

    p_block = *pp_block;
    if( p_sys->b_delayed_open )
    {
        block_Release( p_block );
        return NULL;
    }

    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
    {
        p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */

        p_sys->i_late_frames = 0;

        if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
            avcodec_flush_buffers( p_context );

        block_Release( p_block );
        return NULL;
    }

    if( p_block->i_flags & BLOCK_FLAG_PREROLL )
    {
        /* Do not care about late frames when prerolling
         * TODO avoid decoding of non reference frame
         * (ie all B except for H264 where it depends only on nal_ref_idc) */
        p_sys->i_late_frames = 0;
    }

    if( !p_dec->b_pace_control && (p_sys->i_late_frames > 0) &&
        (mdate() - p_sys->i_late_frames_start > INT64_C(5000000)) )
    {
        if( p_sys->i_pts > VLC_TS_INVALID )
        {
            msg_Err( p_dec, "more than 5 seconds of late video -> "
                     "dropping frame (computer too slow ?)" );
            p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */
        }
        block_Release( p_block );
        p_sys->i_late_frames--;
        return NULL;
    }

    /* A good idea could be to decode all I pictures and see for the other */
    if( !p_dec->b_pace_control &&
        p_sys->b_hurry_up &&
        (p_sys->i_late_frames > 4) )
    {
        b_drawpicture = 0;
        if( p_sys->i_late_frames < 12 )
        {
            p_context->skip_frame =
                    (p_sys->i_skip_frame <= AVDISCARD_NONREF) ?
                    AVDISCARD_NONREF : p_sys->i_skip_frame;
        }
        else
        {
            /* picture too late, won't decode
             * but break picture until a new I, and for mpeg4 ...*/
            p_sys->i_late_frames--; /* needed else it will never be decrease */
            block_Release( p_block );
            return NULL;
        }
    }
    else
    {
        if( p_sys->b_hurry_up )
            p_context->skip_frame = p_sys->i_skip_frame;
        if( !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
            b_drawpicture = 1;
        else
            b_drawpicture = 0;
    }

    if( p_context->width <= 0 || p_context->height <= 0 )
    {
        if( p_sys->b_hurry_up )
            p_context->skip_frame = p_sys->i_skip_frame;
        b_null_size = true;
    }
    else if( !b_drawpicture )
    {
        /* It creates broken picture
         * FIXME either our parser or ffmpeg is broken */
#if 0
        if( p_sys->b_hurry_up )
            p_context->skip_frame = __MAX( p_context->skip_frame,
                                                  AVDISCARD_NONREF );
#endif
    }

    /*
     * Do the actual decoding now */

    /* Don't forget that ffmpeg requires a little more bytes
     * that the real frame size */
    if( p_block->i_buffer > 0 )
    {
        p_sys->b_flush = ( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE ) != 0;

        p_block = block_Realloc( p_block, 0,
                            p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
        if( !p_block )
            return NULL;
        p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
        *pp_block = p_block;
        memset( p_block->p_buffer + p_block->i_buffer, 0,
                FF_INPUT_BUFFER_PADDING_SIZE );
    }

    while( p_block->i_buffer > 0 || p_sys->b_flush )
    {
        int i_used, b_gotpicture;
        picture_t *p_pic;
        AVPacket pkt;

        /* Set the PTS/DTS in the context reordered_opaque field */
        if( p_block->i_pts > VLC_TS_INVALID  )
            p_context->reordered_opaque = (p_block->i_pts << 1) | 0;
        else if( p_block->i_dts > VLC_TS_INVALID )
            p_context->reordered_opaque = (p_block->i_dts << 1) | 1;
        else
            p_context->reordered_opaque = INT64_MIN;
        p_sys->p_ff_pic->reordered_opaque = p_context->reordered_opaque;

        /* Make sure we don't reuse the same timestamps twice */
        p_block->i_pts =
        p_block->i_dts = VLC_TS_INVALID;

        post_mt( p_sys );

        av_init_packet( &pkt );
        pkt.data = p_block->p_buffer;
        pkt.size = p_block->i_buffer;
        i_used = avcodec_decode_video2( p_context, p_sys->p_ff_pic,
                                       &b_gotpicture, &pkt );

        if( b_null_size && !p_sys->b_flush &&
            p_context->width > 0 && p_context->height > 0 )
        {
            /* Reparse it to not drop the I frame */
            b_null_size = false;
            if( p_sys->b_hurry_up )
                p_context->skip_frame = p_sys->i_skip_frame;
            i_used = avcodec_decode_video2( p_context, p_sys->p_ff_pic,
                                           &b_gotpicture, &pkt );
        }
        wait_mt( p_sys );

        if( p_sys->b_flush )
            p_sys->b_first_frame = true;

        if( p_block->i_buffer <= 0 )
            p_sys->b_flush = false;

        if( i_used < 0 )
        {
            if( b_drawpicture )
                msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
                          p_block->i_buffer );
            block_Release( p_block );
            return NULL;
        }
        else if( i_used > p_block->i_buffer ||
                 p_context->thread_count > 1 )
        {
            i_used = p_block->i_buffer;
        }

        /* Consumed bytes */
        p_block->i_buffer -= i_used;
        p_block->p_buffer += i_used;

        /* Nothing to display */
        if( !b_gotpicture )
        {
            if( i_used == 0 ) break;
            continue;
        }

        /* Sanity check (seems to be needed for some streams) */
        if( p_sys->p_ff_pic->pict_type == AV_PICTURE_TYPE_B)
        {
            p_sys->b_has_b_frames = true;
        }

        /* Compute the PTS */
        mtime_t i_pts = VLC_TS_INVALID;
        if( p_sys->p_ff_pic->reordered_opaque != INT64_MIN )
        {
            mtime_t i_ts = p_sys->p_ff_pic->reordered_opaque >> 1;
            bool    b_dts = p_sys->p_ff_pic->reordered_opaque & 1;
            if( b_dts )
            {
                if( !p_context->has_b_frames ||
                    !p_sys->b_has_b_frames ||
                    !p_sys->p_ff_pic->reference ||
                    p_sys->i_pts <= VLC_TS_INVALID )
                    i_pts = i_ts;

                /* Guess what ? The rules are different for Real Video :( */
                if( (p_dec->fmt_in.i_codec == VLC_CODEC_RV30 ||
                     p_dec->fmt_in.i_codec == VLC_CODEC_RV40) &&
                    p_sys->b_has_b_frames )
                {
                    i_pts = VLC_TS_INVALID;
                    if(p_sys->p_ff_pic->reference) i_pts = i_ts;
                }
            }
            else
            {
                i_pts = i_ts;
            }
        }
        if( i_pts <= VLC_TS_INVALID )
            i_pts = p_sys->i_pts;

        /* Interpolate the next PTS */
        if( i_pts > VLC_TS_INVALID )
            p_sys->i_pts = i_pts;
        if( p_sys->i_pts > VLC_TS_INVALID )
        {
            /* interpolate the next PTS */
            if( p_dec->fmt_in.video.i_frame_rate > 0 &&
                p_dec->fmt_in.video.i_frame_rate_base > 0 )
            {
                p_sys->i_pts += INT64_C(1000000) *
                    (2 + p_sys->p_ff_pic->repeat_pict) *
                    p_dec->fmt_in.video.i_frame_rate_base /
                    (2 * p_dec->fmt_in.video.i_frame_rate);
            }
            else if( p_context->time_base.den > 0 )
            {
                int i_tick = p_context->ticks_per_frame;
                if( i_tick <= 0 )
                    i_tick = 1;

                p_sys->i_pts += INT64_C(1000000) *
                    (2 + p_sys->p_ff_pic->repeat_pict) *
                    i_tick * p_context->time_base.num /
                    (2 * p_context->time_base.den);
            }
        }

        /* Update frame late count (except when doing preroll) */
        mtime_t i_display_date = 0;
        if( !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
            i_display_date = decoder_GetDisplayDate( p_dec, i_pts );

        if( i_display_date > 0 && i_display_date <= mdate() )
        {
            p_sys->i_late_frames++;
            if( p_sys->i_late_frames == 1 )
                p_sys->i_late_frames_start = mdate();
        }
        else
        {
            p_sys->i_late_frames = 0;
        }

        if( !b_drawpicture || ( !p_sys->p_va && !p_sys->p_ff_pic->linesize[0] ) )
            continue;

        if( !p_sys->p_ff_pic->opaque )
        {
            /* Get a new picture */
            p_pic = ffmpeg_NewPictBuf( p_dec, p_context );
            if( !p_pic )
            {
                block_Release( p_block );
                return NULL;
            }

            /* Fill p_picture_t from AVVideoFrame and do chroma conversion
             * if needed */
            ffmpeg_CopyPicture( p_dec, p_pic, p_sys->p_ff_pic );
        }
        else
        {
            p_pic = (picture_t *)p_sys->p_ff_pic->opaque;
            decoder_LinkPicture( p_dec, p_pic );
        }

        if( !p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den )
        {
            /* Fetch again the aspect ratio in case it changed */
            p_dec->fmt_out.video.i_sar_num
                = p_context->sample_aspect_ratio.num;
            p_dec->fmt_out.video.i_sar_den
                = p_context->sample_aspect_ratio.den;

            if( !p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den )
            {
                p_dec->fmt_out.video.i_sar_num = 1;
                p_dec->fmt_out.video.i_sar_den = 1;
            }
        }

        /* Send decoded frame to vout */
        if( i_pts > VLC_TS_INVALID)
        {
            p_pic->date = i_pts;

            if( p_sys->b_first_frame )
            {
                /* Hack to force display of still pictures */
                p_sys->b_first_frame = false;
                p_pic->b_force = true;
            }

            p_pic->i_nb_fields = 2 + p_sys->p_ff_pic->repeat_pict;
            p_pic->b_progressive = !p_sys->p_ff_pic->interlaced_frame;
            p_pic->b_top_field_first = p_sys->p_ff_pic->top_field_first;

            p_pic->i_qstride = p_sys->p_ff_pic->qstride;
            int i_mb_h = ( p_pic->format.i_height + 15 ) / 16;
            p_pic->p_q = malloc( p_pic->i_qstride * i_mb_h );
            memcpy( p_pic->p_q, p_sys->p_ff_pic->qscale_table,
                    p_pic->i_qstride * i_mb_h );
            switch( p_sys->p_ff_pic->qscale_type )
            {
                case FF_QSCALE_TYPE_MPEG1:
                    p_pic->i_qtype = QTYPE_MPEG1;
                    break;
                case FF_QSCALE_TYPE_MPEG2:
                    p_pic->i_qtype = QTYPE_MPEG2;
                    break;
                case FF_QSCALE_TYPE_H264:
                    p_pic->i_qtype = QTYPE_H264;
                    break;
            }

            return p_pic;
        }
        else
        {
            decoder_DeletePicture( p_dec, p_pic );
        }
    }
Пример #3
0
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************/
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block = NULL;

    BC_DTS_PROC_OUT proc_out;
    BC_DTS_STATUS driver_stat;

    /* First check the status of the decode to produce pictures */
    if( BC_FUNC_PSYS(DtsGetDriverStatus)( p_sys->bcm_handle, &driver_stat ) != BC_STS_SUCCESS )
        return NULL;

    if( pp_block )
        p_block = *pp_block;

    if( p_block )
    {
        if( ( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) == 0 )
        {
            /* Valid input block, so we can send to HW to decode */
            BC_STATUS status = BC_FUNC_PSYS(DtsProcInput)( p_sys->bcm_handle,
                                            p_block->p_buffer,
                                            p_block->i_buffer,
                                            p_block->i_pts >= VLC_TS_INVALID ? TO_BC_PTS(p_block->i_pts) : 0, false );

            block_Release( p_block );
            *pp_block = NULL;

            if( status != BC_STS_SUCCESS )
                return NULL;
        }
    }
#ifdef DEBUG_CRYSTALHD
    else
    {
        if( driver_stat.ReadyListCount != 0 )
            msg_Err( p_dec, " Input NULL but have pictures %u", driver_stat.ReadyListCount );
    }
#endif

    if( driver_stat.ReadyListCount == 0 )
        return NULL;

    /* Prepare the Output structure */
    /* We always expect and use YUY2 */
    memset( &proc_out, 0, sizeof(BC_DTS_PROC_OUT) );
    proc_out.PicInfo.width  = p_dec->fmt_out.video.i_width;
    proc_out.PicInfo.height = p_dec->fmt_out.video.i_height;
    proc_out.PoutFlags      = BC_POUT_FLAGS_SIZE;
    proc_out.AppCallBack    = ourCallback;
    proc_out.hnd            = p_dec;
    p_sys->proc_out         = &proc_out;

    /* */
    BC_STATUS sts = BC_FUNC_PSYS(DtsProcOutput)( p_sys->bcm_handle, 128, &proc_out );
#ifdef DEBUG_CRYSTALHD
    if( sts != BC_STS_SUCCESS )
        msg_Err( p_dec, "DtsProcOutput returned %i", sts );
#endif

    uint8_t b_eos;
    picture_t *p_pic = p_sys->p_pic;
    switch( sts )
    {
        case BC_STS_SUCCESS:
            if( !(proc_out.PoutFlags & BC_POUT_FLAGS_PIB_VALID) )
            {
                msg_Dbg( p_dec, "Invalid PIB" );
                break;
            }

            if( !p_pic )
                break;

            /* In interlaced mode, do not push the first field in the pipeline */
            if( (proc_out.PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
               !(proc_out.PicInfo.flags & VDEC_FLAG_FIELDPAIR) )
                return NULL;

            //  crystal_CopyPicture( p_pic, &proc_out );
            p_pic->date = proc_out.PicInfo.timeStamp > 0 ?
                          FROM_BC_PTS(proc_out.PicInfo.timeStamp) : VLC_TS_INVALID;
            //p_pic->date += 100 * 1000;
#ifdef DEBUG_CRYSTALHD
            msg_Dbg( p_dec, "TS Output is %"PRIu64, p_pic->date);
#endif
            return p_pic;

        case BC_STS_DEC_NOT_OPEN:
        case BC_STS_DEC_NOT_STARTED:
            msg_Err( p_dec, "Decoder not opened or started" );
            break;

        case BC_STS_INV_ARG:
            msg_Warn( p_dec, "Invalid arguments. Please report" );
            break;

        case BC_STS_FMT_CHANGE:    /* Format change */
            /* if( !(proc_out.PoutFlags & BC_POUT_FLAGS_PIB_VALID) )
                break; */
            p_dec->fmt_out.video.i_width  = proc_out.PicInfo.width;
            p_dec->fmt_out.video.i_height = proc_out.PicInfo.height;
            if( proc_out.PicInfo.height == 1088 )
                p_dec->fmt_out.video.i_height = 1080;
#define setAR( a, b, c ) case a: p_dec->fmt_out.video.i_sar_num = b; \
                                 p_dec->fmt_out.video.i_sar_den = c; break;
            switch( proc_out.PicInfo.aspect_ratio )
            {
                setAR( vdecAspectRatioSquare, 1, 1 )
                setAR( vdecAspectRatio12_11, 12, 11 )
                setAR( vdecAspectRatio10_11, 10, 11 )
                setAR( vdecAspectRatio16_11, 16, 11 )
                setAR( vdecAspectRatio40_33, 40, 33 )
                setAR( vdecAspectRatio24_11, 24, 11 )
                setAR( vdecAspectRatio20_11, 20, 11 )
                setAR( vdecAspectRatio32_11, 32, 11 )
                setAR( vdecAspectRatio80_33, 80, 33 )
                setAR( vdecAspectRatio18_11, 18, 11 )
                setAR( vdecAspectRatio15_11, 15, 11 )
                setAR( vdecAspectRatio64_33, 64, 33 )
                setAR( vdecAspectRatio160_99, 160, 99 )
                setAR( vdecAspectRatio4_3, 4, 3 )
                setAR( vdecAspectRatio16_9, 16, 9 )
                setAR( vdecAspectRatio221_1, 221, 1 )
                default: break;
            }
#undef setAR
            msg_Dbg( p_dec, "Format Change Detected [%i, %i], AR: %i/%i",
                    proc_out.PicInfo.width, proc_out.PicInfo.height,
                    p_dec->fmt_out.video.i_sar_num,
                    p_dec->fmt_out.video.i_sar_den );
            break;

        /* Nothing is documented here... */
        case BC_STS_NO_DATA:
            if( BC_FUNC_PSYS(DtsIsEndOfStream)( p_sys->bcm_handle, &b_eos )
                    == BC_STS_SUCCESS )
                if( b_eos )
                    msg_Dbg( p_dec, "End of Stream" );
            break;
        case BC_STS_TIMEOUT:       /* Timeout */
            msg_Err( p_dec, "ProcOutput timeout" );
            break;
        case BC_STS_IO_XFR_ERROR:
        case BC_STS_IO_USER_ABORT:
        case BC_STS_IO_ERROR:
            msg_Err( p_dec, "ProcOutput return mode not implemented. Please report" );
            break;
        default:
            msg_Err( p_dec, "Unknown return status. Please report %i", sts );
            break;
    }
    if( p_pic )
        picture_Release( p_pic );
    return NULL;
}
Пример #4
0
Файл: svg.c Проект: mstorsjo/vlc
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************
 * This function must be fed with a complete image.
 ****************************************************************************/
static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
{
    decoder_sys_t *p_sys  = (decoder_sys_t *) p_dec->p_sys;
    picture_t *p_pic = NULL;
    int32_t i_width, i_height;

    RsvgHandle *rsvg = NULL;
    cairo_surface_t *surface = NULL;
    cairo_t *cr = NULL;

    if( p_block == NULL ) /* No Drain */
        return VLCDEC_SUCCESS;

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

    rsvg = rsvg_handle_new_from_data( p_block->p_buffer, p_block->i_buffer, NULL );
    if( !rsvg )
        goto done;

    RsvgDimensionData dim;
    rsvg_handle_get_dimensions( rsvg, &dim );

    if( p_sys->f_scale > 0.0 )
    {
        i_width  = (int32_t)(p_sys->f_scale * dim.width);
        i_height = (int32_t)(p_sys->f_scale * dim.height);
    }
    else
    {
        /* Keep aspect */
        if( p_sys->i_width < 0 && p_sys->i_height > 0 )
        {
            i_width  = dim.width * p_sys->i_height / dim.height;
            i_height = p_sys->i_height;
        }
        else if( p_sys->i_width > 0 && p_sys->i_height < 0 )
        {
            i_width  = p_sys->i_width;
            i_height = dim.height * p_sys->i_width / dim.height;
        }
        else if( p_sys->i_width > 0 && p_sys->i_height > 0 )
        {
            i_width  = dim.width * p_sys->i_height / dim.height;
            i_height = p_sys->i_height;
        }
        else
        {
            i_width  = dim.width;
            i_height = dim.height;
        }
    }

    p_dec->fmt_out.i_codec =
    p_dec->fmt_out.video.i_chroma = VLC_CODEC_BGRA;
    p_dec->fmt_out.video.i_width  = i_width;
    p_dec->fmt_out.video.i_height = i_height;
    p_dec->fmt_out.video.i_visible_width  = i_width;
    p_dec->fmt_out.video.i_visible_height = i_height;
    p_dec->fmt_out.video.i_sar_num = 1;
    p_dec->fmt_out.video.i_sar_den = 1;
    p_dec->fmt_out.video.i_rmask = 0x80800000; /* Since librsvg v1.0 */
    p_dec->fmt_out.video.i_gmask = 0x0000ff00;
    p_dec->fmt_out.video.i_bmask = 0x000000ff;
    video_format_FixRgb(&p_dec->fmt_out.video);

    /* Get a new picture */
    if( decoder_UpdateVideoFormat( p_dec ) )
        goto done;
    p_pic = decoder_NewPicture( p_dec );
    if( !p_pic )
        goto done;

    /* NOTE: Do not use the stride calculation from cairo, because it is wrong:
     * stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, dim.width);
     * Use the stride from VLC its picture_t::p[0].i_pitch, which is correct.
     */
    memset(p_pic->p[0].p_pixels, 0, p_pic->p[0].i_pitch * p_pic->p[0].i_lines);
    surface = cairo_image_surface_create_for_data( p_pic->p->p_pixels,
                                                   CAIRO_FORMAT_ARGB32,
                                                   i_width, i_height,
                                                   p_pic->p[0].i_pitch );
    if( !surface )
    {
        picture_Release( p_pic );
        p_pic = NULL;
        goto done;
    }

    /* Decode picture */
    cr = cairo_create( surface );
    if( !cr )
    {
        picture_Release( p_pic );
        p_pic = NULL;
        goto done;
    }

    if ( i_width != dim.width || i_height != dim.height )
    {
        double sw, sh;
        if ( p_sys->f_scale > 0.0 && !(p_sys->i_width > 0 || p_sys->i_height > 0) )
            sw = sh = p_sys->f_scale;
        else
        {
            double aspect = (double) (dim.width * p_dec->fmt_out.video.i_sar_num) /
                    (dim.height * p_dec->fmt_out.video.i_sar_den);
            sw = aspect * i_width / dim.width;
            sh = aspect * i_height / dim.height;
        }
        cairo_scale(cr, sw, sh);
    }

    if( !rsvg_handle_render_cairo( rsvg, cr ) )
    {
        picture_Release( p_pic );
        p_pic = NULL;
        goto done;
    }

    p_pic->date = p_block->i_pts != VLC_TICK_INVALID ? p_block->i_pts : p_block->i_dts;

done:
    if( rsvg )
        g_object_unref( G_OBJECT( rsvg ) );
    if( cr )
        cairo_destroy( cr );
    if( surface )
        cairo_surface_destroy( surface );

    block_Release( p_block );
    if( p_pic != NULL )
        decoder_QueueVideo( p_dec, p_pic );
    return VLCDEC_SUCCESS;
}
Пример #5
0
/*
 * EncodeBlock
 */
static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic)
{
    encoder_sys_t *p_sys = p_enc->p_sys;

    if( unlikely( !p_pic ) )
    {
        return NULL;
    }

    block_t *p_block = block_Alloc( p_sys->i_blocksize );
    if( p_block == NULL )
    {
        return NULL;
    }

    png_structp p_png = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    if( p_png == NULL )
    {
        block_Release( p_block );
        return NULL;
    }

    /* save buffer start */
    uint8_t *p_start = p_block->p_buffer;
    size_t i_start = p_block->i_buffer;

    p_sys->b_error = false;
    png_infop p_info = NULL;

    /* libpng longjmp's there in case of error */
    if( setjmp( png_jmpbuf( p_png ) ) )
        goto error;

    png_set_write_fn( p_png, p_block, user_write, user_flush );
    png_set_error_fn( p_png, p_enc, user_error, user_warning );

    p_info = png_create_info_struct( p_png );
    if( p_info == NULL )
        goto error;

    png_infop p_end_info = png_create_info_struct( p_png );
    if( p_end_info == NULL ) goto error;

    const unsigned i_width = p_enc->fmt_in.video.i_visible_width;
    const unsigned i_height = p_enc->fmt_in.video.i_visible_height;

    png_set_IHDR( p_png, p_info,
            i_width,
            i_height,
            8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
    if( p_sys->b_error ) goto error;

    png_write_info( p_png, p_info );
    if( p_sys->b_error ) goto error;

    /* Encode picture */

    for( unsigned i = 0; i < i_height; i++ )
    {
        png_write_row( p_png, p_pic->p->p_pixels + (i_width * i * 3));
        if( p_sys->b_error ) goto error;
    }

    png_write_end( p_png, p_end_info );
    if( p_sys->b_error ) goto error;

    png_destroy_write_struct( &p_png, &p_info );

    /* restore original buffer position */
    p_block->p_buffer = p_start;
    p_block->i_buffer = i_start - p_block->i_buffer;

    p_block->i_dts = p_block->i_pts = p_pic->date;

    return p_block;

 error:

    png_destroy_write_struct( &p_png, p_info ? &p_info : NULL );

    block_Release(p_block);
    return NULL;
}
Пример #6
0
/*****************************************************************************
 * ProcessPacket: processes a Speex packet.
 *****************************************************************************/
static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                            block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block = *pp_block;

    if( p_block && p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
        Flush( p_dec );

    /* Date management */
    if( p_block && p_block->i_pts > VLC_TS_INVALID &&
        p_block->i_pts != date_Get( &p_sys->end_date ) )
    {
        date_Set( &p_sys->end_date, p_block->i_pts );
    }

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

    *pp_block = NULL; /* To avoid being fed the same packet again */

    if( p_sys->b_packetizer )
    {
        if ( p_sys->p_header->frames_per_packet > 1 )
        {
            short *p_frame_holder = NULL;
            int i_bits_before = 0, i_bits_after = 0, i_bytes_in_speex_frame = 0,
                i_pcm_output_size = 0, i_bits_in_speex_frame = 0;
            block_t *p_new_block = NULL;

            i_pcm_output_size = p_sys->p_header->frame_size;
            p_frame_holder = (short*)xmalloc( sizeof(short)*i_pcm_output_size );

            speex_bits_read_from( &p_sys->bits, (char*)p_oggpacket->packet,
                p_oggpacket->bytes);
            i_bits_before = speex_bits_remaining( &p_sys->bits );
            speex_decode_int(p_sys->p_state, &p_sys->bits, p_frame_holder);
            i_bits_after = speex_bits_remaining( &p_sys->bits );

            i_bits_in_speex_frame = i_bits_before - i_bits_after;
            i_bytes_in_speex_frame = ( i_bits_in_speex_frame +
                (8 - (i_bits_in_speex_frame % 8)) )
                / 8;

            p_new_block = block_Alloc( i_bytes_in_speex_frame );
            memset( p_new_block->p_buffer, 0xff, i_bytes_in_speex_frame );

            /*
             * Copy the first frame in this packet to a new packet.
             */
            speex_bits_rewind( &p_sys->bits );
            speex_bits_write( &p_sys->bits,
                (char*)p_new_block->p_buffer,
                (int)i_bytes_in_speex_frame );

            /*
             * Move the remaining part of the original packet (subsequent
             * frames, if there are any) into the beginning
             * of the original packet so
             * they are preserved following the realloc.
             * Note: Any bits that
             * remain in the initial packet
             * are "filler" if they do not constitute
             * an entire byte.
             */
            if ( i_bits_after > 7 )
            {
                /* round-down since we rounded-up earlier (to include
             * the speex terminator code.
             */
                i_bytes_in_speex_frame--;
                speex_bits_write( &p_sys->bits,
                    (char*)p_block->p_buffer,
                    p_block->i_buffer - i_bytes_in_speex_frame );
                p_block = block_Realloc( p_block,
                    0,
                    p_block->i_buffer-i_bytes_in_speex_frame );
                *pp_block = p_block;
            }
            else
            {
                speex_bits_reset( &p_sys->bits );
            }

            free( p_frame_holder );
            return SendPacket( p_dec, p_new_block);
        }
        else
        {
                return SendPacket( p_dec, p_block );
        }
    }
    else
    {
        block_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket );

        if( p_block )
            block_Release( p_block );
        return p_aout_buffer;
    }
}
Пример #7
0
/*****************************************************************************
 * Process: Process and dispatch buffers
 *****************************************************************************/
static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
                        mtime_t i_max_dts )
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;
    mtime_t i_dts = 0;
    block_t *p_blocks = NULL;
    block_t *p_blocks_out = NULL;

    /* Find out the blocks we need. */
    while ( id->p_queued != NULL
             && (!i_max_dts || id->p_queued->i_dts <= i_max_dts) )
    {
        block_t *p_next = id->p_queued->p_next;
        id->p_queued->p_next = NULL;
        i_dts = id->p_queued->i_dts;
        block_ChainAppend( &p_blocks, id->p_queued );
        id->p_queued = p_next;
    }

    if ( p_sys->i_old_cmd == 0 )
    {
        /* Full forward */
        if ( p_blocks != NULL )
            p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks );
        return i_dts;
    }

    if ( p_sys->i_old_cmd == -1 )
    {
        /* No output at all */
        while ( p_blocks != NULL )
        {
            block_t * p_next = p_blocks->p_next;
            block_Release( p_blocks );
            p_blocks = p_next;
        }
        return i_dts;
    }

    while ( p_blocks != NULL )
    {
        block_t * p_next = p_blocks->p_next;
        block_t * p_out;

        if ( id->b_switcher_video )
        {
            p_out = VideoGetBuffer( p_stream, id, p_blocks );
        }
        else
        {
            p_out = AudioGetBuffer( p_stream, id, p_blocks );
        }
        p_blocks = p_next;
        if ( p_out != NULL )
        {
            block_ChainAppend( &p_blocks_out, p_out );
        }
    }

    if ( p_blocks_out != NULL )
        p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks_out );
    return i_dts;
}
Пример #8
0
static aout_buffer_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block)
{
    block_t *p_block;
    decoder_sys_t *p_sys = p_dec->p_sys;
    aout_buffer_t *p_out = NULL;

    if (pp_block == NULL)
        return NULL;
    p_block = *pp_block;
    if (p_block == NULL)
        return NULL;
    *pp_block = NULL;

    if (p_block->i_pts && !date_Get (&p_sys->end_date))
        date_Set (&p_sys->end_date, p_block->i_pts);
    else
    if (p_block->i_pts < date_Get (&p_sys->end_date))
    {
        msg_Warn (p_dec, "MIDI message in the past?");
        goto drop;
    }

    if (p_block->i_buffer < 1)
        goto drop;

    uint8_t channel = p_block->p_buffer[0] & 0xf;
    uint8_t p1 = (p_block->i_buffer > 1) ? (p_block->p_buffer[1] & 0x7f) : 0;
    uint8_t p2 = (p_block->i_buffer > 2) ? (p_block->p_buffer[2] & 0x7f) : 0;

    switch (p_block->p_buffer[0] & 0xf0)
    {
        case 0x80:
            fluid_synth_noteoff (p_sys->synth, channel, p1);
            break;
        case 0x90:
            fluid_synth_noteon (p_sys->synth, channel, p1, p2);
            break;
        case 0xB0:
            fluid_synth_cc (p_sys->synth, channel, p1, p2);
            break;
        case 0xC0:
            fluid_synth_program_change (p_sys->synth, channel, p1);
            break;
        case 0xE0:
            fluid_synth_pitch_bend (p_sys->synth, channel, (p1 << 7) | p2);
            break;
    }

    unsigned samples =
        (p_block->i_pts - date_Get (&p_sys->end_date)) * 441 / 10000;
    if (samples == 0)
        return NULL;

    p_out = decoder_NewAudioBuffer (p_dec, samples);
    if (p_out == NULL)
        goto drop;

    p_out->i_pts = date_Get (&p_sys->end_date );
    p_out->i_length = date_Increment (&p_sys->end_date, samples)
                      - p_out->i_pts;
    if (!p_sys->fixed)
        fluid_synth_write_float (p_sys->synth, samples,
                                 p_out->p_buffer, 0, 2,
                                 p_out->p_buffer, 1, 2);
    else
        fluid_synth_write_s16 (p_sys->synth, samples,
                               (int16_t *)p_out->p_buffer, 0, 2,
                               (int16_t *)p_out->p_buffer, 1, 2);
drop:
    block_Release (p_block);
    return p_out;
}
Пример #9
0
static void audio_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
{
    VLC_UNUSED(p_dec);
    block_Release( p_buffer );
}
Пример #10
0
/*****************************************************************************
 * DecodeAudio: Called to decode one frame
 *****************************************************************************/
aout_buffer_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    int i_used, i_output;
    aout_buffer_t *p_buffer;
    block_t *p_block;
    AVPacket pkt;

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

    p_block = *pp_block;

    if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra &&
        p_sys->b_delayed_open)
    {
        InitDecoderConfig( p_dec, p_sys->p_context);
        if( ffmpeg_OpenCodec( p_dec ) )
            msg_Err( p_dec, "Cannot open decoder %s", p_sys->psz_namecodec );
    }
    if( p_sys->b_delayed_open )
    {
        block_Release( p_block );
        return NULL;
    }

    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
    {
        block_Release( p_block );
        avcodec_flush_buffers( p_sys->p_context );
        p_sys->i_samples = 0;
        date_Set( &p_sys->end_date, 0 );

        if( p_sys->i_codec_id == CODEC_ID_MP2 || p_sys->i_codec_id == CODEC_ID_MP3 )
            p_sys->i_reject_count = 3;
        return NULL;
    }

    if( p_sys->i_samples > 0 )
    {
        /* More data */
        p_buffer = SplitBuffer( p_dec );
        if( !p_buffer ) block_Release( p_block );
        return p_buffer;
    }

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

    if( p_block->i_buffer <= 0 )
    {
        block_Release( p_block );
        return NULL;
    }

    if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 0 )
    {
        *pp_block = p_block = block_Realloc( p_block, 0, p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
        if( !p_block )
            return NULL;
        p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
        memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE );

        p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED;
    }

    do
    {
        i_output = __MAX( p_block->i_buffer, p_sys->i_output_max );
        if( i_output > p_sys->i_output_max )
        {
            /* Grow output buffer if necessary (eg. for PCM data) */
            p_sys->p_output = av_realloc( p_sys->p_output, i_output );
        }

        av_init_packet( &pkt );
        pkt.data = p_block->p_buffer;
        pkt.size = p_block->i_buffer;
        i_used = avcodec_decode_audio3( p_sys->p_context,
                                       (int16_t*)p_sys->p_output, &i_output,
                                       &pkt );

        if( i_used < 0 || i_output < 0 )
        {
            if( i_used < 0 )
                msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
                          p_block->i_buffer );

            block_Release( p_block );
            return NULL;
        }
        else if( (size_t)i_used > p_block->i_buffer )
        {
            i_used = p_block->i_buffer;
        }

        p_block->i_buffer -= i_used;
        p_block->p_buffer += i_used;

    } while( p_block->i_buffer > 0 && i_output <= 0 );

    if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 8 ||
        p_sys->p_context->sample_rate <= 0 )
    {
        msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d",
                  p_sys->p_context->channels, p_sys->p_context->sample_rate );
        block_Release( p_block );
        return NULL;
    }

    if( p_dec->fmt_out.audio.i_rate != (unsigned int)p_sys->p_context->sample_rate )
    {
        date_Init( &p_sys->end_date, p_sys->p_context->sample_rate, 1 );
        date_Set( &p_sys->end_date, p_block->i_pts );
    }

    /* **** Set audio output parameters **** */
    SetupOutputFormat( p_dec, true );

    if( p_block->i_pts != 0 &&
        p_block->i_pts != date_Get( &p_sys->end_date ) )
    {
        date_Set( &p_sys->end_date, p_block->i_pts );
    }
    p_block->i_pts = 0;

    /* **** Now we can output these samples **** */
    p_sys->i_samples = i_output / (p_dec->fmt_out.audio.i_bitspersample / 8) / p_sys->p_context->channels;
    p_sys->p_samples = p_sys->p_output;

    /* Silent unwanted samples */
    if( p_sys->i_reject_count > 0 )
    {
        memset( p_sys->p_output, 0, i_output );
        p_sys->i_reject_count--;
    }

    p_buffer = SplitBuffer( p_dec );
    if( !p_buffer ) block_Release( p_block );
    return p_buffer;
}
Пример #11
0
/*****************************************************************************
 * Block:
 *****************************************************************************/
static block_t *Block( access_t *p_access )
{
    access_sys_t *p_sys = p_access->p_sys;
    int i_blocks = VCD_BLOCKS_ONCE;
    block_t *p_block;
    int i_read;

    /* Check end of file */
    if( p_access->info.b_eof ) return NULL;

    /* Check end of title */
    while( p_sys->i_sector >= p_sys->p_sectors[p_access->info.i_title + 2] )
    {
        if( p_access->info.i_title + 2 >= p_sys->i_titles )
        {
            p_access->info.b_eof = true;
            return NULL;
        }

        p_access->info.i_update |=
            INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT | INPUT_UPDATE_SIZE;
        p_access->info.i_title++;
        p_access->info.i_seekpoint = 0;
        p_access->info.i_size =
            p_sys->title[p_access->info.i_title]->i_size;
        p_access->info.i_pos = 0;
    }

    /* Don't read after the end of a title */
    if( p_sys->i_sector + i_blocks >=
        p_sys->p_sectors[p_access->info.i_title + 2] )
    {
        i_blocks = p_sys->p_sectors[p_access->info.i_title + 2 ] -
                   p_sys->i_sector;
    }

    /* Do the actual reading */
    if( !( p_block = block_New( p_access, i_blocks * VCD_DATA_SIZE ) ) )
    {
        msg_Err( p_access, "cannot get a new block of size: %i",
                 i_blocks * VCD_DATA_SIZE );
        return NULL;
    }

    if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev,
            p_sys->i_sector, p_block->p_buffer, i_blocks, VCD_TYPE ) < 0 )
    {
        msg_Err( p_access, "cannot read sector %i", p_sys->i_sector );
        block_Release( p_block );

        /* Try to skip one sector (in case of bad sectors) */
        p_sys->i_sector++;
        p_access->info.i_pos += VCD_DATA_SIZE;
        return NULL;
    }

    /* Update seekpoints */
    for( i_read = 0; i_read < i_blocks; i_read++ )
    {
        input_title_t *t = p_sys->title[p_access->info.i_title];

        if( t->i_seekpoint > 0 &&
            p_access->info.i_seekpoint + 1 < t->i_seekpoint &&
            p_access->info.i_pos + i_read * VCD_DATA_SIZE >=
            t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset )
        {
            msg_Dbg( p_access, "seekpoint change" );
            p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
            p_access->info.i_seekpoint++;
        }
    }

    /* Update a few values */
    p_sys->i_sector += i_blocks;
    p_access->info.i_pos += p_block->i_buffer;

    return p_block;
}
Пример #12
0
/*****************************************************************************
 * ParseMPEGBlock: Re-assemble fragments into a block containing a picture
 *****************************************************************************/
static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_pic = NULL;

    /*
     * Check if previous picture is finished
     */
    if( ( p_sys->b_frame_slice &&
          (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) ) &&
          p_sys->p_seq == NULL )
    {
        /* We have a picture but without a sequence header we can't
         * do anything */
        msg_Dbg( p_dec, "waiting for sequence start" );
        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 = false;

    }
    else if( p_sys->b_frame_slice &&
             (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) )
    {
        const bool b_eos = p_frag->p_buffer[3] == 0xb7;

        mtime_t i_duration;

        if( b_eos )
        {
            block_ChainLastAppend( &p_sys->pp_last, p_frag );
            p_frag = NULL;
        }

        p_pic = block_ChainGather( p_sys->p_frame );

        if( b_eos )
            p_pic->i_flags |= BLOCK_FLAG_END_OF_SEQUENCE;

        i_duration = (mtime_t)( 1000000 * p_sys->i_frame_rate_base /
                                p_sys->i_frame_rate );

        if( !p_sys->b_seq_progressive && p_sys->i_picture_structure != 0x03 )
        {
            i_duration /= 2;
        }

        if( p_sys->b_seq_progressive )
        {
            if( p_sys->i_top_field_first == 0 &&
                p_sys->i_repeat_first_field == 1 )
            {
                i_duration *= 2;
            }
            else if( p_sys->i_top_field_first == 1 &&
                     p_sys->i_repeat_first_field == 1 )
            {
                i_duration *= 3;
            }
        }
        else
        {
            if( p_sys->i_picture_structure == 0x03 )
            {
                if( p_sys->i_progressive_frame && p_sys->i_repeat_first_field )
                {
                    i_duration += i_duration / 2;
                }
            }
        }

        if( p_sys->b_low_delay || p_sys->i_picture_type == 0x03 )
        {
            /* Trivial case (DTS == PTS) */
            /* Correct interpolated dts when we receive a new pts/dts */
            if( p_sys->i_pts > VLC_TS_INVALID )
                p_sys->i_interpolated_dts = p_sys->i_pts;
            if( p_sys->i_dts > VLC_TS_INVALID )
                p_sys->i_interpolated_dts = p_sys->i_dts;
        }
        else
        {
            /* Correct interpolated dts when we receive a new pts/dts */
            if(p_sys->i_last_ref_pts > VLC_TS_INVALID && !p_sys->b_second_field)
                p_sys->i_interpolated_dts = p_sys->i_last_ref_pts;
            if( p_sys->i_dts > VLC_TS_INVALID )
                p_sys->i_interpolated_dts = p_sys->i_dts;

            if( !p_sys->b_second_field )
                p_sys->i_last_ref_pts = p_sys->i_pts;
        }

        p_pic->i_dts = p_sys->i_interpolated_dts;
        p_sys->i_interpolated_dts += i_duration;

        /* Set PTS only if we have a B frame or if it comes from the stream */
        if( p_sys->i_pts > VLC_TS_INVALID )
        {
            p_pic->i_pts = p_sys->i_pts;
        }
        else if( p_sys->i_picture_type == 0x03 )
        {
            p_pic->i_pts = p_pic->i_dts;
        }
        else
        {
            p_pic->i_pts = VLC_TS_INVALID;
        }

        switch ( p_sys->i_picture_type )
        {
        case 0x01:
            p_pic->i_flags |= BLOCK_FLAG_TYPE_I;
            break;
        case 0x02:
            p_pic->i_flags |= BLOCK_FLAG_TYPE_P;
            break;
        case 0x03:
            p_pic->i_flags |= BLOCK_FLAG_TYPE_B;
            break;
        }

        p_pic->i_length = p_sys->i_interpolated_dts - p_pic->i_dts;

#if 0
        msg_Dbg( p_dec, "pic: type=%d dts=%"PRId64" pts-dts=%"PRId64,
        p_sys->i_picture_type, p_pic->i_dts, p_pic->i_pts - p_pic->i_dts);
#endif

        /* Reset context */
        p_sys->p_frame = NULL;
        p_sys->pp_last = &p_sys->p_frame;
        p_sys->b_frame_slice = false;

        if( p_sys->i_picture_structure != 0x03 )
        {
            p_sys->b_second_field = !p_sys->b_second_field;
        }
        else
        {
            p_sys->b_second_field = 0;
        }

        /* CC */
        p_sys->b_cc_reset = true;
        p_sys->i_cc_pts = p_pic->i_pts;
        p_sys->i_cc_dts = p_pic->i_dts;
        p_sys->i_cc_flags = p_pic->i_flags;
    }

    if( !p_pic && p_sys->b_cc_reset )
    {
        p_sys->b_cc_reset = false;
        cc_Flush( &p_sys->cc );
    }

    if( !p_frag )
        return p_pic;
    /*
     * Check info of current fragment
     */
    if( p_frag->p_buffer[3] == 0xb8 )
    {
        /* Group start code */
        if( p_sys->p_seq &&
            p_sys->i_seq_old > p_sys->i_frame_rate/p_sys->i_frame_rate_base )
        {
            /* Useful for mpeg1: repeat sequence header every second */
            block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_seq ) );
            if( p_sys->p_ext )
            {
                block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_ext ) );
            }

            p_sys->i_seq_old = 0;
        }
    }
    else if( p_frag->p_buffer[3] == 0xb3 && p_frag->i_buffer >= 8 )
    {
        /* Sequence header code */
        static const int code_to_frame_rate[16][2] =
        {
            { 1, 1 },  /* invalid */
            { 24000, 1001 }, { 24, 1 }, { 25, 1 },       { 30000, 1001 },
            { 30, 1 },       { 50, 1 }, { 60000, 1001 }, { 60, 1 },
            /* Unofficial 15fps from Xing*/
            { 15, 1001 },
            /* Unofficial economy rates from libmpeg3 */
            { 5000, 1001 }, { 1000, 1001 }, { 12000, 1001 }, { 15000, 1001 },
            { 1, 1 },  { 1, 1 }  /* invalid */
        };

        if( p_sys->p_seq ) block_Release( p_sys->p_seq );
        if( p_sys->p_ext ) block_Release( p_sys->p_ext );

        p_sys->p_seq = block_Duplicate( p_frag );
        p_sys->i_seq_old = 0;
        p_sys->p_ext = NULL;

        p_dec->fmt_out.video.i_width =
            ( p_frag->p_buffer[4] << 4)|(p_frag->p_buffer[5] >> 4 );
        p_dec->fmt_out.video.i_height =
            ( (p_frag->p_buffer[5]&0x0f) << 8 )|p_frag->p_buffer[6];
        p_sys->i_aspect_ratio_info = p_frag->p_buffer[7] >> 4;

        /* TODO: MPEG1 aspect ratio */

        p_sys->i_frame_rate = code_to_frame_rate[p_frag->p_buffer[7]&0x0f][0];
        p_sys->i_frame_rate_base =
            code_to_frame_rate[p_frag->p_buffer[7]&0x0f][1];

        p_dec->fmt_out.video.i_frame_rate = p_sys->i_frame_rate;
        p_dec->fmt_out.video.i_frame_rate_base = p_sys->i_frame_rate_base;

        p_sys->b_seq_progressive = true;
        p_sys->b_low_delay = true;

        if ( !p_sys->b_inited )
        {
            msg_Dbg( p_dec, "size %dx%d fps=%.3f",
                 p_dec->fmt_out.video.i_width, p_dec->fmt_out.video.i_height,
                 p_sys->i_frame_rate / (float)p_sys->i_frame_rate_base );
            p_sys->b_inited = 1;
        }
    }
    else if( p_frag->p_buffer[3] == 0xb5 )
Пример #13
0
Файл: ps.c Проект: mstorsjo/vlc
/*****************************************************************************
 * Demux:
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    int i_ret, i_mux_rate;
    block_t *p_pkt;

    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
    if( i_ret < 0 )
    {
        return VLC_DEMUXER_EOF;
    }
    else if( i_ret == 0 )
    {
        if( !p_sys->b_lost_sync )
        {
            msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...",
                                vlc_stream_Tell(p_demux->s) );
            NotifyDiscontinuity( p_sys->tk, p_demux->out );
        }

        p_sys->b_lost_sync = true;
        return VLC_DEMUXER_SUCCESS;
    }

    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
    p_sys->b_lost_sync = false;

    if( p_sys->i_length == VLC_TICK_INVALID && p_sys->b_seekable )
    {
        if( !FindLength( p_demux ) )
            return VLC_DEMUXER_EGENERIC;
    }

    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
    {
        return VLC_DEMUXER_EOF;
    }

    if( p_pkt->i_buffer < 4 )
    {
        block_Release( p_pkt );
        return VLC_DEMUXER_EGENERIC;
    }

    const uint8_t i_stream_id = p_pkt->p_buffer[3];
    switch( i_stream_id )
    {
    case PS_STREAM_ID_END_STREAM:
        block_Release( p_pkt );
        break;

    case PS_STREAM_ID_PACK_HEADER:
        if( !ps_pkt_parse_pack( p_pkt, &p_sys->i_pack_scr, &i_mux_rate ) )
        {
            if( p_sys->i_first_scr == VLC_TICK_INVALID )
                p_sys->i_first_scr = p_sys->i_pack_scr;
            CheckPCR( p_sys, p_demux->out, p_sys->i_pack_scr );
            p_sys->i_scr = p_sys->i_pack_scr;
            p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s );
            if( !p_sys->b_have_pack ) p_sys->b_have_pack = true;
            /* done later on to work around bad vcd/svcd streams */
            /* es_out_SetPCR( p_demux->out, p_sys->i_scr ); */
            if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
        }
        block_Release( p_pkt );
        break;

    case PS_STREAM_ID_SYSTEM_HEADER:
        if( !ps_pkt_parse_system( p_pkt, &p_sys->psm, p_sys->tk ) )
        {
            int i;
            for( i = 0; i < PS_TK_COUNT; i++ )
            {
                ps_track_t *tk = &p_sys->tk[i];

                if( !tk->b_configured && tk->fmt.i_cat != UNKNOWN_ES )
                {
                    if( tk->b_seen )
                        tk->es = es_out_Add( p_demux->out, &tk->fmt );
                     /* else create when seeing packet */
                    tk->b_configured = true;
                }
            }
        }
        block_Release( p_pkt );
        break;

    case PS_STREAM_ID_MAP:
        if( p_sys->psm.i_version == 0xFFFF )
            msg_Dbg( p_demux, "contains a PSM");

        ps_psm_fill( &p_sys->psm, p_pkt, p_sys->tk, p_demux->out );
        block_Release( p_pkt );
        break;

    default:
        /* Reject non video/audio nor PES */
        if( i_stream_id < 0xC0 || i_stream_id > 0xEF )
        {
            block_Release( p_pkt );
            break;
        }
        /* fallthrough */
    case PS_STREAM_ID_PRIVATE_STREAM1:
    case PS_STREAM_ID_EXTENDED:
        {
            int i_id = ps_pkt_id( p_pkt );
            /* Small heuristic to improve MLP detection from AOB */
            if( i_id == 0xa001 &&
                p_sys->i_aob_mlp_count < 500 )
            {
                p_sys->i_aob_mlp_count++;
            }
            else if( i_id == 0xbda1 &&
                     p_sys->i_aob_mlp_count > 0 )
            {
                p_sys->i_aob_mlp_count--;
                i_id = 0xa001;
            }

            bool b_new = false;
            ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];

            if( !tk->b_configured )
            {
                if( !ps_track_fill( tk, &p_sys->psm, i_id, p_pkt, false ) )
                {
                    /* No PSM and no probing yet */
                    if( p_sys->format == PSMF_PS )
                    {
                        if( tk->fmt.i_cat == VIDEO_ES )
                            tk->fmt.i_codec = VLC_CODEC_H264;
#if 0
                        if( i_stream_id == PS_STREAM_ID_PRIVATE_STREAM1 )
                        {
                            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_ATRAC3P );
                            tk->fmt.audio.i_blockalign = 376;
                            tk->fmt.audio.i_channels = 2;
                            tk->fmt.audio.i_rate = 44100;
                        }
#endif
                    }

                    tk->es = es_out_Add( p_demux->out, &tk->fmt );
                    b_new = true;
                    tk->b_configured = true;
                }
                else
                {
                    msg_Dbg( p_demux, "es id=0x%x format unknown", i_id );
                }
            }

            /* Late creation from system header */
            if( !tk->b_seen && tk->b_configured && !tk->es && tk->fmt.i_cat != UNKNOWN_ES )
                tk->es = es_out_Add( p_demux->out, &tk->fmt );

            tk->b_seen = true;

            /* The popular VCD/SVCD subtitling WinSubMux does not
             * renumber the SCRs when merging subtitles into the PES */
            if( tk->b_seen && !p_sys->b_bad_scr &&
                ( tk->fmt.i_codec == VLC_CODEC_OGT ||
                  tk->fmt.i_codec == VLC_CODEC_CVD ) )
            {
                p_sys->b_bad_scr = true;
                p_sys->i_first_scr = VLC_TICK_INVALID;
            }

            if( p_sys->i_pack_scr != VLC_TICK_INVALID && !p_sys->b_bad_scr )
            {
                if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) &&
                    tk->i_first_pts != VLC_TICK_INVALID && tk->i_first_pts - p_sys->i_pack_scr > VLC_TICK_FROM_SEC(2))
                {
                    msg_Warn( p_demux, "Incorrect SCR timing offset by of %"PRId64 "ms, disabling",
                                       MS_FROM_VLC_TICK(tk->i_first_pts - p_sys->i_pack_scr) );
                    p_sys->b_bad_scr = true; /* Disable Offset SCR */
                    p_sys->i_first_scr = VLC_TICK_INVALID;
                }
                else
                    es_out_SetPCR( p_demux->out, p_sys->i_pack_scr );
            }

            if( tk->b_configured && tk->es &&
                !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) )
            {
                if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES )
                {
                    if( !p_sys->b_bad_scr && p_sys->i_pack_scr != VLC_TICK_INVALID && p_pkt->i_pts != VLC_TICK_INVALID &&
                        p_sys->i_pack_scr > p_pkt->i_pts + VLC_TICK_FROM_MS(250) )
                    {
                        msg_Warn( p_demux, "Incorrect SCR timing in advance of %" PRId64 "ms, disabling",
                                           MS_FROM_VLC_TICK(p_sys->i_pack_scr - p_pkt->i_pts) );
                        p_sys->b_bad_scr = true;
                        p_sys->i_first_scr = VLC_TICK_INVALID;
                    }

                    if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id )
                    {
                        p_sys->i_scr_track_id = tk->i_id;
                    }
                }

                if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) &&
                    p_sys->i_scr_track_id == tk->i_id &&
                    p_pkt->i_pts != VLC_TICK_INVALID )
                {
                    /* A hack to sync the A/V on PES files. */
                    msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts );
                    CheckPCR( p_sys, p_demux->out, p_pkt->i_pts );
                    p_sys->i_scr = p_pkt->i_pts;
                    if( p_sys->i_first_scr == VLC_TICK_INVALID )
                        p_sys->i_first_scr = p_sys->i_scr;
                    es_out_SetPCR( p_demux->out, p_pkt->i_pts );
                }

                if( tk->fmt.i_codec == VLC_CODEC_TELETEXT &&
                    p_pkt->i_pts == VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID )
                {
                    /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A)
                     * In this case use the last SCR + 40ms */
                    p_pkt->i_pts = p_sys->i_scr + VLC_TICK_FROM_MS(40);
                }

                if( p_pkt->i_pts > p_sys->i_current_pts )
                {
                    p_sys->i_current_pts = p_pkt->i_pts;
                }

                if( tk->i_next_block_flags )
                {
                    p_pkt->i_flags = tk->i_next_block_flags;
                    tk->i_next_block_flags = 0;
                }
#if 0
                if( tk->fmt.i_codec == VLC_CODEC_ATRAC3P )
                {
                    p_pkt->p_buffer += 14;
                    p_pkt->i_buffer -= 14;
                }
#endif
                es_out_Send( p_demux->out, tk->es, p_pkt );
            }
            else
            {
                block_Release( p_pkt );
            }

            p_sys->i_pack_scr = VLC_TICK_INVALID;
        }
        break;
    }

    demux_UpdateTitleFromStream( p_demux );
    return VLC_DEMUXER_SUCCESS;
}
Пример #14
0
block_t *DirBlock (access_t *p_access)
{
    access_sys_t *p_sys = p_access->p_sys;
    directory_t *current = p_sys->current;

    if (p_access->info.b_eof)
        return NULL;

    if (current == NULL)
    {   /* Startup: send the XSPF header */
        static const char header[] =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            "<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\" xmlns:vlc=\"http://www.videolan.org/vlc/playlist/ns/0/\">\n"
            " <trackList>\n";
        block_t *block = block_Alloc (sizeof (header) - 1);
        if (!block)
            goto fatal;
        memcpy (block->p_buffer, header, sizeof (header) - 1);

        /* "Open" the base directory */
        current = malloc (sizeof (*current));
        if (current == NULL)
        {
            block_Release (block);
            goto fatal;
        }
        current->parent = NULL;
        current->handle = p_sys->handle;
#ifndef HAVE_OPENAT
        current->path = strdup (p_access->psz_filepath);
#endif
        current->uri = p_sys->uri;
        if (fstat (dirfd (current->handle), &current->st))
        {
            free (current);
            block_Release (block);
            goto fatal;
        }

        p_sys->handle = NULL;
        p_sys->uri = NULL;
        p_sys->current = current;
        return block;
    }

    char *entry = vlc_readdir (current->handle);
    if (entry == NULL)
    {   /* End of directory, go back to parent */
        closedir (current->handle);
        p_sys->current = current->parent;
        free (current->uri);
#ifndef HAVE_OPENAT
        free (current->path);
#endif
        free (current);

        if (p_sys->current == NULL)
        {   /* End of XSPF playlist */
            char *footer;
            int len = asprintf( &footer, " </trackList>\n" \
                " <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" \
                "%s" \
                " </extension>\n" \
                "</playlist>\n", p_sys->psz_xspf_extension );
            if (unlikely(len == -1))
                goto fatal;

            block_t *block = block_heap_Alloc (footer, footer, len);
            if (unlikely(block == NULL))
                free (footer);
            p_access->info.b_eof = true;
            return block;
        }
        else
        {
            /* This was the end of a "subnode" */
            /* Write the ID to the extension */
            char *old_xspf_extension = p_sys->psz_xspf_extension;
            if (old_xspf_extension == NULL)
                goto fatal;

            int len2 = asprintf( &p_sys->psz_xspf_extension, "%s  </vlc:node>\n", old_xspf_extension );
            if (len2 == -1)
                goto fatal;
            free( old_xspf_extension );
        }
        return NULL;
    }

    /* Skip current, parent and hidden directories */
    if (entry[0] == '.')
    {
        free (entry);
        return NULL;
    }
    /* Handle recursion */
    if (p_sys->mode != MODE_COLLAPSE)
    {
        directory_t *sub = malloc (sizeof (*sub));
        if (sub == NULL)
        {
            free (entry);
            return NULL;
        }

        DIR *handle;
#ifdef HAVE_OPENAT
        int fd = vlc_openat (dirfd (current->handle), entry, O_RDONLY);
        if (fd != -1)
        {
            handle = fdopendir (fd);
            if (handle == NULL)
                close (fd);
        }
        else
            handle = NULL;
#else
        if (asprintf (&sub->path, "%s/%s", current->path, entry) != -1)
            handle = vlc_opendir (sub->path);
        else
            handle = NULL;
#endif
        if (handle != NULL)
        {
            sub->parent = current;
            sub->handle = handle;

            char *encoded = encode_URI_component (entry);
            if ((encoded == NULL)
             || (asprintf (&sub->uri, "%s/%s", current->uri, encoded) == -1))
                 sub->uri = NULL;
            free (encoded);

            if ((p_sys->mode == MODE_NONE)
             || fstat (dirfd (handle), &sub->st)
             || has_inode_loop (sub)
             || (sub->uri == NULL))
            {
                free (entry);
                closedir (handle);
                free (sub->uri);
                free (sub);
                return NULL;
            }
            p_sys->current = sub;

            /* Add node to xspf extension */
            char *old_xspf_extension = p_sys->psz_xspf_extension;
            if (old_xspf_extension == NULL)
            {
                free (entry);
                goto fatal;
            }

            char *title = convert_xml_special_chars (entry);
            free (entry);
            if (title == NULL
             || asprintf (&p_sys->psz_xspf_extension, "%s"
                          "  <vlc:node title=\"%s\">\n", old_xspf_extension,
                          title) == -1)
            {
                free (title);
                goto fatal;
            }
            free (title);
            free (old_xspf_extension);
            return NULL;
        }
        else
            free (sub);
    }

    /* Skip files with ignored extensions */
    if (p_sys->ignored_exts != NULL)
    {
        const char *ext = strrchr (entry, '.');
        if (ext != NULL)
        {
            size_t extlen = strlen (++ext);
            for (const char *type = p_sys->ignored_exts, *end;
                 type[0]; type = end + 1)
            {
                end = strchr (type, ',');
                if (end == NULL)
                    end = type + strlen (type);

                if (type + extlen == end
                 && !strncasecmp (ext, type, extlen))
                {
                    free (entry);
                    return NULL;
                }

                if (*end == '\0')
                    break;
            }
        }
    }

    char *encoded = encode_URI_component (entry);
    free (entry);
    if (encoded == NULL)
        goto fatal;
    int len = asprintf (&entry,
                        "  <track><location>%s/%s</location>\n" \
                        "   <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" \
                        "    <vlc:id>%d</vlc:id>\n" \
                        "   </extension>\n" \
                        "  </track>\n",
                        current->uri, encoded, p_sys->i_item_count++);
    free (encoded);
    if (len == -1)
        goto fatal;

    /* Write the ID to the extension */
    char *old_xspf_extension = p_sys->psz_xspf_extension;
    if (old_xspf_extension == NULL)
        goto fatal;

    int len2 = asprintf( &p_sys->psz_xspf_extension, "%s   <vlc:item tid=\"%i\" />\n",
                            old_xspf_extension, p_sys->i_item_count-1 );
    if (len2 == -1)
        goto fatal;
    free( old_xspf_extension );

    block_t *block = block_heap_Alloc (entry, entry, len);
    if (unlikely(block == NULL))
    {
        free (entry);
        goto fatal;
    }
    return block;

fatal:
    p_access->info.b_eof = true;
    return NULL;
}
Пример #15
0
static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block)
{
    block_t *p_block;
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_out = NULL;

    if (pp_block == NULL)
        return NULL;
    p_block = *pp_block;
    if (p_block == NULL)
        return NULL;
    *pp_block = NULL;

    if (p_block->i_pts > VLC_TS_INVALID && !date_Get (&p_sys->end_date))
        date_Set (&p_sys->end_date, p_block->i_pts);
    else
    if (p_block->i_pts < date_Get (&p_sys->end_date))
    {
        msg_Warn (p_dec, "MIDI message in the past?");
        goto drop;
    }

    if (p_block->i_buffer < 1)
        goto drop;

    uint8_t event = p_block->p_buffer[0];
    uint8_t channel = p_block->p_buffer[0] & 0xf;
    event &= 0xF0;

    if (event == 0xF0)
        switch (channel)
        {
            case 0:
                if (p_block->p_buffer[p_block->i_buffer - 1] != 0xF7)
                {
            case 7:
                    msg_Warn (p_dec, "fragmented SysEx not implemented");
                    goto drop;
                }
                fluid_synth_sysex (p_sys->synth, (char *)p_block->p_buffer + 1,
                                   p_block->i_buffer - 2, NULL, NULL, NULL, 0);
                break;
            case 0xF:
                fluid_synth_system_reset (p_sys->synth);
                break;
        }

    uint8_t p1 = (p_block->i_buffer > 1) ? (p_block->p_buffer[1] & 0x7f) : 0;
    uint8_t p2 = (p_block->i_buffer > 2) ? (p_block->p_buffer[2] & 0x7f) : 0;

    switch (event & 0xF0)
    {
        case 0x80:
            fluid_synth_noteoff (p_sys->synth, channel, p1);
            break;
        case 0x90:
            fluid_synth_noteon (p_sys->synth, channel, p1, p2);
            break;
        /*case 0xA0: note aftertouch not implemented */
        case 0xB0:
            fluid_synth_cc (p_sys->synth, channel, p1, p2);
            break;
        case 0xC0:
            fluid_synth_program_change (p_sys->synth, channel, p1);
            break;
        case 0xD0:
            fluid_synth_channel_pressure (p_sys->synth, channel, p1);
            break;
        case 0xE0:
            fluid_synth_pitch_bend (p_sys->synth, channel, (p2 << 7) | p1);
            break;
    }

    unsigned samples =
        (p_block->i_pts - date_Get (&p_sys->end_date)) * 441 / 10000;
    if (samples == 0)
        goto drop;

    p_out = decoder_NewAudioBuffer (p_dec, samples);
    if (p_out == NULL)
        goto drop;

    p_out->i_pts = date_Get (&p_sys->end_date );
    p_out->i_length = date_Increment (&p_sys->end_date, samples)
                      - p_out->i_pts;
    fluid_synth_write_float (p_sys->synth, samples, p_out->p_buffer, 0, 2,
                             p_out->p_buffer, 1, 2);
drop:
    block_Release (p_block);
    return p_out;
}
Пример #16
0
static int Open(vlc_object_t *object)
{
    demux_t *demux = (demux_t*)object;

    /* Detect the image type */
    const image_format_t *img;

    const uint8_t *peek;
    int peek_size = 0;
    for (int i = 0; ; i++) {
        img = &formats[i];
        if (!img->codec)
            return VLC_EGENERIC;

        if (img->detect) {
            if (img->detect(demux->s))
                break;
        } else {
            if (peek_size < img->marker_size)
                peek_size = stream_Peek(demux->s, &peek, img->marker_size);
            if (peek_size >= img->marker_size &&
                !memcmp(peek, img->marker, img->marker_size))
                break;
        }
    }
    msg_Dbg(demux, "Detected image: %s",
            vlc_fourcc_GetDescription(VIDEO_ES, img->codec));

    if( img->codec == VLC_CODEC_MXPEG )
    {
        return VLC_EGENERIC; //let avformat demux this file
    }

    /* Load and if selected decode */
    es_format_t fmt;
    es_format_Init(&fmt, VIDEO_ES, img->codec);
    fmt.video.i_chroma = fmt.i_codec;

    block_t *data = Load(demux);
    if (data && var_InheritBool(demux, "image-decode")) {
        char *string = var_InheritString(demux, "image-chroma");
        vlc_fourcc_t chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, string);
        free(string);

        data = Decode(demux, &fmt.video, chroma, data);
        fmt.i_codec = fmt.video.i_chroma;
    }
    fmt.i_id    = var_InheritInteger(demux, "image-id");
    fmt.i_group = var_InheritInteger(demux, "image-group");
    if (var_InheritURational(demux,
                             &fmt.video.i_frame_rate,
                             &fmt.video.i_frame_rate_base,
                             "image-fps") ||
        fmt.video.i_frame_rate <= 0 || fmt.video.i_frame_rate_base <= 0) {
        msg_Err(demux, "Invalid frame rate, using 10/1 instead");
        fmt.video.i_frame_rate      = 10;
        fmt.video.i_frame_rate_base = 1;
    }

    /* If loadind failed, we still continue to avoid mis-detection
     * by other demuxers. */
    if (!data)
        msg_Err(demux, "Failed to load the image");

    /* */
    demux_sys_t *sys = malloc(sizeof(*sys));
    if (!sys) {
        if (data)
            block_Release(data);
        es_format_Clean(&fmt);
        return VLC_ENOMEM;
    }

    sys->data        = data;
    sys->es          = es_out_Add(demux->out, &fmt);
    sys->duration    = CLOCK_FREQ * var_InheritFloat(demux, "image-duration");
    sys->is_realtime = var_InheritBool(demux, "image-realtime");
    sys->pts_origin  = sys->is_realtime ? mdate() : 0;
    sys->pts_next    = VLC_TS_INVALID;
    date_Init(&sys->pts, fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
    date_Set(&sys->pts, 0);

    es_format_Clean(&fmt);

    demux->pf_demux   = Demux;
    demux->pf_control = Control;
    demux->p_sys      = sys;
    return VLC_SUCCESS;
}
Пример #17
0
/*****************************************************************************
 * Write:
 *****************************************************************************/
static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
{
    sout_access_out_sys_t *p_sys = p_access->p_sys;
    int i_err = 0;
    int i_len = 0;

    while( p_buffer )
    {
        block_t *p_next;

        if( p_buffer->i_flags & BLOCK_FLAG_HEADER )
        {
            /* gather header */
            if( p_sys->b_header_complete )
            {
                /* free previously gathered header */
                p_sys->i_header_size = 0;
                p_sys->b_header_complete = false;
            }
            if( (int)(p_buffer->i_buffer + p_sys->i_header_size) >
                p_sys->i_header_allocated )
            {
                p_sys->i_header_allocated =
                    p_buffer->i_buffer + p_sys->i_header_size + 1024;
                p_sys->p_header = xrealloc( p_sys->p_header,
                                                  p_sys->i_header_allocated );
            }
            memcpy( &p_sys->p_header[p_sys->i_header_size],
                    p_buffer->p_buffer,
                    p_buffer->i_buffer );
            p_sys->i_header_size += p_buffer->i_buffer;
        }
        else if( !p_sys->b_header_complete )
        {
            p_sys->b_header_complete = true;

            httpd_StreamHeader( p_sys->p_httpd_stream, p_sys->p_header,
                                p_sys->i_header_size );
        }

        i_len += p_buffer->i_buffer;
        /* send data */
        i_err = httpd_StreamSend( p_sys->p_httpd_stream, p_buffer->p_buffer,
                                  p_buffer->i_buffer );

        p_next = p_buffer->p_next;
        block_Release( p_buffer );
        p_buffer = p_next;

        if( i_err < 0 )
        {
            break;
        }
    }

    if( i_err < 0 )
    {
        block_ChainRelease( p_buffer );
    }

    return( i_err < 0 ? VLC_EGENERIC : i_len );
}
Пример #18
0
Файл: codec.c Проект: Adatan/vlc
static picture_t *decode(decoder_t *dec, block_t **pblock)
{
    decoder_sys_t *sys = dec->p_sys;
    block_t *block;
    MMAL_BUFFER_HEADER_T *buffer;
    bool need_flush = false;
    uint32_t len;
    uint32_t flags = 0;
    MMAL_STATUS_T status;
    picture_t *ret = NULL;

    /*
     * Configure output port if necessary
     */
    if (sys->output_format) {
        if (change_output_format(dec) < 0)
            msg_Err(dec, "Failed to change output port format");
    }

    if (!pblock)
        goto out;

    block = *pblock;

    /*
     * Check whether full flush is required
     */
    if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) {
        flush_decoder(dec);
        block_Release(*pblock);
        return NULL;
    }

    /*
     * Send output buffers
     */
    if (atomic_load(&sys->started)) {
        buffer = mmal_queue_get(sys->decoded_pictures);
        if (buffer) {
            ret = (picture_t *)buffer->user_data;
            ret->date = buffer->pts;
            ret->b_progressive = sys->b_progressive;
            ret->b_top_field_first = sys->b_top_field_first;

            if (sys->output_pool) {
                buffer->data = NULL;
                mmal_buffer_header_reset(buffer);
                mmal_buffer_header_release(buffer);
            }
        }

        fill_output_port(dec);
    }

    if (ret)
        goto out;

    /*
     * Process input
     */
    if (!block)
        goto out;

    *pblock = NULL;

    if (block->i_flags & BLOCK_FLAG_CORRUPTED)
        flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;

    vlc_mutex_lock(&sys->mutex);
    while (block->i_buffer > 0) {
        buffer = mmal_queue_timedwait(sys->input_pool->queue, 2);
        if (!buffer) {
            msg_Err(dec, "Failed to retrieve buffer header for input data");
            need_flush = true;
            break;
        }
        mmal_buffer_header_reset(buffer);
        buffer->cmd = 0;
        buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts;
        buffer->dts = block->i_dts;
        buffer->alloc_size = sys->input->buffer_size;

        len = block->i_buffer;
        if (len > buffer->alloc_size)
            len = buffer->alloc_size;

        buffer->data = block->p_buffer;
        block->p_buffer += len;
        block->i_buffer -= len;
        buffer->length = len;
        if (block->i_buffer == 0)
            buffer->user_data = block;
        buffer->flags = flags;

        status = mmal_port_send_buffer(sys->input, buffer);
        if (status != MMAL_SUCCESS) {
            msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)",
                    status, mmal_status_to_string(status));
            break;
        }
        atomic_fetch_add(&sys->input_in_transit, 1);
    }
    vlc_mutex_unlock(&sys->mutex);

out:
    if (need_flush)
        flush_decoder(dec);

    return ret;
}
Пример #19
0
/****************************************************************************
 * Decode: the whole thing
 ****************************************************************************/
static picture_t *Decode(decoder_t *dec, block_t **pp_block)
{
    struct vpx_codec_ctx *ctx = &dec->p_sys->ctx;

    block_t *block = *pp_block;
    if (!block)
        return NULL;

    if (block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
        return NULL;

    /* Associate packet PTS with decoded frame */
    mtime_t *pkt_pts = malloc(sizeof(*pkt_pts));
    if (!pkt_pts) {
        block_Release(block);
        *pp_block = NULL;
        return NULL;
    }

    *pkt_pts = block->i_pts;

    vpx_codec_err_t err;
    err = vpx_codec_decode(ctx, block->p_buffer, block->i_buffer, pkt_pts, 0);

    block_Release(block);
    *pp_block = NULL;

    if (err != VPX_CODEC_OK) {
        free(pkt_pts);
        const char *error  = vpx_codec_error(ctx);
        const char *detail = vpx_codec_error_detail(ctx);
        if (!detail)
            detail = "no specific information";
        msg_Err(dec, "Failed to decode frame: %s (%s)", error, detail);
        return NULL;
    }

    const void *iter = NULL;
    struct vpx_image *img = vpx_codec_get_frame(ctx, &iter);
    if (!img) {
        free(pkt_pts);
        return NULL;
    }

    /* fetches back the PTS */
    pkt_pts = img->user_priv;
    mtime_t pts = *pkt_pts;
    free(pkt_pts);

    if (img->fmt != VPX_IMG_FMT_I420) {
        msg_Err(dec, "Unsupported output colorspace %d", img->fmt);
        return NULL;
    }

    video_format_t *v = &dec->fmt_out.video;

    if (img->d_w != v->i_visible_width || img->d_h != v->i_visible_height) {
        v->i_visible_width = img->d_w;
        v->i_visible_height = img->d_h;
    }

    picture_t *pic = decoder_NewPicture(dec);
    if (!pic)
        return NULL;

    for (int plane = 0; plane < pic->i_planes; plane++ ) {
        uint8_t *src = img->planes[plane];
        uint8_t *dst = pic->p[plane].p_pixels;
        int src_stride = img->stride[plane];
        int dst_stride = pic->p[plane].i_pitch;

        int size = __MIN( src_stride, dst_stride );
        for( int line = 0; line < pic->p[plane].i_visible_lines; line++ ) {
            memcpy( dst, src, size );
            src += src_stride;
            dst += dst_stride;
        }
    }

    pic->b_progressive = true; /* codec does not support interlacing */
    pic->date = pts;

    return pic;
}
Пример #20
0
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************
 * This function is called just after the thread is launched.
 ****************************************************************************/
static void *DecodeBlock( 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];
    uint8_t *p_buf;
    void *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 )
    {
        /* 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:
            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 != 0 &&
                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 */
            if( vlc_a52_header_Parse( &p_sys->frame, 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;
            }

            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->frame.i_size, p_header, 2 )
                != VLC_SUCCESS )
            {
                /* Need more data */
                return NULL;
            }

            if( p_sys->b_packetizer &&
                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_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, p_sys->frame.i_size );

            /* 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 = 0;

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

    return NULL;
}
Пример #21
0
static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
                             video_format_t *p_fmt_in,
                             video_format_t *p_fmt_out )
{
    picture_t *p_pic = NULL, *p_tmp;

    /* Check if we can reuse the current decoder */
    if( p_image->p_dec &&
        p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma )
    {
        DeleteDecoder( p_image->p_dec );
        p_image->p_dec = 0;
    }

    /* Start a decoder */
    if( !p_image->p_dec )
    {
        p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
        if( !p_image->p_dec )
        {
            block_Release(p_block);
            return NULL;
        }
    }

    p_block->i_pts = p_block->i_dts = mdate();
    while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
             != NULL )
    {
        if( p_pic != NULL )
            picture_Release( p_pic );
        p_pic = p_tmp;
    }

    if( p_pic == NULL )
    {
        msg_Warn( p_image->p_parent, "no image decoded" );
        return 0;
    }

    if( !p_fmt_out->i_chroma )
        p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma;
    if( !p_fmt_out->i_width && p_fmt_out->i_height )
        p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width *
                             p_image->p_dec->fmt_out.video.i_sar_num *
                             p_fmt_out->i_height /
                             p_image->p_dec->fmt_out.video.i_height /
                             p_image->p_dec->fmt_out.video.i_sar_den;

    if( !p_fmt_out->i_height && p_fmt_out->i_width )
        p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height *
                              p_image->p_dec->fmt_out.video.i_sar_den *
                              p_fmt_out->i_width /
                              p_image->p_dec->fmt_out.video.i_width /
                              p_image->p_dec->fmt_out.video.i_sar_num;
    if( !p_fmt_out->i_width )
        p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width;
    if( !p_fmt_out->i_height )
        p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height;
    if( !p_fmt_out->i_visible_width )
        p_fmt_out->i_visible_width = p_fmt_out->i_width;
    if( !p_fmt_out->i_visible_height )
        p_fmt_out->i_visible_height = p_fmt_out->i_height;

    /* Check if we need chroma conversion or resizing */
    if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma ||
        p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width ||
        p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height )
    {
        if( p_image->p_filter )
        if( p_image->p_filter->fmt_in.video.i_chroma !=
            p_image->p_dec->fmt_out.video.i_chroma ||
            p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma )
        {
            /* We need to restart a new filter */
            DeleteFilter( p_image->p_filter );
            p_image->p_filter = 0;
        }

        /* Start a filter */
        if( !p_image->p_filter )
        {
            p_image->p_filter =
                CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out,
                              p_fmt_out );

            if( !p_image->p_filter )
            {
                picture_Release( p_pic );
                return NULL;
            }
        }
        else
        {
            /* Filters should handle on-the-fly size changes */
            p_image->p_filter->fmt_in = p_image->p_dec->fmt_out;
            p_image->p_filter->fmt_out = p_image->p_dec->fmt_out;
            p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma;
            p_image->p_filter->fmt_out.video = *p_fmt_out;
        }

        p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic );
        *p_fmt_out = p_image->p_filter->fmt_out.video;
    }
    else *p_fmt_out = p_image->p_dec->fmt_out.video;

    return p_pic;
}
Пример #22
0
Файл: access.c Проект: BtbN/vlc
/*****************************************************************************
  VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
  NULL is returned if something went wrong.
 *****************************************************************************/
static block_t *
VCDReadBlock( access_t * p_access )
{
    vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
    const int    i_blocks   = p_vcdplayer->i_blocks_per_read;
    block_t     *p_block;
    int          i_read;
    uint8_t     *p_buf;

    dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
               (long unsigned int) p_vcdplayer->i_lsn );

    /* Allocate a block for the reading */
    if( !( p_block = block_Alloc( i_blocks * M2F2_SECTOR_SIZE ) ) )
    {
        msg_Err( p_access, "cannot get a new block of size: %i",
                 i_blocks * M2F2_SECTOR_SIZE );
        block_Release( p_block );
        return NULL;
    }

    p_buf = (uint8_t *) p_block->p_buffer;
    for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
    {
        vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);

        p_access->info.i_pos += M2F2_SECTOR_SIZE;

        switch ( read_status ) {
        case READ_END:
            /* End reached. Return NULL to indicated this. */
            /* We also set the postion to the end so the higher level
               (demux?) doesn't try to keep reading. If everything works out
               right this shouldn't have to happen.
             */
#if 0
            if( p_access->info.i_pos != p_access->info.i_size ) {
                msg_Warn( p_access,
                    "At end but pos (%llu) is not size (%llu). Adjusting.",
                    p_access->info.i_pos, p_access->info.i_size );
                p_access->info.i_pos = p_access->info.i_size;
            }
#endif

            block_Release( p_block );
            return NULL;

        case READ_ERROR:
            /* Some sort of error. Should we increment lsn? to skip block? */
            block_Release( p_block );
            return NULL;
        case READ_STILL_FRAME:
          /* FIXME The below should be done in an event thread.
             Until then...
           */
#if 1
            msleep( INT64_C(1000) * *p_buf );
            VCDSetOrigin(p_access, p_vcdplayer->origin_lsn,
                         p_vcdplayer->i_track, &(p_vcdplayer->play_item));
            // p_vcd->in_still = false;
            dbg_print(INPUT_DBG_STILL, "still wait time done");
#endif

            block_Release( p_block );
            return NULL;

        default:
        case READ_BLOCK:
            /* Read buffer */
            break;
        }

        p_buf += M2F2_SECTOR_SIZE;
        /* Update seekpoint */
        if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
        {
            size_t i_entry = p_vcdplayer->play_item.num+1;
            lsn_t  i_lsn   = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
            if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
            {
                dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
                           "entry change to %zu, current LSN %u >= end %u",
                           i_entry, p_vcdplayer->i_lsn, i_lsn);

                p_vcdplayer->play_item.num = i_entry;

                VCDSetOrigin( p_access,  i_lsn, p_vcdplayer->i_track,
                              &(p_vcdplayer->play_item) );
            }
        }
    }

    return p_block;
}
Пример #23
0
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************
 * This function must be fed with a complete compressed frame.
 ****************************************************************************/
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block;
    picture_t *p_pic = 0;

    png_uint_32 i_width, i_height;
    int i_color_type, i_interlace_type, i_compression_type, i_filter_type;
    int i_bit_depth, i;

    png_structp p_png;
    png_infop p_info, p_end_info;
    png_bytep *p_row_pointers = NULL;

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

    p_block = *pp_block;
    p_sys->b_error = false;

    if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
    {
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    if( p_png == NULL )
    {
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    p_info = png_create_info_struct( p_png );
    if( p_info == NULL )
    {
        png_destroy_read_struct( &p_png, NULL, NULL );
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    p_end_info = png_create_info_struct( p_png );
    if( p_end_info == NULL )
    {
        png_destroy_read_struct( &p_png, &p_info, NULL );
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    /* libpng longjmp's there in case of error */
    if( setjmp( png_jmpbuf( p_png ) ) )
        goto error;

    png_set_read_fn( p_png, (void *)p_block, user_read );
    png_set_error_fn( p_png, (void *)p_dec, user_error, user_warning );

    png_read_info( p_png, p_info );
    if( p_sys->b_error ) goto error;

    png_get_IHDR( p_png, p_info, &i_width, &i_height,
                  &i_bit_depth, &i_color_type, &i_interlace_type,
                  &i_compression_type, &i_filter_type);
    if( p_sys->b_error ) goto error;

    /* Set output properties */
    p_dec->fmt_out.i_codec = VLC_CODEC_RGBA;
    p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width = i_width;
    p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = i_height;
    p_dec->fmt_out.video.i_sar_num = 1;
    p_dec->fmt_out.video.i_sar_den = 1;
    p_dec->fmt_out.video.i_rmask = 0x000000ff;
    p_dec->fmt_out.video.i_gmask = 0x0000ff00;
    p_dec->fmt_out.video.i_bmask = 0x00ff0000;

    if( i_color_type == PNG_COLOR_TYPE_PALETTE )
        png_set_palette_to_rgb( p_png );

    if( i_color_type == PNG_COLOR_TYPE_GRAY ||
        i_color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
          png_set_gray_to_rgb( p_png );

    /* Strip to 8 bits per channel */
    if( i_bit_depth == 16 ) png_set_strip_16( p_png );

    if( png_get_valid( p_png, p_info, PNG_INFO_tRNS ) )
    {
        png_set_tRNS_to_alpha( p_png );
    }
    else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) )
    {
        p_dec->fmt_out.i_codec = VLC_CODEC_RGB24;
    }

    /* Get a new picture */
    p_pic = decoder_NewPicture( p_dec );
    if( !p_pic ) goto error;

    /* Decode picture */
    p_row_pointers = malloc( sizeof(png_bytep) * i_height );
    if( !p_row_pointers )
        goto error;
    for( i = 0; i < (int)i_height; i++ )
        p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;

    png_read_image( p_png, p_row_pointers );
    if( p_sys->b_error ) goto error;
    png_read_end( p_png, p_end_info );
    if( p_sys->b_error ) goto error;

    png_destroy_read_struct( &p_png, &p_info, &p_end_info );
    free( p_row_pointers );

    p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;

    block_Release( p_block ); *pp_block = NULL;
    return p_pic;

 error:

    free( p_row_pointers );
    png_destroy_read_struct( &p_png, &p_info, &p_end_info );
    block_Release( p_block ); *pp_block = NULL;
    return NULL;
}
Пример #24
0
/*****************************************************************************
 * Decode:
 *****************************************************************************/
static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
{
    block_t       *p_block;
    subpicture_t  *p_spu = NULL;

    if( ( pp_block == NULL ) || ( *pp_block == NULL ) ) return NULL;
    p_block = *pp_block;
    *pp_block = NULL;

    if( ( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) ||
          p_block->i_buffer < sizeof(uint16_t) )
    {
        block_Release( p_block );
        return NULL;
    }

    uint8_t *p_buf = p_block->p_buffer;

    /* Read our raw string and create the styled segment for HTML */
    uint16_t i_psz_length = GetWBE( p_buf );
    char *psz_subtitle = malloc( i_psz_length + 1 );
    if ( !psz_subtitle ) return NULL;
    memcpy( psz_subtitle, p_block->p_buffer + sizeof(uint16_t), i_psz_length );
    psz_subtitle[ i_psz_length ] = '\0';
    p_buf += i_psz_length + sizeof(uint16_t);

    for( uint16_t i=0; i < i_psz_length; i++ )
     if ( psz_subtitle[i] == '\r' ) psz_subtitle[i] = '\n';

    segment_t *p_segment = calloc( 1, sizeof(segment_t) );
    if ( !p_segment )
    {
        free( psz_subtitle );
        return NULL;
    }
    p_segment->psz_string = strdup( psz_subtitle );
    p_segment->i_size = strlen( psz_subtitle );
    if ( p_dec->fmt_in.subs.p_style )
    {
        p_segment->styles.i_color = p_dec->fmt_in.subs.p_style->i_font_color;
        p_segment->styles.i_color |= p_dec->fmt_in.subs.p_style->i_font_alpha << 24;
        if ( p_dec->fmt_in.subs.p_style->i_style_flags )
            p_segment->styles.i_flags = p_dec->fmt_in.subs.p_style->i_style_flags;
        p_segment->styles.i_fontsize = p_dec->fmt_in.subs.p_style->i_font_size;
    }

    if ( !p_segment->psz_string )
    {
        SegmentFree( p_segment );
        free( psz_subtitle );
        return NULL;
    }

    /* Create the subpicture unit */
    p_spu = decoder_NewSubpictureText( p_dec );
    if( !p_spu )
    {
        free( psz_subtitle );
        SegmentFree( p_segment );
        return NULL;
    }
    subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;

    /* Parse our styles */
    while( (size_t)(p_buf - p_block->p_buffer) + 8 < p_block->i_buffer )
    {
        uint32_t i_atomsize = GetDWBE( p_buf );
        vlc_fourcc_t i_atomtype = VLC_FOURCC(p_buf[4],p_buf[5],p_buf[6],p_buf[7]);
        p_buf += 8;
        switch( i_atomtype )
        {

        case VLC_FOURCC('s','t','y','l'):
        {
            if ( (size_t)(p_buf - p_block->p_buffer) < 14 ) break;
            uint16_t i_nbrecords = GetWBE(p_buf);
            uint16_t i_cur_record = 0;
            p_buf += 2;
            while( i_cur_record++ < i_nbrecords )
            {
                if ( (size_t)(p_buf - p_block->p_buffer) < 12 ) break;
                uint16_t i_start = __MIN( GetWBE(p_buf), i_psz_length - 1 );
                uint16_t i_end =  __MIN( GetWBE(p_buf + 2), i_psz_length - 1 );

                segment_style_t style;
                style.i_flags = ConvertFlags( p_buf[6] );
                style.i_fontsize = p_buf[7];
                style.i_color = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB
                style.i_color |= (GetDWBE(p_buf+8) & 0xFF) << 24;
                ApplySegmentStyle( &p_segment, i_start, i_end, &style );

                if ( i_nbrecords == 1 )
                {
                    if ( p_buf[6] )
                    {
                        p_spu_sys->style_flags.i_value = ConvertFlags( p_buf[6] );
                        p_spu_sys->style_flags.b_set = true;
                    }
                    p_spu_sys->i_font_height_abs_to_src = p_buf[7];
                    p_spu_sys->font_color.i_value = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB
                    p_spu_sys->font_color.i_value |= (GetDWBE(p_buf+8) & 0xFF) << 24;
                    p_spu_sys->font_color.b_set = true;
                }

                p_buf += 12;
            }
        }   break;

        case VLC_FOURCC('d','r','p','o'):
            if ( (size_t)(p_buf - p_block->p_buffer) < 4 ) break;
            p_spu_sys->i_drop_shadow = __MAX( GetWBE(p_buf), GetWBE(p_buf+2) );
            break;

        case VLC_FOURCC('d','r','p','t'):
            if ( (size_t)(p_buf - p_block->p_buffer) < 2 ) break;
            p_spu_sys->i_drop_shadow_alpha = GetWBE(p_buf);
            break;

        default:
            break;

        }
        p_buf += i_atomsize;
    }

    p_spu->i_start    = p_block->i_pts;
    p_spu->i_stop     = p_block->i_pts + p_block->i_length;
    p_spu->b_ephemer  = (p_block->i_length == 0);
    p_spu->b_absolute = false;

    p_spu_sys->align = SUBPICTURE_ALIGN_BOTTOM;
    p_spu_sys->text  = psz_subtitle;
    p_spu_sys->p_htmlsegments = p_segment;

    block_Release( p_block );

    return p_spu;
}
Пример #25
0
/*****************************************************************************
 * Decode:
 *****************************************************************************/
static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t   *p_sys = p_dec->p_sys;
    block_t         *p_block;
    subpicture_t    *p_spu = NULL;
    video_format_t  fmt;
    bool            b_cached = false;
    vbi_page        p_page;

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

    p_block = *pp_block;
    *pp_block = NULL;

    if( p_block->i_buffer > 0 &&
        ( ( p_block->p_buffer[0] >= 0x10 && p_block->p_buffer[0] <= 0x1f ) ||
          ( p_block->p_buffer[0] >= 0x99 && p_block->p_buffer[0] <= 0x9b ) ) )
    {
        vbi_sliced   *p_sliced = p_sys->p_vbi_sliced;
        unsigned int i_lines = 0;

        p_block->i_buffer--;
        p_block->p_buffer++;
        while( p_block->i_buffer >= 2 )
        {
            int      i_id   = p_block->p_buffer[0];
            unsigned i_size = p_block->p_buffer[1];

            if( 2 + i_size > p_block->i_buffer )
                break;

            if( ( i_id == 0x02 || i_id == 0x03 ) && i_size >= 44 && i_lines < MAX_SLICES )
            {
                if(p_block->p_buffer[3] == 0xE4 )    /* framing_code */
                {
                    unsigned line_offset  = p_block->p_buffer[2] & 0x1f;
                    unsigned field_parity = p_block->p_buffer[2] & 0x20;

                    p_sliced[i_lines].id = VBI_SLICED_TELETEXT_B;
                    if( line_offset > 0 )
                        p_sliced[i_lines].line = line_offset + (field_parity ? 0 : 313);
                    else
                        p_sliced[i_lines].line = 0;
                    for( int i = 0; i < 42; i++ )
                        p_sliced[i_lines].data[i] = vbi_rev8( p_block->p_buffer[4 + i] );
                    i_lines++;
                }
            }

            p_block->i_buffer -= 2 + i_size;
            p_block->p_buffer += 2 + i_size;
        }

        if( i_lines > 0 )
            vbi_decode( p_sys->p_vbi_dec, p_sliced, i_lines, 0 );
    }

    /* */
    vlc_mutex_lock( &p_sys->lock );
    const int i_align = p_sys->i_align;
    const unsigned int i_wanted_page = p_sys->i_wanted_page;
    const unsigned int i_wanted_subpage = p_sys->i_wanted_subpage;
    const bool b_opaque = p_sys->b_opaque;
    vlc_mutex_unlock( &p_sys->lock );

    /* Try to see if the page we want is in the cache yet */
    memset( &p_page, 0, sizeof(vbi_page) );
    b_cached = vbi_fetch_vt_page( p_sys->p_vbi_dec, &p_page,
                                  vbi_dec2bcd( i_wanted_page ),
                                  i_wanted_subpage, VBI_WST_LEVEL_3p5,
                                  25, true );

    if( i_wanted_page == p_sys->i_last_page && !p_sys->b_update )
        goto error;

    if( !b_cached )
    {
        if( p_sys->b_text && p_sys->i_last_page != i_wanted_page )
        {
            /* We need to reset the subtitle */
            p_spu = Subpicture( p_dec, &fmt, true,
                                p_page.columns, p_page.rows,
                                i_align, p_block->i_pts );
            if( !p_spu )
                goto error;
            subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
            p_spu_sys->text = strdup("");

            p_sys->b_update = true;
            p_sys->i_last_page = i_wanted_page;
            goto exit;
        }
        goto error;
    }

    p_sys->b_update = false;
    p_sys->i_last_page = i_wanted_page;
#ifdef ZVBI_DEBUG
    msg_Dbg( p_dec, "we now have page: %d ready for display",
             i_wanted_page );
#endif

    /* Ignore transparent rows at the beginning and end */
    int i_first_row = get_first_visible_row( p_page.text, p_page.rows, p_page.columns );
    int i_num_rows;
    if ( i_first_row < 0 ) {
        i_first_row = p_page.rows - 1;
        i_num_rows = 0;
    } else {
        i_num_rows = get_last_visible_row( p_page.text, p_page.rows, p_page.columns ) - i_first_row + 1;
    }
#ifdef ZVBI_DEBUG
    msg_Dbg( p_dec, "After top and tail of page we have rows %i-%i of %i",
             i_first_row + 1, i_first_row + i_num_rows, p_page.rows );
#endif

    /* If there is a page or sub to render, then we do that here */
    /* Create the subpicture unit */
    p_spu = Subpicture( p_dec, &fmt, p_sys->b_text,
                        p_page.columns, i_num_rows,
                        i_align, p_block->i_pts );
    if( !p_spu )
        goto error;

    if( p_sys->b_text )
    {
        unsigned int i_textsize = 7000;
        int i_total,offset;
//        char p_text[i_textsize+1];
        char *p_text = (char *)malloc(i_textsize+1);			// sunqueen modify

        i_total = vbi_print_page_region( &p_page, p_text, i_textsize,
                        "UTF-8", 0, 0, 0, i_first_row, p_page.columns, i_num_rows );

        for( offset=1; offset<i_total && isspace( p_text[i_total-offset ] ); offset++)
           p_text[i_total-offset] = '\0';

        i_total -= offset;

        offset=0;
        while( offset < i_total && isspace( p_text[offset] ) )
           offset++;

        subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
        p_spu_sys->text = strdup( &p_text[offset] );

        p_spu_sys->align = i_align;
        p_spu_sys->i_font_height_percent = 5;
        p_spu_sys->renderbg = b_opaque;

#ifdef ZVBI_DEBUG
        msg_Info( p_dec, "page %x-%x(%d)\n\"%s\"", p_page.pgno, p_page.subno, i_total, &p_text[offset] );
#endif
		free(p_text);			// sunqueen add
    }
    else
    {
        picture_t *p_pic = p_spu->p_region->p_picture;

        /* ZVBI is stupid enough to assume pitch == width */
        p_pic->p->i_pitch = 4 * fmt.i_width;

        /* Maintain subtitle postion */
        p_spu->p_region->i_y = i_first_row*10;
        p_spu->i_original_picture_width = p_page.columns*12;
        p_spu->i_original_picture_height = p_page.rows*10;

        vbi_draw_vt_page_region( &p_page, ZVBI_PIXFMT_RGBA32,
                          p_spu->p_region->p_picture->p->p_pixels, -1,
                          0, i_first_row, p_page.columns, i_num_rows,
                          1, 1);

        vlc_mutex_lock( &p_sys->lock );
        memcpy( p_sys->nav_link, &p_page.nav_link, sizeof( p_sys->nav_link )) ;
        vlc_mutex_unlock( &p_sys->lock );

        OpaquePage( p_pic, &p_page, fmt, b_opaque, i_first_row * p_page.columns );
    }

exit:
    vbi_unref_page( &p_page );
    block_Release( p_block );
    return p_spu;

error:
    vbi_unref_page( &p_page );
    if( p_spu != NULL )
    {
        decoder_DeleteSubpicture( p_dec, p_spu );
        p_spu = NULL;
    }

    block_Release( p_block );
    return NULL;
}
Пример #26
0
/*****************************************************************************
 * DoWork: convert a buffer
 *****************************************************************************/
static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
{
    filter_sys_t * p_sys = p_filter->p_sys;
    float * p_in = (float*) p_in_buf->p_buffer;
    size_t i_nb_samples = p_in_buf->i_nb_samples;
    size_t i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_out.audio );
    size_t i_nb_rear = 0;
    size_t i;
    block_t *p_out_buf = block_Alloc(
                                sizeof(float) * i_nb_samples * i_nb_channels );
    if( !p_out_buf )
        goto out;

    float * p_out = (float*) p_out_buf->p_buffer;
    p_out_buf->i_nb_samples = i_nb_samples;
    p_out_buf->i_dts        = p_in_buf->i_dts;
    p_out_buf->i_pts        = p_in_buf->i_pts;
    p_out_buf->i_length     = p_in_buf->i_length;

    memset( p_out, 0, p_out_buf->i_buffer );

    if( p_sys->i_rear_left >= 0 )
    {
        ++i_nb_rear;
    }
    if( p_sys->i_rear_center >= 0 )
    {
        ++i_nb_rear;
    }
    if( p_sys->i_rear_right >= 0 )
    {
        ++i_nb_rear;
    }

    for( i = 0; i < i_nb_samples; ++i )
    {
        float f_left = p_in[ i * 2 ];
        float f_right = p_in[ i * 2 + 1 ];
        float f_rear = ( f_left - f_right ) / i_nb_rear;

        if( p_sys->i_center >= 0 )
        {
            float f_center = f_left + f_right;
            f_left -= f_center / 2;
            f_right -= f_center / 2;

            p_out[ i * i_nb_channels + p_sys->i_center ] = f_center;
        }

        if( p_sys->i_left >= 0 )
        {
            p_out[ i * i_nb_channels + p_sys->i_left ] = f_left;
        }
        if( p_sys->i_right >= 0 )
        {
            p_out[ i * i_nb_channels + p_sys->i_right ] = f_right;
        }
        if( p_sys->i_rear_left >= 0 )
        {
            p_out[ i * i_nb_channels + p_sys->i_rear_left ] = f_rear;
        }
        if( p_sys->i_rear_center >= 0 )
        {
            p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
        }
        if( p_sys->i_rear_right >= 0 )
        {
            p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
        }
    }
out:
    block_Release( p_in_buf );
    return p_out_buf;
}
Пример #27
0
/****************************************************************************
 * DecodeBlock:
 ****************************************************************************/
static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    subpicture_t *p_spu = NULL;
    block_t *p_block;

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

    p_block = *pp_block;
    *pp_block = NULL;

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

    if( p_block->i_buffer == 0 || p_block->p_buffer[0] == '\0' )
    {
        block_Release( p_block );
        return NULL;
    }

    subpicture_updater_sys_t *p_spu_sys = malloc( sizeof(*p_spu_sys) );
    if( !p_spu_sys )
    {
        block_Release( p_block );
        return NULL;
    }

    subpicture_updater_t updater = {
        .pf_validate = SubpictureValidate,
        .pf_update   = SubpictureUpdate,
        .pf_destroy  = SubpictureDestroy,
        .p_sys       = p_spu_sys,
    };
    p_spu = decoder_NewSubpicture( p_dec, &updater );
    if( !p_spu )
    {
        msg_Warn( p_dec, "can't get spu buffer" );
        free( p_spu_sys );
        block_Release( p_block );
        return NULL;
    }

    p_spu_sys->p_img = NULL;
    p_spu_sys->p_dec_sys = p_sys;
    p_spu_sys->i_subs_len = p_block->i_buffer;
    p_spu_sys->p_subs_data = malloc( p_block->i_buffer );
    p_spu_sys->i_pts = p_block->i_pts;
    if( !p_spu_sys->p_subs_data )
    {
        subpicture_Delete( p_spu );
        block_Release( p_block );
        return NULL;
    }
    memcpy( p_spu_sys->p_subs_data, p_block->p_buffer,
            p_block->i_buffer );

    p_spu->i_start = p_block->i_pts;
    p_spu->i_stop = __MAX( p_sys->i_max_stop, p_block->i_pts + p_block->i_length );
    p_spu->b_ephemer = true;
    p_spu->b_absolute = true;

    p_sys->i_max_stop = p_spu->i_stop;

    vlc_mutex_lock( &p_sys->lock );
    if( p_sys->p_track )
    {
        ass_process_chunk( p_sys->p_track, p_spu_sys->p_subs_data, p_spu_sys->i_subs_len,
                           p_block->i_pts / 1000, p_block->i_length / 1000 );
    }
    vlc_mutex_unlock( &p_sys->lock );

    DecSysHold( p_sys ); /* Keep a reference for the returned subpicture */

    block_Release( p_block );

    return p_spu;
}
Пример #28
0
Файл: video.c Проект: bobwxb/vlc
/*****************************************************************************
 * DecodeVideo: Called to decode one or more frames
 *****************************************************************************/
static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    AVCodecContext *p_context = p_sys->p_context;
    int b_drawpicture;
    block_t *p_block;

    if( !pp_block )
        return NULL;

    if( !p_context->extradata_size && p_dec->fmt_in.i_extra )
    {
        ffmpeg_InitCodec( p_dec );
        if( p_sys->b_delayed_open )
            OpenVideoCodec( p_dec );
    }

    p_block = *pp_block;
    if(!p_block && !(p_sys->p_codec->capabilities & CODEC_CAP_DELAY) )
        return NULL;

    if( p_sys->b_delayed_open )
    {
        if( p_block )
            block_Release( p_block );
        return NULL;
    }

    if( p_block)
    {
        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
        {
            p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */

            p_sys->i_late_frames = 0;

            post_mt( p_sys );
            if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
                avcodec_flush_buffers( p_context );
            wait_mt( p_sys );

            block_Release( p_block );
            return NULL;
        }

        if( p_block->i_flags & BLOCK_FLAG_PREROLL )
        {
            /* Do not care about late frames when prerolling
             * TODO avoid decoding of non reference frame
             * (ie all B except for H264 where it depends only on nal_ref_idc) */
            p_sys->i_late_frames = 0;
        }
    }

    if( !p_dec->b_pace_control && (p_sys->i_late_frames > 0) &&
        (mdate() - p_sys->i_late_frames_start > INT64_C(5000000)) )
    {
        if( p_sys->i_pts > VLC_TS_INVALID )
        {
            p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */
        }
        if( p_block )
            block_Release( p_block );
        p_sys->i_late_frames--;
        msg_Err( p_dec, "more than 5 seconds of late video -> "
                 "dropping frame (computer too slow ?)" );
        return NULL;
    }

    /* A good idea could be to decode all I pictures and see for the other */
    if( !p_dec->b_pace_control &&
        p_sys->b_hurry_up &&
        (p_sys->i_late_frames > 4) )
    {
        b_drawpicture = 0;
        if( p_sys->i_late_frames < 12 )
        {
            p_context->skip_frame =
                    (p_sys->i_skip_frame <= AVDISCARD_NONREF) ?
                    AVDISCARD_NONREF : p_sys->i_skip_frame;
        }
        else
        {
            /* picture too late, won't decode
             * but break picture until a new I, and for mpeg4 ...*/
            p_sys->i_late_frames--; /* needed else it will never be decrease */
            if( p_block )
                block_Release( p_block );
            msg_Warn( p_dec, "More than 4 late frames, dropping frame" );
            return NULL;
        }
    }
    else
    {
        if( p_sys->b_hurry_up )
            p_context->skip_frame = p_sys->i_skip_frame;
        if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
            b_drawpicture = 1;
        else
            b_drawpicture = 0;
    }

    if( p_context->width <= 0 || p_context->height <= 0 )
    {
        if( p_sys->b_hurry_up )
            p_context->skip_frame = p_sys->i_skip_frame;
    }
    else if( !b_drawpicture )
    {
        /* It creates broken picture
         * FIXME either our parser or ffmpeg is broken */
#if 0
        if( p_sys->b_hurry_up )
            p_context->skip_frame = __MAX( p_context->skip_frame,
                                                  AVDISCARD_NONREF );
#endif
    }

    /*
     * Do the actual decoding now */

    /* Don't forget that libavcodec requires a little more bytes
     * that the real frame size */
    if( p_block && p_block->i_buffer > 0 )
    {
        p_sys->b_flush = ( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE ) != 0;

        p_block = block_Realloc( p_block, 0,
                            p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
        if( !p_block )
            return NULL;
        p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
        *pp_block = p_block;
        memset( p_block->p_buffer + p_block->i_buffer, 0,
                FF_INPUT_BUFFER_PADDING_SIZE );
    }

    while( !p_block || p_block->i_buffer > 0 || p_sys->b_flush )
    {
        int i_used, b_gotpicture;
        AVPacket pkt;

        AVFrame *frame = av_frame_alloc();
        if (unlikely(frame == NULL))
        {
            p_dec->b_error = true;
            break;
        }

        post_mt( p_sys );

        av_init_packet( &pkt );
        if( p_block )
        {
            pkt.data = p_block->p_buffer;
            pkt.size = p_block->i_buffer;
            pkt.pts = p_block->i_pts;
            pkt.dts = p_block->i_dts;
        }
        else
        {
            /* Return delayed frames if codec has CODEC_CAP_DELAY */
            pkt.data = NULL;
            pkt.size = 0;
        }

        if( !p_sys->palette_sent )
        {
            uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
            if (pal) {
                memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE);
                p_sys->palette_sent = true;
            }
        }

        /* Make sure we don't reuse the same timestamps twice */
        if( p_block )
        {
            p_block->i_pts =
            p_block->i_dts = VLC_TS_INVALID;
        }

        i_used = avcodec_decode_video2( p_context, frame, &b_gotpicture,
                                        &pkt );
        av_free_packet( &pkt );

        wait_mt( p_sys );

        if( p_sys->b_flush )
            p_sys->b_first_frame = true;

        if( p_block )
        {
            if( p_block->i_buffer <= 0 )
                p_sys->b_flush = false;

            if( i_used < 0 )
            {
                av_frame_unref(frame);
                if( b_drawpicture )
                    msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
                            p_block->i_buffer );
                break;
            }
            else if( (unsigned)i_used > p_block->i_buffer ||
                    p_context->thread_count > 1 )
            {
                i_used = p_block->i_buffer;
            }

            /* Consumed bytes */
            p_block->i_buffer -= i_used;
            p_block->p_buffer += i_used;
        }

        /* Nothing to display */
        if( !b_gotpicture )
        {
            av_frame_unref(frame);
            if( i_used == 0 ) break;
            continue;
        }

        /* Compute the PTS */
        mtime_t i_pts = frame->pkt_pts;
        if (i_pts <= VLC_TS_INVALID)
            i_pts = frame->pkt_dts;

        if( i_pts <= VLC_TS_INVALID )
            i_pts = p_sys->i_pts;

        /* Interpolate the next PTS */
        if( i_pts > VLC_TS_INVALID )
            p_sys->i_pts = i_pts;
        if( p_sys->i_pts > VLC_TS_INVALID )
        {
            /* interpolate the next PTS */
            if( p_dec->fmt_in.video.i_frame_rate > 0 &&
                p_dec->fmt_in.video.i_frame_rate_base > 0 )
            {
                p_sys->i_pts += CLOCK_FREQ * (2 + frame->repeat_pict) *
                    p_dec->fmt_in.video.i_frame_rate_base /
                    (2 * p_dec->fmt_in.video.i_frame_rate);
            }
            else if( p_context->time_base.den > 0 )
            {
                int i_tick = p_context->ticks_per_frame;
                if( i_tick <= 0 )
                    i_tick = 1;

                p_sys->i_pts += CLOCK_FREQ * (2 + frame->repeat_pict) *
                    i_tick * p_context->time_base.num /
                    (2 * p_context->time_base.den);
            }
        }

        /* Update frame late count (except when doing preroll) */
        mtime_t i_display_date = 0;
        if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
            i_display_date = decoder_GetDisplayDate( p_dec, i_pts );

        if( i_display_date > 0 && i_display_date <= mdate() )
        {
            p_sys->i_late_frames++;
            if( p_sys->i_late_frames == 1 )
                p_sys->i_late_frames_start = mdate();
        }
        else
        {
            p_sys->i_late_frames = 0;
        }

        if( !b_drawpicture || ( !p_sys->p_va && !frame->linesize[0] ) )
        {
            av_frame_unref(frame);
            continue;
        }

        picture_t *p_pic = frame->opaque;
        if( p_pic == NULL )
        {
            /* Get a new picture */
            if( p_sys->p_va == NULL )
                p_pic = ffmpeg_NewPictBuf( p_dec, p_context );
            if( !p_pic )
            {
                av_frame_unref(frame);
                break;
            }

            /* Fill picture_t from AVFrame */
            lavc_CopyPicture(p_dec, p_pic, frame);
        }
        else
        {
            if( p_sys->p_va != NULL )
                vlc_va_Extract( p_sys->p_va, p_pic, frame->data[3] );
            picture_Hold( p_pic );
        }

        if( !p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den )
        {
            /* Fetch again the aspect ratio in case it changed */
            p_dec->fmt_out.video.i_sar_num
                = p_context->sample_aspect_ratio.num;
            p_dec->fmt_out.video.i_sar_den
                = p_context->sample_aspect_ratio.den;

            if( !p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den )
            {
                p_dec->fmt_out.video.i_sar_num = 1;
                p_dec->fmt_out.video.i_sar_den = 1;
            }
        }

        p_pic->date = i_pts;
        /* Hack to force display of still pictures */
        p_pic->b_force = p_sys->b_first_frame;
        p_pic->i_nb_fields = 2 + frame->repeat_pict;
        p_pic->b_progressive = !frame->interlaced_frame;
        p_pic->b_top_field_first = frame->top_field_first;

        av_frame_unref(frame);

        /* Send decoded frame to vout */
        if (i_pts > VLC_TS_INVALID)
        {
            p_sys->b_first_frame = false;
            return p_pic;
        }
        else
            picture_Release( p_pic );
    }

    if( p_block )
        block_Release( p_block );
    return NULL;
}
Пример #29
0
/*****************************************************************************
 * RunDecoder: the libmpeg2 decoder
 *****************************************************************************/
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t   *p_sys = p_dec->p_sys;
    mpeg2_state_t   state;
    picture_t       *p_pic;

    block_t *p_block;

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

    p_block = *pp_block;
    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
    {
        cc_Flush( &p_sys->cc );
        mpeg2_reset( p_sys->p_mpeg2dec, p_sys->p_info->sequence != NULL );
        DpbClean( p_dec );
    }

    while( 1 )
    {
        state = mpeg2_parse( p_sys->p_mpeg2dec );

        switch( state )
        {
        case STATE_SEQUENCE:
        {
            /* */
            DpbClean( p_dec );

            /* */
            mpeg2_custom_fbuf( p_sys->p_mpeg2dec, 1 );

            /* Set the first 2 reference frames */
            GetAR( p_dec );
            for( int i = 0; i < 2; i++ )
            {
                picture_t *p_picture = DpbNewPicture( p_dec );
                if( !p_picture )
                {
                    /* Is it ok ? or do we need a reset ? */
                    block_Release( p_block );
                    return NULL;
                }
                PutPicture( p_dec, p_picture );
            }

            if( p_sys->p_synchro )
                decoder_SynchroRelease( p_sys->p_synchro );

            p_sys->p_synchro =
                decoder_SynchroInit( p_dec, (uint32_t)((uint64_t)1001000000 * 27 /
                                     p_sys->p_info->sequence->frame_period) );
            p_sys->b_after_sequence_header = true;
            break;
        }

        case STATE_GOP:
            /* There can be userdata in a GOP. It needs to be remembered for the next picture. */
            if( p_sys->p_info->user_data_len > 2 )
            {
                free( p_sys->p_gop_user_data );
                p_sys->p_gop_user_data = calloc( p_sys->p_info->user_data_len, sizeof(uint8_t) );
                if( p_sys->p_gop_user_data )
                {
                    p_sys->i_gop_user_data = p_sys->p_info->user_data_len;
                    memcpy( p_sys->p_gop_user_data, p_sys->p_info->user_data, p_sys->p_info->user_data_len );
                }
            }
            break;

        case STATE_PICTURE:
        {
            const mpeg2_info_t *p_info = p_sys->p_info;
            const mpeg2_picture_t *p_current = p_info->current_picture;

            mtime_t i_pts, i_dts;

            if( p_sys->b_after_sequence_header &&
                (p_current->flags &
                    PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_P )
            {
                /* Intra-slice refresh. Simulate a blank I picture. */
                msg_Dbg( p_dec, "intra-slice refresh stream" );
                decoder_SynchroNewPicture( p_sys->p_synchro,
                                           I_CODING_TYPE, 2, 0, 0,
                                           p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );
                decoder_SynchroDecode( p_sys->p_synchro );
                decoder_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
                p_sys->b_slice_i = true;
            }
            p_sys->b_after_sequence_header = false;

#ifdef PIC_FLAG_PTS
            i_pts = p_current->flags & PIC_FLAG_PTS ?
                ( ( p_current->pts ==
                    (uint32_t)p_sys->i_current_pts ) ?
                  p_sys->i_current_pts : p_sys->i_previous_pts ) : 0;
            i_dts = 0;

            /* Hack to handle demuxers which only have DTS timestamps */
            if( !i_pts && !p_block->i_pts && p_block->i_dts > 0 )
            {
                if( p_info->sequence->flags & SEQ_FLAG_LOW_DELAY ||
                    (p_current->flags &
                      PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B )
                {
                    i_pts = p_block->i_dts;
                }
            }
            p_block->i_pts = p_block->i_dts = 0;
            /* End hack */

#else /* New interface */

            i_pts = p_current->flags & PIC_FLAG_TAGS ?
                ( ( p_current->tag == (uint32_t)p_sys->i_current_pts ) ?
                            p_sys->i_current_pts : p_sys->i_previous_pts ) : 0;
            i_dts = p_current->flags & PIC_FLAG_TAGS ?
                ( ( p_current->tag2 == (uint32_t)p_sys->i_current_dts ) ?
                            p_sys->i_current_dts : p_sys->i_previous_dts ) : 0;
#endif

            /* If nb_fields == 1, it is a field picture, and it will be
             * followed by another field picture for which we won't call
             * decoder_SynchroNewPicture() because this would have other
             * problems, so we take it into account here.
             * This kind of sucks, but I didn't think better. --Meuuh
             */
            decoder_SynchroNewPicture( p_sys->p_synchro,
                                       p_current->flags & PIC_MASK_CODING_TYPE,
                                       p_current->nb_fields == 1 ? 2 :
                                       p_current->nb_fields, i_pts, i_dts,
                                       p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );


            bool b_skip = false;
            if( !p_dec->b_pace_control && !p_sys->b_preroll &&
                !(p_sys->b_slice_i
                   && ((p_current->flags
                         & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_P))
                   && !decoder_SynchroChoose( p_sys->p_synchro,
                              p_current->flags
                                & PIC_MASK_CODING_TYPE,
                              /*p_sys->p_vout->render_time*/ 0 /*FIXME*/,
                              p_info->sequence->flags & SEQ_FLAG_LOW_DELAY ) )
            {
                b_skip = true;
            }

            p_pic = NULL;
            if( !b_skip )
                p_pic = DpbNewPicture( p_dec );

            if( b_skip || !p_pic )
            {
                mpeg2_skip( p_sys->p_mpeg2dec, 1 );
                p_sys->b_skip = true;
                decoder_SynchroTrash( p_sys->p_synchro );

                PutPicture( p_dec, NULL );

                if( !b_skip )
                {
                    block_Release( p_block );
                    return NULL;
                }
            }
            else
            {
                mpeg2_skip( p_sys->p_mpeg2dec, 0 );
                p_sys->b_skip = false;
                decoder_SynchroDecode( p_sys->p_synchro );

                PutPicture( p_dec, p_pic );
            }
            if( p_info->user_data_len > 2 || p_sys->i_gop_user_data > 2 )
            {
                p_sys->i_cc_pts = i_pts;
                p_sys->i_cc_dts = i_dts;
                if( (p_current->flags
                             & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_P )
                    p_sys->i_cc_flags = BLOCK_FLAG_TYPE_P;
                else if( (p_current->flags
                             & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B )
                    p_sys->i_cc_flags = BLOCK_FLAG_TYPE_B;
                else p_sys->i_cc_flags = BLOCK_FLAG_TYPE_I;

                if( p_sys->i_gop_user_data > 2 )
                {
                    /* We now have picture info for any cached user_data out of the gop */
                    cc_Extract( &p_sys->cc, &p_sys->p_gop_user_data[0], p_sys->i_gop_user_data );
                    p_sys->i_gop_user_data = 0;
                }

                /* Extract the CC from the user_data of the picture */
                if( p_info->user_data_len > 2 )
                    cc_Extract( &p_sys->cc, &p_info->user_data[0], p_info->user_data_len );
            }
        }
        break;


        case STATE_BUFFER:
            if( !p_block->i_buffer )
            {
                block_Release( p_block );
                return NULL;
            }

            if( (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY
                                      | BLOCK_FLAG_CORRUPTED)) &&
                p_sys->p_synchro &&
                p_sys->p_info->sequence &&
                p_sys->p_info->sequence->width != (unsigned)-1 )
            {
                decoder_SynchroReset( p_sys->p_synchro );
                if( p_sys->p_info->current_fbuf != NULL &&
                    p_sys->p_info->current_fbuf->id != NULL )
                {
                    p_sys->b_garbage_pic = true;
                }
                if( p_sys->b_slice_i )
                {
                    decoder_SynchroNewPicture( p_sys->p_synchro,
                                               I_CODING_TYPE, 2, 0, 0,
                                               p_sys->p_info->sequence->flags &
                                                            SEQ_FLAG_LOW_DELAY );
                    decoder_SynchroDecode( p_sys->p_synchro );
                    decoder_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
                }
            }

            if( p_block->i_flags & BLOCK_FLAG_PREROLL )
            {
                p_sys->b_preroll = true;
            }
            else if( p_sys->b_preroll )
            {
                p_sys->b_preroll = false;
                if( p_sys->p_synchro )
                    decoder_SynchroReset( p_sys->p_synchro );
            }

#ifdef PIC_FLAG_PTS
            if( p_block->i_pts )
            {
                mpeg2_pts( p_sys->p_mpeg2dec, (uint32_t)p_block->i_pts );

#else /* New interface */
            if( p_block->i_pts || p_block->i_dts )
            {
                mpeg2_tag_picture( p_sys->p_mpeg2dec,
                                   (uint32_t)p_block->i_pts,
                                   (uint32_t)p_block->i_dts );
#endif
                p_sys->i_previous_pts = p_sys->i_current_pts;
                p_sys->i_current_pts = p_block->i_pts;
                p_sys->i_previous_dts = p_sys->i_current_dts;
                p_sys->i_current_dts = p_block->i_dts;
            }

            mpeg2_buffer( p_sys->p_mpeg2dec, p_block->p_buffer,
                          p_block->p_buffer + p_block->i_buffer );

            p_block->i_buffer = 0;
            break;

#if MPEG2_RELEASE >= MPEG2_VERSION (0, 5, 0)

        case STATE_SEQUENCE_MODIFIED:
            GetAR( p_dec );
            break;
#endif
        case STATE_PICTURE_2ND:
            p_sys->b_second_field = true;
            break;


        case STATE_INVALID_END:
        case STATE_END:
        case STATE_SLICE:
            p_pic = NULL;
            if( p_sys->p_info->display_fbuf &&
                p_sys->p_info->display_fbuf->id )
            {
                p_pic = p_sys->p_info->display_fbuf->id;
                DpbDisplayPicture( p_dec, p_pic );

                decoder_SynchroEnd( p_sys->p_synchro,
                                    p_sys->p_info->display_picture->flags & PIC_MASK_CODING_TYPE,
                                    p_sys->b_garbage_pic );

                p_pic->date = decoder_SynchroDate( p_sys->p_synchro );
                if( p_sys->b_garbage_pic )
                    p_pic->date = 0; /* ??? */
                p_sys->b_garbage_pic = false;
            }

            if( p_sys->p_info->discard_fbuf &&
                p_sys->p_info->discard_fbuf->id )
            {
                DpbUnlinkPicture( p_dec, p_sys->p_info->discard_fbuf->id );
            }

            /* For still frames */
            if( state == STATE_END && p_pic )
                p_pic->b_force = true;

            if( p_pic )
            {
                /* Avoid frames with identical timestamps.
                 * Especially needed for still frames in DVD menus. */
                if( p_sys->i_last_frame_pts == p_pic->date )
                    p_pic->date++;
                p_sys->i_last_frame_pts = p_pic->date;
                return p_pic;
            }
            break;

        case STATE_INVALID:
        {
            msg_Err( p_dec, "invalid picture encountered" );
            /* I don't think we have anything to do, but well without
             * docs ... */
            break;
        }

        default:
            break;
        }
    }

    /* Never reached */
    return NULL;
}

/*****************************************************************************
 * CloseDecoder: libmpeg2 decoder destruction
 *****************************************************************************/
static void CloseDecoder( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t *)p_this;
    decoder_sys_t *p_sys = p_dec->p_sys;

    DpbClean( p_dec );

    free( p_sys->p_gop_user_data );

    if( p_sys->p_synchro ) decoder_SynchroRelease( p_sys->p_synchro );

    if( p_sys->p_mpeg2dec ) mpeg2_close( p_sys->p_mpeg2dec );

    free( p_sys );
}
Пример #30
0
Файл: mft.c Проект: IAPark/vlc
static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id)
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    HRESULT hr;
    picture_t *picture = NULL;
    block_t *aout_buffer = NULL;

    DWORD output_status = 0;
    MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL };
    hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status);
    if (output_buffer.pEvents)
        IMFCollection_Release(output_buffer.pEvents);
    /* Use the returned sample since it can be provided by the MFT. */
    IMFSample *output_sample = output_buffer.pSample;

    if (hr == S_OK)
    {
        if (!output_sample)
            return VLC_SUCCESS;

        LONGLONG sample_time;
        hr = IMFSample_GetSampleTime(output_sample, &sample_time);
        if (FAILED(hr))
            goto error;
        /* Convert from 100 nanoseconds unit to microseconds. */
        sample_time /= 10;

        DWORD total_length = 0;
        hr = IMFSample_GetTotalLength(output_sample, &total_length);
        if (FAILED(hr))
            goto error;

        if (p_dec->fmt_in.i_cat == VIDEO_ES)
        {
            if (decoder_UpdateVideoFormat(p_dec))
                return VLC_SUCCESS;
            picture = decoder_NewPicture(p_dec);
            if (!picture)
                return VLC_SUCCESS;

            UINT32 interlaced = false;
            hr = IMFSample_GetUINT32(output_sample, &MFSampleExtension_Interlaced, &interlaced);
            picture->b_progressive = !interlaced;

            picture->date = sample_time;
        }
        else
        {
            if (decoder_UpdateAudioFormat(p_dec))
                goto error;
            if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0)
                goto error;
            int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8);
            aout_buffer = decoder_NewAudioBuffer(p_dec, samples);
            if (!aout_buffer)
                return VLC_SUCCESS;
            if (aout_buffer->i_buffer < total_length)
                goto error;

            aout_buffer->i_pts = sample_time;
        }

        IMFMediaBuffer *output_media_buffer = NULL;
        hr = IMFSample_GetBufferByIndex(output_sample, 0, &output_media_buffer);

        BYTE *buffer_start;
        hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL);
        if (FAILED(hr))
            goto error;

        if (p_dec->fmt_in.i_cat == VIDEO_ES)
            CopyPackedBufferToPicture(picture, buffer_start);
        else
            memcpy(aout_buffer->p_buffer, buffer_start, total_length);

        hr = IMFMediaBuffer_Unlock(output_media_buffer);
        IMFSample_Release(output_media_buffer);
        if (FAILED(hr))
            goto error;

        if (p_sys->output_sample)
        {
            /* Sample is not provided by the MFT: clear its content. */
            hr = IMFMediaBuffer_SetCurrentLength(output_media_buffer, 0);
            if (FAILED(hr))
                goto error;
        }
        else
        {
            /* Sample is provided by the MFT: decrease refcount. */
            IMFSample_Release(output_sample);
        }
    }
    else if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET)
    {
        if (p_sys->output_type)
            IMFMediaType_Release(p_sys->output_type);
        if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
            goto error;

        /* Reallocate output sample. */
        if (p_sys->output_sample)
            IMFSample_Release(p_sys->output_sample);
        p_sys->output_sample = NULL;
        if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample))
            goto error;
        return VLC_SUCCESS;
    }
    else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
    {
        return VLC_SUCCESS;
    }
    else /* An error not listed above occurred */
    {
        msg_Err(p_dec, "Unexpected error in IMFTransform::ProcessOutput: %#lx",
                hr);
        goto error;
    }

    if (p_dec->fmt_in.i_cat == VIDEO_ES)
        decoder_QueueVideo(p_dec, picture);
    else
        decoder_QueueAudio(p_dec, aout_buffer);

    return VLC_SUCCESS;

error:
    msg_Err(p_dec, "Error in ProcessOutputStream()");
    if (picture)
        picture_Release(picture);
    if (aout_buffer)
        block_Release(aout_buffer);
    return VLC_EGENERIC;
}