add workaround for non packed xvid/divx5 bitstream
[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 ("video/mpeg, "
184                 "mpegversion = (int) { 1, 2, 4 }, "
185                 "systemstream = (boolean) false, "
186         COMMON_VIDEO_CAPS "; "
187                 "video/x-wmv, "
188         COMMON_VIDEO_CAPS "; "
189                 "video/x-h264, "
190         COMMON_VIDEO_CAPS "; "
191                 "video/x-h263, "
192         COMMON_VIDEO_CAPS "; "
193                 "video/x-divx, "
194         COMMON_VIDEO_CAPS ", divxversion = (int) [ 3, 5 ]; "
195                 "video/x-xvid, " COMMON_VIDEO_CAPS )
196 );
197
198 #define DEBUG_INIT(bla) \
199         GST_DEBUG_CATEGORY_INIT (dvbvideosink_debug, "dvbvideosink", 0, "dvbvideosink element");
200
201 GST_BOILERPLATE_FULL (GstDVBVideoSink, gst_dvbvideosink, GstBaseSink,
202         GST_TYPE_BASE_SINK, DEBUG_INIT);
203
204 static void     gst_dvbvideosink_set_property (GObject *object, guint prop_id,
205                                                                                                                                                                                                         const GValue *value,
206                                                                                                                                                                                                         GParamSpec *pspec);
207 static void     gst_dvbvideosink_get_property (GObject *object, guint prop_id,
208                                                                                                                                                                                                         GValue *value,
209                                                                                                                                                                                                         GParamSpec *pspec);
210
211 static gboolean gst_dvbvideosink_start (GstBaseSink * sink);
212 static gboolean gst_dvbvideosink_stop (GstBaseSink * sink);
213 static gboolean gst_dvbvideosink_event (GstBaseSink * sink, GstEvent * event);
214 static GstFlowReturn gst_dvbvideosink_render (GstBaseSink * sink,
215         GstBuffer * buffer);
216 static gboolean gst_dvbvideosink_query (GstPad * pad, GstQuery * query);
217 static gboolean gst_dvbvideosink_set_caps (GstPad * pad, GstCaps * vscaps);
218 static gboolean gst_dvbvideosink_unlock (GstBaseSink * basesink);
219
220 static void
221 gst_dvbvideosink_base_init (gpointer klass)
222 {
223         static GstElementDetails element_details = {
224                 "A DVB video sink",
225                 "Generic/DVBVideoSink",
226                 "Outputs a MPEG2 or .H264 PES / ES into a DVB video device for hardware playback",
227                 "Felix Domke <tmbinc@elitedvb.net>"
228         };
229         GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
230
231         gst_element_class_add_pad_template (element_class,
232                 gst_static_pad_template_get (&sink_factory));
233         gst_element_class_set_details (element_class, &element_details);
234 }
235
236 /* initialize the plugin's class */
237 static void
238 gst_dvbvideosink_class_init (GstDVBVideoSinkClass *klass)
239 {
240         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
241         GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
242         
243         gobject_class->set_property = gst_dvbvideosink_set_property;
244         gobject_class->get_property = gst_dvbvideosink_get_property;
245         
246         gobject_class = G_OBJECT_CLASS (klass);
247         g_object_class_install_property (gobject_class, ARG_SILENT,
248                 g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
249                                                                                                         FALSE, G_PARAM_READWRITE));
250
251         gstbasesink_class->get_times = NULL;
252         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbvideosink_start);
253         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbvideosink_stop);
254         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbvideosink_render);
255         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbvideosink_event);
256         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbvideosink_unlock);
257 }
258
259 /* initialize the new element
260  * instantiate pads and add them to element
261  * set functions
262  * initialize structure
263  */
264 static void
265 gst_dvbvideosink_init (GstDVBVideoSink *klass,
266                 GstDVBVideoSinkClass * gclass)
267 {
268         GstPad *pad = GST_BASE_SINK_PAD (klass);
269         
270         gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_dvbvideosink_set_caps));
271         gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_dvbvideosink_query));
272         
273         klass->silent = FALSE;
274         klass->divx311_header = NULL;
275         klass->must_send_header = FALSE;
276         klass->codec_data = NULL;
277         klass->must_pack_bitstream = 0;
278         klass->num_non_keyframes = 0;
279         klass->prev_frame = NULL;
280
281         GST_BASE_SINK (klass)->sync = FALSE;
282 }
283
284 static void
285 gst_dvbvideosink_set_property (GObject *object, guint prop_id,
286                                                                                                                                         const GValue *value, GParamSpec *pspec)
287 {
288         GstDVBVideoSink *filter;
289
290         g_return_if_fail (GST_IS_DVBVIDEOSINK (object));
291         filter = GST_DVBVIDEOSINK (object);
292
293         switch (prop_id)
294         {
295         case ARG_SILENT:
296                 filter->silent = g_value_get_boolean (value);
297                 break;
298         default:
299                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
300                 break;
301         }
302 }
303
304 static void
305 gst_dvbvideosink_get_property (GObject *object, guint prop_id,
306                                                                                                                                         GValue *value, GParamSpec *pspec)
307 {
308         GstDVBVideoSink *filter;
309
310         g_return_if_fail (GST_IS_DVBVIDEOSINK (object));
311         filter = GST_DVBVIDEOSINK (object);
312
313         switch (prop_id) {
314         case ARG_SILENT:
315                 g_value_set_boolean (value, filter->silent);
316                 break;
317         default:
318                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
319                 break;
320         }
321 }
322
323 static gboolean
324 gst_dvbvideosink_query (GstPad * pad, GstQuery * query)
325 {
326         GstDVBVideoSink *self = GST_DVBVIDEOSINK (GST_PAD_PARENT (pad));
327 //      GstFormat format;
328         
329         printf("QUERY: type: %d\n", GST_QUERY_TYPE(query));
330         switch (GST_QUERY_TYPE (query)) {
331         case GST_QUERY_POSITION:
332         {
333                 gint64 cur = 0;
334                 GstFormat format;
335
336                 gst_query_parse_position (query, &format, NULL);
337                 
338                 if (format != GST_FORMAT_TIME)
339                         return gst_pad_query_default (pad, query);
340
341                 ioctl(self->fd, VIDEO_GET_PTS, &cur);
342                 printf("PTS: %08llx", cur);
343                 
344                 cur *= 11111;
345                 
346                 gst_query_set_position (query, format, cur);
347                 
348                 GST_DEBUG_OBJECT (self, "position format %d", format);
349                 return TRUE;
350         }
351         default:
352                 return gst_pad_query_default (pad, query);
353         }
354 }
355
356 static gboolean gst_dvbvideosink_unlock (GstBaseSink * basesink)
357 {
358         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
359
360         SEND_COMMAND (self, CONTROL_STOP);
361
362         return TRUE;
363 }
364
365 static gboolean
366 gst_dvbvideosink_event (GstBaseSink * sink, GstEvent * event)
367 {
368         GstDVBVideoSink *self = GST_DVBVIDEOSINK (sink);
369         GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
370
371         switch (GST_EVENT_TYPE (event)) {
372         case GST_EVENT_FLUSH_START:
373                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
374                 self->must_send_header = TRUE;
375                 break;
376         case GST_EVENT_FLUSH_STOP:
377                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
378                 self->must_send_header = TRUE;
379                 while (1)
380                 {
381                         gchar command;
382                         int res;
383
384                         READ_COMMAND (self, command, res);
385                         if (res < 0)
386                                 break;
387                 }
388         default:
389                 break;
390         }
391         return TRUE;
392 }
393
394 static GstFlowReturn
395 gst_dvbvideosink_render (GstBaseSink * sink, GstBuffer * buffer)
396 {
397         GstDVBVideoSink *self = GST_DVBVIDEOSINK (sink);
398         unsigned char *data = GST_BUFFER_DATA(buffer);
399         unsigned int data_len = GST_BUFFER_SIZE (buffer);
400         guint8 pes_header[2048];
401         unsigned int pes_header_len=0;
402         unsigned int payload_len=0;
403         fd_set readfds;
404         fd_set writefds;
405         gint retval;
406 //      int i=0;
407
408 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
409         gboolean commit_prev_frame_data = FALSE,
410                         cache_prev_frame = FALSE;
411 #endif
412
413 //      for (;i < (data_len > 0xF ? 0xF : data_len); ++i)
414 //              printf("%02x ", data[i]);
415 //      printf("%d bytes\n", data_len);
416
417 //      printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
418
419         FD_ZERO (&readfds);
420         FD_SET (READ_SOCKET (self), &readfds);
421
422         FD_ZERO (&writefds);
423         FD_SET (self->fd, &writefds);
424         
425         do {
426                 GST_DEBUG_OBJECT (self, "going into select, have %d bytes to write",
427                                 data_len);
428                 retval = select (FD_SETSIZE, &readfds, &writefds, NULL, NULL);
429         } while ((retval == -1 && errno == EINTR));
430
431         if (retval == -1)
432                 goto select_error;
433
434         if (FD_ISSET (READ_SOCKET (self), &readfds)) {
435                 /* read all stop commands */
436                 while (TRUE) {
437                         gchar command;
438                         int res;
439
440                         READ_COMMAND (self, command, res);
441                         if (res < 0) {
442                                 GST_LOG_OBJECT (self, "no more commands");
443                                 /* no more commands */
444                                 break;
445                         }
446                 }
447                 goto stopped;
448         }
449
450         if (self->fd < 0)
451                 return GST_FLOW_OK;
452
453 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
454         if (self->must_pack_bitstream == 1) {
455                 cache_prev_frame = TRUE;
456                 unsigned int pos = 0;
457                 while(pos < data_len) {
458                         if (data[pos++])
459                                 continue;
460                         if (data[pos++])
461                                 continue;
462                         if (data[pos++] != 1)
463                                 continue;
464                         if ((data[pos++] & 0xF0) == 0x20) { // we need time_inc_res
465                                 gboolean low_delay=FALSE;
466                                 unsigned int ver_id = 1, shape=0, time_inc_res=0, tmp=0;
467                                 struct bitstream bit;
468                                 bitstream_init(&bit, data+pos, 0);
469                                 bitstream_get(&bit, 9);
470                                 if (bitstream_get(&bit, 1)) {
471                                         ver_id = bitstream_get(&bit, 4); // ver_id
472                                         bitstream_get(&bit, 3);
473                                 }
474                                 if ((tmp=bitstream_get(&bit, 4)) == 15) { // Custom Aspect Ration
475                                         bitstream_get(&bit, 8); // skip AR width
476                                         bitstream_get(&bit, 8); // skip AR height
477                                 }
478                                 if (bitstream_get(&bit, 1)) {
479                                         bitstream_get(&bit, 2);
480                                         low_delay = bitstream_get(&bit, 1) ? TRUE : FALSE;
481                                         if (bitstream_get(&bit, 1)) {
482                                                 bitstream_get(&bit, 32);
483                                                 bitstream_get(&bit, 32);
484                                                 bitstream_get(&bit, 15);
485                                         }
486                                 }
487                                 shape = bitstream_get(&bit, 2);
488                                 if (ver_id != 1 && shape == 3 /* Grayscale */)
489                                         bitstream_get(&bit, 4);
490                                 bitstream_get(&bit, 1);
491                                 time_inc_res = bitstream_get(&bit, 16);
492                                 self->time_inc_bits = 0;
493                                 while (time_inc_res) { // count bits
494                                         ++self->time_inc_bits;
495                                         time_inc_res >>= 1;
496                                 }
497 //                              printf("%d time_inc_bits\n", self->time_inc_bits);
498                         }
499                 }
500         }
501
502         if (self->must_pack_bitstream == 1) {
503                 unsigned int pos = 0;
504                 while(pos < data_len) {
505                         if (data[pos++])
506                                 continue;
507                         if (data[pos++])
508                                 continue;
509                         if (data[pos++] != 1)
510                                 continue;
511                         if (data[pos++] != 0xB2)
512                                 continue;
513                         if (data_len - pos < 13)
514                                 break;
515                         if (!strcmp((char*)data+pos, "DivX503b1393p"))
516                                 self->must_pack_bitstream = 0;
517 //                      if (self->must_pack_bitstream)
518 //                              printf("pack needed\n");
519 //                      else
520 //                              printf("no pack needed\n");
521                 }
522         }
523 #endif
524
525         pes_header[0] = 0;
526         pes_header[1] = 0;
527         pes_header[2] = 1;
528         pes_header[3] = 0xE0;
529
530                 /* do we have a timestamp? */
531         if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE) {
532                 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
533                 unsigned long long dts = pts > 7508 ? pts - 7508 : pts; /* what to use as DTS-PTS offset? */
534
535                 pes_header[6] = 0x80;
536                 pes_header[7] = 0xC0;
537                 
538                 pes_header[8] = 10;
539                 
540                 pes_header[9] = 0x31 | ((pts >> 29) & 0xE);
541                 pes_header[10] = pts >> 22;
542                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
543                 pes_header[12] = pts >> 7;
544                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
545
546                 pes_header[14] = 0x11 | ((dts >> 29) & 0xE);
547                 pes_header[15] = dts >> 22;
548                 pes_header[16] = 0x01 | ((dts >> 14) & 0xFE);
549                 pes_header[17] = dts >> 7;
550                 pes_header[18] = 0x01 | ((dts << 1) & 0xFE);
551
552                 pes_header_len = 19;
553
554                 if (self->divx311_header) {  // DIVX311 stuff
555                         if (self->must_send_header) {
556                                 write(self->fd, self->divx311_header, 63);
557                                 self->must_send_header = FALSE;
558                         }
559                         pes_header[19] = 0;
560                         pes_header[20] = 0;
561                         pes_header[21] = 1;
562                         pes_header[22] = 0xb6;
563                         pes_header_len += 4;
564                 }
565                 else if (self->codec_data) {  // MKV stuff
566                         unsigned int pos = 0;
567                         while(TRUE) {
568                                 unsigned int pack_len = (data[pos] << 24) | (data[pos+1] << 16) | (data[pos+2] << 8) | data[pos+3];
569 //                              printf("patch %02x %02x %02x %02x\n",
570 //                                      data[pos],
571 //                                      data[pos + 1],
572 //                                      data[pos + 2],
573 //                                      data[pos + 3]);
574                                 memcpy(data+pos, "\x00\x00\x00\x01", 4);
575 //                              printf("pos %d, (%d) >= %d\n", pos, pos+pack_len, data_len);
576                                 pos += 4;
577                                 if ((pos + pack_len) >= data_len)
578                                         break;
579                                 pos += pack_len;
580                         }
581                         if (self->must_send_header) {
582                                 unsigned char *codec_data = GST_BUFFER_DATA (self->codec_data);
583                                 unsigned int codec_data_len = GST_BUFFER_SIZE (self->codec_data);
584                                 unsigned int pos=0;
585 //                              printf("1\n");
586                                 if (codec_data_len > 7) {
587                                         unsigned short len = (codec_data[6] << 8) | codec_data[7];
588 //                                      printf("2 %d bytes\n", len);
589                                         if (codec_data_len >= (len + 8)) {
590 //                                              printf("3\n");
591                                                 memcpy(pes_header+pes_header_len, "\x00\x00\x00\x01", 4);
592                                                 pes_header_len += 4;
593                                                 memcpy(pes_header+pes_header_len, codec_data+8, len);
594                                                 if (!memcmp(pes_header+pes_header_len, "\x67\x64\x00", 3)) {
595                                                         pes_header[pes_header_len+3] = 0x29; // hardcode h264 level 4.1
596                                                         printf("h264 level patched!\n");
597                                                 }
598                                                 pes_header_len += len;
599                                                 pos = 8 + len;
600                                                 if (codec_data_len > (pos + 2)) {
601                                                         len = (codec_data[pos+1] << 8) | codec_data[pos+2];
602 //                                                      printf("4 %d bytes\n", len);
603                                                         pos += 3;
604                                                         if (codec_data_len >= (pos+len)) {
605                                                                 printf("codec data ok!\n");
606                                                                 memcpy(pes_header+pes_header_len, "\x00\x00\x00\x01", 4);
607                                                                 pes_header_len += 4;
608                                                                 memcpy(pes_header+pes_header_len, codec_data+pos, len);
609                                                                 pes_header_len += len;
610                                                         }
611                                                         else
612                                                                 printf("codec_data to short(4)\n");
613                                                 }
614                                                 else
615                                                         printf("codec_data to short(3)!\n");
616                                         }
617                                         else
618                                                 printf("codec_data to short(2)!\n");
619                                 }
620                                 else
621                                         printf("codec_data to short(1)!\n");
622                                 self->must_send_header = FALSE;
623                         }
624                 }
625         }
626         else {
627 //              printf("no timestamp!\n");
628                 pes_header[6] = 0x80;
629                 pes_header[7] = 0x00;
630                 pes_header[8] = 0;
631                 pes_header_len = 9;
632         }
633
634 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
635         if (self->must_pack_bitstream == 1) {
636                 unsigned int pos = 0;
637                 gboolean i_frame = FALSE;
638 //              gboolean s_frame = FALSE;
639                 while(pos < data_len) {
640                         if (data[pos++])
641                                 continue;
642                         if (data[pos++])
643                                 continue;
644                         if (data[pos++] != 1)
645                                 continue;
646                         if (data[pos++] != 0xB6)
647                                 continue;
648                         switch ((data[pos] & 0xC0) >> 6) {
649                                 case 0: // I-Frame
650 //                                      printf("I ");
651                                         cache_prev_frame = FALSE;
652                                         i_frame = TRUE;
653                                 case 1: // P-Frame
654 //                                      printf("P ");
655                                         if (self->prev_frame != buffer) {
656                                                 struct bitstream bit;
657                                                 gboolean store_frame=FALSE;
658 //                                              if (!i_frame)
659 //                                                      printf("P ");
660                                                 if (self->prev_frame) {
661                                                         if (!self->num_non_keyframes) {
662 //                                                              printf("no non keyframes...immediate commit prev frame\n");
663                                                                 GstFlowReturn ret = gst_dvbvideosink_render(sink, self->prev_frame);
664                                                                 gst_buffer_unref(self->prev_frame);
665                                                                 self->prev_frame = NULL;
666                                                                 if (ret != GST_FLOW_OK)
667                                                                         return ret;
668                                                                 store_frame = TRUE;
669                                                         }
670                                                         else {
671                                                                 struct bitstream bit;
672 //                                                              int i=-4;
673                                                                 pes_header[pes_header_len++] = 0;
674                                                                 pes_header[pes_header_len++] = 0;
675                                                                 pes_header[pes_header_len++] = 1;
676                                                                 pes_header[pes_header_len++] = 0xB6;
677                                                                 bitstream_init(&bit, pes_header+pes_header_len, 1);
678                                                                 bitstream_put(&bit, 1, 2);
679                                                                 bitstream_put(&bit, 0, 1);
680                                                                 bitstream_put(&bit, 1, 1);
681                                                                 bitstream_put(&bit, self->time_inc, self->time_inc_bits);
682                                                                 bitstream_put(&bit, 1, 1);
683                                                                 bitstream_put(&bit, 0, 1);
684                                                                 bitstream_put(&bit, 0x7F >> bit.avail, 8 - bit.avail);
685 //                                                              printf(" insert pack frame %d non keyframes, time_inc %d, time_inc_bits %d -",
686 //                                                                      self->num_non_keyframes, self->time_inc, self->time_inc_bits);
687 //                                                              for (; i < (bit.data - (pes_header+pes_header_len)); ++i)
688 //                                                                      printf(" %02x", pes_header[pes_header_len+i];
689 //                                                              printf("\nset data_len to 0!\n");
690                                                                 data_len = 0;
691                                                                 pes_header_len += bit.data - (pes_header+pes_header_len);
692                                                                 cache_prev_frame = TRUE;
693                                                         }
694                                                 }
695                                                 else if (!i_frame)
696                                                         store_frame = TRUE;
697
698                                                 self->num_non_keyframes=0;
699
700                                                 // extract time_inc
701                                                 bitstream_init(&bit, data+pos, 0);
702                                                 bitstream_get(&bit, 2); // skip coding_type
703                                                 while(bitstream_get(&bit, 1));
704                                                 bitstream_get(&bit, 1);
705                                                 self->time_inc = bitstream_get(&bit, self->time_inc_bits);
706 //                                              printf("\ntime_inc is %d\n", self->time_inc);
707
708                                                 if (store_frame) {
709 //                                                      printf("store frame"\n");
710                                                         self->prev_frame = buffer;
711                                                         gst_buffer_ref (buffer);
712                                                         return GST_FLOW_OK;
713                                                 }
714                                         }
715                                         else {
716                                                 cache_prev_frame = FALSE;
717 //                                              printf(" I/P Frame without non key frame(s)!!\n");
718                                         }
719                                         break;
720                                 case 3: // S-Frame
721 //                                      printf("S ");
722 //                                      s_frame = TRUE;
723                                 case 2: // B-Frame
724 //                                      if (!s_frame)
725 //                                              printf("B ");
726                                         if (++self->num_non_keyframes == 1 && self->prev_frame) {
727 //                                              printf("send grouped with prev P!\n");
728                                                 commit_prev_frame_data = TRUE;
729                                         }
730                                         break;
731                                 case 4: // N-Frame
732                                 default:
733                                         printf("unhandled divx5/xvid frame type %d\n", (data[pos] & 0xC0) >> 6);
734                                         break;
735                         }
736                 }
737 //              printf("\n");
738         }
739 #endif
740
741         payload_len = data_len + pes_header_len - 6;
742
743 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
744         if (self->prev_frame && self->prev_frame != buffer) {
745                 unsigned long long pts = GST_BUFFER_TIMESTAMP(self->prev_frame) * 9LL / 100000 /* convert ns to 90kHz */;
746                 unsigned long long dts = pts > 7508 ? pts - 7508 : pts; /* what to use as DTS-PTS offset? */
747 //              printf("use prev timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(self->prev_frame));
748
749                 pes_header[9] = 0x31 | ((pts >> 29) & 0xE);
750                 pes_header[10] = pts >> 22;
751                 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
752                 pes_header[12] = pts >> 7;
753                 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
754
755                 pes_header[14] = 0x11 | ((dts >> 29) & 0xE);
756                 pes_header[15] = dts >> 22;
757                 pes_header[16] = 0x01 | ((dts >> 14) & 0xFE);
758                 pes_header[17] = dts >> 7;
759                 pes_header[18] = 0x01 | ((dts << 1) & 0xFE);
760         }
761
762         if (commit_prev_frame_data)
763                 payload_len += GST_BUFFER_SIZE (self->prev_frame);
764
765         if (payload_len <= 0xFFFF) {
766                 pes_header[4] = payload_len >> 8;
767                 pes_header[5] = payload_len & 0xFF;
768         }
769         else {
770                 pes_header[4] = 0;
771                 pes_header[5] = 0;
772         }
773 #endif
774
775         write(self->fd, pes_header, pes_header_len);
776
777 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
778         if (commit_prev_frame_data) {
779 //              printf("commit prev frame data\n");
780                 write(self->fd, GST_BUFFER_DATA (self->prev_frame), GST_BUFFER_SIZE (self->prev_frame));
781         }
782
783         if (self->prev_frame && self->prev_frame != buffer) {
784 //              printf("unref prev_frame buffer\n");
785                 gst_buffer_unref(self->prev_frame);
786                 self->prev_frame = NULL;
787         }
788
789         if (cache_prev_frame) {
790 //              printf("cache prev frame\n");
791                 gst_buffer_ref(buffer);
792                 self->prev_frame = buffer;
793         }
794 #endif
795
796         write(self->fd, data, data_len);
797
798         return GST_FLOW_OK;
799 select_error:
800         {
801                 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
802                                 ("select on file descriptor: %s.", g_strerror (errno)));
803                 GST_DEBUG_OBJECT (self, "Error during select");
804                 return GST_FLOW_ERROR;
805         }
806 stopped:
807         {
808                 GST_DEBUG_OBJECT (self, "Select stopped");
809                 ioctl(self->fd, VIDEO_CLEAR_BUFFER);
810                 return GST_FLOW_WRONG_STATE;
811         }
812 }
813
814 static gboolean 
815 gst_dvbvideosink_set_caps (GstPad * pad, GstCaps * vscaps)
816 {
817         GstStructure *structure = gst_caps_get_structure (vscaps, 0);
818         const gchar *mimetype = gst_structure_get_name (structure);
819         GstDVBVideoSink *self = GST_DVBVIDEOSINK (GST_PAD_PARENT (pad));
820         int streamtype = -1;
821
822         if (!strcmp (mimetype, "video/mpeg")) {
823                 gint mpegversion;
824                 gst_structure_get_int (structure, "mpegversion", &mpegversion);
825                 switch (mpegversion) {
826                         case 1:
827                                 streamtype = 6;
828                                 printf("MIMETYPE video/mpeg1 -> VIDEO_SET_STREAMTYPE, 6\n");
829                         break;
830                         case 2:
831                                 streamtype = 0;
832                                 printf("MIMETYPE video/mpeg2 -> VIDEO_SET_STREAMTYPE, 0\n");
833                         break;
834                         case 4:
835                                 streamtype = 4;
836                                 printf("MIMETYPE video/mpeg4 -> VIDEO_SET_STREAMTYPE, 4\n");
837                         break;
838                         default:
839                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
840                         break;
841                 }
842         } else if (!strcmp (mimetype, "video/x-h264")) {
843                 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
844                 streamtype = 1;
845                 if (codec_data) {
846                         printf("H264 have codec data.. force mkv!\n");
847                         self->codec_data = gst_value_get_buffer (codec_data);
848                         gst_buffer_ref (self->codec_data);
849                 }
850                 self->must_send_header = TRUE;
851                 printf("MIMETYPE video/x-h264 VIDEO_SET_STREAMTYPE, 1\n");
852         } else if (!strcmp (mimetype, "video/x-h263")) {
853                 streamtype = 2;
854                 printf("MIMETYPE video/x-h263 VIDEO_SET_STREAMTYPE, 2\n");
855         } else if (!strcmp (mimetype, "video/x-xvid")) {
856                 streamtype = 10;
857 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
858                 self->must_pack_bitstream = 1;
859 #endif
860                 printf("MIMETYPE video/x-xvid -> VIDEO_SET_STREAMTYPE, 10\n");
861         } else if (!strcmp (mimetype, "video/x-divx")) {
862                 gint divxversion;
863                 gst_structure_get_int (structure, "divxversion", &divxversion);
864                 switch (divxversion) {
865                         case 3:
866                         {
867                                 #define B_GET_BITS(w,e,b)  (((w)>>(b))&(((unsigned)(-1))>>((sizeof(unsigned))*8-(e+1-b))))
868                                 #define B_SET_BITS(name,v,e,b)  (((unsigned)(v))<<(b))
869                                 static const guint8 brcm_divx311_sequence_header[] = {
870                                         0x00, 0x00, 0x01, 0xE0, 0x00, 0x39, 0x80, 0xC0, // PES HEADER
871                                         0x0A, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, // ..
872                                         0xFF, 0xFF, 0xFF, // ..
873                                         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, /* 0 .. 7 */
874                                         0x08, 0xC8, 0x0D, 0x40, 0x00, 0x53, 0x88, 0x40, /* 8 .. 15 */
875                                         0x0C, 0x40, 0x01, 0x90, 0x00, 0x97, 0x53, 0x0A, /* 16 .. 24 */
876                                         0x00, 0x00, 0x00, 0x00,
877                                         0x30, 0x7F, 0x00, 0x00, 0x01, 0xB2, 0x44, 0x69, /* 0 .. 7 */
878                                         0x76, 0x58, 0x33, 0x31, 0x31, 0x41, 0x4E, 0x44  /* 8 .. 15 */
879                                 };
880                                 guint8 *data = malloc(63);
881                                 gint height, width;
882                                 gst_structure_get_int (structure, "height", &height);
883                                 gst_structure_get_int (structure, "width", &width);
884                                 memcpy(data, brcm_divx311_sequence_header, 63);
885                                 self->divx311_header = data;
886                                 data += 43;
887                                 data[0] = B_GET_BITS(width,11,4);
888                                 data[1] = B_SET_BITS("width [3..0]", B_GET_BITS(width,3,0), 7, 4) |
889                                         B_SET_BITS("'10'", 0x02, 3, 2) |
890                                         B_SET_BITS("height [11..10]", B_GET_BITS(height,11,10), 1, 0);
891                                 data[2] = B_GET_BITS(height,9,2);
892                                 data[3]= B_SET_BITS("height [1.0]", B_GET_BITS(height,1,0), 7, 6) |
893                                         B_SET_BITS("'100000'", 0x20, 5, 0);
894                                 streamtype = 13;
895                                 self->must_send_header = TRUE;
896                                 printf("MIMETYPE video/x-divx vers. 3 -> VIDEO_SET_STREAMTYPE, 13\n");
897                         }
898                         break;
899                         case 4:
900                                 streamtype = 14;
901                                 printf("MIMETYPE video/x-divx vers. 4 -> VIDEO_SET_STREAMTYPE, 14\n");
902                         break;
903                         case 5:
904                                 streamtype = 15;
905 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
906                                 self->must_pack_bitstream = 1;
907 #endif
908                                 printf("MIMETYPE video/x-divx vers. 5 -> VIDEO_SET_STREAMTYPE, 15\n");
909                         break;
910                         default:
911                                 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled divx version %i", divxversion));
912                         break;
913                 }
914         }
915         if (streamtype != -1) {
916                 if (ioctl(self->fd, VIDEO_SET_STREAMTYPE, streamtype) < 0)
917                         GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL), ("hardware decoder can't handle streamtype %i", streamtype));
918         } else
919                 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", mimetype));
920
921         return TRUE;
922 }
923
924 static gboolean
925 gst_dvbvideosink_start (GstBaseSink * basesink)
926 {
927         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
928         self->fd = open("/dev/dvb/adapter0/video0", O_RDWR);
929 //      self->fd = open("/dump.pes", O_RDWR|O_CREAT, 0555);
930
931         gint control_sock[2];
932
933         if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
934                 goto socket_pair;
935
936         READ_SOCKET (self) = control_sock[0];
937         WRITE_SOCKET (self) = control_sock[1];
938
939         fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
940         fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
941
942         if (self->fd >= 0)
943         {
944                 ioctl(self->fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
945                 ioctl(self->fd, VIDEO_PLAY);
946         }
947
948         return TRUE;
949         /* ERRORS */
950 socket_pair:
951         {
952                 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
953                                 GST_ERROR_SYSTEM);
954                 return FALSE;
955         }
956 }
957
958 static gboolean
959 gst_dvbvideosink_stop (GstBaseSink * basesink)
960 {
961         GstDVBVideoSink *self = GST_DVBVIDEOSINK (basesink);
962         if (self->fd >= 0)
963         {
964                 ioctl(self->fd, VIDEO_STOP);
965                 ioctl(self->fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
966                 close(self->fd);
967         }
968
969         close (READ_SOCKET (self));
970         close (WRITE_SOCKET (self));
971
972         if (self->divx311_header)
973                 free(self->divx311_header);
974
975         if (self->codec_data)
976                 gst_buffer_unref(self->codec_data);
977
978 #ifdef PACK_UNPACKED_XVID_DIVX5_BITSTREAM
979         if (self->prev_frame)
980                 gst_buffer_unref(self->prev_frame);
981 #endif
982
983         return TRUE;
984 }
985
986 /* entry point to initialize the plug-in
987  * initialize the plug-in itself
988  * register the element factories and pad templates
989  * register the features
990  *
991  * exchange the string 'plugin' with your elemnt name
992  */
993 static gboolean
994 plugin_init (GstPlugin *plugin)
995 {
996         return gst_element_register (plugin, "dvbvideosink",
997                                                  GST_RANK_NONE,
998                                                  GST_TYPE_DVBVIDEOSINK);
999 }
1000
1001 /* this is the structure that gstreamer looks for to register plugins
1002  *
1003  * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
1004  * description
1005  */
1006 GST_PLUGIN_DEFINE (
1007         GST_VERSION_MAJOR,
1008         GST_VERSION_MINOR,
1009         "dvb_video_out",
1010         "DVB Video Output",
1011         plugin_init,
1012         VERSION,
1013         "LGPL",
1014         "GStreamer",
1015         "http://gstreamer.net/"
1016 )