tsmux: Add support for Opus

https://bugzilla.gnome.org/show_bug.cgi?id=757049
This commit is contained in:
Sebastian Dröge 2015-10-25 17:27:39 +02:00
parent 1e785a3778
commit e75a9edff1
6 changed files with 338 additions and 2 deletions

View file

@ -5,7 +5,8 @@ SUBDIRS = tsmux
libgstmpegtsmux_la_SOURCES = \ libgstmpegtsmux_la_SOURCES = \
mpegtsmux.c \ mpegtsmux.c \
mpegtsmux_aac.c \ mpegtsmux_aac.c \
mpegtsmux_ttxt.c mpegtsmux_ttxt.c \
mpegtsmux_opus.c
libgstmpegtsmux_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ libgstmpegtsmux_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
@ -18,4 +19,5 @@ libgstmpegtsmux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = \ noinst_HEADERS = \
mpegtsmux.h \ mpegtsmux.h \
mpegtsmux_aac.h \ mpegtsmux_aac.h \
mpegtsmux_ttxt.h mpegtsmux_ttxt.h \
mpegtsmux_opus.h

View file

@ -96,6 +96,7 @@
#include "mpegtsmux_aac.h" #include "mpegtsmux_aac.h"
#include "mpegtsmux_ttxt.h" #include "mpegtsmux_ttxt.h"
#include "mpegtsmux_opus.h"
GST_DEBUG_CATEGORY (mpegtsmux_debug); GST_DEBUG_CATEGORY (mpegtsmux_debug);
#define GST_CAT_DEFAULT mpegtsmux_debug #define GST_CAT_DEFAULT mpegtsmux_debug
@ -142,6 +143,7 @@ static GstStaticPadTemplate mpegtsmux_sink_factory =
"mute = (boolean) { FALSE, TRUE }; " "mute = (boolean) { FALSE, TRUE }; "
"audio/x-ac3, framed = (boolean) TRUE;" "audio/x-ac3, framed = (boolean) TRUE;"
"audio/x-dts, framed = (boolean) TRUE;" "audio/x-dts, framed = (boolean) TRUE;"
"audio/x-opus;"
"subpicture/x-dvb; application/x-teletext; meta/x-klv, parsed=true")); "subpicture/x-dvb; application/x-teletext; meta/x-klv, parsed=true"));
static GstStaticPadTemplate mpegtsmux_src_factory = static GstStaticPadTemplate mpegtsmux_src_factory =
@ -580,6 +582,7 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
const gchar *mt; const gchar *mt;
const GValue *value = NULL; const GValue *value = NULL;
GstBuffer *codec_data = NULL; GstBuffer *codec_data = NULL;
guint8 opus_channel_config_code = 0;
pad = ts_data->collect.pad; pad = ts_data->collect.pad;
caps = gst_pad_get_current_caps (pad); caps = gst_pad_get_current_caps (pad);
@ -667,6 +670,93 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
st = TSMUX_ST_PS_TELETEXT; st = TSMUX_ST_PS_TELETEXT;
/* needs a particularly sized layout */ /* needs a particularly sized layout */
ts_data->prepare_func = mpegtsmux_prepare_teletext; ts_data->prepare_func = mpegtsmux_prepare_teletext;
} else if (strcmp (mt, "audio/x-opus") == 0) {
GstBuffer *streamheader = NULL;
const GValue *v;
GstMapInfo map;
v = gst_structure_get_value (s, "streamheader");
if (v && G_VALUE_HOLDS (v, GST_TYPE_ARRAY)
&& gst_value_array_get_size (v) >= 1) {
const GValue *h = gst_value_array_get_value (v, 0);
streamheader = gst_value_get_buffer (h);
}
/* FIXME: We need to either map all values for the OpusHead header
* to caps, or always require/generate an OpusHead streamheader for the
* caps. E.g. in rtpopusdepay */
if (!streamheader || gst_buffer_get_size (streamheader) < 22) {
gint channels;
if (gst_structure_get_int (s, "channels", &channels) && channels <= 2) {
opus_channel_config_code = channels;
} else {
GST_FIXME_OBJECT (pad,
"Multichannel Opus without streamheader not handled");
goto not_negotiated;
}
}
gst_buffer_map (streamheader, &map, GST_MAP_READ);
if (map.data[9] == 2 && map.data[18] == 255 && map.data[19] == 1
&& map.data[20] == 1) {
/* Dual mono */
opus_channel_config_code = 0;
} else if (map.data[9] >= 1 && map.data[9] <= 2 && map.data[18] == 0) {
/* RTP mapping */
opus_channel_config_code = map.data[9];
} else if (map.data[9] >= 2 && map.data[9] <= 8 && map.data[18] == 1
&& map.size >= 21 + map.data[9]) {
static const guint8 coupled_stream_counts[9] = {
1, 0, 1, 1, 2, 2, 2, 3, 3
};
static const guint8 channel_map_a[8][8] = {
{0},
{0, 1},
{0, 2, 1},
{0, 1, 2, 3},
{0, 4, 1, 2, 3},
{0, 4, 1, 2, 3, 5},
{0, 4, 1, 2, 3, 5, 6},
{0, 6, 1, 2, 3, 4, 5, 7},
};
static const guint8 channel_map_b[8][8] = {
{0},
{0, 1},
{0, 1, 2},
{0, 1, 2, 3},
{0, 1, 2, 3, 4},
{0, 1, 2, 3, 4, 5},
{0, 1, 2, 3, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 6, 7},
};
/* Vorbis mapping */
if (map.data[19] == map.data[9] - coupled_stream_counts[map.data[9]] &&
map.data[20] == coupled_stream_counts[map.data[9]] &&
memcmp (&map.data[21], channel_map_a[map.data[9] - 1],
map.data[9]) == 0) {
opus_channel_config_code = map.data[9];
} else if (map.data[19] == map.data[9] &&
map.data[20] == 0 &&
memcmp (&map.data[21], channel_map_b[map.data[9] - 1],
map.data[9]) == 0) {
opus_channel_config_code = map.data[9] | 0x80;
} else {
gst_buffer_unmap (streamheader, &map);
GST_FIXME_OBJECT (pad, "Opus channel mapping not handled");
goto not_negotiated;
}
} else {
gst_buffer_unmap (streamheader, &map);
GST_FIXME_OBJECT (pad, "Opus channel mapping not handled");
goto not_negotiated;
}
gst_buffer_unmap (streamheader, &map);
st = TSMUX_ST_PS_OPUS;
ts_data->prepare_func = mpegtsmux_prepare_opus;
} else if (strcmp (mt, "meta/x-klv") == 0) { } else if (strcmp (mt, "meta/x-klv") == 0) {
st = TSMUX_ST_PS_KLV; st = TSMUX_ST_PS_KLV;
} }
@ -683,6 +773,8 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
gst_structure_get_int (s, "channels", &ts_data->stream->audio_channels); gst_structure_get_int (s, "channels", &ts_data->stream->audio_channels);
gst_structure_get_int (s, "bitrate", &ts_data->stream->audio_bitrate); gst_structure_get_int (s, "bitrate", &ts_data->stream->audio_bitrate);
ts_data->stream->opus_channel_config_code = opus_channel_config_code;
tsmux_stream_set_buffer_release_func (ts_data->stream, release_buffer_cb); tsmux_stream_set_buffer_release_func (ts_data->stream, release_buffer_cb);
tsmux_program_add_stream (ts_data->prog, ts_data->stream); tsmux_program_add_stream (ts_data->prog, ts_data->stream);

