fixed profile setting
[gst-plugin-dreamsource.git] / src / gstdreamvideosource.c
1 /*
2  * GStreamer dreamvideosource
3  * Copyright 2014-2015 Andreas Frisch <fraxinas@opendreambox.org>
4  *
5  * This program is licensed under the Creative Commons
6  * Attribution-NonCommercial-ShareAlike 3.0 Unported
7  * License. To view a copy of this license, visit
8  * http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
9  * Creative Commons,559 Nathan Abbott Way,Stanford,California 94305,USA.
10  *
11  * Alternatively, this program may be distributed and executed on
12  * hardware which is licensed by Dream Property GmbH.
13  *
14  * This program is NOT free software. It is open source, you are allowed
15  * to modify it (if you keep the license), but it may not be commercially
16  * distributed other than under the conditions noted above.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <gst/gst.h>
24 #include "gstdreamvideosource.h"
25
26 GST_DEBUG_CATEGORY_STATIC (dreamvideosource_debug);
27 #define GST_CAT_DEFAULT dreamvideosource_debug
28
29 GType gst_dreamvideosource_input_mode_get_type (void)
30 {
31         static volatile gsize input_mode_type = 0;
32         static const GEnumValue input_mode[] = {
33                 {GST_DREAMVIDEOSOURCE_INPUT_MODE_LIVE, "GST_DREAMVIDEOSOURCE_INPUT_MODE_LIVE", "live"},
34                 {GST_DREAMVIDEOSOURCE_INPUT_MODE_HDMI_IN, "GST_DREAMVIDEOSOURCE_INPUT_MODE_HDMI_IN", "hdmi_in"},
35                 {GST_DREAMVIDEOSOURCE_INPUT_MODE_BACKGROUND, "GST_DREAMVIDEOSOURCE_INPUT_MODE_BACKGROUND", "background"},
36                 {0, NULL, NULL},
37         };
38
39         if (g_once_init_enter (&input_mode_type)) {
40                 GType tmp = g_enum_register_static ("GstDreamVideoSourceInputMode", input_mode);
41                 g_once_init_leave (&input_mode_type, tmp);
42         }
43         return (GType) input_mode_type;
44 }
45
46 enum
47 {
48         SIGNAL_GET_DTS_OFFSET,
49         LAST_SIGNAL
50 };
51
52 enum
53 {
54         ARG_0,
55         ARG_CAPS,
56         ARG_BITRATE,
57         ARG_INPUT_MODE,
58         ARG_GOP_LENGTH,
59         ARG_GOP_SCENE,
60         ARG_OPEN_GOP,
61         ARG_BFRAMES,
62         ARG_PFRAMES,
63         ARG_SLICES,
64         ARG_LEVEL,
65 };
66
67 static guint gst_dreamvideosource_signals[LAST_SIGNAL] = { 0 };
68
69 #define DEFAULT_BITRATE     2048
70 #define DEFAULT_GOP_LENGTH  0
71 #define DEFAULT_GOP_SCENE   FALSE
72 #define DEFAULT_BFRAMES     2
73 #define DEFAULT_PFRAMES     1
74 #define DEFAULT_SLICES      0
75 #define DEFAULT_LEVEL       level_default
76 #define DEFAULT_FRAMERATE   25
77 #define DEFAULT_WIDTH       1280
78 #define DEFAULT_HEIGHT      720
79 #define DEFAULT_INPUT_MODE  GST_DREAMVIDEOSOURCE_INPUT_MODE_LIVE
80 #define DEFAULT_BUFFER_SIZE 50
81
82 static GstStaticPadTemplate srctemplate =
83     GST_STATIC_PAD_TEMPLATE ("src",
84         GST_PAD_SRC,
85         GST_PAD_ALWAYS,
86         GST_STATIC_CAPS ("video/x-h264, "
87         "width = { 720, 1280, 1920 }, "
88         "height = { 576, 720, 1080 }, "
89         "framerate = { 25/1, 30/1, 50/1, 60/1 }, "
90         "display-aspect-ratio = { 5/4, 16/9 }, "
91         "stream-format = (string) byte-stream, "
92         "profile = (string) { main, high }")
93     );
94
95 #define gst_dreamvideosource_parent_class parent_class
96 G_DEFINE_TYPE (GstDreamVideoSource, gst_dreamvideosource, GST_TYPE_PUSH_SRC);
97
98 static GstCaps *gst_dreamvideosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
99 static gboolean gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
100 static GstCaps *gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps);
101 static gboolean gst_dreamvideosource_query (GstBaseSrc * bsrc, GstQuery * query);
102
103 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc);
104 static gboolean gst_dreamvideosource_unlock_stop (GstBaseSrc * bsrc);
105 static void gst_dreamvideosource_dispose (GObject * gobject);
106 static GstFlowReturn gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf);
107
108 static void gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
109 static void gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
110
111 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition);
112 static gint64 gst_dreamvideosource_get_dts_offset (GstDreamVideoSource *self);
113
114 static gboolean gst_dreamvideosource_encoder_init (GstDreamVideoSource * self);
115 static void gst_dreamvideosource_encoder_release (GstDreamVideoSource * self);
116
117 static void gst_dreamvideosource_read_thread_func (GstDreamVideoSource * self);
118
119 #ifdef PROVIDE_CLOCK
120 static GstClock *gst_dreamvideosource_provide_clock (GstElement * elem);
121 // static GstClockTime gst_dreamvideosource_get_encoder_time_ (GstClock * clock, GstBaseSrc * bsrc);
122 #endif
123
124 static void
125 gst_dreamvideosource_class_init (GstDreamVideoSourceClass * klass)
126 {
127         GObjectClass *gobject_class;
128         GstElementClass *gstelement_class;
129         GstBaseSrcClass *gstbsrc_class;
130         GstPushSrcClass *gstpush_src_class;
131
132         gobject_class = (GObjectClass *) klass;
133         gstelement_class = (GstElementClass *) klass;
134         gstbsrc_class = (GstBaseSrcClass *) klass;
135         gstpush_src_class = (GstPushSrcClass *) klass;
136
137         gobject_class->set_property = gst_dreamvideosource_set_property;
138         gobject_class->get_property = gst_dreamvideosource_get_property;
139         gobject_class->dispose = gst_dreamvideosource_dispose;
140
141         gst_element_class_add_pad_template (gstelement_class,
142                                             gst_static_pad_template_get (&srctemplate));
143
144         gst_element_class_set_static_metadata (gstelement_class,
145             "Dream Video source", "Source/Video",
146             "Provide an h.264 video elementary stream from Dreambox encoder device",
147             "Andreas Frisch <fraxinas@opendreambox.org>");
148
149         gstelement_class->change_state = gst_dreamvideosource_change_state;
150
151         gstbsrc_class->get_caps = gst_dreamvideosource_getcaps;
152         gstbsrc_class->set_caps = gst_dreamvideosource_setcaps;
153         gstbsrc_class->query = gst_dreamvideosource_query;
154         gstbsrc_class->fixate = gst_dreamvideosource_fixate;
155         gstbsrc_class->unlock = gst_dreamvideosource_unlock;
156         gstbsrc_class->unlock_stop = gst_dreamvideosource_unlock_stop;
157
158         gstpush_src_class->create = gst_dreamvideosource_create;
159
160 #ifdef PROVIDE_CLOCK
161         gstelement_class->provide_clock = GST_DEBUG_FUNCPTR (gst_dreamvideosource_provide_clock);
162 //      g_type_class_ref (GST_TYPE_SYSTEM_CLOCK);
163 #endif
164
165         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
166           g_param_spec_int ("bitrate", "Bitrate (kb/s)",
167             "Bitrate in kbit/sec", bitrate_min, bitrate_max, DEFAULT_BITRATE,
168             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169
170         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_LENGTH,
171           g_param_spec_int ("gop-length", "GOP length (ms)",
172             "GOP length in ms", gop_length_auto, gop_length_max, DEFAULT_GOP_LENGTH,
173             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174
175         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_SCENE,
176           g_param_spec_boolean ("gop-scene", "GOP on scene change",
177             "New GOP on scene change", FALSE,
178             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
179
180         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OPEN_GOP,
181           g_param_spec_boolean ("open-gop", "Enable Open GOPs",
182             "Open GOPs", FALSE,
183             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
184
185         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BFRAMES,
186           g_param_spec_int ("bframes", "Number of B-Frames",
187             "Number of B-Frames before P-Frame", bframes_min, bframes_max, DEFAULT_BFRAMES,
188             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
189
190         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PFRAMES,
191           g_param_spec_int ("pframes", "Number of P-Frames",
192             "Number of P-Frames after B-Frames", pframes_min, pframes_max, DEFAULT_PFRAMES,
193             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
194
195         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLICES,
196           g_param_spec_int ("slices", "Number of slices",
197             "Number of slices per picture", slices_min, slices_max, DEFAULT_SLICES,
198             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
199
200         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LEVEL,
201           g_param_spec_int ("level", "h.264 Level",
202             "h.264 Level", level_min, level_max, DEFAULT_LEVEL,
203             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
204
205         g_object_class_install_property (gobject_class, ARG_CAPS,
206           g_param_spec_boxed ("caps", "Caps",
207             "The caps for the source stream", GST_TYPE_CAPS,
208             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209
210         g_object_class_install_property (gobject_class, ARG_INPUT_MODE,
211           g_param_spec_enum ("input-mode", "Input Mode",
212             "Select the input source of the video stream",
213             GST_TYPE_DREAMVIDEOSOURCE_INPUT_MODE, DEFAULT_INPUT_MODE,
214             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
215
216         gst_dreamvideosource_signals[SIGNAL_GET_DTS_OFFSET] =
217                 g_signal_new ("get-dts-offset",
218                 G_TYPE_FROM_CLASS (klass),
219                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
220                 G_STRUCT_OFFSET (GstDreamVideoSourceClass, get_dts_offset),
221                 NULL, NULL, gst_dreamsource_marshal_INT64__VOID, G_TYPE_INT64, 0);
222
223         klass->get_dts_offset = gst_dreamvideosource_get_dts_offset;
224 }
225
226 static gint64
227 gst_dreamvideosource_get_dts_offset (GstDreamVideoSource *self)
228 {
229         GST_DEBUG_OBJECT (self, "gst_dreamvideosource_get_dts_offset %" GST_TIME_FORMAT"", GST_TIME_ARGS (self->dts_offset) );
230         return self->dts_offset;
231 }
232
233 static void gst_dreamvideosource_set_bitrate (GstDreamVideoSource * self, uint32_t bitrate)
234 {
235         g_mutex_lock (&self->mutex);
236         uint32_t vbr = bitrate*1000;
237         if (!self->encoder || !self->encoder->fd)
238         {
239                 self->video_info.bitrate = bitrate;
240                 g_mutex_unlock (&self->mutex);
241                 return;
242         }
243
244         int ret = ioctl(self->encoder->fd, VENC_SET_BITRATE, &vbr);
245         if (ret != 0)
246         {
247                 GST_WARNING_OBJECT (self, "can't set video bitrate to %i bytes/s!", vbr);
248                 g_mutex_unlock (&self->mutex);
249                 return;
250         }
251         GST_INFO_OBJECT (self, "set video bitrate to %i kBytes/s", bitrate);
252         self->video_info.bitrate = bitrate;
253         g_mutex_unlock (&self->mutex);
254 }
255
256 static void gst_dreamvideosource_set_goplen (GstDreamVideoSource * self, uint32_t goplen)
257 {
258         g_mutex_lock (&self->mutex);
259         if (!self->encoder || !self->encoder->fd)
260         {
261                 self->video_info.gop_length = goplen;
262                 g_mutex_unlock (&self->mutex);
263                 return;
264         }
265
266         int ret = ioctl(self->encoder->fd, VENC_SET_GOP_LENGTH, &goplen);
267         if (ret != 0)
268         {
269                 GST_WARNING_OBJECT (self, "can't set video gop length to %i ms!", goplen);
270                 g_mutex_unlock (&self->mutex);
271                 return;
272         }
273         GST_INFO_OBJECT (self, "set video gop length to %i ms", goplen);
274         self->video_info.gop_length = goplen;
275         g_mutex_unlock (&self->mutex);
276 }
277
278 static void gst_dreamvideosource_set_gop_on_scene_change (GstDreamVideoSource * self, gboolean enabled)
279 {
280         g_mutex_lock (&self->mutex);
281         uint32_t en = enabled;
282         if (!self->encoder || !self->encoder->fd)
283         {
284                 self->video_info.gop_scene = enabled;
285                 g_mutex_unlock (&self->mutex);
286                 return;
287         }
288
289         int ret = ioctl(self->encoder->fd, VENC_SET_NEW_GOP_ON_NEW_SCENE, &en);
290         if (ret != 0)
291         {
292                 GST_WARNING_OBJECT (self, "can't set video new gop on new scene to %i (unspported?)!", enabled);
293                 g_mutex_unlock (&self->mutex);
294                 return;
295         }
296         GST_INFO_OBJECT (self, "set video new gop on new scene to %i!", enabled);
297         self->video_info.gop_scene = enabled;
298         g_mutex_unlock (&self->mutex);
299 }
300
301 static void gst_dreamvideosource_set_open_gop (GstDreamVideoSource * self, gboolean enabled)
302 {
303         g_mutex_lock (&self->mutex);
304         if (!self->encoder || !self->encoder->fd)
305         {
306                 self->video_info.open_gop = enabled;
307                 g_mutex_unlock (&self->mutex);
308                 return;
309         }
310
311         uint32_t en = enabled;
312         int ret = ioctl(self->encoder->fd, VENC_SET_OPEN_GOP, &en);
313         if (ret != 0)
314         {
315                 GST_WARNING_OBJECT (self, "can't set video open gop to %i (unspported?)!", enabled);
316                 g_mutex_unlock (&self->mutex);
317                 return;
318         }
319         GST_INFO_OBJECT (self, "set video open gop to %i!", enabled);
320         self->video_info.open_gop = enabled;
321         g_mutex_unlock (&self->mutex);
322 }
323
324 static void gst_dreamvideosource_set_bframes (GstDreamVideoSource * self, uint32_t bframes)
325 {
326         g_mutex_lock (&self->mutex);
327         if (!self->encoder || !self->encoder->fd)
328         {
329                 self->video_info.bframes = bframes;
330                 g_mutex_unlock (&self->mutex);
331                 return;
332         }
333
334         int ret = ioctl(self->encoder->fd, VENC_SET_B_FRAMES, &bframes);
335         if (ret != 0)
336         {
337                 GST_WARNING_OBJECT (self, "can't set video b-frames %i!", bframes);
338                 g_mutex_unlock (&self->mutex);
339                 return;
340         }
341         GST_INFO_OBJECT (self, "set video b-frames to %i", bframes);
342         self->video_info.bframes= bframes;
343         g_mutex_unlock (&self->mutex);
344 }
345
346 static void gst_dreamvideosource_set_pframes (GstDreamVideoSource * self, uint32_t pframes)
347 {
348         g_mutex_lock (&self->mutex);
349         if (!self->encoder || !self->encoder->fd)
350         {
351                 self->video_info.pframes = pframes;
352                 g_mutex_unlock (&self->mutex);
353                 return;
354         }
355
356         int ret = ioctl(self->encoder->fd, VENC_SET_P_FRAMES, &pframes);
357         if (ret != 0)
358         {
359                 GST_WARNING_OBJECT (self, "can't set video p-frames %i!", pframes);
360                 g_mutex_unlock (&self->mutex);
361                 return;
362         }
363         GST_INFO_OBJECT (self, "set video p-frames to %i", pframes);
364         self->video_info.pframes= pframes;
365         g_mutex_unlock (&self->mutex);
366 }
367
368 static void gst_dreamvideosource_set_slices (GstDreamVideoSource * self, uint32_t slices)
369 {
370         g_mutex_lock (&self->mutex);
371         if (!self->encoder || !self->encoder->fd)
372         {
373                 self->video_info.slices = slices;
374                 g_mutex_unlock (&self->mutex);
375                 return;
376         }
377
378         int ret = ioctl(self->encoder->fd, VENC_SET_SLICES_PER_PIC, &slices);
379         if (ret != 0)
380         {
381                 GST_WARNING_OBJECT (self, "can't set video slices to %i %i!", slices, ret);
382                 g_mutex_unlock (&self->mutex);
383                 return;
384         }
385         GST_INFO_OBJECT (self, "set video slices to %i", slices);
386         self->video_info.slices = slices;
387         g_mutex_unlock (&self->mutex);
388 }
389
390 static void gst_dreamvideosource_set_level (GstDreamVideoSource * self, uint32_t level)
391 {
392         g_mutex_lock (&self->mutex);
393         if (!self->encoder || !self->encoder->fd)
394         {
395                 self->video_info.level = level;
396                 g_mutex_unlock (&self->mutex);
397                 return;
398         }
399
400         int ret = ioctl(self->encoder->fd, VENC_SET_LEVEL, &level);
401         if (ret != 0)
402         {
403                 GST_WARNING_OBJECT (self, "can't set h264 level to %i %i!", level, ret);
404                 g_mutex_unlock (&self->mutex);
405                 return;
406         }
407         GST_INFO_OBJECT (self, "set video h264 level to %i", level);
408         self->video_info.level = level;
409         g_mutex_unlock (&self->mutex);
410 }
411
412 static gboolean gst_dreamvideosource_set_format (GstDreamVideoSource * self, VideoFormatInfo * info)
413 {
414         g_mutex_lock (&self->mutex);
415         info->bitrate = self->video_info.bitrate;
416         info->gop_length = self->video_info.gop_length;
417         info->gop_scene = self->video_info.gop_scene;
418         info->open_gop = self->video_info.open_gop;
419         info->bframes = self->video_info.bframes;
420         info->pframes = self->video_info.pframes;
421         info->slices = self->video_info.slices;
422         info->level = self->video_info.level;
423
424         if (!self->encoder || !self->encoder->fd)
425         {
426                 self->video_info = *info;
427                 g_mutex_unlock (&self->mutex);
428                 return TRUE;
429         }
430
431         if (info->fps_n > 0)
432         {
433                 int venc_fps = 0;
434                 switch (info->fps_n) {
435                         case 25:
436                                 venc_fps = rate_25;
437                                 break;
438                         case 30:
439                                 venc_fps = rate_30;
440                                 break;
441                         case 50:
442                                 venc_fps = rate_50;
443                                 break;
444                         case 60:
445                                 venc_fps = rate_60;
446                                 break;
447                         case 23:
448                                 venc_fps = rate_23_976;
449                                 break;
450                         case 24:
451                                 venc_fps = rate_24;
452                                 break;
453                         case 29:
454                                 venc_fps = rate_29_97;
455                                 break;
456                         case 59:
457                                 venc_fps = rate_59_94;
458                         default:
459                                 GST_ERROR_OBJECT (self, "invalid framerate %d/%d", info->fps_n, info->fps_d);
460                                 goto fail;
461                 }
462                 if (!ioctl(self->encoder->fd, VENC_SET_FRAMERATE, &venc_fps))
463                         GST_INFO_OBJECT (self, "set framerate to %d/%d -> ioctrl(%d, VENC_SET_FRAMERATE, &%d)", info->fps_n, info->fps_d, self->encoder->fd, venc_fps);
464                 else
465                 {
466                         GST_WARNING_OBJECT (self, "can't set framerate to %d/%d -> ioctrl(%d, VENC_SET_FRAMERATE, &%d)", info->fps_n, info->fps_d, self->encoder->fd, venc_fps);
467                         goto fail;
468                 }
469         }
470
471         if (info->width && info->height)
472         {
473                 int venc_size = 0;
474                 if ( info->width == 720 && info->height == 576 )
475                         venc_size = fmt_720x576;
476                 else if ( info->width == 1280 && info->height == 720)
477                         venc_size = fmt_1280x720;
478                 else if ( info->width == 1920 && info->height == 1080)
479                         venc_size = fmt_1920x1080;
480                 else
481                 {
482                         GST_ERROR_OBJECT (self, "invalid resolution %dx%d", info->width, info->height);
483                         goto fail;
484                 }
485                 if (!ioctl(self->encoder->fd, VENC_SET_RESOLUTION, &venc_size))
486                         GST_INFO_OBJECT (self, "set resolution to %dx%d -> ioctrl(%d, VENC_SET_RESOLUTION, &%d)", info->width, info->height, self->encoder->fd, venc_size);
487                 else
488                 {
489                         GST_WARNING_OBJECT (self, "can't set resolution to %dx%d -> ioctrl(%d, VENC_SET_RESOLUTION, &%d)", info->width, info->height, self->encoder->fd, venc_size);
490                         goto fail;
491                 }
492         }
493
494         if(!ioctl(self->encoder->fd, VENC_SET_PROFILE, &info->profile))
495                 GST_INFO_OBJECT (self, "set profile to %d -> ioctl(%d, VENC_SET_PROFILE)", info->profile, self->encoder->fd);
496         else
497                 GST_WARNING_OBJECT (self, "can't set profile to %d -> ioctl(%d, VENC_SET_PROFILE)", info->profile, self->encoder->fd);
498
499         self->video_info = *info;
500         g_mutex_unlock (&self->mutex);
501         return TRUE;
502
503 fail:
504         g_mutex_unlock (&self->mutex);
505         return FALSE;
506 }
507
508 void gst_dreamvideosource_set_input_mode (GstDreamVideoSource *self, GstDreamVideoSourceInputMode mode)
509 {
510         g_return_if_fail (GST_IS_DREAMVIDEOSOURCE (self));
511         GEnumValue *val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (GST_TYPE_DREAMVIDEOSOURCE_INPUT_MODE)), mode);
512         if (!val)
513         {
514                 GST_ERROR_OBJECT (self, "no such input_mode %i!", mode);
515                 return;
516         }
517         const gchar *value_nick = val->value_nick;
518
519         g_mutex_lock (&self->mutex);
520         if (!self->encoder || !self->encoder->fd)
521         {
522                 self->input_mode = mode;
523                 goto out;
524         }
525         int int_mode = mode;
526         int ret = ioctl(self->encoder->fd, VENC_SET_SOURCE, &int_mode);
527         if (ret != 0)
528         {
529                 GST_WARNING_OBJECT (self, "can't set input mode to %s (%i) error: %s", value_nick, mode, strerror(errno));
530                 goto out;
531         }
532         GST_INFO_OBJECT (self, "successfully set input mode to %s (%i)", value_nick, mode);
533         self->input_mode = mode;
534
535 out:
536         g_mutex_unlock (&self->mutex);
537         return;
538 }
539
540 GstDreamVideoSourceInputMode gst_dreamvideosource_get_input_mode (GstDreamVideoSource *self)
541 {
542         GstDreamVideoSourceInputMode result;
543         g_return_val_if_fail (GST_IS_DREAMVIDEOSOURCE (self), -1);
544         g_mutex_lock (&self->mutex);
545         result =self->input_mode;
546         g_mutex_unlock (&self->mutex);
547         return result;
548 }
549
550 gboolean
551 gst_dreamvideosource_plugin_init (GstPlugin *plugin)
552 {
553         GST_DEBUG_CATEGORY_INIT (dreamvideosource_debug, "dreamvideosource", 0, "dreamvideosource");
554         return gst_element_register (plugin, "dreamvideosource", GST_RANK_PRIMARY, GST_TYPE_DREAMVIDEOSOURCE);
555 }
556
557 static void
558 gst_dreamvideosource_init (GstDreamVideoSource * self)
559 {
560         self->current_caps = NULL;
561         self->new_caps = NULL;
562
563         self->dts_valid = FALSE;
564         self->encoder = NULL;
565         self->descriptors_available = 0;
566         self->input_mode = DEFAULT_INPUT_MODE;
567
568         self->buffer_size = DEFAULT_BUFFER_SIZE;
569         g_queue_init (&self->current_frames);
570         self->readthread = NULL;
571
572         g_mutex_init (&self->mutex);
573         g_cond_init (&self->cond);
574         READ_SOCKET (self) = -1;
575         WRITE_SOCKET (self) = -1;
576
577         gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
578         gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
579
580         self->encoder = NULL;
581         self->encoder_clock = NULL;
582
583 #ifdef dump
584         self->dumpfd = open("/media/hdd/movie/dreamvideosource.dump", O_WRONLY | O_CREAT | O_TRUNC);
585         GST_DEBUG_OBJECT (self, "dumpfd = %i (%s)", self->dumpfd, (self->dumpfd > 0) ? "OK" : strerror(errno));
586 #endif
587 }
588
589 static gboolean gst_dreamvideosource_encoder_init (GstDreamVideoSource * self)
590 {
591         GST_LOG_OBJECT (self, "initializating encoder...");
592         self->encoder = malloc (sizeof(EncoderInfo));
593
594         if (!self->encoder) {
595                 GST_ERROR_OBJECT (self,"out of space");
596                 return FALSE;
597         }
598
599         char fn_buf[32];
600         sprintf(fn_buf, "/dev/venc%d", 0);
601         self->encoder->fd = open(fn_buf, O_RDWR | O_SYNC);
602         if (self->encoder->fd <= 0) {
603                 GST_ERROR_OBJECT (self,"cannot open device %s (%s)", fn_buf, strerror(errno));
604                 free(self->encoder);
605                 self->encoder = NULL;
606                 return FALSE;
607         }
608
609         self->encoder->buffer = malloc(VBUFSIZE);
610         if (!self->encoder->buffer) {
611                 GST_ERROR_OBJECT(self,"cannot alloc buffer");
612                 return FALSE;
613         }
614
615         self->encoder->cdb = (unsigned char *)mmap (0, VMMAPSIZE, PROT_READ, MAP_PRIVATE, self->encoder->fd, 0);
616
617         if (!self->encoder->cdb || self->encoder->cdb == MAP_FAILED) {
618                 GST_ERROR_OBJECT(self, "cannot alloc buffer: %s (%i)", strerror(errno), errno);
619                 self->encoder->cdb = NULL;
620                 return FALSE;
621         }
622
623         int control_sock[2];
624         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
625         {
626                 GST_ERROR_OBJECT(self, "cannot create control sockets: %s (%i)", strerror(errno), errno);
627                 return FALSE;
628         }
629         READ_SOCKET (self) = control_sock[0];
630         WRITE_SOCKET (self) = control_sock[1];
631         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
632         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
633
634         gst_dreamvideosource_set_bitrate (self, self->video_info.bitrate);
635         gst_dreamvideosource_set_goplen(self, self->video_info.gop_length);
636         gst_dreamvideosource_set_bframes(self,  self->video_info.bframes);
637         gst_dreamvideosource_set_pframes(self,  self->video_info.pframes);
638         gst_dreamvideosource_set_gop_on_scene_change(self, self->video_info.gop_scene);
639         gst_dreamvideosource_set_open_gop(self, self->video_info.open_gop);
640         gst_dreamvideosource_set_slices(self, self->video_info.slices);
641         gst_dreamvideosource_set_level(self, self->video_info.level);
642         gst_dreamvideosource_set_format (self, &self->video_info);
643         gst_dreamvideosource_set_input_mode (self, self->input_mode);
644
645         GST_LOG_OBJECT (self, "encoder %s successfully initialized", fn_buf);
646         return TRUE;
647 }
648
649 static void gst_dreamvideosource_encoder_release (GstDreamVideoSource * self)
650 {
651         GST_LOG_OBJECT (self, "releasing encoder...");
652         if (self->encoder) {
653                 if (self->encoder->buffer)
654                         free(self->encoder->buffer);
655                 if (self->encoder->cdb)
656                         munmap(self->encoder->cdb, VMMAPSIZE);
657                 if (self->encoder->fd)
658                         close(self->encoder->fd);
659                 free(self->encoder);
660         }
661         self->encoder = NULL;
662         close (READ_SOCKET (self));
663         close (WRITE_SOCKET (self));
664         READ_SOCKET (self) = -1;
665         WRITE_SOCKET (self) = -1;
666         if (self->encoder_clock) {
667                 gst_object_unref (self->encoder_clock);
668                 self->encoder_clock = NULL;
669         }
670 }
671
672 static void
673 gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
674 {
675         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
676
677         switch (prop_id) {
678                 case ARG_CAPS:
679                 {
680                         if (self->new_caps)
681                                 gst_caps_unref (self->new_caps);
682                         self->new_caps = gst_caps_copy (gst_value_get_caps (value));
683                         gst_pad_mark_reconfigure (GST_BASE_SRC_PAD (GST_BASE_SRC(object)));
684                         break;
685                 }
686                 case ARG_BITRATE:
687                         gst_dreamvideosource_set_bitrate(self, g_value_get_int (value));
688                         break;
689                 case ARG_INPUT_MODE:
690                         gst_dreamvideosource_set_input_mode (self, g_value_get_enum (value));
691                         break;
692                 case ARG_GOP_LENGTH:
693                         gst_dreamvideosource_set_goplen(self, g_value_get_int (value));
694                         break;
695                 case ARG_GOP_SCENE:
696                         gst_dreamvideosource_set_gop_on_scene_change(self, g_value_get_boolean (value));
697                         break;
698                 case ARG_OPEN_GOP:
699                         gst_dreamvideosource_set_open_gop(self, g_value_get_boolean (value));
700                         break;
701                 case ARG_BFRAMES:
702                         gst_dreamvideosource_set_bframes(self, g_value_get_int (value));
703                         break;
704                 case ARG_PFRAMES:
705                         gst_dreamvideosource_set_pframes(self, g_value_get_int (value));
706                         break;
707                 case ARG_SLICES:
708                         gst_dreamvideosource_set_slices(self, g_value_get_int (value));
709                         break;
710                 case ARG_LEVEL:
711                         gst_dreamvideosource_set_level(self, g_value_get_int (value));
712                         break;
713                 default:
714                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
715                         break;
716         }
717 }
718
719 static void
720 gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
721 {
722         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
723
724         switch (prop_id) {
725                 case ARG_CAPS:
726                         g_value_take_boxed (value, gst_dreamvideosource_getcaps (GST_BASE_SRC(object), GST_CAPS_ANY));
727                         break;
728                 case ARG_BITRATE:
729                         g_value_set_int (value, self->video_info.bitrate);
730                         break;
731                 case ARG_INPUT_MODE:
732                         g_value_set_enum (value, gst_dreamvideosource_get_input_mode (self));
733                         break;
734                 case ARG_GOP_LENGTH:
735                         g_value_set_int(value, self->video_info.gop_length);
736                         break;
737                 case ARG_GOP_SCENE:
738                         g_value_set_boolean(value, self->video_info.gop_scene);
739                         break;
740                 case ARG_OPEN_GOP:
741                         g_value_set_boolean(value, self->video_info.open_gop);
742                         break;
743                 case ARG_BFRAMES:
744                         g_value_set_int(value, self->video_info.bframes);
745                         break;
746                 case ARG_PFRAMES:
747                         g_value_set_int(value, self->video_info.pframes);
748                         break;
749                 case ARG_SLICES:
750                         g_value_set_int(value, self->video_info.slices);
751                         break;
752                 case ARG_LEVEL:
753                         g_value_set_int(value, self->video_info.level);
754                         break;
755                 default:
756                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
757                         break;
758         }
759 }
760
761 static GstCaps *
762 gst_dreamvideosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
763 {
764         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
765         GstCaps *caps;
766
767         g_mutex_lock (&self->mutex);
768         if (self->new_caps)
769         {
770                 GST_DEBUG_OBJECT (self, "gst_dreamvideosource_getcaps has new_caps: %" GST_PTR_FORMAT " / current_caps: %" GST_PTR_FORMAT "", self->new_caps, self->current_caps);
771                 if (self->current_caps)
772                 {
773                         caps = gst_caps_new_empty ();
774                         gst_caps_replace (&caps, self->new_caps);
775                         self->new_caps = NULL;
776                 }
777                 else
778                         caps = gst_caps_copy (self->new_caps);
779         } else if (self->current_caps == NULL) {
780                 GstPadTemplate *pad_template;
781                 pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS(self), "src");
782                 if (pad_template)
783                         caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
784                 else
785                         caps = gst_caps_new_empty ();
786
787                 caps = gst_pad_template_get_caps (pad_template);
788         } else
789                 caps = gst_caps_copy(self->current_caps);
790
791         GST_LOG_OBJECT (self, "gst_dreamvideosource_getcaps %" GST_PTR_FORMAT " filter %" GST_PTR_FORMAT, caps, filter);
792
793         if (filter) {
794                 GstCaps *intersection;
795                 intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
796                 gst_caps_unref (caps);
797                 caps = intersection;
798         }
799
800         GST_LOG_OBJECT (self, "return caps %" GST_PTR_FORMAT, caps);
801         g_mutex_unlock (&self->mutex);
802         return caps;
803 }
804
805 static gboolean
806 gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
807 {
808         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
809         GstCaps *current_caps;
810         const GstStructure *structure;
811         VideoFormatInfo info;
812         gboolean ret;
813         const GValue *framerate;
814         gint *profile;
815
816         g_mutex_lock (&self->mutex);
817         structure = gst_caps_get_structure (caps, 0);
818
819         current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc));
820
821         GST_LOG_OBJECT (self, "gst_dreamvideosource_setcaps parameter %" GST_PTR_FORMAT " self->current_caps=%" GST_PTR_FORMAT " pad's current_caps=%" GST_PTR_FORMAT "  new_caps=%" GST_PTR_FORMAT"", caps, current_caps, self->current_caps, self->new_caps);
822
823         if (current_caps && gst_caps_is_equal (current_caps, caps)) {
824                 GST_LOG_OBJECT (self, "New caps equal to old ones: %" GST_PTR_FORMAT, caps);
825                 ret = TRUE;
826         } else {
827                 GstState state;
828                 gst_element_get_state (GST_ELEMENT(self), &state, NULL, 1*GST_MSECOND);
829                 if (state == GST_STATE_PLAYING)
830                 {
831                         GST_WARNING_OBJECT (self, "can't change caps while in PLAYING state %" GST_PTR_FORMAT, caps);
832                         g_mutex_unlock (&self->mutex);
833                         return TRUE;
834                 }
835                 else if (gst_structure_has_name (structure, "video/x-h264"))
836                 {
837                         memset (&info, 0, sizeof(VideoFormatInfo));
838                         ret = gst_structure_get_int (structure, "width", &info.width);
839                         ret &= gst_structure_get_int (structure, "height", &info.height);
840                         framerate = gst_structure_get_value (structure, "framerate");
841                         if (GST_VALUE_HOLDS_FRACTION(framerate)) {
842                                 info.fps_n = gst_value_get_fraction_numerator (framerate);
843                                 info.fps_d = gst_value_get_fraction_denominator (framerate);
844                         }
845                         GST_DEBUG_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
846
847                         const gchar* profile = gst_structure_get_string(structure, "profile");
848
849                         info.profile = profile_main;
850
851                         if (!profile)
852                                 GST_WARNING_OBJECT (self, "profile missing in caps... set main progile");
853                         else if (!g_strcmp0 (profile, "high"))
854                                 info.profile = profile_high;
855                         else if (!g_strcmp0 (profile, "main"))
856                                 info.profile = profile_main;
857                         else
858                                 GST_WARNING_OBJECT (self, "unknown profile '%s' in caps... set main profile");
859
860                         gst_caps_replace (&self->current_caps, caps);
861
862                         g_mutex_unlock (&self->mutex);
863                         if (gst_caps_is_fixed(caps) && gst_dreamvideosource_set_format(self, &info))
864                                 ret = gst_pad_push_event (bsrc->srcpad, gst_event_new_caps (caps));
865                         g_mutex_lock (&self->mutex);
866                 }
867                 else {
868                         GST_WARNING_OBJECT (self, "unsupported caps: %" GST_PTR_FORMAT, caps);
869                         ret = FALSE;
870                 }
871         }
872         if (current_caps)
873                 gst_caps_unref (current_caps);
874
875         g_mutex_unlock (&self->mutex);
876         return ret;
877 }
878
879 static GstCaps *
880 gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps)
881 {
882         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
883         GstStructure *structure;
884
885         caps = gst_caps_make_writable (caps);
886         structure = gst_caps_get_structure (caps, 0);
887
888         if (gst_structure_has_field (structure, "width"))
889                 gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
890         if (gst_structure_has_field (structure, "height"))
891                 gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
892         if (gst_structure_has_field (structure, "framerate"))
893                 gst_structure_fixate_field_nearest_fraction (structure, "framerate", DEFAULT_FRAMERATE, 1);
894         if (gst_structure_has_field (structure, "display-aspect-ratio"))
895                 gst_structure_fixate_field_nearest_fraction (structure, "display-aspect-ratio", DEFAULT_WIDTH, DEFAULT_HEIGHT);
896
897         caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
898         GST_DEBUG_OBJECT (self, "fixated caps: %" GST_PTR_FORMAT, caps);
899         return caps;
900 }
901
902 static gboolean gst_dreamvideosource_query (GstBaseSrc * bsrc, GstQuery * query)
903 {
904         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
905         gboolean ret = TRUE;
906
907         switch (GST_QUERY_TYPE (query)) {
908                 case GST_QUERY_LATENCY:{
909                         if (self->video_info.fps_n) {
910                                 GstClockTime min, max;
911
912                                 g_mutex_lock (&self->mutex);
913                                 min = gst_util_uint64_scale_ceil (GST_SECOND, self->video_info.fps_d, self->video_info.fps_n);
914                                 g_mutex_unlock (&self->mutex);
915
916                                 max = self->buffer_size * min;
917
918                                 gst_query_set_latency (query, TRUE, min, max);
919                                 GST_DEBUG_OBJECT (bsrc, "set LATENCY QUERY %" GST_PTR_FORMAT, query);
920                                 ret = TRUE;
921                         } else {
922                                 ret = FALSE;
923                         }
924                         break;
925                 }
926                 default:
927                         ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
928                         break;
929         }
930         return ret;
931 }
932
933 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc)
934 {
935         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
936         GST_DEBUG_OBJECT (self, "stop creating buffers");
937         g_mutex_lock (&self->mutex);
938         self->flushing = TRUE;
939         GST_DEBUG_OBJECT (self, "set flushing TRUE");
940         g_cond_signal (&self->cond);
941         GST_DEBUG_OBJECT (self, "post cond");
942         g_mutex_unlock (&self->mutex);
943         GST_DEBUG_OBJECT (self, "post unlock");
944         return TRUE;
945 }
946
947 static gboolean gst_dreamvideosource_unlock_stop (GstBaseSrc * bsrc)
948 {
949         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
950         GST_DEBUG_OBJECT (self, "stop flushing...");
951         g_mutex_lock (&self->mutex);
952         self->flushing = FALSE;
953         g_queue_foreach (&self->current_frames, (GFunc) gst_buffer_unref, NULL);
954         g_queue_clear (&self->current_frames);
955         g_mutex_unlock (&self->mutex);
956         return TRUE;
957 }
958
959 static void gst_dreamvideosource_read_thread_func (GstDreamVideoSource * self)
960 {
961         EncoderInfo *enc = self->encoder;
962         GstDreamSourceReadthreadState state = READTHREADSTATE_NONE;
963         GstBuffer *readbuf;
964
965         if (!enc) {
966                 GST_WARNING_OBJECT (self, "encoder device not opened!");
967                 return;
968         }
969
970         GST_DEBUG_OBJECT (self, "enter read thread");
971
972         GstMessage *message;
973         GValue val = { 0 };
974
975         message = gst_message_new_stream_status (GST_OBJECT_CAST (self), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (GST_OBJECT_PARENT(self)));
976         g_value_init (&val, GST_TYPE_G_THREAD);
977         g_value_set_boxed (&val, self->readthread);
978         gst_message_set_stream_status_object (message, &val);
979         g_value_unset (&val);
980         GST_DEBUG_OBJECT (self, "posting ENTER stream status");
981         gst_element_post_message (GST_ELEMENT_CAST (self), message);
982         GstClockTime clock_time, base_time;
983         gboolean discont = TRUE;
984
985         while (TRUE) {
986                 readbuf = NULL;
987                 {
988                         if (state == READTHREADSTATE_STOP)
989                                 goto stop_running;
990
991                         struct pollfd rfd[2];
992                         int timeout, nfds;
993
994                         rfd[0].fd = READ_SOCKET (self);
995                         rfd[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
996                         rfd[1].revents = 0;
997                         rfd[1].events = POLLIN;
998                         nfds = 1;
999                         timeout = 0;
1000
1001                         if (state <= READTRREADSTATE_PAUSED)
1002                                 timeout = 200;
1003                         else if (state == READTRREADSTATE_RUNNING && self->descriptors_available == 0)
1004                         {
1005                                 rfd[1].fd = enc->fd;
1006                                 self->descriptors_count = 0;
1007                                 timeout = 200;
1008                                 nfds = 2;
1009                         }
1010
1011                         int ret = poll(rfd, nfds, timeout);
1012
1013                         if (G_UNLIKELY (ret == -1))
1014                         {
1015                                 GST_ERROR_OBJECT (self, "SELECT ERROR!");
1016                                 goto stop_running;
1017                         }
1018                         else if ( ret == 0 && self->descriptors_available == 0 )
1019                         {
1020                                 g_mutex_lock (&self->mutex);
1021                                 gst_clock_get_internal_time(self->encoder_clock);
1022                                 g_mutex_unlock (&self->mutex);
1023                                 GST_DEBUG_OBJECT (self, "SELECT TIMEOUT");
1024                                 discont = TRUE;
1025 //                              readbuf = gst_buffer_new();
1026                         }
1027                         else if ( rfd[0].revents )
1028                         {
1029                                 char command;
1030                                 READ_COMMAND (self, command, ret);
1031                                 switch (command) {
1032                                         case CONTROL_STOP:
1033                                                 GST_DEBUG_OBJECT (self, "CONTROL_STOP!");
1034                                                 state = READTHREADSTATE_STOP;
1035                                                 break;
1036                                         case CONTROL_PAUSE:
1037                                                 GST_DEBUG_OBJECT (self, "CONTROL_PAUSE!");
1038                                                 state = READTRREADSTATE_PAUSED;
1039                                                 break;
1040                                         case CONTROL_RUN:
1041                                                 GST_DEBUG_OBJECT (self, "CONTROL_RUN");
1042                                                 state = READTRREADSTATE_RUNNING;
1043                                                 break;
1044                                         default:
1045                                                 GST_ERROR_OBJECT (self, "illegal control socket command %c received!", command);
1046                                 }
1047                                 continue;
1048                         }
1049                         else if ( G_LIKELY(rfd[1].revents & POLLIN) )
1050                         {
1051                                 int rlen = read(enc->fd, enc->buffer, VBUFSIZE);
1052                                 if (G_UNLIKELY (!self->encoder_clock))
1053                                 {
1054                                         GST_DEBUG_OBJECT(self, "no encoder clock yet... continue");
1055                                         continue;
1056                                 }
1057                                 clock_time = gst_clock_get_internal_time (self->encoder_clock);
1058                                 base_time = gst_element_get_base_time(GST_ELEMENT(self));
1059                                 if (rlen <= 0 || rlen % VBDSIZE ) {
1060                                         if ( errno == 512 )
1061                                                 goto stop_running;
1062                                         GST_WARNING_OBJECT (self, "read error %s (%i)", strerror(errno), errno);
1063                                         goto stop_running;
1064                                 }
1065                                 self->descriptors_available = rlen / VBDSIZE;
1066                                 GST_LOG_OBJECT (self, "encoder buffer was empty, %d descriptors available", self->descriptors_available);
1067                         }
1068                         if (self->flushing)
1069                         {
1070                                 g_mutex_lock (&self->mutex);
1071                                 GST_DEBUG_OBJECT (self, "FLUSHING!");
1072                                 g_cond_signal (&self->cond);
1073                                 g_mutex_unlock (&self->mutex);
1074                                 continue;
1075                         }
1076                 }
1077
1078                 while (self->descriptors_count < self->descriptors_available)
1079                 {
1080                         GstClockTime encoder_dts = GST_CLOCK_TIME_NONE;
1081                         GstClockTime encoder_pts = GST_CLOCK_TIME_NONE;
1082                         GstClockTime result_dts = GST_CLOCK_TIME_NONE;
1083                         GstClockTime result_pts = GST_CLOCK_TIME_NONE;
1084                         gint64 dts_pts_offset;
1085                         gboolean skip_frame = FALSE;
1086
1087                         off_t offset = self->descriptors_count * VBDSIZE;
1088                         VideoBufferDescriptor *desc = (VideoBufferDescriptor*)(&enc->buffer[offset]);
1089
1090                         uint32_t f = desc->stCommon.uiFlags;
1091
1092                         GST_LOG_OBJECT (self, "descriptors_count=%d, descriptors_available=%d\tuiOffset=%d, uiLength=%d", self->descriptors_count, self->descriptors_available, desc->stCommon.uiOffset, desc->stCommon.uiLength);
1093
1094                         if (G_UNLIKELY (f & CDB_FLAG_METADATA))
1095                         {
1096                                 GST_LOG_OBJECT (self, "CDB_FLAG_METADATA... skip outdated packet");
1097                                 self->descriptors_count = self->descriptors_available;
1098                                 continue;
1099                         }
1100
1101                         // uiDTS since kernel driver booted
1102                         if (f & VBD_FLAG_DTS_VALID && desc->uiDTS)
1103                         {
1104                                 encoder_dts = MPEGTIME_TO_GSTTIME(desc->uiDTS);
1105                                 GST_LOG_OBJECT (self, "f & VBD_FLAG_DTS_VALID && encoder's uiDTS=%" GST_TIME_FORMAT"", GST_TIME_ARGS(encoder_dts));
1106
1107                                 g_mutex_lock (&self->mutex);
1108                                 if (G_UNLIKELY (self->dts_offset == GST_CLOCK_TIME_NONE && self->flushing == FALSE))
1109                                 {
1110                                         if (self->dreamaudiosrc)
1111                                         {
1112                                                 guint64 audiosource_dts_offset;
1113                                                 g_signal_emit_by_name(self->dreamaudiosrc, "get-dts-offset", &audiosource_dts_offset);
1114                                                 if (audiosource_dts_offset != GST_CLOCK_TIME_NONE)
1115                                                 {
1116                                                         GST_DEBUG_OBJECT (self, "use DREAMAUDIOSOURCE's dts_offset=%" GST_TIME_FORMAT "", GST_TIME_ARGS (audiosource_dts_offset) );
1117                                                         self->dts_offset = audiosource_dts_offset;
1118                                                 }
1119                                         }
1120                                         else if (self->dts_offset == GST_CLOCK_TIME_NONE)
1121                                         {
1122                                                 self->dts_offset = encoder_dts - clock_time;
1123                                                 GST_DEBUG_OBJECT (self, "use encoder_dts-clock_time as dts_offset (%" GST_TIME_FORMAT" = %" GST_TIME_FORMAT" - %" GST_TIME_FORMAT")", GST_TIME_ARGS (self->dts_offset), GST_TIME_ARGS (encoder_dts), GST_TIME_ARGS (clock_time));
1124                                         }
1125                                 }
1126                                 if (G_UNLIKELY (self->dts_valid == FALSE && self->dts_offset != GST_CLOCK_TIME_NONE))
1127                                         self->dts_valid = TRUE;
1128                                 g_mutex_unlock (&self->mutex);
1129                         }
1130
1131                         g_mutex_lock (&self->mutex);
1132                         if (G_UNLIKELY (self->dts_valid == FALSE))
1133                         {
1134                                 GST_DEBUG_OBJECT (self, "dts_valid not set, skipping frame...");
1135                                 self->descriptors_count++;
1136                                 g_mutex_unlock (&self->mutex);
1137                                 break;
1138                         }
1139                         else
1140                                 g_mutex_unlock (&self->mutex);
1141
1142                         if (G_UNLIKELY (encoder_dts < self->dts_offset))
1143                         {
1144                                 GST_DEBUG_OBJECT (self, "encoder_dts < dts_offset, skipping frame...");
1145                                 skip_frame = TRUE;
1146                         }
1147 //                      if (self->video_info.fps_d)
1148 //                              GST_BUFFER_DURATION(readbuf) = gst_util_uint64_scale (GST_SECOND, self->video_info.fps_d, self->video_info.fps_n);
1149
1150                         if (!skip_frame && encoder_dts != GST_CLOCK_TIME_NONE)
1151                         {
1152                                 if (f & CDB_FLAG_PTS_VALID)
1153                                         encoder_pts = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
1154                                 else
1155                                         encoder_pts = encoder_dts;
1156                                 dts_pts_offset = encoder_pts - encoder_dts;
1157
1158                                 GstClockTime orig_dts_clock_time = encoder_dts - self->dts_offset;
1159                                 GstClockTime orig_pts_clock_time = orig_dts_clock_time + dts_pts_offset;
1160                                 GstClockTime calib_dts_clock_time = orig_dts_clock_time;
1161
1162                                 GstClockTime internal, external;
1163                                 GstClockTime rate_n, rate_d;
1164                                 GstClockTimeDiff diff;
1165
1166                                 gst_clock_get_calibration (self->encoder_clock, &internal, &external, &rate_n, &rate_d);
1167
1168                                 if (internal > orig_dts_clock_time) {
1169                                         diff = internal - orig_dts_clock_time;
1170                                         diff = gst_util_uint64_scale (diff, rate_n, rate_d);
1171                                         calib_dts_clock_time = external - diff;
1172                                 } else {
1173                                         diff = orig_dts_clock_time - internal;
1174                                         diff = gst_util_uint64_scale (diff, rate_n, rate_d);
1175                                         calib_dts_clock_time = external + diff;
1176                                 }
1177
1178                                 if ( calib_dts_clock_time < base_time )
1179                                 {
1180                                         GST_DEBUG_OBJECT (self, "calib_dts_clock_time < base_time, skipping frame...");
1181                                         skip_frame = TRUE;
1182                                 }
1183                                 result_dts = calib_dts_clock_time - base_time;
1184                                 result_pts = result_dts + dts_pts_offset;
1185
1186 #define extra_timestamp_debug
1187 #ifdef extra_timestamp_debug
1188                                 GstClockTime my_int_time = gst_clock_get_internal_time(self->encoder_clock);
1189                                 GstClockTime pipeline_int_time = GST_CLOCK_TIME_NONE;
1190                                 GstClock *elemclk = gst_element_get_clock (GST_ELEMENT (self));
1191                                 if (elemclk)
1192                                 {
1193                                         pipeline_int_time = gst_clock_get_internal_time(elemclk);
1194                                         gst_object_unref (elemclk);
1195                                 }
1196
1197                                 GST_LOG_OBJECT (self, "post-calibration\n"
1198                                 "  %" GST_TIME_FORMAT " =base_time       %" GST_TIME_FORMAT " =clock_time            %" PRId64 " =dts_pts_offset\n"
1199                                 "  %" GST_TIME_FORMAT " =encoder_dts     %" GST_TIME_FORMAT " =orig_dts_clock_time   %" GST_TIME_FORMAT " =calib_dts_clock_time   %" GST_TIME_FORMAT " =result_dts\n"
1200                                 "  %" GST_TIME_FORMAT " =encoder_pts     %" GST_TIME_FORMAT " =orig_pts_clock_time                                            %" GST_TIME_FORMAT " =result_pts\n"
1201                                 "  %" GST_TIME_FORMAT " =internal        %" GST_TIME_FORMAT " =external              %" GST_TIME_FORMAT " =diff                   %" PRId64 "/%" PRId64 " =rate\n"
1202                                 "  %" GST_TIME_FORMAT " =my_int_time     %" GST_TIME_FORMAT " =pipeline_int_time"
1203                                 ,
1204                                 GST_TIME_ARGS (base_time), GST_TIME_ARGS (clock_time), dts_pts_offset,
1205                                 GST_TIME_ARGS (encoder_dts), GST_TIME_ARGS (orig_dts_clock_time), GST_TIME_ARGS (calib_dts_clock_time), GST_TIME_ARGS (result_dts),
1206                                 GST_TIME_ARGS (encoder_pts), GST_TIME_ARGS (orig_pts_clock_time), GST_TIME_ARGS (result_pts),
1207                                 GST_TIME_ARGS (internal), GST_TIME_ARGS (external), GST_TIME_ARGS (diff), rate_n, rate_d,
1208                                 GST_TIME_ARGS (my_int_time), GST_TIME_ARGS (pipeline_int_time)
1209                                 );
1210 #endif
1211                         }
1212
1213                         if (!skip_frame)
1214                         {
1215                                 readbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, enc->cdb, VMMAPSIZE, desc->stCommon.uiOffset, desc->stCommon.uiLength, self, NULL);
1216                                 if (result_dts != GST_CLOCK_TIME_NONE)
1217                                 {
1218                                         GST_BUFFER_DTS(readbuf) = result_dts;
1219                                         GST_BUFFER_PTS(readbuf) = result_pts;
1220                                 }
1221                         }
1222
1223 #ifdef dump
1224                         int wret = write(self->dumpfd, (unsigned char*)(enc->cdb + desc->stCommon.uiOffset), desc->stCommon.uiLength);
1225                         GST_LOG_OBJECT (self, "read %i dumped %i total %" G_GSIZE_FORMAT " ", desc->stCommon.uiLength, wret, gst_buffer_get_size (*outbuf) );
1226 #endif
1227                         self->descriptors_count++;
1228                         break;
1229                 }
1230
1231                 if (self->descriptors_count == self->descriptors_available)
1232                 {
1233                         GST_LOG_OBJECT (self, "self->descriptors_count == self->descriptors_available -> release %i consumed descriptors", self->descriptors_count);
1234                         if (state == READTHREADSTATE_STOP)
1235                                 GST_DEBUG_OBJECT (self, "readthread stopping, don't write to fd anymore!");
1236                         /* release consumed descs */
1237                         else if (write(enc->fd, &self->descriptors_count, sizeof(self->descriptors_count)) != sizeof(self->descriptors_count)) {
1238                                 GST_WARNING_OBJECT (self, "release consumed descs write error!");
1239                                 goto stop_running;
1240                         }
1241                         self->descriptors_available = 0;
1242                 }
1243
1244                 if (readbuf)
1245                 {
1246                         g_mutex_lock (&self->mutex);
1247                         if (!self->flushing)
1248                         {
1249                                 while (g_queue_get_length (&self->current_frames) >= self->buffer_size)
1250                                 {
1251                                         GstBuffer * oldbuf = g_queue_pop_head (&self->current_frames);
1252                                         GST_WARNING_OBJECT (self, "dropping %" GST_PTR_FORMAT " because of queue overflow! buffers count=%i", oldbuf, g_queue_get_length (&self->current_frames));
1253                                         gst_buffer_unref(oldbuf);
1254                                         GST_BUFFER_FLAG_SET ((GstBuffer *) g_queue_peek_head (&self->current_frames), GST_BUFFER_FLAG_DISCONT);
1255                                 }
1256                                 if (discont)
1257                                 {
1258                                         GST_BUFFER_FLAG_SET (readbuf, GST_BUFFER_FLAG_DISCONT);
1259                                         discont = FALSE;
1260                                 }
1261                                 g_queue_push_tail (&self->current_frames, readbuf);
1262                                 GST_INFO_OBJECT (self, "read %" GST_PTR_FORMAT " to queue... buffers count=%i", readbuf, g_queue_get_length (&self->current_frames));
1263                                 g_cond_signal (&self->cond);
1264                         }
1265                         else
1266                                 gst_buffer_unref(readbuf);
1267 //                      g_cond_signal (&self->cond);
1268                         g_mutex_unlock (&self->mutex);
1269                 }
1270         }
1271
1272         g_assert_not_reached ();
1273         return;
1274
1275         stop_running:
1276         {
1277 //              g_mutex_unlock (&self->mutex);
1278                 g_cond_signal (&self->cond);
1279                 GST_DEBUG ("stop running, exit thread");
1280                 message = gst_message_new_stream_status (GST_OBJECT_CAST (self), GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (GST_OBJECT_PARENT(self)));
1281                 g_value_init (&val, GST_TYPE_G_THREAD);
1282                 g_value_set_boxed (&val, self->readthread);
1283                 gst_message_set_stream_status_object (message, &val);
1284                 g_value_unset (&val);
1285                 GST_DEBUG_OBJECT (self, "posting LEAVE stream status");
1286                 gst_element_post_message (GST_ELEMENT_CAST (self), message);
1287                 return;
1288         }
1289 }
1290
1291 static GstFlowReturn
1292 gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf)
1293 {
1294         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (psrc);
1295
1296         GST_LOG_OBJECT (self, "new buffer requested. queue has %i buffers", g_queue_get_length (&self->current_frames));
1297
1298         g_mutex_lock (&self->mutex);
1299         while (g_queue_is_empty (&self->current_frames) && !self->flushing)
1300         {
1301                 GST_INFO_OBJECT (self, "waiting for buffer from encoder");
1302                 g_cond_wait (&self->cond, &self->mutex);
1303         }
1304
1305         *outbuf = g_queue_pop_head (&self->current_frames);
1306         g_mutex_unlock (&self->mutex);
1307
1308         if (*outbuf)
1309         {
1310                 GST_INFO_OBJECT (self, "pushing %" GST_PTR_FORMAT ". queue has %i buffers", *outbuf, g_queue_get_length (&self->current_frames));
1311                 return GST_FLOW_OK;
1312         }
1313         GST_INFO_OBJECT (self, "FLUSHING");
1314         return GST_FLOW_FLUSHING;
1315 }
1316
1317
1318 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition)
1319 {
1320         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
1321         GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS;
1322         int ret;
1323
1324         switch (transition) {
1325                 case GST_STATE_CHANGE_NULL_TO_READY:
1326                 {
1327                         if (!gst_dreamvideosource_encoder_init (self))
1328                         {
1329                                 GError *err = g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ, "Can't initialize encoder device");
1330                                 GstMessage *msg = gst_message_new_error (GST_OBJECT (self), err, NULL);
1331                                 gst_element_post_message (element, msg);
1332                                 g_error_free (err);
1333                                 return GST_STATE_CHANGE_FAILURE;
1334                         }
1335                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_NULL_TO_READY");
1336                         break;
1337                 }
1338                 case GST_STATE_CHANGE_READY_TO_PAUSED:
1339                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
1340                         self->dreamaudiosrc = gst_bin_get_by_name_recurse_up(GST_BIN(GST_ELEMENT_PARENT(self)), "dreamaudiosource0");
1341                 #ifdef PROVIDE_CLOCK
1342                         if (self->dreamaudiosrc)
1343                         {
1344                                 self->encoder_clock = gst_element_provide_clock (self->dreamaudiosrc);
1345                                 GST_DEBUG_OBJECT (self, "using dreamaudiosrc's encoder_clock = %" GST_PTR_FORMAT, self->encoder_clock);
1346                         } else {
1347                                 self->encoder_clock = gst_dreamsource_clock_new ("GstDreamVideoSourceClock", self->encoder->fd);
1348                                 GST_OBJECT_FLAG_SET (self, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
1349                                 GstMessage* msg;
1350                                 msg = gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->encoder_clock, TRUE);
1351                                 GST_DEBUG_OBJECT (self, "new clock: %" GST_PTR_FORMAT " %" GST_PTR_FORMAT " typename=%s", self->encoder_clock, msg, GST_MESSAGE_TYPE_NAME(msg));
1352                                 gst_element_post_message (element, msg);
1353                         }
1354                 #endif
1355                         self->dts_offset = GST_CLOCK_TIME_NONE;
1356                         self->flushing = TRUE;
1357                         self->readthread = g_thread_try_new ("dreamvideosrc-read", (GThreadFunc) gst_dreamvideosource_read_thread_func, self, NULL);
1358                         GST_DEBUG_OBJECT (self, "started readthread @%p", self->readthread );
1359                         break;
1360                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1361                         g_mutex_lock (&self->mutex);
1362                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
1363                         self->dts_valid = FALSE;
1364                         GstClock *pipeline_clock = gst_element_get_clock (GST_ELEMENT (self));
1365                         if (pipeline_clock)
1366                         {
1367                                 if (self->dreamaudiosrc)
1368                                         GST_DEBUG_OBJECT (self, "dreamaudiosource owns the clock and is responsible for slaving it");
1369                                 else if (pipeline_clock != self->encoder_clock)
1370                                 {
1371                                         gst_clock_set_master (self->encoder_clock, pipeline_clock);
1372                                         GST_DEBUG_OBJECT (self, "slaved %" GST_PTR_FORMAT "to pipeline_clock %" GST_PTR_FORMAT "", self->encoder_clock, pipeline_clock);
1373                                 }
1374                                 else
1375                                         GST_DEBUG_OBJECT (self, "encoder_clock is master clock");
1376                         }
1377                                 else
1378                                         GST_WARNING_OBJECT (self, "no pipeline clock!");
1379                         ret = ioctl(self->encoder->fd, VENC_START);
1380                         if ( ret != 0 )
1381                                 goto fail;
1382                         self->descriptors_available = 0;
1383                         CLEAR_COMMAND (self);
1384                         g_mutex_unlock (&self->mutex);
1385                         break;
1386                 default:
1387                         break;
1388         }
1389
1390         if (GST_ELEMENT_CLASS (parent_class)->change_state)
1391                 sret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1392
1393         switch (transition) {
1394                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1395                         g_mutex_lock (&self->mutex);
1396                         SEND_COMMAND (self, CONTROL_RUN);
1397                         GST_INFO_OBJECT (self, "started encoder!");
1398                         g_mutex_unlock (&self->mutex);
1399                         break;
1400                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1401                         g_mutex_lock (&self->mutex);
1402                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED self->descriptors_count=%i self->descriptors_available=%i", self->descriptors_count, self->descriptors_available);
1403                         SEND_COMMAND (self, CONTROL_PAUSE);
1404                         if (self->descriptors_count < self->descriptors_available)
1405                                 self->descriptors_count = self->descriptors_available;
1406                         if (self->descriptors_count)
1407                                 write(self->encoder->fd, &self->descriptors_count, sizeof(self->descriptors_count));
1408                         ret = ioctl(self->encoder->fd, VENC_STOP);
1409                         if ( ret != 0 )
1410                                 goto fail;
1411 #ifdef PROVIDE_CLOCK
1412                         gst_clock_set_master (self->encoder_clock, NULL);
1413 #endif
1414                         GST_INFO_OBJECT (self, "stopped encoder!");
1415                         g_mutex_unlock (&self->mutex);
1416                         break;
1417                 case GST_STATE_CHANGE_PAUSED_TO_READY:
1418                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PAUSED_TO_READY");
1419 #ifdef PROVIDE_CLOCK
1420                         gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), self->encoder_clock));
1421                         if (!self->dreamaudiosrc)
1422                                 gst_clock_set_calibration (self->encoder_clock, 0, 0, 1, 1);
1423 #endif
1424                         GST_DEBUG_OBJECT (self, "stopping readthread @%p...", self->readthread);
1425                         SEND_COMMAND (self, CONTROL_STOP);
1426                         g_thread_join (self->readthread);
1427                         if (self->dreamaudiosrc)
1428                                 gst_object_unref(self->dreamaudiosrc);
1429                         self->dreamaudiosrc = NULL;
1430                         break;
1431                 case GST_STATE_CHANGE_READY_TO_NULL:
1432                         gst_dreamvideosource_encoder_release (self);
1433                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_READY_TO_NULL");
1434                         break;
1435                 default:
1436                         break;
1437         }
1438
1439         return sret;
1440 fail:
1441         GST_ERROR_OBJECT(self,"can't perform encoder ioctl! error: %s (%i)", strerror(errno), errno);
1442         g_mutex_unlock (&self->mutex);
1443         return GST_STATE_CHANGE_FAILURE;
1444 }
1445
1446 static void
1447 gst_dreamvideosource_dispose (GObject * gobject)
1448 {
1449         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (gobject);
1450 #ifdef PROVIDE_CLOCK
1451         if (self->encoder_clock) {
1452                 gst_object_unref (self->encoder_clock);
1453                 self->encoder_clock = NULL;
1454         }
1455 #endif
1456 #ifdef dump
1457         close(self->dumpfd);
1458 #endif
1459         if (self->current_caps)
1460                 gst_caps_unref(self->current_caps);
1461         if (self->new_caps)
1462                 gst_caps_unref(self->new_caps);
1463         g_mutex_clear (&self->mutex);
1464         g_cond_clear (&self->cond);
1465         GST_DEBUG_OBJECT (self, "disposed");
1466         G_OBJECT_CLASS (parent_class)->dispose (gobject);
1467 }
1468
1469 #ifdef PROVIDE_CLOCK
1470 static GstClock *gst_dreamvideosource_provide_clock (GstElement * element)
1471 {
1472         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
1473
1474         if (!self->encoder || self->encoder->fd < 0)
1475         {
1476                 GST_DEBUG_OBJECT (self, "encoder device not started, can't provide clock!");
1477                 return NULL;
1478         }
1479
1480         if (!self->encoder_clock)
1481         {
1482                 GST_DEBUG_OBJECT (self, "this element is not the clock provider!");
1483                 return NULL;
1484         }
1485
1486         return GST_CLOCK_CAST (gst_object_ref (self->encoder_clock));
1487 }
1488 #endif