2 * GStreamer DVB Media Sink
3 * Copyright 2006 Felix Domke <tmbinc@elitedvb.net>
5 * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
6 * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
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
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.
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.
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.
48 * SECTION:element-plugin
51 * <title>Example launch line</title>
54 * gst-launch -v -m audiotestsrc ! plugin ! fakesink silent=TRUE
65 #include <sys/ioctl.h>
66 #include <sys/socket.h>
67 #include <linux/dvb/audio.h>
68 #include <linux/dvb/video.h>
74 /* We add a control socket as in fdsrc to make it shutdown quickly when it's blocking on the fd.
75 * Poll is used to determine when the fd is ready for use. When the element state is changed,
76 * it happens from another thread while fdsink is select'ing on the fd. The state-change thread
77 * sends a control message, so fdsink wakes up and changes state immediately otherwise
78 * it would stay blocked until it receives some data. */
80 /* the poll call is also performed on the control sockets, that way
81 * we can send special commands to unblock the select call */
82 #define CONTROL_STOP 'S' /* stop the select call */
83 #define CONTROL_SOCKETS(sink) sink->control_sock
84 #define WRITE_SOCKET(sink) sink->control_sock[1]
85 #define READ_SOCKET(sink) sink->control_sock[0]
87 #define SEND_COMMAND(sink, command) \
89 unsigned char c; c = command; \
90 write (WRITE_SOCKET(sink), &c, 1); \
93 #define READ_COMMAND(sink, command, res) \
95 res = read(READ_SOCKET(sink), &command, 1); \
98 #include "gstdvbaudiosink.h"
100 #ifndef AUDIO_GET_PTS
101 #define AUDIO_GET_PTS _IOR('o', 19, gint64)
104 GST_DEBUG_CATEGORY_STATIC (dvbaudiosink_debug);
105 #define GST_CAT_DEFAULT dvbaudiosink_debug
107 /* Filter signals and args */
118 static GstStaticPadTemplate sink_factory =
119 GST_STATIC_PAD_TEMPLATE (
123 GST_STATIC_CAPS ("audio/mpeg, "
124 "mpegversion = (int) { 1, 2, 4 }; "
125 "audio/x-private1-ac3; "
130 #define DEBUG_INIT(bla) \
131 GST_DEBUG_CATEGORY_INIT (dvbaudiosink_debug, "dvbaudiosink", 0, "dvbaudiosink element");
133 GST_BOILERPLATE_FULL (GstDVBAudioSink, gst_dvbaudiosink, GstBaseSink,
134 GST_TYPE_BASE_SINK, DEBUG_INIT);
136 static void gst_dvbaudiosink_set_property (GObject *object, guint prop_id,
139 static void gst_dvbaudiosink_get_property (GObject *object, guint prop_id,
143 static gboolean gst_dvbaudiosink_start (GstBaseSink * sink);
144 static gboolean gst_dvbaudiosink_stop (GstBaseSink * sink);
145 static gboolean gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event);
146 static GstFlowReturn gst_dvbaudiosink_render (GstBaseSink * sink,
148 static gboolean gst_dvbaudiosink_query (GstElement * element, GstQuery * query);
149 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink);
150 static gboolean gst_dvbaudiosink_unlock_stop (GstBaseSink * basesink);
151 static gboolean gst_dvbaudiosink_set_caps (GstBaseSink * sink, GstCaps * caps);
153 gboolean bypass_set = FALSE;
156 gst_dvbaudiosink_base_init (gpointer klass)
158 static GstElementDetails element_details = {
160 "Generic/DVBAudioSink",
161 "Outputs a MPEG2 PES / ES into a DVB audio device for hardware playback",
162 "Felix Domke <tmbinc@elitedvb.net>"
164 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
166 gst_element_class_add_pad_template (element_class,
167 gst_static_pad_template_get (&sink_factory));
168 gst_element_class_set_details (element_class, &element_details);
171 /* initialize the plugin's class */
173 gst_dvbaudiosink_class_init (GstDVBAudioSinkClass *klass)
175 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
176 GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
178 gobject_class->set_property = gst_dvbaudiosink_set_property;
179 gobject_class->get_property = gst_dvbaudiosink_get_property;
181 gobject_class = G_OBJECT_CLASS (klass);
182 g_object_class_install_property (gobject_class, ARG_SILENT,
183 g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
184 FALSE, G_PARAM_READWRITE));
186 gstbasesink_class->get_times = NULL;
187 gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_start);
188 gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_stop);
189 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_render);
190 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_event);
191 gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_unlock);
192 gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR ( gst_dvbaudiosink_unlock_stop);
193 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_dvbaudiosink_set_caps);
194 GST_ELEMENT_CLASS (klass)->query = GST_DEBUG_FUNCPTR(gst_dvbaudiosink_query);
197 /* initialize the new element
198 * instantiate pads and add them to element
200 * initialize structure
203 gst_dvbaudiosink_init (GstDVBAudioSink *klass,
204 GstDVBAudioSinkClass * gclass)
206 klass->silent = FALSE;
207 klass->aac_adts_header_valid = FALSE;
209 GST_BASE_SINK (klass)->sync = FALSE;
213 gst_dvbaudiosink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
215 GstDVBAudioSink *filter;
217 g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
218 filter = GST_DVBAUDIOSINK (object);
223 filter->silent = g_value_get_boolean (value);
226 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232 gst_dvbaudiosink_get_property (GObject *object, guint prop_id,
233 GValue *value, GParamSpec *pspec)
235 GstDVBAudioSink *filter;
237 g_return_if_fail (GST_IS_DVBAUDIOSINK (object));
238 filter = GST_DVBAUDIOSINK (object);
242 g_value_set_boolean (value, filter->silent);
245 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
251 gst_dvbaudiosink_query (GstElement * element, GstQuery * query)
253 GstDVBAudioSink *self = GST_DVBAUDIOSINK (element);
255 // printf("query %d %d\n", GST_QUERY_TYPE(query), GST_QUERY_POSITION);
257 switch (GST_QUERY_TYPE (query)) {
258 case GST_QUERY_POSITION:
261 static gint64 last_pos = 0;
264 gst_query_parse_position (query, &format, NULL);
266 if (format != GST_FORMAT_TIME)
269 ioctl(self->fd, AUDIO_GET_PTS, &cur);
270 // printf("gst_dvbaudiosink_query AUDIO_GET_PTS: %08llx\n", cur);
272 /* workaround until driver fixed */
280 gst_query_set_position (query, format, cur);
282 GST_DEBUG_OBJECT (self, "position format %d", format);
287 return GST_ELEMENT_CLASS (parent_class)->query (element, query);
291 static gboolean gst_dvbaudiosink_unlock (GstBaseSink * basesink)
293 GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
295 SEND_COMMAND (self, CONTROL_STOP);
300 static gboolean gst_dvbaudiosink_unlock_stop (GstBaseSink * sink)
302 GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
308 READ_COMMAND (self, command, res);
311 GST_LOG_OBJECT (self, "no more commands");
312 /* no more commands */
320 gst_dvbaudiosink_set_caps (GstBaseSink * basesink, GstCaps * caps)
322 GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
323 GstStructure *structure = gst_caps_get_structure (caps, 0);
324 const char *type = gst_structure_get_name (structure);
328 if (!strcmp(type, "audio/mpeg")) {
330 gst_structure_get_int (structure, "mpegversion", &mpegversion);
331 switch (mpegversion) {
335 gst_structure_get_int (structure, "layer", &layer);
340 printf("MIMETYPE %s version %d layer %d\n",type,mpegversion,layer);
346 const GValue *codec_data = gst_structure_get_value (structure, "codec_data");
347 printf("MIMETYPE %s version %d (AAC)\n", type, mpegversion);
349 guint8 *h = GST_BUFFER_DATA(gst_value_get_buffer (codec_data));
350 guint8 obj_type = ((h[0] & 0xC) >> 2) + 1;
351 guint8 rate_idx = ((h[0] & 0x3) << 1) | ((h[1] & 0x80) >> 7);
352 guint8 channels = (h[1] & 0x78) >> 3;
353 // printf("have codec data -> obj_type = %d, rate_idx = %d, channels = %d\n",
354 // obj_type, rate_idx, channels);
355 /* Sync point over a full byte */
356 self->aac_adts_header[0] = 0xFF;
357 /* Sync point continued over first 4 bits + static 4 bits
358 * (ID, layer, protection)*/
359 self->aac_adts_header[1] = 0xF1;
360 if (mpegversion == 2)
361 self->aac_adts_header[1] |= 8;
362 /* Object type over first 2 bits */
363 self->aac_adts_header[2] = obj_type << 6;
364 /* rate index over next 4 bits */
365 self->aac_adts_header[2] |= rate_idx << 2;
366 /* channels over last 2 bits */
367 self->aac_adts_header[2] |= (channels & 0x4) >> 2;
368 /* channels continued over next 2 bits + 4 bits at zero */
369 self->aac_adts_header[3] = (channels & 0x3) << 6;
370 self->aac_adts_header_valid = TRUE;
373 gint rate, channels, rate_idx=0, obj_type=1; // hardcoded yet.. hopefully this works every time ;)
374 gint AdtsSamplingRates[] = {
375 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
376 16000, 12000, 11025, 8000, 7350, 0
378 printf("no codec data!\n");
379 if (gst_structure_get_int (structure, "rate", &rate) && gst_structure_get_int (structure, "channels", &channels)) {
381 if (AdtsSamplingRates[rate_idx] == rate)
384 } while (AdtsSamplingRates[rate_idx]);
385 if (AdtsSamplingRates[rate_idx]) {
386 printf("mpegversion %d, channels %d, rate %d, rate_idx %d\n", mpegversion, channels, rate, rate_idx);
387 /* Sync point over a full byte */
388 self->aac_adts_header[0] = 0xFF;
389 /* Sync point continued over first 4 bits + static 4 bits
390 * (ID, layer, protection)*/
391 self->aac_adts_header[1] = 0xF1;
392 if (mpegversion == 2)
393 self->aac_adts_header[1] |= 8;
394 /* Object type over first 2 bits */
395 self->aac_adts_header[2] = obj_type << 6;
396 /* rate index over next 4 bits */
397 self->aac_adts_header[2] |= rate_idx << 2;
398 /* channels over last 2 bits */
399 self->aac_adts_header[2] |= (channels & 0x4) >> 2;
400 /* channels continued over next 2 bits + 4 bits at zero */
401 self->aac_adts_header[3] = (channels & 0x3) << 6;
402 self->aac_adts_header_valid = TRUE;
411 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("unhandled mpeg version %i", mpegversion));
415 else if (!strcmp(type, "audio/x-ac3") || !strcmp(type, "audio/ac3"))
417 printf("MIMETYPE %s\n",type);
420 else if (!strcmp(type, "audio/x-private1-dts"))
422 printf("MIMETYPE %s (DVD Audio - 2 byte skipping)\n",type);
426 else if (!strcmp(type, "audio/x-private1-ac3"))
428 printf("MIMETYPE %s (DVD Audio - 2 byte skipping)\n",type);
432 else if (!strcmp(type, "audio/x-dts") || !strcmp(type, "audio/dts"))
434 printf("MIMETYPE %s\n",type);
436 GST_ELEMENT_ERROR (self, STREAM, CODEC_NOT_FOUND, (NULL), ("DTS not yet handled by driver"));
440 GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), ("unimplemented stream type %s", type));
444 GST_DEBUG_OBJECT(self, "setting dvb mode 0x%02x\n", bypass);
446 if (ioctl(self->fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
448 GST_ELEMENT_WARNING (self, STREAM, DECODE, (NULL), ("hardware decoder can't be set to bypass mode %i.", bypass));
456 gst_dvbaudiosink_event (GstBaseSink * sink, GstEvent * event)
458 GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
459 GST_DEBUG_OBJECT (self, "EVENT %s", gst_event_type_get_name(GST_EVENT_TYPE (event)));
461 switch (GST_EVENT_TYPE (event)) {
462 case GST_EVENT_FLUSH_START:
463 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
465 case GST_EVENT_FLUSH_STOP:
466 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
470 struct pollfd pfd[2];
472 pfd[0].fd = READ_SOCKET(self);
473 pfd[0].events = POLLIN;
475 /* needs driver support */
476 pfd[1].fd = self->fd;
477 pfd[1].events = POLLHUP;
480 GST_DEBUG_OBJECT (self, "going into poll to wait for EOS");
481 retval = poll(pfd, 2, -1);
482 } while ((retval == -1 && errno == EINTR));
484 if (pfd[0].revents & POLLIN) /* flush */
486 GST_DEBUG_OBJECT (self, "EOS wait ended because of buffer empty. now waiting for PTS %llx", self->pts_eos);
488 long long lastdiff = 0;
490 unsigned long long cur;
491 ioctl(self->fd, AUDIO_GET_PTS, &cur);
493 long long diff = self->last_pts_eos - cur;
495 GST_DEBUG_OBJECT (self, "at %llx (diff %llx)", cur, diff);
497 if ( diff <= 0x1000 || lastdiff == diff )
501 retval = poll(pfd, 1, 1000);
502 /* check for flush */
503 if (pfd[0].revents & POLLIN)
509 case GST_EVENT_NEWSEGMENT:{
512 gdouble rate, applied_rate;
513 gint64 cur, stop, time;
514 int skip = 0, repeat = 0, ret;
515 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &fmt, &cur, &stop, &time);
516 // g_print("DVBAUDIOSINK GST_EVENT_NEWSEGMENT rate=%f applied_rate=%f\n", rate, applied_rate);
517 int video_fd = open("/dev/dvb/adapter0/video0", O_RDWR);
519 if (fmt == GST_FORMAT_TIME)
526 ret = ioctl(video_fd, VIDEO_SLOWMOTION, repeat);
527 ret = ioctl(video_fd, VIDEO_FAST_FORWARD, skip);
529 // gst_segment_set_newsegment_full (&dec->segment, update, rate, applied_rate, dformat, cur, stop, time);
543 gst_dvbaudiosink_render (GstBaseSink * sink, GstBuffer * buffer)
545 GstDVBAudioSink *self = GST_DVBAUDIOSINK (sink);
546 unsigned char pes_header[64];
547 int skip = self->skip;
548 unsigned int size = GST_BUFFER_SIZE (buffer) - skip;
549 unsigned char *data = GST_BUFFER_DATA (buffer) + skip;
551 size_t pes_header_size;
552 struct pollfd pfd[2];
555 // for (;i < (size > 0x1F ? 0x1F : size); ++i)
556 // printf("%02x ", data[i]);
557 // printf("%d bytes\n", size);
558 // printf("timestamp: %08llx\n", (long long)GST_BUFFER_TIMESTAMP(buffer));
562 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL), ("hardware decoder not setup (no caps in pipeline?)"));
563 return GST_FLOW_ERROR;
566 pfd[0].fd = READ_SOCKET(self);
567 pfd[0].events = POLLIN;
568 pfd[1].fd = self->fd;
569 pfd[1].events = POLLOUT;
572 GST_DEBUG_OBJECT (self, "going into poll, have %d bytes to write",
574 retval = poll(pfd, 2, -1);
575 } while ((retval == -1 && errno == EINTR));
580 if (pfd[0].revents & POLLIN) {
581 /* read all stop commands */
586 READ_COMMAND (self, command, res);
588 GST_LOG_OBJECT (self, "no more commands");
589 /* no more commands */
602 pes_header[3] = 0xC0;
604 if (self->aac_adts_header_valid)
607 /* do we have a timestamp? */
608 if (GST_BUFFER_TIMESTAMP(buffer) != GST_CLOCK_TIME_NONE)
610 unsigned long long pts = GST_BUFFER_TIMESTAMP(buffer) * 9LL / 100000 /* convert ns to 90kHz */;
612 self->last_pts_eos = self->pts_eos;
615 pes_header[4] = (size + 8) >> 8;
616 pes_header[5] = (size + 8) & 0xFF;
618 pes_header[6] = 0x80;
619 pes_header[7] = 0x80;
623 pes_header[9] = 0x21 | ((pts >> 29) & 0xE);
624 pes_header[10] = pts >> 22;
625 pes_header[11] = 0x01 | ((pts >> 14) & 0xFE);
626 pes_header[12] = pts >> 7;
627 pes_header[13] = 0x01 | ((pts << 1) & 0xFE);
628 pes_header_size = 14;
631 pes_header[4] = (size + 3) >> 8;
632 pes_header[5] = (size + 3) & 0xFF;
633 pes_header[6] = 0x80;
634 pes_header[7] = 0x00;
639 if (self->aac_adts_header_valid) {
640 self->aac_adts_header[3] &= 0xC0;
641 /* frame size over last 2 bits */
642 self->aac_adts_header[3] |= (size & 0x1800) >> 11;
643 /* frame size continued over full byte */
644 self->aac_adts_header[4] = (size & 0x1FF8) >> 3;
645 /* frame size continued first 3 bits */
646 self->aac_adts_header[5] = (size & 7) << 5;
647 /* buffer fullness (0x7FF for VBR) over 5 last bits */
648 self->aac_adts_header[5] |= 0x1F;
649 /* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for
650 * number of raw data blocks */
651 self->aac_adts_header[6] = 0xFC;
652 memcpy(pes_header + pes_header_size, self->aac_adts_header, 7);
653 pes_header_size += 7;
656 write(self->fd, pes_header, pes_header_size);
657 write(self->fd, data, GST_BUFFER_SIZE (buffer) - skip);
662 GST_ELEMENT_ERROR (self, RESOURCE, READ, (NULL),
663 ("poll on file descriptor: %s.", g_strerror (errno)));
664 GST_DEBUG_OBJECT (self, "Error during poll");
665 return GST_FLOW_ERROR;
669 GST_DEBUG_OBJECT (self, "Select stopped");
670 ioctl(self->fd, AUDIO_CLEAR_BUFFER);
671 return GST_FLOW_WRONG_STATE;
676 gst_dvbaudiosink_start (GstBaseSink * basesink)
678 GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
679 self->fd = open("/dev/dvb/adapter0/audio0", O_RDWR);
680 // self->fd = open("/dump.pes", O_RDWR|O_CREAT, 0555);
682 gint control_sock[2];
684 if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
687 READ_SOCKET (self) = control_sock[0];
688 WRITE_SOCKET (self) = control_sock[1];
690 fcntl (READ_SOCKET (self), F_SETFL, O_NONBLOCK);
691 fcntl (WRITE_SOCKET (self), F_SETFL, O_NONBLOCK);
695 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY);
696 ioctl(self->fd, AUDIO_PLAY);
697 // ioctl(self->fd, AUDIO_SET_BYPASS_MODE, 0);
703 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, (NULL),
710 gst_dvbaudiosink_stop (GstBaseSink * basesink)
712 GstDVBAudioSink *self = GST_DVBAUDIOSINK (basesink);
715 ioctl(self->fd, AUDIO_STOP);
716 ioctl(self->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX);
718 int video_fd = open("/dev/dvb/adapter0/video0", O_RDWR);
721 ioctl(video_fd, VIDEO_SLOWMOTION, 0);
722 ioctl(video_fd, VIDEO_FAST_FORWARD, 0);
731 /* entry point to initialize the plug-in
732 * initialize the plug-in itself
733 * register the element factories and pad templates
734 * register the features
736 * exchange the string 'plugin' with your elemnt name
739 plugin_init (GstPlugin *plugin)
741 return gst_element_register (plugin, "dvbaudiosink",
743 GST_TYPE_DVBAUDIOSINK);
746 /* this is the structure that gstreamer looks for to register plugins
748 * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
760 "http://gstreamer.net/"