View file

@ -0,0 +1,128 @@
/*
* Copyright 2006, 2007, 2008 Fluendo S.A.
* Authors: Jan Schmidt <jan@fluendo.com>
* Kapil Agrawal <kapil@fluendo.com>
* Julien Moutte <julien@fluendo.com>
*
* This library is licensed under 4 different licenses and you
* can choose to use it under the terms of any one of them. The
* four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
* license.
*
* MPL:
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* LGPL:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* GPL:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* MIT:
*
* Unless otherwise indicated, Source Code is licensed under MIT license.
* See further explanation attached in License Statement (distributed in the file
* LICENSE).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mpegtsmux_opus.h"
#include <string.h>
#define GST_CAT_DEFAULT mpegtsmux_debug
GstBuffer *
mpegtsmux_prepare_opus (GstBuffer * buf, MpegTsPadData * pad_data,
MpegTsMux * mux)
{
gssize insize = gst_buffer_get_size (buf);
gsize outsize;
GstBuffer *outbuf;
GstMapInfo map;
guint n;
/* TODO: Write start/end trim */
outsize = 2 + insize / 255 + 1;
outbuf = gst_buffer_new_and_alloc (outsize);
gst_buffer_copy_into (outbuf, buf,
GST_BUFFER_COPY_METADATA | GST_BUFFER_COPY_TIMESTAMPS, 0, 0);
gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
map.data[0] = 0x7f;
map.data[1] = 0xe0;
n = 2;
do {
g_assert (n < outsize);
/* FIXME: this should be using insize for writing here but ffmpeg and the
* only available sample stream from obe.tv are not including the control
* header size in au_size
*/
map.data[n] = MIN (insize, 255);
insize -= 255;
n++;
} while (insize >= 0);
gst_buffer_unmap (outbuf, &map);
outbuf = gst_buffer_append (outbuf, gst_buffer_ref (buf));
return outbuf;
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2006, 2007, 2008 Fluendo S.A.
* Authors: Jan Schmidt <jan@fluendo.com>
* Kapil Agrawal <kapil@fluendo.com>
* Julien Moutte <julien@fluendo.com>
*
* This library is licensed under 4 different licenses and you
* can choose to use it under the terms of any one of them. The
* four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
* license.
*
* MPL:
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* LGPL:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* GPL:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* MIT:
*
* Unless otherwise indicated, Source Code is licensed under MIT license.
* See further explanation attached in License Statement (distributed in the file
* LICENSE).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifndef __MPEGTSMUX_OPUS_H__
#define __MPEGTSMUX_OPUS_H__
#include "mpegtsmux.h"
GstBuffer * mpegtsmux_prepare_opus (GstBuffer * buf, MpegTsPadData * data,
MpegTsMux * mux);
#endif /* __MPEGTSMUX_OPUS_H__ */

