small cleanup, add PCM support via audiosink (only works with dreambox linux 3.2...
[gst-plugin-dvbmediasink.git] / src / gstdvbvideosink.c
1 /* GStreamer DVB Media Sink
2  * Copyright 2006 Felix Domke <tmbinc@elitedvb.net>
3  * based on code by:
4  * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
5  * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
6  * 
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Alternatively, the contents of this file may be used under the
26  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
27  * which case the following provisions apply instead of the ones
28  * mentioned above:
29  *
30  * This library is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU Library General Public
32  * License as published by the Free Software Foundation; either
33  * version 2 of the License, or (at your option) any later version.
34  *
35  * This library is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38  * Library General Public License for more details.
39  *
40  * You should have received a copy of the GNU Library General Public
41  * License along with this library; if not, write to the
42  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
43  * Boston, MA 02111-1307, USA.
44  */
45
46 /**
47  * SECTION:element-plugin
48  *
49  * <refsect2>
50  * <title>Example launch line</title>
51  * <para>
52  * <programlisting>
53  * gst-launch -v -m audiotestsrc ! plugin ! fakesink silent=TRUE
54  * </programlisting>
55  * </para>
56  * </refsect2>
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #include <config.h>
61 #endif
62 #include <unistd.h>
63 #include <stdint.h>
64 #include <sys/ioctl.h>
65 #include <sys/socket.h>
66 #include <linux/dvb/video.h>
67 #include <fcntl.h>
68 #include <poll.h>
69 #include <string.h>
70
71 #include <gst/gst.h>
72
73 #include "gstdvbvideosink.h"
74 #include "gstdvbsink-marshal.h"
75
76 #ifndef VIDEO_GET_PTS
77 #define VIDEO_GET_PTS              _IOR('o', 57, gint64)
78 #endif
79
80 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
81 struct bitstream
82 {
83         guint8 *data;
84         guint8 last;
85         int avail;
86 };
87
88 void bitstream_init(struct bitstream *bit, const void *buffer, gboolean wr)
89 {
90         bit->data = (guint8*) buffer;
91         if (wr) {
92                 bit->avail = 0;
93                 bit->last = 0;
94         }
95         else {
96                 bit->avail = 8;
97                 bit->last = *bit->data++;
98         }
99 }
100
101 unsigned long bitstream_get(struct bitstream *bit, int bits)
102 {
103         unsigned long res=0;
104         while (bits)
105         {
106                 unsigned int d=bits;
107                 if (!bit->avail) {
108                         bit->last = *bit->data++;
109                         bit->avail = 8;
110                 }
111                 if (d > bit->avail)
112                         d=bit->avail;
113                 res<<=d;
114                 res|=(bit->last>>(bit->avail-d))&~(-1<<d);
115                 bit->avail-=d;
116                 bits-=d;
117         }
118         return res;
119 }
120
121 void bitstream_put(struct bitstream *bit, unsigned long val, int bits)
122 {
123         while (bits)
124         {
125                 bit->last |= ((val & (1 << (bits-1))) ? 1 : 0) << (7 - bit->avail);
126                 if (++bit->avail == 8) {
127                         *bit->data = bit->last;
128                         ++bit->data;
129                         bit->last = 0;
130                         bit->avail = 0;
131                 }
132                 --bits;
133         }
134 }
135 #endif
136
137 /* We add a control socket as in fdsrc to make it shutdown quickly when it's blocking on the fd.
138  * Poll is used to determine when the fd is ready for use. When the element state is changed,
139  * it happens from another thread while fdsink is poll'ing on the fd. The state-change thread 
140  * sends a control message, so fdsink wakes up and changes state immediately otherwise
141  * it would stay blocked until it receives some data. */
142
143 /* the poll call is also performed on the control sockets, that way
144  * we can send special commands to unblock the poll call */
145 #define CONTROL_STOP            'S'                     /* stop the poll call */
146 #define CONTROL_SOCKETS(sink)   sink->control_sock
147 #define WRITE_SOCKET(sink)      sink->control_sock[1]
148 #define READ_SOCKET(sink)       sink->control_sock[0]
149
150 #define SEND_COMMAND(sink, command)                     \
151 G_STMT_START {                                          \
152         unsigned char c; c = command;                   \
153         write (WRITE_SOCKET(sink), &c, 1);              \
154 } G_STMT_END
155
156 #define READ_COMMAND(sink, command, res)                \
157 G_STMT_START {                                          \
158         res = read(READ_SOCKET(sink), &command, 1);     \
159 } G_STMT_END
160
161 GST_DEBUG_CATEGORY_STATIC (dvbvideosink_debug);
162 #define GST_CAT_DEFAULT dvbvideosink_debug
163
164 #define COMMON_VIDEO_CAPS \
165   "width = (int) [ 16, 4096 ], " \
166   "height = (int) [ 16, 4096 ], " \
167   "framerate = (fraction) [ 0, MAX ]"
168
169 #define MPEG4V2_LIMITED_CAPS \
170   "width = (int) [ 16, 800 ], " \
171   "height = (int) [ 16, 600 ], " \
172   "framerate = (fraction) [ 0, MAX ]"
173
174 enum
175 {
176         SIGNAL_GET_DECODER_TIME,
177         LAST_SIGNAL
178 };
179
180 static guint gst_dvb_videosink_signals[LAST_SIGNAL] = { 0 };
181
182 static GstStaticPadTemplate sink_factory_bcm7400 =
183 GST_STATIC_PAD_TEMPLATE (
184         "sink",
185         GST_PAD_SINK,
186         GST_PAD_ALWAYS,
187         GST_STATIC_CAPS (
188                 "video/mpeg, "
189                 "mpegversion = (int) { 1, 2, 4 }, "
190                 "systemstream = (boolean) false, "
191         COMMON_VIDEO_CAPS "; "
192                 "video/x-h264, "
193         COMMON_VIDEO_CAPS "; "
194                 "video/x-h263, "
195         COMMON_VIDEO_CAPS "; "
196                 "video/x-msmpeg, "
197         MPEG4V2_LIMITED_CAPS ", mspegversion = (int) 43; "
198                 "video/x-divx, "
199         MPEG4V2_LIMITED_CAPS ", divxversion = (int) [ 3, 5 ]; "
200                 "video/x-xvid, "
201         MPEG4V2_LIMITED_CAPS "; "
202                 "video/x-3ivx, "
203         MPEG4V2_LIMITED_CAPS "; ")
204 );
205
206 static GstStaticPadTemplate sink_factory_bcm7405 =
207 GST_STATIC_PAD_TEMPLATE (
208         "sink",
209         GST_PAD_SINK,
210         GST_PAD_ALWAYS,
211         GST_STATIC_CAPS (
212                 "video/mpeg, "
213                 "mpegversion = (int) { 1, 2, 4 }, "
214                 "systemstream = (boolean) false, "
215         COMMON_VIDEO_CAPS "; "
216                 "video/x-msmpeg, "
217         COMMON_VIDEO_CAPS ", mspegversion = (int) 43; "
218                 "video/x-h264, "
219         COMMON_VIDEO_CAPS "; "
220                 "video/x-h263, "
221         COMMON_VIDEO_CAPS "; "
222                 "video/x-divx, "
223         COMMON_VIDEO_CAPS ", divxversion = (int) [ 3, 5 ]; "
224                 "video/x-xvid, "
225         COMMON_VIDEO_CAPS "; "
226                 "video/x-3ivx, "
227         COMMON_VIDEO_CAPS "; ")
228 );
229
230
231 static GstStaticPadTemplate sink_factory_bcm7401 =
232 GST_STATIC_PAD_TEMPLATE (
233         "sink",
234         GST_PAD_SINK,
235         GST_PAD_ALWAYS,
236         GST_STATIC_CAPS (
237                 "video/mpeg, "
238                 "mpegversion = (int) { 1, 2, 4 }, "
239                 "systemstream = (boolean) false, "
240         COMMON_VIDEO_CAPS "; "
241                 "video/x-h264, "
242         COMMON_VIDEO_CAPS "; "
243                 "video/x-h263, "
244         COMMON_VIDEO_CAPS "; ")
245 );
246
247 static GstStaticPadTemplate sink_factory_ati_xilleon =
248 GST_STATIC_PAD_TEMPLATE (
249         "sink",
250         GST_PAD_SINK,
251         GST_PAD_ALWAYS,
252         GST_STATIC_CAPS (
253                 "video/mpeg, "
254                 "mpegversion = (int) { 1, 2 }, "
255                 "systemstream = (boolean) false, "
256         COMMON_VIDEO_CAPS "; ")
257 );
258
259 #define DEBUG_INIT(bla) \
260         GST_DEBUG_CATEGORY_INIT (dvbvideosink_debug, "dvbvideosink", 0, "dvbvideosink element");
261
262 GST_BOILERPLATE_FULL (GstDVBVideoSink, gst_dvbvideosink, GstBaseSink,
263         GST_TYPE_BASE_SINK, DEBUG_INIT);
264
265 static gboolean gst_dvbvideosink_start (GstBaseSink * sink);
266 static gboolean gst_dvbvideosink_stop (GstBaseSink * sink);
267 static gboolean gst_dvbvideosink_event (GstBaseSink * sink, GstEvent * event);
268 static GstFlowReturn gst_dvbvideosink_render (GstBaseSink * sink, GstBuffer * buffer);
269 static gboolean gst_dvbvideosink_set_caps (GstBaseSink * sink, GstCaps * caps);
270 static gboolean gst_dvbvideosink_unlock (GstBaseSink * basesink);
271 static gboolean gst_dvbvideosink_unlock_stop (GstBaseSink * basesink);
272 static void gst_dvbvideosink_dispose (GObject * object);
273 static GstStateChangeReturn gst_dvbvideosink_change_state (GstElement * element, GstStateChange transition);
274 static gint64 gst_dvbvideosink_get_decoder_time (GstDVBVideoSink *self);
275
276 typedef enum { DM7025, DM800, DM8000, DM500HD, DM800SE, DM7020HD } hardware_type_t;
277
278 static hardware_type_t hwtype;
279
280 static void
281 gst_dvbvideosink_base_init (gpointer klass)
282 {
283         static GstElementDetails element_details = {
284                 "A DVB video sink",
285                 "Generic/DVBVideoSink",
286                 "Output video PES / ES into a DVB video device for hardware playback",
287                 "Felix Domke <tmbinc@elitedvb.net>"
288         };
289         GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
290
291         int fd = open("/proc/stb/info/model", O_RDONLY);
292         if ( fd > 0 )
293         {
294                 gchar string[9] = { 0, };
295                 ssize_t rd = read(fd, string, 8);
296                 if ( rd >= 5 )
297                 {
298                         if ( !strncasecmp(string, "DM7025", 6) ) {
299                                 hwtype = DM7025;
300                                 GST_INFO ("model is DM7025... set ati xilleon caps");
301                                 gst_element_class_add_pad_template (element_class,
302                                         gst_static_pad_template_get (&sink_factory_ati_xilleon));
303                         } else if ( !strncasecmp(string, "DM500HD", 7) ) {
304                                 hwtype = DM500HD;
305                                 GST_INFO ("model is DM500HD... set bcm7405 caps");
306                                 gst_element_class_add_pad_template (element_class,
307                                         gst_static_pad_template_get (&sink_factory_bcm7405));
308                         } else if ( !strncasecmp(string, "DM800SE", 7) ) {
309                                 hwtype = DM800SE;
310                                 GST_INFO ("model is DM800SE... set bcm7405 caps");
311                                 gst_element_class_add_pad_template (element_class,
312                                         gst_static_pad_template_get (&sink_factory_bcm7405));
313                         } else if ( !strncasecmp(string, "DM7020HD", 8) ) {
314                                 hwtype = DM7020HD;
315                                 GST_INFO ("model is DM7020HD... set bcm7405 caps");
316                                 gst_element_class_add_pad_template (element_class,
317                                         gst_static_pad_template_get (&sink_factory_bcm7405));
318                         } else if ( !strncasecmp(string, "DM8000", 6) ) {
319                                 hwtype = DM8000;
320                                 GST_INFO ("model is DM8000... set bcm7400 caps");
321                                 gst_element_class_add_pad_template (element_class,
322                                         gst_static_pad_template_get (&sink_factory_bcm7400));
323                         } else if ( !strncasecmp(string, "DM800", 5) ) {
324                                 hwtype = DM800;
325                                 GST_INFO ("model is DM800 set bcm7401 caps");
326                                 gst_element_class_add_pad_template (element_class,
327                                         gst_static_pad_template_get (&sink_factory_bcm7401));
328                         }
329                 }
330                 close(fd);
331         }
332
333         gst_element_class_set_details (element_class, &element_details);
334 }
335
336 /* initialize the plugin's class */
337 static void
338 gst_dvbvideosink_class_init (GstDVBVideoSinkClass *klass)
339 {
340         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
341         GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
342         GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
343
344         gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dvbvideosink_dispose);
345
346         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbvideosink_start);
347         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbvideosink_stop);
348         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbvideosink_render);
349         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbvideosink_event);
350         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbvideosink_unlock);
351         gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_dvbvideosink_unlock_stop);
352         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dvbvideosink_set_caps);
353
354         element_class->change_state = GST_DEBUG_FUNCPTR (gst_dvbvideosink_change_state);
355
356         gst_dvb_videosink_signals[SIGNAL_GET_DECODER_TIME] =
357                 g_signal_new ("get-decoder-time",
358                 G_TYPE_FROM_CLASS (klass),
359                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
360                 G_STRUCT_OFFSET (GstDVBVideoSinkClass, get_decoder_time),
361                 NULL, NULL, gst_dvbsink_marshal_INT64__VOID, G_TYPE_INT64, 0);
362
363         klass->get_decoder_time = gst_dvbvideosink_get_decoder_time;
364 }
365
366 #define H264_BUFFER_SIZE (64*1024+2048)
367
368 /* initialize the new element
369  * instantiate pads and add them to element
370  * set functions
371  * initialize structure
372  */
373 static void
374 gst_dvbvideosink_init (GstDVBVideoSink *klass, GstDVBVideoSinkClass * gclass)
375 {
376         FILE *f = fopen("/proc/stb/vmpeg/0/fallback_framerate", "r");
377         klass->dec_running = FALSE;
378         klass->must_send_header = 1;
379         klass->h264_buffer = NULL;
380         klass->h264_nal_len_size = 0;
381         klass->codec_data = NULL;
382         klass->codec_type = CT_H264;
383 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
384         klass->must_pack_bitstream = 0;
385         klass->num_non_keyframes = 0;
386         klass->prev_frame = NULL;
387 #endif
388         klass->no_write = 0;
389         klass->queue = NULL;
390         klass->fd = -1;
391
392         if (f) {
393                 fgets(klass->saved_fallback_framerate, 16, f);
394                 fclose(f);
395         }
396
397         gst_base_sink_set_sync(GST_BASE_SINK (klass), FALSE);
398         gst_base_sink_set_async_enabled(GST_BASE_SINK (klass), TRUE);
399 }
400
401 static void gst_dvbvideosink_dispose (GObject * object)
402 {
403         GstDVBVideoSink *self = GST_DVBVIDEOSINK (object);
404         GstState state, pending;
405         GST_DEBUG_OBJECT(self, "dispose");
406
407 // hack for decodebin2 bug.. decodebin2 tries to dispose ..but doesnt set state to NULL when it is READY
408         switch(gst_element_get_state(GST_ELEMENT(object), &state, &pending, GST_CLOCK_TIME_NONE))
409         {
410         case GST_STATE_CHANGE_SUCCESS:
411                 GST_DEBUG_OBJECT(self, "success");
412                 if (state != GST_STATE_NULL) {
413                         GST_DEBUG_OBJECT(self, "state %d in dispose.. set it to NULL (decodebin2 bug?)", state);
414                         if (gst_element_set_state(GST_ELEMENT(object), GST_STATE_NULL) == GST_STATE_CHANGE_ASYNC) {
415                                 GST_DEBUG_OBJECT(self, "set state returned async... wait!");
416                                 gst_element_get_state(GST_ELEMENT(object), &state, &pending, GST_CLOCK_TIME_NONE);
417                         }
418                 }
419                 break;
420         case GST_STATE_CHANGE_ASYNC:
421                 GST_DEBUG_OBJECT(self, "async");
422                 break;
423         case GST_STATE_CHANGE_FAILURE:
424                 GST_DEBUG_OBJECT(self, "failure");
425                 break;
426         case GST_STATE_CHANGE_NO_PREROLL:
427                 GST_DEBUG_OBJECT(self, "no preroll");
428                 break;
429         default:
430                 break;
431         }
432 // hack end
433
434         GST_DEBUG_OBJECT(self, "state in dispose %d, pending %d", state, pending);
435
436         G_OBJECT_CLASS (parent_class)->dispose (object);
437 }
438
439 static gint64 gst_dvbvideosink_get_decoder_time (GstDVBVideoSink *self)
440 {
441         if (self->dec_running) {
442                 gint64 cur = 0;
443                 static gint64 last_pos = 0;
444
445                 ioctl(self->fd, VIDEO_GET_PTS, &cur);
446
447                 /* workaround until driver fixed */
448                 if (cur)
449                         last_pos = cur;
450                 else
451                         cur = last_pos;
452
453                 cur *= 11111;
454
455                 return cur;
456         }
457         return GST_CLOCK_TIME_NONE;
458 }
459
460 static gboolean gst_dvbvideosink_unlock (GstBaseSink * basesink)
461 {
462         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
463         GST_OBJECT_LOCK(self);
464         self->no_write |= 2;
465         GST_OBJECT_UNLOCK(self);
466         SEND_COMMAND (self, CONTROL_STOP);
467         GST_DEBUG_OBJECT (basesink, "unlock");
468         return TRUE;
469 }
470
471 static gboolean gst_dvbvideosink_unlock_stop (GstBaseSink * basesink)
472 {
473         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
474         GST_OBJECT_LOCK(self);
475         self->no_write &= ~2;
476         GST_OBJECT_UNLOCK(self);
477         GST_DEBUG_OBJECT (basesink, "unlock_stop");
478         return TRUE;
479 }
480
481 void queue_push(queue_entry_t **queue_base, guint8 *data, size_t len)
482 {
483         queue_entry_t *entry = malloc(sizeof(queue_entry_t)+len);
484         queue_entry_t *last = *queue_base;
485         guint8 *d = (guint8*)(entry+1);
486         memcpy(d, data, len);
487         entry->bytes = len;
488         entry->offset = 0;
489         if (!last)
490                 *queue_base = entry;
491         else {
492                 while(last->next)
493                         last = last->next;
494                 last->next = entry;
495         }
496         entry->next = NULL;
497 }
498
499 void queue_pop(queue_entry_t **queue_base)
500 {
501         queue_entry_t *base = *queue_base;
502         *queue_base = base->next;
503         free(base);
504 }
505
506 int queue_front(queue_entry_t **queue_base, guint8 **data, size_t *bytes)
507 {
508         if (!*queue_base) {
509                 *bytes = 0;
510                 *data = 0;
511         }
512         else {
513                 queue_entry_t *entry = *queue_base;
514                 *bytes = entry->bytes - entry->offset;
515                 *data = ((guint8*)(entry+1))+entry->offset;
516         }
517         return *bytes;
518 }
519
520 static gboolean
521 gst_dvbvideosink_event (GstBaseSink * sink, GstEvent * event)
522 {
523         GstDVBVideoSink *self = GST_DVBVIDEOSINK (sink);
524         GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
525         int ret=TRUE;
526
527         switch (GST_EVENT_TYPE (event)) {
528         case GST_EVENT_FLUSH_START:
529                 GST_OBJECT_LOCK(self);
530                 self->no_write |= 1;
531                 GST_OBJECT_UNLOCK(self);
532                 SEND_COMMAND (self, CONTROL_STOP);
533                 break;
534         case GST_EVENT_FLUSH_STOP:
535                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
536                 GST_OBJECT_LOCK(self);
537                 self->must_send_header = 1;
538                 if (hwtype == DM7025)
539                         ++self->must_send_header;  // we must send the sequence header twice on dm7025... 
540                 while (self->queue)
541                         queue_pop(&self->queue);
542                 self->no_write &= ~1;
543                 GST_OBJECT_UNLOCK(self);
544                 break;
545         case GST_EVENT_EOS:
546         {
547                 struct pollfd pfd[2];
548                 int retval;
549
550                 pfd[0].fd = READ_SOCKET(self);
551                 pfd[0].events = POLLIN;
552                 pfd[1].fd = self->fd;
553                 pfd[1].events = POLLIN;
554
555                 GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
556                 while (1) {
557                         retval = poll(pfd, 2, 250);
558                         if (retval < 0) {
559                                 perror("poll in EVENT_EOS");
560                                 ret=FALSE;
561                                 break;
562                         }
563
564                         if (pfd[0].revents & POLLIN) {
565                                 GST_DEBUG_OBJECT (self, "wait EOS aborted!!\n");
566                                 ret=FALSE;
567                                 break;
568                         }
569
570                         if (pfd[1].revents & POLLIN) {
571                                 GST_DEBUG_OBJECT (self, "got buffer empty from driver!\n");
572                                 break;
573                         }
574
575                         if (sink->flushing) {
576                                 GST_DEBUG_OBJECT (self, "wait EOS flushing!!\n");
577                                 ret=FALSE;
578                                 break;
579                         }
580                 }
581                 GST_PAD_PREROLL_LOCK (sink->sinkpad);
582
583                 break;
584         }
585         case GST_EVENT_NEWSEGMENT:{
586                 GstFormat fmt;
587                 gboolean update;
588                 gdouble rate, applied_rate;
589                 gint64 cur, stop, time;
590                 int skip = 0, repeat = 0, ret;
591                 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &fmt, &cur, &stop, &time);
592                 GST_DEBUG_OBJECT (self, "GST_EVENT_NEWSEGMENT rate=%f applied_rate=%f\n", rate, applied_rate);
593                 
594                 if (fmt == GST_FORMAT_TIME)
595                 {       
596                         if ( rate > 1 )
597                                 skip = (int) rate;
598                         else if ( rate < 1 )
599                                 repeat = 1.0/rate;
600
601                         ret = ioctl(self->fd, VIDEO_SLOWMOTION, repeat);
602                         ret = ioctl(self->fd, VIDEO_FAST_FORWARD, skip);
603 //                      gst_segment_set_newsegment_full (&dec->segment, update, rate, applied_rate, dformat, cur, stop, time);
604                 }
605                 break;
606         }
607
608         default:
609                 break;
610         }
611
612         return ret;
613 }
614
615 #define ASYNC_WRITE(data, len) do { \
616                 switch(AsyncWrite(sink, self, data, len)) { \
617                 case -1: goto poll_error; \
618                 case -3: goto write_error; \
619                 default: break; \
620                 } \
621         } while(0)
622
623 static int AsyncWrite(GstBaseSink * sink, GstDVBVideoSink *self, unsigned char *data, unsigned int len)
624 {
625         unsigned int written=0;
626         struct pollfd pfd[2];
627
628         pfd[0].fd = READ_SOCKET(self);
629         pfd[0].events = POLLIN;
630         pfd[1].fd = self->fd;
631         pfd[1].events = POLLOUT | POLLPRI;
632
633         do {
634 loop_start:
635                 if (self->no_write & 1) {
636                         GST_DEBUG_OBJECT (self, "skip %d bytes", len - written);
637                         break;
638                 }
639                 else if (self->no_write & 6) {
640                         // directly push to queue
641                         GST_OBJECT_LOCK(self);
642                         queue_push(&self->queue, data + written, len - written);
643                         GST_OBJECT_UNLOCK(self);
644                         GST_DEBUG_OBJECT (self, "pushed %d bytes to queue", len - written);
645                         break;
646                 }
647                 else
648                         GST_LOG_OBJECT (self, "going into poll, have %d bytes to write", len - written);
649                 if (poll(pfd, 2, -1) == -1) {
650                         if (errno == EINTR)
651                                 continue;
652                         return -1;
653                 }
654                 if (pfd[0].revents & POLLIN) {
655                         /* read all stop commands */
656                         while (TRUE) {
657                                 gchar command;
658                                 int res;
659                                 READ_COMMAND (self, command, res);
660                                 if (res < 0) {
661                                         GST_DEBUG_OBJECT (self, "no more commands");
662                                         /* no more commands */
663                                         goto loop_start;
664                                 }
665                         }
666                 }
667                 if (pfd[1].revents & POLLPRI) {
668                         GstStructure *s;
669                         GstMessage *msg;
670                         struct video_event evt;
671                         if (ioctl(self->fd, VIDEO_GET_EVENT, &evt) < 0)
672                                 g_warning ("failed to ioctl VIDEO_GET_EVENT!");
673                         else {
674                                 GST_INFO_OBJECT (self, "VIDEO_EVENT %d", evt.type);
675                                 if (evt.type == VIDEO_EVENT_SIZE_CHANGED) {
676                                         s = gst_structure_new ("eventSizeChanged",
677                                                 "aspect_ratio", G_TYPE_INT, evt.u.size.aspect_ratio == 0 ? 2 : 3,
678                                                 "width", G_TYPE_INT, evt.u.size.w,
679                                                 "height", G_TYPE_INT, evt.u.size.h, NULL);
680                                         msg = gst_message_new_element (GST_OBJECT (sink), s);
681                                         gst_element_post_message (GST_ELEMENT (sink), msg);
682                                 } else if (evt.type == VIDEO_EVENT_FRAME_RATE_CHANGED) {
683                                         s = gst_structure_new ("eventFrameRateChanged",
684                                                 "frame_rate", G_TYPE_INT, evt.u.frame_rate, NULL);
685                                         msg = gst_message_new_element (GST_OBJECT (sink), s);
686                                         gst_element_post_message (GST_ELEMENT (sink), msg);
687                                 } else if (evt.type == 16 /*VIDEO_EVENT_PROGRESSIVE_CHANGED*/) {
688                                         s = gst_structure_new ("eventProgressiveChanged",
689                                                 "progressive", G_TYPE_INT, evt.u.frame_rate, NULL);
690                                         msg = gst_message_new_element (GST_OBJECT (sink), s);
691                                         gst_element_post_message (GST_ELEMENT (sink), msg);
692                                 } else
693                                         g_warning ("unhandled DVBAPI Video Event %d", evt.type);
694                         }
695                 }
696                 if (pfd[1].revents & POLLOUT) {
697                         size_t queue_entry_size;
698                         guint8 *queue_data;
699                         GST_OBJECT_LOCK(self);
700                         if (queue_front(&self->queue, &queue_data, &queue_entry_size)) {
701                                 int wr = write(self->fd, queue_data, queue_entry_size);
702                                 if (wr < 0) {
703                                         switch (errno) {
704                                                 case EINTR:
705                                                 case EAGAIN:
706                                                         break;
707                                                 default:
708                                                         GST_OBJECT_UNLOCK(self);
709                                                         return -3;
710                                         }
711                                 }
712                                 else if (wr == queue_entry_size) {
713                                         queue_pop(&self->queue);
714                                         GST_DEBUG_OBJECT (self, "written %d queue bytes... pop entry", wr);
715                                 }
716                                 else {
717                                         self->queue->offset += wr;
718                                         GST_DEBUG_OBJECT (self, "written %d queue bytes... update offset", wr);
719                                 }
720                                 GST_OBJECT_UNLOCK(self);
721                                 continue;
722                         }
723                         GST_OBJECT_UNLOCK(self);
724                         int wr = write(self->fd, data+written, len - written);
725                         if (wr < 0) {
726                                 switch (errno) {
727                                         case EINTR:
728                                         case EAGAIN:
729                                                 continue;
730                                         default:
731                                                 return -3;
732                                 }
733                         }
734                         written += wr;
735                 }
736         } while (written != len);
737
738         return 0;
739 }
740
741 static GstFlowReturn
742 gst_dvbvideosink_render (GstBaseSink * sink, GstBuffer * buffer)
743 {
744         GstDVBVideoSink *self = GST_DVBVIDEOSINK (sink);
745         unsigned char *data = GST_BUFFER_DATA(buffer);
746         unsigned int data_len = GST_BUFFER_SIZE (buffer);
747         guint8 pes_header[2048];
748         unsigned int pes_header_len=0;
749         unsigned int payload_len=0;
750 //      int i=0;
751
752 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
753         gboolean commit_prev_frame_data = FALSE,
754                         cache_prev_frame = FALSE;
755 #endif
756
757 //      for (;i < (data_len > 0xF ? 0xF : data_len); ++i)
758 //              printf("%02x ", data[i]);
759 //      printf("%d bytes\n", data_len);
760 //      printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
761
762         if (self->fd < 0)
763                 return GST_FLOW_OK;
764
765 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
766         if (self->must_pack_bitstream == 1) {
767                 cache_prev_frame = TRUE;
768                 unsigned int pos = 0;
769                 while(pos < data_len) {
770                         if (data[pos++])
771                                 continue;
772                         if (data[pos++])
773                                 continue;
774                         while (!data[pos])
775                                 ++pos;
776                         if (data[pos++] != 1)
777                                 continue;
778                         if ((data[pos++] & 0xF0) == 0x20) { // we need time_inc_res
779                                 gboolean low_delay=FALSE;
780                                 unsigned int ver_id = 1, shape=0, time_inc_res=0, tmp=0;
781                                 struct bitstream bit;
782                                 bitstream_init(&bit, data+pos, 0);
783                                 bitstream_get(&bit, 9);
784                                 if (bitstream_get(&bit, 1)) {
785                                         ver_id = bitstream_get(&bit, 4); // ver_id
786                                         bitstream_get(&bit, 3);
787                                 }
788                                 if ((tmp=bitstream_get(&bit, 4)) == 15) { // Custom Aspect Ration
789                                         bitstream_get(&bit, 8); // skip AR width
790                                         bitstream_get(&bit, 8); // skip AR height
791                                 }
792                                 if (bitstream_get(&bit, 1)) {
793                                         bitstream_get(&bit, 2);
794                                         low_delay = bitstream_get(&bit, 1) ? TRUE : FALSE;
795                                         if (bitstream_get(&bit, 1)) {
796                                                 bitstream_get(&bit, 32);
797                                                 bitstream_get(&bit, 32);
798                                                 bitstream_get(&bit, 15);
799                                         }
800                                 }
801                                 shape = bitstream_get(&bit, 2);
802                                 if (ver_id != 1 && shape == 3 /* Grayscale */)
803                                         bitstream_get(&bit, 4);
804                                 bitstream_get(&bit, 1);
805                                 time_inc_res = bitstream_get(&bit, 16);
806                                 self->time_inc_bits = 0;
807                                 while (time_inc_res) { // count bits
808                                         ++self->time_inc_bits;
809                                         time_inc_res >>= 1;
810                                 }
811 //                              printf("%d time_inc_bits\n", self->time_inc_bits);
812                         }
813                 }
814         }
815
816         if (self->must_pack_bitstream == 1) {
817                 int tmp1, tmp2;
818                 unsigned char c1, c2;
819                 unsigned int pos = 0;
820                 while(pos < data_len) {
821                         if (data[pos++])
822                                 continue;
823                         if (data[pos++])
824                                 continue;
825                         while (!data[pos])
826                                 ++pos;
827                         if (data[pos++] != 1)
828                                 continue;
829                         if (data[pos++] != 0xB2)
830                                 continue;
831                         if (data_len - pos < 13)
832                                 break;
833                         if (sscanf((char*)data+pos, "DivX%d%c%d%cp", &tmp1, &c1, &tmp2, &c2) == 4 && (c1 == 'b' || c1 == 'B') && (c2 == 'p' || c2 == 'P')) {
834                                 GST_INFO_OBJECT (self, "%s seen... already packed!", (char*)data+pos);
835                                 self->must_pack_bitstream = 0;
836                         }
837 //                      if (self->must_pack_bitstream)
838 //                              printf("pack needed\n");
839 //                      else
840 //                              printf("no pack needed\n");
841                 }
842         }
843 #endif
844
845         pes_header[0] = 0;
846         pes_header[1] = 0;
847         pes_header[2] = 1;
848         pes_header[3] = 0xE0;
849
850                 /* do we have a timestamp? */
851         if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE) {
852                 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
853
854                 pes_header[6] = 0x80;
855                 pes_header[7] = 0x80;
856                 
857                 pes_header[8] = 5;
858                 
859                 pes_header[9] =  0x21 | ((pts >> 29) & 0xE);
860                 pes_header[10] = pts >> 22;
861                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
862                 pes_header[12] = pts >> 7;
863                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
864
865                 pes_header_len = 14;
866
867                 if (self->codec_data) {
868                         switch (self->codec_type) { // we must always resend the codec data before every seq header on dm8k
869                         case CT_MPEG4_PART2:
870                         case CT_DIVX4:
871                                 if (data[0] == 0xb3 || !memcmp(data, "\x00\x00\x01\xb3", 4))
872                                         self->must_send_header = 1;
873                         default:
874                                 break;
875                         }
876                         if (self->must_send_header) {
877                                 if (self->codec_type != CT_MPEG1 && self->codec_type != CT_MPEG2 && (self->codec_type != CT_DIVX4 || data[3] == 0x00)) {
878                                         unsigned char *codec_data = GST_BUFFER_DATA (self->codec_data);
879                                         unsigned int codec_data_len = GST_BUFFER_SIZE (self->codec_data);
880                                         if (self->codec_type == CT_DIVX311)
881                                                 ASYNC_WRITE(codec_data, codec_data_len);
882                                         else {
883                                                 memcpy(pes_header+pes_header_len, codec_data, codec_data_len);
884                                                 pes_header_len += codec_data_len;
885                                         }
886                                         self->must_send_header = 0;
887                                 }
888                         }
889                         if (self->codec_type == CT_H264) {  // MKV stuff
890                                 unsigned int pos = 0;
891                                 if (self->h264_nal_len_size == 4) {
892                                         while(TRUE) {
893                                                 unsigned int pack_len = (data[pos] << 24) | (data[pos+1] << 16) | (data[pos+2] << 8) | data[pos+3];
894 //                                              printf("patch %02x %02x %02x %02x\n",
895 //                                                      data[pos],
896 //                                                      data[pos + 1],
897 //                                                      data[pos + 2],
898 //                                                      data[pos + 3]);
899                                                 memcpy(data+pos, "\x00\x00\x00\x01", 4);
900 //                                              printf("pos %d, (%d) >= %d\n", pos, pos+pack_len, data_len);
901                                                 pos += 4;
902                                                 if ((pos + pack_len) >= data_len)
903                                                         break;
904                                                 pos += pack_len;
905                                         }
906                                 }
907                                 else if (self->h264_nal_len_size == 3) {
908                                         while(TRUE) {
909                                                 unsigned int pack_len = (data[pos] << 16) | (data[pos+1] << 8) | data[pos+2];
910 //                                              printf("patch %02x %02x %02x\n",
911 //                                                      data[pos],
912 //                                                      data[pos + 1],
913 //                                                      data[pos + 2]);
914                                                 memcpy(data+pos, "\x00\x00\x01", 3);
915 //                                              printf("pos %d, (%d) >= %d\n", pos, pos+pack_len, data_len);
916                                                 pos += 3;
917                                                 if ((pos + pack_len) >= data_len)
918                                                         break;
919                                                 pos += pack_len;
920                                         }
921                                 }
922                                 else {
923                                         unsigned char *dest = GST_BUFFER_DATA (self->h264_buffer);
924                                         unsigned int dest_pos = 0;
925                                         while(TRUE) {
926                                                 unsigned int pack_len = self->h264_nal_len_size == 2 ? (data[pos] << 8) | data[pos+1] : data[pos];
927                                                 if (dest_pos + pack_len <= H264_BUFFER_SIZE) {
928                                                         memcpy(dest+dest_pos, "\x00\x00\x01", 3);
929                                                         dest_pos += 3;
930                                                         pos += self->h264_nal_len_size;
931                                                         memcpy(dest+dest_pos, data+pos, pack_len);
932                                                         dest_pos += pack_len;
933                                                         if ((pos + pack_len) >= data_len)
934                                                                 break;
935                                                         pos += pack_len;
936                                                 }
937                                                 else {
938                                                         g_error("BUG!!!!!!!! H264 buffer to small skip video data!!.. please report!\n");
939                                                         break;
940                                                 }
941                                         }
942                                         data = dest;
943                                         data_len = dest_pos;
944                                 }
945                         }
946                         else if (self->codec_type == CT_MPEG4_PART2) {
947                                 if (data[0] || data[1] || data[2] != 1) {
948                                         memcpy(pes_header+pes_header_len, "\x00\x00\x01", 3);
949                                         pes_header_len += 3;
950                                 }
951                         }
952                         else if (self->codec_type == CT_DIVX311) {
953                                 if (data[0] || data[1] || data[2] != 1 || data[3] != 0xb6) {
954                                         memcpy(pes_header+pes_header_len, "\x00\x00\x01\xb6", 4);
955                                         pes_header_len += 4;
956                                 }
957                         }
958                 }
959         }
960         else {
961 //              printf("no timestamp!\n");
962                 pes_header[6] = 0x80;
963                 pes_header[7] = 0x00;
964                 pes_header[8] = 0;
965                 pes_header_len = 9;
966         }
967
968 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
969         if (self->must_pack_bitstream == 1) {
970                 unsigned int pos = 0;
971                 gboolean i_frame = FALSE;
972 //              gboolean s_frame = FALSE;
973                 while(pos < data_len) {
974                         if (data[pos++])
975                                 continue;
976                         if (data[pos++])
977                                 continue;
978                         while (!data[pos])
979                                 ++pos;
980                         if (data[pos++] != 1)
981                                 continue;
982                         if (data[pos++] != 0xB6)
983                                 continue;
984                         switch ((data[pos] & 0xC0) >> 6) {
985                                 case 0: // I-Frame
986 //                                      printf("I ");
987                                         cache_prev_frame = FALSE;
988                                         i_frame = TRUE;
989                                 case 1: // P-Frame
990 //                                      if (!i_frame)
991 //                                              printf("P ");
992                                         if (self->prev_frame != buffer) {
993                                                 struct bitstream bit;
994                                                 gboolean store_frame=FALSE;
995                                                 if (self->prev_frame) {
996                                                         if (!self->num_non_keyframes) {
997 //                                                              printf("no non keyframes...immediate commit prev frame\n");
998                                                                 GstFlowReturn ret = gst_dvbvideosink_render(sink, self->prev_frame);
999                                                                 gst_buffer_unref(self->prev_frame);
1000                                                                 self->prev_frame = NULL;
1001                                                                 if (ret != GST_FLOW_OK)
1002                                                                         return ret;
1003                                                                 store_frame = TRUE;
1004                                                         }
1005                                                         else {
1006 //                                                              int i=-4;
1007                                                                 pes_header[pes_header_len++] = 0;
1008                                                                 pes_header[pes_header_len++] = 0;
1009                                                                 pes_header[pes_header_len++] = 1;
1010                                                                 pes_header[pes_header_len++] = 0xB6;
1011                                                                 bitstream_init(&bit, pes_header+pes_header_len, 1);
1012                                                                 bitstream_put(&bit, 1, 2);
1013                                                                 bitstream_put(&bit, 0, 1);
1014                                                                 bitstream_put(&bit, 1, 1);
1015                                                                 bitstream_put(&bit, self->time_inc, self->time_inc_bits);
1016                                                                 bitstream_put(&bit, 1, 1);
1017                                                                 bitstream_put(&bit, 0, 1);
1018                                                                 bitstream_put(&bit, 0x7F >> bit.avail, 8 - bit.avail);
1019 //                                                              printf(" insert pack frame %d non keyframes, time_inc %d, time_inc_bits %d -",
1020 //                                                                      self->num_non_keyframes, self->time_inc, self->time_inc_bits);
1021 //                                                              for (; i < (bit.data - (pes_header+pes_header_len)); ++i)
1022 //                                                                      printf(" %02x", pes_header[pes_header_len+i]);
1023 //                                                              printf("\nset data_len to 0!\n");
1024                                                                 data_len = 0;
1025                                                                 pes_header_len += bit.data - (pes_header+pes_header_len);
1026                                                                 cache_prev_frame = TRUE;
1027                                                         }
1028                                                 }
1029                                                 else if (!i_frame)
1030                                                         store_frame = TRUE;
1031
1032                                                 self->num_non_keyframes=0;
1033
1034                                                 // extract time_inc
1035                                                 bitstream_init(&bit, data+pos, 0);
1036                                                 bitstream_get(&bit, 2); // skip coding_type
1037                                                 while(bitstream_get(&bit, 1));
1038                                                 bitstream_get(&bit, 1);
1039                                                 self->time_inc = bitstream_get(&bit, self->time_inc_bits);
1040 //                                              printf("\ntime_inc is %d\n", self->time_inc);
1041
1042                                                 if (store_frame) {
1043 //                                                      printf("store frame\n");
1044                                                         self->prev_frame = buffer;
1045                                                         gst_buffer_ref (buffer);
1046                                                         return GST_FLOW_OK;
1047                                                 }
1048                                         }
1049                                         else {
1050                                                 cache_prev_frame = FALSE;
1051 //                                              printf(" I/P Frame without non key frame(s)!!\n");
1052                                         }
1053                                         break;
1054                                 case 3: // S-Frame
1055 //                                      printf("S ");
1056 //                                      s_frame = TRUE;
1057                                 case 2: // B-Frame
1058 //                                      if (!s_frame)
1059 //                                              printf("B ");
1060                                         if (++self->num_non_keyframes == 1 && self->prev_frame) {
1061 //                                              printf("send grouped with prev P!\n");
1062                                                 commit_prev_frame_data = TRUE;
1063                                         }
1064                                         break;
1065                                 case 4: // N-Frame
1066                                 default:
1067                                         g_warning("unhandled divx5/xvid frame type %d\n", (data[pos] & 0xC0) >> 6);
1068                                         break;
1069                         }
1070                 }
1071 //              printf("\n");
1072         }
1073 #endif
1074
1075         payload_len = data_len + pes_header_len - 6;
1076
1077 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1078         if (self->prev_frame && self->prev_frame != buffer) {
1079                 unsigned long long pts = GST_BUFFER_TIMESTAMP(self->prev_frame) * 9LL / 100000 /* convert ns to 90kHz */;
1080 //              printf("use prev timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(self->prev_frame));
1081
1082                 pes_header[9] =  0x21 | ((pts >> 29) & 0xE);
1083                 pes_header[10] = pts >> 22;
1084                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
1085                 pes_header[12] = pts >> 7;
1086                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
1087         }
1088
1089         if (commit_prev_frame_data)
1090                 payload_len += GST_BUFFER_SIZE (self->prev_frame);
1091 #endif
1092
1093         if (self->codec_type == CT_MPEG2 || self->codec_type == CT_MPEG1) {
1094                 if (!self->codec_data && data_len > 3 && !data[0] && !data[1] && data[2] == 1 && data[3] == 0xb3) { // sequence header?
1095                         gboolean ok = TRUE;
1096                         unsigned int pos = 4;
1097                         unsigned int sheader_data_len=0;
1098                         while(pos < data_len && ok) {
1099                                 if ( pos >= data_len )
1100                                         break;
1101                                 pos+=7;
1102                                 if ( pos >=data_len )
1103                                         break;
1104                                 sheader_data_len=12;
1105                                 if ( data[pos] & 2 ) { // intra matrix avail?
1106                                         pos+=64;
1107                                         if ( pos >=data_len )
1108                                                 break;
1109                                         sheader_data_len+=64;
1110                                 }
1111                                 if ( data[pos] & 1 ) { // non intra matrix avail?
1112                                         pos+=64;
1113                                         if ( pos >=data_len )
1114                                                 break;
1115                                         sheader_data_len+=64;
1116                                 }
1117                                 pos+=1;
1118                                 if ( pos+3 >=data_len )
1119                                         break;
1120                                 // extended start code
1121                                 if ( !data[pos] && !data[pos+1] && data[pos+2] == 1 && data[pos+3] == 0xB5 ) {
1122                                         pos+=3;
1123                                         sheader_data_len+=3;
1124                                         do {
1125                                                 pos+=1;
1126                                                 ++sheader_data_len;
1127                                                 if (pos+2 > data_len)
1128                                                         goto leave;
1129                                         }
1130                                         while( data[pos] || data[pos+1] || data[pos+2] != 1 );
1131                                 }
1132                                 if ( pos+3 >=data_len )
1133                                         break;
1134                                 // private data
1135                                 if ( !data[pos] && !data[pos+1] && data[pos+2] && data[pos+3] == 0xB2 ) {
1136                                         pos+=3;
1137                                         sheader_data_len+=3;
1138                                         do {
1139                                                 pos+=1;
1140                                                 ++sheader_data_len;
1141                                                 if (pos+2 > data_len)
1142                                                         goto leave;
1143                                         }
1144                                         while( data[pos] || data[pos+1] || data[pos+2] != 1 );
1145                                 }
1146                                 self->codec_data = gst_buffer_new_and_alloc(sheader_data_len);
1147                                 memcpy(GST_BUFFER_DATA(self->codec_data), data+pos-sheader_data_len, sheader_data_len);
1148                                 self->must_send_header = 0;
1149 leave:
1150                                 ok = FALSE;
1151                         }
1152                 }
1153                 else if (self->codec_data && self->must_send_header) {
1154                         unsigned char *codec_data = GST_BUFFER_DATA (self->codec_data);
1155                         unsigned int codec_data_len = GST_BUFFER_SIZE (self->codec_data);
1156                         int pos = 0;
1157                         while(pos < data_len) {
1158                                 if ( data[pos++] )
1159                                         continue;
1160                                 if ( data[pos++] )
1161                                         continue;
1162                                 while ( !data[pos] )
1163                                         pos++;
1164                                 if ( data[pos++] != 1 )
1165                                         continue;
1166                                 if ( data[pos++] != 0xb8 ) // group start code
1167                                         continue;
1168                                 pos-=4; // before group start
1169                                 payload_len += codec_data_len;
1170                                 if (payload_len <= 0xFFFF) {
1171                                         pes_header[4] = payload_len >> 8;
1172                                         pes_header[5] = payload_len & 0xFF;
1173                                 }
1174                                 else {
1175                                         pes_header[4] = 0;
1176                                         pes_header[5] = 0;
1177                                 }
1178                                 ASYNC_WRITE(pes_header, pes_header_len);
1179                                 ASYNC_WRITE(data, pos);
1180                                 ASYNC_WRITE(codec_data, codec_data_len);
1181                                 ASYNC_WRITE(data+pos, data_len - pos);
1182                                 --self->must_send_header;
1183                                 return GST_FLOW_OK;
1184                         }
1185                 }
1186         }
1187
1188         if (payload_len <= 0xFFFF) {
1189                 pes_header[4] = payload_len >> 8;
1190                 pes_header[5] = payload_len & 0xFF;
1191         }
1192         else {
1193                 pes_header[4] = 0;
1194                 pes_header[5] = 0;
1195         }
1196
1197         ASYNC_WRITE(pes_header, pes_header_len);
1198
1199 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1200         if (commit_prev_frame_data) {
1201 //              printf("commit prev frame data\n");
1202                 ASYNC_WRITE(GST_BUFFER_DATA (self->prev_frame), GST_BUFFER_SIZE (self->prev_frame));
1203         }
1204
1205         if (self->prev_frame && self->prev_frame != buffer) {
1206 //              printf("unref prev_frame buffer\n");
1207                 gst_buffer_unref(self->prev_frame);
1208                 self->prev_frame = NULL;
1209         }
1210
1211         if (cache_prev_frame) {
1212 //              printf("cache prev frame\n");
1213                 gst_buffer_ref(buffer);
1214                 self->prev_frame = buffer;
1215         }
1216 #endif
1217         ASYNC_WRITE(data, data_len);
1218
1219         return GST_FLOW_OK;
1220 poll_error:
1221         {
1222                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
1223                                 ("poll on file descriptor: %s.", g_strerror (errno)));
1224                 GST_WARNING_OBJECT (self, "Error during poll");
1225                 return GST_FLOW_ERROR;
1226         }
1227 write_error:
1228         {
1229                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
1230                                 ("write on file descriptor: %s.", g_strerror (errno)));
1231                 GST_WARNING_OBJECT (self, "Error during write");
1232                 return GST_FLOW_ERROR;
1233         }
1234         self->must_send_header = 1;
1235         if (hwtype == DM7025)
1236                 ++self->must_send_header;  // we must send the sequence header twice on dm7025...
1237 }
1238
1239 static gboolean 
1240 gst_dvbvideosink_set_caps (GstBaseSink * basesink, GstCaps * caps)
1241 {
1242         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
1243         GstStructure *structure = gst_caps_get_structure (caps, 0);
1244         const char *mimetype = gst_structure_get_name (structure);
1245         int streamtype = -1;
1246
1247         if (!strcmp (mimetype, "video/mpeg")) {
1248                 gint mpegversion;
1249                 gst_structure_get_int (structure, "mpegversion", &mpegversion);
1250                 switch (mpegversion) {
1251                         case 1:
1252                                 streamtype = 6;
1253                                 self->codec_type = CT_MPEG1;
1254                                 GST_INFO_OBJECT (self, "MIMETYPE video/mpeg1 -> VIDEO_SET_STREAMTYPE, 6");
1255                         break;
1256                         case 2:
1257                                 streamtype = 0;
1258                                 self->codec_type = CT_MPEG2;
1259                                 GST_INFO_OBJECT (self, "MIMETYPE video/mpeg2 -> VIDEO_SET_STREAMTYPE, 0");
1260                         break;
1261                         case 4:
1262                         {
1263                                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
1264                                 if (codec_data) {
1265                                         GST_INFO_OBJECT (self, "MPEG4 have codec data");
1266                                         self->codec_data = gst_value_get_buffer (codec_data);
1267                                         self->codec_type = CT_MPEG4_PART2;
1268                                         gst_buffer_ref (self->codec_data);
1269                                 }
1270                                 streamtype = 4;
1271                                 GST_INFO_OBJECT (self, "MIMETYPE video/mpeg4 -> VIDEO_SET_STREAMTYPE, 4");
1272                         }
1273                         break;
1274                         default:
1275                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
1276                         break;
1277                 }
1278         } else if (!strcmp (mimetype, "video/x-3ivx")) {
1279                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
1280                 if (codec_data) {
1281                         GST_INFO_OBJECT (self, "have 3ivx codec... handle as CT_MPEG4_PART2");
1282                         self->codec_data = gst_value_get_buffer (codec_data);
1283                         self->codec_type = CT_MPEG4_PART2;
1284                         gst_buffer_ref (self->codec_data);
1285                 }
1286                 streamtype = 4;
1287                 GST_INFO_OBJECT (self, "MIMETYPE video/x-3ivx -> VIDEO_SET_STREAMTYPE, 4");
1288         } else if (!strcmp (mimetype, "video/x-h264")) {
1289                 const GValue *cd_data = gst_structure_get_value (structure, "codec_data");
1290                 streamtype = 1;
1291                 if (cd_data) {
1292                         unsigned char tmp[2048];
1293                         unsigned int tmp_len = 0;
1294                         GstBuffer *codec_data = gst_value_get_buffer (cd_data);
1295                         unsigned char *data = GST_BUFFER_DATA (codec_data);
1296                         unsigned int cd_len = GST_BUFFER_SIZE (codec_data);
1297                         unsigned int cd_pos = 0;
1298                         GST_INFO_OBJECT (self, "H264 have codec data..!");
1299                         if (cd_len > 7 && data[0] == 1) {
1300                                 unsigned short len = (data[6] << 8) | data[7];
1301 //                              printf("2 %d bytes\n", len);
1302                                 if (cd_len >= (len + 8)) {
1303                                         unsigned int i=0;
1304                                         uint8_t profile_num[] = { 66, 77, 88, 100 };
1305                                         uint8_t profile_cmp[2] = { 0x67, 0x00 };
1306                                         const char *profile_str[] = { "baseline", "main", "extended", "high" };
1307 //                                      printf("3\n");
1308                                         memcpy(tmp, "\x00\x00\x00\x01", 4);
1309                                         tmp_len += 4;
1310 //                                      printf("header part1 ");
1311 //                                      for (i = 0; i < len; ++i)
1312 //                                              printf("%02x ", data[8+i]);
1313 //                                      printf("\n");
1314                                         memcpy(tmp+tmp_len, data+8, len);
1315                                         for (i = 0; i < 4; ++i) {
1316                                                 profile_cmp[1] = profile_num[i];
1317                                                 if (!memcmp(tmp+tmp_len, profile_cmp, 2)) {
1318                                                         uint8_t level_org = tmp[tmp_len+3];
1319                                                         if (level_org > 0x29) {
1320                                                                 GST_INFO_OBJECT (self, "H264 %s profile@%d.%d patched down to 4.1!", profile_str[i], level_org / 10 , level_org % 10);
1321                                                                 tmp[tmp_len+3] = 0x29; // level 4.1
1322                                                         }
1323                                                         else
1324                                                                 GST_INFO_OBJECT (self, "H264 %s profile@%d.%d", profile_str[i], level_org / 10 , level_org % 10);
1325                                                         break;
1326                                                 }
1327                                         }
1328                                         tmp_len += len;
1329                                         cd_pos = 8 + len;
1330                                         if (cd_len > (cd_pos + 2)) {
1331                                                 len = (data[cd_pos+1] << 8) | data[cd_pos+2];
1332 //                                              printf("4 %d bytes\n", len);
1333                                                 cd_pos += 3;
1334                                                 if (cd_len >= (cd_pos+len)) {
1335 //                                                      printf("codec data ok!\n");
1336                                                         memcpy(tmp+tmp_len, "\x00\x00\x00\x01", 4);
1337                                                         tmp_len += 4;
1338 //                                                      printf("header part2 %02x %02x %02x %02x ... %d bytes\n", data[cd_pos], data[cd_pos+1], data[cd_pos+2], data[cd_pos+3], len);
1339                                                         memcpy(tmp+tmp_len, data+cd_pos, len);
1340                                                         tmp_len += len;
1341                                                         self->codec_data = gst_buffer_new_and_alloc(tmp_len);
1342                                                         memcpy(GST_BUFFER_DATA(self->codec_data), tmp, tmp_len);
1343                                                         self->h264_nal_len_size = (data[4] & 0x03) + 1;
1344                                                         if (self->h264_nal_len_size < 3)
1345                                                                 self->h264_buffer = gst_buffer_new_and_alloc(H264_BUFFER_SIZE);
1346                                                 }
1347                                                 else
1348                                                         GST_WARNING_OBJECT (self, "codec_data to short(4)");
1349                                         }
1350                                         else
1351                                                 GST_WARNING_OBJECT (self, "codec_data to short(3)");
1352                                 }
1353                                 else
1354                                         GST_WARNING_OBJECT (self, "codec_data to short(2)");
1355                         }
1356                         else if (cd_len <= 7)
1357                                 GST_WARNING_OBJECT (self, "codec_data to short(1)");
1358                         else
1359                                 GST_WARNING_OBJECT (self, "wrong avcC version %d!", data[0]);
1360                 }
1361                 else
1362                         self->h264_nal_len_size = 0;
1363                 GST_INFO_OBJECT (self, "MIMETYPE video/x-h264 VIDEO_SET_STREAMTYPE, 1");
1364         } else if (!strcmp (mimetype, "video/x-h263")) {
1365                 streamtype = 2;
1366                 GST_INFO_OBJECT (self, "MIMETYPE video/x-h263 VIDEO_SET_STREAMTYPE, 2");
1367         } else if (!strcmp (mimetype, "video/x-xvid")) {
1368                 streamtype = 10;
1369 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1370                 self->must_pack_bitstream = 1;
1371 #endif
1372                 GST_INFO_OBJECT (self, "MIMETYPE video/x-xvid -> VIDEO_SET_STREAMTYPE, 10");
1373         } else if (!strcmp (mimetype, "video/x-divx") || !strcmp (mimetype, "video/x-msmpeg")) {
1374                 gint divxversion = -1;
1375                 if (!gst_structure_get_int (structure, "divxversion", &divxversion) && !gst_structure_get_int (structure, "msmpegversion", &divxversion))
1376                         ;
1377                 switch (divxversion) {
1378                         case 3:
1379                         case 43:
1380                         {
1381                                 #define B_GET_BITS(w,e,b)  (((w)>>(b))&(((unsigned)(-1))>>((sizeof(unsigned))*8-(e+1-b))))
1382                                 #define B_SET_BITS(name,v,e,b)  (((unsigned)(v))<<(b))
1383                                 static const guint8 brcm_divx311_sequence_header[] = {
1384                                         0x00, 0x00, 0x01, 0xE0, 0x00, 0x34, 0x80, 0x80, // PES HEADER
1385                                         0x05, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, 
1386                                         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, /* 0 .. 7 */
1387                                         0x08, 0xC8, 0x0D, 0x40, 0x00, 0x53, 0x88, 0x40, /* 8 .. 15 */
1388                                         0x0C, 0x40, 0x01, 0x90, 0x00, 0x97, 0x53, 0x0A, /* 16 .. 24 */
1389                                         0x00, 0x00, 0x00, 0x00,
1390                                         0x30, 0x7F, 0x00, 0x00, 0x01, 0xB2, 0x44, 0x69, /* 0 .. 7 */
1391                                         0x76, 0x58, 0x33, 0x31, 0x31, 0x41, 0x4E, 0x44  /* 8 .. 15 */
1392                                 };
1393                                 self->codec_data = gst_buffer_new_and_alloc(63);
1394                                 guint8 *data = GST_BUFFER_DATA(self->codec_data);
1395                                 gint height, width;
1396                                 gst_structure_get_int (structure, "height", &height);
1397                                 gst_structure_get_int (structure, "width", &width);
1398                                 memcpy(data, brcm_divx311_sequence_header, 63);
1399                                 data += 38;
1400                                 data[0] = B_GET_BITS(width,11,4);
1401                                 data[1] = B_SET_BITS("width [3..0]", B_GET_BITS(width,3,0), 7, 4) |
1402                                         B_SET_BITS("'10'", 0x02, 3, 2) |
1403                                         B_SET_BITS("height [11..10]", B_GET_BITS(height,11,10), 1, 0);
1404                                 data[2] = B_GET_BITS(height,9,2);
1405                                 data[3]= B_SET_BITS("height [1.0]", B_GET_BITS(height,1,0), 7, 6) |
1406                                         B_SET_BITS("'100000'", 0x20, 5, 0);
1407                                 streamtype = 13;
1408                                 self->codec_type = CT_DIVX311;
1409                                 GST_INFO_OBJECT (self, "MIMETYPE video/x-divx vers. 3 -> VIDEO_SET_STREAMTYPE, 13");
1410                         }
1411                         break;
1412                         case 4:
1413                                 streamtype = 14;
1414                                 self->codec_type = CT_DIVX4;
1415                                 self->codec_data = gst_buffer_new_and_alloc(12);
1416                                 guint8 *data = GST_BUFFER_DATA(self->codec_data);
1417                                 memcpy(data, "\x00\x00\x01\xb2\x44\x69\x76\x58\x34\x41\x4e\x44", 12);
1418                                 GST_INFO_OBJECT (self, "MIMETYPE video/x-divx vers. 4 -> VIDEO_SET_STREAMTYPE, 14");
1419                         break;
1420                         case 6:
1421                         case 5:
1422                                 streamtype = 15;
1423 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1424                                 self->must_pack_bitstream = 1;
1425 #endif
1426                                 GST_INFO_OBJECT (self, "MIMETYPE video/x-divx vers. 5 -> VIDEO_SET_STREAMTYPE, 15");
1427                         break;
1428                         default:
1429                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled divx version %i", divxversion));
1430                         break;
1431                 }
1432         }
1433         if (streamtype != -1) {
1434                 gint numerator, denominator;
1435                 if (gst_structure_get_fraction (structure, "framerate", &numerator, &denominator)) {
1436                         FILE *f = fopen("/proc/stb/vmpeg/0/fallback_framerate", "w");
1437                         if (f) {
1438                                 int valid_framerates[] = { 23976, 24000, 25000, 29970, 30000, 50000, 59940, 60000 };
1439                                 int framerate = (int)(((double)numerator * 1000) / denominator);
1440                                 int diff = 60000;
1441                                 int best = 0;
1442                                 int i = 0;
1443                                 for (; i < 7; ++i) {
1444                                         int ndiff = abs(framerate - valid_framerates[i]);
1445                                         if (ndiff < diff) {
1446                                                 diff = ndiff;
1447                                                 best = i;
1448                                         }
1449                                 }
1450                                 fprintf(f, "%d", valid_framerates[best]);
1451                                 fclose(f);
1452                         }
1453                 }
1454                 if (self->dec_running) {
1455                         ioctl(self->fd, VIDEO_STOP, 0);
1456                         self->dec_running = FALSE;
1457                 }
1458                 if (ioctl(self->fd, VIDEO_SET_STREAMTYPE, streamtype) < 0 )
1459                         if ( streamtype != 0 && streamtype != 6 )
1460                                 GST_ELEMENT_ERROR (self, STREAM, CODEC_NOT_FOUND, (NULL), ("hardware decoder can't handle streamtype %i", streamtype));
1461                 ioctl(self->fd, VIDEO_PLAY);
1462                 self->dec_running = TRUE;
1463         } else
1464                 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", mimetype));
1465
1466         return TRUE;
1467 }
1468
1469 static int readMpegProc(char *str, int decoder)
1470 {
1471         int val = -1;
1472         char tmp[64];
1473         sprintf(tmp, "/proc/stb/vmpeg/%d/%s", decoder, str);
1474         FILE *f = fopen(tmp, "r");
1475         if (f)
1476         {
1477                 fscanf(f, "%x", &val);
1478                 fclose(f);
1479         }
1480         return val;
1481 }
1482
1483 static int readApiSize(int fd, int *xres, int *yres, int *aspect)
1484 {
1485         video_size_t size;
1486         if (!ioctl(fd, VIDEO_GET_SIZE, &size))
1487         {
1488                 *xres = size.w;
1489                 *yres = size.h;
1490                 *aspect = size.aspect_ratio == 0 ? 2 : 3;  // convert dvb api to etsi
1491                 return 0;
1492         }
1493         return -1;
1494 }
1495
1496 static int readApiFrameRate(int fd, int *framerate)
1497 {
1498         unsigned int frate;
1499         if (!ioctl(fd, VIDEO_GET_FRAME_RATE, &frate))
1500         {
1501                 *framerate = frate;
1502                 return 0;
1503         }
1504         return -1;
1505 }
1506
1507 static gboolean
1508 gst_dvbvideosink_start (GstBaseSink * basesink)
1509 {
1510         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
1511         gint control_sock[2];
1512
1513         GST_DEBUG_OBJECT (self, "start");
1514
1515
1516         if (socketpair(PF_UNIX, SOCK_STREAM, 0, control_sock) < 0) {
1517                 perror("socketpair");
1518                 goto socket_pair;
1519         }
1520
1521         READ_SOCKET (self) = control_sock[0];
1522         WRITE_SOCKET (self) = control_sock[1];
1523
1524         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
1525         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
1526
1527         return TRUE;
1528         /* ERRORS */
1529 socket_pair:
1530         {
1531                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
1532                                 GST_ERROR_SYSTEM);
1533                 return FALSE;
1534         }
1535 }
1536
1537 static gboolean
1538 gst_dvbvideosink_stop (GstBaseSink * basesink)
1539 {
1540         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
1541         FILE *f = fopen("/proc/stb/vmpeg/0/fallback_framerate", "w");
1542         GST_DEBUG_OBJECT (self, "stop");
1543         if (self->fd >= 0)
1544         {
1545                 if (self->dec_running) {
1546                         ioctl(self->fd, VIDEO_STOP);
1547                         self->dec_running = FALSE;
1548                 }
1549                 ioctl(self->fd, VIDEO_SLOWMOTION, 0);
1550                 ioctl(self->fd, VIDEO_FAST_FORWARD, 0);
1551                 ioctl(self->fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
1552                 close(self->fd);
1553         }
1554
1555         if (self->codec_data)
1556                 gst_buffer_unref(self->codec_data);
1557
1558         if (self->h264_buffer)
1559                 gst_buffer_unref(self->h264_buffer);
1560
1561 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1562         if (self->prev_frame)
1563                 gst_buffer_unref(self->prev_frame);
1564 #endif
1565
1566         while(self->queue)
1567                 queue_pop(&self->queue);
1568
1569         if (f) {
1570                 fputs(self->saved_fallback_framerate, f);
1571                 fclose(f);
1572         }
1573
1574         close (READ_SOCKET (self));
1575         close (WRITE_SOCKET (self));
1576         READ_SOCKET (self) = -1;
1577         WRITE_SOCKET (self) = -1;
1578
1579         return TRUE;
1580 }
1581
1582 static GstStateChangeReturn
1583 gst_dvbvideosink_change_state (GstElement * element, GstStateChange transition)
1584 {
1585         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1586         GstDVBVideoSink *self = GST_DVBVIDEOSINK (element);
1587
1588         switch (transition) {
1589         case GST_STATE_CHANGE_NULL_TO_READY:
1590                 GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_NULL_TO_READY");
1591                 break;
1592         case GST_STATE_CHANGE_READY_TO_PAUSED:
1593                 GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_READY_TO_PAUSED");
1594
1595                 self->fd = open("/dev/dvb/adapter0/video0", O_RDWR|O_NONBLOCK);
1596 //              self->fd = open("/dump.pes", O_RDWR|O_CREAT|O_TRUNC, 0555);
1597
1598                 GST_OBJECT_LOCK(self);
1599                 self->no_write |= 4;
1600                 GST_OBJECT_UNLOCK(self);
1601
1602                 if (self->fd >= 0) {
1603                         GstStructure *s = 0;
1604                         GstMessage *msg = 0;
1605                         int aspect = -1, width = -1, height = -1, framerate = -1,
1606                                 progressive = readMpegProc("progressive", 0);
1607
1608                         if (readApiSize(self->fd, &width, &height, &aspect) == -1) {
1609                                 aspect = readMpegProc("aspect", 0);
1610                                 width = readMpegProc("xres", 0);
1611                                 height = readMpegProc("yres", 0);
1612                         } else
1613                                 aspect = aspect == 0 ? 2 : 3; // dvb api to etsi
1614                         if (readApiFrameRate(self->fd, &framerate) == -1)
1615                                 framerate = readMpegProc("framerate", 0);
1616
1617                         s = gst_structure_new ("eventSizeAvail",
1618                                 "aspect_ratio", G_TYPE_INT, aspect == 0 ? 2 : 3,
1619                                 "width", G_TYPE_INT, width,
1620                                 "height", G_TYPE_INT, height, NULL);
1621                         msg = gst_message_new_element (GST_OBJECT (element), s);
1622                         gst_element_post_message (GST_ELEMENT (element), msg);
1623                         s = gst_structure_new ("eventFrameRateAvail",
1624                                 "frame_rate", G_TYPE_INT, framerate, NULL);
1625                         msg = gst_message_new_element (GST_OBJECT (element), s);
1626                         gst_element_post_message (GST_ELEMENT (element), msg);
1627                         s = gst_structure_new ("eventProgressiveAvail",
1628                                 "progressive", G_TYPE_INT, progressive, NULL);
1629                         msg = gst_message_new_element (GST_OBJECT (element), s);
1630                         gst_element_post_message (GST_ELEMENT (element), msg);
1631                         ioctl(self->fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
1632                         ioctl(self->fd, VIDEO_FREEZE);
1633                 }
1634                 break;
1635         case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1636                 GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PAUSED_TO_PLAYING");
1637                 ioctl(self->fd, VIDEO_CONTINUE);
1638                 GST_OBJECT_LOCK(self);
1639                 self->no_write &= ~4;
1640                 GST_OBJECT_UNLOCK(self);
1641                 break;
1642         default:
1643                 break;
1644         }
1645
1646         ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1647
1648         switch (transition) {
1649         case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1650                 GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PLAYING_TO_PAUSED");
1651                 GST_OBJECT_LOCK(self);
1652                 self->no_write |= 4;
1653                 GST_OBJECT_UNLOCK(self);
1654                 ioctl(self->fd, VIDEO_FREEZE);
1655                 SEND_COMMAND (self, CONTROL_STOP);
1656                 break;
1657         case GST_STATE_CHANGE_PAUSED_TO_READY:
1658                 GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_PAUSED_TO_READY");
1659                 break;
1660         case GST_STATE_CHANGE_READY_TO_NULL:
1661                 GST_DEBUG_OBJECT (self,"GST_STATE_CHANGE_READY_TO_NULL");
1662                 break;
1663         default:
1664                 break;
1665         }
1666
1667         return ret;
1668 }
1669
1670 /* entry point to initialize the plug-in
1671  * initialize the plug-in itself
1672  * register the element factories and pad templates
1673  * register the features
1674  *
1675  * exchange the string 'plugin' with your elemnt name
1676  */
1677 static gboolean
1678 plugin_init (GstPlugin *plugin)
1679 {
1680         return gst_element_register (plugin, "dvbvideosink",
1681                                                  GST_RANK_PRIMARY,
1682                                                  GST_TYPE_DVBVIDEOSINK);
1683 }
1684
1685 /* this is the structure that gstreamer looks for to register plugins
1686  *
1687  * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
1688  * description
1689  */
1690 GST_PLUGIN_DEFINE (
1691         GST_VERSION_MAJOR,
1692         GST_VERSION_MINOR,
1693         "dvb_video_out",
1694         "DVB Video Output",
1695         plugin_init,
1696         VERSION,
1697         "LGPL",
1698         "GStreamer",
1699         "http://gstreamer.net/"
1700 )