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