GstVaapiDecoderStatus
gst_vaapi_decoder_ffmpeg_decode(GstVaapiDecoder *decoder, GstBuffer *buffer)
{
    GstVaapiDecoderFfmpeg * const ffdecoder = GST_VAAPI_DECODER_FFMPEG(decoder);
    GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
    GstClockTime inbuf_ts;
    guchar *outbuf;
    gint inbuf_ofs, inbuf_size, outbuf_size;
    gboolean got_frame;

    g_return_val_if_fail(priv->is_constructed,
                         GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);

    if (!priv->is_opened) {
        priv->is_opened = gst_vaapi_decoder_ffmpeg_open(ffdecoder, buffer);
        if (!priv->is_opened)
            return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
    }

    inbuf_ofs  = 0;
    inbuf_size = GST_BUFFER_SIZE(buffer);
    inbuf_ts   = GST_BUFFER_TIMESTAMP(buffer);

    if (priv->pctx) {
        do {
            int parsed_size = av_parser_parse2(
                priv->pctx,
                priv->avctx,
                &outbuf, &outbuf_size,
                GST_BUFFER_DATA(buffer) + inbuf_ofs, inbuf_size,
                inbuf_ts, inbuf_ts ,0
            );
            got_frame = outbuf && outbuf_size > 0;

            if (parsed_size > 0) {
                inbuf_ofs  += parsed_size;
                inbuf_size -= parsed_size;
            }
        } while (!got_frame && inbuf_size > 0);
        inbuf_ts    = priv->pctx->pts;
    }
    else {
        outbuf      = GST_BUFFER_DATA(buffer);
        outbuf_size = inbuf_size;
        got_frame   = outbuf && outbuf_size > 0;
        inbuf_ofs   = inbuf_size;
        inbuf_size  = 0;
    }

    if (inbuf_size > 0 &&
        !gst_vaapi_decoder_push_buffer_sub(decoder, buffer,
                                           inbuf_ofs, inbuf_size))
        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;

    if (!got_frame && !GST_BUFFER_IS_EOS(buffer))
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;

    priv->in_timestamp = inbuf_ts;
    return decode_frame(ffdecoder, outbuf, outbuf_size);
}
static GstVaapiDecoderStatus
decode_step (GstVaapiDecoder * decoder)
{
  GstVaapiParserState *const ps = &decoder->parser_state;
  GstVaapiDecoderStatus status;
  GstBuffer *buffer;
  gboolean got_frame;
  guint got_unit_size, input_size;

  status = gst_vaapi_decoder_check_status (decoder);
  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
    return status;

  /* Fill adapter with all buffers we have in the queue */
  for (;;) {
    buffer = pop_buffer (decoder);
    if (!buffer)
      break;

    ps->at_eos = GST_BUFFER_IS_EOS (buffer);
    if (!ps->at_eos)
      gst_adapter_push (ps->input_adapter, buffer);
  }

  /* Parse and decode all decode units */
  input_size = gst_adapter_available (ps->input_adapter);
  if (input_size == 0) {
    if (ps->at_eos)
      return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
  }

  do {
    if (!ps->current_frame) {
      ps->current_frame = g_slice_new0 (GstVideoCodecFrame);
      if (!ps->current_frame)
        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
      ps->current_frame->ref_count = 1;
      ps->current_frame->system_frame_number = ps->current_frame_number++;
    }

    status = do_parse (decoder, ps->current_frame, ps->input_adapter,
        ps->at_eos, &got_unit_size, &got_frame);
    GST_DEBUG ("parse frame (status = %d)", status);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
      if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA && ps->at_eos)
        status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
      break;
    }

    if (got_unit_size > 0) {
      buffer = gst_adapter_take_buffer (ps->input_adapter, got_unit_size);
      input_size -= got_unit_size;

      if (gst_adapter_available (ps->output_adapter) == 0) {
        ps->current_frame->pts = gst_adapter_prev_pts (ps->input_adapter, NULL);
      }
      gst_adapter_push (ps->output_adapter, buffer);
    }

    if (got_frame) {
      ps->current_frame->input_buffer =
          gst_adapter_take_buffer (ps->output_adapter,
          gst_adapter_available (ps->output_adapter));

      status = do_decode (decoder, ps->current_frame);
      GST_DEBUG ("decode frame (status = %d)", status);

      gst_video_codec_frame_unref (ps->current_frame);
      ps->current_frame = NULL;
      break;
    }
  } while (input_size > 0);
  return status;
}