2 * gstvaapih263encoder.c - H.263 encoder
4 * Copyright (C) 2011 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #include "gstvaapih263encoder.h"
25 #include <gst/gstclock.h>
27 #include "gst/vaapi/gstvaapiobject.h"
28 #include "gst/vaapi/gstvaapiobject_priv.h"
29 #include "gst/vaapi/gstvaapicontext.h"
30 #include "gst/vaapi/gstvaapisurface.h"
31 #include "gst/vaapi/gstvaapivideobuffer.h"
32 #include "gst/vaapi/gstvaapidisplay_priv.h"
34 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h263_encoder_debug);
35 #define GST_CAT_DEFAULT gst_vaapi_h263_encoder_debug
37 struct _GstH263EncoderPrivate {
38 GstVaapiSurface *ref_surface; /* reference buffer*/
39 GstVaapiSurface *recon_surface; /* reconstruct buffer*/
41 VABufferID seq_parameter;
42 VABufferID pic_parameter;
43 VABufferID slice_parameter;
46 G_DEFINE_TYPE(GstH263Encoder, gst_h263_encoder, GST_TYPE_VAAPI_BASE_ENCODER);
48 static EncoderStatus gst_h263_encoder_flush(GstVaapiEncoder* encoder,
49 GstVaapiDisplay *display, GstVaapiContext *context,
53 static void gst_h263_encoder_class_init(GstH263EncoderClass *klass);
54 static void gst_h263_encoder_init(GstH263Encoder *encoder);
55 static void gst_h263_encoder_finalize(GObject *object);
57 static gboolean gst_h263_validate_parameters(GstVaapiBaseEncoder* encoder);
58 static gboolean gst_h263_encoder_release_resource(
59 GstVaapiBaseEncoder* encoder, GstVaapiDisplay *display,
60 GstVaapiContext *context);
61 static EncoderStatus gst_h263_encoder_rendering(GstVaapiBaseEncoder *encoder,
62 GstVaapiDisplay *display, GstVaapiContext *context,
63 GstVaapiSurface *surface, guint frame_index,
64 VABufferID coded_buf, gboolean *is_key);
67 gst_h263_encoder_new(void)
69 return GST_H263_ENCODER(g_object_new(GST_TYPE_H263_ENCODER, NULL));
74 gst_h263_encoder_class_init(GstH263EncoderClass *klass)
76 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
77 GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass);
78 GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
79 g_type_class_add_private(klass, sizeof(GstH263EncoderPrivate));
81 GST_DEBUG_CATEGORY_INIT (gst_vaapi_h263_encoder_debug, "gst_va_h263_encoder", 0,
82 "gst_va_h263_encoder element");
84 object_class->finalize = gst_h263_encoder_finalize;
86 base_class->validate_attributes = gst_h263_validate_parameters;
87 base_class->pre_alloc_resource = NULL;
88 base_class->release_resource = gst_h263_encoder_release_resource;
89 base_class->render_frame = gst_h263_encoder_rendering;
90 base_class->notify_frame = NULL;
91 base_class->copy_coded_frame = NULL;
94 encoder_class->flush = gst_h263_encoder_flush;
96 encoder_class->get_codec_data = NULL;
101 gst_h263_encoder_init(GstH263Encoder *h263_encoder)
103 GstH263EncoderPrivate *h263_prv = GST_H263_ENCODER_GET_PRIVATE(h263_encoder);
104 ENCODER_ASSERT(h263_prv);
107 h263_encoder->bitrate = 0;
108 h263_encoder->intra_period = H263_DEFAULT_INTRA_PERIOD;
109 h263_encoder->init_qp = H263_DEFAULT_INIT_QP;
110 h263_encoder->min_qp = H263_DEFAULT_MIN_QP;
113 h263_prv->ref_surface = NULL;
114 h263_prv->recon_surface = NULL;
116 h263_prv->seq_parameter = VA_INVALID_ID;
117 h263_prv->pic_parameter = VA_INVALID_ID;
118 h263_prv->slice_parameter = VA_INVALID_ID;
122 gst_h263_encoder_finalize(GObject *object)
124 /*free private buffers*/
125 GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
127 if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
128 gst_vaapi_encoder_uninitialize(encoder);
130 G_OBJECT_CLASS(gst_h263_encoder_parent_class)->finalize(object);
134 gst_h263_validate_parameters(GstVaapiBaseEncoder* encoder)
136 GstH263Encoder *h263_encoder = GST_H263_ENCODER(encoder);
137 if (!ENCODER_WIDTH(h263_encoder) || !ENCODER_HEIGHT(h263_encoder) || !ENCODER_FPS(h263_encoder)) {
140 if (!h263_encoder->intra_period) {
141 h263_encoder->intra_period = H263_DEFAULT_INTRA_PERIOD;
143 if (-1 == h263_encoder->init_qp) {
144 h263_encoder->init_qp = H263_DEFAULT_INIT_QP;
146 if (-1 == h263_encoder->min_qp) {
147 h263_encoder->min_qp = H263_DEFAULT_MIN_QP;
150 /* default compress ratio 1: (4*8*1.5) */
151 if (!h263_encoder->bitrate) {
152 h263_encoder->bitrate = ENCODER_WIDTH(h263_encoder)*ENCODER_HEIGHT(h263_encoder)*ENCODER_FPS(h263_encoder)/4;
154 gst_vaapi_base_encoder_set_va_profile(GST_VAAPI_BASE_ENCODER(h263_encoder), VAProfileH263Baseline);
161 h263_release_parameters(GstH263Encoder *h263_encoder, GstVaapiDisplay *display)
163 GstH263EncoderPrivate *h263_prv = GST_H263_ENCODER_GET_PRIVATE(h263_encoder);
164 VADisplay va_dpy = gst_vaapi_display_get_display(display);
165 VAStatus va_status = VA_STATUS_SUCCESS;
167 VAAPI_UNUSED_ARG(va_status);
169 if (VA_INVALID_ID != h263_prv->seq_parameter) {
170 va_status = vaDestroyBuffer(va_dpy, h263_prv->seq_parameter);
171 h263_prv->seq_parameter = VA_INVALID_ID;
173 if (VA_INVALID_ID != h263_prv->pic_parameter) {
174 va_status = vaDestroyBuffer(va_dpy, h263_prv->pic_parameter);
175 h263_prv->pic_parameter = VA_INVALID_ID;
177 if (VA_INVALID_ID != h263_prv->slice_parameter) {
178 va_status = vaDestroyBuffer(va_dpy, h263_prv->slice_parameter);
179 h263_prv->slice_parameter = VA_INVALID_ID;
185 gst_h263_encoder_release_resource(GstVaapiBaseEncoder* encoder,
186 GstVaapiDisplay *display,
187 GstVaapiContext *context)
189 GstH263Encoder *h263_encoder = GST_H263_ENCODER(encoder);
190 GstH263EncoderPrivate *h263_prv = GST_H263_ENCODER_GET_PRIVATE(h263_encoder);
192 h263_release_parameters(h263_encoder, display);
194 /*remove ref_surface*/
195 if (h263_prv->ref_surface) {
197 gst_vaapi_context_put_surface(context, h263_prv->ref_surface);
199 g_object_unref(h263_prv->ref_surface);
201 h263_prv->ref_surface = NULL;
204 /*remove recon_surface*/
205 if (h263_prv->recon_surface) {
207 gst_vaapi_context_put_surface(context, h263_prv->recon_surface);
209 g_object_unref(h263_prv->recon_surface);
211 h263_prv->recon_surface = NULL;
218 gst_h263_encoder_rendering(GstVaapiBaseEncoder *encoder, GstVaapiDisplay *display,
219 GstVaapiContext *context, GstVaapiSurface *surface,
220 guint frame_index, VABufferID coded_buf, gboolean *is_key)
223 GstH263Encoder *h263_encoder = GST_H263_ENCODER(encoder);
224 GstH263EncoderPrivate *h263_prv = GST_H263_ENCODER_GET_PRIVATE(h263_encoder);
225 VADisplay va_dpy = gst_vaapi_display_get_display(display);
226 VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
228 VAStatus va_status = VA_STATUS_SUCCESS;
229 EncoderStatus ret = ENCODER_NO_ERROR;
231 *is_key = (frame_index % h263_encoder->intra_period == 0);
233 /* initialize sequence parameter set, only first time */
234 if (VA_INVALID_ID == h263_prv->seq_parameter) { /*only the first time*/
235 VAEncSequenceParameterBufferH263 seq_h263 = {0};
237 seq_h263.intra_period = h263_encoder->intra_period;
238 seq_h263.bits_per_second = h263_encoder->bitrate;
239 seq_h263.frame_rate = ENCODER_FPS(h263_encoder);
240 seq_h263.initial_qp = h263_encoder->init_qp;
241 seq_h263.min_qp = h263_encoder->min_qp;
243 va_status = vaCreateBuffer(va_dpy, context_id,
244 VAEncSequenceParameterBufferType,
245 sizeof(seq_h263), 1, &seq_h263, &h263_prv->seq_parameter);
246 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_ENC_RES_ERR, "h263 alloc seq-buffer failed.");
247 va_status = vaRenderPicture(va_dpy, context_id, &h263_prv->seq_parameter, 1);
248 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "h263 vaRenderPicture seq-parameters failed.");
251 /* set reference and reconstructed surfaces */
252 if (!h263_prv->ref_surface) {
253 h263_prv->ref_surface = gst_vaapi_context_get_surface(context);
254 ENCODER_CHECK_STATUS(h263_prv->ref_surface, ENCODER_SURFACE_ERR, "h263 reference surface, h263_pop_free_surface failed.");
256 if (!h263_prv->recon_surface) {
257 h263_prv->recon_surface = gst_vaapi_context_get_surface(context);
258 ENCODER_CHECK_STATUS(h263_prv->recon_surface, ENCODER_SURFACE_ERR, "h263 reconstructed surface, h263_pop_free_surface failed.");
261 /* initialize picture, every time, every frame */
262 VAEncPictureParameterBufferH263 pic_h263 = {0};
263 pic_h263.reference_picture = GST_VAAPI_OBJECT_ID(h263_prv->ref_surface);
264 pic_h263.reconstructed_picture = GST_VAAPI_OBJECT_ID(h263_prv->recon_surface);
265 pic_h263.coded_buf = coded_buf;
266 pic_h263.picture_width = ENCODER_WIDTH(h263_encoder);
267 pic_h263.picture_height = ENCODER_HEIGHT(h263_encoder);
268 pic_h263.picture_type = (*is_key) ? VAEncPictureTypeIntra : VAEncPictureTypePredictive;
269 if (VA_INVALID_ID != h263_prv->pic_parameter) { /* destroy first*/
270 va_status = vaDestroyBuffer(va_dpy, h263_prv->pic_parameter);
271 h263_prv->pic_parameter = VA_INVALID_ID;
274 va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
275 sizeof(pic_h263), 1, &pic_h263, &h263_prv->pic_parameter);
276 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
277 ENCODER_ENC_RES_ERR, "h263 creating pic-param buffer failed.");
278 va_status = vaRenderPicture(va_dpy, context_id, &h263_prv->pic_parameter, 1);
279 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
280 ENCODER_PICTURE_ERR, "h263 rendering pic-param buffer failed.");
281 /*initialize slice parameters, only ONE slice for h263*/
282 VAEncSliceParameterBuffer slice_h263 = { 0 };
283 slice_h263.start_row_number = 0;
284 slice_h263.slice_height = (ENCODER_HEIGHT(h263_encoder)+15)/16; /*MB?*/
285 slice_h263.slice_flags.bits.is_intra = *is_key;
286 slice_h263.slice_flags.bits.disable_deblocking_filter_idc = 0;
287 if (VA_INVALID_ID != h263_prv->slice_parameter) {
288 vaDestroyBuffer(va_dpy, h263_prv->slice_parameter);
289 h263_prv->slice_parameter = VA_INVALID_ID;
292 va_status = vaCreateBuffer(va_dpy,
294 VAEncSliceParameterBufferType,
298 &h263_prv->slice_parameter);
299 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
301 "h263 creating slice-parameters buffer failed.");
303 va_status = vaRenderPicture(va_dpy, context_id, &h263_prv->slice_parameter, 1);
304 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
306 "h263 rendering slice-parameters buffer failed.");
308 /*swap ref_surface and recon_surface */
309 GstVaapiSurface *swap = h263_prv->ref_surface;
310 h263_prv->ref_surface = h263_prv->recon_surface;
311 h263_prv->recon_surface = swap;