videnc: Take into account cropping when configuring the codec
[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, GstVideoCodecFrame * frame)
214 {
215   int err, i;
216   GstVideoCropMeta *crop;
217   VIDENC2_Params *params;
218   VIDENC2_DynamicParams *dynParams;
219
220   GstCaps *caps = NULL;
221   int max_out_size = 0;
222   GstVideoInfo *info = &self->input_state->info;
223
224   params = (VIDENC2_Params *) self->params;
225   params->encodingPreset = 0x03;
226   params->rateControlPreset = self->rate_preset;
227   params->dataEndianness = XDM_BYTE;
228   params->maxInterFrameInterval = 1;
229   params->maxBitRate = -1;
230   params->minBitRate = 0;
231   params->maxHeight = info->height;
232   params->maxWidth = info->width;
233   params->inputChromaFormat = XDM_YUV_420SP;
234   params->inputContentType = IVIDEO_PROGRESSIVE;
235   params->operatingMode = IVIDEO_ENCODE_ONLY;
236   params->inputDataMode = IVIDEO_ENTIREFRAME;
237   params->outputDataMode = IVIDEO_ENTIREFRAME;
238   params->numInputDataUnits = 1;
239   params->numOutputDataUnits = 1;
240   for (i = 0; i < IVIDEO_MAX_NUM_METADATA_PLANES; i++) {
241     params->metadataType[i] = IVIDEO_METADATAPLANE_NONE;
242   }
243
244   dynParams = (VIDENC2_DynamicParams *) self->dynParams;
245
246   dynParams->refFrameRate = gst_util_uint64_scale (1000, info->fps_n,
247       info->fps_d);
248   dynParams->targetFrameRate = dynParams->refFrameRate;
249
250   if ((crop = gst_buffer_get_video_crop_meta (frame->input_buffer))) {
251     dynParams->inputWidth = crop->width;
252     dynParams->inputHeight = crop->height;
253   } else {
254     dynParams->inputWidth = info->width;
255     dynParams->inputHeight = info->height;
256   }
257   dynParams->targetBitRate = self->bitrate;
258   dynParams->intraFrameInterval = self->intra_interval;
259   dynParams->captureWidth = dynParams->inputWidth;
260
261   dynParams->forceFrame = IVIDEO_NA_FRAME;
262   dynParams->interFrameInterval = 1;
263   dynParams->mvAccuracy = IVIDENC2_MOTIONVECTOR_QUARTERPEL;
264   dynParams->sampleAspectRatioHeight = 1;
265   dynParams->sampleAspectRatioWidth = 1;
266   dynParams->generateHeader = XDM_ENCODE_AU;
267   dynParams->ignoreOutbufSizeFlag = 1;
268   dynParams->lateAcquireArg = -1;
269
270   self->inBufs->chromaFormat = XDM_YUV_420SP;
271   self->inBufs->numPlanes = 2;
272
273   g_assert (GST_DUCATIVIDENC_GET_CLASS (self)->configure);
274   if (!GST_DUCATIVIDENC_GET_CLASS (self)->configure (self, &caps) ||
275       caps == NULL)
276     goto configure_failed;
277
278   if (self->codec == NULL) {
279     const gchar *codec_name;
280
281     codec_name = GST_DUCATIVIDENC_GET_CLASS (self)->codec_name;
282     self->codec = VIDENC2_create (self->engine,
283         (String) codec_name, self->params);
284
285     if (self->codec == NULL)
286       goto create_codec_fails;
287   }
288
289   err = VIDENC2_control (self->codec, XDM_SETPARAMS, self->dynParams,
290       self->status);
291   if (err) {
292     GST_ERROR_OBJECT (self, "XDM_SETPARAMS err=%d, extendedError=%08x",
293         err, self->status->extendedError);
294     gst_ducati_log_extended_error_info (self->status->extendedError);
295
296     return FALSE;
297   }
298
299   err = VIDENC2_control (self->codec, XDM_GETBUFINFO, self->dynParams,
300       self->status);
301   if (err) {
302     GST_ERROR_OBJECT (self, "XDM_GETBUFINFO err=%d, extendedError=%08x",
303         err, self->status->extendedError);
304
305     return FALSE;
306   }
307
308   self->outBufs->numBufs = self->status->bufInfo.minNumOutBufs;
309   for (i = 0; i < self->outBufs->numBufs; i++) {
310     int size = self->status->bufInfo.minOutBufSize[i].bytes;
311     if (size > max_out_size)
312       max_out_size = size;
313   }
314
315   self->output_state =
316       gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps,
317       self->input_state);
318   self->output_state->info.size = max_out_size;
319
320   /* And negotiate the pool */
321   if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self)))
322     goto negotiation_failed;
323
324   GST_INFO_OBJECT (self, "configured");
325
326   self->configure = FALSE;
327
328   return TRUE;
329
330   /* ERRORS */
331 configure_failed:
332   GST_ERROR_OBJECT (self, "Can not configure subclasses");
333   return FALSE;
334
335 create_codec_fails:
336   GST_ERROR_OBJECT (self, "could not create codec");
337   return FALSE;
338
339 negotiation_failed:
340   GST_WARNING_OBJECT (self, "Could not negotiate pool");
341   return FALSE;
342 }
343
344 static gboolean
345 gst_ducati_videnc_open_engine (GstDucatiVidEnc * self)
346 {
347   int error_code;
348
349   if (self->device == NULL) {
350     self->device = dce_init ();
351     if (self->device == NULL)
352       return FALSE;
353   }
354
355   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &error_code);
356   if (self->engine == NULL) {
357     GST_ERROR_OBJECT (self, "couldn't open engine");
358     return FALSE;
359   }
360
361   return TRUE;
362 }
363
364 static gboolean
365 gst_ducati_videnc_allocate_params (GstDucatiVidEnc * self)
366 {
367   return GST_DUCATIVIDENC_GET_CLASS (self)->allocate_params (self,
368       sizeof (IVIDENC2_Params), sizeof (IVIDENC2_DynamicParams),
369       sizeof (IVIDENC2_Status), sizeof (IVIDENC2_InArgs),
370       sizeof (IVIDENC2_OutArgs));
371 }
372
373 static gboolean
374 gst_ducati_videnc_allocate_params_default (GstDucatiVidEnc * self,
375     gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz,
376     gint outargs_sz)
377 {
378   self->params = dce_alloc (params_sz);
379   memset (self->params, 0, params_sz);
380   self->params->size = params_sz;
381
382   self->dynParams = dce_alloc (dynparams_sz);
383   memset (self->dynParams, 0, dynparams_sz);
384   self->dynParams->size = dynparams_sz;
385
386   self->status = dce_alloc (status_sz);
387   memset (self->status, 0, status_sz);
388   self->status->size = status_sz;
389
390   self->inBufs = dce_alloc (sizeof (IVIDEO2_BufDesc));
391   memset (self->inBufs, 0, sizeof (IVIDEO2_BufDesc));
392
393   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
394   memset (self->outBufs, 0, sizeof (XDM2_BufDesc));
395
396   self->inArgs = dce_alloc (inargs_sz);
397   memset (self->inArgs, 0, inargs_sz);
398   self->inArgs->size = inargs_sz;
399
400   self->outArgs = dce_alloc (outargs_sz);
401   memset (self->outArgs, 0, outargs_sz);
402   self->outArgs->size = outargs_sz;
403
404   GST_INFO_OBJECT (self, "started");
405
406   return TRUE;
407 }
408
409 static gboolean
410 gst_ducati_videnc_free_params (GstDucatiVidEnc * self)
411 {
412   if (self->params) {
413     dce_free (self->params);
414     self->params = NULL;
415   }
416
417   if (self->dynParams) {
418     dce_free (self->dynParams);
419     self->dynParams = NULL;
420   }
421
422   if (self->inArgs) {
423     dce_free (self->inArgs);
424     self->inArgs = NULL;
425   }
426
427   if (self->outArgs) {
428     dce_free (self->outArgs);
429     self->outArgs = NULL;
430   }
431
432   if (self->status) {
433     dce_free (self->status);
434     self->status = NULL;
435   }
436
437   if (self->inBufs) {
438     dce_free (self->inBufs);
439     self->inBufs = NULL;
440   }
441
442   if (self->outBufs) {
443     dce_free (self->outBufs);
444     self->outBufs = NULL;
445   }
446
447   if (self->codec) {
448     VIDENC2_delete (self->codec);
449     self->codec = NULL;
450   }
451
452   return TRUE;
453 }
454
455 static void
456 gst_ducati_videnc_close_engine (GstDucatiVidEnc * self)
457 {
458   if (self->engine) {
459     Engine_close (self->engine);
460     self->engine = NULL;
461   }
462
463   if (self->device) {
464     dce_deinit (self->device);
465     self->device = NULL;
466   }
467 }
468
469
470 static gboolean
471 ducati_videnc_start (GstVideoEncoder * video_encoder)
472 {
473   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
474
475   self->configure = TRUE;
476
477   if (!gst_ducati_videnc_open_engine (self))
478     goto fail;
479
480   if (!gst_ducati_videnc_allocate_params (self))
481     goto fail;
482
483   return TRUE;
484
485 fail:
486   gst_ducati_videnc_free_params (self);
487   gst_ducati_videnc_close_engine (self);
488   return FALSE;
489 }
490
491 static gboolean
492 ducati_videnc_stop (GstVideoEncoder * video_encoder)
493 {
494   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
495
496   gst_ducati_videnc_free_params (self);
497   gst_ducati_videnc_close_engine (self);
498
499   if (self->input_pool) {
500     gst_object_unref (self->input_pool);
501     self->input_pool = NULL;
502   }
503
504   if (self->output_pool) {
505     gst_object_unref (self->output_pool);
506     self->output_pool = NULL;
507   }
508
509   return TRUE;
510 }
511
512 static GstFlowReturn
513 ducati_videnc_handle_frame (GstVideoEncoder * video_encoder,
514     GstVideoCodecFrame * frame)
515 {
516   int i;
517   XDAS_Int32 err;
518   GstClockTime t;
519   /*GstClockTime ts; */
520   GstBuffer *inbuf, *outbuf;
521   GstDucatiPriv *input_buffer_priv, *output_buffer_priv;
522
523   GstDucatiVidEnc *self = GST_DUCATIVIDENC (video_encoder);
524   GstVideoInfo *info = &self->input_state->info;
525
526   if (G_UNLIKELY (self->configure)) {
527     if (!gst_ducati_videnc_configure (self, frame)) {
528       GST_DEBUG_OBJECT (self, "configure failed");
529       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), (NULL));
530
531       return GST_FLOW_ERROR;
532     }
533   }
534
535   /*ts = GST_BUFFER_TIMESTAMP (inbuf); */
536 have_inbuf:
537   input_buffer_priv =
538       gst_buffer_add_ducati_priv (frame->input_buffer, self->device, info);
539   if (input_buffer_priv == NULL) {
540     GstBuffer *newbuf;
541
542     GST_DEBUG_OBJECT (self, "memcpying input");
543     if (!gst_buffer_pool_acquire_buffer (self->input_pool, &newbuf, NULL))
544       goto alloc_inbuf_failed;
545
546     gst_buffer_copy_into (newbuf, frame->input_buffer, GST_BUFFER_COPY_ALL,
547         0, gst_buffer_get_size (frame->input_buffer));
548
549     gst_buffer_unref (frame->input_buffer);
550     frame->input_buffer = newbuf;
551     goto have_inbuf;
552   }
553
554   inbuf = gst_buffer_ref (frame->input_buffer);
555   if (gst_buffer_pool_acquire_buffer (self->output_pool, &outbuf, NULL) !=
556       GST_FLOW_OK)
557     goto alloc_outbuf_failed;
558
559   output_buffer_priv = gst_buffer_add_ducati_priv (outbuf, self->device, info);
560
561   self->inBufs->planeDesc[0].buf =
562       (XDAS_Int8 *) omap_bo_handle (input_buffer_priv->bo);
563   self->inBufs->planeDesc[0].memType = XDM_MEMTYPE_BO;
564   self->inBufs->planeDesc[0].bufSize.tileMem.width = info->width;
565   self->inBufs->planeDesc[0].bufSize.tileMem.height = info->height;
566   self->inBufs->planeDesc[1].buf = (XDAS_Int8 *) input_buffer_priv->uv_offset;
567   self->inBufs->planeDesc[1].memType = XDM_MEMTYPE_BO_OFFSET;
568   self->inBufs->planeDesc[1].bufSize.tileMem.width = info->width;
569   self->inBufs->planeDesc[1].bufSize.tileMem.height = info->height / 2;
570
571   apply_cropping (self, frame);
572
573   self->inBufs->imagePitch[0] = info->width;
574   self->inBufs->imagePitch[1] = info->width;
575   self->inBufs->topFieldFirstFlag = TRUE;
576
577   self->outBufs->numBufs = 1;
578   self->outBufs->descs[0].buf =
579       (XDAS_Int8 *) omap_bo_handle (output_buffer_priv->bo);
580   self->outBufs->descs[0].bufSize.bytes = gst_buffer_get_size (outbuf);
581   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
582
583   /* Givin our ref to the codec */
584   self->inArgs->inputID = GPOINTER_TO_INT (inbuf);
585
586   GST_DEBUG_OBJECT (self, "Calling VIDENC2_process");
587   t = gst_util_get_timestamp ();
588   err = VIDENC2_process (self->codec, self->inBufs, self->outBufs,
589       self->inArgs, self->outArgs);
590   t = gst_util_get_timestamp () - t;
591   GST_DEBUG_OBJECT (self, "VIDENC2_process took %10dns (%d ms)", (gint) t,
592       (gint) (t / 1000000));
593
594   if (err) {
595     GST_WARNING_OBJECT (self, "process failed: err=%d, extendedError=%08x",
596         err, self->outArgs->extendedError);
597     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
598
599     err = VIDENC2_control (self->codec,
600         XDM_GETSTATUS, (IVIDENC2_DynamicParams *) self->dynParams,
601         self->status);
602
603     GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
604         err, self->status->extendedError);
605
606     return GST_FLOW_ERROR;
607   }
608
609   if (self->outArgs->bytesGenerated > 0) {
610     if (GST_DUCATIVIDENC_GET_CLASS (self)->is_sync_point (self,
611             self->outArgs->encodedFrameType))
612       GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
613
614     GST_DEBUG_OBJECT (self, "Encoded frame in %u bytes",
615         self->outArgs->bytesGenerated);
616     frame->output_buffer = gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL,
617         0, self->outArgs->bytesGenerated);
618
619     /* FIXME Check if we actually need to copy the  buffer */
620
621     /* As we can get frames in a different order we sent them (if the codec
622        supports B frames and we set it up for generating those), we need to
623        work out what input frame corresponds to the frame we just got, to
624        keep presentation times correct.
625        It seems that the codec will free buffers in the right order for this,
626        but I can not find anything saying this in the docs, so:
627        - it might be subject to change
628        - it might not be true in all setups
629        - it might not be true for all codecs
630        However, that's the only way I can see to do it. So there's a nice
631        assert below that will blow up if the codec does not free exactly one
632        input frame when it outputs a frame. That doesn't catch all cases,
633        such as when it frees them in the wrong order, but that seems less
634        likely to happen.
635        The timestamp and duration are given to the base class, which will
636        in turn set them onto the encoded buffer. */
637     g_assert (self->outArgs->freeBufID[0] && !self->outArgs->freeBufID[1]);
638     inbuf = GST_BUFFER (self->outArgs->freeBufID[0]);
639 #if 0
640     frame->pts = GST_BUFFER_TIMESTAMP (inbuf);
641     frame->duration = GST_BUFFER_DURATION (inbuf);
642     GST_BUFFER_OFFSET_END (frame->output_buffer) = GST_BUFFER_TIMESTAMP (inbuf);
643 #endif
644   }
645
646   gst_buffer_unref (outbuf);
647
648   for (i = 0; self->outArgs->freeBufID[i]; i++) {
649     GstBuffer *buf = (GstBuffer *) self->outArgs->freeBufID[i];
650
651     GST_LOG_OBJECT (self, "free buffer: %p", buf);
652     gst_buffer_unref (buf);
653   }
654
655   return gst_video_encoder_finish_frame (video_encoder, frame);
656
657 alloc_inbuf_failed:
658   GST_INFO_OBJECT (self, "Could not allocate input buffer");
659   return gst_video_encoder_finish_frame (video_encoder, frame);
660
661 alloc_outbuf_failed:
662   GST_INFO_OBJECT (self, "Could not allocate output buffer");
663   gst_buffer_unref (inbuf);
664   return gst_video_encoder_finish_frame (video_encoder, frame);
665 }
666
667 static gboolean
668 ducati_propose_alloc (GstVideoEncoder * encoder, GstQuery * query)
669 {
670   gsize size;
671   GstCaps *caps;
672   gboolean need_pool;
673   GstStructure *config;
674
675   GstBufferPool *pool = NULL;
676   GstDucatiVidEnc *self = GST_DUCATIVIDENC (encoder);
677
678   gst_query_parse_allocation (query, &caps, &need_pool);
679   if (caps == NULL)
680     goto no_caps;
681
682   if (self->input_pool)
683     pool = gst_object_ref (self->input_pool);
684
685   if (pool != NULL) {
686     GstCaps *pcaps;
687
688     /* we had a pool, check caps */
689     GST_DEBUG_OBJECT (self, "check existing pool caps");
690     config = gst_buffer_pool_get_config (pool);
691     gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
692     gst_structure_free (config);
693
694     if (!gst_caps_is_equal (caps, pcaps)) {
695       GST_DEBUG_OBJECT (self, "pool has different caps");
696       /* different caps, we can't use this pool */
697       gst_object_unref (pool);
698       pool = NULL;
699     }
700   }
701
702   if (pool == NULL && need_pool) {
703     GstVideoInfo info;
704
705     if (!gst_video_info_from_caps (&info, caps))
706       goto invalid_caps;
707
708     GST_DEBUG_OBJECT (self, "create new pool");
709     pool = gst_drm_buffer_pool_new (dce_get_fd ());
710
711     /* the normal size of a frame */
712     size = info.size;
713   }
714
715   if (pool) {
716     config = gst_buffer_pool_get_config (pool);
717     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
718     if (!gst_buffer_pool_set_config (pool, config))
719       goto config_failed;
720
721     /* we need at least 2 buffer because we hold on to the last one */
722     gst_query_add_allocation_pool (query, pool, size, 2, 0);
723     self->input_pool = pool;
724     /*gst_buffer_pool_set_active (pool, TRUE); */
725   }
726
727   gst_query_add_allocation_meta (query, GST_DRM_META_API_TYPE, NULL);
728   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
729   gst_query_add_allocation_meta (query, GST_DMA_BUF_META_API_TYPE, NULL);
730   gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
731
732   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
733       query);
734
735   /* ERRORS */
736 no_caps:
737   {
738     GST_DEBUG_OBJECT (self, "no caps specified");
739     return FALSE;
740   }
741 invalid_caps:
742   {
743     GST_DEBUG_OBJECT (self, "invalid caps specified");
744     return FALSE;
745   }
746 config_failed:
747   {
748     GST_DEBUG_OBJECT (self, "failed setting config");
749     gst_object_unref (pool);
750     return FALSE;
751   }
752 }
753
754 static gboolean
755 ducati_decide_allocation (GstVideoEncoder * encoder, GstQuery * query)
756 {
757   GstStructure *config;
758   GstCaps *outcaps, *caps;
759
760   GstBufferPool *pool = NULL;
761   guint nb_pools, min = 0, max = 0, size = 0;
762
763   GstDucatiVidEnc *self = GST_DUCATIVIDENC (encoder);
764
765   if (!GST_VIDEO_ENCODER_CLASS (parent_class)->decide_allocation (encoder,
766           query))
767     return FALSE;
768
769   gst_query_parse_allocation (query, &outcaps, NULL);
770   if ((nb_pools = gst_query_get_n_allocation_pools (query))) {
771     guint i;
772
773     for (i = 0; i < nb_pools; i++) {
774       gst_query_parse_nth_allocation_pool (query, i, &pool, &size, &min, &max);
775
776       /* Check that it has the proper options */
777       if (gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_DRM_META) &&
778           gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_DMABUF_META)
779           && gst_buffer_pool_has_option (pool,
780               GST_BUFFER_POOL_OPTION_VIDEO_META))
781         break;
782
783       gst_object_unref (pool);
784       pool = NULL;
785     }
786   }
787
788   if (self->output_pool) {
789     GstStructure *s;
790
791     if (pool == self->output_pool) {
792       GST_DEBUG_OBJECT (self, "Proposing the same pool, keeping it");
793       gst_object_unref (pool);
794
795       goto done;
796     }
797
798     s = gst_buffer_pool_get_config (self->output_pool);
799     gst_buffer_pool_config_get_params (s, &caps, NULL, NULL, NULL);
800     gst_structure_free (s);
801     if (gst_caps_is_equal (caps, outcaps)) {
802       GST_DEBUG_OBJECT (self, "Same caps, keeping pool");
803       goto done;
804     }
805
806     GST_DEBUG_OBJECT (self, "Deactivating previous pool");
807     g_object_unref (self->output_pool);
808     gst_structure_free (s);
809   }
810
811   if (pool) {
812     GST_DEBUG_OBJECT (self, "Using proposed pool: %" GST_PTR_FORMAT, pool);
813     self->output_pool = pool;
814     goto done;
815   } else {
816     GST_DEBUG_OBJECT (self, "Creating new pool");
817     self->output_pool = gst_drm_buffer_pool_new (dce_get_fd ());
818   }
819
820 done:
821   if (size < self->output_state->info.size)
822     size = self->output_state->info.size;
823
824   config = gst_buffer_pool_get_config (self->output_pool);
825   gst_buffer_pool_config_set_params (config, self->output_state->caps, size,
826       min, max);
827
828   /* just set the option, if the pool can support it we will transparently use
829    * it through the video info API. We could also see if the pool support this
830    * option and only activate it then. */
831   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
832   gst_buffer_pool_set_config (self->output_pool, config);
833
834   /* Give our pool as best option */
835   if (nb_pools)
836     gst_query_set_nth_allocation_pool (query, 0, self->output_pool, size, min,
837         max);
838   else
839     gst_query_add_allocation_pool (query, self->output_pool, size, min, max);
840
841   /* Activate the pool ourself */
842   return gst_buffer_pool_set_active (self->output_pool, TRUE);
843 }
844
845 static gboolean
846 gst_ducati_videnc_is_sync_point_default (GstDucatiVidEnc * enc, int type)
847 {
848   return type == IVIDEO_I_FRAME;
849 }
850
851 static void
852 gst_ducati_videnc_class_init (GstDucatiVidEncClass * klass)
853 {
854   GObjectClass *gobject_class;
855   GstVideoEncoderClass *videoencoder_class;
856
857   gobject_class = G_OBJECT_CLASS (klass);
858   videoencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
859
860   gobject_class->set_property = gst_ducati_videnc_set_property;
861   gobject_class->get_property = gst_ducati_videnc_get_property;
862   gobject_class->finalize = gst_ducati_videnc_finalize;
863
864   videoencoder_class->set_format = GST_DEBUG_FUNCPTR (ducati_videnc_set_format);
865   videoencoder_class->start = GST_DEBUG_FUNCPTR (ducati_videnc_start);
866   videoencoder_class->stop = GST_DEBUG_FUNCPTR (ducati_videnc_stop);
867   videoencoder_class->handle_frame =
868       GST_DEBUG_FUNCPTR (ducati_videnc_handle_frame);
869   videoencoder_class->propose_allocation =
870       GST_DEBUG_FUNCPTR (ducati_propose_alloc);
871   videoencoder_class->decide_allocation =
872       GST_DEBUG_FUNCPTR (ducati_decide_allocation);
873
874   klass->configure = NULL;
875   klass->allocate_params = gst_ducati_videnc_allocate_params_default;
876   klass->is_sync_point = gst_ducati_videnc_is_sync_point_default;
877
878   g_object_class_install_property (gobject_class, PROP_BITRATE,
879       g_param_spec_int ("bitrate", "Bitrate", "Bitrate in kbit/sec", -1,
880           100 * 1024, DEFAULT_BITRATE, G_PARAM_READWRITE));
881
882   g_object_class_install_property (gobject_class, PROP_RATE_PRESET,
883       g_param_spec_enum ("rate-preset", "H.264 Rate Control",
884           "H.264 Rate Control",
885           GST_TYPE_DUCATI_VIDENC_RATE_PRESET, DEFAULT_RATE_PRESET,
886           G_PARAM_READWRITE));
887
888   g_object_class_install_property (gobject_class, PROP_INTRA_INTERVAL,
889       g_param_spec_int ("intra-interval", "Intra-frame interval",
890           "Interval between intra frames (keyframes)", 0, INT_MAX,
891           DEFAULT_INTRA_INTERVAL, G_PARAM_READWRITE));
892 }
893
894 static void
895 gst_ducati_videnc_init (GstDucatiVidEnc * self)
896 {
897   GST_DEBUG ("gst_ducati_videnc_init");
898
899   self->device = NULL;
900   self->engine = NULL;
901   self->codec = NULL;
902   self->params = NULL;
903   self->status = NULL;
904   self->inBufs = NULL;
905   self->outBufs = NULL;
906   self->inArgs = NULL;
907   self->outArgs = NULL;
908   self->input_pool = NULL;
909   self->output_pool = NULL;
910   self->input_state = NULL;
911   self->output_state = NULL;
912
913   self->bitrate = DEFAULT_BITRATE * 1000;
914   self->rate_preset = DEFAULT_RATE_PRESET;
915   self->intra_interval = DEFAULT_INTRA_INTERVAL;
916 }