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