Ejemplo n.º 1
0
static void Video_OnFlush(decoder_t *p_dec)
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    timestamp_FifoEmpty(p_sys->u.video.timestamp_fifo);
    /* Invalidate all pictures that are currently in flight
     * since flushing make all previous indices returned by
     * MediaCodec invalid. */
    if (p_sys->api->b_direct_rendering)
        InvalidateAllPictures(p_dec);
}
Ejemplo n.º 2
0
/*****************************************************************************
 * StopMediaCodec: Close the mediacodec instance
 *****************************************************************************/
static void StopMediaCodec(decoder_t *p_dec)
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    /* Invalidate all pictures that are currently in flight in order
     * to prevent the vout from using destroyed output buffers. */
    if (p_sys->api->b_direct_rendering)
        InvalidateAllPictures(p_dec);

    p_sys->api->stop(p_sys->api);
    if (p_dec->fmt_in.i_cat == VIDEO_ES && p_sys->u.video.p_awh)
        AWindowHandler_releaseSurface(p_sys->u.video.p_awh, AWindow_Video);
}
Ejemplo n.º 3
0
static int Video_OnNewBlock(decoder_t *p_dec, block_t *p_block)
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    bool b_csd_changed = false, b_size_changed = false;
    bool b_delayed_start = false;

    if (p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK
        && !p_sys->api->b_support_interlaced)
        return -1;

    if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
    {
        if (p_sys->decoded)
        {
            timestamp_FifoEmpty(p_sys->u.video.timestamp_fifo);
            /* Invalidate all pictures that are currently in flight
             * since flushing make all previous indices returned by
             * MediaCodec invalid. */
            if (p_sys->api->b_direct_rendering)
                InvalidateAllPictures(p_dec);
        }

        if (DecodeFlush(p_dec) != VLC_SUCCESS)
            return -1;
        return 0;
    }

    if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
        H264ProcessBlock(p_dec, p_block, &b_csd_changed, &b_size_changed);
    else if (p_dec->fmt_in.i_codec == VLC_CODEC_HEVC)
        HEVCProcessBlock(p_dec, p_block, &b_csd_changed, &b_size_changed);

    if (p_sys->api->b_started && b_csd_changed)
    {
        if (b_size_changed)
        {
            msg_Err(p_dec, "SPS/PPS changed during playback and "
                    "video size are different. Restart it !");
            StopMediaCodec(p_dec);
        } else
        {
            msg_Err(p_dec, "SPS/PPS changed during playback. Flush it");
            if (DecodeFlush(p_dec) != VLC_SUCCESS)
                return -1;
        }
    }

    if (b_csd_changed)
        b_delayed_start = true;

    /* try delayed opening if there is a new extra data */
    if (!p_sys->api->b_started)
    {
        switch (p_dec->fmt_in.i_codec)
        {
        case VLC_CODEC_VC1:
            if (p_dec->fmt_in.i_extra)
                b_delayed_start = true;
        default:
            break;
        }
        if (b_delayed_start && StartMediaCodec(p_dec) != VLC_SUCCESS)
            return -1;
        if (!p_sys->api->b_started)
            return 0;
    }

    timestamp_FifoPut(p_sys->u.video.timestamp_fifo,
                      p_block->i_pts ? VLC_TS_INVALID : p_block->i_dts);
    return 1;
}
Ejemplo n.º 4
0
/**
 * DecodeCommon called from DecodeVideo or DecodeAudio.
 * It returns -1 in case of error, 0 otherwise. The output buffer is returned
 * in pp_out_pic for Video, and pp_out_block for Audio.
 */
