encoder: add video codec-state API.

Add interface to communicate the encoder resolution and related info
like framerate, interlaced vs. progressive, etc. This new interface
supersedes gst_vaapi_encoder_set_format() and doesn't use any GstCaps
but rather use GstVideoCodecState.

Note that gst_vaapi_encoder_set_codec_state() is also a synchronization
point for codec config. This means that the encoder is reconfigured
there to match the latest properties.
This commit is contained in:
Gwenole Beauchesne 2014-01-10 10:54:22 +01:00
parent 2c4fde0eae
commit 5394c75461
7 changed files with 194 additions and 199 deletions

View file

@ -416,16 +416,35 @@ gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
return ret;
}
/* Ensures the underlying VA context for encoding is created */
static gboolean
gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
/* Checks video info */
static GstVaapiEncoderStatus
check_video_info (GstVaapiEncoder * encoder, const GstVideoInfo * vip)
{
if (!vip->width || !vip->height)
goto error_invalid_resolution;
if (!vip->fps_n || !vip->fps_d)
goto error_invalid_framerate;
return GST_VAAPI_ENCODER_STATUS_SUCCESS;
/* ERRORS */
error_invalid_resolution:
{
GST_ERROR ("invalid resolution (%dx%d)", vip->width, vip->height);
return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
}
error_invalid_framerate:
{
GST_ERROR ("invalid framerate (%d/%d)", vip->fps_n, vip->fps_d);
return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
}
}
/* Updates video context */
static void
set_context_info (GstVaapiEncoder * encoder)
{
GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
GstVaapiContextInfo *const cip = &encoder->context_info;
GstVaapiContext *context;
if (GST_VAAPI_ENCODER_CONTEXT (encoder))
return TRUE;
cip->profile = GST_VAAPI_PROFILE_UNKNOWN;
cip->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
@ -434,72 +453,107 @@ gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
cip->height = GST_VAAPI_ENCODER_HEIGHT (encoder);
cip->ref_frames = 0;
klass->set_context_info (encoder);
}
context = gst_vaapi_context_new_full (encoder->display, cip);
if (!context)
return FALSE;
/* Ensures the underlying VA context for encoding is created */
static gboolean
gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
{
GstVaapiContextInfo *const cip = &encoder->context_info;
GST_VAAPI_ENCODER_CONTEXT (encoder) = context;
GST_VAAPI_ENCODER_VA_CONTEXT (encoder) = gst_vaapi_context_get_id (context);
set_context_info (encoder);
if (encoder->context) {
if (!gst_vaapi_context_reset_full (encoder->context, cip))
return FALSE;
} else {
encoder->context = gst_vaapi_context_new_full (encoder->display, cip);
if (!encoder->context)
return FALSE;
}
encoder->va_context = gst_vaapi_context_get_id (encoder->context);
return TRUE;
}
/**
* gst_vaapi_encoder_set_format:
* @encoder: a #GstVaapiEncoder
* @state : a #GstVideoCodecState
* @ref_caps: the set of reference caps (from pad template)
*
* Notifies the encoder of incoming data format (video resolution),
* and additional information like framerate.
*
* Return value: the newly allocated set of caps
*/
GstCaps *
gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder,
GstVideoCodecState * state, GstCaps * ref_caps)
/* Reconfigures the encoder with the new properties */
static GstVaapiEncoderStatus
gst_vaapi_encoder_reconfigure_internal (GstVaapiEncoder * encoder)
{
GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
GstCaps *out_caps = NULL;
GstVaapiEncoderStatus status;
if (!GST_VIDEO_INFO_WIDTH (&state->info) ||
!GST_VIDEO_INFO_HEIGHT (&state->info)) {
GST_WARNING ("encoder set format failed, width or height equal to 0.");
return NULL;
}
GST_VAAPI_ENCODER_VIDEO_INFO (encoder) = state->info;
out_caps = klass->set_format (encoder, state, ref_caps);
if (!out_caps)
goto error;
if (GST_VAAPI_ENCODER_CAPS (encoder) &&
gst_caps_is_equal (out_caps, GST_VAAPI_ENCODER_CAPS (encoder))) {
gst_caps_unref (out_caps);
return GST_VAAPI_ENCODER_CAPS (encoder);
}
gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), out_caps);
g_assert (GST_VAAPI_ENCODER_CONTEXT (encoder) == NULL);
gst_vaapi_object_replace (&GST_VAAPI_ENCODER_CONTEXT (encoder), NULL);
status = klass->reconfigure (encoder);
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
return status;
if (!gst_vaapi_encoder_ensure_context (encoder))
goto error;
goto error_reset_context;
encoder->codedbuf_pool = gst_vaapi_coded_buffer_pool_new (encoder,
encoder->codedbuf_size);
if (!encoder->codedbuf_pool) {
GST_ERROR ("failed to initialized coded buffer pool");
goto error;
}
if (!encoder->codedbuf_pool)
goto error_codedbuf_pool_allocation_failed;
gst_vaapi_video_pool_set_capacity (encoder->codedbuf_pool, 5);
return GST_VAAPI_ENCODER_STATUS_SUCCESS;
return out_caps;
/* ERRORS */
error_codedbuf_pool_allocation_failed:
{
GST_ERROR ("failed to initialize coded buffer pool");
return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
}
error_reset_context:
{
GST_ERROR ("failed to update VA context");
return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
}
}
error:
gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), NULL);
gst_caps_replace (&out_caps, NULL);
GST_ERROR ("encoder set format failed");
return NULL;
/**
* gst_vaapi_encoder_set_codec_state:
* @encoder: a #GstVaapiEncoder
* @state : a #GstVideoCodecState
*
* Notifies the encoder about the source surface properties. The
* accepted set of properties is: video resolution, colorimetry,
* pixel-aspect-ratio and framerate.
*
* This function is a synchronization point for codec configuration.
* This means that, at this point, the encoder is reconfigured to
* match the new properties and any other change beyond this point has
* zero effect.
*
* Return value: a #GstVaapiEncoderStatus
*/
GstVaapiEncoderStatus
gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder,
GstVideoCodecState * state)
{
GstVaapiEncoderStatus status;
g_return_val_if_fail (encoder != NULL,
GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
g_return_val_if_fail (state != NULL,
GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
if (encoder->num_codedbuf_queued > 0)
goto error_operation_failed;
if (!gst_video_info_is_equal (&state->info, &encoder->video_info)) {
status = check_video_info (encoder, &state->info);
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
return status;
encoder->video_info = state->info;
}
return gst_vaapi_encoder_reconfigure_internal (encoder);
/* ERRORS */
error_operation_failed:
{
GST_ERROR ("could not change codec state after encoding started");
return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
}
}
/**
@ -762,11 +816,11 @@ gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)
CHECK_VTABLE_HOOK (init);
CHECK_VTABLE_HOOK (finalize);
CHECK_VTABLE_HOOK (get_default_properties);
CHECK_VTABLE_HOOK (reconfigure);
CHECK_VTABLE_HOOK (encode);
CHECK_VTABLE_HOOK (reordering);
CHECK_VTABLE_HOOK (flush);
CHECK_VTABLE_HOOK (set_context_info);
CHECK_VTABLE_HOOK (set_format);
#undef CHECK_VTABLE_HOOK

View file

@ -106,9 +106,9 @@ GstVaapiEncoderStatus
gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
GstBuffer ** out_codec_data_ptr);
GstCaps *
gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder,
GstVideoCodecState * state, GstCaps * ref_caps);
GstVaapiEncoderStatus
gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder,
GstVideoCodecState * state);
GstVaapiEncoderStatus
gst_vaapi_encoder_set_property (GstVaapiEncoder * encoder, gint prop_id,

View file

@ -82,14 +82,6 @@ typedef struct
guint frame_num;
} GstVaapiEncoderH264Ref;
#define GST_VAAPI_H264_CAPS \
"video/x-h264, " \
"framerate = (fraction) [0/1, MAX], " \
"width = (int) [ 1, MAX ], " \
"height = (int) [ 1, MAX ], " \
"stream-format = (string) { avc, byte-stream }, " \
"alignment = (string) { au } "
typedef enum
{
GST_VAAPI_ENC_H264_REORD_NONE = 0,
@ -1262,12 +1254,6 @@ init_encoder_public_attributes (GstVaapiEncoderH264 * encoder)
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
guint width_mbs, height_mbs, total_mbs;
if (!GST_VAAPI_ENCODER_WIDTH (encoder) ||
!GST_VAAPI_ENCODER_HEIGHT (encoder) ||
!GST_VAAPI_ENCODER_FPS_N (encoder) ||
!GST_VAAPI_ENCODER_FPS_D (encoder)) {
return FALSE;
}
if (!encoder->profile)
encoder->profile = GST_VAAPI_ENCODER_H264_DEFAULT_PROFILE;
@ -1317,7 +1303,7 @@ init_encoder_public_attributes (GstVaapiEncoderH264 * encoder)
}
static gboolean
init_encoder_private_attributes (GstVaapiEncoderH264 * encoder, GstCaps * caps)
init_encoder_private_attributes (GstVaapiEncoderH264 * encoder)
{
if (encoder->b_frame_num)
encoder->cts_offset = GST_SECOND * GST_VAAPI_ENCODER_FPS_D (encoder) /
@ -1625,65 +1611,25 @@ gst_vaapi_encoder_h264_set_context_info (GstVaapiEncoder * base_encoder)
GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
}
static GstCaps *
gst_vaapi_encoder_h264_set_format (GstVaapiEncoder * base,
GstVideoCodecState * in_state, GstCaps * ref_caps)
static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_reconfigure (GstVaapiEncoder * base_encoder)
{
GstVaapiEncoderH264 *encoder;
GstCaps *result = NULL, *tmp;
GstStructure *structure;
const GValue *value;
const gchar *stream_format;
encoder = GST_VAAPI_ENCODER_H264 (base);
tmp = gst_caps_from_string ("video/x-h264");
gst_caps_set_simple (tmp,
"width", G_TYPE_INT, GST_VAAPI_ENCODER_WIDTH (encoder),
"height", G_TYPE_INT, GST_VAAPI_ENCODER_HEIGHT (encoder),
"framerate", GST_TYPE_FRACTION,
GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder),
NULL);
result = gst_caps_intersect (tmp, ref_caps);
gst_caps_unref (tmp);
/* fixed stream-format and choose byte-stream first */
structure = gst_caps_get_structure (result, 0);
value = gst_structure_get_value (structure, "stream-format");
if (value) {
gst_structure_fixate_field_string (structure, "stream-format",
"byte-stream");
stream_format = gst_structure_get_string (structure, "stream-format");
} else {
stream_format = "byte-stream";
gst_structure_set (structure, "stream-format", G_TYPE_STRING, stream_format,
NULL);
}
if (strcmp (stream_format, "byte-stream") == 0)
encoder->is_avc = FALSE;
else /* need codec data later */
encoder->is_avc = TRUE;
#if GST_CHECK_VERSION(1,0,0)
result = gst_caps_fixate (result);
#endif
GstVaapiEncoderH264 *const encoder =
GST_VAAPI_ENCODER_H264_CAST (base_encoder);
if (!init_encoder_public_attributes (encoder)) {
GST_WARNING ("encoder ensure public attributes failed ");
goto error;
}
if (!init_encoder_private_attributes (encoder, result)) {
if (!init_encoder_private_attributes (encoder)) {
GST_WARNING ("prepare encoding failed ");
goto error;
}
return result;
return GST_VAAPI_ENCODER_STATUS_SUCCESS;
error:
gst_caps_unref (result);
return NULL;
return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
}
static gboolean

View file

@ -107,13 +107,6 @@ ensure_public_attributes (GstVaapiEncoderMpeg2 * encoder)
{
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
if (!GST_VAAPI_ENCODER_WIDTH (encoder) ||
!GST_VAAPI_ENCODER_HEIGHT (encoder) ||
!GST_VAAPI_ENCODER_FPS_N (encoder) ||
!GST_VAAPI_ENCODER_FPS_D (encoder)) {
return FALSE;
}
if (encoder->ip_period > encoder->intra_period) {
encoder->ip_period = encoder->intra_period - 1;
}
@ -680,51 +673,20 @@ gst_vaapi_encoder_mpeg2_set_context_info (GstVaapiEncoder * base_encoder)
MAX_SLICE_HDR_SIZE;
}
static gboolean
prepare_encoding (GstVaapiEncoderMpeg2 * encoder, GstCaps * caps)
static GstVaapiEncoderStatus
gst_vaapi_encoder_mpeg2_reconfigure (GstVaapiEncoder * base_encoder)
{
return TRUE;
}
static GstCaps *
gst_vaapi_encoder_mpeg2_set_format (GstVaapiEncoder * base,
GstVideoCodecState * in_state, GstCaps * ref_caps)
{
GstVaapiEncoderMpeg2 *encoder;
GstCaps *result = NULL, *tmp;
encoder = GST_VAAPI_ENCODER_MPEG2 (base);
tmp = gst_caps_from_string ("video/mpeg");
gst_caps_set_simple (tmp,
"mpegversion", G_TYPE_INT, 2,
"systemstream", G_TYPE_BOOLEAN, FALSE,
"width", G_TYPE_INT, GST_VAAPI_ENCODER_WIDTH (encoder),
"height", G_TYPE_INT, GST_VAAPI_ENCODER_HEIGHT (encoder),
"framerate", GST_TYPE_FRACTION,
GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder),
NULL);
result = gst_caps_intersect (tmp, ref_caps);
gst_caps_unref (tmp);
#if GST_CHECK_VERSION(1,0,0)
result = gst_caps_fixate (result);
#endif
GstVaapiEncoderMpeg2 *const encoder =
GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder);
if (!ensure_public_attributes (encoder)) {
GST_WARNING ("encoder ensure public attributes failed ");
goto error;
}
if (!prepare_encoding (encoder, result)) {
GST_WARNING ("prepare encoding failed ");
goto error;
}
return result;
return GST_VAAPI_ENCODER_STATUS_SUCCESS;
error:
gst_caps_unref (result);
return NULL;
return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
}
static gboolean

