defer setting default encoder modes to encoder init
[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 = gst_pad_template_get_caps (pad_template);
335
336         self->encoder = NULL;
337         self->descriptors_available = 0;
338         self->input_mode = DEFAULT_INPUT_MODE;
339
340         self->buffer_size = DEFAULT_BUFFER_SIZE;
341         g_queue_init (&self->current_frames);
342         self->readthread = NULL;
343
344         g_mutex_init (&self->mutex);
345         g_cond_init (&self->cond);
346         READ_SOCKET (self) = -1;
347         WRITE_SOCKET (self) = -1;
348
349         gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
350         gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
351
352         self->encoder = NULL;
353         self->encoder_clock = NULL;
354
355 #ifdef dump
356         self->dumpfd = open("/media/hdd/movie/dreamvideosource.dump", O_WRONLY | O_CREAT | O_TRUNC);
357         GST_DEBUG_OBJECT (self, "dumpfd = %i (%s)", self->dumpfd, (self->dumpfd > 0) ? "OK" : strerror(errno));
358 #endif
359 }
360
361 static gboolean gst_dreamvideosource_encoder_init (GstDreamVideoSource * self)
362 {
363         GST_LOG_OBJECT (self, "initializating encoder...");
364         self->encoder = malloc (sizeof(EncoderInfo));
365
366         if (!self->encoder) {
367                 GST_ERROR_OBJECT (self,"out of space");
368                 return FALSE;
369         }
370
371         char fn_buf[32];
372         sprintf(fn_buf, "/dev/venc%d", 0);
373         self->encoder->fd = open(fn_buf, O_RDWR | O_SYNC);
374         if (self->encoder->fd <= 0) {
375                 GST_ERROR_OBJECT (self,"cannot open device %s (%s)", fn_buf, strerror(errno));
376                 free(self->encoder);
377                 self->encoder = NULL;
378                 return FALSE;
379         }
380
381         self->encoder->buffer = malloc(VBUFSIZE);
382         if (!self->encoder->buffer) {
383                 GST_ERROR_OBJECT(self,"cannot alloc buffer");
384                 return FALSE;
385         }
386
387         self->encoder->cdb = (unsigned char *)mmap (0, VMMAPSIZE, PROT_READ, MAP_PRIVATE, self->encoder->fd, 0);
388
389         if (!self->encoder->cdb || self->encoder->cdb == MAP_FAILED) {
390                 GST_ERROR_OBJECT(self,"cannot alloc buffer: %s (%d)", strerror(errno));
391                 self->encoder->cdb = NULL;
392                 return FALSE;
393         }
394
395         int control_sock[2];
396         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
397         {
398                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM);
399                 return GST_STATE_CHANGE_FAILURE;
400         }
401         READ_SOCKET (self) = control_sock[0];
402         WRITE_SOCKET (self) = control_sock[1];
403         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
404         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
405
406         gst_dreamvideosource_set_bitrate (self, self->video_info.bitrate);
407         gst_dreamvideosource_set_format (self, &self->video_info);
408         gst_dreamvideosource_set_input_mode (self, self->input_mode);
409
410 #ifdef PROVIDE_CLOCK
411         self->encoder_clock = gst_dreamsource_clock_new ("GstDreamVideoSinkClock", self->encoder->fd);
412         GST_OBJECT_FLAG_SET (self, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
413 #endif
414
415         GST_LOG_OBJECT (self, "encoder %s successfully initialized", fn_buf);
416         return TRUE;
417 }
418
419 static void gst_dreamvideosource_encoder_release (GstDreamVideoSource * self)
420 {
421         GST_LOG_OBJECT (self, "releasing encoder...");
422         if (self->encoder) {
423                 if (self->encoder->buffer)
424                         free(self->encoder->buffer);
425                 if (self->encoder->cdb)
426                         munmap(self->encoder->cdb, VMMAPSIZE);
427                 if (self->encoder->fd)
428                         close(self->encoder->fd);
429                 free(self->encoder);
430         }
431         self->encoder = NULL;
432         close (READ_SOCKET (self));
433         close (WRITE_SOCKET (self));
434         READ_SOCKET (self) = -1;
435         WRITE_SOCKET (self) = -1;
436         if (self->encoder_clock) {
437                 gst_object_unref (self->encoder_clock);
438                 self->encoder_clock = NULL;
439         }
440 }
441
442 static void
443 gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
444 {
445         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
446
447         switch (prop_id) {
448                 case ARG_CAPS:
449                 {
450                         GstCaps *caps = gst_caps_copy (gst_value_get_caps (value));
451                         gst_dreamvideosource_setcaps(GST_BASE_SRC(object), caps);
452                         gst_caps_unref (caps);
453                         break;
454                 }
455                 case ARG_BITRATE:
456                         gst_dreamvideosource_set_bitrate(self, g_value_get_int (value));
457                         break;
458                 case ARG_INPUT_MODE:
459                         gst_dreamvideosource_set_input_mode (self, g_value_get_enum (value));
460                         break;
461                 default:
462                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
463                         break;
464         }
465 }
466
467 static void
468 gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
469 {
470         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
471
472         switch (prop_id) {
473                 case ARG_CAPS:
474                         g_value_take_boxed (value, gst_dreamvideosource_getcaps (GST_BASE_SRC(object), GST_CAPS_ANY));
475                         break;
476                 case ARG_BITRATE:
477                         g_value_set_int (value, self->video_info.bitrate/1000);
478                         break;
479                 case ARG_INPUT_MODE:
480                         g_value_set_enum (value, gst_dreamvideosource_get_input_mode (self));
481                         break;
482                 default:
483                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
484                         break;
485         }
486 }
487
488 static GstCaps *
489 gst_dreamvideosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
490 {
491         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
492         GstCaps *caps = gst_caps_copy(self->current_caps);
493
494         GST_LOG_OBJECT (self, "gst_dreamvideosource_getcaps %" GST_PTR_FORMAT " filter %" GST_PTR_FORMAT, caps, filter);
495
496         if (filter) {
497                 GstCaps *intersection;
498                 intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
499                 gst_caps_unref (caps);
500                 caps = intersection;
501         }
502
503         GST_DEBUG_OBJECT (self, "return caps %" GST_PTR_FORMAT, caps);
504         return caps;
505 }
506
507 static gboolean
508 gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
509 {
510         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
511         GstBaseSrcClass *bclass = GST_BASE_SRC_GET_CLASS (bsrc);
512         GstCaps *current_caps;
513         const GstStructure *structure;
514         VideoFormatInfo info;
515         gboolean ret;
516         int width, height;
517         const GValue *framerate, *par;
518         structure = gst_caps_get_structure (caps, 0);
519
520         current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc));
521         if (current_caps && gst_caps_is_equal (current_caps, caps)) {
522                 GST_DEBUG_OBJECT (self, "New caps equal to old ones: %" GST_PTR_FORMAT, caps);
523                 ret = TRUE;
524         } else {
525                 GstState state;
526                 gst_element_get_state (GST_ELEMENT(self), &state, NULL, 1*GST_MSECOND);
527                 if (state == GST_STATE_PLAYING)
528                 {
529                         GST_WARNING_OBJECT (self, "can't change caps while in PLAYING state %" GST_PTR_FORMAT, caps);
530                         return TRUE;
531                 }
532                 else if (gst_structure_has_name (structure, "video/x-h264"))
533                 {
534                         memset (&info, 0, sizeof(VideoFormatInfo));
535                         ret = gst_structure_get_int (structure, "width", &info.width);
536                         ret &= gst_structure_get_int (structure, "height", &info.height);
537                         framerate = gst_structure_get_value (structure, "framerate");
538                         if (GST_VALUE_HOLDS_FRACTION(framerate)) {
539                                 info.fps_n = gst_value_get_fraction_numerator (framerate);
540                                 info.fps_d = gst_value_get_fraction_denominator (framerate);
541                         }
542                         GST_INFO_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
543                         gst_caps_replace (&self->current_caps, caps);
544
545                         if (gst_dreamvideosource_set_format(self, &info) && gst_caps_is_fixed(caps))
546                                 ret = gst_pad_push_event (bsrc->srcpad, gst_event_new_caps (caps));
547                 }
548                 else {
549                         GST_WARNING_OBJECT (self, "unsupported caps: %" GST_PTR_FORMAT, caps);
550                         ret = FALSE;
551                 }
552         }
553         if (current_caps)
554                 gst_caps_unref (current_caps);
555         return ret;
556 }
557
558 static GstCaps *
559 gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps)
560 {
561         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
562         GstStructure *structure;
563
564         caps = gst_caps_make_writable (caps);
565         structure = gst_caps_get_structure (caps, 0);
566
567         gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
568         gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
569         gst_structure_fixate_field_nearest_fraction (structure, "framerate", DEFAULT_FRAMERATE, 1);
570         gst_structure_fixate_field_nearest_fraction (structure, "pixel-aspect-ratio", DEFAULT_WIDTH, DEFAULT_HEIGHT);
571
572         caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
573         GST_DEBUG_OBJECT (bsrc, "fixate caps: %" GST_PTR_FORMAT, caps);
574         return caps;
575 }
576
577 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc)
578 {
579         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
580         GST_DEBUG_OBJECT (self, "stop creating buffers");
581         g_mutex_lock (&self->mutex);
582         self->flushing = TRUE;
583         GST_DEBUG_OBJECT (self, "set flushing TRUE");
584         g_cond_signal (&self->cond);
585         g_mutex_unlock (&self->mutex);
586         return TRUE;
587 }
588
589 static gboolean gst_dreamvideosource_unlock_stop (GstBaseSrc * bsrc)
590 {
591         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
592         GST_DEBUG_OBJECT (self, "start creating buffers...");
593         g_mutex_lock (&self->mutex);
594         self->flushing = FALSE;
595         g_queue_foreach (&self->current_frames, (GFunc) gst_buffer_unref, NULL);
596         g_queue_clear (&self->current_frames);
597         g_mutex_unlock (&self->mutex);
598         return TRUE;
599 }
600
601 static void gst_dreamvideosource_read_thread_func (GstDreamVideoSource * self)
602 {
603         EncoderInfo *enc = self->encoder;
604         GstBuffer *readbuf;
605
606         if (!enc) {
607                 GST_WARNING_OBJECT (self, "encoder device not opened!");
608                 return;
609         }
610
611         GST_DEBUG_OBJECT (self, "enter read thread");
612
613         GstMessage *message;
614         GValue val = { 0 };
615
616         message = gst_message_new_stream_status (GST_OBJECT_CAST (self), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (GST_OBJECT_PARENT(self)));
617         g_value_init (&val, GST_TYPE_G_THREAD);
618         g_value_set_boxed (&val, self->readthread);
619         gst_message_set_stream_status_object (message, &val);
620         g_value_unset (&val);
621         GST_DEBUG_OBJECT (self, "posting ENTER stream status");
622         gst_element_post_message (GST_ELEMENT_CAST (self), message);
623
624         while (TRUE) {
625                 readbuf = NULL;
626                 {
627                         struct pollfd rfd[2];
628                         int timeout, nfds;
629
630                         rfd[0].fd = READ_SOCKET (self);
631                         rfd[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
632
633                         if (self->descriptors_available == 0)
634                         {
635                                 rfd[1].fd = enc->fd;
636                                 rfd[1].events = POLLIN;
637                                 self->descriptors_count = 0;
638                                 timeout = 200;
639                                 nfds = 2;
640                         }
641                         else
642                         {
643                                 rfd[1].revents = 0;
644                                 nfds = 1;
645                                 timeout = 0;
646                         }
647
648                         int ret = poll(rfd, nfds, timeout);
649
650                         if (G_UNLIKELY (ret == -1))
651                         {
652                                 GST_ERROR_OBJECT (self, "SELECT ERROR!");
653                                 goto stop_running;
654                         }
655                         else if ( ret == 0 && self->descriptors_available == 0 )
656                         {
657                                 gst_clock_get_time(self->encoder_clock);
658                                 g_mutex_lock (&self->mutex);
659                                 if (self->flushing)
660                                 {
661                                         GST_DEBUG_OBJECT (self, "FLUSHING!");
662                                         g_cond_signal (&self->cond);
663                                         g_mutex_unlock (&self->mutex);
664                                         continue;
665                                 }
666                                 g_mutex_unlock (&self->mutex);
667                                 GST_DEBUG_OBJECT (self, "SELECT TIMEOUT");
668                                 //!!! TODO generate valid dummy payload
669                                 readbuf = gst_buffer_new();
670                         }
671                         else if ( rfd[0].revents )
672                         {
673                                 char command;
674                                 READ_COMMAND (self, command, ret);
675                                 if (command == CONTROL_STOP)
676                                 {
677                                         GST_DEBUG_OBJECT (self, "CONTROL_STOP!");
678                                         goto stop_running;
679                                 }
680                         }
681                         else if ( G_LIKELY(rfd[1].revents & POLLIN) )
682                         {
683                                 int rlen = read(enc->fd, enc->buffer, VBUFSIZE);
684                                 if (rlen <= 0 || rlen % VBDSIZE ) {
685                                         if ( errno == 512 )
686                                                 goto stop_running;
687                                         GST_WARNING_OBJECT (self, "read error %s (%i)", strerror(errno), errno);
688                                         goto stop_running;
689                                 }
690                                 self->descriptors_available = rlen / VBDSIZE;
691                                 GST_LOG_OBJECT (self, "encoder buffer was empty, %d descriptors available", self->descriptors_available);
692                         }
693                 }
694
695                 while (self->descriptors_count < self->descriptors_available)
696                 {
697                         off_t offset = self->descriptors_count * VBDSIZE;
698                         VideoBufferDescriptor *desc = (VideoBufferDescriptor*)(&enc->buffer[offset]);
699
700                         uint32_t f = desc->stCommon.uiFlags;
701
702                         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);
703
704                         if (G_UNLIKELY (f & CDB_FLAG_METADATA))
705                         {
706                                 GST_LOG_OBJECT (self, "CDB_FLAG_METADATA... skip outdated packet");
707                                 self->descriptors_count = self->descriptors_available;
708                                 continue;
709                         }
710
711                         readbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, enc->cdb, VMMAPSIZE, desc->stCommon.uiOffset, desc->stCommon.uiLength, self, NULL);
712
713                         GstClockTime buffer_dts = GST_CLOCK_TIME_NONE;
714                         GstClockTime buffer_pts = GST_CLOCK_TIME_NONE;
715
716                         // uiDTS since kernel driver booted
717                         if (f & VBD_FLAG_DTS_VALID && desc->uiDTS)
718                         {
719                                 buffer_dts = MPEGTIME_TO_GSTTIME(desc->uiDTS);
720                                 GST_LOG_OBJECT (self, "f & VBD_FLAG_DTS_VALID && encoder's uiDTS=%" GST_TIME_FORMAT"", GST_TIME_ARGS(buffer_dts));
721
722                                 g_mutex_lock (&self->mutex);
723                                 if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
724                                 {
725                                         if (self->dreamaudiosrc)
726                                         {
727                                                 guint64 audiosource_base_pts;
728                                                 g_signal_emit_by_name(self->dreamaudiosrc, "get-base-pts", &audiosource_base_pts);
729                                                 if (audiosource_base_pts != GST_CLOCK_TIME_NONE)
730                                                 {
731                                                         GST_DEBUG_OBJECT (self, "use DREAMAUDIOSOURCE's base_pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (audiosource_base_pts) );
732                                                         self->base_pts = audiosource_base_pts;
733                                                 }
734                                         }
735                                         if (self->base_pts == GST_CLOCK_TIME_NONE)
736                                         {
737                                                 self->base_pts = buffer_dts;
738                                                 GST_DEBUG_OBJECT (self, "use mpeg stream pts as base_pts=%" GST_TIME_FORMAT" (%lld)", GST_TIME_ARGS (self->base_pts), desc->uiDTS);
739                                         }
740                                 }
741                                 g_mutex_unlock (&self->mutex);
742
743                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_dts >= self->base_pts )
744                                 {
745                                         buffer_dts -= self->base_pts;
746                                         GST_BUFFER_DTS(readbuf) = buffer_dts;
747                                         GST_LOG_OBJECT (self, "corrected dts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (GST_BUFFER_DTS(readbuf)));
748                                 }
749                         }
750
751                         if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
752                         {
753                                 GST_DEBUG_OBJECT (self, "self->base_pts == GST_CLOCK_TIME_NONE! skip this frame");
754                                 self->descriptors_count++;
755                                 break;
756                         }
757
758                         if (self->video_info.fps_d)
759                                 GST_BUFFER_DURATION(readbuf) = gst_util_uint64_scale (GST_SECOND, self->video_info.fps_d, self->video_info.fps_n);
760
761 //                      if (f & CDB_FLAG_PTS_VALID)
762 //                      {
763 //                              GstClock *clock = gst_element_get_clock (GST_ELEMENT(self));
764 //                              if (clock)
765 //                              {
766 //                                      GstClockTime clock_time, base_time;
767 //                                      clock_time = gst_clock_get_time (clock);
768 //                                      base_time = gst_element_get_base_time (GST_ELEMENT(self));
769 // 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",
770 // 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) );
771 // 
772 //                                      if (clock_time && clock_time > base_time)
773 //                                      {
774 //                                              buffer_time = clock_time - base_time;
775 //                                              gst_object_unref (clock);
776 //      //                                      buffer_time -= GST_BUFFER_DURATION(readbuf);
777 //                                              GST_BUFFER_PTS(readbuf) = buffer_time;
778 //                                              GST_BUFFER_DTS(readbuf) = buffer_time;
779 //
780 //                                      }
781 //                                      else
782 //                                              buffer_time = GST_CLOCK_TIME_NONE;
783 //                              }
784 //                      }
785
786                         if (/*(!clock || buffer_time == GST_CLOCK_TIME_NONE) && */f & CDB_FLAG_PTS_VALID)
787                         {
788                                 buffer_pts = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
789                                 GST_LOG_OBJECT (self, "f & CDB_FLAG_PTS_VALID && encoder's  uiPTS=%" GST_TIME_FORMAT"", GST_TIME_ARGS(buffer_pts));
790                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_pts >= self->base_pts )
791                                 {
792                                         buffer_pts -= self->base_pts/* + GST_BUFFER_DURATION(readbuf)*/;
793                                         GST_BUFFER_PTS(readbuf) = buffer_pts;
794                                         GST_INFO_OBJECT (self, "currected pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (GST_BUFFER_PTS(readbuf)));
795                                 }
796                         }
797
798 #ifdef dump
799                         int wret = write(self->dumpfd, (unsigned char*)(enc->cdb + desc->stCommon.uiOffset), desc->stCommon.uiLength);
800                         GST_LOG_OBJECT (self, "read %i dumped %i total %" G_GSIZE_FORMAT " ", desc->stCommon.uiLength, wret, gst_buffer_get_size (*outbuf) );
801 #endif
802                         self->descriptors_count++;
803                         break;
804                 }
805
806                 if (self->descriptors_count == self->descriptors_available)
807                 {
808                         GST_LOG_OBJECT (self, "self->descriptors_count == self->descriptors_available -> release %i consumed descriptors", self->descriptors_count);
809                         /* release consumed descs */
810                         if (write(enc->fd, &self->descriptors_count, sizeof(self->descriptors_count)) != sizeof(self->descriptors_count)) {
811                                 GST_WARNING_OBJECT (self, "release consumed descs write error!");
812                                 goto stop_running;
813                         }
814                         self->descriptors_available = 0;
815                 }
816
817                 if (readbuf)
818                 {
819                         g_mutex_lock (&self->mutex);
820                         if (!self->flushing)
821                         {
822                                 while (g_queue_get_length (&self->current_frames) >= self->buffer_size)
823                                 {
824                                         GstBuffer * oldbuf = g_queue_pop_head (&self->current_frames);
825                                         GST_WARNING_OBJECT (self, "dropping %" GST_PTR_FORMAT " because of queue overflow! buffers count=%i", oldbuf, g_queue_get_length (&self->current_frames));
826                                         gst_buffer_unref(oldbuf);
827                                 }
828                                 g_queue_push_tail (&self->current_frames, readbuf);
829                         }
830                         else
831                                 gst_buffer_unref(readbuf);
832                         g_cond_signal (&self->cond);
833                         GST_INFO_OBJECT (self, "read %" GST_PTR_FORMAT " to queue", readbuf );
834                         g_mutex_unlock (&self->mutex);
835                 }
836         }
837
838         g_assert_not_reached ();
839         return;
840
841         stop_running:
842         {
843                 g_mutex_unlock (&self->mutex);
844                 g_cond_signal (&self->cond);
845                 GST_DEBUG ("stop running, exit thread");
846                 message = gst_message_new_stream_status (GST_OBJECT_CAST (self), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (GST_OBJECT_PARENT(self)));
847                 g_value_init (&val, GST_TYPE_G_THREAD);
848                 g_value_set_boxed (&val, self->readthread);
849                 gst_message_set_stream_status_object (message, &val);
850                 g_value_unset (&val);
851                 GST_DEBUG_OBJECT (self, "posting LEAVE stream status");
852                 gst_element_post_message (GST_ELEMENT_CAST (self), message);
853                 return;
854         }
855 }
856
857 static GstFlowReturn
858 gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf)
859 {
860         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (psrc);
861
862         GST_LOG_OBJECT (self, "new buffer requested");
863
864         g_mutex_lock (&self->mutex);
865         while (g_queue_is_empty (&self->current_frames) && !self->flushing)
866         {
867                 g_cond_wait (&self->cond, &self->mutex);
868                 GST_INFO_OBJECT (self, "waiting for buffer from encoder");
869         }
870
871         *outbuf = g_queue_pop_head (&self->current_frames);
872         g_mutex_unlock (&self->mutex);
873
874         if (*outbuf)
875         {
876                 GST_INFO_OBJECT (self, "pushing %" GST_PTR_FORMAT "", *outbuf );
877                 return GST_FLOW_OK;
878         }
879         GST_INFO_OBJECT (self, "FLUSHING");
880         return GST_FLOW_FLUSHING;
881 }
882
883
884 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition)
885 {
886         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
887         GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS;
888         int ret;
889
890         switch (transition) {
891                 case GST_STATE_CHANGE_NULL_TO_READY:
892                 {
893                         if (!gst_dreamvideosource_encoder_init (self))
894                                 return GST_STATE_CHANGE_FAILURE;
895                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_NULL_TO_READY");
896                         break;
897                 }
898                 case GST_STATE_CHANGE_READY_TO_PAUSED:
899                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
900 #ifdef PROVIDE_CLOCK
901                         GstMessage* msg;
902                         msg = gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->encoder_clock, TRUE);
903                         GST_INFO_OBJECT (self, "clock: %" GST_PTR_FORMAT " %" GST_PTR_FORMAT " typename=%s", self->encoder_clock, msg, GST_MESSAGE_TYPE_NAME(msg));
904                         gst_element_post_message (element, msg);
905 #endif
906                         self->flushing = TRUE;
907                         self->readthread = g_thread_try_new ("dreamvideosrc-read", (GThreadFunc) gst_dreamvideosource_read_thread_func, self, NULL);
908                         GST_DEBUG_OBJECT (self, "started readthread @%p", self->readthread );
909                         break;
910                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
911                         g_mutex_lock (&self->mutex);
912                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
913                         self->base_pts = GST_CLOCK_TIME_NONE;
914                         ret = ioctl(self->encoder->fd, VENC_START);
915                         if ( ret != 0 )
916                                 goto fail;
917                         self->descriptors_available = 0;
918                         CLEAR_COMMAND (self);
919                         GST_INFO_OBJECT (self, "started encoder!");
920                         g_mutex_unlock (&self->mutex);
921                         break;
922                 default:
923                         break;
924         }
925
926         if (GST_ELEMENT_CLASS (parent_class)->change_state)
927                 sret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
928
929         switch (transition) {
930                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
931                         g_mutex_lock (&self->mutex);
932                         self->flushing = TRUE;
933                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED self->descriptors_count=%i self->descriptors_available=%i", self->descriptors_count, self->descriptors_available);
934                         while (self->descriptors_count < self->descriptors_available)
935                         {
936                                 GST_LOG_OBJECT (self, "flushing self->descriptors_count=%i");
937                                 self->descriptors_count++;
938                         }
939                         if (self->descriptors_count)
940                                 write(self->encoder->fd, &self->descriptors_count, sizeof(self->descriptors_count));
941                         ret = ioctl(self->encoder->fd, VENC_STOP);
942                         if ( ret != 0 )
943                                 goto fail;
944 #ifdef PROVIDE_CLOCK
945                         gst_clock_set_master (self->encoder_clock, NULL);
946 #endif
947                         GST_INFO_OBJECT (self, "stopped encoder!");
948                         g_mutex_unlock (&self->mutex);
949                         break;
950                 case GST_STATE_CHANGE_PAUSED_TO_READY:
951                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PAUSED_TO_READY");
952 #ifdef PROVIDE_CLOCK
953                         gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), self->encoder_clock));
954 #endif
955                         GST_DEBUG_OBJECT (self, "stopping readthread @%p...", self->readthread);
956                         SEND_COMMAND (self, CONTROL_STOP);
957                         g_thread_join (self->readthread);
958                         break;
959                 case GST_STATE_CHANGE_READY_TO_NULL:
960                         gst_dreamvideosource_encoder_release (self);
961                         GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_READY_TO_NULL, close control sockets");
962                         break;
963                 default:
964                         break;
965         }
966
967         return sret;
968 fail:
969         GST_ERROR_OBJECT(self,"can't perform encoder ioctl!");
970         g_mutex_unlock (&self->mutex);
971         return GST_STATE_CHANGE_FAILURE;
972 }
973
974 static gboolean
975 gst_dreamvideosource_start (GstBaseSrc * bsrc)
976 {
977         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
978         self->dreamaudiosrc = gst_bin_get_by_name_recurse_up(GST_BIN(GST_ELEMENT_PARENT(self)), "dreamaudiosource0");
979         GST_DEBUG_OBJECT (self, "started. reference to dreamaudiosource=%" GST_PTR_FORMAT"", self->dreamaudiosrc);
980         return TRUE;
981 }
982
983 static gboolean
984 gst_dreamvideosource_stop (GstBaseSrc * bsrc)
985 {
986         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
987         if (self->dreamaudiosrc)
988                 gst_object_unref(self->dreamaudiosrc);
989         GST_DEBUG_OBJECT (self, "stop");
990         return TRUE;
991 }
992
993 static void
994 gst_dreamvideosource_dispose (GObject * gobject)
995 {
996         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (gobject);
997 #ifdef PROVIDE_CLOCK
998         if (self->encoder_clock) {
999                 gst_object_unref (self->encoder_clock);
1000                 self->encoder_clock = NULL;
1001         }
1002 #endif
1003 #ifdef dump
1004         close(self->dumpfd);
1005 #endif
1006         if (self->current_caps)
1007                 gst_caps_unref(self->current_caps);
1008         g_mutex_clear (&self->mutex);
1009         g_cond_clear (&self->cond);
1010         GST_DEBUG_OBJECT (self, "disposed");
1011         G_OBJECT_CLASS (parent_class)->dispose (gobject);
1012 }
1013
1014 #ifdef PROVIDE_CLOCK
1015 static GstClock *gst_dreamvideosource_provide_clock (GstElement * element)
1016 {
1017         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
1018
1019         if (!self->encoder || self->encoder->fd < 0)
1020         {
1021                 GST_DEBUG_OBJECT (self, "encoder device not started, can't provide clock!");
1022                 return NULL;
1023         }
1024
1025         return GST_CLOCK_CAST (gst_object_ref (self->encoder_clock));
1026 }
1027 #endif