static int DecodeCommon(decoder_t *p_dec, block_t **pp_block,
                        picture_t **pp_out_pic, block_t **pp_out_block)
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block = pp_block ? *pp_block : NULL;
    unsigned int i_attempts = 0;
    jlong timeout = 0;
    int i_output_ret = 0;
    int i_input_ret = 0;
    bool b_abort = false;
    bool b_error = false;
    bool b_new_block = p_block ? p_sys->b_new_block : false;

    if (p_sys->error_state)
        goto endclean;

    if (b_new_block)
    {
        int i_ret, i_flags = 0;

        p_sys->b_new_block = false;

        if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
        {
            if (DecodeFlush(p_dec) != VLC_SUCCESS)
                b_error = true;
            goto endclean;
        }

        i_ret = p_sys->pf_on_new_block(p_dec, p_block, &i_flags);
        if (i_ret != 1)
        {
            if (i_ret == -1)
                b_error = true;
            goto endclean;
        }
        if (i_flags & NEWBLOCK_FLAG_FLUSH)
        {
            if (DecodeFlush(p_dec) != VLC_SUCCESS)
            {
                b_error = true;
                goto endclean;
            }
        }

        if (i_flags & NEWBLOCK_FLAG_RESTART)
        {
            StopMediaCodec(p_dec);
            if (StartMediaCodec(p_dec) != VLC_SUCCESS)
            {
                b_error = true;
                goto endclean;
            }
        }
    }
    if (!p_sys->api->b_started)
        goto endclean;

    do
    {
        if ((p_sys->i_csd_send < p_sys->i_csd_count || p_block)
         && i_input_ret == 0)
        {
            int i_index = p_sys->api->dequeue_in(p_sys->api, timeout);

            if (i_index >= 0)
            {
                block_t *p_in_block;
                mtime_t i_ts;

                if (p_sys->i_csd_send < p_sys->i_csd_count)
                {
                    p_in_block = p_sys->pp_csd[p_sys->i_csd_send];
                    i_ts = 0;
                }
                else
                {
                    p_in_block = p_block;
                    i_ts = p_block->i_pts;
                    if (!i_ts && p_block->i_dts)
                        i_ts = p_block->i_dts;
                }
                i_input_ret = p_sys->api->queue_in(p_sys->api, i_index,
                                                   p_in_block->p_buffer,
                                                   p_in_block->i_buffer, i_ts,
                                                   p_in_block->i_flags & BLOCK_FLAG_CSD) == 0 ? 1 : -1;
                if (i_input_ret == 1)
                {
                    if (p_sys->i_csd_send < p_sys->i_csd_count)
                    {
                        p_sys->i_csd_send++;
                        i_input_ret = 0;
                    }
                    else
                    {
                        p_sys->decoded = true;
                        if (p_block->i_flags & BLOCK_FLAG_PREROLL )
                            p_sys->i_preroll_end = i_ts;
                    }
                }
            }
            else if (i_index == MC_API_INFO_TRYAGAIN)
                i_input_ret = 0;
            else
                i_input_ret = -1;

            /* No need to try output if no input buffer is decoded */
            if (!p_sys->decoded)
                continue;
        }

        if (i_input_ret != -1 && p_sys->decoded && i_output_ret == 0)
        {
            i_output_ret = GetAndProcessOutput(p_dec, pp_out_pic, pp_out_block,
                                               timeout);

            if (i_output_ret == 0 && i_input_ret == 0)
            {
                if (++i_attempts == 20)
                {
                    /* HACK: When direct rendering is enabled, there is a
                     * possible deadlock between the Decoder and the Vout. It
                     * happens when the Vout is paused and when the Decoder is
                     * flushing. In that case, the Vout won't release any
                     * output buffers, therefore MediaCodec won't dequeue any
                     * input buffers. To work around this issue, release all
                     * output buffers if DecodeCommon is waiting more than 400
                     * msec for a new input buffer. */ 
                    msg_Warn(p_dec, "Decoder stuck: invalidate all buffers");
                    InvalidateAllPictures(p_dec);
                }
                if (!p_sys->b_has_format && ++i_attempts > 100)
                {
                    /* No output and no format, thereforce mediacodec didn't
                     * produce any output or events yet. Don't wait
                     * indefinitely and abort after 2seconds (100 * 2 * 10ms)
                     * without any data.  Indeed, MediaCodec can fail without
                     * throwing any exception or error returns... */
                    msg_Err(p_dec, "No output/input for %lld ms, abort",
                                    i_attempts * timeout);
                    b_error = true;
                    break;
                }
            }
        }
        timeout = 10 * 1000; // 10 ms
        /* loop until either the input or the output are processed (i_input_ret
         * or i_output_ret == 1 ) or caused an error (i_input_ret or
         * i_output_ret == -1 )*/
    } while (p_block && i_input_ret == 0 && i_output_ret == 0 && !b_abort);

    if (i_input_ret == -1 || i_output_ret == -1)
    {
        msg_Err(p_dec, "%s failed",
                i_input_ret == -1 ? "PutInput" : "GetOutput");
        b_error = true;
    }

endclean:

    /* If pf_decode returns NULL, we'll get a new p_block from the next
     * pf_decode call. Therefore we need to release the current one even if we
     * couldn't process it (it happens in case or error or if MediaCodec is
     * still not opened). We also must release the current p_block if we were
     * able to process it. */
    if (p_block && (i_output_ret != 1 || i_input_ret != 0))
    {
        block_Release(p_block);
        *pp_block = NULL;
        p_sys->b_new_block = true;
    }
    if (b_error && !p_sys->error_state) {
        /* Signal the error to the Java. */
        jni_EventHardwareAccelerationError();
        p_sys->error_state = true;
    }

    return b_error ? -1 : 0;
}