work on caps reconfiguration in progress
[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_BASE_PTS,
49         LAST_SIGNAL
50 };
51
52 enum
53 {
54         ARG_0,
55         ARG_CAPS,
56         ARG_BITRATE,
57         ARG_INPUT_MODE
58 };
59
60 static guint gst_dreamvideosource_signals[LAST_SIGNAL] = { 0 };
61
62 #define DEFAULT_BITRATE     2048
63 #define DEFAULT_FRAMERATE   25
64 #define DEFAULT_WIDTH       1280
65 #define DEFAULT_HEIGHT      720
66 #define DEFAULT_INPUT_MODE  GST_DREAMVIDEOSOURCE_INPUT_MODE_LIVE
67 #define DEFAULT_BUFFER_SIZE 16
68
69 static GstStaticPadTemplate srctemplate =
70     GST_STATIC_PAD_TEMPLATE ("src",
71         GST_PAD_SRC,
72         GST_PAD_ALWAYS,
73         GST_STATIC_CAPS ("video/x-h264, "
74         "width = { 720, 1280, 1920 }, "
75         "height = { 576, 720, 1080 }, "
76         "framerate = { 25/1, 30/1, 50/1, 60/1 }, "
77         "pixel-aspect-ratio = { 5/4, 16/9 }, "
78         "stream-format = (string) byte-stream, "
79         "profile = (string) main")
80     );
81
82 #define gst_dreamvideosource_parent_class parent_class
83 G_DEFINE_TYPE (GstDreamVideoSource, gst_dreamvideosource, GST_TYPE_PUSH_SRC);
84
85 static GstCaps *gst_dreamvideosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
86 static gboolean gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
87 static GstCaps *gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps);
88
89 static gboolean gst_dreamvideosource_start (GstBaseSrc * bsrc);
90 static gboolean gst_dreamvideosource_stop (GstBaseSrc * bsrc);
91 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc);
92 static gboolean gst_dreamvideosource_unlock_stop (GstBaseSrc * bsrc);
93 static void gst_dreamvideosource_dispose (GObject * gobject);
94 static GstFlowReturn gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf);
95
96 static void gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
97 static void gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
98
99 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition);
100 static gint64 gst_dreamvideosource_get_base_pts (GstDreamVideoSource *self);
101
102 static gboolean gst_dreamvideosource_encoder_init (GstDreamVideoSource * self);
103 static void gst_dreamvideosource_encoder_release (GstDreamVideoSource * self);
104
105 static void gst_dreamvideosource_read_thread_func (GstDreamVideoSource * self);
106
107 #ifdef PROVIDE_CLOCK
108 static GstClock *gst_dreamvideosource_provide_clock (GstElement * elem);
109 // static GstClockTime gst_dreamvideosource_get_encoder_time_ (GstClock * clock, GstBaseSrc * bsrc);
110 #endif
111
112 static void
113 gst_dreamvideosource_class_init (GstDreamVideoSourceClass * klass)
114 {
115         GObjectClass *gobject_class;
116         GstElementClass *gstelement_class;
117         GstBaseSrcClass *gstbsrc_class;
118         GstPushSrcClass *gstpush_src_class;
119
120         gobject_class = (GObjectClass *) klass;
121         gstelement_class = (GstElementClass *) klass;
122         gstbsrc_class = (GstBaseSrcClass *) klass;
123         gstpush_src_class = (GstPushSrcClass *) klass;
124
125         gobject_class->set_property = gst_dreamvideosource_set_property;
126         gobject_class->get_property = gst_dreamvideosource_get_property;
127         gobject_class->dispose = gst_dreamvideosource_dispose;
128
129         gst_element_class_add_pad_template (gstelement_class,
130                                             gst_static_pad_template_get (&srctemplate));
131
132         gst_element_class_set_static_metadata (gstelement_class,
133             "Dream Video source", "Source/Video",
134             "Provide an h.264 video elementary stream from Dreambox encoder device",
135             "Andreas Frisch <fraxinas@opendreambox.org>");
136
137         gstelement_class->change_state = gst_dreamvideosource_change_state;
138
139         gstbsrc_class->get_caps = gst_dreamvideosource_getcaps;
140         gstbsrc_class->set_caps = gst_dreamvideosource_setcaps;
141         gstbsrc_class->fixate = gst_dreamvideosource_fixate;
142         gstbsrc_class->start = gst_dreamvideosource_start;
143         gstbsrc_class->stop = gst_dreamvideosource_stop;
144         gstbsrc_class->unlock = gst_dreamvideosource_unlock;
145         gstbsrc_class->unlock_stop = gst_dreamvideosource_unlock_stop;
146
147         gstpush_src_class->create = gst_dreamvideosource_create;
148
149 #ifdef PROVIDE_CLOCK
150         gstelement_class->provide_clock = GST_DEBUG_FUNCPTR (gst_dreamvideosource_provide_clock);
151 //      g_type_class_ref (GST_TYPE_SYSTEM_CLOCK);
152 #endif
153
154         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
155           g_param_spec_int ("bitrate", "Bitrate (kb/s)",
156             "Bitrate in kbit/sec", 16, 200000, DEFAULT_BITRATE,
157             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
158
159         g_object_class_install_property (gobject_class, ARG_CAPS,
160           g_param_spec_boxed ("caps", "Caps",
161             "The caps for the source stream", GST_TYPE_CAPS,
162             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
163
164         g_object_class_install_property (gobject_class, ARG_INPUT_MODE,
165           g_param_spec_enum ("input-mode", "Input Mode",
166             "Select the input source of the video stream",
167             GST_TYPE_DREAMVIDEOSOURCE_INPUT_MODE, DEFAULT_INPUT_MODE,
168             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169
170         gst_dreamvideosource_signals[SIGNAL_GET_BASE_PTS] =
171                 g_signal_new ("get-base-pts",
172                 G_TYPE_FROM_CLASS (klass),
173                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
174                 G_STRUCT_OFFSET (GstDreamVideoSourceClass, get_base_pts),
175                 NULL, NULL, gst_dreamsource_marshal_INT64__VOID, G_TYPE_INT64, 0);
176
177         klass->get_base_pts = gst_dreamvideosource_get_base_pts;
178 }
179
180 static gint64
181 gst_dreamvideosource_get_base_pts (GstDreamVideoSource *self)
182 {
183         GST_DEBUG_OBJECT (self, "gst_dreamvideosource_get_base_pts %" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
184         return self->base_pts;
185 }
186
187 static void gst_dreamvideosource_set_bitrate (GstDreamVideoSource * self, uint32_t bitrate)
188 {
189         g_mutex_lock (&self->mutex);
190         uint32_t vbr = bitrate*1000;
191         if (!self->encoder || !self->encoder->fd)
192         {
193                 self->video_info.bitrate = bitrate;
194                 g_mutex_unlock (&self->mutex);
195                 return;
196         }
197
198         int ret = ioctl(self->encoder->fd, VENC_SET_BITRATE, &vbr);
199         if (ret != 0)
200         {
201                 GST_WARNING_OBJECT (self, "can't set video bitrate to %i bytes/s!", vbr);
202                 g_mutex_unlock (&self->mutex);
203                 return;
204         }
205         GST_INFO_OBJECT (self, "set video bitrate to %i kBytes/s", bitrate);
206         self->video_info.bitrate = bitrate;
207         g_mutex_unlock (&self->mutex);
208 }
209
210 static gboolean gst_dreamvideosource_set_format (GstDreamVideoSource * self, VideoFormatInfo * info)
211 {
212         g_mutex_lock (&self->mutex);
213         if (!self->encoder || !self->encoder->fd)
214         {
215                 self->video_info = *info;
216                 g_mutex_unlock (&self->mutex);
217                 return TRUE;
218         }
219
220         if (info->fps_n > 0)
221         {
222                 int venc_fps = 0;
223                 switch (info->fps_n) {
224                         case 25:
225                                 venc_fps = rate_25;
226                                 break;
227                         case 30:
228                                 venc_fps = rate_30;
229                                 break;
230                         case 50:
231                                 venc_fps = rate_50;
232                                 break;
233                         case 60:
234                                 venc_fps = rate_60;
235                                 break;
236                         default:
237                                 GST_ERROR_OBJECT (self, "invalid framerate %d/%d", info->fps_n, info->fps_d);
238                                 goto fail;
239                 }
240                 if (!ioctl(self->encoder->fd, VENC_SET_FRAMERATE, &venc_fps))
241                         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);
242                 else
243                 {
244                         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);
245                         goto fail;
246                 }
247         }
248
249         if (info->width && info->height)
250         {
251                 int venc_size = 0;
252                 if ( info->width == 720 && info->height == 576 )
253                         venc_size = fmt_720x576;
254                 else if ( info->width == 1280 && info->height == 720)
255                         venc_size = fmt_1280x720;
256                 else if ( info->width == 1920 && info->height == 1080)
257                         venc_size = fmt_1920x1080;
258                 else
259                 {
260                         GST_ERROR_OBJECT (self, "invalid resolution %dx%d", info->width, info->height);
261                         goto fail;
262                 }
263                 if (!ioctl(self->encoder->fd, VENC_SET_RESOLUTION, &venc_size))
264                         GST_INFO_OBJECT (self, "set resolution to %dx%d -> ioctrl(%d, VENC_SET_RESOLUTION, &%d)", info->width, info->height, self->encoder->fd, venc_size);
265                 else
266                 {
267                         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);
268                         goto fail;
269                 }
270         }
271
272         self->video_info = *info;
273         g_mutex_unlock (&self->mutex);
274         return TRUE;
275
276 fail:
277         g_mutex_unlock (&self->mutex);
278         return FALSE;
279 }
280
281 void gst_dreamvideosource_set_input_mode (GstDreamVideoSource *self, GstDreamVideoSourceInputMode mode)
282 {
283         g_return_if_fail (GST_IS_DREAMVIDEOSOURCE (self));
284         GEnumValue *val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (GST_TYPE_DREAMVIDEOSOURCE_INPUT_MODE)), mode);
285         if (!val)
286         {
287                 GST_ERROR_OBJECT (self, "no such input_mode %i!", mode);
288                 return;
289         }
290         const gchar *value_nick = val->value_nick;
291
292         g_mutex_lock (&self->mutex);
293         if (!self->encoder || !self->encoder->fd)
294         {
295                 self->input_mode = mode;
296                 goto out;
297         }
298         int int_mode = mode;
299         int ret = ioctl(self->encoder->fd, VENC_SET_SOURCE, &int_mode);
300         if (ret != 0)
301         {
302                 GST_WARNING_OBJECT (self, "can't set input mode to %s (%i) error: %s", value_nick, mode, strerror(errno));
303                 goto out;
304         }
305         GST_INFO_OBJECT (self, "successfully set input mode to %s (%i)", value_nick, mode);
306         self->input_mode = mode;
307
308 out:
309         g_mutex_unlock (&self->mutex);
310         return;
311 }
312
313 GstDreamVideoSourceInputMode gst_dreamvideosource_get_input_mode (GstDreamVideoSource *self)
314 {
315         GstDreamVideoSourceInputMode result;
316         g_return_val_if_fail (GST_IS_DREAMVIDEOSOURCE (self), -1);
317         g_mutex_lock (&self->mutex);
318         result =self->input_mode;
319         g_mutex_unlock (&self->mutex);
320         return result;
321 }
322
323 gboolean
324 gst_dreamvideosource_plugin_init (GstPlugin *plugin)
325 {
326         GST_DEBUG_CATEGORY_INIT (dreamvideosource_debug, "dreamvideosource", 0, "dreamvideosource");
327         return gst_element_register (plugin, "dreamvideosource", GST_RANK_PRIMARY, GST_TYPE_DREAMVIDEOSOURCE);
328 }
329
330 static void
331 gst_dreamvideosource_init (GstDreamVideoSource * self)
332 {
333         GstPadTemplate *pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS(self), "src");
334         self->current_caps = NULL;
335         self->new_caps = NULL;
336
337         self->encoder = NULL;
338         self->descriptors_available = 0;
339         self->input_mode = DEFAULT_INPUT_MODE;
340
341         self->buffer_size = DEFAULT_BUFFER_SIZE;
342         g_queue_init (&self->current_frames);
343         self->readthread = NULL;
344
345         g_mutex_init (&self->mutex);
346         g_cond_init (&self->cond);
347         READ_SOCKET (self) = -1;
348         WRITE_SOCKET (self) = -1;
349
350         gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
351         gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
352
353         self->encoder = NULL;
354         self->encoder_clock = NULL;
355
356 #ifdef dump
357         self->dumpfd = open("/media/hdd/movie/dreamvideosource.dump", O_WRONLY | O_CREAT | O_TRUNC);
358         GST_DEBUG_OBJECT (self, "dumpfd = %i (%s)", self->dumpfd, (self->dumpfd > 0) ? "OK" : strerror(errno));
359 #endif
360 }
361
362 static gboolean gst_dreamvideosource_encoder_init (GstDreamVideoSource * self)
363 {
364         GST_LOG_OBJECT (self, "initializating encoder...");
365         self->encoder = malloc (sizeof(EncoderInfo));
366
367         if (!self->encoder) {
368                 GST_ERROR_OBJECT (self,"out of space");
369                 return FALSE;
370         }
371
372         char fn_buf[32];
373         sprintf(fn_buf, "/dev/venc%d", 0);
374         self->encoder->fd = open(fn_buf, O_RDWR | O_SYNC);
375         if (self->encoder->fd <= 0) {
376                 GST_ERROR_OBJECT (self,"cannot open device %s (%s)", fn_buf, strerror(errno));
377                 free(self->encoder);
378                 self->encoder = NULL;
379                 return FALSE;
380         }
381
382         self->encoder->buffer = malloc(VBUFSIZE);
383         if (!self->encoder->buffer) {
384                 GST_ERROR_OBJECT(self,"cannot alloc buffer");
385                 return FALSE;
386         }
387
388         self->encoder->cdb = (unsigned char *)mmap (0, VMMAPSIZE, PROT_READ, MAP_PRIVATE, self->encoder->fd, 0);
389
390         if (!self->encoder->cdb || self->encoder->cdb == MAP_FAILED) {
391                 GST_ERROR_OBJECT(self,"cannot alloc buffer: %s (%d)", strerror(errno));
392                 self->encoder->cdb = NULL;
393                 return FALSE;
394         }
395
396         int control_sock[2];
397         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
398         {
399                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM);
400                 return GST_STATE_CHANGE_FAILURE;
401         }
402         READ_SOCKET (self) = control_sock[0];
403         WRITE_SOCKET (self) = control_sock[1];
404         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
405         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
406
407         gst_dreamvideosource_set_bitrate (self, self->video_info.bitrate);
408         gst_dreamvideosource_set_format (self, &self->video_info);
409         gst_dreamvideosource_set_input_mode (self, self->input_mode);
410
411 #ifdef PROVIDE_CLOCK
412         self->encoder_clock = gst_dreamsource_clock_new ("GstDreamVideoSinkClock", self->encoder->fd);
413         GST_OBJECT_FLAG_SET (self, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
414 #endif
415
416         GST_LOG_OBJECT (self, "encoder %s successfully initialized", fn_buf);
417         return TRUE;
418 }
419
420 static void gst_dreamvideosource_encoder_release (GstDreamVideoSource * self)
421 {
422         GST_LOG_OBJECT (self, "releasing encoder...");
423         if (self->encoder) {
424                 if (self->encoder->buffer)
425                         free(self->encoder->buffer);
426                 if (self->encoder->cdb)
427                         munmap(self->encoder->cdb, VMMAPSIZE);
428                 if (self->encoder->fd)
429                         close(self->encoder->fd);
430                 free(self->encoder);
431         }
432         self->encoder = NULL;
433         close (READ_SOCKET (self));
434         close (WRITE_SOCKET (self));
435         READ_SOCKET (self) = -1;
436         WRITE_SOCKET (self) = -1;
437         if (self->encoder_clock) {
438                 gst_object_unref (self->encoder_clock);
439                 self->encoder_clock = NULL;
440         }
441 }
442
443 static void
444 gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
445 {
446         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
447
448         switch (prop_id) {
449                 case ARG_CAPS:
450                 {
451                         if (self->new_caps)
452                                 gst_caps_unref (self->new_caps);
453                         self->new_caps = gst_caps_copy (gst_value_get_caps (value));
454                         GST_WARNING_OBJECT (self, "gst_dreamvideosource_set_property new_caps %" GST_PTR_FORMAT "", self->new_caps);
455                         gst_pad_mark_reconfigure (GST_BASE_SRC_PAD (GST_BASE_SRC(object)));
456 //                      gst_dreamvideosource_setcaps(GST_BASE_SRC(object), caps);
457 //                      gst_caps_unref (caps);
458                         break;
459                 }
460                 case ARG_BITRATE:
461                         gst_dreamvideosource_set_bitrate(self, g_value_get_int (value));
462                         break;
463                 case ARG_INPUT_MODE:
464                         gst_dreamvideosource_set_input_mode (self, g_value_get_enum (value));
465                         break;
466                 default:
467                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
468                         break;
469         }
470 }
471
472 static void
473 gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
474 {
475         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
476
477         switch (prop_id) {
478                 case ARG_CAPS:
479                         g_value_take_boxed (value, gst_dreamvideosource_getcaps (GST_BASE_SRC(object), GST_CAPS_ANY));
480                         break;
481                 case ARG_BITRATE:
482                         g_value_set_int (value, self->video_info.bitrate/1000);
483                         break;
484                 case ARG_INPUT_MODE:
485                         g_value_set_enum (value, gst_dreamvideosource_get_input_mode (self));
486                         break;
487                 default:
488                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
489                         break;
490         }
491 }
492
493 static GstCaps *
494 gst_dreamvideosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
495 {
496         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
497         GstCaps *caps;
498
499         if (self->current_caps == NULL) {
500                 GstPadTemplate *pad_template;
501                 pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS(self), "src");
502                 g_return_val_if_fail (pad_template != NULL, NULL);
503                 GST_WARNING_OBJECT (self, "no current_caps -> use template caps");
504                 caps = gst_pad_template_get_caps (pad_template);
505         }
506         if (self->current_caps)
507         {
508                 GST_WARNING_OBJECT (self, "current caps available");
509                 caps = gst_caps_copy(self->current_caps);
510         }
511
512         GST_WARNING_OBJECT (self, "gst_dreamvideosource_getcaps %" GST_PTR_FORMAT " filter %" GST_PTR_FORMAT, caps, filter);
513
514         if (filter) {
515                 GstCaps *intersection;
516                 intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
517                 gst_caps_unref (caps);
518                 caps = intersection;
519         }
520
521         GST_WARNING_OBJECT (self, "return caps %" GST_PTR_FORMAT, caps);
522         return caps;
523 }
524
525 static gboolean
526 gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
527 {
528         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
529         GstBaseSrcClass *bclass = GST_BASE_SRC_GET_CLASS (bsrc);
530         GstCaps *current_caps;
531         const GstStructure *structure;
532         VideoFormatInfo info;
533         gboolean ret;
534         int width, height;
535         const GValue *framerate, *par;
536
537         g_mutex_lock (&self->mutex);
538         if (self->new_caps)
539         {
540                 GST_WARNING_OBJECT (self, "instead of parameter %" GST_PTR_FORMAT " use self->new_caps %" GST_PTR_FORMAT"", caps, self->new_caps);
541                 gst_caps_unref (caps);
542                 caps = gst_caps_copy (self->new_caps);
543                 gst_caps_unref (self->new_caps);
544                 self->new_caps = NULL;
545         }
546         structure = gst_caps_get_structure (caps, 0);
547
548         current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc));
549
550         GST_WARNING_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);
551
552         if (current_caps && gst_caps_is_equal (current_caps, caps)) {
553                 GST_WARNING_OBJECT (self, "New caps equal to old ones: %" GST_PTR_FORMAT, caps);
554                 ret = TRUE;
555         } else {
556                 GstState state;
557                 gst_element_get_state (GST_ELEMENT(self), &state, NULL, 1*GST_MSECOND);
558                 if (state == GST_STATE_PLAYING)
559                 {
560                         GST_WARNING_OBJECT (self, "can't change caps while in PLAYING state %" GST_PTR_FORMAT, caps);
561                         g_mutex_unlock (&self->mutex);
562                         return TRUE;
563                 }
564                 else if (gst_structure_has_name (structure, "video/x-h264"))
565                 {
566                         memset (&info, 0, sizeof(VideoFormatInfo));
567                         ret = gst_structure_get_int (structure, "width", &info.width);
568                         ret &= gst_structure_get_int (structure, "height", &info.height);
569                         framerate = gst_structure_get_value (structure, "framerate");
570                         if (GST_VALUE_HOLDS_FRACTION(framerate)) {
571                                 info.fps_n = gst_value_get_fraction_numerator (framerate);
572                                 info.fps_d = gst_value_get_fraction_denominator (framerate);
573                         }
574                         GST_WARNING_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
575                         gst_caps_replace (&self->current_caps, caps);
576
577                         gboolean fixed = gst_caps_is_fixed(caps);
578                         g_mutex_unlock (&self->mutex);
579
580                         GST_WARNING_OBJECT (self, "before set_format caps=%" GST_PTR_FORMAT "GST_IS_CAPS?%i fixed?%i", caps, GST_IS_CAPS(caps), fixed);
581                         if (fixed && gst_dreamvideosource_set_format(self, &info))
582                                 ret = gst_pad_push_event (bsrc->srcpad, gst_event_new_caps (caps));
583                 }
584                 else {
585                         GST_WARNING_OBJECT (self, "unsupported caps: %" GST_PTR_FORMAT, caps);
586                         ret = FALSE;
587                 }
588         }
589         if (current_caps)
590                 gst_caps_unref (current_caps);
591         g_mutex_unlock (&self->mutex);
592         return ret;
593 }
594
595 static GstCaps *
596 gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps)
597 {
598         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
599         GstStructure *structure;
600
601         caps = gst_caps_make_writable (caps);
602         structure = gst_caps_get_structure (caps, 0);
603
604         gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
605         gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
606         gst_structure_fixate_field_nearest_fraction (structure, "framerate", DEFAULT_FRAMERATE, 1);
607         gst_structure_fixate_field_nearest_fraction (structure, "pixel-aspect-ratio", DEFAULT_WIDTH, DEFAULT_HEIGHT);
608
609         caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
610         GST_WARNING_OBJECT (bsrc, "fixate caps: %" GST_PTR_FORMAT, caps);
611         return caps;
612 }
613
614 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc)
615 {
616         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
617         GST_DEBUG_OBJECT (self, "stop creating buffers");
618         g_mutex_lock (&self->mutex);
619         self->flushing = TRUE;
620         GST_DEBUG_OBJECT (self, "set flushing TRUE");
621         g_cond_signal (&self->cond);
622         g_mutex_unlock (&self->mutex);
623         return TRUE;
624 }
625
626 static gboolean gst_dreamvideosource_unlock_stop (GstBaseSrc * bsrc)
627 {
628         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
629         GST_DEBUG_OBJECT (self, "start creating buffers...");
630         g_mutex_lock (&self->mutex);
631         self->flushing = FALSE;
632         g_queue_foreach (&self->current_frames, (GFunc) gst_buffer_unref, NULL);
633         g_queue_clear (&self->current_frames);
634         g_mutex_unlock (&self->mutex);
635         return TRUE;
636 }
637
638 static void gst_dreamvideosource_read_thread_func (GstDreamVideoSource * self)
639 {
640         EncoderInfo *enc = self->encoder;
641         GstBuffer *readbuf;
642
643         if (!enc) {
644                 GST_WARNING_OBJECT (self, "encoder device not opened!");
645                 return;
646         }
647
648         GST_DEBUG_OBJECT (self, "enter read thread");
649
650         GstMessage *message;
651         GValue val = { 0 };
652
653         message = gst_message_new_stream_status (GST_OBJECT_CAST (self), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (GST_OBJECT_PARENT(self)));
654         g_value_init (&val, GST_TYPE_G_THREAD);
655         g_value_set_boxed (&val, self->readthread);
656         gst_message_set_stream_status_object (message, &val);
657         g_value_unset (&val);
658         GST_DEBUG_OBJECT (self, "posting ENTER stream status");
659         gst_element_post_message (GST_ELEMENT_CAST (self), message);
660
661         while (TRUE) {
662                 readbuf = NULL;
663                 {
664                         struct pollfd rfd[2];
665                         int timeout, nfds;
666
667                         rfd[0].fd = READ_SOCKET (self);
668                         rfd[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
669
670                         if (self->descriptors_available == 0)
671                         {
672                                 rfd[1].fd = enc->fd;
673                                 rfd[1].events = POLLIN;
674                                 self->descriptors_count = 0;
675                                 timeout = 200;
676                                 nfds = 2;
677                         }
678                         else
679                         {
680                                 rfd[1].revents = 0;
681                                 nfds = 1;
682                                 timeout = 0;
683                         }
684
685                         int ret = poll(rfd, nfds, timeout);
686
687                         if (G_UNLIKELY (ret == -1))
688                         {
689                                 GST_ERROR_OBJECT (self, "SELECT ERROR!");
690                                 goto stop_running;
691                         }
692                         else if ( ret == 0 && self->descriptors_available == 0 )
693                         {
694                                 gst_clock_get_time(self->encoder_clock);
695                                 g_mutex_lock (&self->mutex);
696                                 if (self->flushing)
697                                 {
698                                         GST_DEBUG_OBJECT (self, "FLUSHING!");
699                                         g_cond_signal (&self->cond);
700                                         g_mutex_unlock (&self->mutex);
701                                         continue;
702                                 }
703                                 g_mutex_unlock (&self->mutex);
704                                 GST_DEBUG_OBJECT (self, "SELECT TIMEOUT");
705                                 //!!! TODO generate valid dummy payload
706                                 readbuf = gst_buffer_new();
707                         }
708                         else if ( rfd[0].revents )
709                         {
710                                 char command;
711                                 READ_COMMAND (self, command, ret);
712                                 if (command == CONTROL_STOP)
713                                 {
714                                         GST_DEBUG_OBJECT (self, "CONTROL_STOP!");
715                                         goto stop_running;
716                                 }
717                         }
718                         else if ( G_LIKELY(rfd[1].revents & POLLIN) )
719                         {
720                                 int rlen = read(enc->fd, enc->buffer, VBUFSIZE);
721                                 if (rlen <= 0 || rlen % VBDSIZE ) {
722                                         if ( errno == 512 )
723                                                 goto stop_running;
724                                         GST_WARNING_OBJECT (self, "read error %s (%i)", strerror(errno), errno);
725                                         goto stop_running;
726                                 }
727                                 self->descriptors_available = rlen / VBDSIZE;
728                                 GST_LOG_OBJECT (self, "encoder buffer was empty, %d descriptors available", self->descriptors_available);
729                         }
730                 }
731
732                 while (self->descriptors_count < self->descriptors_available)
733                 {
734                         off_t offset = self->descriptors_count * VBDSIZE;
735                         VideoBufferDescriptor *desc = (VideoBufferDescriptor*)(&enc->buffer[offset]);
736
737                         uint32_t f = desc->stCommon.uiFlags;
738
739                         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);
740
741                         if (G_UNLIKELY (f & CDB_FLAG_METADATA))
742                         {
743                                 GST_LOG_OBJECT (self, "CDB_FLAG_METADATA... skip outdated packet");
744                                 self->descriptors_count = self->descriptors_available;
745                                 continue;
746                         }
747
748                         readbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, enc->cdb, VMMAPSIZE, desc->stCommon.uiOffset, desc->stCommon.uiLength, self, NULL);
749
750                         GstClockTime buffer_dts = GST_CLOCK_TIME_NONE;
751                         GstClockTime buffer_pts = GST_CLOCK_TIME_NONE;
752
753                         // uiDTS since kernel driver booted
754                         if (f & VBD_FLAG_DTS_VALID && desc->uiDTS)
755                         {
756                                 buffer_dts = MPEGTIME_TO_GSTTIME(desc->uiDTS);
757                                 GST_LOG_OBJECT (self, "f & VBD_FLAG_DTS_VALID && encoder's uiDTS=%" GST_TIME_FORMAT"", GST_TIME_ARGS(buffer_dts));
758
759                                 g_mutex_lock (&self->mutex);
760                                 if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
761                                 {
762                                         if (self->dreamaudiosrc)
763                                         {
764                                                 guint64 audiosource_base_pts;
765                                                 g_signal_emit_by_name(self->dreamaudiosrc, "get-base-pts", &audiosource_base_pts);
766                                                 if (audiosource_base_pts != GST_CLOCK_TIME_NONE)
767                                                 {
768                                                         GST_DEBUG_OBJECT (self, "use DREAMAUDIOSOURCE's base_pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (audiosource_base_pts) );
769                                                         self->base_pts = audiosource_base_pts;
770                                                 }
771                                         }
772                                         if (self->base_pts == GST_CLOCK_TIME_NONE)
773                                         {
774                                                 self->base_pts = buffer_dts;
775                                                 GST_DEBUG_OBJECT (self, "use mpeg stream pts as base_pts=%" GST_TIME_FORMAT" (%lld)", GST_TIME_ARGS (self->base_pts), desc->uiDTS);
776                                         }
777                                 }
778                                 g_mutex_unlock (&self->mutex);
779
780                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_dts >= self->base_pts )
781                                 {
782                                         buffer_dts -= self->base_pts;
783                                         GST_BUFFER_DTS(readbuf) = buffer_dts;
784                                         GST_LOG_OBJECT (self, "corrected dts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (GST_BUFFER_DTS(readbuf)));
785                                 }
786                         }
787
788                         if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
789                         {
790                                 GST_DEBUG_OBJECT (self, "self->base_pts == GST_CLOCK_TIME_NONE! skip this frame");
791                                 self->descriptors_count++;
792                                 break;
793                         }
794
795                         if (self->video_info.fps_d)
796                                 GST_BUFFER_DURATION(readbuf) = gst_util_uint64_scale (GST_SECOND, self->video_info.fps_d, self->video_info.fps_n);
797
798 //                      if (f & CDB_FLAG_PTS_VALID)
799 //                      {
800 //                              GstClock *clock = gst_element_get_clock (GST_ELEMENT(self));
801 //                              if (clock)
802 //                              {
803 //                                      GstClockTime clock_time, base_time;
804 //                                      clock_time = gst_clock_get_time (clock);
805 //                                      base_time = gst_element_get_base_time (GST_ELEMENT(self));
806 // GST_ERROR_OBJECT (self, "\n%" GST_TIME_FORMAT "=mpeg pts\n%" GST_TIME_FORMAT "=dreamsource_clock_time\n%" GST_TIME_FORMAT "=base_time\n%" GST_TIME_FORMAT "=base_pts",
807 // GST_TIME_ARGS (MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS)), GST_TIME_ARGS (clock_time), GST_TIME_ARGS (base_time), GST_TIME_ARGS(self->base_pts) );
808 // 
809 //                                      if (clock_time && clock_time > base_time)
810 //                                      {
811 //                                              buffer_time = clock_time - base_time;
812 //                                              gst_object_unref (clock);
813 //      //                                      buffer_time -= GST_BUFFER_DURATION(readbuf);
814 //                                              GST_BUFFER_PTS(readbuf) = buffer_time;
815 //                                              GST_BUFFER_DTS(readbuf) = buffer_time;
816 //
817 //                                      }
818 //                                      else
819 //                                              buffer_time = GST_CLOCK_TIME_NONE;
820 //                              }
821 //                      }
822
823                         if (/*(!clock || buffer_time == GST_CLOCK_TIME_NONE) && */f & CDB_FLAG_PTS_VALID)
824                         {
825                                 buffer_pts = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
826                                 GST_LOG_OBJECT (self, "f & CDB_FLAG_PTS_VALID && encoder's  uiPTS=%" GST_TIME_FORMAT"", GST_TIME_ARGS(buffer_pts));
827                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_pts >= self->base_pts )
828                                 {
829                                         buffer_pts -= self->base_pts/* + GST_BUFFER_DURATION(readbuf)*/;
830                                         GST_BUFFER_PTS(readbuf) = buffer_pts;
831                                         GST_INFO_OBJECT (self, "currected pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (GST_BUFFER_PTS(readbuf)));
832                                 }
833                         }
834
835 #ifdef dump
836                         int wret = write(self->dumpfd, (unsigned char*)(enc->cdb + desc->stCommon.uiOffset), desc->stCommon.uiLength);
837                         GST_LOG_OBJECT (self, "read %i dumped %i total %" G_GSIZE_FORMAT " ", desc->stCommon.uiLength, wret, gst_buffer_get_size (*outbuf) );
838 #endif
839                         self->descriptors_count++;
840                         break;
841                 }
842
843                 if (self->descriptors_count == self->descriptors_available)
844                 {
845                         GST_LOG_OBJECT (self, "self->descriptors_count == self->descriptors_available -> release %i consumed descriptors", self->descriptors_count);
846                         /* release consumed descs */
847                         if (write(enc->fd, &self->descriptors_count, sizeof(self->descriptors_count)) != sizeof(self->descriptors_count)) {
848                                 GST_WARNING_OBJECT (self, "release consumed descs write error!");
849                                 goto stop_running;
850                         }
851                         self->descriptors_available = 0;
852                 }
853
854                 if (readbuf)
855                 {
856                         g_mutex_lock (&self->mutex);
857                         if (!self->flushing)
858                         {
859                                 while (g_queue_get_length (&self->current_frames) >= self->buffer_size)
860                                 {
861                                         GstBuffer * oldbuf = g_queue_pop_head (&self->current_frames);
862                                         GST_WARNING_OBJECT (self, "dropping %" GST_PTR_FORMAT " because of queue overflow! buffers count=%i", oldbuf, g_queue_get_length (&self->current_frames));
863                                         gst_buffer_unref(oldbuf);
864                                 }
865                                 g_queue_push_tail (&self->current_frames, readbuf);
866                         }
867                         else
868                                 gst_buffer_unref(readbuf);
869                         g_cond_signal (&self->cond);
870                         GST_INFO_OBJECT (self, "read %" GST_PTR_FORMAT " to queue", readbuf );
871                         g_mutex_unlock (&self->mutex);
872                 }
873         }
874
875         g_assert_not_reached ();
876         return;
877
878         stop_running:
879         {
880                 g_mutex_unlock (&self->mutex);
881                 g_cond_signal (&self->cond);
882                 GST_DEBUG ("stop running, exit thread");
883                 message = gst_message_new_stream_status (GST_OBJECT_CAST (self), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (GST_OBJECT_PARENT(self)));
884                 g_value_init (&val, GST_TYPE_G_THREAD);
885                 g_value_set_boxed (&val, self->readthread);
886                 gst_message_set_stream_status_object (message, &val);
887                 g_value_unset (&val);
888                 GST_DEBUG_OBJECT (self, "posting LEAVE stream status");
889                 gst_element_post_message (GST_ELEMENT_CAST (self), message);
890                 return;
891         }
892 }
893
894 static GstFlowReturn
895 gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf)
896 {
897         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (psrc);
898
899         GST_LOG_OBJECT (self, "new buffer requested");
900
901         g_mutex_lock (&self->mutex);
902         while (g_queue_is_empty (&self->current_frames) && !self->flushing)
903         {
904                 g_cond_wait (&self->cond, &self->mutex);
905                 GST_INFO_OBJECT (self, "waiting for buffer from encoder");
906         }
907
908         *outbuf = g_queue_pop_head (&self->current_frames);
909         g_mutex_unlock (&self->mutex);
910
911         if (*outbuf)
912         {
913                 GST_INFO_OBJECT (self, "pushing %" GST_PTR_FORMAT "", *outbuf );
914                 return GST_FLOW_OK;
915         }
916         GST_INFO_OBJECT (self, "FLUSHING");
917         return GST_FLOW_FLUSHING;
918 }
919
920
921 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition)
922 {
923         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
924         GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS;
925         int ret;
926
927         switch (transition) {
928                 case GST_STATE_CHANGE_NULL_TO_READY:
929                 {
930                         if (!gst_dreamvideosource_encoder_init (self))
931                                 return GST_STATE_CHANGE_FAILURE;
932                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_NULL_TO_READY");
933                         break;
934                 }
935                 case GST_STATE_CHANGE_READY_TO_PAUSED:
936                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
937 #ifdef PROVIDE_CLOCK
938                         GstMessage* msg;
939                         msg = gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->encoder_clock, TRUE);
940                         GST_INFO_OBJECT (self, "clock: %" GST_PTR_FORMAT " %" GST_PTR_FORMAT " typename=%s", self->encoder_clock, msg, GST_MESSAGE_TYPE_NAME(msg));
941                         gst_element_post_message (element, msg);
942 #endif
943                         self->flushing = TRUE;
944                         self->readthread = g_thread_try_new ("dreamvideosrc-read", (GThreadFunc) gst_dreamvideosource_read_thread_func, self, NULL);
945                         GST_DEBUG_OBJECT (self, "started readthread @%p", self->readthread );
946                         break;
947                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
948                         g_mutex_lock (&self->mutex);
949                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
950                         self->base_pts = GST_CLOCK_TIME_NONE;
951                         ret = ioctl(self->encoder->fd, VENC_START);
952                         if ( ret != 0 )
953                                 goto fail;
954                         self->descriptors_available = 0;
955                         CLEAR_COMMAND (self);
956                         GST_INFO_OBJECT (self, "started encoder!");
957                         g_mutex_unlock (&self->mutex);
958                         break;
959                 default:
960                         break;
961         }
962
963         if (GST_ELEMENT_CLASS (parent_class)->change_state)
964                 sret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
965
966         switch (transition) {
967                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
968                         g_mutex_lock (&self->mutex);
969                         self->flushing = TRUE;
970                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED self->descriptors_count=%i self->descriptors_available=%i", self->descriptors_count, self->descriptors_available);
971                         while (self->descriptors_count < self->descriptors_available)
972                         {
973                                 GST_LOG_OBJECT (self, "flushing self->descriptors_count=%i");
974                                 self->descriptors_count++;
975                         }
976                         if (self->descriptors_count)
977                                 write(self->encoder->fd, &self->descriptors_count, sizeof(self->descriptors_count));
978                         ret = ioctl(self->encoder->fd, VENC_STOP);
979                         if ( ret != 0 )
980                                 goto fail;
981 #ifdef PROVIDE_CLOCK
982                         gst_clock_set_master (self->encoder_clock, NULL);
983 #endif
984                         GST_INFO_OBJECT (self, "stopped encoder!");
985                         g_mutex_unlock (&self->mutex);
986                         break;
987                 case GST_STATE_CHANGE_PAUSED_TO_READY:
988                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PAUSED_TO_READY");
989 #ifdef PROVIDE_CLOCK
990                         gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), self->encoder_clock));
991 #endif
992                         GST_DEBUG_OBJECT (self, "stopping readthread @%p...", self->readthread);
993                         SEND_COMMAND (self, CONTROL_STOP);
994                         g_thread_join (self->readthread);
995                         break;
996                 case GST_STATE_CHANGE_READY_TO_NULL:
997                         gst_dreamvideosource_encoder_release (self);
998                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_READY_TO_NULL, close control sockets");
999                         break;
1000                 default:
1001                         break;
1002         }
1003
1004         return sret;
1005 fail:
1006         GST_ERROR_OBJECT(self,"can't perform encoder ioctl!");
1007         g_mutex_unlock (&self->mutex);
1008         return GST_STATE_CHANGE_FAILURE;
1009 }
1010
1011 static gboolean
1012 gst_dreamvideosource_start (GstBaseSrc * bsrc)
1013 {
1014         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
1015         self->dreamaudiosrc = gst_bin_get_by_name_recurse_up(GST_BIN(GST_ELEMENT_PARENT(self)), "dreamaudiosource0");
1016         GST_DEBUG_OBJECT (self, "started. reference to dreamaudiosource=%" GST_PTR_FORMAT"", self->dreamaudiosrc);
1017         return TRUE;
1018 }
1019
1020 static gboolean
1021 gst_dreamvideosource_stop (GstBaseSrc * bsrc)
1022 {
1023         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
1024         if (self->dreamaudiosrc)
1025                 gst_object_unref(self->dreamaudiosrc);
1026         GST_DEBUG_OBJECT (self, "stop");
1027         return TRUE;
1028 }
1029
1030 static void
1031 gst_dreamvideosource_dispose (GObject * gobject)
1032 {
1033         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (gobject);
1034 #ifdef PROVIDE_CLOCK
1035         if (self->encoder_clock) {
1036                 gst_object_unref (self->encoder_clock);
1037                 self->encoder_clock = NULL;
1038         }
1039 #endif
1040 #ifdef dump
1041         close(self->dumpfd);
1042 #endif
1043         if (self->current_caps)
1044                 gst_caps_unref(self->current_caps);
1045         if (self->new_caps)
1046                 gst_caps_unref(self->new_caps);
1047         g_mutex_clear (&self->mutex);
1048         g_cond_clear (&self->cond);
1049         GST_DEBUG_OBJECT (self, "disposed");
1050         G_OBJECT_CLASS (parent_class)->dispose (gobject);
1051 }
1052
1053 #ifdef PROVIDE_CLOCK
1054 static GstClock *gst_dreamvideosource_provide_clock (GstElement * element)
1055 {
1056         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
1057
1058         if (!self->encoder || self->encoder->fd < 0)
1059         {
1060                 GST_DEBUG_OBJECT (self, "encoder device not started, can't provide clock!");
1061                 return NULL;
1062         }
1063
1064         return GST_CLOCK_CAST (gst_object_ref (self->encoder_clock));
1065 }
1066 #endif