1 /* GStreamer
2 * Copyright (c) 2011, Texas Instruments Incorporated
3 * Copyright (c) 2011, Collabora Ltd.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Alessandro Decina <alessandro.decina@collabora.com>
21 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include "gstducati.h"
28 #include "gstducatividenc.h"
29 #include <ti/sdo/codecs/mpeg4enc/impeg4enc.h>
31 #include <string.h>
33 #include <math.h>
35 #define GST_CAT_DEFAULT gst_ducati_debug
37 #define DEFAULT_BITRATE 2048
38 #define DEFAULT_RATE_PRESET GST_DUCATI_VIDENC_RATE_PRESET_STORAGE
40 #define GST_TYPE_DUCATI_VIDENC_RATE_PRESET (gst_ducati_videnc_rate_preset_get_type ())
43 enum
44 {
45 LAST_SIGNAL
46 };
48 enum
49 {
50 PROP_0,
51 PROP_BITRATE,
52 PROP_RATE_PRESET
53 };
55 static void gst_ducati_videnc_set_property (GObject * object, guint prop_id,
56 const GValue * value, GParamSpec * pspec);
57 static void gst_ducati_videnc_get_property (GObject * object, guint prop_id,
58 GValue * value, GParamSpec * pspec);
60 static gboolean gst_ducati_videnc_set_format (GstBaseVideoEncoder *
61 base_video_encoder, GstVideoState * state);
62 static gboolean gst_ducati_videnc_start (GstBaseVideoEncoder *
63 base_video_encoder);
64 static gboolean gst_ducati_videnc_stop (GstBaseVideoEncoder *
65 base_video_encoder);
66 static GstFlowReturn gst_ducati_videnc_finish (GstBaseVideoEncoder *
67 base_video_encoder);
68 static GstFlowReturn gst_ducati_videnc_handle_frame (GstBaseVideoEncoder *
69 base_video_encoder, GstVideoFrame * frame);
70 static gboolean gst_ducati_videnc_allocate_params_default (GstDucatiVidEnc *
71 self, gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz,
72 gint outargs_sz);
73 static gboolean gst_ducati_videnc_configure_default (GstDucatiVidEnc * self);
76 GST_BOILERPLATE (GstDucatiVidEnc, gst_ducati_videnc, GstBaseVideoEncoder,
77 GST_TYPE_BASE_VIDEO_ENCODER);
80 /* the values for the following enums are taken from the codec */
82 enum
83 {
84 GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY = 1, /**< CBR rate control for video conferencing. */
85 GST_DUCATI_VIDENC_RATE_PRESET_STORAGE = 2, /**< VBR rate control for local storage (DVD)
86 * recording.
87 */
88 GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS = 3, /**< Two pass rate control for non real time
89 * applications.
90 */
91 GST_DUCATI_VIDENC_RATE_PRESET_NONE = 4, /**< No configurable video rate control
92 * mechanism.
93 */
94 GST_DUCATI_VIDENC_RATE_PRESET_USER_DEFINED = 5,/**< User defined configuration using extended
95 * parameters.
96 */
97 };
99 static GType
100 gst_ducati_videnc_rate_preset_get_type (void)
101 {
102 static GType type = 0;
104 if (!type) {
105 static const GEnumValue vals[] = {
106 {GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY, "Low Delay", "low-delay"},
107 {GST_DUCATI_VIDENC_RATE_PRESET_STORAGE, "Storage", "storage"},
108 {GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS, "Two-Pass", "two-pass"},
109 {0, NULL, NULL},
110 };
112 type = g_enum_register_static ("GstDucatiVidEncRatePreset", vals);
113 }
115 return type;
116 }
118 static void
119 gst_ducati_videnc_base_init (gpointer g_class)
120 {
121 }
123 static void
124 gst_ducati_videnc_class_init (GstDucatiVidEncClass * klass)
125 {
126 GObjectClass *gobject_class;
127 GstBaseVideoEncoderClass *basevideoencoder_class;
129 gobject_class = G_OBJECT_CLASS (klass);
130 basevideoencoder_class = GST_BASE_VIDEO_ENCODER_CLASS (klass);
132 gobject_class->set_property = gst_ducati_videnc_set_property;
133 gobject_class->get_property = gst_ducati_videnc_get_property;
135 basevideoencoder_class->set_format =
136 GST_DEBUG_FUNCPTR (gst_ducati_videnc_set_format);
137 basevideoencoder_class->start = GST_DEBUG_FUNCPTR (gst_ducati_videnc_start);
138 basevideoencoder_class->stop = GST_DEBUG_FUNCPTR (gst_ducati_videnc_stop);
139 basevideoencoder_class->finish = GST_DEBUG_FUNCPTR (gst_ducati_videnc_finish);
140 basevideoencoder_class->handle_frame =
141 GST_DEBUG_FUNCPTR (gst_ducati_videnc_handle_frame);
143 klass->allocate_params = gst_ducati_videnc_allocate_params_default;
144 klass->configure = gst_ducati_videnc_configure_default;
146 g_object_class_install_property (gobject_class, PROP_BITRATE,
147 g_param_spec_int ("bitrate", "Bitrate", "Bitrate in kbit/sec", -1,
148 100 * 1024, DEFAULT_BITRATE, G_PARAM_READWRITE));
150 g_object_class_install_property (gobject_class, PROP_RATE_PRESET,
151 g_param_spec_enum ("rate-preset", "H.264 Rate Control",
152 "H.264 Rate Control",
153 GST_TYPE_DUCATI_VIDENC_RATE_PRESET, DEFAULT_RATE_PRESET,
154 G_PARAM_READWRITE));
155 }
157 static void
158 gst_ducati_videnc_init (GstDucatiVidEnc * self, GstDucatiVidEncClass * klass)
159 {
160 GST_DEBUG ("gst_ducati_videnc_init");
162 self->engine = NULL;
163 self->codec = NULL;
164 self->params = NULL;
165 self->status = NULL;
166 self->inBufs = NULL;
167 self->outBufs = NULL;
168 self->inArgs = NULL;
169 self->outArgs = NULL;
170 self->input_pool = NULL;
171 self->output_pool = NULL;
173 self->bitrate = DEFAULT_BITRATE * 1000;
174 self->rate_preset = DEFAULT_RATE_PRESET;
175 }
177 static gboolean
178 gst_ducati_videnc_set_format (GstBaseVideoEncoder * base_video_encoder,
179 GstVideoState * state)
180 {
181 GstDucatiVidEnc *self = GST_DUCATIVIDENC (base_video_encoder);
183 self->configure = TRUE;
185 return TRUE;
186 }
188 static void
189 gst_ducati_videnc_set_property (GObject * object, guint prop_id,
190 const GValue * value, GParamSpec * pspec)
191 {
192 GstDucatiVidEnc *self = GST_DUCATIVIDENC (object);
194 g_return_if_fail (GST_IS_DUCATIVIDENC (object));
195 self = GST_DUCATIVIDENC (object);
197 switch (prop_id) {
198 case PROP_BITRATE:
199 self->bitrate = g_value_get_int (value) * 1000;
200 break;
201 case PROP_RATE_PRESET:
202 self->rate_preset = g_value_get_enum (value);
203 break;
204 default:
205 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206 }
207 }
209 static void
210 gst_ducati_videnc_get_property (GObject * object, guint prop_id,
211 GValue * value, GParamSpec * pspec)
212 {
213 GstDucatiVidEnc *self = GST_DUCATIVIDENC (object);
215 g_return_if_fail (GST_IS_DUCATIVIDENC (object));
216 self = GST_DUCATIVIDENC (object);
218 switch (prop_id) {
219 case PROP_BITRATE:
220 g_value_set_int (value, self->bitrate / 1000);
221 break;
222 case PROP_RATE_PRESET:
223 g_value_set_enum (value, self->rate_preset);
224 break;
225 default:
226 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
227 }
228 }
230 static gboolean
231 gst_ducati_videnc_configure (GstDucatiVidEnc * self)
232 {
233 int err;
234 int i;
235 int max_out_size = 0;
236 const GstVideoState *state;
238 state = gst_base_video_encoder_get_state (GST_BASE_VIDEO_ENCODER (self));
240 if (!GST_DUCATIVIDENC_GET_CLASS (self)->configure (self))
241 return FALSE;
243 if (self->codec == NULL) {
244 const gchar *codec_name;
246 codec_name = GST_DUCATIVIDENC_GET_CLASS (self)->codec_name;
247 self->codec = VIDENC2_create (self->engine,
248 (String) codec_name, self->params);
249 if (self->codec == NULL) {
250 GST_ERROR_OBJECT (self, "couldn't create codec");
251 return FALSE;
252 }
253 }
255 err = VIDENC2_control (self->codec,
256 XDM_SETPARAMS, self->dynParams, self->status);
257 if (err) {
258 GST_ERROR_OBJECT (self, "XDM_SETPARAMS err=%d, extendedError=%08x",
259 err, self->status->extendedError);
261 return FALSE;
262 }
264 err = VIDENC2_control (self->codec,
265 XDM_GETBUFINFO, self->dynParams, self->status);
266 if (err) {
267 GST_ERROR_OBJECT (self, "XDM_GETBUFINFO err=%d, extendedError=%08x",
268 err, self->status->extendedError);
270 return FALSE;
271 }
273 self->outBufs->numBufs = self->status->bufInfo.minNumOutBufs;
274 for (i = 0; i < self->outBufs->numBufs; i++) {
275 int size = self->status->bufInfo.minOutBufSize[i].bytes;
276 if (size > max_out_size)
277 max_out_size = size;
278 }
280 g_assert (self->input_pool == NULL);
281 self->input_pool =
282 gst_ducati_bufferpool_new (GST_ELEMENT (self), NULL,
283 state->bytes_per_picture);
285 g_assert (self->output_pool == NULL);
286 self->output_pool =
287 gst_ducati_bufferpool_new (GST_ELEMENT (self), NULL, max_out_size);
289 GST_INFO_OBJECT (self, "configured");
291 self->configure = FALSE;
293 return TRUE;
294 }
296 static gboolean
297 gst_ducati_videnc_configure_default (GstDucatiVidEnc * self)
298 {
299 VIDENC2_DynamicParams *dynParams;
300 const GstVideoState *state;
301 int i;
303 state = gst_base_video_encoder_get_state (GST_BASE_VIDEO_ENCODER (self));
305 self->params = (VIDENC2_Params *) self->params;
306 self->params->encodingPreset = 0x03;
307 self->params->rateControlPreset = self->rate_preset;
308 self->params->maxHeight = state->height;
309 self->params->maxWidth = state->width;
310 self->params->dataEndianness = XDM_BYTE;
311 self->params->maxInterFrameInterval = 1;
312 self->params->maxBitRate = -1;
313 self->params->minBitRate = 0;
314 self->params->inputChromaFormat = XDM_YUV_420SP;
315 self->params->inputContentType = IVIDEO_PROGRESSIVE;
316 self->params->operatingMode = IVIDEO_ENCODE_ONLY;
317 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
318 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
319 self->params->numInputDataUnits = 1;
320 self->params->numOutputDataUnits = 1;
321 for (i = 0; i < IVIDEO_MAX_NUM_METADATA_PLANES; i++) {
322 self->params->metadataType[i] = IVIDEO_METADATAPLANE_NONE;
323 }
325 dynParams = self->dynParams;
326 dynParams = (VIDENC2_DynamicParams *) self->dynParams;
328 dynParams->refFrameRate =
329 gst_util_uint64_scale (1000, state->fps_n, state->fps_d);
330 dynParams->targetFrameRate = dynParams->refFrameRate;
331 dynParams->inputWidth = state->width;
332 dynParams->inputHeight = state->height;
333 dynParams->targetBitRate = self->bitrate;
334 dynParams->intraFrameInterval = 15;
335 dynParams->captureWidth = dynParams->inputWidth;
336 dynParams->forceFrame = IVIDEO_NA_FRAME;
337 dynParams->interFrameInterval = 1;
338 dynParams->mvAccuracy = IVIDENC2_MOTIONVECTOR_QUARTERPEL;
339 dynParams->sampleAspectRatioHeight = 1;
340 dynParams->sampleAspectRatioWidth = 1;
341 dynParams->generateHeader = XDM_ENCODE_AU;
342 dynParams->ignoreOutbufSizeFlag = 1;
343 dynParams->lateAcquireArg = -1;
345 self->inBufs->chromaFormat = XDM_YUV_420SP;
346 self->inBufs->numPlanes = 2;
348 return TRUE;
349 }
351 static gboolean
352 gst_ducati_videnc_open_engine (GstDucatiVidEnc * self)
353 {
354 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, NULL);
355 if (self->engine == NULL) {
356 GST_ERROR_OBJECT (self, "couldn't open engine");
357 return FALSE;
358 }
360 return TRUE;
361 }
363 static gboolean
364 gst_ducati_videnc_allocate_params (GstDucatiVidEnc * self)
365 {
366 return GST_DUCATIVIDENC_GET_CLASS (self)->allocate_params (self,
367 sizeof (IVIDENC2_Params), sizeof (IVIDENC2_DynamicParams),
368 sizeof (IVIDENC2_Status), sizeof (IVIDENC2_InArgs),
369 sizeof (IVIDENC2_OutArgs));
370 }
372 static gboolean
373 gst_ducati_videnc_allocate_params_default (GstDucatiVidEnc * self, gint params_sz,
374 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
375 {
376 self->params = dce_alloc (params_sz);
377 memset (self->params, 0, params_sz);
378 self->params->size = params_sz;
380 self->dynParams = dce_alloc (dynparams_sz);
381 memset (self->dynParams, 0, dynparams_sz);
382 self->dynParams->size = dynparams_sz;
384 self->status = dce_alloc (status_sz);
385 memset (self->status, 0, status_sz);
386 self->status->size = status_sz;
388 self->inBufs = dce_alloc (sizeof (IVIDEO2_BufDesc));
389 memset (self->inBufs, 0, sizeof (IVIDEO2_BufDesc));
391 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
392 memset (self->outBufs, 0, sizeof (XDM2_BufDesc));
394 self->inArgs = dce_alloc (inargs_sz);
395 memset (self->inArgs, 0, inargs_sz);
396 self->inArgs->size = inargs_sz;
398 self->outArgs = dce_alloc (outargs_sz);
399 memset (self->outArgs, 0, outargs_sz);
400 self->outArgs->size = outargs_sz;
402 GST_INFO_OBJECT (self, "started");
404 return TRUE;
405 }
407 static gboolean
408 gst_ducati_videnc_free_params (GstDucatiVidEnc * self)
409 {
410 if (self->params) {
411 dce_free (self->params);
412 self->params = NULL;
413 }
415 if (self->dynParams) {
416 dce_free (self->dynParams);
417 self->dynParams = NULL;
418 }
420 if (self->inArgs) {
421 dce_free (self->inArgs);
422 self->inArgs = NULL;
423 }
425 if (self->outArgs) {
426 dce_free (self->outArgs);
427 self->outArgs = NULL;
428 }
430 if (self->status) {
431 dce_free (self->status);
432 self->status = NULL;
433 }
435 if (self->inBufs) {
436 dce_free (self->inBufs);
437 self->inBufs = NULL;
438 }
440 if (self->outBufs) {
441 dce_free (self->outBufs);
442 self->inBufs = NULL;
443 }
445 if (self->codec) {
446 VIDENC2_delete (self->codec);
447 self->codec = NULL;
448 }
450 return TRUE;
451 }
453 static void
454 gst_ducati_videnc_close_engine (GstDucatiVidEnc * self)
455 {
456 if (self->engine) {
457 Engine_close (self->engine);
458 self->engine = NULL;
459 }
460 }
463 static gboolean
464 gst_ducati_videnc_start (GstBaseVideoEncoder * base_video_encoder)
465 {
466 GstDucatiVidEnc *self = GST_DUCATIVIDENC (base_video_encoder);
468 self->configure = TRUE;
470 if (!gst_ducati_videnc_open_engine (self))
471 goto fail;
473 if (!gst_ducati_videnc_allocate_params (self))
474 goto fail;
476 return TRUE;
478 fail:
479 gst_ducati_videnc_free_params (self);
480 gst_ducati_videnc_close_engine (self);
481 return FALSE;
482 }
484 static gboolean
485 gst_ducati_videnc_stop (GstBaseVideoEncoder * base_video_encoder)
486 {
487 GstDucatiVidEnc *self = GST_DUCATIVIDENC (base_video_encoder);
489 gst_ducati_videnc_free_params (self);
490 gst_ducati_videnc_close_engine (self);
492 if (self->input_pool) {
493 gst_ducati_bufferpool_destroy (self->input_pool);
494 self->input_pool = NULL;
495 }
497 if (self->output_pool) {
498 gst_ducati_bufferpool_destroy (self->output_pool);
499 self->output_pool = NULL;
500 }
502 return TRUE;
503 }
505 static GstFlowReturn
506 gst_ducati_videnc_finish (GstBaseVideoEncoder * base_video_encoder)
507 {
508 GstDucatiVidEnc *self = GST_DUCATIVIDENC (base_video_encoder);
510 GST_DEBUG_OBJECT (self, "finish");
512 return GST_FLOW_OK;
513 }
515 static GstFlowReturn
516 gst_ducati_videnc_handle_frame (GstBaseVideoEncoder * base_video_encoder,
517 GstVideoFrame * frame)
518 {
519 GstDucatiVidEnc *self = GST_DUCATIVIDENC (base_video_encoder);
520 GstBuffer *inbuf, *outbuf;
521 guint8 *y_vaddr, *uv_vaddr;
522 SSPtr y_paddr, uv_paddr, outbuf_paddr;
523 XDAS_Int32 err;
524 const GstVideoState *state;
525 int i;
527 state = gst_base_video_encoder_get_state (base_video_encoder);
529 if (G_UNLIKELY (self->configure)) {
530 if (!gst_ducati_videnc_configure (self)) {
531 GST_DEBUG_OBJECT (self, "configure failed");
532 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), (NULL));
534 return GST_FLOW_ERROR;
535 }
536 }
538 inbuf = GST_BUFFER (gst_ducati_bufferpool_get (self->input_pool, NULL));
539 memcpy (GST_BUFFER_DATA (inbuf), GST_BUFFER_DATA (frame->sink_buffer),
540 GST_BUFFER_SIZE (frame->sink_buffer));
541 outbuf = GST_BUFFER (gst_ducati_bufferpool_get (self->output_pool, NULL));
543 y_vaddr = GST_BUFFER_DATA (inbuf);
544 uv_vaddr = y_vaddr + gst_video_format_get_component_offset (state->format,
545 1, state->width, state->height);
547 y_paddr = TilerMem_VirtToPhys (y_vaddr);
548 uv_paddr = TilerMem_VirtToPhys (uv_vaddr);
550 outbuf_paddr = TilerMem_VirtToPhys (GST_BUFFER_DATA (outbuf));
552 self->inBufs->planeDesc[0].buf = (XDAS_Int8 *) y_paddr;
553 self->inBufs->planeDesc[0].memType = XDM_MEMTYPE_TILEDPAGE;
554 self->inBufs->planeDesc[0].bufSize.tileMem.width = state->width;
555 self->inBufs->planeDesc[0].bufSize.tileMem.height = state->height;
556 self->inBufs->planeDesc[1].buf = (XDAS_Int8 *) uv_paddr;
557 self->inBufs->planeDesc[1].memType = XDM_MEMTYPE_TILEDPAGE;
558 self->inBufs->planeDesc[1].bufSize.tileMem.width = state->width;
559 self->inBufs->planeDesc[1].bufSize.tileMem.height = state->height / 2;
560 self->inBufs->imagePitch[0] = state->width;
561 self->inBufs->imagePitch[1] = state->width;
562 self->inBufs->imageRegion.bottomRight.x = state->width;
563 self->inBufs->activeFrameRegion.bottomRight.x = state->width;
564 self->inBufs->imageRegion.bottomRight.y = state->height;
565 self->inBufs->activeFrameRegion.bottomRight.y = state->height;
566 self->inBufs->topFieldFirstFlag = TRUE;
568 self->outBufs->numBufs = 1;
569 self->outBufs->descs[0].buf = (XDAS_Int8 *) outbuf_paddr;
570 self->outBufs->descs[0].bufSize.bytes = GST_BUFFER_SIZE (outbuf);
572 self->inArgs->inputID = GPOINTER_TO_INT (inbuf);
574 err = VIDENC2_process (self->codec, self->inBufs, self->outBufs,
575 self->inArgs, self->outArgs);
576 if (err) {
577 GST_WARNING_OBJECT (self, "process failed: err=%d, extendedError=%08x",
578 err, self->status->extendedError);
580 err = VIDENC2_control (self->codec,
581 XDM_GETSTATUS, (IVIDENC2_DynamicParams *) self->dynParams,
582 self->status);
584 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
585 err, self->status->extendedError);
587 return GST_FLOW_ERROR;
588 }
590 frame->src_buffer = gst_buffer_new_and_alloc (self->outArgs->bytesGenerated);
591 memcpy (GST_BUFFER_DATA (frame->src_buffer),
592 GST_BUFFER_DATA (outbuf), self->outArgs->bytesGenerated);
594 gst_buffer_unref (outbuf);
596 for (i = 0; self->outArgs->freeBufID[i]; i++) {
597 GstBuffer *buf = (GstBuffer *) self->outArgs->freeBufID[i];
599 GST_LOG_OBJECT (self, "free buffer: %p", buf);
600 gst_buffer_unref (buf);
601 }
603 return gst_base_video_encoder_finish_frame (base_video_encoder, frame);
604 }