fix skipping in files with just one sequence header
[gst-plugin-dvbmediasink.git] / src / gstdvbvideosink.c
1 /*
2  * GStreamer DVB Media Sink
3  * Copyright 2006 Felix Domke <tmbinc@elitedvb.net>
4  * based on code by:
5  * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
6  * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
7  * 
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Alternatively, the contents of this file may be used under the
27  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28  * which case the following provisions apply instead of the ones
29  * mentioned above:
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of the GNU Library General Public
33  * License as published by the Free Software Foundation; either
34  * version 2 of the License, or (at your option) any later version.
35  *
36  * This library is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39  * Library General Public License for more details.
40  *
41  * You should have received a copy of the GNU Library General Public
42  * License along with this library; if not, write to the
43  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44  * Boston, MA 02111-1307, USA.
45  */
46
47 /**
48  * SECTION:element-plugin
49  *
50  * <refsect2>
51  * <title>Example launch line</title>
52  * <para>
53  * <programlisting>
54  * gst-launch -v -m audiotestsrc ! plugin ! fakesink silent=TRUE
55  * </programlisting>
56  * </para>
57  * </refsect2>
58  */
59
60 #ifdef HAVE_CONFIG_H
61 #include <config.h>
62 #endif
63 #include <unistd.h>
64 #include <sys/ioctl.h>
65 #include <sys/socket.h>
66 #include <linux/dvb/video.h>
67 #include <fcntl.h>
68 #include <string.h>
69
70 #include <gst/gst.h>
71
72 #include "gstdvbvideosink.h"
73
74 #ifndef VIDEO_GET_PTS
75 #define VIDEO_GET_PTS              _IOR('o', 57, gint64)
76 #endif
77
78 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
79 struct bitstream
80 {
81         guint8 *data;
82         guint8 last;
83         int avail;
84 };
85
86 void bitstream_init(struct bitstream *bit, const void *buffer, gboolean wr)
87 {
88         bit->data = (guint8*) buffer;
89         if (wr) {
90                 bit->avail = 0;
91                 bit->last = 0;
92         }
93         else {
94                 bit->avail = 8;
95                 bit->last = *bit->data++;
96         }
97 }
98
99 unsigned long bitstream_get(struct bitstream *bit, int bits)
100 {
101         unsigned long res=0;
102         while (bits)
103         {
104                 unsigned int d=bits;
105                 if (!bit->avail) {
106                         bit->last = *bit->data++;
107                         bit->avail = 8;
108                 }
109                 if (d > bit->avail)
110                         d=bit->avail;
111                 res<<=d;
112                 res|=(bit->last>>(bit->avail-d))&~(-1<<d);
113                 bit->avail-=d;
114                 bits-=d;
115         }
116         return res;
117 }
118
119 void bitstream_put(struct bitstream *bit, unsigned long val, int bits)
120 {
121         while (bits)
122         {
123                 bit->last |= ((val & (1 << (bits-1))) ? 1 : 0) << (7 - bit->avail);
124                 if (++bit->avail == 8) {
125                         *bit->data = bit->last;
126                         ++bit->data;
127                         bit->last = 0;
128                         bit->avail = 0;
129                 }
130                 --bits;
131         }
132 }
133 #endif
134
135 /* We add a control socket as in fdsrc to make it shutdown quickly when it's blocking on the fd.
136  * Select is used to determine when the fd is ready for use. When the element state is changed,
137  * it happens from another thread while fdsink is select'ing on the fd. The state-change thread 
138  * sends a control message, so fdsink wakes up and changes state immediately otherwise
139  * it would stay blocked until it receives some data. */
140
141 /* the select call is also performed on the control sockets, that way
142  * we can send special commands to unblock the select call */
143 #define CONTROL_STOP                                            'S'              /* stop the select call */
144 #define CONTROL_SOCKETS(sink)    sink->control_sock
145 #define WRITE_SOCKET(sink)                      sink->control_sock[1]
146 #define READ_SOCKET(sink)                        sink->control_sock[0]
147
148 #define SEND_COMMAND(sink, command)                                     \
149 G_STMT_START {                                                                                                                  \
150         unsigned char c; c = command;                                            \
151         write (WRITE_SOCKET(sink), &c, 1);                               \
152 } G_STMT_END
153
154 #define READ_COMMAND(sink, command, res)                                \
155 G_STMT_START {                                                                                                                           \
156         res = read(READ_SOCKET(sink), &command, 1);      \
157 } G_STMT_END
158
159 GST_DEBUG_CATEGORY_STATIC (dvbvideosink_debug);
160 #define GST_CAT_DEFAULT dvbvideosink_debug
161
162 /* Filter signals and args */
163 enum {
164         /* FILL ME */
165         LAST_SIGNAL
166 };
167
168 enum {
169         ARG_0,
170         ARG_SILENT
171 };
172
173 #define COMMON_VIDEO_CAPS \
174   "width = (int) [ 16, 4096 ], " \
175   "height = (int) [ 16, 4096 ], " \
176   "framerate = (fraction) [ 0, MAX ]"
177
178 static GstStaticPadTemplate sink_factory =
179 GST_STATIC_PAD_TEMPLATE (
180         "sink",
181         GST_PAD_SINK,
182         GST_PAD_ALWAYS,
183         GST_STATIC_CAPS (
184                 "video/mpeg, "
185                 "mpegversion = (int) { 1, 2, 4 }, "
186                 "systemstream = (boolean) false, "
187         COMMON_VIDEO_CAPS "; "
188                 "video/x-msmpeg, "
189         COMMON_VIDEO_CAPS ", mspegversion = (int) 43; "
190                 "video/x-h264, "
191         COMMON_VIDEO_CAPS "; "
192                 "video/x-h263, "
193         COMMON_VIDEO_CAPS "; "
194                 "video/x-divx, "
195         COMMON_VIDEO_CAPS ", divxversion = (int) [ 3, 5 ]; "
196                 "video/x-xvid, "
197         COMMON_VIDEO_CAPS "; ")
198 );
199
200 #define DEBUG_INIT(bla) \
201         GST_DEBUG_CATEGORY_INIT (dvbvideosink_debug, "dvbvideosink", 0, "dvbvideosink element");
202
203 GST_BOILERPLATE_FULL (GstDVBVideoSink, gst_dvbvideosink, GstBaseSink,
204         GST_TYPE_BASE_SINK, DEBUG_INIT);
205
206 static void     gst_dvbvideosink_set_property (GObject *object, guint prop_id,
207                                                                                                                                                                                                         const GValue *value,
208                                                                                                                                                                                                         GParamSpec *pspec);
209 static void     gst_dvbvideosink_get_property (GObject *object, guint prop_id,
210                                                                                                                                                                                                         GValue *value,
211                                                                                                                                                                                                         GParamSpec *pspec);
212
213 static gboolean gst_dvbvideosink_start (GstBaseSink * sink);
214 static gboolean gst_dvbvideosink_stop (GstBaseSink * sink);
215 static gboolean gst_dvbvideosink_event (GstBaseSink * sink, GstEvent * event);
216 static GstFlowReturn gst_dvbvideosink_render (GstBaseSink * sink,
217         GstBuffer * buffer);
218 static gboolean gst_dvbvideosink_query (GstElement * element, GstQuery * query);
219 static gboolean gst_dvbvideosink_set_caps (GstBaseSink * sink, GstCaps * caps);
220 static gboolean gst_dvbvideosink_unlock (GstBaseSink * basesink);
221
222 static void
223 gst_dvbvideosink_base_init (gpointer klass)
224 {
225         static GstElementDetails element_details = {
226                 "A DVB video sink",
227                 "Generic/DVBVideoSink",
228                 "Output video PES / ES into a DVB video device for hardware playback",
229                 "Felix Domke <tmbinc@elitedvb.net>"
230         };
231         GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
232
233         gst_element_class_add_pad_template (element_class,
234                 gst_static_pad_template_get (&sink_factory));
235         gst_element_class_set_details (element_class, &element_details);
236 }
237
238 /* initialize the plugin's class */
239 static void
240 gst_dvbvideosink_class_init (GstDVBVideoSinkClass *klass)
241 {
242         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
243         GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
244         
245         gobject_class->set_property = gst_dvbvideosink_set_property;
246         gobject_class->get_property = gst_dvbvideosink_get_property;
247         
248         gobject_class = G_OBJECT_CLASS (klass);
249         g_object_class_install_property (gobject_class, ARG_SILENT,
250                 g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
251                                                                                                         FALSE, G_PARAM_READWRITE));
252
253         gstbasesink_class->get_times = NULL;
254         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbvideosink_start);
255         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbvideosink_stop);
256         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbvideosink_render);
257         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbvideosink_event);
258         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbvideosink_unlock);
259         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dvbvideosink_set_caps);
260         GST_ELEMENT_CLASS (klass)->query = GST_DEBUG_FUNCPTR (gst_dvbvideosink_query);
261 }
262
263 #define H264_BUFFER_SIZE (64*1024+2048)
264
265 /* initialize the new element
266  * instantiate pads and add them to element
267  * set functions
268  * initialize structure
269  */
270 static void
271 gst_dvbvideosink_init (GstDVBVideoSink *klass,
272                 GstDVBVideoSinkClass * gclass)
273 {
274         FILE *f = fopen("/proc/stb/vmpeg/0/fallback_framerate", "r");
275         klass->dec_running = FALSE;
276         klass->silent = FALSE;
277         klass->must_send_header = TRUE;
278         klass->h264_buffer = NULL;
279         klass->h264_nal_len_size = 0;
280         klass->codec_data = NULL;
281         klass->codec_type = CT_H264;
282 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
283         klass->must_pack_bitstream = 0;
284         klass->num_non_keyframes = 0;
285         klass->prev_frame = NULL;
286 #endif
287
288         if (f) {
289                 fgets(klass->saved_fallback_framerate, 16, f);
290                 fclose(f);
291         }
292         GST_BASE_SINK (klass)->sync = FALSE;
293 }
294
295 static void
296 gst_dvbvideosink_set_property (GObject *object, guint prop_id,
297                                                                                                                                         const GValue *value, GParamSpec *pspec)
298 {
299         GstDVBVideoSink *filter;
300
301         g_return_if_fail (GST_IS_DVBVIDEOSINK (object));
302         filter = GST_DVBVIDEOSINK (object);
303
304         switch (prop_id)
305         {
306         case ARG_SILENT:
307                 filter->silent = g_value_get_boolean (value);
308                 break;
309         default:
310                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311                 break;
312         }
313 }
314
315 static void
316 gst_dvbvideosink_get_property (GObject *object, guint prop_id,
317                                                                                                                                         GValue *value, GParamSpec *pspec)
318 {
319         GstDVBVideoSink *filter;
320
321         g_return_if_fail (GST_IS_DVBVIDEOSINK (object));
322         filter = GST_DVBVIDEOSINK (object);
323
324         switch (prop_id) {
325         case ARG_SILENT:
326                 g_value_set_boolean (value, filter->silent);
327                 break;
328         default:
329                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
330                 break;
331         }
332 }
333
334 static gboolean
335 gst_dvbvideosink_query (GstElement * element, GstQuery * query)
336 {
337         GstDVBVideoSink *self = GST_DVBVIDEOSINK (element);
338
339 //      printf("QUERY: type: %d (%d)\n", GST_QUERY_TYPE(query), GST_QUERY_POSITION);
340
341         switch (GST_QUERY_TYPE (query)) {
342         case GST_QUERY_POSITION:
343         {
344                 gint64 cur = 0;
345                 GstFormat format;
346
347                 gst_query_parse_position (query, &format, NULL);
348
349                 if (format != GST_FORMAT_TIME)
350                         goto query_default;
351
352                 ioctl(self->fd, VIDEO_GET_PTS, &cur);
353 //              printf("PTS: %08llx", cur);
354
355                 cur *= 11111;
356
357                 gst_query_set_position (query, format, cur);
358                 
359                 GST_DEBUG_OBJECT (self, "position format %d", format);
360                 return TRUE;
361         }
362         default:
363 query_default:
364                 return GST_ELEMENT_CLASS (parent_class)->query (element, query);
365         }
366 }
367
368 static gboolean gst_dvbvideosink_unlock (GstBaseSink * basesink)
369 {
370         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
371
372         SEND_COMMAND (self, CONTROL_STOP);
373
374         return TRUE;
375 }
376
377 static gboolean
378 gst_dvbvideosink_event (GstBaseSink * sink, GstEvent * event)
379 {
380         GstDVBVideoSink *self = GST_DVBVIDEOSINK (sink);
381         GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
382
383         switch (GST_EVENT_TYPE (event)) {
384         case GST_EVENT_FLUSH_START:
385                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
386                 self->must_send_header = TRUE;
387                 break;
388         case GST_EVENT_FLUSH_STOP:
389                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
390                 self->must_send_header = TRUE;
391                 while (1)
392                 {
393                         gchar command;
394                         int res;
395
396                         READ_COMMAND (self, command, res);
397                         if (res < 0)
398                                 break;
399                 }
400         default:
401                 break;
402         }
403         return TRUE;
404 }
405
406 static GstFlowReturn
407 gst_dvbvideosink_render (GstBaseSink * sink, GstBuffer * buffer)
408 {
409         GstDVBVideoSink *self = GST_DVBVIDEOSINK (sink);
410         unsigned char *data = GST_BUFFER_DATA(buffer);
411         unsigned int data_len = GST_BUFFER_SIZE (buffer);
412         guint8 pes_header[2048];
413         unsigned int pes_header_len=0;
414         unsigned int payload_len=0;
415         fd_set readfds;
416         fd_set writefds;
417         fd_set priofds;
418         gint retval;
419 //      int i=0;
420
421 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
422         gboolean commit_prev_frame_data = FALSE,
423                         cache_prev_frame = FALSE;
424 #endif
425
426 //      for (;i < (data_len > 0xF ? 0xF : data_len); ++i)
427 //              printf("%02x ", data[i]);
428 //      printf("%d bytes\n", data_len);
429
430 //      printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
431
432         FD_ZERO (&readfds);
433         FD_SET (READ_SOCKET (self), &readfds);
434
435         FD_ZERO (&writefds);
436         FD_SET (self->fd, &writefds);
437
438         FD_ZERO (&priofds);
439         FD_SET (self->fd, &priofds);
440
441         do {
442                 GST_DEBUG_OBJECT (self, "going into select, have %d bytes to write",
443                                 data_len);
444                 retval = select (FD_SETSIZE, &readfds, &writefds, &priofds, NULL);
445         } while ((retval == -1 && errno == EINTR));
446
447         if (retval == -1)
448                 goto select_error;
449
450         if (FD_ISSET (READ_SOCKET (self), &readfds)) {
451                 /* read all stop commands */
452                 while (TRUE) {
453                         gchar command;
454                         int res;
455
456                         READ_COMMAND (self, command, res);
457                         if (res < 0) {
458                                 GST_LOG_OBJECT (self, "no more commands");
459                                 /* no more commands */
460                                 break;
461                         }
462                 }
463                 goto stopped;
464         }
465
466         if (FD_ISSET (self->fd, &priofds))
467         {
468                 GstStructure *s;
469                 GstMessage *msg;
470
471                 struct video_event evt;
472                 if (ioctl(self->fd, VIDEO_GET_EVENT, &evt) < 0)
473                         g_warning ("failed to ioctl VIDEO_GET_EVENT!");
474                 else
475                 {
476                         printf("VIDEO_EVENT %d\n", evt.type);
477                         if (evt.type == VIDEO_EVENT_SIZE_CHANGED)
478                         {
479                                 s = gst_structure_new ("eventSizeChanged",
480                                         "aspect_ratio", G_TYPE_INT, evt.u.size.aspect_ratio == 0 ? 2 : 3,
481                                         "width", G_TYPE_INT, evt.u.size.w,
482                                         "height", G_TYPE_INT, evt.u.size.h, NULL);
483                                 msg = gst_message_new_element (GST_OBJECT (sink), s);
484                                 gst_element_post_message (GST_ELEMENT (sink), msg);
485                         }
486                         else if (evt.type == VIDEO_EVENT_FRAME_RATE_CHANGED)
487                         {
488                                 s = gst_structure_new ("eventFrameRateChanged",
489                                         "frame_rate", G_TYPE_INT, evt.u.frame_rate, NULL);
490                                 msg = gst_message_new_element (GST_OBJECT (sink), s);
491                                 gst_element_post_message (GST_ELEMENT (sink), msg);
492                         }
493                         else if (evt.type == 16 /*VIDEO_EVENT_PROGRESSIVE_CHANGED*/)
494                         {
495                                 s = gst_structure_new ("eventProgressiveChanged",
496                                         "progressive", G_TYPE_INT, evt.u.frame_rate, NULL);
497                                 msg = gst_message_new_element (GST_OBJECT (sink), s);
498                                 gst_element_post_message (GST_ELEMENT (sink), msg);
499                         }
500                         else
501                                 g_warning ("unhandled DVBAPI Video Event %d", evt.type);
502                 }
503         }
504
505         if (self->fd < 0)
506                 return GST_FLOW_OK;
507
508 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
509         if (self->must_pack_bitstream == 1) {
510                 cache_prev_frame = TRUE;
511                 unsigned int pos = 0;
512                 while(pos < data_len) {
513                         if (data[pos++])
514                                 continue;
515                         if (data[pos++])
516                                 continue;
517                         while (!data[pos])
518                                 ++pos;
519                         if (data[pos++] != 1)
520                                 continue;
521                         if ((data[pos++] & 0xF0) == 0x20) { // we need time_inc_res
522                                 gboolean low_delay=FALSE;
523                                 unsigned int ver_id = 1, shape=0, time_inc_res=0, tmp=0;
524                                 struct bitstream bit;
525                                 bitstream_init(&bit, data+pos, 0);
526                                 bitstream_get(&bit, 9);
527                                 if (bitstream_get(&bit, 1)) {
528                                         ver_id = bitstream_get(&bit, 4); // ver_id
529                                         bitstream_get(&bit, 3);
530                                 }
531                                 if ((tmp=bitstream_get(&bit, 4)) == 15) { // Custom Aspect Ration
532                                         bitstream_get(&bit, 8); // skip AR width
533                                         bitstream_get(&bit, 8); // skip AR height
534                                 }
535                                 if (bitstream_get(&bit, 1)) {
536                                         bitstream_get(&bit, 2);
537                                         low_delay = bitstream_get(&bit, 1) ? TRUE : FALSE;
538                                         if (bitstream_get(&bit, 1)) {
539                                                 bitstream_get(&bit, 32);
540                                                 bitstream_get(&bit, 32);
541                                                 bitstream_get(&bit, 15);
542                                         }
543                                 }
544                                 shape = bitstream_get(&bit, 2);
545                                 if (ver_id != 1 && shape == 3 /* Grayscale */)
546                                         bitstream_get(&bit, 4);
547                                 bitstream_get(&bit, 1);
548                                 time_inc_res = bitstream_get(&bit, 16);
549                                 self->time_inc_bits = 0;
550                                 while (time_inc_res) { // count bits
551                                         ++self->time_inc_bits;
552                                         time_inc_res >>= 1;
553                                 }
554 //                              printf("%d time_inc_bits\n", self->time_inc_bits);
555                         }
556                 }
557         }
558
559         if (self->must_pack_bitstream == 1) {
560                 int tmp1, tmp2;
561                 unsigned char c1, c2;
562                 unsigned int pos = 0;
563                 while(pos < data_len) {
564                         if (data[pos++])
565                                 continue;
566                         if (data[pos++])
567                                 continue;
568                         while (!data[pos])
569                                 ++pos;
570                         if (data[pos++] != 1)
571                                 continue;
572                         if (data[pos++] != 0xB2)
573                                 continue;
574                         if (data_len - pos < 13)
575                                 break;
576                         if (sscanf((char*)data+pos, "DivX%d%c%d%cp", &tmp1, &c1, &tmp2, &c2) == 4 && (c1 == 'b' || c1 == 'B') && (c2 == 'p' || c2 == 'P')) {
577                                 printf("%s seen... already packed!\n", (char*)data+pos);
578                                 self->must_pack_bitstream = 0;
579                         }
580 //                      if (self->must_pack_bitstream)
581 //                              printf("pack needed\n");
582 //                      else
583 //                              printf("no pack needed\n");
584                 }
585         }
586 #endif
587
588         pes_header[0] = 0;
589         pes_header[1] = 0;
590         pes_header[2] = 1;
591         pes_header[3] = 0xE0;
592
593                 /* do we have a timestamp? */
594         if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE) {
595                 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
596
597                 pes_header[6] = 0x80;
598                 pes_header[7] = 0x80;
599                 
600                 pes_header[8] = 5;
601                 
602                 pes_header[9] =  0x21 | ((pts >> 29) & 0xE);
603                 pes_header[10] = pts >> 22;
604                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
605                 pes_header[12] = pts >> 7;
606                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
607
608                 pes_header_len = 14;
609
610                 if (self->codec_data) {
611                         if (self->must_send_header) {
612                                 if (self->codec_type != CT_MPEG1 && self->codec_type != CT_MPEG2) {
613                                         unsigned char *codec_data = GST_BUFFER_DATA (self->codec_data);
614                                         unsigned int codec_data_len = GST_BUFFER_SIZE (self->codec_data);
615                                         if (self->codec_type == CT_DIVX311)
616                                                 write(self->fd, codec_data, codec_data_len);
617                                         else {
618                                                 memcpy(pes_header+pes_header_len, codec_data, codec_data_len);
619                                                 pes_header_len += codec_data_len;
620                                         }
621                                         self->must_send_header = FALSE;
622                                 }
623                         }
624                         if (self->codec_type == CT_H264) {  // MKV stuff
625                                 unsigned int pos = 0;
626                                 if (self->h264_nal_len_size == 4) {
627                                         while(TRUE) {
628                                                 unsigned int pack_len = (data[pos] << 24) | (data[pos+1] << 16) | (data[pos+2] << 8) | data[pos+3];
629 //                                              printf("patch %02x %02x %02x %02x\n",
630 //                                                      data[pos],
631 //                                                      data[pos + 1],
632 //                                                      data[pos + 2],
633 //                                                      data[pos + 3]);
634                                                 memcpy(data+pos, "\x00\x00\x00\x01", 4);
635 //                                              printf("pos %d, (%d) >= %d\n", pos, pos+pack_len, data_len);
636                                                 pos += 4;
637                                                 if ((pos + pack_len) >= data_len)
638                                                         break;
639                                                 pos += pack_len;
640                                         }
641                                 }
642                                 else if (self->h264_nal_len_size == 3) {
643                                         while(TRUE) {
644                                                 unsigned int pack_len = (data[pos] << 16) | (data[pos+1] << 8) | data[pos+2];
645 //                                              printf("patch %02x %02x %02x\n",
646 //                                                      data[pos],
647 //                                                      data[pos + 1],
648 //                                                      data[pos + 2]);
649                                                 memcpy(data+pos, "\x00\x00\x01", 3);
650 //                                              printf("pos %d, (%d) >= %d\n", pos, pos+pack_len, data_len);
651                                                 pos += 3;
652                                                 if ((pos + pack_len) >= data_len)
653                                                         break;
654                                                 pos += pack_len;
655                                         }
656                                 }
657                                 else {
658                                         unsigned char *dest = GST_BUFFER_DATA (self->h264_buffer);
659                                         unsigned int dest_pos = 0;
660                                         while(TRUE) {
661                                                 unsigned int pack_len = self->h264_nal_len_size == 2 ? (data[pos] << 8) | data[pos+1] : data[pos];
662                                                 if (dest_pos + pack_len <= H264_BUFFER_SIZE) {
663                                                         memcpy(dest+dest_pos, "\x00\x00\x01", 3);
664                                                         dest_pos += 3;
665                                                         pos += self->h264_nal_len_size;
666                                                         memcpy(dest+dest_pos, data+pos, pack_len);
667                                                         dest_pos += pack_len;
668                                                         if ((pos + pack_len) >= data_len)
669                                                                 break;
670                                                         pos += pack_len;
671                                                 }
672                                                 else {
673                                                         printf("BUG!!!!!!!! H264 buffer to small skip video data!!.. please report!\n");
674                                                         break;
675                                                 }
676                                         }
677                                         data = dest;
678                                         data_len = dest_pos;
679                                 }
680                         }
681                         else if (self->codec_type == CT_MPEG4_PART2) {
682                                 memcpy(pes_header+pes_header_len, "\x00\x00\x01", 3);
683                                 pes_header_len += 3;
684                         }
685                         else if (self->codec_type == CT_DIVX311) {
686                                 memcpy(pes_header+pes_header_len, "\x00\x00\x01\xb6", 4);
687                                 pes_header_len += 4;
688                         }
689                 }
690         }
691         else {
692 //              printf("no timestamp!\n");
693                 pes_header[6] = 0x80;
694                 pes_header[7] = 0x00;
695                 pes_header[8] = 0;
696                 pes_header_len = 9;
697         }
698
699 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
700         if (self->must_pack_bitstream == 1) {
701                 unsigned int pos = 0;
702                 gboolean i_frame = FALSE;
703 //              gboolean s_frame = FALSE;
704                 while(pos < data_len) {
705                         if (data[pos++])
706                                 continue;
707                         if (data[pos++])
708                                 continue;
709                         while (!data[pos])
710                                 ++pos;
711                         if (data[pos++] != 1)
712                                 continue;
713                         if (data[pos++] != 0xB6)
714                                 continue;
715                         switch ((data[pos] & 0xC0) >> 6) {
716                                 case 0: // I-Frame
717 //                                      printf("I ");
718                                         cache_prev_frame = FALSE;
719                                         i_frame = TRUE;
720                                 case 1: // P-Frame
721 //                                      if (!i_frame)
722 //                                              printf("P ");
723                                         if (self->prev_frame != buffer) {
724                                                 struct bitstream bit;
725                                                 gboolean store_frame=FALSE;
726                                                 if (self->prev_frame) {
727                                                         if (!self->num_non_keyframes) {
728 //                                                              printf("no non keyframes...immediate commit prev frame\n");
729                                                                 GstFlowReturn ret = gst_dvbvideosink_render(sink, self->prev_frame);
730                                                                 gst_buffer_unref(self->prev_frame);
731                                                                 self->prev_frame = NULL;
732                                                                 if (ret != GST_FLOW_OK)
733                                                                         return ret;
734                                                                 store_frame = TRUE;
735                                                         }
736                                                         else {
737 //                                                              int i=-4;
738                                                                 pes_header[pes_header_len++] = 0;
739                                                                 pes_header[pes_header_len++] = 0;
740                                                                 pes_header[pes_header_len++] = 1;
741                                                                 pes_header[pes_header_len++] = 0xB6;
742                                                                 bitstream_init(&bit, pes_header+pes_header_len, 1);
743                                                                 bitstream_put(&bit, 1, 2);
744                                                                 bitstream_put(&bit, 0, 1);
745                                                                 bitstream_put(&bit, 1, 1);
746                                                                 bitstream_put(&bit, self->time_inc, self->time_inc_bits);
747                                                                 bitstream_put(&bit, 1, 1);
748                                                                 bitstream_put(&bit, 0, 1);
749                                                                 bitstream_put(&bit, 0x7F >> bit.avail, 8 - bit.avail);
750 //                                                              printf(" insert pack frame %d non keyframes, time_inc %d, time_inc_bits %d -",
751 //                                                                      self->num_non_keyframes, self->time_inc, self->time_inc_bits);
752 //                                                              for (; i < (bit.data - (pes_header+pes_header_len)); ++i)
753 //                                                                      printf(" %02x", pes_header[pes_header_len+i]);
754 //                                                              printf("\nset data_len to 0!\n");
755                                                                 data_len = 0;
756                                                                 pes_header_len += bit.data - (pes_header+pes_header_len);
757                                                                 cache_prev_frame = TRUE;
758                                                         }
759                                                 }
760                                                 else if (!i_frame)
761                                                         store_frame = TRUE;
762
763                                                 self->num_non_keyframes=0;
764
765                                                 // extract time_inc
766                                                 bitstream_init(&bit, data+pos, 0);
767                                                 bitstream_get(&bit, 2); // skip coding_type
768                                                 while(bitstream_get(&bit, 1));
769                                                 bitstream_get(&bit, 1);
770                                                 self->time_inc = bitstream_get(&bit, self->time_inc_bits);
771 //                                              printf("\ntime_inc is %d\n", self->time_inc);
772
773                                                 if (store_frame) {
774 //                                                      printf("store frame\n");
775                                                         self->prev_frame = buffer;
776                                                         gst_buffer_ref (buffer);
777                                                         return GST_FLOW_OK;
778                                                 }
779                                         }
780                                         else {
781                                                 cache_prev_frame = FALSE;
782 //                                              printf(" I/P Frame without non key frame(s)!!\n");
783                                         }
784                                         break;
785                                 case 3: // S-Frame
786 //                                      printf("S ");
787 //                                      s_frame = TRUE;
788                                 case 2: // B-Frame
789 //                                      if (!s_frame)
790 //                                              printf("B ");
791                                         if (++self->num_non_keyframes == 1 && self->prev_frame) {
792 //                                              printf("send grouped with prev P!\n");
793                                                 commit_prev_frame_data = TRUE;
794                                         }
795                                         break;
796                                 case 4: // N-Frame
797                                 default:
798                                         printf("unhandled divx5/xvid frame type %d\n", (data[pos] & 0xC0) >> 6);
799                                         break;
800                         }
801                 }
802 //              printf("\n");
803         }
804 #endif
805
806         payload_len = data_len + pes_header_len - 6;
807
808 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
809         if (self->prev_frame && self->prev_frame != buffer) {
810                 unsigned long long pts = GST_BUFFER_TIMESTAMP(self->prev_frame) * 9LL / 100000 /* convert ns to 90kHz */;
811 //              printf("use prev timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(self->prev_frame));
812
813                 pes_header[9] =  0x21 | ((pts >> 29) & 0xE);
814                 pes_header[10] = pts >> 22;
815                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
816                 pes_header[12] = pts >> 7;
817                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
818         }
819
820         if (commit_prev_frame_data)
821                 payload_len += GST_BUFFER_SIZE (self->prev_frame);
822 #endif
823
824         if (self->codec_type == CT_MPEG2 || self->codec_type == CT_MPEG1) {
825                 if (!self->codec_data && data_len > 3 && !data[0] && !data[1] && data[2] == 1 && data[3] == 0xb3) { // sequence header?
826                         gboolean ok = TRUE;
827                         unsigned int pos = 4;
828                         unsigned int sheader_data_len=0;
829                         while(pos < data_len && ok) {
830                                 if ( pos >= data_len )
831                                         break;
832                                 pos+=7;
833                                 if ( pos >=data_len )
834                                         break;
835                                 sheader_data_len=12;
836                                 if ( data[pos] & 2 ) { // intra matrix avail?
837                                         pos+=64;
838                                         if ( pos >=data_len )
839                                                 break;
840                                         sheader_data_len+=64;
841                                 }
842                                 if ( data[pos] & 1 ) { // non intra matrix avail?
843                                         pos+=64;
844                                         if ( pos >=data_len )
845                                                 break;
846                                         sheader_data_len+=64;
847                                 }
848                                 pos+=1;
849                                 if ( pos+3 >=data_len )
850                                         break;
851                                 // extended start code
852                                 if ( !data[pos] && !data[pos+1] && data[pos+2] == 1 && data[pos+3] == 0xB5 ) {
853                                         pos+=3;
854                                         sheader_data_len+=3;
855                                         do {
856                                                 pos+=1;
857                                                 ++sheader_data_len;
858                                                 if (pos+2 > data_len)
859                                                         goto leave;
860                                         }
861                                         while( data[pos] || data[pos+1] || data[pos+2] != 1 );
862                                 }
863                                 if ( pos+3 >=data_len )
864                                         break;
865                                 // private data
866                                 if ( !data[pos] && !data[pos+1] && data[pos+2] && data[pos+3] == 0xB2 ) {
867                                         pos+=3;
868                                         sheader_data_len+=3;
869                                         do {
870                                                 pos+=1;
871                                                 ++sheader_data_len;
872                                                 if (pos+2 > data_len)
873                                                         goto leave;
874                                         }
875                                         while( data[pos] || data[pos+1] || data[pos+2] != 1 );
876                                 }
877                                 self->codec_data = gst_buffer_new_and_alloc(sheader_data_len);
878                                 memcpy(GST_BUFFER_DATA(self->codec_data), data+pos-sheader_data_len, sheader_data_len);
879                                 self->must_send_header = FALSE;
880 leave:
881                                 ok = FALSE;
882                         }
883                 }
884                 else if (self->codec_data && self->must_send_header) {
885                         unsigned char *codec_data = GST_BUFFER_DATA (self->codec_data);
886                         unsigned int codec_data_len = GST_BUFFER_SIZE (self->codec_data);
887                         int pos = 0;
888                         while(pos < data_len) {
889                                 if ( data[pos++] )
890                                         continue;
891                                 if ( data[pos++] )
892                                         continue;
893                                 while ( !data[pos] )
894                                         pos++;
895                                 if ( data[pos++] != 1 )
896                                         continue;
897                                 if ( data[pos++] != 0xb8 ) // group start code
898                                         continue;
899                                 pos-=4; // before group start
900                                 payload_len += codec_data_len;
901                                 if (payload_len <= 0xFFFF) {
902                                         pes_header[4] = payload_len >> 8;
903                                         pes_header[5] = payload_len & 0xFF;
904                                 }
905                                 else {
906                                         pes_header[4] = 0;
907                                         pes_header[5] = 0;
908                                 }
909                                 write(self->fd, pes_header, pes_header_len);
910                                 write(self->fd, data, pos);
911                                 write(self->fd, codec_data, codec_data_len);
912                                 write(self->fd, data+pos, data_len - pos);
913                                 self->must_send_header = FALSE;
914                                 return GST_FLOW_OK;
915                         }
916                 }
917         }
918
919         if (payload_len <= 0xFFFF) {
920                 pes_header[4] = payload_len >> 8;
921                 pes_header[5] = payload_len & 0xFF;
922         }
923         else {
924                 pes_header[4] = 0;
925                 pes_header[5] = 0;
926         }
927
928         write(self->fd, pes_header, pes_header_len);
929
930 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
931         if (commit_prev_frame_data) {
932 //              printf("commit prev frame data\n");
933                 write(self->fd, GST_BUFFER_DATA (self->prev_frame), GST_BUFFER_SIZE (self->prev_frame));
934         }
935
936         if (self->prev_frame && self->prev_frame != buffer) {
937 //              printf("unref prev_frame buffer\n");
938                 gst_buffer_unref(self->prev_frame);
939                 self->prev_frame = NULL;
940         }
941
942         if (cache_prev_frame) {
943 //              printf("cache prev frame\n");
944                 gst_buffer_ref(buffer);
945                 self->prev_frame = buffer;
946         }
947 #endif
948
949         write(self->fd, data, data_len);
950
951         return GST_FLOW_OK;
952 select_error:
953         {
954                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
955                                 ("select on file descriptor: %s.", g_strerror (errno)));
956                 GST_DEBUG_OBJECT (self, "Error during select");
957                 return GST_FLOW_ERROR;
958         }
959 stopped:
960         {
961                 GST_DEBUG_OBJECT (self, "Select stopped");
962                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
963                 return GST_FLOW_WRONG_STATE;
964         }
965 }
966
967 static gboolean 
968 gst_dvbvideosink_set_caps (GstBaseSink * basesink, GstCaps * caps)
969 {
970         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
971         GstStructure *structure = gst_caps_get_structure (caps, 0);
972         const char *mimetype = gst_structure_get_name (structure);
973         int streamtype = -1;
974
975         if (!strcmp (mimetype, "video/mpeg")) {
976                 gint mpegversion;
977                 gst_structure_get_int (structure, "mpegversion", &mpegversion);
978                 switch (mpegversion) {
979                         case 1:
980                                 streamtype = 6;
981                                 self->codec_type = CT_MPEG1;
982                                 printf("MIMETYPE video/mpeg1 -> VIDEO_SET_STREAMTYPE, 6\n");
983                         break;
984                         case 2:
985                                 streamtype = 0;
986                                 self->codec_type = CT_MPEG2;
987                                 printf("MIMETYPE video/mpeg2 -> VIDEO_SET_STREAMTYPE, 0\n");
988                         break;
989                         case 4:
990                         {
991                                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
992                                 if (codec_data) {
993                                         printf("MPEG4 have codec data\n");
994                                         self->codec_data = gst_value_get_buffer (codec_data);
995                                         self->codec_type = CT_MPEG4_PART2;
996                                         gst_buffer_ref (self->codec_data);
997                                 }
998                                 streamtype = 4;
999                                 printf("MIMETYPE video/mpeg4 -> VIDEO_SET_STREAMTYPE, 4\n");
1000                         }
1001                         break;
1002                         default:
1003                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
1004                         break;
1005                 }
1006         } else if (!strcmp (mimetype, "video/x-h264")) {
1007                 const GValue *cd_data = gst_structure_get_value (structure, "codec_data");
1008                 streamtype = 1;
1009                 if (cd_data) {
1010                         unsigned char tmp[2048];
1011                         unsigned int tmp_len = 0;
1012                         GstBuffer *codec_data = gst_value_get_buffer (cd_data);
1013                         unsigned char *data = GST_BUFFER_DATA (codec_data);
1014                         unsigned int cd_len = GST_BUFFER_SIZE (codec_data);
1015                         unsigned int cd_pos = 0;
1016                         printf("H264 have codec data..!\n");
1017 //                      printf("1\n");
1018                         if (cd_len > 7 && data[0] == 1) {
1019                                 unsigned short len = (data[6] << 8) | data[7];
1020 //                              printf("2 %d bytes\n", len);
1021                                 if (cd_len >= (len + 8)) {
1022                                         unsigned int i=0;
1023                                         uint8_t profile_num[] = { 66, 77, 88, 100 };
1024                                         uint8_t profile_cmp[2] = { 0x67, 0x00 };
1025                                         const char *profile_str[] = { "baseline", "main", "extended", "high" };
1026 //                                      printf("3\n");
1027                                         memcpy(tmp, "\x00\x00\x00\x01", 4);
1028                                         tmp_len += 4;
1029 //                                      printf("header part1 ");
1030 //                                      for (i = 0; i < len; ++i)
1031 //                                              printf("%02x ", data[8+i]);
1032 //                                      printf("\n");
1033                                         memcpy(tmp+tmp_len, data+8, len);
1034                                         for (i = 0; i < 4; ++i) {
1035                                                 profile_cmp[1] = profile_num[i];
1036                                                 if (!memcmp(tmp+tmp_len, profile_cmp, 2)) {
1037                                                         uint8_t level_org = tmp[tmp_len+3];
1038                                                         if (level_org > 0x29) {
1039                                                                 printf("H264 %s profile@%d.%d patched down to 4.1!\n",
1040                                                                         profile_str[i], level_org / 10 , level_org % 10);
1041                                                                 tmp[tmp_len+3] = 0x29; // level 4.1
1042                                                         }
1043                                                         else
1044                                                                 printf("H264 %s profile@%d.%d\n",
1045                                                                         profile_str[i], level_org / 10 , level_org % 10);
1046                                                         break;
1047                                                 }
1048                                         }
1049                                         tmp_len += len;
1050                                         cd_pos = 8 + len;
1051                                         if (cd_len > (cd_pos + 2)) {
1052                                                 len = (data[cd_pos+1] << 8) | data[cd_pos+2];
1053 //                                              printf("4 %d bytes\n", len);
1054                                                 cd_pos += 3;
1055                                                 if (cd_len >= (cd_pos+len)) {
1056 //                                                      printf("codec data ok!\n");
1057                                                         memcpy(tmp+tmp_len, "\x00\x00\x00\x01", 4);
1058                                                         tmp_len += 4;
1059 //                                                      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);
1060                                                         memcpy(tmp+tmp_len, data+cd_pos, len);
1061                                                         tmp_len += len;
1062                                                         self->codec_data = gst_buffer_new_and_alloc(tmp_len);
1063                                                         memcpy(GST_BUFFER_DATA(self->codec_data), tmp, tmp_len);
1064                                                         self->h264_nal_len_size = (data[4] & 0x03) + 1;
1065                                                         if (self->h264_nal_len_size < 3)
1066                                                                 self->h264_buffer = gst_buffer_new_and_alloc(H264_BUFFER_SIZE);
1067                                                 }
1068                                                 else
1069                                                         printf("codec_data to short(4)\n");
1070                                         }
1071                                         else
1072                                                 printf("codec_data to short(3)!\n");
1073                                 }
1074                                 else
1075                                         printf("codec_data to short(2)!\n");
1076                         }
1077                         else if (cd_len <= 7)
1078                                 printf("codec_data to short(1)!\n");
1079                         else
1080                                 printf("wrong avcC version %d!\n", data[0]);
1081                 }
1082                 else
1083                         self->h264_nal_len_size = 0;
1084                 printf("MIMETYPE video/x-h264 VIDEO_SET_STREAMTYPE, 1\n");
1085         } else if (!strcmp (mimetype, "video/x-h263")) {
1086                 streamtype = 2;
1087                 printf("MIMETYPE video/x-h263 VIDEO_SET_STREAMTYPE, 2\n");
1088         } else if (!strcmp (mimetype, "video/x-xvid")) {
1089                 streamtype = 10;
1090 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1091                 self->must_pack_bitstream = 1;
1092 #endif
1093                 printf("MIMETYPE video/x-xvid -> VIDEO_SET_STREAMTYPE, 10\n");
1094         } else if (!strcmp (mimetype, "video/x-divx") || !strcmp (mimetype, "video/x-msmpeg")) {
1095                 gint divxversion = -1;
1096                 if (!gst_structure_get_int (structure, "divxversion", &divxversion) && !gst_structure_get_int (structure, "msmpegversion", &divxversion))
1097                         ;
1098                 switch (divxversion) {
1099                         case 3:
1100                         case 43:
1101                         {
1102                                 #define B_GET_BITS(w,e,b)  (((w)>>(b))&(((unsigned)(-1))>>((sizeof(unsigned))*8-(e+1-b))))
1103                                 #define B_SET_BITS(name,v,e,b)  (((unsigned)(v))<<(b))
1104                                 static const guint8 brcm_divx311_sequence_header[] = {
1105                                         0x00, 0x00, 0x01, 0xE0, 0x00, 0x34, 0x80, 0x80, // PES HEADER
1106                                         0x05, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, 
1107                                         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, /* 0 .. 7 */
1108                                         0x08, 0xC8, 0x0D, 0x40, 0x00, 0x53, 0x88, 0x40, /* 8 .. 15 */
1109                                         0x0C, 0x40, 0x01, 0x90, 0x00, 0x97, 0x53, 0x0A, /* 16 .. 24 */
1110                                         0x00, 0x00, 0x00, 0x00,
1111                                         0x30, 0x7F, 0x00, 0x00, 0x01, 0xB2, 0x44, 0x69, /* 0 .. 7 */
1112                                         0x76, 0x58, 0x33, 0x31, 0x31, 0x41, 0x4E, 0x44  /* 8 .. 15 */
1113                                 };
1114                                 self->codec_data = gst_buffer_new_and_alloc(63);
1115                                 guint8 *data = GST_BUFFER_DATA(self->codec_data);
1116                                 gint height, width;
1117                                 gst_structure_get_int (structure, "height", &height);
1118                                 gst_structure_get_int (structure, "width", &width);
1119                                 memcpy(data, brcm_divx311_sequence_header, 63);
1120                                 data += 38;
1121                                 data[0] = B_GET_BITS(width,11,4);
1122                                 data[1] = B_SET_BITS("width [3..0]", B_GET_BITS(width,3,0), 7, 4) |
1123                                         B_SET_BITS("'10'", 0x02, 3, 2) |
1124                                         B_SET_BITS("height [11..10]", B_GET_BITS(height,11,10), 1, 0);
1125                                 data[2] = B_GET_BITS(height,9,2);
1126                                 data[3]= B_SET_BITS("height [1.0]", B_GET_BITS(height,1,0), 7, 6) |
1127                                         B_SET_BITS("'100000'", 0x20, 5, 0);
1128                                 streamtype = 13;
1129                                 self->codec_type = CT_DIVX311;
1130                                 printf("MIMETYPE video/x-divx vers. 3 -> VIDEO_SET_STREAMTYPE, 13\n");
1131                         }
1132                         break;
1133                         case 4:
1134                                 streamtype = 14;
1135                                 printf("MIMETYPE video/x-divx vers. 4 -> VIDEO_SET_STREAMTYPE, 14\n");
1136                         break;
1137                         case 6:
1138                         case 5:
1139                                 streamtype = 15;
1140 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1141                                 self->must_pack_bitstream = 1;
1142 #endif
1143                                 printf("MIMETYPE video/x-divx vers. 5 -> VIDEO_SET_STREAMTYPE, 15\n");
1144                         break;
1145                         default:
1146                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled divx version %i", divxversion));
1147                         break;
1148                 }
1149         }
1150         if (streamtype != -1) {
1151                 gint numerator, denominator;
1152                 if (gst_structure_get_fraction (structure, "framerate", &numerator, &denominator)) {
1153                         FILE *f = fopen("/proc/stb/vmpeg/0/fallback_framerate", "w");
1154                         if (f) {
1155                                 int valid_framerates[] = { 23976, 24000, 25000, 29970, 30000, 50000, 59940, 60000 };
1156                                 int framerate = (int)(((double)numerator * 1000) / denominator);
1157                                 int diff = 60000;
1158                                 int best = 0;
1159                                 int i = 0;
1160                                 for (; i < 7; ++i) {
1161                                         int ndiff = abs(framerate - valid_framerates[i]);
1162                                         if (ndiff < diff) {
1163                                                 diff = ndiff;
1164                                                 best = i;
1165                                         }
1166                                 }
1167                                 fprintf(f, "%d", valid_framerates[best]);
1168                                 fclose(f);
1169                         }
1170                 }
1171                 if (self->dec_running) {
1172                         ioctl(self->fd, VIDEO_STOP, 0);
1173                         self->dec_running = FALSE;
1174                 }
1175                 if (ioctl(self->fd, VIDEO_SET_STREAMTYPE, streamtype) < 0 )
1176                         if ( streamtype != 0 && streamtype != 6 )
1177                                 GST_ELEMENT_ERROR (self, STREAM, CODEC_NOT_FOUND, (NULL), ("hardware decoder can't handle streamtype %i", streamtype));
1178                 ioctl(self->fd, VIDEO_PLAY);
1179                 self->dec_running = TRUE;
1180         } else
1181                 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", mimetype));
1182
1183         return TRUE;
1184 }
1185
1186 static int readMpegProc(char *str, int decoder)
1187 {
1188         int val = -1;
1189         char tmp[64];
1190         sprintf(tmp, "/proc/stb/vmpeg/%d/%s", decoder, str);
1191         FILE *f = fopen(tmp, "r");
1192         if (f)
1193         {
1194                 fscanf(f, "%x", &val);
1195                 fclose(f);
1196         }
1197         return val;
1198 }
1199
1200 static int readApiSize(int fd, int *xres, int *yres, int *aspect)
1201 {
1202         video_size_t size;
1203         if (!ioctl(fd, VIDEO_GET_SIZE, &size))
1204         {
1205                 *xres = size.w;
1206                 *yres = size.h;
1207                 *aspect = size.aspect_ratio == 0 ? 2 : 3;  // convert dvb api to etsi
1208                 return 0;
1209         }
1210         return -1;
1211 }
1212
1213 static int readApiFrameRate(int fd, int *framerate)
1214 {
1215         unsigned int frate;
1216         if (!ioctl(fd, VIDEO_GET_FRAME_RATE, &frate))
1217         {
1218                 *framerate = frate;
1219                 return 0;
1220         }
1221         return -1;
1222 }
1223
1224 static gboolean
1225 gst_dvbvideosink_start (GstBaseSink * basesink)
1226 {
1227         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
1228         self->fd = open("/dev/dvb/adapter0/video0", O_RDWR);
1229 //      self->fd = open("/dump.pes", O_RDWR|O_CREAT|O_TRUNC, 0555);
1230
1231         gint control_sock[2];
1232
1233         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
1234                 goto socket_pair;
1235
1236         READ_SOCKET (self) = control_sock[0];
1237         WRITE_SOCKET (self) = control_sock[1];
1238
1239         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
1240         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
1241
1242         if (self->fd >= 0)
1243         {
1244                 GstStructure *s = 0;
1245                 GstMessage *msg = 0;
1246                 int aspect = -1, width = -1, height = -1, framerate = -1,
1247                         progressive = readMpegProc("progressive", 0);
1248
1249                 if (readApiSize(self->fd, &width, &height, &aspect) == -1)
1250                 {
1251                         aspect = readMpegProc("aspect", 0);
1252                         width = readMpegProc("xres", 0);
1253                         height = readMpegProc("yres", 0);
1254                 }
1255                 else
1256                         aspect = aspect == 0 ? 2 : 3; // dvb api to etsi
1257                 if (readApiFrameRate(self->fd, &framerate) == -1)
1258                         framerate = readMpegProc("framerate", 0);
1259
1260                 s = gst_structure_new ("eventSizeAvail",
1261                         "aspect_ratio", G_TYPE_INT, aspect == 0 ? 2 : 3,
1262                         "width", G_TYPE_INT, width,
1263                         "height", G_TYPE_INT, height, NULL);
1264                 msg = gst_message_new_element (GST_OBJECT (basesink), s);
1265                 gst_element_post_message (GST_ELEMENT (basesink), msg);
1266
1267                 s = gst_structure_new ("eventFrameRateAvail",
1268                         "frame_rate", G_TYPE_INT, framerate, NULL);
1269                 msg = gst_message_new_element (GST_OBJECT (basesink), s);
1270                 gst_element_post_message (GST_ELEMENT (basesink), msg);
1271
1272                 s = gst_structure_new ("eventProgressiveAvail",
1273                         "progressive", G_TYPE_INT, progressive, NULL);
1274                 msg = gst_message_new_element (GST_OBJECT (basesink), s);
1275                 gst_element_post_message (GST_ELEMENT (basesink), msg);
1276
1277                 ioctl(self->fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
1278         }
1279
1280         return TRUE;
1281         /* ERRORS */
1282 socket_pair:
1283         {
1284                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
1285                                 GST_ERROR_SYSTEM);
1286                 return FALSE;
1287         }
1288 }
1289
1290 static gboolean
1291 gst_dvbvideosink_stop (GstBaseSink * basesink)
1292 {
1293         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
1294         FILE *f = fopen("/proc/stb/vmpeg/0/fallback_framerate", "w");
1295         if (self->fd >= 0)
1296         {
1297                 if (self->dec_running) {
1298                         ioctl(self->fd, VIDEO_STOP);
1299                         self->dec_running = FALSE;
1300                 }
1301                 ioctl(self->fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
1302                 close(self->fd);
1303         }
1304
1305         close (READ_SOCKET (self));
1306         close (WRITE_SOCKET (self));
1307
1308         if (self->codec_data)
1309                 gst_buffer_unref(self->codec_data);
1310
1311         if (self->h264_buffer)
1312                 gst_buffer_unref(self->h264_buffer);
1313
1314 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
1315         if (self->prev_frame)
1316                 gst_buffer_unref(self->prev_frame);
1317 #endif
1318
1319         if (f) {
1320                 fputs(self->saved_fallback_framerate, f);
1321                 fclose(f);
1322         }
1323
1324         return TRUE;
1325 }
1326
1327 /* entry point to initialize the plug-in
1328  * initialize the plug-in itself
1329  * register the element factories and pad templates
1330  * register the features
1331  *
1332  * exchange the string 'plugin' with your elemnt name
1333  */
1334 static gboolean
1335 plugin_init (GstPlugin *plugin)
1336 {
1337         return gst_element_register (plugin, "dvbvideosink",
1338                                                  GST_RANK_PRIMARY,
1339                                                  GST_TYPE_DVBVIDEOSINK);
1340 }
1341
1342 /* this is the structure that gstreamer looks for to register plugins
1343  *
1344  * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
1345  * description
1346  */
1347 GST_PLUGIN_DEFINE (
1348         GST_VERSION_MAJOR,
1349         GST_VERSION_MINOR,
1350         "dvb_video_out",
1351         "DVB Video Output",
1352         plugin_init,
1353         VERSION,
1354         "LGPL",
1355         "GStreamer",
1356         "http://gstreamer.net/"
1357 )