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