clear control sock on state change, fixes pause->playing deadlock
[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 enum
30 {
31         SIGNAL_GET_BASE_PTS,
32         LAST_SIGNAL
33 };
34
35 enum
36 {
37   ARG_0,
38   ARG_CAPS,
39   ARG_BITRATE,
40 };
41
42 static guint gst_dreamvideosource_signals[LAST_SIGNAL] = { 0 };
43
44
45 #define DEFAULT_BITRATE 2048
46 #define DEFAULT_FRAMERATE 25
47 #define DEFAULT_WIDTH 1280
48 #define DEFAULT_HEIGHT 720
49
50 static GstStaticPadTemplate srctemplate =
51     GST_STATIC_PAD_TEMPLATE ("src",
52         GST_PAD_SRC,
53         GST_PAD_ALWAYS,
54         GST_STATIC_CAPS ("video/x-h264, "
55         "width = { 720, 1280, 1920 }, "
56         "height = { 576, 720, 1080 }, "
57         "framerate = { 25/1, 30/1, 50/1, 60/1 }, "
58         "pixel-aspect-ratio = { 5/4, 16/9 }, "
59         "stream-format = (string) byte-stream, "
60         "profile = (string) main")
61     );
62
63 #define gst_dreamvideosource_parent_class parent_class
64 G_DEFINE_TYPE (GstDreamVideoSource, gst_dreamvideosource, GST_TYPE_PUSH_SRC);
65
66 static GstCaps *gst_dreamvideosource_getcaps (GstBaseSrc * psrc, GstCaps * filter);
67 static gboolean gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
68 static GstCaps *gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps);
69
70 static gboolean gst_dreamvideosource_start (GstBaseSrc * bsrc);
71 static gboolean gst_dreamvideosource_stop (GstBaseSrc * bsrc);
72 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc);
73 static void gst_dreamvideosource_dispose (GObject * gobject);
74 static GstFlowReturn gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf);
75
76 static void gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
77 static void gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
78
79 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition);
80 static gint64 gst_dreamvideosource_get_base_pts (GstDreamVideoSource *self);
81
82 static void
83 gst_dreamvideosource_class_init (GstDreamVideoSourceClass * klass)
84 {
85         GObjectClass *gobject_class;
86         GstElementClass *gstelement_class;
87         GstBaseSrcClass *gstbsrc_class;
88         GstPushSrcClass *gstpush_src_class;
89
90         gobject_class = (GObjectClass *) klass;
91         gstelement_class = (GstElementClass *) klass;
92         gstbsrc_class = (GstBaseSrcClass *) klass;
93         gstpush_src_class = (GstPushSrcClass *) klass;
94
95         gobject_class->set_property = gst_dreamvideosource_set_property;
96         gobject_class->get_property = gst_dreamvideosource_get_property;
97         gobject_class->dispose = gst_dreamvideosource_dispose;
98
99         gst_element_class_add_pad_template (gstelement_class,
100                                             gst_static_pad_template_get (&srctemplate));
101
102         gst_element_class_set_static_metadata (gstelement_class,
103             "Dream Video source", "Source/Video",
104             "Provide an h.264 video elementary stream from Dreambox encoder device",
105             "Andreas Frisch <fraxinas@opendreambox.org>");
106
107         gstelement_class->change_state = gst_dreamvideosource_change_state;
108
109         gstbsrc_class->get_caps = gst_dreamvideosource_getcaps;
110         gstbsrc_class->set_caps = gst_dreamvideosource_setcaps;
111         gstbsrc_class->fixate = gst_dreamvideosource_fixate;
112         gstbsrc_class->start = gst_dreamvideosource_start;
113         gstbsrc_class->stop = gst_dreamvideosource_stop;
114         gstbsrc_class->unlock = gst_dreamvideosource_unlock;
115
116         gstpush_src_class->create = gst_dreamvideosource_create;
117
118         g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
119           g_param_spec_int ("bitrate", "Bitrate (kb/s)",
120             "Bitrate in kbit/sec", 16, 200000, DEFAULT_BITRATE,
121             G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
122
123         g_object_class_install_property (gobject_class, ARG_CAPS,
124           g_param_spec_boxed ("caps", "Caps",
125             "The caps for the source stream", GST_TYPE_CAPS,
126             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127
128         gst_dreamvideosource_signals[SIGNAL_GET_BASE_PTS] =
129                 g_signal_new ("get-base-pts",
130                 G_TYPE_FROM_CLASS (klass),
131                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
132                 G_STRUCT_OFFSET (GstDreamVideoSourceClass, get_base_pts),
133                 NULL, NULL, gst_dreamsource_marshal_INT64__VOID, G_TYPE_INT64, 0);
134
135         klass->get_base_pts = gst_dreamvideosource_get_base_pts;
136 }
137
138 static gint64
139 gst_dreamvideosource_get_base_pts (GstDreamVideoSource *self)
140 {
141         GST_DEBUG_OBJECT (self, "gst_dreamvideosource_get_base_pts %" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
142         return self->base_pts;
143 }
144
145 static void gst_dreamvideosource_set_bitrate (GstDreamVideoSource * self, uint32_t bitrate)
146 {
147         if (!self->encoder || !self->encoder->fd)
148                 return;
149         g_mutex_lock (&self->mutex);
150         uint32_t vbr = bitrate*1000;
151         int ret = ioctl(self->encoder->fd, VENC_SET_BITRATE, &vbr);
152         if (ret != 0)
153         {
154                 GST_WARNING_OBJECT (self, "can't set video bitrate to %i bytes/s!", vbr);
155                 g_mutex_unlock (&self->mutex);
156                 return;
157         }
158         GST_INFO_OBJECT (self, "set video bitrate to %i kBytes/s", bitrate);
159         self->video_info.bitrate = vbr;
160         g_mutex_unlock (&self->mutex);
161 }
162
163 static gboolean gst_dreamvideosource_set_format (GstDreamVideoSource * self, VideoFormatInfo * info)
164 {
165         if (!self->encoder || !self->encoder->fd)
166         {
167                 GST_ERROR_OBJECT (self, "can't set format because encoder device not opened!");
168                 return FALSE;
169         }
170
171         GST_OBJECT_LOCK (self);
172
173         if (info->fps_n > 0)
174         {
175                 int venc_fps = 0;
176                 switch (info->fps_n) {
177                         case 25:
178                                 venc_fps = rate_25;
179                                 break;
180                         case 30:
181                                 venc_fps = rate_30;
182                                 break;
183                         case 50:
184                                 venc_fps = rate_50;
185                                 break;
186                         case 60:
187                                 venc_fps = rate_60;
188                                 break;
189                         default:
190                                 GST_ERROR_OBJECT (self, "invalid framerate %d/%d", info->fps_n, info->fps_d);
191                                 goto fail;
192                 }
193                 if (!ioctl(self->encoder->fd, VENC_SET_FRAMERATE, &venc_fps))
194                         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);
195                 else
196                 {
197                         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);
198                         goto fail;
199                 }
200         }
201
202         if (info->width && info->height)
203         {
204                 int venc_size = 0;
205                 if ( info->width == 720 && info->height == 576 )
206                         venc_size = fmt_720x576;
207                 else if ( info->width == 1280 && info->height == 720)
208                         venc_size = fmt_1280x720;
209                 else if ( info->width == 1920 && info->height == 1080)
210                         venc_size = fmt_1920x1080;
211                 else
212                 {
213                         GST_ERROR_OBJECT (self, "invalid resolution %dx%d", info->width, info->height);
214                         goto fail;
215                 }
216                 if (!ioctl(self->encoder->fd, VENC_SET_RESOLUTION, &venc_size))
217                         GST_INFO_OBJECT (self, "set resolution to %dx%d -> ioctrl(%d, VENC_SET_RESOLUTION, &%d)", info->width, info->height, self->encoder->fd, venc_size);
218                 else
219                 {
220                         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);
221                         goto fail;
222                 }
223         }
224
225         self->video_info = *info;
226         GST_OBJECT_UNLOCK (self);
227         return TRUE;
228
229 fail:
230         GST_OBJECT_UNLOCK (self);
231         return FALSE;
232 }
233
234
235 gboolean
236 gst_dreamvideosource_plugin_init (GstPlugin *plugin)
237 {
238         GST_DEBUG_CATEGORY_INIT (dreamvideosource_debug, "dreamvideosource", 0, "dreamvideosource");
239         return gst_element_register (plugin, "dreamvideosource", GST_RANK_PRIMARY, GST_TYPE_DREAMVIDEOSOURCE);
240 }
241
242 static void
243 gst_dreamvideosource_init (GstDreamVideoSource * self)
244 {
245         GstPadTemplate *pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS(self), "src");
246         self->current_caps = gst_pad_template_get_caps (pad_template);
247
248         self->encoder = NULL;
249         self->descriptors_available = 0;
250
251         self->buffers_in_use = 0;
252
253         g_mutex_init (&self->mutex);
254         READ_SOCKET (self) = -1;
255         WRITE_SOCKET (self) = -1;
256
257         gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
258         gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
259
260         self->encoder = malloc(sizeof(EncoderInfo));
261
262         if(!self->encoder) {
263                 GST_ERROR_OBJECT(self,"out of space");
264                 return;
265         }
266
267         char fn_buf[32];
268         sprintf(fn_buf, "/dev/venc%d", 0);
269         self->encoder->fd = open(fn_buf, O_RDWR | O_SYNC);
270         if(self->encoder->fd <= 0) {
271                 GST_ERROR_OBJECT(self,"cannot open device %s (%s)", fn_buf, strerror(errno));
272                 free(self->encoder);
273                 self->encoder = NULL;
274                 return;
275         }
276
277         self->encoder->buffer = malloc(VBUFSIZE);
278         if(!self->encoder->buffer) {
279                 GST_ERROR_OBJECT(self,"cannot alloc buffer");
280                 return;
281         }
282
283         self->encoder->cdb = (unsigned char *)mmap(0, VMMAPSIZE, PROT_READ, MAP_PRIVATE, self->encoder->fd, 0);
284
285         if(!self->encoder->cdb) {
286                 GST_ERROR_OBJECT(self,"cannot mmap cdb");
287                 return;
288         }
289
290 #ifdef dump
291         self->dumpfd = open("/media/hdd/movie/dreamvideosource.dump", O_WRONLY | O_CREAT | O_TRUNC);
292         GST_DEBUG_OBJECT (self, "dumpfd = %i (%s)", self->dumpfd, (self->dumpfd > 0) ? "OK" : strerror(errno));
293 #endif
294 }
295
296 static void
297 gst_dreamvideosource_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
298 {
299         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
300
301         switch (prop_id) {
302                 case ARG_CAPS:
303                 {
304                         GstCaps *caps = gst_caps_copy (gst_value_get_caps (value));
305                         gst_dreamvideosource_setcaps(GST_BASE_SRC(object), caps);
306                         gst_caps_unref (caps);
307                         break;
308                 }
309                 case ARG_BITRATE:
310                         gst_dreamvideosource_set_bitrate(self, g_value_get_int (value));
311                         break;
312                 default:
313                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
314                         break;
315         }
316 }
317
318 static void
319 gst_dreamvideosource_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
320 {
321         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (object);
322
323         switch (prop_id) {
324                 case ARG_CAPS:
325                         g_value_take_boxed (value, gst_dreamvideosource_getcaps (GST_BASE_SRC(object), GST_CAPS_ANY));
326                         break;
327                 case ARG_BITRATE:
328                         g_value_set_int (value, self->video_info.bitrate/1000);
329                         break;
330                 default:
331                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
332                         break;
333         }
334 }
335
336 static GstCaps *
337 gst_dreamvideosource_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
338 {
339         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
340         GstCaps *caps = gst_caps_copy(self->current_caps);
341
342         GST_LOG_OBJECT (self, "gst_dreamvideosource_getcaps %" GST_PTR_FORMAT " filter %" GST_PTR_FORMAT, caps, filter);
343
344         if (filter) {
345                 GstCaps *intersection;
346                 intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
347                 gst_caps_unref (caps);
348                 caps = intersection;
349         }
350
351         GST_DEBUG_OBJECT (self, "return caps %" GST_PTR_FORMAT, caps);
352         return caps;
353 }
354
355 static gboolean
356 gst_dreamvideosource_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
357 {
358         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
359         GstBaseSrcClass *bclass = GST_BASE_SRC_GET_CLASS (bsrc);
360         GstCaps *current_caps;
361         const GstStructure *structure;
362         VideoFormatInfo info;
363         gboolean ret;
364         int width, height;
365         const GValue *framerate, *par;
366         structure = gst_caps_get_structure (caps, 0);
367
368         current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc));
369         if (current_caps && gst_caps_is_equal (current_caps, caps)) {
370                 GST_DEBUG_OBJECT (self, "New caps equal to old ones: %" GST_PTR_FORMAT, caps);
371                 ret = TRUE;
372         } else {
373                 GstState state;
374                 gst_element_get_state (GST_ELEMENT(self), &state, NULL, 1*GST_MSECOND);
375                 if (state == GST_STATE_PLAYING)
376                 {
377                         GST_WARNING_OBJECT (self, "can't change caps while in PLAYING state %" GST_PTR_FORMAT, caps);
378                         return TRUE;
379                 }
380                 else if (gst_structure_has_name (structure, "video/x-h264"))
381                 {
382                         memset (&info, 0, sizeof(VideoFormatInfo));
383                         ret = gst_structure_get_int (structure, "width", &info.width);
384                         ret &= gst_structure_get_int (structure, "height", &info.height);
385                         framerate = gst_structure_get_value (structure, "framerate");
386                         if (GST_VALUE_HOLDS_FRACTION(framerate)) {
387                                 info.fps_n = gst_value_get_fraction_numerator (framerate);
388                                 info.fps_d = gst_value_get_fraction_denominator (framerate);
389                         }
390                         GST_INFO_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
391                         gst_caps_replace (&self->current_caps, caps);
392
393                         if (gst_dreamvideosource_set_format(self, &info) && gst_caps_is_fixed(caps))
394                                 ret = gst_pad_push_event (bsrc->srcpad, gst_event_new_caps (caps));
395                 }
396                 else {
397                         GST_WARNING_OBJECT (self, "unsupported caps: %" GST_PTR_FORMAT, caps);
398                         ret = FALSE;
399                 }
400         }
401         if (current_caps)
402                 gst_caps_unref (current_caps);
403         return ret;
404 }
405
406 static GstCaps *
407 gst_dreamvideosource_fixate (GstBaseSrc * bsrc, GstCaps * caps)
408 {
409         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
410         GstStructure *structure;
411
412         caps = gst_caps_make_writable (caps);
413         structure = gst_caps_get_structure (caps, 0);
414
415         gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
416         gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
417         gst_structure_fixate_field_nearest_fraction (structure, "framerate", DEFAULT_FRAMERATE, 1);
418         gst_structure_fixate_field_nearest_fraction (structure, "pixel-aspect-ratio", DEFAULT_WIDTH, DEFAULT_HEIGHT);
419
420         caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
421         GST_DEBUG_OBJECT (bsrc, "fixate caps: %" GST_PTR_FORMAT, caps);
422         return caps;
423 }
424
425 static gboolean gst_dreamvideosource_unlock (GstBaseSrc * bsrc)
426 {
427         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
428         GST_DEBUG_OBJECT (self, "stop creating buffers");
429         SEND_COMMAND (self, CONTROL_STOP);
430         return TRUE;
431 }
432
433 static void
434 gst_dreamvideosource_free_buffer (GstDreamVideoSource * self)
435 {
436         self->buffers_in_use--;
437         GST_TRACE_OBJECT (self, "gst_dreamvideosource_free_buffer buffer still in use: %i", self->buffers_in_use);
438 }
439
440 static GstFlowReturn
441 gst_dreamvideosource_create (GstPushSrc * psrc, GstBuffer ** outbuf)
442 {
443         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (psrc);
444         EncoderInfo *enc = self->encoder;
445
446         GST_LOG_OBJECT (self, "new buffer requested");
447
448         if (!enc) {
449                 GST_WARNING_OBJECT (self, "encoder device not opened!");
450                 return GST_FLOW_ERROR;
451         }
452
453         while (1)
454         {
455                 *outbuf = NULL;
456
457                 if (self->descriptors_available == 0)
458                 {
459                         self->descriptors_count = 0;
460                         struct pollfd rfd[2];
461
462                         rfd[0].fd = enc->fd;
463                         rfd[0].events = POLLIN;
464                         rfd[1].fd = READ_SOCKET (self);
465                         rfd[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
466
467                         int ret = poll(rfd, 2, 200);
468
469                         if (G_UNLIKELY (ret == -1))
470                         {
471                                 GST_ERROR_OBJECT (self, "SELECT ERROR!");
472                                 return GST_FLOW_ERROR;
473                         }
474                         else if ( ret == 0 )
475                         {
476                                 GST_LOG_OBJECT (self, "SELECT TIMEOUT");
477                                 //!!! TODO generate dummy payload
478                                 *outbuf = gst_buffer_new();
479                         }
480                         else if ( G_UNLIKELY (rfd[1].revents) )
481                         {
482                                 char command;
483                                 READ_COMMAND (self, command, ret);
484                                 if (command == CONTROL_STOP)
485                                 {
486                                         GST_LOG_OBJECT (self, "CONTROL_STOP!");
487                                         return GST_FLOW_FLUSHING;
488                                 }
489                         }
490                         else if ( G_LIKELY(rfd[0].revents & POLLIN) )
491                         {
492                                 int rlen = read(enc->fd, enc->buffer, VBUFSIZE);
493                                 if (rlen <= 0 || rlen % VBDSIZE ) {
494                                         if ( errno == 512 )
495                                                 return GST_FLOW_FLUSHING;
496                                         GST_WARNING_OBJECT (self, "read error %s (%i)", strerror(errno), errno);
497                                         return GST_FLOW_ERROR;
498                                 }
499                                 self->descriptors_available = rlen / VBDSIZE;
500                                 GST_LOG_OBJECT (self, "encoder buffer was empty, %d descriptors available", self->descriptors_available);
501                         }
502                 }
503
504                 while (self->descriptors_count < self->descriptors_available) {
505                         off_t offset = self->descriptors_count * VBDSIZE;
506                         VideoBufferDescriptor *desc = (VideoBufferDescriptor*)(&enc->buffer[offset]);
507
508                         uint32_t f = desc->stCommon.uiFlags;
509
510                         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);
511
512                         if (G_UNLIKELY (f & CDB_FLAG_METADATA))
513                         {
514                                 GST_LOG_OBJECT (self, "CDB_FLAG_METADATA... skip outdated packet");
515                                 self->descriptors_count = self->descriptors_available;
516                                 continue;
517                         }
518
519                         if (f & VBD_FLAG_DTS_VALID && desc->uiDTS)
520                         {
521                                 if (G_UNLIKELY (self->base_pts == GST_CLOCK_TIME_NONE))
522                                 {
523                                         if (self->dreamaudiosrc)
524                                         {
525                                                 g_mutex_lock (&self->mutex);
526                                                 guint64 audiosource_base_pts;
527                                                 g_signal_emit_by_name(self->dreamaudiosrc, "get-base-pts", &audiosource_base_pts);
528                                                 if (audiosource_base_pts != GST_CLOCK_TIME_NONE)
529                                                 {
530                                                         GST_DEBUG_OBJECT (self, "use DREAMAUDIOSOURCE's base_pts=%" GST_TIME_FORMAT "", GST_TIME_ARGS (audiosource_base_pts) );
531                                                         self->base_pts = audiosource_base_pts;
532                                                 }
533                                                 g_mutex_unlock (&self->mutex);
534                                         }
535                                         if (self->base_pts == GST_CLOCK_TIME_NONE)
536                                         {
537                                                 self->base_pts = MPEGTIME_TO_GSTTIME(desc->uiDTS);
538                                                 GST_DEBUG_OBJECT (self, "use mpeg stream pts as base_pts=%" GST_TIME_FORMAT"", GST_TIME_ARGS (self->base_pts) );
539                                         }
540                                 }
541                         }
542
543                         *outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, enc->cdb, VMMAPSIZE, desc->stCommon.uiOffset, desc->stCommon.uiLength, self, (GDestroyNotify)gst_dreamvideosource_free_buffer);
544
545                         if (f & CDB_FLAG_PTS_VALID)
546                         {
547                                 GstClockTime buffer_time = MPEGTIME_TO_GSTTIME(desc->stCommon.uiPTS);
548                                 if (self->base_pts != GST_CLOCK_TIME_NONE && buffer_time > self->base_pts )
549                                 {
550                                         buffer_time -= self->base_pts;
551                                         GST_BUFFER_PTS(*outbuf) = buffer_time;
552                                         GST_BUFFER_DTS(*outbuf) = buffer_time;
553                                 }
554                         }
555 #ifdef dump
556                         int wret = write(self->dumpfd, (unsigned char*)(enc->cdb + desc->stCommon.uiOffset), desc->stCommon.uiLength);
557                         GST_LOG_OBJECT (self, "read %i dumped %i total %" G_GSIZE_FORMAT " ", desc->stCommon.uiLength, wret, gst_buffer_get_size (*outbuf) );
558 #endif
559
560                         self->descriptors_count++;
561
562                         break;
563                 }
564
565                 if (self->descriptors_count == self->descriptors_available) {
566                         GST_LOG_OBJECT (self, "self->descriptors_count == self->descriptors_available -> release %i consumed descriptors", self->descriptors_count);
567                         /* release consumed descs */
568                         if (write(enc->fd, &self->descriptors_count, sizeof(self->descriptors_count)) != sizeof(self->descriptors_count)) {
569                                 GST_WARNING_OBJECT (self, "release consumed descs write error!");
570                                 return GST_FLOW_ERROR;
571                         }
572                         self->descriptors_available = 0;
573                 }
574
575                 if (*outbuf)
576                 {
577                         self->buffers_in_use++;
578                         GST_DEBUG_OBJECT (self, "pushing %" GST_PTR_FORMAT "", *outbuf );
579                         return GST_FLOW_OK;
580                 }
581
582         }
583         return GST_FLOW_ERROR;
584 }
585
586 static GstStateChangeReturn gst_dreamvideosource_change_state (GstElement * element, GstStateChange transition)
587 {
588         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (element);
589         GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS;
590         int ret;
591         GST_OBJECT_LOCK (self);
592         switch (transition) {
593                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
594                         GST_LOG_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_PLAYING");
595                         self->base_pts = GST_CLOCK_TIME_NONE;
596                         ret = ioctl(self->encoder->fd, VENC_START);
597                         if ( ret != 0 )
598                                 goto fail;
599                         self->descriptors_available = 0;
600                         CLEAR_COMMAND (self);
601                         GST_INFO_OBJECT (self, "started encoder!");
602                         break;
603                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
604                         GST_DEBUG_OBJECT (self, "GST_STATE_CHANGE_PLAYING_TO_PAUSED self->descriptors_count=%i self->descriptors_available=%i", self->descriptors_count, self->descriptors_available);
605                         while (self->descriptors_count < self->descriptors_available)
606                                 GST_LOG_OBJECT (self, "flushing self->descriptors_count=%i", self->descriptors_count++);
607                         if (self->descriptors_count)
608                                 write(self->encoder->fd, &self->descriptors_count, sizeof(self->descriptors_count));
609                         ret = ioctl(self->encoder->fd, VENC_STOP);
610                         if ( ret != 0 )
611                                 goto fail;
612                         GST_INFO_OBJECT (self, "stopped encoder!");
613                         break;
614                 default:
615                         break;
616         }
617         GST_OBJECT_UNLOCK (self);
618         if (GST_ELEMENT_CLASS (parent_class)->change_state)
619                 sret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
620         return sret;
621 fail:
622         GST_ERROR_OBJECT(self,"can't perform encoder ioctl!");
623         GST_OBJECT_UNLOCK (self);
624         return GST_STATE_CHANGE_FAILURE;
625 }
626
627 static gboolean
628 gst_dreamvideosource_start (GstBaseSrc * bsrc)
629 {
630         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
631         self->dreamaudiosrc = gst_bin_get_by_name_recurse_up(GST_BIN(GST_ELEMENT_PARENT(self)), "dreamaudiosource0");
632
633         int control_sock[2];
634         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
635         {
636                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM);
637                 return FALSE;
638         }
639         READ_SOCKET (self) = control_sock[0];
640         WRITE_SOCKET (self) = control_sock[1];
641         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
642         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
643
644         GST_DEBUG_OBJECT (self, "started. reference to dreamaudiosource=%" GST_PTR_FORMAT"", self->dreamaudiosrc);
645         return TRUE;
646 }
647
648 static gboolean
649 gst_dreamvideosource_stop (GstBaseSrc * bsrc)
650 {
651         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (bsrc);
652         if (self->dreamaudiosrc)
653                 gst_object_unref(self->dreamaudiosrc);
654         GST_DEBUG_OBJECT (self, "stop");
655         return TRUE;
656 }
657
658 static void
659 gst_dreamvideosource_dispose (GObject * gobject)
660 {
661         GstDreamVideoSource *self = GST_DREAMVIDEOSOURCE (gobject);
662         if (self->encoder) {
663                 if (self->encoder->buffer)
664                         free(self->encoder->buffer);
665                 if (self->encoder->cdb)
666                         munmap(self->encoder->cdb, VMMAPSIZE);
667                 if (self->encoder->fd)
668                         close(self->encoder->fd);
669                 free(self->encoder);
670         }
671 #ifdef dump
672         close(self->dumpfd);
673 #endif
674         if (self->current_caps)
675                 gst_caps_unref(self->current_caps);
676         g_mutex_clear (&self->mutex);
677         GST_DEBUG_OBJECT (self, "disposed");
678         G_OBJECT_CLASS (parent_class)->dispose (gobject);
679 }