#include <va/va_drmcommon.h>
#include "vacompat.h"
+#include "gstvabaseenc.h"
#include "gstvaencoder.h"
#include "gstvacaps.h"
#include "gstvaprofile.h"
#include "gstvadisplay_priv.h"
GST_DEBUG_CATEGORY_STATIC (gst_va_h264enc_debug);
-#ifndef GST_DISABLE_GST_DEBUG
#define GST_CAT_DEFAULT gst_va_h264enc_debug
-#else
-#define GST_CAT_DEFAULT NULL
-#endif
+
+#define GST_VA_H264_ENC(obj) ((GstVaH264Enc *) obj)
+#define GST_VA_H264_ENC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaH264EncClass))
+#define GST_VA_H264_ENC_CLASS(klass) ((GstVaH264EncClass *) klass)
typedef struct _GstVaH264Enc GstVaH264Enc;
typedef struct _GstVaH264EncClass GstVaH264EncClass;
typedef struct _GstVaH264EncFrame GstVaH264EncFrame;
typedef struct _GstVaH264LevelLimits GstVaH264LevelLimits;
-#define GST_VA_H264_ENC(obj) ((GstVaH264Enc *) obj)
-#define GST_VA_H264_ENC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaH264EncClass))
-#define GST_VA_H264_ENC_CLASS(klass) ((GstVaH264EncClass *) klass)
-
enum
{
PROP_KEY_INT_MAX = 1,
PROP_RATE_CONTROL,
PROP_CPB_SIZE,
PROP_AUD,
- PROP_DEVICE_PATH,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES];
+static GstElementClass *parent_class = NULL;
+
/* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
#define SX_BITRATE 6
/* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
#define MAX_GOP_SIZE 1024
-static GstObjectClass *parent_class = NULL;
-
/* *INDENT-OFF* */
struct _GstVaH264EncClass
{
- GstVideoEncoderClass parent_class;
-
- GstVaCodecs codec;
- gchar *render_device_path;
-
- gboolean (*reconfig) (GstVaH264Enc * encoder);
- gboolean (*push_frame) (GstVaH264Enc * encoder,
- GstVideoCodecFrame * frame,
- gboolean last);
- gboolean (*pop_frame) (GstVaH264Enc * encoder,
- GstVideoCodecFrame ** out_frame);
- gboolean (*encode_frame) (GstVaH264Enc * encoder,
- GstVideoCodecFrame * frame);
+ GstVaBaseEncClass parent_class;
};
/* *INDENT-ON* */
struct _GstVaH264Enc
{
/*< private > */
- GstVideoEncoder parent_instance;
+ GstVaBaseEnc parent;
- GstVaDisplay *display;
-
- gint width;
- gint height;
- VAProfile profile;
- VAEntrypoint entrypoint;
- guint rt_format;
- guint codedbuf_size;
/* properties */
struct
{
guint32 target_usage;
} prop;
- GstVideoCodecState *input_state;
- GstVideoCodecState *output_state;
- GstCaps *in_caps;
- GstVideoInfo in_info;
- GstVideoInfo sinkpad_info;
- GstBufferPool *raw_pool;
-
- GstClockTime start_pts;
- GstClockTime frame_duration;
- /* Total frames we handled since reconfig. */
- guint input_frame_count;
- guint output_frame_count;
-
- GstVaEncoder *encoder;
-
- GQueue reorder_list;
- GQueue ref_list;
-
- GQueue output_list;
-
/* H264 fields */
gint mb_width;
gint mb_height;
gint poc;
gint frame_num;
- gboolean last_frame;
/* The pic_num will be marked as unused_for_reference, which is
* replaced by this frame. -1 if we do not need to care about it
* explicitly. */
/* The total frame count we handled. */
guint total_frame_count;
+
+ gboolean last_frame;
};
/**
GstVaH264EncFrame *frame;
frame = g_slice_new (GstVaH264EncFrame);
- frame->last_frame = FALSE;
frame->frame_num = 0;
frame->unused_for_reference_pic_num = -1;
frame->picture = NULL;
frame->total_frame_count = 0;
+ frame->last_frame = FALSE;
return frame;
}
* ignored.
*/
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint bitrate;
guint32 rc_mode;
guint32 quality_level;
- quality_level = gst_va_encoder_get_quality_level (self->encoder,
- self->profile, self->entrypoint);
+ quality_level = gst_va_encoder_get_quality_level (base->encoder,
+ base->profile, base->entrypoint);
if (self->rc.target_usage > quality_level) {
GST_INFO_OBJECT (self, "User setting target-usage: %d is not supported, "
"fallback to %d", self->rc.target_usage, quality_level);
}
/* TODO: find a better heuristics to infer a nearer control mode */
- rc_mode = gst_va_encoder_get_rate_control_mode (self->encoder,
- self->profile, self->entrypoint);
+ rc_mode = gst_va_encoder_get_rate_control_mode (base->encoder,
+ base->profile, base->entrypoint);
if (!(rc_mode & self->prop.rc_ctrl)) {
GST_INFO_OBJECT (self, "The race control mode %s is not supported, "
"fallback to %s mode",
factor = (guint64) self->mb_width * self->mb_height * bits_per_mb;
bitrate = gst_util_uint64_scale (factor,
- GST_VIDEO_INFO_FPS_N (&self->in_info),
- GST_VIDEO_INFO_FPS_D (&self->in_info)) / 1000;
+ GST_VIDEO_INFO_FPS_N (&base->input_state->info),
+ GST_VIDEO_INFO_FPS_D (&base->input_state->info)) / 1000;
GST_INFO_OBJECT (self, "target bitrate computed to %u kbps", bitrate);
}
static gboolean
_calculate_level (GstVaH264Enc * self)
{
- const guint cpb_factor = _get_h264_cpb_nal_factor (self->profile);
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
+ const guint cpb_factor = _get_h264_cpb_nal_factor (base->profile);
guint i, PicSizeMbs, MaxDpbMbs, MaxMBPS;
PicSizeMbs = self->mb_width * self->mb_height;
MaxDpbMbs = PicSizeMbs * (self->gop.num_ref_frames + 1);
MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs,
- GST_VIDEO_INFO_FPS_N (&self->in_info),
- GST_VIDEO_INFO_FPS_D (&self->in_info));
+ GST_VIDEO_INFO_FPS_N (&base->input_state->info),
+ GST_VIDEO_INFO_FPS_D (&base->input_state->info));
for (i = 0; i < G_N_ELEMENTS (_va_h264_level_limits); i++) {
const GstVaH264LevelLimits *const limits = &_va_h264_level_limits[i];
static void
_validate_parameters (GstVaH264Enc * self)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
gint32 max_slices;
/* Ensure the num_slices provided by the user not exceed the limit
* of the number of slices permitted by the stream and by the
* hardware. */
g_assert (self->num_slices >= 1);
- max_slices = gst_va_encoder_get_max_slice_num (self->encoder,
- self->profile, self->entrypoint);
+ max_slices = gst_va_encoder_get_max_slice_num (base->encoder,
+ base->profile, base->entrypoint);
if (self->num_slices > max_slices)
self->num_slices = max_slices;
/* The stream size limit. */
/* Ensure trellis. */
if (self->use_trellis &&
- !gst_va_encoder_has_trellis (self->encoder, self->profile,
- self->entrypoint)) {
+ !gst_va_encoder_has_trellis (base->encoder, base->profile,
+ base->entrypoint)) {
GST_INFO_OBJECT (self, "The trellis is not supported");
self->use_trellis = FALSE;
}
static void
_generate_gop_structure (GstVaH264Enc * self)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint32 list0, list1, gop_ref_num;
gint32 p_frames;
/* If not set, generate a idr every second */
if (self->gop.idr_period == 0) {
- self->gop.idr_period = (GST_VIDEO_INFO_FPS_N (&self->in_info)
- + GST_VIDEO_INFO_FPS_D (&self->in_info) - 1) /
- GST_VIDEO_INFO_FPS_D (&self->in_info);
+ self->gop.idr_period = (GST_VIDEO_INFO_FPS_N (&base->input_state->info)
+ + GST_VIDEO_INFO_FPS_D (&base->input_state->info) - 1) /
+ GST_VIDEO_INFO_FPS_D (&base->input_state->info);
}
/* Do not use a too huge GOP size. */
}
}
- if (!gst_va_encoder_get_max_num_reference (self->encoder, self->profile,
- self->entrypoint, &list0, &list1)) {
+ if (!gst_va_encoder_get_max_num_reference (base->encoder, base->profile,
+ base->entrypoint, &list0, &list1)) {
GST_INFO_OBJECT (self, "Failed to get the max num reference");
list0 = 1;
list1 = 0;
static void
_calculate_coded_size (GstVaH264Enc * self)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint codedbuf_size = 0;
- if (self->profile == VAProfileH264High
- || self->profile == VAProfileH264MultiviewHigh
- || self->profile == VAProfileH264StereoHigh) {
+ if (base->profile == VAProfileH264High
+ || base->profile == VAProfileH264MultiviewHigh
+ || base->profile == VAProfileH264StereoHigh) {
/* The number of bits of macroblock_layer( ) data for any macroblock
is not greater than 128 + RawMbBits */
guint RawMbBits = 0;
guint MbWidthC = 8;
guint MbHeightC = 8;
- switch (self->rt_format) {
+ switch (base->rt_format) {
case VA_RT_FORMAT_YUV420:
BitDepthY = 8;
BitDepthC = 8;
self->num_slices * (4 + GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
/* Add 5% for safety */
- self->codedbuf_size = (guint) ((gfloat) codedbuf_size * 1.05);
+ base->codedbuf_size = (guint) ((gfloat) codedbuf_size * 1.05);
- GST_DEBUG_OBJECT (self, "Calculate codedbuf size: %u", self->codedbuf_size);
+ GST_DEBUG_OBJECT (self, "Calculate codedbuf size: %u", base->codedbuf_size);
}
static guint
static gboolean
_init_packed_headers (GstVaH264Enc * self)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint32 packed_headers;
guint32 desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE /* SPS */
| VA_ENC_PACKED_HEADER_PICTURE /* PPS */
self->packed_headers = 0;
- packed_headers = gst_va_encoder_get_packed_headers (self->encoder,
- self->profile, self->entrypoint);
+ packed_headers = gst_va_encoder_get_packed_headers (base->encoder,
+ base->profile, base->entrypoint);
if (packed_headers == 0)
return FALSE;
static gboolean
_decide_profile (GstVaH264Enc * self)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
gboolean ret = FALSE;
GstVideoFormat in_format;
VAProfile profile;
candidates = g_ptr_array_new_with_free_func (g_free);
/* First, check whether the downstream requires a specified profile. */
- allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
+ allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (base));
if (!allowed_caps)
- allowed_caps = gst_pad_query_caps (GST_VIDEO_ENCODER_SRC_PAD (self), NULL);
+ allowed_caps = gst_pad_query_caps (GST_VIDEO_ENCODER_SRC_PAD (base), NULL);
if (allowed_caps && !gst_caps_is_empty (allowed_caps)) {
num_structures = gst_caps_get_size (allowed_caps);
goto out;
}
- in_format = GST_VIDEO_INFO_FORMAT (&self->in_info);
+ in_format = GST_VIDEO_INFO_FORMAT (&base->input_state->info);
rt_format = _get_rtformat (self, in_format);
if (!rt_format) {
GST_ERROR_OBJECT (self, "unsupported video format %s",
if (profile == VAProfileNone)
continue;
- if (!gst_va_encoder_has_profile_and_entrypoint (self->encoder,
+ if (!gst_va_encoder_has_profile_and_entrypoint (base->encoder,
profile, VAEntrypointEncSlice))
continue;
- if ((rt_format & gst_va_encoder_get_rtformat (self->encoder,
+ if ((rt_format & gst_va_encoder_get_rtformat (base->encoder,
profile, VAEntrypointEncSlice)) == 0)
continue;
- self->profile = profile;
- self->entrypoint = VAEntrypointEncSlice;
- self->rt_format = rt_format;
+ base->profile = profile;
+ base->entrypoint = VAEntrypointEncSlice;
+ base->rt_format = rt_format;
ret = TRUE;
goto out;
}
if (profile == VAProfileNone)
continue;
- if (!gst_va_encoder_has_profile_and_entrypoint (self->encoder,
+ if (!gst_va_encoder_has_profile_and_entrypoint (base->encoder,
profile, VAEntrypointEncSlice))
continue;
- if ((rt_format & gst_va_encoder_get_rtformat (self->encoder,
+ if ((rt_format & gst_va_encoder_get_rtformat (base->encoder,
profile, VAEntrypointEncSlice)) == 0)
continue;
- self->profile = profile;
- self->entrypoint = VAEntrypointEncSlice;
- self->rt_format = rt_format;
+ base->profile = profile;
+ base->entrypoint = VAEntrypointEncSlice;
+ base->rt_format = rt_format;
ret = TRUE;
}
if (self->use_dct8x8 && !g_strstr_len (profile_name, -1, "high")) {
GST_INFO_OBJECT (self, "Disable dct8x8, profile %s does not support it",
- gst_va_profile_name (self->profile));
+ gst_va_profile_name (base->profile));
self->use_dct8x8 = FALSE;
self->prop.use_dct8x8 = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DCT8X8]);
if (self->use_cabac && (!g_strstr_len (profile_name, -1, "main")
&& !g_strstr_len (profile_name, -1, "high"))) {
GST_INFO_OBJECT (self, "Disable cabac, profile %s does not support it",
- gst_va_profile_name (self->profile));
+ gst_va_profile_name (base->profile));
self->use_cabac = FALSE;
self->prop.use_cabac = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CABAC]);
if (self->gop.num_bframes > 0 && g_strstr_len (profile_name, -1, "baseline")) {
GST_INFO_OBJECT (self, "No B frames, profile %s does not support it",
- gst_va_profile_name (self->profile));
+ gst_va_profile_name (base->profile));
self->gop.num_bframes = 0;
self->gop.b_pyramid = 0;
}
static void
gst_va_h264_enc_reset_state (GstVaH264Enc * self)
{
- self->width = 0;
- self->height = 0;
- self->profile = VAProfileNone;
- self->entrypoint = 0;
- self->rt_format = 0;
- self->codedbuf_size = 0;
-
- self->frame_duration = GST_CLOCK_TIME_NONE;
- self->input_frame_count = 0;
- self->output_frame_count = 0;
+ gst_va_base_enc_reset_state (GST_VA_BASE_ENC (self));
self->level_idc = 0;
self->level_str = NULL;
}
static gboolean
-gst_va_h264_enc_reconfig (GstVaH264Enc * self)
+gst_va_h264_enc_reconfig (GstVaBaseEnc * base)
{
+ GstVideoEncoder *venc = GST_VIDEO_ENCODER (base);
+ GstVaH264Enc *self = GST_VA_H264_ENC (base);
+ GstCaps *out_caps;
+ guint max_ref_frames;
+ GstVideoCodecState *output_state;
+
gst_va_h264_enc_reset_state (self);
- self->width = GST_VIDEO_INFO_WIDTH (&self->in_info);
- self->height = GST_VIDEO_INFO_HEIGHT (&self->in_info);
+ base->width = GST_VIDEO_INFO_WIDTH (&base->input_state->info);
+ base->height = GST_VIDEO_INFO_HEIGHT (&base->input_state->info);
- self->mb_width = GST_ROUND_UP_16 (self->width) / 16;
- self->mb_height = GST_ROUND_UP_16 (self->height) / 16;
+ self->mb_width = GST_ROUND_UP_16 (base->width) / 16;
+ self->mb_height = GST_ROUND_UP_16 (base->height) / 16;
/* Frame rate is needed for rate control and PTS setting. */
- if (GST_VIDEO_INFO_FPS_N (&self->in_info) == 0
- || GST_VIDEO_INFO_FPS_D (&self->in_info) == 0) {
+ if (GST_VIDEO_INFO_FPS_N (&base->input_state->info) == 0
+ || GST_VIDEO_INFO_FPS_D (&base->input_state->info) == 0) {
GST_INFO_OBJECT (self, "Unknown framerate, just set to 30 fps");
- GST_VIDEO_INFO_FPS_N (&self->in_info) = 30;
- GST_VIDEO_INFO_FPS_D (&self->in_info) = 1;
+ GST_VIDEO_INFO_FPS_N (&base->input_state->info) = 30;
+ GST_VIDEO_INFO_FPS_D (&base->input_state->info) = 1;
}
- self->frame_duration = gst_util_uint64_scale (GST_SECOND,
- GST_VIDEO_INFO_FPS_D (&self->in_info),
- GST_VIDEO_INFO_FPS_N (&self->in_info));
+ base->frame_duration = gst_util_uint64_scale (GST_SECOND,
+ GST_VIDEO_INFO_FPS_D (&base->input_state->info),
+ GST_VIDEO_INFO_FPS_N (&base->input_state->info));
GST_DEBUG_OBJECT (self, "resolution:%dx%d, MB size: %dx%d,"
" frame duration is %" GST_TIME_FORMAT,
- self->width, self->height, self->mb_width, self->mb_height,
- GST_TIME_ARGS (self->frame_duration));
+ base->width, base->height, self->mb_width, self->mb_height,
+ GST_TIME_ARGS (base->frame_duration));
if (!_decide_profile (self))
return FALSE;
if (!_init_packed_headers (self))
return FALSE;
+ max_ref_frames = self->gop.num_ref_frames + 3 /* scratch frames */ ;
+ if (!gst_va_encoder_open (base->encoder, base->profile, base->entrypoint,
+ GST_VIDEO_INFO_FORMAT (&base->input_state->info), base->rt_format,
+ self->mb_width * 16, self->mb_height * 16, base->codedbuf_size,
+ max_ref_frames, self->rc.rc_ctrl_mode, self->packed_headers)) {
+ GST_ERROR_OBJECT (self, "Failed to open the VA encoder.");
+ return FALSE;
+ }
+
+ /* Add some tags */
+ gst_va_base_enc_add_codec_tag (base, "H264");
+
+ out_caps = gst_va_profile_caps (base->profile);
+ g_assert (out_caps);
+ out_caps = gst_caps_fixate (out_caps);
+
+ if (self->level_str)
+ gst_caps_set_simple (out_caps, "level", G_TYPE_STRING, self->level_str,
+ NULL);
+
+ gst_caps_set_simple (out_caps, "width", G_TYPE_INT, base->width,
+ "height", G_TYPE_INT, base->height, "alignment", G_TYPE_STRING, "au",
+ "stream-format", G_TYPE_STRING, "byte-stream", NULL);
+
+ GST_DEBUG_OBJECT (self, "output caps is %" GST_PTR_FORMAT, out_caps);
+
+ output_state =
+ gst_video_encoder_set_output_state (venc, out_caps, base->input_state);
+ gst_video_codec_state_unref (output_state);
+
+ if (!gst_video_encoder_negotiate (venc)) {
+ GST_ERROR_OBJECT (self, "Failed to negotiate with the downstream");
+ return FALSE;
+ }
+
return TRUE;
}
static gboolean
-gst_va_h264_enc_push_frame (GstVaH264Enc * self, GstVideoCodecFrame * gst_frame,
+_push_one_frame (GstVaBaseEnc * base, GstVideoCodecFrame * gst_frame,
gboolean last)
{
+ GstVaH264Enc *self = GST_VA_H264_ENC (base);
GstVaH264EncFrame *frame;
g_return_val_if_fail (self->gop.cur_frame_index <= self->gop.idr_period,
if (gst_frame) {
/* Begin a new GOP, should have a empty reorder_list. */
if (self->gop.cur_frame_index == self->gop.idr_period) {
- g_assert (g_queue_is_empty (&self->reorder_list));
+ g_assert (g_queue_is_empty (&base->reorder_list));
self->gop.cur_frame_index = 0;
self->gop.cur_frame_num = 0;
}
GST_LOG_OBJECT (self, "system_frame_number: %d, an IDR frame, starts"
" a new GOP", gst_frame->system_frame_number);
- g_queue_clear_full (&self->ref_list,
+ g_queue_clear_full (&base->ref_list,
(GDestroyNotify) gst_video_codec_frame_unref);
}
_slice_type_name (frame->type));
self->gop.cur_frame_index++;
- g_queue_push_tail (&self->reorder_list,
+ g_queue_push_tail (&base->reorder_list,
gst_video_codec_frame_ref (gst_frame));
}
/* Ensure next push will start a new GOP. */
self->gop.cur_frame_index = self->gop.idr_period;
- if (!g_queue_is_empty (&self->reorder_list)) {
- last_frame = g_queue_peek_tail (&self->reorder_list);
+ if (!g_queue_is_empty (&base->reorder_list)) {
+ last_frame = g_queue_peek_tail (&base->reorder_list);
frame = _enc_frame (last_frame);
if (frame->type == GST_H264_B_SLICE) {
frame->type = GST_H264_P_SLICE;
static GstVideoCodecFrame *
_pop_pyramid_b_frame (GstVaH264Enc * self)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint i;
gint index = -1;
GstVaH264EncFrame *b_vaframe;
b_vaframe = NULL;
/* Find the lowest level with smallest poc. */
- for (i = 0; i < g_queue_get_length (&self->reorder_list); i++) {
+ for (i = 0; i < g_queue_get_length (&base->reorder_list); i++) {
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
- f = g_queue_peek_nth (&self->reorder_list, i);
+ f = g_queue_peek_nth (&base->reorder_list, i);
if (!b_frame) {
b_frame = f;
/* Check whether its refs are already poped. */
g_assert (b_vaframe->left_ref_poc_diff != 0);
g_assert (b_vaframe->right_ref_poc_diff != 0);
- for (i = 0; i < g_queue_get_length (&self->reorder_list); i++) {
+ for (i = 0; i < g_queue_get_length (&base->reorder_list); i++) {
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
- f = g_queue_peek_nth (&self->reorder_list, i);
+ f = g_queue_peek_nth (&base->reorder_list, i);
if (f == b_frame)
continue;
/* Ensure we already have enough backward refs */
count.num = 0;
count.poc = b_vaframe->poc;
- g_queue_foreach (&self->ref_list, (GFunc) _count_backward_ref_num, &count);
+ g_queue_foreach (&base->ref_list, (GFunc) _count_backward_ref_num, &count);
if (count.num >= self->gop.ref_num_list1) {
GstVideoCodecFrame *f;
/* it will unref at pop_frame */
- f = g_queue_pop_nth (&self->reorder_list, index);
+ f = g_queue_pop_nth (&base->reorder_list, index);
g_assert (f == b_frame);
} else {
b_frame = NULL;
}
static gboolean
-gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVideoCodecFrame ** out_frame)
+_pop_one_frame (GstVaBaseEnc * base, GstVideoCodecFrame ** out_frame)
{
+ GstVaH264Enc *self = GST_VA_H264_ENC (base);
GstVaH264EncFrame *vaframe;
GstVideoCodecFrame *frame;
struct RefFramesCount count;
*out_frame = NULL;
- if (g_queue_is_empty (&self->reorder_list))
+ if (g_queue_is_empty (&base->reorder_list))
return TRUE;
/* Return the last pushed non-B immediately. */
- frame = g_queue_peek_tail (&self->reorder_list);
+ frame = g_queue_peek_tail (&base->reorder_list);
vaframe = _enc_frame (frame);
if (vaframe->type != GST_H264_B_SLICE) {
- frame = g_queue_pop_tail (&self->reorder_list);
+ frame = g_queue_pop_tail (&base->reorder_list);
goto get_one;
}
/* If GOP end, pop anyway. */
if (self->gop.cur_frame_index == self->gop.idr_period) {
- frame = g_queue_pop_head (&self->reorder_list);
+ frame = g_queue_pop_head (&base->reorder_list);
goto get_one;
}
/* Ensure we already have enough backward refs */
- frame = g_queue_peek_head (&self->reorder_list);
+ frame = g_queue_peek_head (&base->reorder_list);
vaframe = _enc_frame (frame);
count.num = 0;
count.poc = vaframe->poc;
- g_queue_foreach (&self->ref_list, _count_backward_ref_num, &count);
+ g_queue_foreach (&base->ref_list, _count_backward_ref_num, &count);
if (count.num >= self->gop.ref_num_list1) {
- frame = g_queue_pop_head (&self->reorder_list);
+ frame = g_queue_pop_head (&base->reorder_list);
goto get_one;
}
return TRUE;
}
+static gboolean
+gst_va_h264_enc_reorder_frame (GstVaBaseEnc * base, GstVideoCodecFrame * frame,
+ gboolean bump_all, GstVideoCodecFrame ** out_frame)
+{
+ if (!_push_one_frame (base, frame, bump_all)) {
+ GST_ERROR_OBJECT (base, "Failed to push the input frame"
+ " system_frame_number: %d into the reorder list",
+ frame->system_frame_number);
+
+ *out_frame = NULL;
+ return FALSE;
+ }
+
+ if (!_pop_one_frame (base, out_frame)) {
+ GST_ERROR_OBJECT (base, "Failed to pop the frame from the reorder list");
+ *out_frame = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static inline gboolean
_fill_sps (GstVaH264Enc * self, VAEncSequenceParameterBufferH264 * seq_param)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
GstH264Profile profile;
guint32 constraint_set0_flag, constraint_set1_flag;
guint32 constraint_set2_flag, constraint_set3_flag;
constraint_set2_flag = 0;
constraint_set3_flag = 0;
- switch (self->profile) {
+ switch (base->profile) {
case VAProfileH264ConstrainedBaseline:
profile = GST_H264_PROFILE_BASELINE;
/* A.2.1 (baseline profile constraints) */
static gboolean
_add_sequence_header (GstVaH264Enc * self, GstVaH264EncFrame * frame)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
gsize size;
#define SPS_SIZE 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE + MAX_VUI_PARAMS_SIZE + \
2 * MAX_HRD_PARAMS_SIZE) / 8
return FALSE;
}
- if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
+ if (!gst_va_encoder_add_packed_header (base->encoder, frame->picture,
VAEncPackedHeaderSequence, packed_sps, size, FALSE)) {
GST_ERROR_OBJECT (self, "Failed to add the packed sequence header");
return FALSE;
_fill_sequence_param (GstVaH264Enc * self,
VAEncSequenceParameterBufferH264 * sequence)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
gboolean direct_8x8_inference_flag = TRUE;
g_assert (self->gop.log2_max_frame_num >= 4);
* direct_8x8_inference_flag is equal to 1 for all levels of the
* Extended profile. Table A-4. We only have constrained baseline
* here. */
- if (self->profile == VAProfileH264ConstrainedBaseline)
+ if (base->profile == VAProfileH264ConstrainedBaseline)
direct_8x8_inference_flag = FALSE;
/* *INDENT-OFF* */
},
.aspect_ratio_idc = 0xff,
/* FIXME: what if no framerate info is provided */
- .sar_width = GST_VIDEO_INFO_PAR_N (&self->in_info),
- .sar_height = GST_VIDEO_INFO_PAR_D (&self->in_info),
- .num_units_in_tick = GST_VIDEO_INFO_FPS_D (&self->in_info),
- .time_scale = GST_VIDEO_INFO_FPS_N (&self->in_info) * 2,
+ .sar_width = GST_VIDEO_INFO_PAR_N (&base->input_state->info),
+ .sar_height = GST_VIDEO_INFO_PAR_D (&base->input_state->info),
+ .num_units_in_tick = GST_VIDEO_INFO_FPS_D (&base->input_state->info),
+ .time_scale = GST_VIDEO_INFO_FPS_N (&base->input_state->info) * 2,
};
/* *INDENT-ON* */
/* frame_cropping_flag */
- if (self->width & 15 || self->height & 15) {
+ if (base->width & 15 || base->height & 15) {
static const guint SubWidthC[] = { 1, 2, 2, 1 };
static const guint SubHeightC[] = { 1, 2, 1, 1 };
const guint CropUnitX =
sequence->frame_cropping_flag = 1;
sequence->frame_crop_left_offset = 0;
sequence->frame_crop_right_offset = (16 * self->mb_width -
- self->width) / CropUnitX;
+ base->width) / CropUnitX;
sequence->frame_crop_top_offset = 0;
sequence->frame_crop_bottom_offset = (16 * self->mb_height -
- self->height) / CropUnitY;
+ base->height) / CropUnitY;
}
}
_add_sequence_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture,
VAEncSequenceParameterBufferH264 * sequence)
{
- if (!gst_va_encoder_add_param (self->encoder, picture,
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
+
+ if (!gst_va_encoder_add_param (base->encoder, picture,
VAEncSequenceParameterBufferType, sequence, sizeof (*sequence))) {
GST_ERROR_OBJECT (self, "Failed to create the sequence parameter");
return FALSE;
return TRUE;
}
-static gboolean
-_add_rate_control_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
-{
- uint32_t window_size;
- struct VAEncMiscParameterRateControlWrap
- {
- VAEncMiscParameterType type;
- VAEncMiscParameterRateControl rate_control;
- } rate_control;
-
- if (self->rc.rc_ctrl_mode == VA_RC_CQP)
- return TRUE;
-
- window_size = self->rc.rc_ctrl_mode == VA_RC_VBR ?
- self->rc.max_bitrate_bits / 2 : self->rc.max_bitrate_bits;
-
- /* *INDENT-OFF* */
- rate_control = (struct VAEncMiscParameterRateControlWrap) {
- .type = VAEncMiscParameterTypeRateControl,
- .rate_control = {
- .bits_per_second = self->rc.max_bitrate_bits,
- .target_percentage = self->rc.target_percentage,
- .window_size = window_size,
- .initial_qp = self->rc.qp_i,
- .min_qp = self->rc.min_qp,
- .max_qp = self->rc.max_qp,
- .rc_flags.bits.mb_rate_control = self->rc.mbbrc,
- .quality_factor = 0,
- },
- };
- /* *INDENT-ON* */
-
- if (!gst_va_encoder_add_param (self->encoder, picture,
- VAEncMiscParameterBufferType, &rate_control, sizeof (rate_control))) {
- GST_ERROR_OBJECT (self, "Failed to create the race control parameter");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_add_hrd_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
-{
- /* *INDENT-OFF* */
- struct
- {
- VAEncMiscParameterType type;
- VAEncMiscParameterHRD hrd;
- } hrd = {
- .type = VAEncMiscParameterTypeHRD,
- .hrd = {
- .buffer_size = self->rc.cpb_length_bits,
- .initial_buffer_fullness = self->rc.cpb_length_bits / 2,
- },
- };
- /* *INDENT-ON* */
-
- if (self->rc.rc_ctrl_mode == VA_RC_CQP || self->rc.rc_ctrl_mode == VA_RC_VCM)
- return TRUE;
-
- g_assert (self->rc.max_bitrate_bits > 0);
-
-
- if (!gst_va_encoder_add_param (self->encoder, picture,
- VAEncMiscParameterBufferType, &hrd, sizeof (hrd))) {
- GST_ERROR_OBJECT (self, "Failed to create the HRD parameter");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_add_quality_level_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
-{
- /* *INDENT-OFF* */
- struct
- {
- VAEncMiscParameterType type;
- VAEncMiscParameterBufferQualityLevel ql;
- } quality_level = {
- .type = VAEncMiscParameterTypeQualityLevel,
- .ql.quality_level = self->rc.target_usage,
- };
- /* *INDENT-ON* */
-
- if (self->rc.target_usage == 0)
- return TRUE;
-
- if (!gst_va_encoder_add_param (self->encoder, picture,
- VAEncMiscParameterBufferType, &quality_level,
- sizeof (quality_level))) {
- GST_ERROR_OBJECT (self, "Failed to create the quality level parameter");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_add_frame_rate_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
-{
- /* *INDENT-OFF* */
- struct
- {
- VAEncMiscParameterType type;
- VAEncMiscParameterFrameRate fr;
- } framerate = {
- .type = VAEncMiscParameterTypeFrameRate,
- /* denominator = framerate >> 16 & 0xffff;
- * numerator = framerate & 0xffff; */
- .fr.framerate = (GST_VIDEO_INFO_FPS_N (&self->in_info) & 0xffff) |
- ((GST_VIDEO_INFO_FPS_D (&self->in_info) & 0xffff) << 16)
- };
- /* *INDENT-ON* */
-
- if (!gst_va_encoder_add_param (self->encoder, picture,
- VAEncMiscParameterBufferType, &framerate, sizeof (framerate))) {
- GST_ERROR_OBJECT (self, "Failed to create the frame rate parameter");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_add_trellis_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
-{
- /* *INDENT-OFF* */
- struct
- {
- VAEncMiscParameterType type;
- VAEncMiscParameterQuantization tr;
- } trellis = {
- .type = VAEncMiscParameterTypeQuantization,
- .tr.quantization_flags.bits = {
- .disable_trellis = 0,
- .enable_trellis_I = 1,
- .enable_trellis_B = 1,
- .enable_trellis_P = 1,
- },
- };
- /* *INDENT-ON* */
-
- if (!self->use_trellis)
- return TRUE;
-
- if (!gst_va_encoder_add_param (self->encoder, picture,
- VAEncMiscParameterBufferType, &trellis, sizeof (trellis))) {
- GST_ERROR_OBJECT (self, "Failed to create the trellis parameter");
- return FALSE;
- }
-
- return TRUE;
-}
-
static inline gboolean
_fill_picture_parameter (GstVaH264Enc * self, GstVaH264EncFrame * frame,
VAEncPictureParameterBufferH264 * pic_param)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint i;
/* *INDENT-OFF* */
*pic_param = (VAEncPictureParameterBufferH264) {
- .CurrPic.picture_id = gst_va_encode_picture_get_reconstruct_surface (frame->picture),
- .CurrPic.TopFieldOrderCnt = frame->poc,
+ .CurrPic = {
+ .picture_id =
+ gst_va_encode_picture_get_reconstruct_surface (frame->picture),
+ .TopFieldOrderCnt = frame->poc,
+ },
.coded_buf = frame->picture->coded_buffer,
/* Only support one sps and pps now. */
.pic_parameter_set_id = 0,
if (frame->type != GST_H264_I_SLICE) {
GstVaH264EncFrame *f;
- if (g_queue_is_empty (&self->ref_list)) {
+ if (g_queue_is_empty (&base->ref_list)) {
GST_ERROR_OBJECT (self, "No reference found for frame type %s",
_slice_type_name (frame->type));
return FALSE;
}
- g_assert (g_queue_get_length (&self->ref_list) <= self->gop.num_ref_frames);
+ g_assert (g_queue_get_length (&base->ref_list) <= self->gop.num_ref_frames);
/* ref frames in queue are already sorted by frame_num. */
- for (; i < g_queue_get_length (&self->ref_list); i++) {
- f = _enc_frame (g_queue_peek_nth (&self->ref_list, i));
+ for (; i < g_queue_get_length (&base->ref_list); i++) {
+ f = _enc_frame (g_queue_peek_nth (&base->ref_list, i));
pic_param->ReferenceFrames[i].picture_id =
gst_va_encode_picture_get_reconstruct_surface (f->picture);
_add_picture_parameter (GstVaH264Enc * self, GstVaH264EncFrame * frame,
VAEncPictureParameterBufferH264 * pic_param)
{
- if (!gst_va_encoder_add_param (self->encoder, frame->picture,
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
+
+ if (!gst_va_encoder_add_param (base->encoder, frame->picture,
VAEncPictureParameterBufferType, pic_param,
sizeof (VAEncPictureParameterBufferH264))) {
GST_ERROR_OBJECT (self, "Failed to create the picture parameter");
_add_picture_header (GstVaH264Enc * self, GstVaH264EncFrame * frame,
GstH264PPS * pps)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
#define PPS_SIZE 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8
guint8 packed_pps[PPS_SIZE] = { 0, };
#undef PPS_SIZE
return FALSE;
}
- if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
+ if (!gst_va_encoder_add_packed_header (base->encoder, frame->picture,
VAEncPackedHeaderPicture, packed_pps, size, FALSE)) {
GST_ERROR_OBJECT (self, "Failed to add the packed picture header");
return FALSE;
GstVaH264EncFrame * list0[16], guint list0_num,
GstVaH264EncFrame * list1[16], guint list1_num)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
int8_t slice_qp_delta = 0;
gint i;
slice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
}
- if (!gst_va_encoder_add_param (self->encoder, frame->picture,
+ if (!gst_va_encoder_add_param (base->encoder, frame->picture,
VAEncSliceParameterBufferType, slice,
sizeof (VAEncSliceParameterBufferH264))) {
GST_ERROR_OBJECT (self, "Failed to create the slice parameter");
GstVaH264EncFrame * list0[16], guint list0_num,
GstVaH264EncFrame * list1[16], guint list1_num)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
GstH264SliceHdr slice_hdr;
gsize size;
GstH264NalUnitType nal_type = GST_H264_NAL_SLICE;
return FALSE;
}
- if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
+ if (!gst_va_encoder_add_packed_header (base->encoder, frame->picture,
VAEncPackedHeaderSlice, packed_slice_hdr, size, FALSE)) {
GST_ERROR_OBJECT (self, "Failed to add the packed slice header");
return FALSE;
static gboolean
_add_aud (GstVaH264Enc * self, GstVaH264EncFrame * frame)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
guint8 aud_data[8] = { };
gsize size;
guint8 primary_pic_type = 0;
return FALSE;
}
- if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
+ if (!gst_va_encoder_add_packed_header (base->encoder, frame->picture,
VAEncPackedHeaderRawData, aud_data, size, FALSE)) {
GST_ERROR_OBJECT (self, "Failed to add the AUD");
return FALSE;
}
static gboolean
-gst_va_h264_enc_encode_frame (GstVaH264Enc * self,
- GstVideoCodecFrame * gst_frame)
+_encode_one_frame (GstVaH264Enc * self, GstVideoCodecFrame * gst_frame)
{
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
VAEncPictureParameterBufferH264 pic_param;
GstH264PPS pps;
GstVaH264EncFrame *list0[16] = { NULL, };
if (frame->poc == 0) {
VAEncSequenceParameterBufferH264 sequence;
- if (!_add_rate_control_parameter (self, frame->picture))
+ if (!gst_va_base_enc_add_rate_control_parameter (base, frame->picture,
+ self->rc.rc_ctrl_mode, self->rc.max_bitrate_bits,
+ self->rc.target_percentage, self->rc.qp_i, self->rc.min_qp,
+ self->rc.max_qp, self->rc.mbbrc))
return FALSE;
- if (!_add_quality_level_parameter (self, frame->picture))
+ if (!gst_va_base_enc_add_quality_level_parameter (base, frame->picture,
+ self->rc.target_usage))
return FALSE;
- if (!_add_frame_rate_parameter (self, frame->picture))
+ if (!gst_va_base_enc_add_frame_rate_parameter (base, frame->picture))
return FALSE;
- if (!_add_hrd_parameter (self, frame->picture))
+ if (!gst_va_base_enc_add_hrd_parameter (base, frame->picture,
+ self->rc.rc_ctrl_mode, self->rc.cpb_length_bits))
return FALSE;
- if (!_add_trellis_parameter (self, frame->picture))
+ if (!gst_va_base_enc_add_trellis_parameter (base, frame->picture,
+ self->use_trellis))
return FALSE;
_fill_sequence_param (self, &sequence);
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
- for (i = g_queue_get_length (&self->ref_list) - 1; i >= 0; i--) {
- f = g_queue_peek_nth (&self->ref_list, i);
+ for (i = g_queue_get_length (&base->ref_list) - 1; i >= 0; i--) {
+ f = g_queue_peek_nth (&base->ref_list, i);
vaf = _enc_frame (f);
if (vaf->poc > frame->poc)
continue;
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
- for (i = 0; i < g_queue_get_length (&self->ref_list); i++) {
- f = g_queue_peek_nth (&self->ref_list, i);
+ for (i = 0; i < g_queue_get_length (&base->ref_list); i++) {
+ f = g_queue_peek_nth (&base->ref_list, i);
vaf = _enc_frame (f);
if (vaf->poc < frame->poc)
continue;
return FALSE;
if ((self->packed_headers & VA_ENC_PACKED_HEADER_SLICE) &&
- (!_add_slice_header (self, frame, &pps, &slice, list0, list0_num, list1,
- list1_num)))
+ (!_add_slice_header (self, frame, &pps, &slice, list0, list0_num,
+ list1, list1_num)))
return FALSE;
slice_start_mb += slice_mbs;
}
- if (!gst_va_encoder_encode (self->encoder, frame->picture)) {
+ if (!gst_va_encoder_encode (base->encoder, frame->picture)) {
GST_ERROR_OBJECT (self, "Encode frame error");
return FALSE;
}
}
static gboolean
-gst_va_h264_enc_start (GstVideoEncoder * encoder)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (encoder);
-
- /* Set the minimum pts to some huge value (1000 hours). This keeps
- * the dts at the start of the stream from needing to be
- * negative. */
- self->start_pts = GST_SECOND * 60 * 60 * 1000;
- gst_video_encoder_set_min_pts (encoder, self->start_pts);
-
- return TRUE;
-}
-
-static gboolean
-gst_va_h264_enc_open (GstVideoEncoder * venc)
-{
- GstVaH264Enc *encoder = GST_VA_H264_ENC (venc);
- GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (venc);
- gboolean ret = FALSE;
-
- if (!gst_va_ensure_element_data (venc, klass->render_device_path,
- &encoder->display))
- return FALSE;
-
- if (!g_atomic_pointer_get (&encoder->encoder)) {
- GstVaEncoder *va_encoder;
-
- va_encoder = gst_va_encoder_new (encoder->display, klass->codec);
- if (va_encoder)
- ret = TRUE;
-
- gst_object_replace ((GstObject **) (&encoder->encoder),
- (GstObject *) va_encoder);
- gst_clear_object (&va_encoder);
- } else {
- ret = TRUE;
- }
-
- return ret;
-}
-
-static gboolean
-gst_va_h264_enc_close (GstVideoEncoder * venc)
+gst_va_h264_enc_start (GstVideoEncoder * venc)
{
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
gst_va_h264_enc_reset_state (self);
- gst_clear_object (&self->encoder);
- gst_clear_object (&self->display);
-
- return TRUE;
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->start (venc);
}
-static GstCaps *
-gst_va_h264_enc_get_caps (GstVideoEncoder * venc, GstCaps * filter)
+static gboolean
+gst_va_h264_enc_stop (GstVideoEncoder * venc)
{
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstCaps *caps = NULL, *tmp;
-
- if (self->encoder)
- caps = gst_va_encoder_get_sinkpad_caps (self->encoder);
-
- if (caps) {
- if (filter) {
- tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (caps);
- caps = tmp;
- }
- } else {
- caps = gst_video_encoder_proxy_getcaps (venc, NULL, filter);
- }
- GST_LOG_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, caps);
- return caps;
-}
-
-static void
-_flush_all_frames (GstVideoEncoder * venc)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
+ gst_va_h264_enc_reset_state (self);
- g_queue_clear_full (&self->reorder_list,
- (GDestroyNotify) gst_video_codec_frame_unref);
- g_queue_clear_full (&self->output_list,
- (GDestroyNotify) gst_video_codec_frame_unref);
- g_queue_clear_full (&self->ref_list,
- (GDestroyNotify) gst_video_codec_frame_unref);
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (venc);
}
static gboolean
{
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- _flush_all_frames (venc);
-
/* begin from an IDR after flush. */
self->gop.cur_frame_index = 0;
self->gop.cur_frame_num = 0;
- return TRUE;
+ return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (venc);
}
-static gboolean
-gst_va_h264_enc_stop (GstVideoEncoder * venc)
+static void
+gst_va_h264_enc_prepare_output (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
{
- GstVaH264Enc *const self = GST_VA_H264_ENC (venc);
-
- _flush_all_frames (venc);
-
- if (!gst_va_encoder_close (self->encoder)) {
- GST_ERROR_OBJECT (self, "Failed to close the VA encoder");
- return FALSE;
- }
-
- if (self->raw_pool)
- gst_buffer_pool_set_active (self->raw_pool, FALSE);
- gst_clear_object (&self->raw_pool);
-
- if (self->input_state)
- gst_video_codec_state_unref (self->input_state);
- self->input_state = NULL;
- if (self->output_state)
- gst_video_codec_state_unref (self->output_state);
- self->output_state = NULL;
+ GstVaH264Enc *self = GST_VA_H264_ENC (base);
+ GstVaH264EncFrame *frame_enc;
- gst_clear_caps (&self->in_caps);
+ frame_enc = _enc_frame (frame);
- return TRUE;
+ frame->pts =
+ base->start_pts + base->frame_duration * frame_enc->total_frame_count;
+ /* The PTS should always be later than the DTS. */
+ frame->dts = base->start_pts + base->frame_duration *
+ ((gint64) base->output_frame_count -
+ (gint64) self->gop.num_reorder_frames);
+ base->output_frame_count++;
+ frame->duration = base->frame_duration;
}
-static gboolean
-_try_import_buffer (GstVaH264Enc * self, GstBuffer * inbuf)
+static gint
+_sort_by_frame_num (gconstpointer a, gconstpointer b, gpointer user_data)
{
- VASurfaceID surface;
-
- /* The VA buffer. */
- surface = gst_va_buffer_get_surface (inbuf);
- if (surface != VA_INVALID_ID)
- return TRUE;
+ GstVaH264EncFrame *frame1 = _enc_frame ((GstVideoCodecFrame *) a);
+ GstVaH264EncFrame *frame2 = _enc_frame ((GstVideoCodecFrame *) b);
- /* TODO: DMA buffer. */
+ g_assert (frame1->frame_num != frame2->frame_num);
- return FALSE;
+ return frame1->frame_num - frame2->frame_num;
}
-static GstBufferPool *
-_get_sinkpad_pool (GstVaH264Enc * self)
+static GstVideoCodecFrame *
+_find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
{
- GstAllocator *allocator;
- GstAllocationParams params = { 0, };
- guint size, usage_hint = 0;
- GArray *surface_formats = NULL;
- GstCaps *caps;
-
- if (self->raw_pool)
- return self->raw_pool;
-
- g_assert (self->in_caps);
- caps = gst_caps_copy (self->in_caps);
- gst_caps_set_features_simple (caps,
- gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
-
- gst_allocation_params_init (¶ms);
-
- size = GST_VIDEO_INFO_SIZE (&self->in_info);
-
- surface_formats = gst_va_encoder_get_surface_formats (self->encoder);
-
- allocator = gst_va_allocator_new (self->display, surface_formats);
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
+ GstVaH264EncFrame *b_vaframe;
+ GstVideoCodecFrame *b_frame;
+ guint i;
- self->raw_pool = gst_va_pool_new_with_config (caps, size, 1, 0,
- usage_hint, GST_VA_FEATURE_AUTO, allocator, ¶ms);
- if (!self->raw_pool) {
- gst_object_unref (allocator);
+ /* We still have more space. */
+ if (g_queue_get_length (&base->ref_list) < self->gop.num_ref_frames)
return NULL;
- }
-
- gst_va_allocator_get_format (allocator, &self->sinkpad_info, NULL, NULL);
- gst_object_unref (allocator);
+ /* Not b_pyramid, sliding window is enough. */
+ if (!self->gop.b_pyramid)
+ return g_queue_peek_head (&base->ref_list);
- gst_buffer_pool_set_active (self->raw_pool, TRUE);
+ /* I/P frame, just using sliding window. */
+ if (frame->type != GST_H264_B_SLICE)
+ return g_queue_peek_head (&base->ref_list);
- return self->raw_pool;
-}
+ /* Choose the B frame with lowest POC. */
+ b_frame = NULL;
+ b_vaframe = NULL;
+ for (i = 0; i < g_queue_get_length (&base->ref_list); i++) {
+ GstVaH264EncFrame *vaf;
+ GstVideoCodecFrame *f;
-static GstFlowReturn
-_import_input_buffer (GstVaH264Enc * self, GstBuffer * inbuf, GstBuffer ** buf)
-{
- GstBuffer *buffer = NULL;
- GstBufferPool *pool;
- GstFlowReturn ret;
- GstVideoFrame in_frame, out_frame;
- gboolean imported, copied;
-
- imported = _try_import_buffer (self, inbuf);
- if (imported) {
- *buf = gst_buffer_ref (inbuf);
- return GST_FLOW_OK;
- }
-
- /* input buffer doesn't come from a vapool, thus it is required to
- * have a pool, grab from it a new buffer and copy the input
- * buffer to the new one */
- if (!(pool = _get_sinkpad_pool (self)))
- return GST_FLOW_ERROR;
-
- ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
- if (ret != GST_FLOW_OK)
- return ret;
-
- GST_LOG_OBJECT (self, "copying input frame");
-
- if (!gst_video_frame_map (&in_frame, &self->in_info, inbuf, GST_MAP_READ))
- goto invalid_buffer;
- if (!gst_video_frame_map (&out_frame, &self->sinkpad_info, buffer,
- GST_MAP_WRITE)) {
- gst_video_frame_unmap (&in_frame);
- goto invalid_buffer;
- }
-
- copied = gst_video_frame_copy (&out_frame, &in_frame);
-
- gst_video_frame_unmap (&out_frame);
- gst_video_frame_unmap (&in_frame);
-
- if (!copied)
- goto invalid_buffer;
-
- /* strictly speaking this is not needed but let's play safe */
- if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS |
- GST_BUFFER_COPY_TIMESTAMPS, 0, -1))
- return GST_FLOW_ERROR;
-
- *buf = buffer;
-
- return GST_FLOW_OK;
-
-invalid_buffer:
- {
- GST_ELEMENT_WARNING (self, CORE, NOT_IMPLEMENTED, (NULL),
- ("invalid video buffer received"));
- if (buffer)
- gst_buffer_unref (buffer);
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-_push_buffer_to_downstream (GstVaH264Enc * self, GstVideoCodecFrame * frame)
-{
- GstVaH264EncFrame *frame_enc;
- GstFlowReturn ret;
- guint coded_size;
- goffset offset;
- GstBuffer *buf;
- VASurfaceID surface;
- VACodedBufferSegment *seg, *seg_list;
-
- frame_enc = _enc_frame (frame);
-
- /* Wait for encoding to finish */
- surface = gst_va_encode_picture_get_raw_surface (frame_enc->picture);
- if (!va_sync_surface (self->display, surface))
- goto error;
-
- seg_list = NULL;
- if (!va_map_buffer (self->display, frame_enc->picture->coded_buffer,
- (gpointer *) & seg_list))
- goto error;
-
- if (!seg_list) {
- GST_WARNING_OBJECT (self, "coded buffer has no segment list");
- goto error;
- }
-
- coded_size = 0;
- for (seg = seg_list; seg; seg = seg->next)
- coded_size += seg->size;
-
- buf = gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (self),
- coded_size);
- if (!buf) {
- GST_ERROR_OBJECT (self, "Failed to allocate output buffer, size %d",
- coded_size);
- goto error;
- }
-
- offset = 0;
- for (seg = seg_list; seg; seg = seg->next) {
- gsize write_size;
-
- write_size = gst_buffer_fill (buf, offset, seg->buf, seg->size);
- if (write_size != seg->size) {
- GST_WARNING_OBJECT (self, "Segment size is %d, but copied %"
- G_GSIZE_FORMAT, seg->size, write_size);
- break;
- }
- offset += seg->size;
- }
-
- va_unmap_buffer (self->display, frame_enc->picture->coded_buffer);
-
- frame->pts =
- self->start_pts + self->frame_duration * frame_enc->total_frame_count;
- /* The PTS should always be later than the DTS. */
- frame->dts = self->start_pts + self->frame_duration *
- ((gint64) self->output_frame_count -
- (gint64) self->gop.num_reorder_frames);
- self->output_frame_count++;
- frame->duration = self->frame_duration;
-
- gst_buffer_replace (&frame->output_buffer, buf);
- gst_clear_buffer (&buf);
-
- GST_LOG_OBJECT (self, "Push to downstream: frame system_frame_number: %d,"
- " pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
- " duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
- frame->system_frame_number, GST_TIME_ARGS (frame->pts),
- GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
- gst_buffer_get_size (frame->output_buffer));
-
- ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
- return ret;
-
-error:
- gst_clear_buffer (&frame->output_buffer);
- gst_clear_buffer (&buf);
- gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
-
- return GST_FLOW_ERROR;
-}
-
-static gboolean
-_reorder_frame (GstVideoEncoder * venc, GstVideoCodecFrame * frame,
- gboolean bump_all, GstVideoCodecFrame ** out_frame)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
-
- g_assert (klass->push_frame);
- if (!klass->push_frame (self, frame, bump_all)) {
- GST_ERROR_OBJECT (self, "Failed to push the input frame"
- " system_frame_number: %d into the reorder list",
- frame->system_frame_number);
-
- *out_frame = NULL;
- return FALSE;
- }
-
- g_assert (klass->pop_frame);
- if (!klass->pop_frame (self, out_frame)) {
- GST_ERROR_OBJECT (self, "Failed to pop the frame from the reorder list");
- *out_frame = NULL;
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gint
-_sort_by_frame_num (gconstpointer a, gconstpointer b, gpointer user_data)
-{
- GstVaH264EncFrame *frame1 = _enc_frame ((GstVideoCodecFrame *) a);
- GstVaH264EncFrame *frame2 = _enc_frame ((GstVideoCodecFrame *) b);
-
- g_assert (frame1->frame_num != frame2->frame_num);
-
- return frame1->frame_num - frame2->frame_num;
-}
-
-static GstVideoCodecFrame *
-_find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
-{
- GstVaH264EncFrame *b_vaframe;
- GstVideoCodecFrame *b_frame;
- guint i;
-
- /* We still have more space. */
- if (g_queue_get_length (&self->ref_list) < self->gop.num_ref_frames)
- return NULL;
-
- /* Not b_pyramid, sliding window is enough. */
- if (!self->gop.b_pyramid)
- return g_queue_peek_head (&self->ref_list);
-
- /* I/P frame, just using sliding window. */
- if (frame->type != GST_H264_B_SLICE)
- return g_queue_peek_head (&self->ref_list);
-
- /* Choose the B frame with lowest POC. */
- b_frame = NULL;
- b_vaframe = NULL;
- for (i = 0; i < g_queue_get_length (&self->ref_list); i++) {
- GstVaH264EncFrame *vaf;
- GstVideoCodecFrame *f;
-
- f = g_queue_peek_nth (&self->ref_list, i);
- vaf = _enc_frame (f);
- if (vaf->type != GST_H264_B_SLICE)
- continue;
+ f = g_queue_peek_nth (&base->ref_list, i);
+ vaf = _enc_frame (f);
+ if (vaf->type != GST_H264_B_SLICE)
+ continue;
if (!b_frame) {
b_frame = f;
/* No B frame as ref. */
if (!b_frame)
- return g_queue_peek_head (&self->ref_list);
+ return g_queue_peek_head (&base->ref_list);
- if (b_frame != g_queue_peek_head (&self->ref_list)) {
+ if (b_frame != g_queue_peek_head (&base->ref_list)) {
b_vaframe = _enc_frame (b_frame);
frame->unused_for_reference_pic_num = b_vaframe->frame_num;
GST_LOG_OBJECT (self, "The frame with POC: %d, pic_num %d will be"
}
static GstFlowReturn
-_encode_frame (GstVideoEncoder * venc, GstVideoCodecFrame * gst_frame)
+gst_va_h264_enc_encode_frame (GstVaBaseEnc * base,
+ GstVideoCodecFrame * gst_frame, gboolean is_last)
{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
+ GstVaH264Enc *self = GST_VA_H264_ENC (base);
GstVaH264EncFrame *frame;
GstVideoCodecFrame *unused_ref = NULL;
frame = _enc_frame (gst_frame);
+ frame->last_frame = is_last;
+
g_assert (frame->picture == NULL);
- frame->picture = gst_va_encode_picture_new (self->encoder,
+ frame->picture = gst_va_encode_picture_new (base->encoder,
gst_frame->input_buffer);
if (!frame->picture) {
- GST_ERROR_OBJECT (venc, "Failed to create the encode picture");
+ GST_ERROR_OBJECT (self, "Failed to create the encode picture");
return GST_FLOW_ERROR;
}
if (frame->is_ref)
unused_ref = _find_unused_reference_frame (self, frame);
- if (!klass->encode_frame (self, gst_frame)) {
- GST_ERROR_OBJECT (venc, "Failed to encode the frame");
+ if (!_encode_one_frame (self, gst_frame)) {
+ GST_ERROR_OBJECT (self, "Failed to encode the frame");
return GST_FLOW_ERROR;
}
- g_queue_push_tail (&self->output_list, gst_video_codec_frame_ref (gst_frame));
+ g_queue_push_tail (&base->output_list, gst_video_codec_frame_ref (gst_frame));
if (frame->is_ref) {
if (unused_ref) {
- if (!g_queue_remove (&self->ref_list, unused_ref))
+ if (!g_queue_remove (&base->ref_list, unused_ref))
g_assert_not_reached ();
gst_video_codec_frame_unref (unused_ref);
}
/* Add it into the reference list. */
- g_queue_push_tail (&self->ref_list, gst_video_codec_frame_ref (gst_frame));
- g_queue_sort (&self->ref_list, _sort_by_frame_num, NULL);
+ g_queue_push_tail (&base->ref_list, gst_video_codec_frame_ref (gst_frame));
+ g_queue_sort (&base->ref_list, _sort_by_frame_num, NULL);
- g_assert (g_queue_get_length (&self->ref_list) <= self->gop.num_ref_frames);
+ g_assert (g_queue_get_length (&base->ref_list) <= self->gop.num_ref_frames);
}
return GST_FLOW_OK;
}
-static GstFlowReturn
-gst_va_h264_enc_handle_frame (GstVideoEncoder * venc,
- GstVideoCodecFrame * frame)
+static gboolean
+gst_va_h264_enc_new_frame (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstFlowReturn ret;
- GstBuffer *in_buf = NULL;
- GstVaH264EncFrame *frame_in = NULL;
- GstVideoCodecFrame *frame_out, *frame_encode = NULL;
-
- GST_LOG_OBJECT (venc,
- "handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
- frame->system_frame_number,
- GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
- GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
-
- ret = _import_input_buffer (self, frame->input_buffer, &in_buf);
- if (ret != GST_FLOW_OK)
- goto error_buffer_invalid;
-
- gst_buffer_replace (&frame->input_buffer, in_buf);
- gst_clear_buffer (&in_buf);
+ GstVaH264EncFrame *frame_in;
frame_in = gst_va_enc_frame_new ();
- frame_in->total_frame_count = self->input_frame_count++;
+ frame_in->total_frame_count = base->input_frame_count++;
gst_video_codec_frame_set_user_data (frame, frame_in, gst_va_enc_frame_free);
- if (!_reorder_frame (venc, frame, FALSE, &frame_encode))
- goto error_reorder;
-
- /* pass it to reorder list and we should not use it again. */
- frame = NULL;
-
- while (frame_encode) {
- ret = _encode_frame (venc, frame_encode);
- if (ret != GST_FLOW_OK)
- goto error_encode;
-
- while (g_queue_get_length (&self->output_list) > 0) {
- frame_out = g_queue_pop_head (&self->output_list);
- gst_video_codec_frame_unref (frame_out);
- ret = _push_buffer_to_downstream (self, frame_out);
- if (ret != GST_FLOW_OK)
- goto error_push_buffer;
- }
-
- frame_encode = NULL;
- if (!_reorder_frame (venc, NULL, FALSE, &frame_encode))
- goto error_reorder;
- }
-
- return ret;
-
-error_buffer_invalid:
- {
- GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
- ("Failed to import the input frame."), (NULL));
- gst_clear_buffer (&in_buf);
- gst_clear_buffer (&frame->output_buffer);
- gst_video_encoder_finish_frame (venc, frame);
- return ret;
- }
-error_reorder:
- {
- GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
- ("Failed to reorder the input frame."), (NULL));
- if (frame) {
- gst_clear_buffer (&frame->output_buffer);
- gst_video_encoder_finish_frame (venc, frame);
- }
- return GST_FLOW_ERROR;
- }
-error_encode:
- {
- GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
- ("Failed to encode the frame."), (NULL));
- gst_clear_buffer (&frame_encode->output_buffer);
- gst_video_encoder_finish_frame (venc, frame_encode);
- return ret;
- }
-error_push_buffer:
- GST_ERROR_OBJECT (self, "Failed to push the buffer");
- return ret;
-}
-
-static GstFlowReturn
-gst_va_h264_enc_drain (GstVideoEncoder * venc)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstFlowReturn ret = GST_FLOW_OK;
- GstVideoCodecFrame *frame_enc = NULL;
-
- GST_DEBUG_OBJECT (self, "Encoder is draining");
-
- /* Kickout all cached frames */
- if (!_reorder_frame (venc, NULL, TRUE, &frame_enc)) {
- ret = GST_FLOW_ERROR;
- goto error_and_purge_all;
- }
-
- while (frame_enc) {
- if (g_queue_is_empty (&self->reorder_list))
- _enc_frame (frame_enc)->last_frame = TRUE;
-
- ret = _encode_frame (venc, frame_enc);
- if (ret != GST_FLOW_OK)
- goto error_and_purge_all;
-
- frame_enc = g_queue_pop_head (&self->output_list);
- gst_video_codec_frame_unref (frame_enc);
- ret = _push_buffer_to_downstream (self, frame_enc);
- frame_enc = NULL;
- if (ret != GST_FLOW_OK)
- goto error_and_purge_all;
-
- frame_enc = NULL;
- if (!_reorder_frame (venc, NULL, TRUE, &frame_enc)) {
- ret = GST_FLOW_ERROR;
- goto error_and_purge_all;
- }
- }
-
- g_assert (g_queue_is_empty (&self->reorder_list));
-
- /* Output all frames. */
- while (!g_queue_is_empty (&self->output_list)) {
- frame_enc = g_queue_pop_head (&self->output_list);
- gst_video_codec_frame_unref (frame_enc);
- ret = _push_buffer_to_downstream (self, frame_enc);
- frame_enc = NULL;
- if (ret != GST_FLOW_OK)
- goto error_and_purge_all;
- }
-
- /* Also clear the reference list. */
- g_queue_clear_full (&self->ref_list,
- (GDestroyNotify) gst_video_codec_frame_unref);
-
- return GST_FLOW_OK;
-
-error_and_purge_all:
- if (frame_enc) {
- gst_clear_buffer (&frame_enc->output_buffer);
- gst_video_encoder_finish_frame (venc, frame_enc);
- }
-
- if (!g_queue_is_empty (&self->output_list)) {
- GST_WARNING_OBJECT (self, "Still %d frame in the output list"
- " after drain", g_queue_get_length (&self->output_list));
- while (!g_queue_is_empty (&self->output_list)) {
- frame_enc = g_queue_pop_head (&self->output_list);
- gst_video_codec_frame_unref (frame_enc);
- gst_clear_buffer (&frame_enc->output_buffer);
- gst_video_encoder_finish_frame (venc, frame_enc);
- }
- }
-
- if (!g_queue_is_empty (&self->reorder_list)) {
- GST_WARNING_OBJECT (self, "Still %d frame in the reorder list"
- " after drain", g_queue_get_length (&self->reorder_list));
- while (!g_queue_is_empty (&self->reorder_list)) {
- frame_enc = g_queue_pop_head (&self->reorder_list);
- gst_video_codec_frame_unref (frame_enc);
- gst_clear_buffer (&frame_enc->output_buffer);
- gst_video_encoder_finish_frame (venc, frame_enc);
- }
- }
-
- /* Also clear the reference list. */
- g_queue_clear_full (&self->ref_list,
- (GDestroyNotify) gst_video_codec_frame_unref);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_va_h264_enc_finish (GstVideoEncoder * venc)
-{
- return gst_va_h264_enc_drain (venc);
-}
-
-static GstAllocator *
-_allocator_from_caps (GstVaH264Enc * self, GstCaps * caps)
-{
- GstAllocator *allocator = NULL;
-
- if (gst_caps_is_dmabuf (caps)) {
- allocator = gst_va_dmabuf_allocator_new (self->display);
- } else {
- GArray *surface_formats =
- gst_va_encoder_get_surface_formats (self->encoder);
- allocator = gst_va_allocator_new (self->display, surface_formats);
- }
-
- return allocator;
-}
-
-static gboolean
-gst_va_h264_enc_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstAllocator *allocator = NULL;
- GstAllocationParams params = { 0, };
- GstBufferPool *pool;
- GstCaps *caps;
- GstVideoInfo info;
- gboolean need_pool = FALSE;
- guint size, usage_hint = 0;
-
- gst_query_parse_allocation (query, &caps, &need_pool);
- if (!caps)
- return FALSE;
-
- if (!gst_video_info_from_caps (&info, caps)) {
- GST_ERROR_OBJECT (self, "Cannot parse caps %" GST_PTR_FORMAT, caps);
- return FALSE;
- }
-
- size = GST_VIDEO_INFO_SIZE (&info);
-
- gst_allocation_params_init (¶ms);
-
- if (!(allocator = _allocator_from_caps (self, caps)))
- return FALSE;
-
- pool = gst_va_pool_new_with_config (caps, size, 1, 0, usage_hint,
- GST_VA_FEATURE_AUTO, allocator, ¶ms);
- if (!pool) {
- gst_object_unref (allocator);
- goto config_failed;
- }
-
- gst_query_add_allocation_param (query, allocator, ¶ms);
- gst_query_add_allocation_pool (query, pool, size, 0, 0);
-
- GST_DEBUG_OBJECT (self,
- "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
- pool, allocator);
-
- gst_object_unref (allocator);
- gst_object_unref (pool);
-
- gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
-
return TRUE;
-
- /* ERRORS */
-config_failed:
- {
- GST_ERROR_OBJECT (self, "failed to set config");
- return FALSE;
- }
-}
-
-static void
-gst_va_h264_enc_set_context (GstElement * element, GstContext * context)
-{
- GstVaDisplay *old_display, *new_display;
- GstVaH264Enc *self = GST_VA_H264_ENC (element);
- GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
- gboolean ret;
-
- old_display = self->display ? gst_object_ref (self->display) : NULL;
-
- ret = gst_va_handle_set_context (element, context, klass->render_device_path,
- &self->display);
-
- new_display = self->display ? gst_object_ref (self->display) : NULL;
-
- if (!ret || (old_display && new_display && old_display != new_display
- && self->encoder)) {
- GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
- ("Can't replace VA display while operating"), (NULL));
- }
-
- gst_clear_object (&old_display);
- gst_clear_object (&new_display);
-
- GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
-}
-
-static gboolean
-gst_va_h264_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
- GstCaps *out_caps;
- guint max_ref_frames;
-
- g_return_val_if_fail (state->caps != NULL, FALSE);
-
- if (self->input_state)
- gst_video_codec_state_unref (self->input_state);
- self->input_state = gst_video_codec_state_ref (state);
-
- gst_caps_replace (&self->in_caps, state->caps);
-
- if (!gst_video_info_from_caps (&self->in_info, self->in_caps))
- return FALSE;
-
- if (gst_va_h264_enc_drain (venc) != GST_FLOW_OK)
- return FALSE;
-
- if (!gst_va_encoder_close (self->encoder)) {
- GST_ERROR_OBJECT (self, "Failed to close the VA encoder");
- return FALSE;
- }
-
- g_assert (klass->reconfig);
- if (!klass->reconfig (self)) {
- GST_ERROR_OBJECT (self, "Reconfig the encoder error");
- return FALSE;
- }
-
- max_ref_frames = self->gop.num_ref_frames + 3 /* scratch frames */ ;
- if (!gst_va_encoder_open (self->encoder, self->profile, self->entrypoint,
- GST_VIDEO_INFO_FORMAT (&self->in_info), self->rt_format,
- self->mb_width * 16, self->mb_height * 16, self->codedbuf_size,
- max_ref_frames, self->rc.rc_ctrl_mode, self->packed_headers)) {
- GST_ERROR_OBJECT (self, "Failed to open the VA encoder.");
- return FALSE;
- }
-
- /* Add some tags */
- {
- GstTagList *tags = gst_tag_list_new_empty ();
- const gchar *encoder_name;
- guint bitrate = 0;
-
- g_object_get (venc, "bitrate", &bitrate, NULL);
- if (bitrate > 0)
- gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
- bitrate, NULL);
-
- if ((encoder_name =
- gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (venc),
- GST_ELEMENT_METADATA_LONGNAME)))
- gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
- encoder_name, NULL);
-
- gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, "H264", NULL);
-
- gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
- gst_tag_list_unref (tags);
- }
-
- out_caps = gst_va_profile_caps (self->profile);
- g_assert (out_caps);
- out_caps = gst_caps_fixate (out_caps);
-
- if (self->level_str)
- gst_caps_set_simple (out_caps, "level", G_TYPE_STRING, self->level_str,
- NULL);
-
- gst_caps_set_simple (out_caps, "width", G_TYPE_INT, self->width,
- "height", G_TYPE_INT, self->height, "alignment", G_TYPE_STRING, "au",
- "stream-format", G_TYPE_STRING, "byte-stream", NULL);
-
- GST_DEBUG_OBJECT (self, "output caps is %" GST_PTR_FORMAT, out_caps);
-
- if (self->output_state)
- gst_video_codec_state_unref (self->output_state);
- self->output_state = gst_video_encoder_set_output_state (venc, out_caps,
- self->input_state);
-
- if (!gst_video_encoder_negotiate (venc)) {
- GST_ERROR_OBJECT (self, "Failed to negotiate with the downstream");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_query_context (GstVaH264Enc * self, GstQuery * query)
-{
- GstVaDisplay *display = NULL;
- gboolean ret;
-
- gst_object_replace ((GstObject **) & display, (GstObject *) self->display);
- ret = gst_va_handle_context_query (GST_ELEMENT_CAST (self), query, display);
- gst_clear_object (&display);
-
- return ret;
-}
-
-static gboolean
-gst_va_h264_enc_src_query (GstVideoEncoder * venc, GstQuery * query)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
- gboolean ret = FALSE;
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_CONTEXT:{
- ret = _query_context (self, query);
- break;
- }
- case GST_QUERY_CAPS:{
- GstCaps *caps = NULL, *tmp, *filter = NULL;
- GstVaEncoder *va_encoder = NULL;
- gboolean fixed_caps;
-
- gst_object_replace ((GstObject **) & va_encoder,
- (GstObject *) self->encoder);
-
- gst_query_parse_caps (query, &filter);
-
- fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_ENCODER_SRC_PAD (venc));
-
- if (!fixed_caps && va_encoder)
- caps = gst_va_encoder_get_srcpad_caps (va_encoder);
-
- gst_clear_object (&va_encoder);
-
- if (caps) {
- if (filter) {
- tmp = gst_caps_intersect_full (filter, caps,
- GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (caps);
- caps = tmp;
- }
-
- GST_LOG_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, caps);
- gst_query_set_caps_result (query, caps);
- gst_caps_unref (caps);
- ret = TRUE;
- break;
- }
- /* else jump to default */
- }
- default:
- ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (venc, query);
- break;
- }
-
- return ret;
-}
-
-static gboolean
-gst_va_h264_enc_sink_query (GstVideoEncoder * venc, GstQuery * query)
-{
- GstVaH264Enc *self = GST_VA_H264_ENC (venc);
-
- if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT)
- return _query_context (self, query);
-
- return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (venc, query);
}
/* *INDENT-OFF* */
{
GstVaH264Enc *self = GST_VA_H264_ENC (instance);
- g_queue_init (&self->reorder_list);
- g_queue_init (&self->ref_list);
- g_queue_init (&self->output_list);
-
/* default values */
self->prop.key_int_max = 0;
self->prop.num_bframes = 0;
const GValue * value, GParamSpec * pspec)
{
GstVaH264Enc *const self = GST_VA_H264_ENC (object);
+ GstVaBaseEnc *base = GST_VA_BASE_ENC (self);
- if (self->encoder && gst_va_encoder_is_open (self->encoder)) {
+ if (base->encoder && gst_va_encoder_is_open (base->encoder)) {
GST_ERROR_OBJECT (object,
"failed to set any property after encoding started");
return;
case PROP_CPB_SIZE:
g_value_set_uint (value, self->prop.cpb_size);
break;
- case PROP_DEVICE_PATH:{
- if (!(self->display && GST_IS_VA_DISPLAY_DRM (self->display))) {
- g_value_set_string (value, NULL);
- } else {
- g_object_get_property (G_OBJECT (self->display), "path", value);
- }
- break;
- }
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
GST_OBJECT_UNLOCK (self);
}
-struct CData
+static void
+gst_va_h264_enc_dispose (GObject * object)
{
- gchar *render_device_path;
- gchar *description;
- GstCaps *sink_caps;
- GstCaps *src_caps;
-};
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
static void
gst_va_h264_enc_class_init (gpointer g_klass, gpointer class_data)
{
GstCaps *src_doc_caps, *sink_doc_caps;
+ GstPadTemplate *sink_pad_templ, *src_pad_templ;
GObjectClass *const object_class = G_OBJECT_CLASS (g_klass);
GstElementClass *const element_class = GST_ELEMENT_CLASS (g_klass);
GstVideoEncoderClass *const venc_class = GST_VIDEO_ENCODER_CLASS (g_klass);
- GstVaH264EncClass *const klass = GST_VA_H264_ENC_CLASS (g_klass);
- GstPadTemplate *sink_pad_templ, *src_pad_templ;
+ GstVaBaseEncClass *va_enc_class = GST_VA_BASE_ENC_CLASS (g_klass);
struct CData *cdata = class_data;
gchar *long_name;
- parent_class = g_type_class_peek_parent (g_klass);
-
- klass->render_device_path = g_strdup (cdata->render_device_path);
- klass->codec = H264;
-
if (cdata->description) {
long_name = g_strdup_printf ("VA-API H.264 Encoder in %s",
cdata->description);
sink_doc_caps = gst_caps_from_string (sink_caps_str);
src_doc_caps = gst_caps_from_string (src_caps_str);
+ parent_class = g_type_class_peek_parent (g_klass);
+
+ va_enc_class->codec = H264;
+ va_enc_class->render_device_path = g_strdup (cdata->render_device_path);
+
sink_pad_templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
cdata->sink_caps);
gst_element_class_add_pad_template (element_class, sink_pad_templ);
gst_pad_template_set_documentation_caps (src_pad_templ, src_doc_caps);
gst_caps_unref (src_doc_caps);
+ object_class->dispose = gst_va_h264_enc_dispose;
object_class->set_property = gst_va_h264_enc_set_property;
object_class->get_property = gst_va_h264_enc_get_property;
- element_class->set_context = GST_DEBUG_FUNCPTR (gst_va_h264_enc_set_context);
- venc_class->open = GST_DEBUG_FUNCPTR (gst_va_h264_enc_open);
venc_class->start = GST_DEBUG_FUNCPTR (gst_va_h264_enc_start);
- venc_class->close = GST_DEBUG_FUNCPTR (gst_va_h264_enc_close);
venc_class->stop = GST_DEBUG_FUNCPTR (gst_va_h264_enc_stop);
- venc_class->handle_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_handle_frame);
- venc_class->finish = GST_DEBUG_FUNCPTR (gst_va_h264_enc_finish);
venc_class->flush = GST_DEBUG_FUNCPTR (gst_va_h264_enc_flush);
- venc_class->set_format = GST_DEBUG_FUNCPTR (gst_va_h264_enc_set_format);
- venc_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h264_enc_get_caps);
- venc_class->propose_allocation =
- GST_DEBUG_FUNCPTR (gst_va_h264_enc_propose_allocation);
- venc_class->src_query = GST_DEBUG_FUNCPTR (gst_va_h264_enc_src_query);
- venc_class->sink_query = GST_DEBUG_FUNCPTR (gst_va_h264_enc_sink_query);
-
- klass->reconfig = GST_DEBUG_FUNCPTR (gst_va_h264_enc_reconfig);
- klass->push_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_push_frame);
- klass->pop_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_pop_frame);
- klass->encode_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_encode_frame);
+
+ va_enc_class->reconfig = GST_DEBUG_FUNCPTR (gst_va_h264_enc_reconfig);
+ va_enc_class->new_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_new_frame);
+ va_enc_class->reorder_frame =
+ GST_DEBUG_FUNCPTR (gst_va_h264_enc_reorder_frame);
+ va_enc_class->encode_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_encode_frame);
+ va_enc_class->prepare_output =
+ GST_DEBUG_FUNCPTR (gst_va_h264_enc_prepare_output);
g_free (long_name);
g_free (cdata->description);
GST_TYPE_VA_ENCODER_RATE_CONTROL, VA_RC_CBR,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
- properties[PROP_DEVICE_PATH] = g_param_spec_string ("device-path",
- "Device Path", "DRM device path", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
gst_type_mark_as_plugin_api (gst_va_encoder_rate_control_get_type (), 0);
_complete_src_caps (GstCaps * srccaps)
{
GstCaps *caps = gst_caps_copy (srccaps);
- GValue val = G_VALUE_INIT;
-
- g_value_init (&val, G_TYPE_STRING);
- g_value_set_string (&val, "au");
- gst_caps_set_value (caps, "alignment", &val);
- g_value_unset (&val);
- g_value_init (&val, G_TYPE_STRING);
- g_value_set_string (&val, "byte-stream");
- gst_caps_set_value (caps, "stream-format", &val);
- g_value_unset (&val);
+ gst_caps_set_simple (caps, "alignment", G_TYPE_STRING, "au", "stream-format",
+ G_TYPE_STRING, "byte-stream", NULL);
return caps;
}
}
g_once (&debug_once, _register_debug_category, NULL);
- type = g_type_register_static (GST_TYPE_VIDEO_ENCODER,
+ type = g_type_register_static (GST_TYPE_VA_BASE_ENC,
type_name, &type_info, 0);
ret = gst_element_register (plugin, feature_name, rank, type);