View file

@ -200,6 +200,13 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type)
TSMUX_PACKET_FLAG_PES_FULL_HEADER | TSMUX_PACKET_FLAG_PES_FULL_HEADER |
TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT; TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT;
break; break;
case TSMUX_ST_PS_OPUS:
/* FIXME: assign sequential extended IDs? */
stream->id = 0xBD;
stream->stream_type = TSMUX_ST_PRIVATE_DATA;
stream->is_opus = TRUE;
stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
break;
default: default:
g_critical ("Stream type 0x%0x not yet implemented", stream_type); g_critical ("Stream type 0x%0x not yet implemented", stream_type);
break; break;
@ -910,6 +917,17 @@ tsmux_stream_get_es_descrs (TsMuxStream * stream,
g_ptr_array_add (pmt_stream->descriptors, descriptor); g_ptr_array_add (pmt_stream->descriptors, descriptor);
break; break;
} }
if (stream->is_opus) {
descriptor = gst_mpegts_descriptor_from_registration ("Opus", NULL, 0);
g_ptr_array_add (pmt_stream->descriptors, descriptor);
descriptor =
gst_mpegts_descriptor_from_custom_with_extension
(GST_MTS_DESC_DVB_EXTENSION, 0x80,
&stream->opus_channel_config_code, 1);
g_ptr_array_add (pmt_stream->descriptors, descriptor);
}
if (stream->is_meta) { if (stream->is_meta) {
descriptor = gst_mpegts_descriptor_from_registration ("KLVA", NULL, 0); descriptor = gst_mpegts_descriptor_from_registration ("KLVA", NULL, 0);
GST_ERROR ("adding KLVA registration descriptor!"); GST_ERROR ("adding KLVA registration descriptor!");

View file

@ -141,6 +141,7 @@ enum TsMuxStreamType {
TSMUX_ST_PS_DVB_SUBPICTURE = 0x8c, TSMUX_ST_PS_DVB_SUBPICTURE = 0x8c,
TSMUX_ST_PS_TELETEXT = 0x8d, TSMUX_ST_PS_TELETEXT = 0x8d,
TSMUX_ST_PS_KLV = 0x8e, /* only used internally */ TSMUX_ST_PS_KLV = 0x8e, /* only used internally */
TSMUX_ST_PS_OPUS = 0x8f, /* only used internally */
TSMUX_ST_PS_DVD_SUBPICTURE = 0xff, TSMUX_ST_PS_DVD_SUBPICTURE = 0xff,
/* Non-standard definitions */ /* Non-standard definitions */
@ -209,6 +210,10 @@ struct TsMuxStream {
gchar language[4]; gchar language[4];
gboolean is_meta; gboolean is_meta;
/* Opus */
gboolean is_opus;
guint8 opus_channel_config_code;
}; };
/* stream management */ /* stream management */