View file

@ -55,12 +55,60 @@ G_BEGIN_DECLS
#define GST_VAAPI_ENCODER_VA_CONTEXT(encoder) \
(GST_VAAPI_ENCODER_CAST(encoder)->va_context)
#define GST_VAAPI_ENCODER_VIDEO_INFO(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info)
#define GST_VAAPI_ENCODER_CAPS(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->caps)
#define GST_VAAPI_ENCODER_WIDTH(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.width)
#define GST_VAAPI_ENCODER_HEIGHT(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.height)
#define GST_VAAPI_ENCODER_FPS_N(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.fps_n)
#define GST_VAAPI_ENCODER_FPS_D(encoder) (GST_VAAPI_ENCODER_CAST(encoder)->video_info.fps_d)
/**
* GST_VAAPI_ENCODER_VIDEO_INFO:
* @encoder: a #GstVaapiEncoder
*
* Macro that evaluates to the #GstVideoInfo of @encoder.
* This is an internal macro that does not do any run-time type check.
*/
#undef GST_VAAPI_ENCODER_VIDEO_INFO
#define GST_VAAPI_ENCODER_VIDEO_INFO(encoder) \
(&GST_VAAPI_ENCODER_CAST (encoder)->video_info)
/**
* GST_VAAPI_ENCODER_WIDTH:
* @encoder: a #GstVaapiEncoder
*
* Macro that evaluates to the coded width of the picture.
* This is an internal macro that does not do any run-time type check.
*/
#undef GST_VAAPI_ENCODER_WIDTH
#define GST_VAAPI_ENCODER_WIDTH(encoder) \
(GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->width)
/**
* GST_VAAPI_ENCODER_HEIGHT:
* @encoder: a #GstVaapiEncoder
*
* Macro that evaluates to the coded height of the picture.
* This is an internal macro that does not do any run-time type check.
*/
#undef GST_VAAPI_ENCODER_HEIGHT
#define GST_VAAPI_ENCODER_HEIGHT(encoder) \
(GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->height)
/**
* GST_VAAPI_ENCODER_FPS_N:
* @encoder: a #GstVaapiEncoder
*
* Macro that evaluates to the coded framerate numerator.
* This is an internal macro that does not do any run-time type check.
*/
#undef GST_VAAPI_ENCODER_FPS_N
#define GST_VAAPI_ENCODER_FPS_N(encoder) \
(GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->fps_n)
/**
* GST_VAAPI_ENCODER_FPS_D:
* @encoder: a #GstVaapiEncoder
*
* Macro that evaluates to the coded framerate denominator.
* This is an internal macro that does not do any run-time type check.
*/
#undef GST_VAAPI_ENCODER_FPS_D
#define GST_VAAPI_ENCODER_FPS_D(encoder) \
(GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->fps_d)
/**
* GST_VAAPI_ENCODER_RATE_CONTROL:
@ -113,7 +161,6 @@ struct _GstVaapiEncoder
GstVaapiDisplay *display;
GstVaapiContext *context;
GstVaapiContextInfo context_info;
GstCaps *caps;
VADisplay va_display;
VAContextID va_context;
@ -157,12 +204,10 @@ struct _GstVaapiEncoderClass
gboolean (*init) (GstVaapiEncoder * encoder);
void (*finalize) (GstVaapiEncoder * encoder);
GstCaps * (*set_format) (GstVaapiEncoder * encoder,
GstVideoCodecState * in_state,
GstCaps * ref_caps);
void (*set_context_info) (GstVaapiEncoder * encoder);
GstVaapiEncoderStatus (*reconfigure) (GstVaapiEncoder * encoder);
GPtrArray * (*get_default_properties) (void);
GstVaapiEncoderStatus (*set_property) (GstVaapiEncoder * encoder,
gint prop_id,
@ -196,8 +241,8 @@ struct _GstVaapiEncoderClass
.class_data = &g_class_data, \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, init), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, finalize), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, reconfigure), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, get_default_properties), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, set_format), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, set_context_info), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, reordering), \
GST_VAAPI_ENCODER_CLASS_HOOK (codec, encode), \

View file

@ -457,31 +457,18 @@ gst_vaapiencode_close (GstVideoEncoder * venc)
static gboolean
set_codec_state (GstVaapiEncode * encode, GstVideoCodecState * state)
{
GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (encode);
GstCaps *out_caps, *allowed_caps, *template_caps, *intersect;
GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode);
GstVaapiEncoderStatus status;
g_return_val_if_fail (encode->encoder, FALSE);
/* get peer caps for stream-format avc/bytestream, codec_data */
template_caps = gst_pad_get_pad_template_caps (plugin->srcpad);
allowed_caps = gst_pad_get_allowed_caps (plugin->srcpad);
intersect = gst_caps_intersect (template_caps, allowed_caps);
gst_caps_unref (template_caps);
gst_caps_unref (allowed_caps);
/* codec data was not set */
out_caps = gst_vaapi_encoder_set_format (encode->encoder, state, intersect);
gst_caps_unref (intersect);
g_return_val_if_fail (out_caps, FALSE);
if (!gst_caps_is_fixed (out_caps)) {
GST_ERROR ("encoder output caps was not fixed");
gst_caps_unref (out_caps);
/* Initialize codec specific parameters */
if (klass->set_config && !klass->set_config (encode))
return FALSE;
}
GST_DEBUG ("set srcpad caps to: %" GST_PTR_FORMAT, out_caps);
gst_caps_unref (out_caps);
status = gst_vaapi_encoder_set_codec_state (encode->encoder, state);
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
return FALSE;
return TRUE;
}

View file

@ -68,6 +68,7 @@ struct _GstVaapiEncodeClass
gboolean (*set_property) (GstVaapiEncode * encode,
guint prop_id, const GValue * value);
gboolean (*set_config) (GstVaapiEncode * encode);
GstCaps * (*get_caps) (GstVaapiEncode * encode);
GstVaapiEncoder * (*alloc_encoder) (GstVaapiEncode * encode,
GstVaapiDisplay * display);