mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
decoder: add new GstVaapiDecoder API.
Split decoding process into two steps: (i) parse incoming bitstreams into simple decoder-units until the frame or field is complete; and (ii) decode the whole frame or field at once. This is an ABI change.
This commit is contained in:
parent
f5e6444b78
commit
66cc8754fc
3 changed files with 231 additions and 7 deletions
|
@ -48,6 +48,64 @@ enum {
|
||||||
|
|
||||||
static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
|
static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
|
static void
|
||||||
|
parser_state_finalize(GstVaapiParserState *ps)
|
||||||
|
{
|
||||||
|
if (ps->input_adapter) {
|
||||||
|
gst_adapter_clear(ps->input_adapter);
|
||||||
|
g_object_unref(ps->input_adapter);
|
||||||
|
ps->input_adapter = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps->output_adapter) {
|
||||||
|
gst_adapter_clear(ps->output_adapter);
|
||||||
|
g_object_unref(ps->output_adapter);
|
||||||
|
ps->output_adapter = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parser_state_init(GstVaapiParserState *ps)
|
||||||
|
{
|
||||||
|
ps->input_adapter = gst_adapter_new();
|
||||||
|
if (!ps->input_adapter)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ps->output_adapter = gst_adapter_new();
|
||||||
|
if (!ps->output_adapter)
|
||||||
|
return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GstVaapiDecoderUnit *
|
||||||
|
parser_state_get_pending_unit(GstVaapiParserState *ps, GstAdapter *adapter)
|
||||||
|
{
|
||||||
|
GstVaapiDecoderUnit * const unit = ps->pending_unit;
|
||||||
|
|
||||||
|
ps->pending_unit = NULL;
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
parser_state_set_pending_unit(GstVaapiParserState *ps,
|
||||||
|
GstAdapter *adapter, GstVaapiDecoderUnit *unit)
|
||||||
|
{
|
||||||
|
ps->pending_unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parser_state_prepare(GstVaapiParserState *ps, GstAdapter *adapter)
|
||||||
|
{
|
||||||
|
/* XXX: check we really have a continuity from the previous call */
|
||||||
|
if (ps->current_adapter != adapter)
|
||||||
|
goto reset;
|
||||||
|
return;
|
||||||
|
|
||||||
|
reset:
|
||||||
|
ps->current_adapter = adapter;
|
||||||
|
ps->input_offset2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroy_buffer(GstBuffer *buffer)
|
destroy_buffer(GstBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
@ -89,13 +147,97 @@ pop_buffer(GstVaapiDecoder *decoder)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstVaapiDecoderStatus
|
||||||
|
do_parse(GstVaapiDecoder *decoder,
|
||||||
|
GstVideoCodecFrame *base_frame, GstAdapter *adapter, gboolean at_eos,
|
||||||
|
guint *got_unit_size_ptr, gboolean *got_frame_ptr)
|
||||||
|
{
|
||||||
|
GstVaapiParserState * const ps = &decoder->priv->parser_state;
|
||||||
|
GstVaapiDecoderFrame *frame;
|
||||||
|
GstVaapiDecoderUnit *unit;
|
||||||
|
GstVaapiDecoderStatus status;
|
||||||
|
|
||||||
|
*got_unit_size_ptr = 0;
|
||||||
|
*got_frame_ptr = FALSE;
|
||||||
|
|
||||||
|
frame = gst_video_codec_frame_get_user_data(base_frame);
|
||||||
|
if (!frame) {
|
||||||
|
frame = gst_vaapi_decoder_frame_new();
|
||||||
|
if (!frame)
|
||||||
|
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
|
||||||
|
gst_video_codec_frame_set_user_data(base_frame,
|
||||||
|
frame, (GDestroyNotify)gst_vaapi_mini_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_state_prepare(ps, adapter);
|
||||||
|
|
||||||
|
unit = parser_state_get_pending_unit(ps, adapter);
|
||||||
|
if (unit)
|
||||||
|
goto got_unit;
|
||||||
|
|
||||||
|
ps->current_frame = base_frame;
|
||||||
|
status = GST_VAAPI_DECODER_GET_CLASS(decoder)->parse(decoder,
|
||||||
|
adapter, at_eos, &unit);
|
||||||
|
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
|
||||||
|
if (unit)
|
||||||
|
gst_vaapi_decoder_unit_unref(unit);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_VAAPI_DECODER_UNIT_IS_FRAME_START(unit) && frame->prev_slice) {
|
||||||
|
parser_state_set_pending_unit(ps, adapter, unit);
|
||||||
|
goto got_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
got_unit:
|
||||||
|
unit->offset = frame->output_offset;
|
||||||
|
frame->units = g_slist_prepend(frame->units, unit);
|
||||||
|
frame->output_offset += unit->size;
|
||||||
|
if (GST_VAAPI_DECODER_UNIT_IS_SLICE(unit))
|
||||||
|
frame->prev_slice = unit;
|
||||||
|
|
||||||
|
*got_unit_size_ptr = unit->size;
|
||||||
|
if (GST_VAAPI_DECODER_UNIT_IS_FRAME_END(unit)) {
|
||||||
|
got_frame:
|
||||||
|
frame->units = g_slist_reverse(frame->units);
|
||||||
|
*got_frame_ptr = TRUE;
|
||||||
|
}
|
||||||
|
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstVaapiDecoderStatus
|
||||||
|
do_decode(GstVaapiDecoder *decoder, GstVideoCodecFrame *base_frame)
|
||||||
|
{
|
||||||
|
GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
|
||||||
|
GstVaapiParserState * const ps = &decoder->priv->parser_state;
|
||||||
|
GstVaapiDecoderFrame *frame;
|
||||||
|
GstVaapiDecoderStatus status;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
ps->current_frame = base_frame;
|
||||||
|
|
||||||
|
frame = base_frame->user_data;
|
||||||
|
for (l = frame->units; l != NULL; l = l->next) {
|
||||||
|
GstVaapiDecoderUnit * const unit = l->data;
|
||||||
|
if (GST_VAAPI_DECODER_UNIT_IS_SKIPPED(unit))
|
||||||
|
continue;
|
||||||
|
status = klass->decode(decoder, unit);
|
||||||
|
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static GstVaapiDecoderStatus
|
static GstVaapiDecoderStatus
|
||||||
decode_step(GstVaapiDecoder *decoder)
|
decode_step(GstVaapiDecoder *decoder)
|
||||||
{
|
{
|
||||||
|
GstVaapiDecoderPrivate * const priv = decoder->priv;
|
||||||
|
GstVaapiParserState * const ps = &priv->parser_state;
|
||||||
GstVaapiDecoderStatus status;
|
GstVaapiDecoderStatus status;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
|
gboolean at_eos, got_frame;
|
||||||
|
guint got_unit_size;
|
||||||
|
|
||||||
/* Decoding will fail if there is no surface left */
|
|
||||||
status = gst_vaapi_decoder_check_status(decoder);
|
status = gst_vaapi_decoder_check_status(decoder);
|
||||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
|
@ -105,11 +247,47 @@ decode_step(GstVaapiDecoder *decoder)
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||||
|
|
||||||
status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer);
|
at_eos = GST_BUFFER_IS_EOS(buffer);
|
||||||
GST_DEBUG("decode frame (status = %d)", status);
|
if (!at_eos)
|
||||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS && GST_BUFFER_IS_EOS(buffer))
|
gst_adapter_push(ps->input_adapter, buffer);
|
||||||
status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
|
|
||||||
gst_buffer_unref(buffer);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = do_parse(decoder, ps->current_frame,
|
||||||
|
ps->input_adapter, at_eos, &got_unit_size, &got_frame);
|
||||||
|
GST_DEBUG("parse frame (status = %d)", status);
|
||||||
|
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (got_unit_size > 0) {
|
||||||
|
buffer = gst_adapter_take_buffer(ps->input_adapter,
|
||||||
|
got_unit_size);
|
||||||
|
if (gst_adapter_available(ps->output_adapter) == 0) {
|
||||||
|
ps->current_frame->pts =
|
||||||
|
gst_adapter_prev_timestamp(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;
|
||||||
|
}
|
||||||
|
} while (status == GST_VAAPI_DECODER_STATUS_SUCCESS &&
|
||||||
|
gst_adapter_available(ps->input_adapter) > 0);
|
||||||
} while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
|
} while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -211,6 +389,8 @@ gst_vaapi_decoder_finalize(GObject *object)
|
||||||
|
|
||||||
set_codec_data(decoder, NULL);
|
set_codec_data(decoder, NULL);
|
||||||
|
|
||||||
|
parser_state_finalize(&priv->parser_state);
|
||||||
|
|
||||||
if (priv->caps) {
|
if (priv->caps) {
|
||||||
gst_caps_unref(priv->caps);
|
gst_caps_unref(priv->caps);
|
||||||
priv->caps = NULL;
|
priv->caps = NULL;
|
||||||
|
@ -332,6 +512,8 @@ gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
|
||||||
{
|
{
|
||||||
GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
|
GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
|
||||||
|
|
||||||
|
parser_state_init(&priv->parser_state);
|
||||||
|
|
||||||
decoder->priv = priv;
|
decoder->priv = priv;
|
||||||
priv->display = NULL;
|
priv->display = NULL;
|
||||||
priv->va_display = NULL;
|
priv->va_display = NULL;
|
||||||
|
|
|
@ -24,8 +24,10 @@
|
||||||
#define GST_VAAPI_DECODER_H
|
#define GST_VAAPI_DECODER_H
|
||||||
|
|
||||||
#include <gst/gstbuffer.h>
|
#include <gst/gstbuffer.h>
|
||||||
|
#include <gst/base/gstadapter.h>
|
||||||
#include <gst/vaapi/gstvaapicontext.h>
|
#include <gst/vaapi/gstvaapicontext.h>
|
||||||
#include <gst/vaapi/gstvaapisurfaceproxy.h>
|
#include <gst/vaapi/gstvaapisurfaceproxy.h>
|
||||||
|
#include <gst/video/gstvideoutils.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -56,6 +58,7 @@ G_BEGIN_DECLS
|
||||||
typedef struct _GstVaapiDecoder GstVaapiDecoder;
|
typedef struct _GstVaapiDecoder GstVaapiDecoder;
|
||||||
typedef struct _GstVaapiDecoderPrivate GstVaapiDecoderPrivate;
|
typedef struct _GstVaapiDecoderPrivate GstVaapiDecoderPrivate;
|
||||||
typedef struct _GstVaapiDecoderClass GstVaapiDecoderClass;
|
typedef struct _GstVaapiDecoderClass GstVaapiDecoderClass;
|
||||||
|
struct _GstVaapiDecoderUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstVaapiDecoderStatus:
|
* GstVaapiDecoderStatus:
|
||||||
|
@ -110,7 +113,11 @@ struct _GstVaapiDecoderClass {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
GstVaapiDecoderStatus (*decode)(GstVaapiDecoder *decoder, GstBuffer *buffer);
|
GstVaapiDecoderStatus (*parse)(GstVaapiDecoder *decoder,
|
||||||
|
GstAdapter *adapter, gboolean at_eos,
|
||||||
|
struct _GstVaapiDecoderUnit **unit_ptr);
|
||||||
|
GstVaapiDecoderStatus (*decode)(GstVaapiDecoder *decoder,
|
||||||
|
struct _GstVaapiDecoderUnit *unit);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType
|
GType
|
||||||
|
|
|
@ -25,12 +25,24 @@
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gst/vaapi/gstvaapidecoder.h>
|
#include <gst/vaapi/gstvaapidecoder.h>
|
||||||
|
#include <gst/vaapi/gstvaapidecoder_frame.h>
|
||||||
#include <gst/vaapi/gstvaapicontext.h>
|
#include <gst/vaapi/gstvaapicontext.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define GST_VAAPI_DECODER_CAST(decoder) ((GstVaapiDecoder *)(decoder))
|
#define GST_VAAPI_DECODER_CAST(decoder) ((GstVaapiDecoder *)(decoder))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GST_VAAPI_PARSER_STATE:
|
||||||
|
* @decoder: a #GstVaapiDecoder
|
||||||
|
*
|
||||||
|
* Macro that evaluates to the #GstVaapiParserState of @decoder.
|
||||||
|
* This is an internal macro that does not do any run-time type check.
|
||||||
|
*/
|
||||||
|
#undef GST_VAAPI_PARSER_STATE
|
||||||
|
#define GST_VAAPI_PARSER_STATE(decoder) \
|
||||||
|
(&GST_VAAPI_DECODER_CAST(decoder)->priv->parser_state)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GST_VAAPI_DECODER_DISPLAY:
|
* GST_VAAPI_DECODER_DISPLAY:
|
||||||
* @decoder: a #GstVaapiDecoder
|
* @decoder: a #GstVaapiDecoder
|
||||||
|
@ -76,6 +88,18 @@ G_BEGIN_DECLS
|
||||||
#define GST_VAAPI_DECODER_CODEC_DATA(decoder) \
|
#define GST_VAAPI_DECODER_CODEC_DATA(decoder) \
|
||||||
GST_VAAPI_DECODER_CAST(decoder)->priv->codec_data
|
GST_VAAPI_DECODER_CAST(decoder)->priv->codec_data
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GST_VAAPI_DECODER_CODEC_FRAME:
|
||||||
|
* @decoder: a #GstVaapiDecoder
|
||||||
|
*
|
||||||
|
* Macro that evaluates to the #GstVideoCodecFrame holding decoder
|
||||||
|
* units for the current frame.
|
||||||
|
* This is an internal macro that does not do any run-time type check.
|
||||||
|
*/
|
||||||
|
#undef GST_VAAPI_DECODER_CODEC_FRAME
|
||||||
|
#define GST_VAAPI_DECODER_CODEC_FRAME(decoder) \
|
||||||
|
GST_VAAPI_PARSER_STATE(decoder)->current_frame
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GST_VAAPI_DECODER_WIDTH:
|
* GST_VAAPI_DECODER_WIDTH:
|
||||||
* @decoder: a #GstVaapiDecoder
|
* @decoder: a #GstVaapiDecoder
|
||||||
|
@ -109,6 +133,16 @@ G_BEGIN_DECLS
|
||||||
GST_VAAPI_TYPE_DECODER, \
|
GST_VAAPI_TYPE_DECODER, \
|
||||||
GstVaapiDecoderPrivate))
|
GstVaapiDecoderPrivate))
|
||||||
|
|
||||||
|
typedef struct _GstVaapiParserState GstVaapiParserState;
|
||||||
|
struct _GstVaapiParserState {
|
||||||
|
GstVideoCodecFrame *current_frame;
|
||||||
|
GstAdapter *current_adapter;
|
||||||
|
GstAdapter *input_adapter;
|
||||||
|
gint input_offset2;
|
||||||
|
GstAdapter *output_adapter;
|
||||||
|
GstVaapiDecoderUnit *pending_unit;
|
||||||
|
};
|
||||||
|
|
||||||
struct _GstVaapiDecoderPrivate {
|
struct _GstVaapiDecoderPrivate {
|
||||||
GstVaapiDisplay *display;
|
GstVaapiDisplay *display;
|
||||||
VADisplay va_display;
|
VADisplay va_display;
|
||||||
|
@ -125,6 +159,7 @@ struct _GstVaapiDecoderPrivate {
|
||||||
guint par_d;
|
guint par_d;
|
||||||
GQueue *buffers;
|
GQueue *buffers;
|
||||||
GQueue *surfaces;
|
GQueue *surfaces;
|
||||||
|
GstVaapiParserState parser_state;
|
||||||
guint is_interlaced : 1;
|
guint is_interlaced : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue