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