*/
#include "config.h"
-#include <assert.h>
#include <string.h>
#include "gstvaapicompat.h"
#include "gstvaapidecoder.h"
PROP_DISPLAY,
PROP_CAPS,
+ PROP_CODEC_INFO,
};
static void
set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
}
+static inline void
+set_codec_info(GstVaapiDecoder *decoder, GstVaapiCodecInfo *codec_info)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+ if (codec_info) {
+ priv->codec_info = *codec_info;
+ if (!priv->codec_info.pic_size)
+ priv->codec_info.pic_size = sizeof(GstVaapiPicture);
+ if (!priv->codec_info.slice_size)
+ priv->codec_info.slice_size = sizeof(GstVaapiSlice);
+ }
+}
+
static void
clear_queue(GQueue *q, GDestroyNotify destroy)
{
if (priv->context) {
g_object_unref(priv->context);
priv->context = NULL;
+ priv->va_context = VA_INVALID_ID;
}
if (priv->buffers) {
if (priv->display) {
g_object_unref(priv->display);
priv->display = NULL;
+ priv->va_display = NULL;
}
G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
switch (prop_id) {
case PROP_DISPLAY:
priv->display = g_object_ref(g_value_get_object(value));
+ if (priv->display)
+ priv->va_display = gst_vaapi_display_get_display(priv->display);
+ else
+ priv->va_display = NULL;
break;
case PROP_CAPS:
set_caps(decoder, g_value_get_pointer(value));
break;
+ case PROP_CODEC_INFO:
+ set_codec_info(decoder, g_value_get_pointer(value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
"Decoder caps",
"The decoder caps",
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_CODEC_INFO,
+ g_param_spec_pointer("codec-info",
+ "Codec info",
+ "The codec info",
+ G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
}
static void
GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
decoder->priv = priv;
+ priv->display = NULL;
+ priv->va_display = NULL;
priv->context = NULL;
+ priv->va_context = VA_INVALID_ID;
priv->caps = NULL;
priv->codec = 0;
priv->codec_data = NULL;
width,
height
);
- return priv->context != NULL;
+ if (!priv->context)
+ return FALSE;
+
+ priv->va_context = gst_vaapi_context_get_id(priv->context);
+ return TRUE;
}
gboolean
{
return push_surface(decoder, g_object_ref(proxy), timestamp);
}
+
+static void
+destroy_iq_matrix(GstVaapiDecoder *decoder, GstVaapiIqMatrix *iq_matrix);
+
+static void
+destroy_slice(GstVaapiDecoder *decoder, GstVaapiSlice *slice);
+
+static void
+destroy_slice_cb(gpointer data, gpointer user_data)
+{
+ GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(user_data);
+ GstVaapiSlice * const slice = data;
+
+ destroy_slice(decoder, slice);
+}
+
+static void
+destroy_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+ if (picture->slices) {
+ g_ptr_array_foreach(picture->slices, destroy_slice_cb, decoder);
+ g_ptr_array_free(picture->slices, TRUE);
+ picture->slices = NULL;
+ }
+
+ if (picture->iq_matrix) {
+ destroy_iq_matrix(decoder, picture->iq_matrix);
+ picture->iq_matrix = NULL;
+ }
+
+ picture->surface = NULL;
+ picture->surface_id = VA_INVALID_ID;
+
+ vaapi_destroy_buffer(priv->va_display, &picture->param_id);
+ picture->param = NULL;
+ g_slice_free1(priv->codec_info.pic_size, picture);
+}
+
+static GstVaapiPicture *
+create_picture(GstVaapiDecoder *decoder)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+ GstVaapiPicture *picture;
+
+ picture = g_slice_alloc(priv->codec_info.pic_size);
+ if (!picture)
+ return NULL;
+
+ picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
+ picture->flags = 0;
+ picture->surface_id = VA_INVALID_ID;
+ picture->surface = NULL;
+ picture->param_id = VA_INVALID_ID;
+ picture->param = NULL;
+ picture->slices = NULL;
+ picture->iq_matrix = NULL;
+ picture->pts = GST_CLOCK_TIME_NONE;
+
+ picture->surface = gst_vaapi_context_get_surface(priv->context);
+ if (!picture->surface)
+ goto error;
+ picture->surface_id = gst_vaapi_surface_get_id(picture->surface);
+
+ picture->param = vaapi_create_buffer(
+ priv->va_display,
+ priv->va_context,
+ VAPictureParameterBufferType,
+ priv->codec_info.pic_param_size,
+ &picture->param_id
+ );
+ if (!picture->param)
+ goto error;
+
+ picture->slices = g_ptr_array_new();
+ if (!picture->slices)
+ goto error;
+ return picture;
+
+error:
+ destroy_picture(priv->va_display, picture);
+ return NULL;
+}
+
+GstVaapiPicture *
+gst_vaapi_decoder_new_picture(GstVaapiDecoder *decoder)
+{
+ return create_picture(decoder);
+}
+
+void
+gst_vaapi_decoder_free_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
+{
+ destroy_picture(decoder, picture);
+}
+
+static void
+destroy_iq_matrix(GstVaapiDecoder *decoder, GstVaapiIqMatrix *iq_matrix)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+ vaapi_destroy_buffer(priv->va_display, &iq_matrix->param_id);
+ iq_matrix->param = NULL;
+ g_slice_free(GstVaapiIqMatrix, iq_matrix);
+}
+
+static GstVaapiIqMatrix *
+create_iq_matrix(GstVaapiDecoder *decoder)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+ GstVaapiIqMatrix *iq_matrix;
+
+ iq_matrix = g_slice_new(GstVaapiIqMatrix);
+ if (!iq_matrix)
+ return NULL;
+
+ iq_matrix->param_id = VA_INVALID_ID;
+
+ iq_matrix->param = vaapi_create_buffer(
+ priv->va_display,
+ priv->va_context,
+ VAIQMatrixBufferType,
+ priv->codec_info.iq_matrix_size,
+ &iq_matrix->param_id
+ );
+ if (!iq_matrix->param)
+ goto error;
+ return iq_matrix;
+
+error:
+ destroy_iq_matrix(decoder, iq_matrix);
+ return NULL;
+}
+
+GstVaapiIqMatrix *
+gst_vaapi_decoder_new_iq_matrix(GstVaapiDecoder *decoder)
+{
+ return create_iq_matrix(decoder);
+}
+
+static void
+destroy_slice(GstVaapiDecoder *decoder, GstVaapiSlice *slice)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+ vaapi_destroy_buffer(priv->va_display, &slice->data_id);
+ vaapi_destroy_buffer(priv->va_display, &slice->param_id);
+ slice->param = NULL;
+ g_slice_free1(priv->codec_info.slice_size, slice);
+}
+
+static GstVaapiSlice *
+create_slice(GstVaapiDecoder *decoder, guchar *buf, guint buf_size)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+ GstVaapiSlice *slice;
+ VASliceParameterBufferBase *slice_param;
+ guchar *data;
+
+ slice = g_slice_alloc(priv->codec_info.slice_size);
+ if (!slice)
+ return NULL;
+
+ slice->data_id = VA_INVALID_ID;
+ slice->param_id = VA_INVALID_ID;
+
+ data = vaapi_create_buffer(
+ priv->va_display,
+ priv->va_context,
+ VASliceDataBufferType,
+ buf_size,
+ &slice->data_id
+ );
+ if (!data)
+ goto error;
+ memcpy(data, buf, buf_size);
+ vaapi_unmap_buffer(priv->va_display, slice->data_id, NULL);
+
+ slice->param = vaapi_create_buffer(
+ priv->va_display,
+ priv->va_context,
+ VASliceParameterBufferType,
+ priv->codec_info.slice_param_size,
+ &slice->param_id
+ );
+ if (!slice->param)
+ goto error;
+
+ slice_param = slice->param;
+ slice_param->slice_data_size = buf_size;
+ slice_param->slice_data_offset = 0;
+ slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
+ return slice;
+
+error:
+ destroy_slice(decoder, slice);
+ return NULL;
+}
+
+GstVaapiSlice *
+gst_vaapi_decoder_new_slice(
+ GstVaapiDecoder *decoder,
+ GstVaapiPicture *picture,
+ guchar *buf,
+ guint buf_size
+)
+{
+ GstVaapiSlice *slice;
+
+ slice = create_slice(decoder, buf, buf_size);
+ if (!slice)
+ return NULL;
+ g_ptr_array_add(picture->slices, slice);
+ return slice;
+}
+
+gboolean
+gst_vaapi_decoder_decode_picture(
+ GstVaapiDecoder *decoder,
+ GstVaapiPicture *picture
+)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+ GstVaapiIqMatrix * const iq_matrix = picture->iq_matrix;
+ GstVaapiSlice *slice;
+ VABufferID va_buffers[3];
+ guint i, n_va_buffers = 0;
+ VAStatus status;
+
+ GST_DEBUG("decode picture 0x%08x", gst_vaapi_surface_get_id(picture->surface));
+
+ vaapi_unmap_buffer(priv->va_display, picture->param_id, &picture->param);
+ va_buffers[n_va_buffers++] = picture->param_id;
+
+ if (iq_matrix) {
+ vaapi_unmap_buffer(priv->va_display, iq_matrix->param_id, &iq_matrix->param);
+ va_buffers[n_va_buffers++] = iq_matrix->param_id;
+ }
+
+ status = vaBeginPicture(
+ priv->va_display,
+ priv->va_context,
+ picture->surface_id
+ );
+ if (!vaapi_check_status(status, "vaBeginPicture()"))
+ return FALSE;
+
+ status = vaRenderPicture(
+ priv->va_display,
+ priv->va_context,
+ va_buffers, n_va_buffers
+ );
+ if (!vaapi_check_status(status, "vaRenderPicture()"))
+ return FALSE;
+
+ for (i = 0; i < picture->slices->len; i++) {
+ slice = g_ptr_array_index(picture->slices, i);
+
+ vaapi_unmap_buffer(priv->va_display, slice->param_id, NULL);
+ va_buffers[0] = slice->param_id;
+ va_buffers[1] = slice->data_id;
+ n_va_buffers = 2;
+
+ status = vaRenderPicture(
+ priv->va_display,
+ priv->va_context,
+ va_buffers, n_va_buffers
+ );
+ if (!vaapi_check_status(status, "vaRenderPicture()"))
+ return FALSE;
+ }
+
+ status = vaEndPicture(priv->va_display, priv->va_context);
+ if (!vaapi_check_status(status, "vaEndPicture()"))
+ return FALSE;
+ return TRUE;
+}
GST_VAAPI_TYPE_DECODER, \
GstVaapiDecoderPrivate))
+typedef enum _GstVaapiPictureType GstVaapiPictureType;
+typedef struct _GstVaapiCodecInfo GstVaapiCodecInfo;
+typedef struct _GstVaapiPicture GstVaapiPicture;
+typedef struct _GstVaapiSlice GstVaapiSlice;
+typedef struct _GstVaapiIqMatrix GstVaapiIqMatrix;
+
+enum _GstVaapiPictureType {
+ GST_VAAPI_PICTURE_TYPE_NONE = 0, // Undefined
+ GST_VAAPI_PICTURE_TYPE_I, // Intra
+ GST_VAAPI_PICTURE_TYPE_P, // Predicted
+ GST_VAAPI_PICTURE_TYPE_B, // Bi-directional predicted
+ GST_VAAPI_PICTURE_TYPE_S, // S(GMC)-VOP (MPEG-4)
+ GST_VAAPI_PICTURE_TYPE_SI, // Switching Intra
+ GST_VAAPI_PICTURE_TYPE_SP, // Switching Predicted
+ GST_VAAPI_PICTURE_TYPE_BI, // BI type (VC-1)
+};
+
+enum {
+ GST_VAAPI_PICTURE_SKIPPED = 1 << 0, // Skipped frame
+ GST_VAAPI_PICTURE_REFERENCE = 1 << 1, // Reference frame
+};
+
+#define GST_VAAPI_PICTURE(picture) \
+ ((GstVaapiPicture *)(picture))
+
+#define GST_VAAPI_PICTURE_IS_REFERENCE(picture) \
+ ((GST_VAAPI_PICTURE(picture)->flags & GST_VAAPI_PICTURE_REFERENCE) != 0)
+
+struct _GstVaapiCodecInfo {
+ guint pic_size; // GstVaapiPicture size
+ guint slice_size; // GstVaapiSlice size
+ guint pic_param_size; // VAPictureParameterBuffer size
+ guint slice_param_size; // VASliceParameterBuffer size
+ guint iq_matrix_size; // VAIQMatrixBuffer size
+};
+
+struct _GstVaapiPicture {
+ GstVaapiPictureType type;
+ guint flags;
+ VASurfaceID surface_id;
+ GstVaapiSurface *surface;
+ VABufferID param_id;
+ void *param;
+ GPtrArray *slices;
+ GstVaapiIqMatrix *iq_matrix;
+ GstClockTime pts;
+};
+
+struct _GstVaapiSlice {
+ VABufferID param_id;
+ void *param;
+ VABufferID data_id;
+};
+
+struct _GstVaapiIqMatrix {
+ VABufferID param_id;
+ void *param;
+};
+
struct _GstVaapiDecoderPrivate {
GstVaapiDisplay *display;
+ VADisplay va_display;
GstVaapiContext *context;
+ VAContextID va_context;
GstCaps *caps;
GstVaapiCodec codec;
GstBuffer *codec_data;
+ GstVaapiCodecInfo codec_info;
guint width;
guint height;
guint fps_n;
GstClockTime timestamp
) attribute_hidden;
+GstVaapiPicture *
+gst_vaapi_decoder_new_picture(GstVaapiDecoder *decoder)
+ attribute_hidden;
+
+void
+gst_vaapi_decoder_free_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
+ attribute_hidden;
+
+GstVaapiIqMatrix *
+gst_vaapi_decoder_new_iq_matrix(GstVaapiDecoder *decoder)
+ attribute_hidden;
+
+GstVaapiSlice *
+gst_vaapi_decoder_new_slice(
+ GstVaapiDecoder *decoder,
+ GstVaapiPicture *picture,
+ guchar *buf,
+ guint buf_size
+) attribute_hidden;
+
+gboolean
+gst_vaapi_decoder_decode_picture(
+ GstVaapiDecoder *decoder,
+ GstVaapiPicture *picture
+) attribute_hidden;
+
G_END_DECLS
#endif /* GST_VAAPI_DECODER_PRIV_H */