Use buffer qdata for the private info of Ducati instead of GstMeta
[gstreamer-omap:gst-ducati.git] / src / gstducatividenc.c
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  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "gstducati.h"
28 #include "gstducatipriv.h"
29 #include "gstducatividenc.h"
30
31 #include <math.h>
32 #include <string.h>
33 #include <sys/drm/gstdrmmeta.h>
34 #include <sys/dma/gstdmabufmeta.h>
35
36
37 #define GST_CAT_DEFAULT gst_ducati_debug
38
39 #define DEFAULT_BITRATE 2048
40 #define DEFAULT_RATE_PRESET GST_DUCATI_VIDENC_RATE_PRESET_STORAGE
41 #define DEFAULT_INTRA_INTERVAL 16
42
43 #define GST_TYPE_DUCATI_VIDENC_RATE_PRESET (gst_ducati_videnc_rate_preset_get_type ())
44
45
46 enum
47 {
48   LAST_SIGNAL
49 };
50
51 enum
52 {
53   PROP_0,
54   PROP_BITRATE,
55   PROP_RATE_PRESET,
56   PROP_INTRA_INTERVAL
57 };
58
59 #define gst_ducati_videnc_parent_class parent_class
60 G_DEFINE_TYPE (GstDucatiVidEnc, gst_ducati_videnc, GST_TYPE_VIDEO_ENCODER);
61
62 /* the values for the following enums are taken from the codec */
63 enum
64 {
65   GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY = IVIDEO_LOW_DELAY,   /**< CBR rate control for video conferencing. */
66   GST_DUCATI_VIDENC_RATE_PRESET_STORAGE = IVIDEO_STORAGE,  /**< VBR rate control for local storage (DVD)
67                            *   recording.
68                            */
69   GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS = IVIDEO_TWOPASS,  /**< Two pass rate control for non real time
70                            *   applications.
71                            */
72   GST_DUCATI_VIDENC_RATE_PRESET_NONE = IVIDEO_NONE,        /**< No configurable video rate control
73                             *  mechanism.
74                             */
75   GST_DUCATI_VIDENC_RATE_PRESET_USER_DEFINED = IVIDEO_USER_DEFINED,/**< User defined configuration using extended
76                            *   parameters.
77                            */
78 };
79
80 static GType
81 gst_ducati_videnc_rate_preset_get_type (void)
82 {
83   static GType type = 0;
84
85   if (!type) {
86     static const GEnumValue vals[] = {
87       {GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY, "Low Delay", "low-delay"},
88       {GST_DUCATI_VIDENC_RATE_PRESET_STORAGE, "Storage", "storage"},
89       {GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS, "Two-Pass", "two-pass"},
90       {GST_DUCATI_VIDENC_RATE_PRESET_NONE, "None", "none"},
91       {GST_DUCATI_VIDENC_RATE_PRESET_USER_DEFINED, "User defined",
92           "user-defined"},
93       {0, NULL, NULL},
94     };
95
96     type = g_enum_register_static ("GstDucatiVidEncRatePreset", vals);
97   }
98
99   return type;
100 }
101
102 static void
103 apply_cropping (GstDucatiVidEnc * self, GstVideoCodecFrame * frame)
104 {
105   GstVideoCropMeta *crop;
106
107   crop = gst_buffer_get_video_crop_meta (frame->input_buffer);
108
109   if (crop) {
110     /* setting imageRegion doesn't seem to be strictly needed if activeFrameRegion
111      * is set but we set it anyway...  */
112     self->inBufs->activeFrameRegion.topLeft.x =
113         self->inBufs->imageRegion.topLeft.x = crop->x;
114     self->inBufs->activeFrameRegion.topLeft.y =
115         self->inBufs->imageRegion.topLeft.y = crop->y;
116     self->inBufs->activeFrameRegion.bottomRight.x =
117         self->inBufs->imageRegion.bottomRight.x = crop->x + crop->width;
118     self->inBufs->activeFrameRegion.bottomRight.y =
119         self->inBufs->imageRegion.bottomRight.y = crop->y + crop->height;
120
121     return;
122   }
123
124   self->inBufs->activeFrameRegion.topLeft.x =
125       self->inBufs->imageRegion.topLeft.x = 0;
126   self->inBufs->activeFrameRegion.topLeft.y =
127       self->inBufs->imageRegion.topLeft.y = 0;
128   self->inBufs->activeFrameRegion.bottomRight.x =
129       self->inBufs->imageRegion.bottomRight.x = self->input_state->info.width;
130   self->inBufs->activeFrameRegion.bottomRight.y =
131       self->inBufs->imageRegion.bottomRight.y = self->input_state->info.height;
132 }
133
134 static gboolean
135 ducati_videnc_set_format (GstVideoEncoder * video_encoder,
136     GstVideoCodecState * input_state)
137 {
138   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
139
140   /* Store input input_state */
141   if (self->input_state)
142     gst_video_codec_state_unref (self->input_state);
143   self->input_state = gst_video_codec_state_ref (input_state);
144
145   self->configure = TRUE;
146
147   return TRUE;
148 }
149
150 static void
151 gst_ducati_videnc_finalize (GObject * object)
152 {
153   GstDucatiVidEnc *self;
154
155   g_return_if_fail (GST_IS_DUCATIVIDENC (object));
156   self = GST_DUCATIVIDENC (object);
157
158   if (self->input_state)
159     gst_video_codec_state_unref (self->input_state);
160   if (self->output_state)
161     gst_video_codec_state_unref (self->output_state);
162 }
163
164 static void
165 gst_ducati_videnc_set_property (GObject * object, guint prop_id,
166     const GValue * value, GParamSpec * pspec)
167 {
168   GstDucatiVidEnc *self;
169
170   g_return_if_fail (GST_IS_DUCATIVIDENC (object));
171   self = GST_DUCATIVIDENC (object);
172
173   switch (prop_id) {
174     case PROP_BITRATE:
175       self->bitrate = g_value_get_int (value) * 1000;
176       break;
177     case PROP_RATE_PRESET:
178       self->rate_preset = g_value_get_enum (value);
179       break;
180     case PROP_INTRA_INTERVAL:
181       self->intra_interval = g_value_get_int (value);
182       break;
183     default:
184       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185   }
186 }
187
188 static void
189 gst_ducati_videnc_get_property (GObject * object, guint prop_id,
190     GValue * value, GParamSpec * pspec)
191 {
192   GstDucatiVidEnc *self;
193
194   g_return_if_fail (GST_IS_DUCATIVIDENC (object));
195   self = GST_DUCATIVIDENC (object);
196
197   switch (prop_id) {
198     case PROP_BITRATE:
199       g_value_set_int (value, self->bitrate / 1000);
200       break;
201     case PROP_RATE_PRESET:
202       g_value_set_enum (value, self->rate_preset);
203       break;
204     case PROP_INTRA_INTERVAL:
205       g_value_set_int (value, self->intra_interval);
206       break;
207     default:
208       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209   }
210 }
211
212 static gboolean
213 gst_ducati_videnc_configure (GstDucatiVidEnc * self)
214 {
215   int err;
216   int i;
217
218   GstCaps *caps = NULL;
219   int max_out_size = 0;
220
221   if (!GST_DUCATIVIDENC_GET_CLASS (self)->configure (self, &caps) ||
222       caps == NULL)
223     goto configure_failed;
224
225   if (self->codec == NULL) {
226     const gchar *codec_name;
227
228     codec_name = GST_DUCATIVIDENC_GET_CLASS (self)->codec_name;
229     self->codec = VIDENC2_create (self->engine,
230         (String) codec_name, self->params);
231
232     if (self->codec == NULL)
233       goto create_codec_fails;
234   }
235
236   err = VIDENC2_control (self->codec, XDM_SETPARAMS, self->dynParams,
237       self->status);
238   if (err) {
239     GST_ERROR_OBJECT (self, "XDM_SETPARAMS err=%d, extendedError=%08x",
240         err, self->status->extendedError);
241     gst_ducati_log_extended_error_info (self->status->extendedError);
242
243     return FALSE;
244   }
245
246   err = VIDENC2_control (self->codec, XDM_GETBUFINFO, self->dynParams,
247       self->status);
248   if (err) {
249     GST_ERROR_OBJECT (self, "XDM_GETBUFINFO err=%d, extendedError=%08x",
250         err, self->status->extendedError);
251
252     return FALSE;
253   }
254
255   self->outBufs->numBufs = self->status->bufInfo.minNumOutBufs;
256   for (i = 0; i < self->outBufs->numBufs; i++) {
257     int size = self->status->bufInfo.minOutBufSize[i].bytes;
258     if (size > max_out_size)
259       max_out_size = size;
260   }
261
262   self->output_state =
263       gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
264       self->input_state);
265   self->output_state->info.size = max_out_size;
266
267   /* And negotiate the pool */
268   if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self)))
269     goto negotiation_failed;
270
271   GST_INFO_OBJECT (self, "configured");
272
273   self->configure = FALSE;
274
275   return TRUE;
276
277   /* ERRORS */
278 configure_failed:
279   GST_ERROR_OBJECT (self, "Can not configure subclasses");
280   return FALSE;
281
282 create_codec_fails:
283   GST_ERROR_OBJECT (self, "could not create codec");
284   return FALSE;
285
286 negotiation_failed:
287   GST_WARNING_OBJECT (self, "Could not negotiate pool");
288   return FALSE;
289 }
290
291 static gboolean
292 gst_ducati_videnc_configure_default (GstDucatiVidEnc * self, GstCaps ** caps)
293 {
294   int i;
295   VIDENC2_Params *params;
296   VIDENC2_DynamicParams *dynParams;
297
298   GstVideoInfo *info = &self->input_state->info;
299
300   params = (VIDENC2_Params *) self->params;
301   params->encodingPreset = 0x03;
302   params->rateControlPreset = self->rate_preset;
303   params->maxHeight = info->height;
304   params->maxWidth = info->width;
305   params->dataEndianness = XDM_BYTE;
306   params->maxInterFrameInterval = 1;
307   params->maxBitRate = -1;
308   params->minBitRate = 0;
309   params->inputChromaFormat = XDM_YUV_420SP;
310   params->inputContentType = IVIDEO_PROGRESSIVE;
311   params->operatingMode = IVIDEO_ENCODE_ONLY;
312   params->inputDataMode = IVIDEO_ENTIREFRAME;
313   params->outputDataMode = IVIDEO_ENTIREFRAME;
314   params->numInputDataUnits = 1;
315   params->numOutputDataUnits = 1;
316   for (i = 0; i < IVIDEO_MAX_NUM_METADATA_PLANES; i++) {
317     params->metadataType[i] = IVIDEO_METADATAPLANE_NONE;
318   }
319
320   dynParams = (VIDENC2_DynamicParams *) self->dynParams;
321
322   dynParams->refFrameRate =
323       gst_util_uint64_scale (1000, info->fps_n, info->fps_d);
324   dynParams->targetFrameRate = dynParams->refFrameRate;
325   dynParams->inputWidth = info->width;
326   dynParams->inputHeight = info->height;
327   dynParams->targetBitRate = self->bitrate;
328   dynParams->intraFrameInterval = self->intra_interval;
329   dynParams->captureWidth = dynParams->inputWidth;
330
331   dynParams->forceFrame = IVIDEO_NA_FRAME;
332   dynParams->interFrameInterval = 1;
333   dynParams->mvAccuracy = IVIDENC2_MOTIONVECTOR_QUARTERPEL;
334   dynParams->sampleAspectRatioHeight = 1;
335   dynParams->sampleAspectRatioWidth = 1;
336   dynParams->generateHeader = XDM_ENCODE_AU;
337   dynParams->ignoreOutbufSizeFlag = 1;
338   dynParams->lateAcquireArg = -1;
339
340   self->inBufs->chromaFormat = XDM_YUV_420SP;
341   self->inBufs->numPlanes = 2;
342
343   return TRUE;
344 }
345
346 static gboolean
347 gst_ducati_videnc_open_engine (GstDucatiVidEnc * self)
348 {
349   int error_code;
350
351   if (self->device == NULL) {
352     self->device = dce_init ();
353     if (self->device == NULL)
354       return FALSE;
355   }
356
357   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &error_code);
358   if (self->engine == NULL) {
359     GST_ERROR_OBJECT (self, "couldn't open engine");
360     return FALSE;
361   }
362
363   return TRUE;
364 }
365
366 static gboolean
367 gst_ducati_videnc_allocate_params (GstDucatiVidEnc * self)
368 {
369   return GST_DUCATIVIDENC_GET_CLASS (self)->allocate_params (self,
370       sizeof (IVIDENC2_Params), sizeof (IVIDENC2_DynamicParams),
371       sizeof (IVIDENC2_Status), sizeof (IVIDENC2_InArgs),
372       sizeof (IVIDENC2_OutArgs));
373 }
374
375 static gboolean
376 gst_ducati_videnc_allocate_params_default (GstDucatiVidEnc * self,
377     gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz,
378     gint outargs_sz)
379 {
380   self->params = dce_alloc (params_sz);
381   memset (self->params, 0, params_sz);
382   self->params->size = params_sz;
383
384   self->dynParams = dce_alloc (dynparams_sz);
385   memset (self->dynParams, 0, dynparams_sz);
386   self->dynParams->size = dynparams_sz;
387
388   self->status = dce_alloc (status_sz);
389   memset (self->status, 0, status_sz);
390   self->status->size = status_sz;
391
392   self->inBufs = dce_alloc (sizeof (IVIDEO2_BufDesc));
393   memset (self->inBufs, 0, sizeof (IVIDEO2_BufDesc));
394
395   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
396   memset (self->outBufs, 0, sizeof (XDM2_BufDesc));
397
398   self->inArgs = dce_alloc (inargs_sz);
399   memset (self->inArgs, 0, inargs_sz);
400   self->inArgs->size = inargs_sz;
401
402   self->outArgs = dce_alloc (outargs_sz);
403   memset (self->outArgs, 0, outargs_sz);
404   self->outArgs->size = outargs_sz;
405
406   GST_INFO_OBJECT (self, "started");
407
408   return TRUE;
409 }
410
411 static gboolean
412 gst_ducati_videnc_free_params (GstDucatiVidEnc * self)
413 {
414   if (self->params) {
415     dce_free (self->params);
416     self->params = NULL;
417   }
418
419   if (self->dynParams) {
420     dce_free (self->dynParams);
421     self->dynParams = NULL;
422   }
423
424   if (self->inArgs) {
425     dce_free (self->inArgs);
426     self->inArgs = NULL;
427   }
428
429   if (self->outArgs) {
430     dce_free (self->outArgs);
431     self->outArgs = NULL;
432   }
433
434   if (self->status) {
435     dce_free (self->status);
436     self->status = NULL;
437   }
438
439   if (self->inBufs) {
440     dce_free (self->inBufs);
441     self->inBufs = NULL;
442   }
443
444   if (self->outBufs) {
445     dce_free (self->outBufs);
446     self->outBufs = NULL;
447   }
448
449   if (self->codec) {
450     VIDENC2_delete (self->codec);
451     self->codec = NULL;
452   }
453
454   return TRUE;
455 }
456
457 static void
458 gst_ducati_videnc_close_engine (GstDucatiVidEnc * self)
459 {
460   if (self->engine) {
461     Engine_close (self->engine);
462     self->engine = NULL;
463   }
464
465   if (self->device) {
466     dce_deinit (self->device);
467     self->device = NULL;
468   }
469 }
470
471
472 static gboolean
473 ducati_videnc_start (GstVideoEncoder * video_encoder)
474 {
475   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
476
477   self->configure = TRUE;
478
479   if (!gst_ducati_videnc_open_engine (self))
480     goto fail;
481
482   if (!gst_ducati_videnc_allocate_params (self))
483     goto fail;
484
485   return TRUE;
486
487 fail:
488   gst_ducati_videnc_free_params (self);
489   gst_ducati_videnc_close_engine (self);
490   return FALSE;
491 }
492
493 static gboolean
494 ducati_videnc_stop (GstVideoEncoder * video_encoder)
495 {
496   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
497
498   gst_ducati_videnc_free_params (self);
499   gst_ducati_videnc_close_engine (self);
500
501   if (self->input_pool) {
502     gst_object_unref (self->input_pool);
503     self->input_pool = NULL;
504   }
505
506   if (self->output_pool) {
507     gst_object_unref (self->output_pool);
508     self->output_pool = NULL;
509   }
510
511   return TRUE;
512 }
513
514 static GstFlowReturn
515 ducati_videnc_handle_frame (GstVideoEncoder * video_encoder,
516     GstVideoCodecFrame * frame)
517 {
518   int i;
519   XDAS_Int32 err;
520   GstClockTime t;
521   /*GstClockTime ts; */
522   GstBuffer *inbuf, *outbuf;
523   GstDucatiPriv *input_buffer_priv, *output_buffer_priv;
524
525   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
526   GstVideoInfo *info = &self->input_state->info;
527
528   if (G_UNLIKELY (self->configure)) {
529     if (!gst_ducati_videnc_configure (self)) {
530       GST_DEBUG_OBJECT (self, "configure failed");
531       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), (NULL));
532
533       return GST_FLOW_ERROR;
534     }
535   }
536
537   /*ts = GST_BUFFER_TIMESTAMP (inbuf); */
538 have_inbuf:
539   input_buffer_priv =
540       gst_buffer_add_ducati_priv (frame->input_buffer, self->device, info);
541   if (input_buffer_priv == NULL) {
542     GstBuffer *newbuf;
543
544     GST_DEBUG_OBJECT (self, "memcpying input");
545     if (!gst_buffer_pool_acquire_buffer (self->input_pool, &newbuf, NULL))
546       goto alloc_inbuf_failed;
547
548     gst_buffer_copy_into (newbuf, frame->input_buffer, GST_BUFFER_COPY_ALL,
549         0, gst_buffer_get_size (frame->input_buffer));
550
551     gst_buffer_unref (frame->input_buffer);
552     frame->input_buffer = newbuf;
553     goto have_inbuf;
554   }
555
556   inbuf = gst_buffer_ref (frame->input_buffer);
557   if (gst_buffer_pool_acquire_buffer (self->output_pool, &outbuf, NULL) !=
558       GST_FLOW_OK)
559     goto alloc_outbuf_failed;
560
561   output_buffer_priv = gst_buffer_add_ducati_priv (outbuf, self->device, info);
562
563   self->inBufs->planeDesc[0].buf =
564       (XDAS_Int8 *) omap_bo_handle (input_buffer_priv->bo);
565   self->inBufs->planeDesc[0].memType = XDM_MEMTYPE_BO;
566   self->inBufs->planeDesc[0].bufSize.tileMem.width = info->width;
567   self->inBufs->planeDesc[0].bufSize.tileMem.height = info->height;
568   self->inBufs->planeDesc[1].buf = (XDAS_Int8 *) input_buffer_priv->uv_offset;
569   self->inBufs->planeDesc[1].memType = XDM_MEMTYPE_BO_OFFSET;
570   self->inBufs->planeDesc[1].bufSize.tileMem.width = info->width;
571   self->inBufs->planeDesc[1].bufSize.tileMem.height = info->height / 2;
572
573   apply_cropping (self, frame);
574
575   self->inBufs->imagePitch[0] = info->width;
576   self->inBufs->imagePitch[1] = info->width;
577   self->inBufs->topFieldFirstFlag = TRUE;
578
579   self->outBufs->numBufs = 1;
580   self->outBufs->descs[0].buf =
581       (XDAS_Int8 *) omap_bo_handle (output_buffer_priv->bo);
582   self->outBufs->descs[0].bufSize.bytes = gst_buffer_get_size (outbuf);
583   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
584
585   self->inArgs->inputID = GPOINTER_TO_INT (inbuf);
586
587   GST_DEBUG_OBJECT (self, "Calling VIDENC2_process");
588   t = gst_util_get_timestamp ();
589   err = VIDENC2_process (self->codec, self->inBufs, self->outBufs,
590       self->inArgs, self->outArgs);
591   t = gst_util_get_timestamp () - t;
592   GST_DEBUG_OBJECT (self, "VIDENC2_process took %10dns (%d ms)", (gint) t,
593       (gint) (t / 1000000));
594
595   if (err) {
596     GST_WARNING_OBJECT (self, "process failed: err=%d, extendedError=%08x",
597         err, self->outArgs->extendedError);
598     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
599
600     err = VIDENC2_control (self->codec,
601         XDM_GETSTATUS, (IVIDENC2_DynamicParams *) self->dynParams,
602         self->status);
603
604     GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
605         err, self->status->extendedError);
606
607     return GST_FLOW_ERROR;
608   }
609
610   if (self->outArgs->bytesGenerated > 0) {
611     if (GST_DUCATIVIDENC_GET_CLASS (self)->is_sync_point (self,
612             self->outArgs->encodedFrameType))
613       GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
614
615     ;
616     GST_DEBUG_OBJECT (self, "Encoded frame in %u bytes",
617         self->outArgs->bytesGenerated);
618     gst_buffer_set_size (outbuf, self->outArgs->bytesGenerated);
619     frame->output_buffer = gst_buffer_copy (outbuf);
620
621     /* FIXME Check if we actually need to copy the  buffer */
622
623     /* As we can get frames in a different order we sent them (if the codec
624        supports B frames and we set it up for generating those), we need to
625        work out what input frame corresponds to the frame we just got, to
626        keep presentation times correct.
627        It seems that the codec will free buffers in the right order for this,
628        but I can not find anything saying this in the docs, so:
629        - it might be subject to change
630        - it might not be true in all setups
631        - it might not be true for all codecs
632        However, that's the only way I can see to do it. So there's a nice
633        assert below that will blow up if the codec does not free exactly one
634        input frame when it outputs a frame. That doesn't catch all cases,
635        such as when it frees them in the wrong order, but that seems less
636        likely to happen.
637        The timestamp and duration are given to the base class, which will
638        in turn set them onto the encoded buffer. */
639     g_assert (self->outArgs->freeBufID[0] && !self->outArgs->freeBufID[1]);
640     inbuf = GST_BUFFER (self->outArgs->freeBufID[0]);
641 #if 0
642     frame->pts = GST_BUFFER_TIMESTAMP (inbuf);
643     frame->duration = GST_BUFFER_DURATION (inbuf);
644     GST_BUFFER_OFFSET_END (frame->output_buffer) = GST_BUFFER_TIMESTAMP (inbuf);
645 #endif
646   }
647
648   gst_buffer_unref (outbuf);
649
650   for (i = 0; self->outArgs->freeBufID[i]; i++) {
651     GstBuffer *buf = (GstBuffer *) self->outArgs->freeBufID[i];
652
653     GST_LOG_OBJECT (self, "free buffer: %p", buf);
654     gst_buffer_unref (buf);
655   }
656
657   return gst_video_encoder_finish_frame (video_encoder, frame);
658
659 alloc_inbuf_failed:
660   GST_INFO_OBJECT (self, "Could not allocate input buffer");
661   return gst_video_encoder_finish_frame (video_encoder, frame);
662
663 alloc_outbuf_failed:
664   GST_INFO_OBJECT (self, "Could not allocate output buffer");
665   gst_buffer_unref (inbuf);
666   return gst_video_encoder_finish_frame (video_encoder, frame);
667 }
668
669 static gboolean
670 ducati_propose_alloc (GstVideoEncoder * encoder, GstQuery * query)
671 {
672   gsize size;
673   GstCaps *caps;
674   gboolean need_pool;
675   GstStructure *config;
676
677   GstBufferPool *pool = NULL;
678   GstDucatiVidEnc *self = GST_DUCATIVIDENC (encoder);
679
680   gst_query_parse_allocation (query, &caps, &need_pool);
681   if (caps == NULL)
682     goto no_caps;
683
684   if (self->input_pool)
685     pool = gst_object_ref (self->input_pool);
686
687   if (pool != NULL) {
688     GstCaps *pcaps;
689
690     /* we had a pool, check caps */
691     GST_DEBUG_OBJECT (self, "check existing pool caps");
692     config = gst_buffer_pool_get_config (pool);
693     gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
694     gst_structure_free (config);
695
696     if (!gst_caps_is_equal (caps, pcaps)) {
697       GST_DEBUG_OBJECT (self, "pool has different caps");
698       /* different caps, we can't use this pool */
699       gst_object_unref (pool);
700       pool = NULL;
701     }
702   }
703
704   if (pool == NULL && need_pool) {
705     GstVideoInfo info;
706
707     if (!gst_video_info_from_caps (&info, caps))
708       goto invalid_caps;
709
710     GST_DEBUG_OBJECT (self, "create new pool");
711     pool = gst_drm_buffer_pool_new (GST_ELEMENT (self), dce_get_fd ());
712
713     /* the normal size of a frame */
714     size = info.size;
715   }
716
717   if (pool) {
718     config = gst_buffer_pool_get_config (pool);
719     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
720     if (!gst_buffer_pool_set_config (pool, config))
721       goto config_failed;
722
723     /* we need at least 2 buffer because we hold on to the last one */
724     gst_query_add_allocation_pool (query, pool, size, 2, 0);
725     self->input_pool = pool;
726     /*gst_buffer_pool_set_active (pool, TRUE); */
727   }
728
729   gst_query_add_allocation_meta (query, GST_DRM_META_API_TYPE, NULL);
730   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
731   gst_query_add_allocation_meta (query, GST_DMA_BUF_META_API_TYPE, NULL);
732   gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
733
734   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
735       query);
736
737   /* ERRORS */
738 no_caps:
739   {
740     GST_DEBUG_OBJECT (self, "no caps specified");
741     return FALSE;
742   }
743 invalid_caps:
744   {
745     GST_DEBUG_OBJECT (self, "invalid caps specified");
746     return FALSE;
747   }
748 config_failed:
749   {
750     GST_DEBUG_OBJECT (self, "failed setting config");
751     gst_object_unref (pool);
752     return FALSE;
753   }
754 }
755
756 static gboolean
757 ducati_decide_allocation (GstVideoEncoder * encoder, GstQuery * query)
758 {
759   GstStructure *config;
760   GstCaps *outcaps, *caps;
761
762   GstBufferPool *pool = NULL;
763   guint nb_pools, min = 0, max = 0, size = 0;
764
765   GstDucatiVidEnc *self = GST_DUCATIVIDENC (encoder);
766
767   if (!GST_VIDEO_ENCODER_CLASS (parent_class)->decide_allocation (encoder,
768           query))
769     return FALSE;
770
771   gst_query_parse_allocation (query, &outcaps, NULL);
772   if ((nb_pools = gst_query_get_n_allocation_pools (query))) {
773     guint i;
774
775     for (i = 0; i < nb_pools; i++) {
776       gst_query_parse_nth_allocation_pool (query, i, &pool, &size, &min, &max);
777
778       /* Check that it has the proper options */
779       if (gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_DRM_META) &&
780           gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_DMABUF_META)
781           && gst_buffer_pool_has_option (pool,
782               GST_BUFFER_POOL_OPTION_VIDEO_META))
783         break;
784
785       gst_object_unref (pool);
786       pool = NULL;
787     }
788   }
789
790   if (self->output_pool) {
791     GstStructure *s;
792
793     if (pool == self->output_pool) {
794       GST_DEBUG_OBJECT (self, "Proposing the same pool, keeping it");
795       gst_object_unref (pool);
796
797       goto done;
798     }
799
800     s = gst_buffer_pool_get_config (self->output_pool);
801     gst_buffer_pool_config_get_params (s, &caps, NULL, NULL, NULL);
802     gst_structure_free (s);
803     if (gst_caps_is_equal (caps, outcaps)) {
804       GST_DEBUG_OBJECT (self, "Same caps, keeping pool");
805       goto done;
806     }
807
808     GST_DEBUG_OBJECT (self, "Deactivating previous pool");
809     g_object_unref (self->output_pool);
810     gst_structure_free (s);
811   }
812
813   if (pool) {
814     GST_DEBUG_OBJECT (self, "Using proposed pool: %" GST_PTR_FORMAT, pool);
815     self->output_pool = pool;
816     goto done;
817   } else {
818     GST_DEBUG_OBJECT (self, "Creating new pool");
819     self->output_pool =
820         gst_drm_buffer_pool_new (GST_ELEMENT (self), dce_get_fd ());
821   }
822
823 done:
824   if (size < self->output_state->info.size)
825     size = self->output_state->info.size;
826
827   config = gst_buffer_pool_get_config (self->output_pool);
828   gst_buffer_pool_config_set_params (config, self->output_state->caps, size,
829       min, max);
830
831   /* just set the option, if the pool can support it we will transparently use
832    * it through the video info API. We could also see if the pool support this
833    * option and only activate it then. */
834   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
835   gst_buffer_pool_set_config (self->output_pool, config);
836
837   /* Give our pool as best option */
838   if (nb_pools)
839     gst_query_set_nth_allocation_pool (query, 0, self->output_pool, size, min,
840         max);
841   else
842     gst_query_add_allocation_pool (query, self->output_pool, size, min, max);
843
844   /* Activate the pool ourself */
845   return gst_buffer_pool_set_active (self->output_pool, TRUE);
846 }
847
848 static gboolean
849 gst_ducati_videnc_is_sync_point_default (GstDucatiVidEnc * enc, int type)
850 {
851   return type == IVIDEO_I_FRAME;
852 }
853
854 static void
855 gst_ducati_videnc_class_init (GstDucatiVidEncClass * klass)
856 {
857   GObjectClass *gobject_class;
858   GstVideoEncoderClass *videoencoder_class;
859
860   gobject_class = G_OBJECT_CLASS (klass);
861   videoencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
862
863   gobject_class->set_property = gst_ducati_videnc_set_property;
864   gobject_class->get_property = gst_ducati_videnc_get_property;
865   gobject_class->finalize = gst_ducati_videnc_finalize;
866
867   videoencoder_class->set_format = GST_DEBUG_FUNCPTR (ducati_videnc_set_format);
868   videoencoder_class->start = GST_DEBUG_FUNCPTR (ducati_videnc_start);
869   videoencoder_class->stop = GST_DEBUG_FUNCPTR (ducati_videnc_stop);
870   videoencoder_class->handle_frame =
871       GST_DEBUG_FUNCPTR (ducati_videnc_handle_frame);
872   videoencoder_class->propose_allocation =
873       GST_DEBUG_FUNCPTR (ducati_propose_alloc);
874   videoencoder_class->decide_allocation =
875       GST_DEBUG_FUNCPTR (ducati_decide_allocation);
876
877   klass->allocate_params = gst_ducati_videnc_allocate_params_default;
878   klass->configure = gst_ducati_videnc_configure_default;
879   klass->is_sync_point = gst_ducati_videnc_is_sync_point_default;
880
881   g_object_class_install_property (gobject_class, PROP_BITRATE,
882       g_param_spec_int ("bitrate", "Bitrate", "Bitrate in kbit/sec", -1,
883           100 * 1024, DEFAULT_BITRATE, G_PARAM_READWRITE));
884
885   g_object_class_install_property (gobject_class, PROP_RATE_PRESET,
886       g_param_spec_enum ("rate-preset", "H.264 Rate Control",
887           "H.264 Rate Control",
888           GST_TYPE_DUCATI_VIDENC_RATE_PRESET, DEFAULT_RATE_PRESET,
889           G_PARAM_READWRITE));
890
891   g_object_class_install_property (gobject_class, PROP_INTRA_INTERVAL,
892       g_param_spec_int ("intra-interval", "Intra-frame interval",
893           "Interval between intra frames (keyframes)", 0, INT_MAX,
894           DEFAULT_INTRA_INTERVAL, G_PARAM_READWRITE));
895 }
896
897 static void
898 gst_ducati_videnc_init (GstDucatiVidEnc * self)
899 {
900   GST_DEBUG ("gst_ducati_videnc_init");
901
902   self->device = NULL;
903   self->engine = NULL;
904   self->codec = NULL;
905   self->params = NULL;
906   self->status = NULL;
907   self->inBufs = NULL;
908   self->outBufs = NULL;
909   self->inArgs = NULL;
910   self->outArgs = NULL;
911   self->input_pool = NULL;
912   self->output_pool = NULL;
913   self->input_state = NULL;
914   self->output_state = NULL;
915
916   self->bitrate = DEFAULT_BITRATE * 1000;
917   self->rate_preset = DEFAULT_RATE_PRESET;
918   self->intra_interval = DEFAULT_INTRA_INTERVAL;
919 }