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