mpegtsdemux: add MPEG TS demuxer rewrite from Edward Hervey

with contributions from Miquel Angel Farre Guiu and Zaheer Abbas Merali
This commit is contained in:
Janne Grunau 2011-02-16 17:57:42 +01:00 committed by Edward Hervey
parent 2bb835f69a
commit 22ecf13e42
16 changed files with 7644 additions and 0 deletions

View file

@ -320,6 +320,7 @@ AG_GST_CHECK_PLUGIN(legacyresample)
AG_GST_CHECK_PLUGIN(librfb)
AG_GST_CHECK_PLUGIN(liveadder)
AG_GST_CHECK_PLUGIN(mpegdemux)
AG_GST_CHECK_PLUGIN(mpegtsdemux)
AG_GST_CHECK_PLUGIN(mpegtsmux)
AG_GST_CHECK_PLUGIN(mpegpsmux)
AG_GST_CHECK_PLUGIN(mpeg4videoparse)
@ -1748,6 +1749,7 @@ gst/legacyresample/Makefile
gst/librfb/Makefile
gst/liveadder/Makefile
gst/mpegdemux/Makefile
gst/mpegtsdemux/Makefile
gst/mpegtsmux/Makefile
gst/mpegtsmux/tsmux/Makefile
gst/mpegpsmux/Makefile

View file

@ -103,6 +103,7 @@ rm -rf $RPM_BUILD_ROOT
%{_libdir}/gstreamer-%{majorminor}/libgstmpegtsmux.so
%{_libdir}/gstreamer-%{majorminor}/libgstscaletempoplugin.so
%{_libdir}/gstreamer-%{majorminor}/libgstmpegdemux.so
%{_libdir}/gstreamer-%{majorminor}/libgstmpegtsdemux.so
%{_libdir}/gstreamer-%{majorminor}/libgstjp2k.so
%{_libdir}/gstreamer-%{majorminor}/libgstapexsink.so
%{_libdir}/gstreamer-%{majorminor}/libgstqtmux.so

View file

@ -0,0 +1,27 @@
plugin_LTLIBRARIES = libgstmpegtsdemux.la
libgstmpegtsdemux_la_SOURCES = \
gsttsdemux.c \
gstmpegdesc.c \
mpegtsbase.c \
mpegtspacketizer.c \
mpegtsparse.c \
tsdemux.c
libgstmpegtsdemux_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstmpegtsdemux_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
$(GST_BASE_LIBS) $(GST_LIBS)
libgstmpegtsdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstmpegtsdemux_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = \
gstmpegdefs.h \
gstmpegdesc.h \
mpegtsbase.h \
mpegtspacketizer.h \
mpegtsparse.c \
tsdemux.h

117
gst/mpegtsdemux/TODO Normal file
View file

@ -0,0 +1,117 @@
mpegtsparse rebasing
--------------------
Rationale :
-----------
mpegtsparse code is more sane to handle and work with.
We need a modular demuxer
We need to avoid duplicating code regarding mpeg-ts in a gazillion
elements and allow easy creatiof new elements.
Battleplan :
------------
* Figure out code from mpegtsparse which would be also needed for a
mpeg-ts demuxer (ex: packet/psi/pcr parsing).
* Extract common code into a base mpegtsbase class.
* Refactor mpegtsparse to subclass that base class.
* Create a minimalistic demuxer that creates pads (based on PSI info)
and outputs ES packets (let's say mpeg audio and video to start with)
Potential subclasses :
----------------------
* MpegTSParse : Program splitter. Given an incoming multi-program
mpeg-ts stream, it can provide request pads for each program. Each
of those pads will contain the ts packets specific to that program.
* TSDemux : Program demuxer. Given an incoming single or multi-program
mpeg-ts stream, it will reconstruct the original Program Streams of
the selected program and output them on dynamically created pads.
* HDVSplitter : Given an incoming HDV mpeg-ts stream, it will locate
the beginning of new scenes and output a mpeg-ts stream with the
PAT/PMT/AUX packets properly ordered and marked with DISCONT, so
that the following pipeline will automatically cut up a tape dump
into individual scenes:
filesrc ! hdvsplit ! multifilesink next-file=discont
Code/Design common to a program-spliter and a demuxer :
-------------------------------------------------------
* Parsing TS packets
* Establishing PAT/PMT mapping
* Handling the notions of Programs/Streams
* Seeking ?
One proposal... would be to have the base class automatically create
all the structures (and relationships) for the following objects:
* Programs (from PAT/PMT, dunno if it could come from something
else)
* Program id
* Streams contained in that program (with links to them)
* Which stream contains the PCR
* Metadata ?
* Streams (ideally... in a table for fast access)
* We want to be able to have stream-type specific information
easily accessible also (like mpeg video specific data)
* Maybe some other info ???
The subclasses would then be able to make their own decision based
on those objects.
Maybe we could have some virtual methods that will be called when a
new program is detected, a new stream is added, etc...
It is the subclass who decides what's to do with a given packet once
it's been parsed.
tsparse : forward it as-is to the pad corresponding to the program
tsdemux : forward it to the proper PS parser
hdvsplit : ?
Ideas to be taken into account for a proper demuxer :
-----------------------------------------------------
* Push-based (with inacurrate seeking)
* Pull-based (with fast *AND* accurate seeking)
* Modular system to add stream-type specific helper parsing
* Doesn't have to be fully fledged, just enough to help any kind of
seeking and scanning code.
* ...
Problems to figure out :
------------------------
* clock
Needed for proper dvb playback. mpegtsdemux currently does internal
clock estimation... to provide a clock with PCR estimations.
A proper way to solve that would be to timestamp the buffers at the
source element using the system clock, and then adjusting the PCR
against those values. (i.e. doing the opposite of what's done in
mpegtsdemux, but it will be more accurate since the timestamping is
done at the source).
Bugs that need fixing :
-----------------------
* Perfomance : Creation/Destruction of buffers is slow
* => This is due to g_type_instance_create using a dogslow rwlock
which take up to 50% of gst_adapter_take_buffer()
=> Bugzilla #585375 (performance and contention problems)
Code structure:
MpegTSBase
+--- MpegTSParse
+--- TSDemux
Known limitations and problems :
--------------------------------
* mpegtspacketizer
* Assumes 188 bytes packets. It should support all modes.
* offset/timestamp of incoming buffers need to be carried on to the
sub-buffers in order for several demuxer features to work correctly.
* mpegtsparser
* SERIOUS room for improvement performance-wise (see callgrind)

View file

@ -0,0 +1,234 @@
/*
* This library is licensed under 2 different licenses and you
* can choose to use it under the terms of either one of them. The
* two licenses are the MPL 1.1 and the LGPL.
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* The Original Code is Fluendo MPEG Demuxer plugin.
*
* The Initial Developer of the Original Code is Fluendo, S.L.
* Portions created by Fluendo, S.L. are Copyright (C) 2005
* Fluendo, S.L. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*/
#ifndef __GST_MPEG_DEFS_H__
#define __GST_MPEG_DEFS_H__
/*
* 1011 1100 program_stream_map
* 1011 1101 private_stream_1
* 1011 1110 padding_stream
* 1011 1111 private_stream_2
* 110x xxxx ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream number x xxxx
* 1110 xxxx ITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream number xxxx
* 1111 0000 ECM_stream
* 1111 0001 EMM_stream
* 1111 0010 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A or ISO/IEC 13818-6_DSMCC_stream
* 1111 0011 ISO/IEC_13522_stream
* 1111 0100 ITU-T Rec. H.222.1 type A
* 1111 0101 ITU-T Rec. H.222.1 type B
* 1111 0110 ITU-T Rec. H.222.1 type C
* 1111 0111 ITU-T Rec. H.222.1 type D
* 1111 1000 ITU-T Rec. H.222.1 type E
* 1111 1001 ancillary_stream
* 1111 1010 E 1111 1110 reserved data stream
* 1111 1111 program_stream_directory
*/
#define ID_PS_END_CODE 0x000001B9
#define ID_PS_PACK_START_CODE 0x000001BA
#define ID_PS_SYSTEM_HEADER_START_CODE 0x000001BB
#define ID_PS_PROGRAM_STREAM_MAP 0x000001BC
#define ID_PRIVATE_STREAM_1 0x000001BD
#define ID_PADDING_STREAM 0x000001BE
#define ID_PRIVATE_STREAM_2 0x000001BF
#define ID_ISO_IEC_MPEG12_AUDIO_STREAM_0 0x000001C0
#define ID_ISO_IEC_MPEG12_AUDIO_STREAM_32 0x000001DF
#define ID_ISO_IEC_MPEG12_VIDEO_STREAM_0 0x000001E0
#define ID_ISO_IEC_MPEG12_VIDEO_STREAM_16 0x000001EF
#define ID_ECM_STREAM 0x000001F0
#define ID_EMM_STREAM 0x000001F1
#define ID_DSMCC_STREAM 0x000001F2
#define ID_ISO_IEC_13522_STREAM 0x000001F3
#define ID_ITU_TREC_H222_TYPE_A_STREAM 0x000001F4
#define ID_ITU_TREC_H222_TYPE_B_STREAM 0x000001F5
#define ID_ITU_TREC_H222_TYPE_C_STREAM 0x000001F6
#define ID_ITU_TREC_H222_TYPE_D_STREAM 0x000001F7
#define ID_ITU_TREC_H222_TYPE_E_STREAM 0x000001F8
#define ID_ANCILLARY_STREAM 0x000001F9
#define ID_RESERVED_STREAM_1 0x000001FA
#define ID_RESERVED_STREAM_2 0x000001FB
#define ID_EXTENDED_METADATA 0x000001FC
#define ID_EXTENDED_STREAM_ID 0x000001FD
#define ID_RESERVED_STREAM_3 0x000001FE
#define ID_PROGRAM_STREAM_DIRECTORY 0x000001FF
#define PACKET_VIDEO_START_CODE 0x000001E0
#define PACKET_AUDIO_START_CODE 0x000001C0
#define PICTURE_START_CODE 0x00000100
#define USER_DATA_START_CODE 0x000001B2
#define SEQUENCE_HEADER_CODE 0x000001B3
#define SEQUENCE_ERROR_CODE 0x000001B4
#define EXTENSION_START_CODE 0x000001B5
#define SEQUENCE_END_CODE 0x000001B7
#define GROUP_START_CODE 0x000001B8
#define AC3_SYNC_WORD 0x0b770000
#define MPEG_TS_SYNC_BYTE 0x00000047
#define PID_PROGRAM_ASSOCIATION_TABLE 0x0000
#define PID_CONDITIONAL_ACCESS_TABLE 0x0001
#define PID_RESERVED_FIRST 0x0002
#define PID_RESERVED_LAST 0x0010
#define PID_NULL_PACKET 0x1FFF
#define PID_TYPE_UNKNOWN 0
#define PID_TYPE_RESERVED 1
#define PID_TYPE_PROGRAM_ASSOCIATION 2
#define PID_TYPE_CONDITIONAL_ACCESS 3
#define PID_TYPE_PROGRAM_MAP 4
#define PID_TYPE_ELEMENTARY 5
#define PID_TYPE_NULL_PACKET 6
#define PID_TYPE_PRIVATE_SECTION 7
/* Stream type assignments
*
* 0x00 ITU-T | ISO/IEC Reserved
* 0x01 ISO/IEC 11172 Video
* 0x02 ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or
* ISO/IEC 11172-2 constrained parameter video
* stream
* 0x03 ISO/IEC 11172 Audio
* 0x04 ISO/IEC 13818-3 Audio
* 0x05 ITU-T Rec. H.222.0 | ISO/IEC 13818-1
* private_sections
* 0x06 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES
* packets containing private data
* 0x07 ISO/IEC 13522 MHEG
* 0x08 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A
* DSM CC
* 0x09 ITU-T Rec. H.222.1
* 0x0A ISO/IEC 13818-6 type A
* 0x0B ISO/IEC 13818-6 type B
* 0x0C ISO/IEC 13818-6 type C
* 0x0D ISO/IEC 13818-6 type D
* 0x0E ISO/IEC 13818-1 auxiliary
* 0x0F-0x7F ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved
* 0x80-0xFF User Private
*/
#define ST_RESERVED 0x00
#define ST_VIDEO_MPEG1 0x01
#define ST_VIDEO_MPEG2 0x02
#define ST_AUDIO_MPEG1 0x03
#define ST_AUDIO_MPEG2 0x04
#define ST_PRIVATE_SECTIONS 0x05
#define ST_PRIVATE_DATA 0x06
#define ST_MHEG 0x07
#define ST_DSMCC 0x08
#define ST_H222_1 0x09
/* later extensions */
#define ST_AUDIO_AAC 0x0f
#define ST_VIDEO_MPEG4 0x10
#define ST_VIDEO_H264 0x1b
/* Un-official Dirac extension */
#define ST_VIDEO_DIRAC 0xd1
/* private stream types */
#define ST_PS_AUDIO_AC3 0x81
#define ST_PS_AUDIO_DTS 0x8a
#define ST_PS_AUDIO_LPCM 0x8b
#define ST_PS_DVD_SUBPICTURE 0xff
/* Blu-ray related */
#define ST_BD_AUDIO_LPCM 0x80
#define ST_BD_AUDIO_AC3 0x81
#define ST_BD_AUDIO_DTS 0x82
#define ST_BD_AUDIO_AC3_TRUE_HD 0x83
#define ST_BD_AUDIO_AC3_PLUS 0x84
#define ST_BD_AUDIO_DTS_HD 0x85
#define ST_BD_AUDIO_DTS_HD_MASTER_AUDIO 0x86
#define ST_BD_AUDIO_EAC3 0x87
#define ST_BD_PGS_SUBPICTURE 0x90
#define ST_BD_IGS 0x91
#define ST_BD_SUBTITLE 0x92
#define ST_BD_SECONDARY_AC3_PLUS 0xa1
#define ST_BD_SECONDARY_DTS_HD 0xa2
/* defined for VC1 extension in RP227 */
#define ST_PRIVATE_EA 0xea
/* HDV AUX stream mapping
* 0xA0 ISO/IEC 61834-11
* 0xA1 ISO/IEC 61834-11
*/
#define ST_HDV_AUX_A 0xa0
#define ST_HDV_AUX_V 0xa1
/* Un-official time-code stream */
#define ST_PS_TIMECODE 0xd2
/* Internal stream types >= 0x100 */
#define ST_GST_AUDIO_RAWA52 0x181
/* Used when we don't yet know which stream type it will be in a PS stream */
#define ST_GST_VIDEO_MPEG1_OR_2 0x102
#define CLOCK_BASE 9LL
#define CLOCK_FREQ (CLOCK_BASE * 10000)
#define PCRTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
GST_MSECOND/10, 300 * CLOCK_BASE))
#define MPEGTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
GST_MSECOND/10, CLOCK_BASE))
#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \
CLOCK_BASE, GST_MSECOND/10))
#define MPEG_MUX_RATE_MULT 50
/* sync:4 == 00xx ! pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */
#define READ_TS(data, target, lost_sync_label) \
if ((*data & 0x01) != 0x01) goto lost_sync_label; \
target = ((guint64) (*data++ & 0x0E)) << 29; \
target |= ((guint64) (*data++ )) << 22; \
if ((*data & 0x01) != 0x01) goto lost_sync_label; \
target |= ((guint64) (*data++ & 0xFE)) << 14; \
target |= ((guint64) (*data++ )) << 7; \
if ((*data & 0x01) != 0x01) goto lost_sync_label; \
target |= ((guint64) (*data++ & 0xFE)) >> 1;
/* some extra GstFlowReturn values used internally */
#define GST_FLOW_NEED_MORE_DATA GST_FLOW_CUSTOM_SUCCESS
#define GST_FLOW_LOST_SYNC GST_FLOW_CUSTOM_SUCCESS_1
#endif /* __GST_MPEG_DEFS_H__ */

View file

@ -0,0 +1,209 @@
/*
* 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.
*
* The Original Code is Fluendo MPEG Demuxer plugin.
*
* The Initial Developer of the Original Code is Fluendo, S.L.
* Portions created by Fluendo, S.L. are Copyright (C) 2005
* Fluendo, S.L. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU Lesser General Public License Version 2 or later (the "LGPL"),
* in which case the provisions of the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of the MPL or the LGPL.
*/
#include <string.h>
#include <gst/gst.h>
#include "gstmpegdesc.h"
GST_DEBUG_CATEGORY (gstmpegtsdesc_debug);
#define GST_CAT_DEFAULT (gstmpegtsdesc_debug)
void
gst_mpeg_descriptor_free (GstMPEGDescriptor * desc)
{
g_return_if_fail (desc != NULL);
g_free (desc);
}
static guint
gst_mpeg_descriptor_parse_1 (guint8 * data, guint size)
{
guint8 tag;
guint8 length;
/* need at least 2 bytes for tag and length */
if (size < 2)
return 0;
tag = *data++;
length = *data++;
size -= 2;
GST_DEBUG ("tag: 0x%02x, length: %d", tag, length);
if (length > size)
return 0;
GST_MEMDUMP ("tag contents:", data, length);
return length + 2;
}
GstMPEGDescriptor *
gst_mpeg_descriptor_parse (guint8 * data, guint size)
{
guint8 *current;
guint consumed, total, n_desc;
GstMPEGDescriptor *result;
g_return_val_if_fail (data != NULL, NULL);
current = data;
total = 0;
n_desc = 0;
do {
consumed = gst_mpeg_descriptor_parse_1 (current, size);
if (consumed > 0) {
current += consumed;
total += consumed;
size -= consumed;
n_desc++;
}
}
while (consumed > 0);
GST_DEBUG ("parsed %d descriptors", n_desc);
if (total == 0)
return NULL;
result = g_malloc (sizeof (GstMPEGDescriptor) + total);
result->n_desc = n_desc;
result->data_length = total;
result->data = ((guint8 *) result) + sizeof (GstMPEGDescriptor);
memcpy (result->data, data, total);
return result;
}
guint
gst_mpeg_descriptor_n_desc (GstMPEGDescriptor * desc)
{
g_return_val_if_fail (desc != NULL, 0);
return desc->n_desc;
}
guint8 *
gst_mpeg_descriptor_find (GstMPEGDescriptor * desc, gint tag)
{
guint8 length;
guint8 *current;
guint size;
g_return_val_if_fail (desc != NULL, NULL);
current = desc->data;
length = desc->data_length;
while (length > 0) {
if (DESC_TAG (current) == tag)
return current;
size = DESC_LENGTH (current) + 2;
current += size;
length -= size;
}
return NULL;
}
/* array needs freeing afterwards */
GArray *
gst_mpeg_descriptor_find_all (GstMPEGDescriptor * desc, gint tag)
{
GArray *all;
guint8 length;
guint8 *current;
guint size;
g_return_val_if_fail (desc != NULL, NULL);
all = g_array_new (TRUE, TRUE, sizeof (guint8 *));
current = desc->data;
length = desc->data_length;
while (length > 0) {
if (DESC_TAG (current) == tag)
g_array_append_val (all, current);
size = DESC_LENGTH (current) + 2;
current += size;
length -= size;
}
GST_DEBUG ("found tag 0x%02x %d times", tag, all->len);
return all;
}
guint8 *
gst_mpeg_descriptor_nth (GstMPEGDescriptor * desc, guint i)
{
guint8 length;
guint8 *current;
guint size;
g_return_val_if_fail (desc != NULL, NULL);
if (i > desc->n_desc)
return NULL;
current = desc->data;
length = desc->data_length;
while (length > 0) {
if (i == 0)
return current;
size = DESC_LENGTH (current) + 2;
current += size;
length -= size;
i--;
}
return NULL;
}
void
gst_mpegtsdesc_init_debug (void)
{
GST_DEBUG_CATEGORY_INIT (gstmpegtsdesc_debug, "mpegtsdesc", 0,
"MPEG transport stream parser (descriptor)");
}

View file

@ -0,0 +1,342 @@
/*
* 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.
*
* The Original Code is Fluendo MPEG Demuxer plugin.
*
* The Initial Developer of the Original Code is Fluendo, S.L.
* Portions created by Fluendo, S.L. are Copyright (C) 2005
* Fluendo, S.L. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU Lesser General Public License Version 2 or later (the "LGPL"),
* in which case the provisions of the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of the MPL or the LGPL.
*/
#ifndef __GST_MPEG_DESC_H__
#define __GST_MPEG_DESC_H__
#include <glib.h>
/*
* descriptor_tag TS PS Identification
* 0 n/a n/a Reserved
* 1 n/a n/a Reserved
* 2 X X video_stream_descriptor
* 3 X X audio_stream_descriptor
* 4 X X hierarchy_descriptor
* 5 X X registration_descriptor
* 6 X X data_stream_alignment_descriptor
* 7 X X target_background_grid_descriptor
* 8 X X video_window_descriptor
* 9 X X CA_descriptor
* 10 X X ISO_639_language_descriptor
* 11 X X system_clock_descriptor
* 12 X X multiplex_buffer_utilization_descriptor
* 13 X X copyright_descriptor
* 14 X maximum bitrate descriptor
* 15 X X private data indicator descriptor
* 16 X X smoothing buffer descriptor
* 17 X STD_descriptor
* 18 X X IBP descriptor
* 19-63 n/a n/a ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved
* 64-255 n/a n/a User Private
*/
#define DESC_VIDEO_STREAM 2
#define DESC_AUDIO_STREAM 3
#define DESC_HIERARCHY 4
#define DESC_REGISTRATION 5
#define DESC_DATA_STREAM_ALIGNMENT 6
#define DESC_TARGET_BACKGROUND_GRID 7
#define DESC_VIDEO_WINDOW 8
#define DESC_CA 9
#define DESC_ISO_639_LANGUAGE 10
#define DESC_SYSTEM_CLOCK 11
#define DESC_MULTIPLEX_BUFFER_UTILISATION 12
#define DESC_COPYRIGHT 13
#define DESC_MAXIMUM_BITRATE 14
#define DESC_PRIVATE_DATA_INDICATOR 15
#define DESC_SMOOTHING_BUFFER 16
#define DESC_STD 17
#define DESC_IBP 18
#define DESC_DIRAC_TC_PRIVATE 0xAC
/* DVB tags */
#define DESC_DVB_CAROUSEL_IDENTIFIER 0x13
#define DESC_DVB_NETWORK_NAME 0x40
#define DESC_DVB_SERVICE_LIST 0x41
#define DESC_DVB_STUFFING 0x42
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM 0x43
#define DESC_DVB_CABLE_DELIVERY_SYSTEM 0x44
#define DESC_DVB_VBI_DATA 0x45
#define DESC_DVB_VBI_TELETEXT 0x46
#define DESC_DVB_BOUQUET_NAME 0x47
#define DESC_DVB_SERVICE 0x48
#define DESC_DVB_COUNTRY_AVAILABILITY 0x49
#define DESC_DVB_LINKAGE 0x4A
#define DESC_DVB_NVOD_REFERENCE 0x4B
#define DESC_DVB_TIME_SHIFTED_SERVICE 0x4C
#define DESC_DVB_SHORT_EVENT 0x4D
#define DESC_DVB_EXTENDED_EVENT 0x4E
#define DESC_DVB_TIME_SHIFTED_EVENT 0x4F
#define DESC_DVB_COMPONENT 0x50
#define DESC_DVB_MOSAIC 0x51
#define DESC_DVB_STREAM_IDENTIFIER 0x52
#define DESC_DVB_CA_IDENTIFIER 0x53
#define DESC_DVB_CONTENT 0x54
#define DESC_DVB_PARENTAL_RATING 0x55
#define DESC_DVB_TELETEXT 0x56
#define DESC_DVB_TELEPHONE 0x57
#define DESC_DVB_LOCAL_TIME_OFFSET 0x58
#define DESC_DVB_SUBTITLING 0x59
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM 0x5A
#define DESC_DVB_MULTILINGUAL_NETWORK_NAME 0x5B
#define DESC_DVB_MULTILINGUAL_BOUQUET_NAME 0x5C
#define DESC_DVB_MULTILINGUAL_SERVICE_NAME 0x5D
#define DESC_DVB_MULTILINGUAL_COMPONENT 0x5E
#define DESC_DVB_PRIVATE_DATA 0x5F
#define DESC_DVB_SERVICE_MOVE 0x60
#define DESC_DVB_SHORT_SMOOTHING_BUFFER 0x61
#define DESC_DVB_FREQUENCY_LIST 0x62
#define DESC_DVB_PARTIAL_TRANSPORT_STREAM 0x63
#define DESC_DVB_DATA_BROADCAST 0x64
#define DESC_DVB_SCRAMBLING 0x65
#define DESC_DVB_DATA_BROADCAST_ID 0x66
#define DESC_DVB_TRANSPORT_STREAM 0x67
#define DESC_DVB_DSNG 0x68
#define DESC_DVB_PDC 0x69
#define DESC_DVB_AC3 0x6A
#define DESC_DVB_ANCILLARY_DATA 0x6B
#define DESC_DVB_CELL_LIST 0x6C
#define DESC_DVB_CELL_FREQUENCY_LINK 0x6D
#define DESC_DVB_ANNOUNCEMENT_SUPPORT 0x6E
#define DESC_DVB_APPLICATION_SIGNALLING 0x6F
#define DESC_DVB_ADAPTATION_FIELD_DATA 0x70
#define DESC_DVB_SERVICE_IDENTIFIER 0x71
#define DESC_DVB_SERVICE_AVAILABILITY 0x72
#define DESC_DVB_DEFAULT_AUTHORITY 0x73
#define DESC_DVB_RELATED_CONTENT 0x74
#define DESC_DVB_TVA_ID 0x75
#define DESC_DVB_CONTENT_IDENTIFIER 0x76
#define DESC_DVB_TIMESLICE_FEC_IDENTIFIER 0x77
#define DESC_DVB_ECM_REPETITION_RATE 0x78
#define DESC_DVB_S2_SATELLITE_DELIVERY_SYSTEM 0x79
#define DESC_DVB_ENHANCED_AC3 0x7A
#define DESC_DVB_DTS 0x7B
#define DESC_DVB_AAC 0x7C
/* 0x7D and 0x7E are reserved for future use */
#define DESC_DVB_EXTENSION 0x7F
/* 0x80 - 0xFE are user defined */
#define DESC_DTG_LOGICAL_CHANNEL 0x83 /* from DTG D-Book */
/* 0xFF is forbidden */
/* common for all descriptors */
#define DESC_TAG(desc) (desc[0])
#define DESC_LENGTH(desc) (desc[1])
/* video_stream_descriptor */
#define DESC_VIDEO_STREAM_multiple_framerate_flag(desc) (((desc)[2] & 0x80) == 0x80)
#define DESC_VIDEO_STREAM_frame_rate_code(desc) (((desc)[2] & 0x38) >> 3)
#define DESC_VIDEO_STREAM_MPEG_1_only_flag(desc) (((desc)[2] & 0x04) == 0x04)
#define DESC_VIDEO_STREAM_constrained_parameter_flag(desc) (((desc)[2] & 0x02) == 0x02)
#define DESC_VIDEO_STREAM_still_picture_flag(desc) (((desc)[2] & 0x01) == 0x01)
/* if (MPEG_1_only_flag == 1) */
#define DESC_VIDEO_STREAM_profile_and_level_indication(desc) ((desc)[3])
#define DESC_VIDEO_STREAM_chroma_format(desc) (((desc)[4] & 0xc0) >> 6)
#define DESC_VIDEO_STREAM_frame_rate_extension_flag(desc) (((desc)[4] & 0x20) == 0x20)
/* audio_stream_descriptor */
#define DESC_AUDIO_STREAM_free_format_flag(desc) (((desc)[2] & 0x80) == 0x80)
#define DESC_AUDIO_STREAM_ID(desc) (((desc)[2] & 0x40) == 0x40)
#define DESC_AUDIO_STREAM_layer(desc) (((desc)[2] & 0x30) >> 4)
#define DESC_AUDIO_STREAM_variable_rate_audio_indicator(desc) (((desc)[2] & 0x08) == 0x08)
/* hierarchy_descriptor */
#define DESC_HIERARCHY_hierarchy_type(desc) (((desc)[2] & 0x0f))
#define DESC_HIERARCHY_hierarchy_layer_index(desc) (((desc)[3] & 0x3f))
#define DESC_HIERARCHY_hierarchy_embedded_layer_index(desc) (((desc)[4] & 0x3f))
#define DESC_HIERARCHY_hierarchy_channel(desc) (((desc)[5] & 0x3f))
/* registration_descriptor */
#define DESC_REGISTRATION_format_identifier(desc) (GST_READ_UINT32_BE ((desc)+2))
#define DESC_REGISTRATION_additional_ident_info_len(desc) ((desc)[1] - 4)
#define DESC_REGISTRATION_additional_ident_info(desc) (&(desc)[6])
/* data_stream_alignment_descriptor */
#define DESC_DATA_STREAM_ALIGNMENT_alignment_type(desc) ((desc)[2])
/* target_background_grid_descriptor */
#define DESC_TARGET_BACKGROUND_GRID_horizontal_size(desc) (GST_READ_UINT16_BE ((desc)+2) >> 2)
#define DESC_TARGET_BACKGROUND_GRID_vertical_size(desc) ((GST_READ_UINT32_BE ((desc)+2) & 0x0003fff0) >> 4)
#define DESC_TARGET_BACKGROUND_GRID_aspect_ratio_information(desc) ((desc)[5] & 0x0f)
/* video_window_descriptor */
#define DESC_VIDEO_WINDOW_horizontal_offset(desc) (GST_READ_UINT16_BE ((desc)+2) >> 2)
#define DESC_VIDEO_WINDOW_vertical_offset(desc) ((GST_READ_UINT32_BE ((desc)+2) & 0x0003fff0) >> 4)
#define DESC_VIDEO_WINDOW_window_priority(desc) ((desc)[5] & 0x0f)
/* CA_descriptor */
#define DESC_CA_system_ID(desc) (GST_READ_UINT16_BE ((desc)+2))
#define DESC_CA_PID(desc) (GST_READ_UINT16_BE ((desc)+2) & 0x1fff)
/* ISO_639_language_descriptor */
#define DESC_ISO_639_LANGUAGE_codes_n(desc) ((desc[1]) >> 2)
#define DESC_ISO_639_LANGUAGE_language_code_nth(desc,i) (&(desc[2 + (4*i)]))
#define DESC_ISO_639_LANGUAGE_audio_type_nth(desc,i) ((desc)[5 + (4*i)])
/* system_clock_descriptor */
#define DESC_SYSTEM_CLOCK_external_clock_reference_indicator(desc) (((desc)[2] & 0x80) == 0x80)
#define DESC_SYSTEM_CLOCK_clock_accuracy_integer(desc) ((desc)[2] & 0x3f)
#define DESC_SYSTEM_CLOCK_clock_accuracy_exponent(desc) (((desc)[3] & 0xe0) >> 5)
/* multiplex_buffer_utilization_descriptor */
#define DESC_MULTIPLEX_BUFFER_UTILISATION_bound_valid_flag(desc) (((desc)[2] & 0x80) == 0x80)
#define DESC_MULTIPLEX_BUFFER_UTILISATION_LTW_offset_lower_bound(desc) (GST_READ_UINT16_BE ((desc)+2) & 0x7fff)
#define DESC_MULTIPLEX_BUFFER_UTILISATION_LTW_offset_upper_bound(desc) (GST_READ_UINT16_BE ((desc)+4) & 0x7fff)
/* copyright_descriptor */
#define DESC_COPYRIGHT_copyright_identifier(desc) (GST_READ_UINT32_BE ((desc)+2))
#define DESC_COPYRIGHT_additional_copyright_info_len(desc) ((desc)[1] - 4)
#define DESC_COPYRIGHT_additional_copyright_info(desc) (&(desc)[6])
/* maximum_bitrate_descriptor */
#define DESC_MAXIMUM_BITRAT_maximum_bitrate(desc) (((((guint32)desc[2]) & 0x3f) << 16) | \
GST_READ_UINT16_BE ((desc)+3))
/* private_data_indicator_descriptor */
#define DESC_PRIVATE_DATA_INDICATOR_indicator(desc) (GST_READ_UINT32_BE(&desc[2]))
/* smoothing_buffer_descriptor */
#define DESC_SMOOTHING_BUFFER_sb_leak_rate(desc) (((((guint32)desc[2]) & 0x3f) << 16) | \
GST_READ_UINT16_BE ((desc)+3))
#define DESC_SMOOTHING_BUFFER_sb_size(desc) (((((guint32)desc[5]) & 0x3f) << 16) | \
GST_READ_UINT16_BE ((desc)+6))
/* STD_descriptor */
#define DESC_STD_leak_valid_flag(desc) (((desc)[2] & 0x01) == 0x01)
/* ibp_descriptor */
#define DESC_IBP_closed_gop_flag(desc) (((desc)[2] & 0x80) == 0x80)
#define DESC_IBP_identical_gop_flag(desc) (((desc)[2] & 0x40) == 0x40)
#define DESC_IBP_max_gop_length(desc) (GST_READ_UINT16_BE ((desc)+6) & 0x3fff)
/* time_code descriptor */
#define DESC_TIMECODE_video_pid(desc) (GST_READ_UINT16_BE ((desc) + 2) & 0x1fff)
/* Stream identifier descriptor */
#define DESC_DVB_STREAM_IDENTIFIER_component_tag(desc) (desc[2])
/* DVB Network Name descriptor */
#define DESC_DVB_NETWORK_NAME_length(desc) (GST_READ_UINT8((desc)+1))
#define DESC_DVB_NETWORK_NAME_text(desc) (desc+2)
/* DVB Service Descriptor */
#define DESC_DVB_SERVICE_type(desc) (desc[2])
#define DESC_DVB_SERVICE_provider_name_length(desc) (desc[3])
#define DESC_DVB_SERVICE_provider_name_text(desc) (desc+4)
#define DESC_DVB_SERVICE_name_length(desc) (desc[4 + DESC_DVB_SERVICE_provider_name_length(desc)])
#define DESC_DVB_SERVICE_name_text(desc) (desc + 5 + DESC_DVB_SERVICE_provider_name_length(desc))
/* DVB Component Descriptor */
#define DESC_DVB_COMPONENT_stream_content(desc) (desc[2] & 0x0F)
#define DESC_DVB_COMPONENT_type(desc) (desc[3])
#define DESC_DVB_COMPONENT_tag(desc) (desc[4])
#define DESC_DVB_COMPONENT_language(desc) (desc + 5)
/* DVB Bouquet Name Descriptor */
#define DESC_DVB_BOUQUET_NAME_text(desc) (desc + 2)
/* DVB Short Event Descriptor */
#define DESC_DVB_SHORT_EVENT_name_text(desc) (desc + 6)
#define DESC_DVB_SHORT_EVENT_name_length(desc) (desc[5])
#define DESC_DVB_SHORT_EVENT_description_text(desc) (desc + 6 + DESC_DVB_SHORT_EVENT_name_length(desc) + 1)
#define DESC_DVB_SHORT_EVENT_description_length(desc) (desc[6 + DESC_DVB_SHORT_EVENT_name_length(desc)])
/* DVB Extended Event Descriptor */
#define DESC_DVB_EXTENDED_EVENT_descriptor_number(desc) ((desc[2] & 0xF0) >> 4)
#define DESC_DVB_EXTENDED_EVENT_last_descriptor_number(desc) (desc[2] & 0x0F)
#define DESC_DVB_EXTENDED_EVENT_iso639_language_code(desc) (desc + 3)
#define DESC_DVB_EXTENDED_EVENT_items_length(desc) (desc[6])
#define DESC_DVB_EXTENDED_EVENT_items(desc) (desc + 7)
#define DESC_DVB_EXTENDED_EVENT_text_length(desc) (desc[7 + DESC_DVB_EXTENDED_EVENT_items_length(desc)])
#define DESC_DVB_EXTENDED_EVENT_text(desc) (desc + 7 + DESC_DVB_EXTENDED_EVENT_items_length(desc) + 1)
/* DVB Satellite Delivery System Descriptor */
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_frequency(desc) (desc + 2)
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_orbital_position(desc) (desc + 6)
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_west_east_flag(desc) ((desc[8] & 0x80) == 0x80)
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_polarization(desc) ((desc[8] >> 5) & 0x3)
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_modulation(desc) (desc[8] & 0x1F)
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_symbol_rate(desc) (desc + 9)
#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_fec_inner(desc) (desc[12] & 0x0F)
/* DVB Terrestrial Delivery System Descriptor */
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_frequency(desc) (GST_READ_UINT32_BE((desc) + 2))
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_bandwidth(desc) ((desc[6] >> 5) & 0x7)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_constellation(desc) ((desc[7] >> 6) & 0x3)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_hierarchy(desc) ((desc[7] >> 3) & 0x7)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_hp(desc) (desc[7] & 0x7)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_lp(desc) ((desc[8] >> 5) & 0x7)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_guard_interval(desc) ((desc[8] >> 3) & 0x3)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_transmission_mode(desc) ((desc[8] >> 1) & 0x3)
#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_other_frequency(desc) ((desc[8] & 0x01) == 0x01)
/* DVB Cable Delivery System Descriptor */
#define DESC_DVB_CABLE_DELIVERY_SYSTEM_frequency(desc) (desc + 2)
#define DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_outer(desc) (desc[7] & 0x0F)
#define DESC_DVB_CABLE_DELIVERY_SYSTEM_modulation(desc) (desc[8])
#define DESC_DVB_CABLE_DELIVERY_SYSTEM_symbol_rate(desc) (desc + 9)
#define DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_inner(desc) (desc[12] & 0x0F)
/* DVB Data Broadcast Descriptor */
#define DESC_DVB_DATA_BROADCAST_data_broadcast_id(desc) (GST_READ_UINT16_BE((desc) + 2))
#define DESC_DVB_DATA_BROADCAST_component_tag(desc) (desc[4])
#define DESC_DVB_DATA_BROADCAST_selector_length(desc) (desc[5])
#define DESC_DVB_DATA_BROADCAST_selector(desc) (desc + 6)
#define DESC_DVB_DATA_BROADCAST_iso639_language_code(desc) (desc + 6 + DESC_DVB_DATA_BROADCAST_selector_length(desc))
#define DESC_DVB_DATA_BROADCAST_text_length(desc) (desc + 9 + DESC_DVB_DATA_BROADCAST_selector_length(desc))
#define DESC_DVB_DATA_BROADCAST_text(desc) (desc + 10 + DESC_DVB_DATA_BROADCAST_selector_length(desc))
/* DVB Data Broadcast Id Descriptor */
#define DESC_DVB_DATA_BROADCAST_ID_data_broadcast_id(desc) (GST_READ_UINT16_BE((desc) + 2))
#define DESC_DVB_DATA_BROADCAST_ID_id_selector_byte(desc) (desc + 4)
/* DVB Carousel Identifier Descriptor */
#define DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id(desc) (GST_READ_UINT32_BE((desc) + 2))
/* registration_descriptor format IDs */
#define DRF_ID_HDMV 0x48444d56
#define DRF_ID_VC1 0x56432D31 /* defined in RP227 */
typedef struct {
guint n_desc;
guint8 data_length;
guint8 *data;
} GstMPEGDescriptor;
void gst_mpegtsdesc_init_debug (void);
GstMPEGDescriptor* gst_mpeg_descriptor_parse (guint8 *data, guint size);
void gst_mpeg_descriptor_free (GstMPEGDescriptor *desc);
guint gst_mpeg_descriptor_n_desc (GstMPEGDescriptor *desc);
guint8* gst_mpeg_descriptor_find (GstMPEGDescriptor *desc, gint tag);
GArray* gst_mpeg_descriptor_find_all (GstMPEGDescriptor * desc, gint tag);
guint8* gst_mpeg_descriptor_nth (GstMPEGDescriptor *desc, guint i);
#endif /* __GST_MPEG_DESC_H__ */

View file

@ -0,0 +1,47 @@
/*
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mpegtsbase.h"
#include "mpegtspacketizer.h"
#include "mpegtsparse.h"
#include "tsdemux.h"
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_mpegtsbase_plugin_init (plugin))
return FALSE;
if (!gst_mpegtsparse_plugin_init (plugin))
return FALSE;
if (!gst_ts_demux_plugin_init (plugin))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"mpegtsdemux",
"MPEG TS demuxer",
plugin_init, VERSION,
GST_LICENSE_UNKNOWN, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

1257
gst/mpegtsdemux/mpegtsbase.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*
* mpegtsbase.h - GStreamer MPEG transport stream base class
* Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
* 2007 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
* Edward Hervey <edward.hervey@collabora.co.uk>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef GST_MPEG_TS_BASE_H
#define GST_MPEG_TS_BASE_H
#include <gst/gst.h>
#include "mpegtspacketizer.h"
G_BEGIN_DECLS
#define GST_TYPE_MPEGTS_BASE \
(mpegts_base_get_type())
#define GST_MPEGTS_BASE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEGTS_BASE,MpegTSBase))
#define GST_MPEGTS_BASE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEGTS_BASE,MpegTSBaseClass))
#define GST_IS_MPEGTS_BASE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEGTS_BASE))
#define GST_IS_MPEGTS_BASE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEGTS_BASE))
#define GST_MPEGTS_BASE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MPEGTS_BASE, MpegTSBaseClass))
typedef struct _MpegTSBase MpegTSBase;
typedef struct _MpegTSBaseClass MpegTSBaseClass;
typedef struct _MpegTSBaseStream MpegTSBaseStream;
typedef struct _MpegTSBaseProgram MpegTSBaseProgram;
struct _MpegTSBaseStream
{
guint16 pid;
guint8 stream_type;
GstStructure* stream_info;
};
struct _MpegTSBaseProgram
{
gint program_number;
guint16 pmt_pid;
guint16 pcr_pid;
GstStructure *pmt_info;
MpegTSBaseStream **streams;
gint patcount;
/* Pending Tags for the program */
GstTagList *tags;
guint event_id;
};
typedef enum {
BASE_MODE_SCANNING,
BASE_MODE_SEEKING,
BASE_MODE_STREAMING
} MpegTSBaseMode;
struct _MpegTSBase {
GstElement element;
GstPad *sinkpad;
/* pull-based behaviour */
MpegTSBaseMode mode;
/* location of first sync point */
guint64 initial_sync_point;
/* Current pull offset (also set by seek handler) */
guint64 seek_offset;
/* Cached packetsize */
guint16 packetsize;
/* the following vars must be protected with the OBJECT_LOCK as they can be
* accessed from the application thread and the streaming thread */
GHashTable *programs;
GstStructure *pat;
MpegTSPacketizer2 *packetizer;
/* arrays that say whether a pid is a known psi pid or a pes pid
* FIXME: Make these bit arrays so we can make them 8 times smaller */
gboolean *known_psi;
gboolean *is_pes;
gboolean disposed;
/* size of the MpegTSBaseProgram structure, can be overridden
* by subclasses if they have their own MpegTSBaseProgram subclasses. */
gsize program_size;
/* size of the MpegTSBaseStream structure, can be overridden
* by subclasses if they have their own MpegTSBaseStream subclasses */
gsize stream_size;
/*Offset from the origin to the first PAT (pullmode) */
guint64 first_pat_offset;
};
struct _MpegTSBaseClass {
GstElementClass parent_class;
/* Virtual methods */
GstFlowReturn (*push) (MpegTSBase *base, MpegTSPacketizerPacket *packet, MpegTSPacketizerSection * section);
gboolean (*push_event) (MpegTSBase *base, GstEvent * event);
/* program_started gets called when program's pmt arrives for first time */
void (*program_started) (MpegTSBase *base, MpegTSBaseProgram *program);
/* program_stopped gets called when pat no longer has program's pmt */
void (*program_stopped) (MpegTSBase *base, MpegTSBaseProgram *program);
/* stream_added is called whenever a new stream has been identified */
void (*stream_added) (MpegTSBase *base, MpegTSBaseStream *stream, MpegTSBaseProgram *program);
/* stream_removed is called whenever a stream is no longer referenced */
void (*stream_removed) (MpegTSBase *base, MpegTSBaseStream *stream);
/* find_timestamps is called to find PCR */
GstFlowReturn (*find_timestamps) (MpegTSBase * base, guint64 initoff, guint64 *offset);
/* signals */
void (*pat_info) (GstStructure *pat);
void (*pmt_info) (GstStructure *pmt);
void (*nit_info) (GstStructure *nit);
void (*sdt_info) (GstStructure *sdt);
void (*eit_info) (GstStructure *eit);
};
GType mpegts_base_get_type(void);
MpegTSBaseProgram *mpegts_base_get_program (MpegTSBase * base, gint program_number);
MpegTSBaseProgram *mpegts_base_add_program (MpegTSBase * base, gint program_number, guint16 pmt_pid);
guint8 *mpegts_get_descriptor_from_stream (MpegTSBaseStream * stream, guint8 tag);
guint8 *mpegts_get_descriptor_from_program (MpegTSBaseProgram * program, guint8 tag);
gboolean gst_mpegtsbase_plugin_init (GstPlugin * plugin);
gboolean mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet);
gboolean mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section);
void mpegts_base_program_remove_stream (MpegTSBase * base, MpegTSBaseProgram * program, guint16 pid);
void mpegts_base_remove_program(MpegTSBase *base, gint program_number);
G_END_DECLS
#endif /* GST_MPEG_TS_BASE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,167 @@
/*
* mpegtspacketizer.h -
* Copyright (C) 2007 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef GST_MPEGTS_PACKETIZER_H
#define GST_MPEGTS_PACKETIZER_H
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include <glib.h>
#define MPEGTS_NORMAL_PACKETSIZE 188
#define MPEGTS_M2TS_PACKETSIZE 192
#define MPEGTS_DVB_ASI_PACKETSIZE 204
#define MPEGTS_ATSC_PACKETSIZE 208
#define MPEGTS_MIN_PACKETSIZE MPEGTS_NORMAL_PACKETSIZE
#define MPEGTS_MAX_PACKETSIZE MPEGTS_ATSC_PACKETSIZE
#define MPEGTS_AFC_PCR_FLAG 0x10
#define MPEGTS_AFC_OPCR_FLAG 0x08
G_BEGIN_DECLS
#define GST_TYPE_MPEGTS_PACKETIZER \
(mpegts_packetizer_get_type())
#define GST_MPEGTS_PACKETIZER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEGTS_PACKETIZER,MpegTSPacketizer2))
#define GST_MPEGTS_PACKETIZER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEGTS_PACKETIZER,MpegTSPacketizer2Class))
#define GST_IS_MPEGTS_PACKETIZER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEGTS_PACKETIZER))
#define GST_IS_MPEGTS_PACKETIZER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEGTS_PACKETIZER))
typedef struct _MpegTSPacketizer2 MpegTSPacketizer2;
typedef struct _MpegTSPacketizer2Class MpegTSPacketizer2Class;
typedef struct
{
guint continuity_counter;
GstAdapter *section_adapter;
guint8 section_table_id;
guint section_length;
GSList *subtables;
guint64 offset;
} MpegTSPacketizerStream;
struct _MpegTSPacketizer2 {
GObject object;
GstAdapter *adapter;
/* streams hashed by pid */
MpegTSPacketizerStream **streams;
gboolean disposed;
gboolean know_packet_size;
guint16 packet_size;
GstCaps *caps;
/* current offset of the tip of the adapter */
guint64 offset;
gboolean empty;
};
struct _MpegTSPacketizer2Class {
GObjectClass object_class;
};
typedef struct
{
GstBuffer *buffer;
gint16 pid;
guint8 payload_unit_start_indicator;
guint8 adaptation_field_control;
guint8 continuity_counter;
guint8 *payload;
guint8 *data_start;
guint8 *data_end;
guint8 *data;
guint8 afc_flags;
guint64 pcr;
guint64 opcr;
guint64 offset;
} MpegTSPacketizerPacket;
typedef struct
{
gboolean complete;
GstBuffer *buffer;
gint16 pid;
guint8 table_id;
guint16 subtable_extension;
guint section_length;
guint8 version_number;
guint8 current_next_indicator;
guint32 crc;
} MpegTSPacketizerSection;
typedef struct
{
guint8 table_id;
/* the spec says sub_table_extension is the fourth and fifth byte of a
* section when the section_syntax_indicator is set to a value of "1". If
* section_syntax_indicator is 0, sub_table_extension will be set to 0 */
guint16 subtable_extension;
guint8 version_number;
guint32 crc;
} MpegTSPacketizerStreamSubtable;
typedef enum {
PACKET_BAD = FALSE,
PACKET_OK = TRUE,
PACKET_NEED_MORE
} MpegTSPacketizerPacketReturn;
GType mpegts_packetizer_get_type(void);
MpegTSPacketizer2 *mpegts_packetizer_new (void);
void mpegts_packetizer_clear (MpegTSPacketizer2 *packetizer);
void mpegts_packetizer_push (MpegTSPacketizer2 *packetizer, GstBuffer *buffer);
gboolean mpegts_packetizer_has_packets (MpegTSPacketizer2 *packetizer);
MpegTSPacketizerPacketReturn mpegts_packetizer_next_packet (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerPacket *packet);
void mpegts_packetizer_clear_packet (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerPacket *packet);
void mpegts_packetizer_remove_stream(MpegTSPacketizer2 *packetizer,
gint16 pid);
gboolean mpegts_packetizer_push_section (MpegTSPacketizer2 *packetzer,
MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_pat (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_pmt (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_nit (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_sdt (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer,
MpegTSPacketizerSection *section);
G_END_DECLS
#endif /* GST_MPEGTS_PACKETIZER_H */

View file

@ -0,0 +1,718 @@
/*
* mpegtsparse.c -
* Copyright (C) 2007 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
* Zaheer Abbas Merali <zaheerabbas at merali dot org>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include "mpegtsbase.h"
#include "mpegtsparse.h"
#include "gstmpegdesc.h"
/* latency in mseconds */
#define TS_LATENCY 700
#define TABLE_ID_UNSET 0xFF
#define RUNNING_STATUS_RUNNING 4
GST_DEBUG_CATEGORY_STATIC (mpegts_parse_debug);
#define GST_CAT_DEFAULT mpegts_parse_debug
typedef struct _MpegTSParsePad MpegTSParsePad;
typedef struct
{
MpegTSBaseProgram program;
gint selected;
gboolean active;
MpegTSParsePad *tspad;
} MpegTSParseProgram;
struct _MpegTSParsePad
{
GstPad *pad;
/* the program number that the peer wants on this pad */
gint program_number;
MpegTSParseProgram *program;
/* set to FALSE before a push and TRUE after */
gboolean pushed;
/* the return of the latest push */
GstFlowReturn flow_return;
GstTagList *tags;
guint event_id;
};
static GstStaticPadTemplate src_template =
GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
);
static GstStaticPadTemplate program_template =
GST_STATIC_PAD_TEMPLATE ("program_%d", GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ")
);
enum
{
ARG_0,
PROP_PROGRAM_NUMBERS,
/* FILL ME */
};
static void
mpegts_parse_program_started (MpegTSBase * base, MpegTSBaseProgram * program);
static void
mpegts_parse_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program);
static GstFlowReturn
mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
MpegTSPacketizerSection * section);
static void mpegts_parse_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void mpegts_parse_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void mpegts_parse_finalize (GObject * object);
static MpegTSParsePad *mpegts_parse_create_tspad (MpegTSParse2 * parse,
const gchar * name);
static void mpegts_parse_destroy_tspad (MpegTSParse2 * parse,
MpegTSParsePad * tspad);
static GstPad *mpegts_parse_activate_program (MpegTSParse2 * parse,
MpegTSParseProgram * program);
static void mpegts_parse_reset_selected_programs (MpegTSParse2 * parse,
gchar * programs);
static void mpegts_parse_pad_removed (GstElement * element, GstPad * pad);
static GstPad *mpegts_parse_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name);
static void mpegts_parse_release_pad (GstElement * element, GstPad * pad);
static gboolean mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query);
static gboolean push_event (MpegTSBase * base, GstEvent * event);
GST_BOILERPLATE (MpegTSParse2, mpegts_parse, MpegTSBase, GST_TYPE_MPEGTS_BASE);
static void
mpegts_parse_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&program_template));
gst_element_class_set_details_simple (element_class,
"MPEG transport stream parser", "Codec/Parser",
"Parses MPEG2 transport streams",
"Alessandro Decina <alessandro@nnva.org>, "
"Zaheer Abbas Merali <zaheerabbas at merali dot org>");
}
static void
mpegts_parse_class_init (MpegTSParse2Class * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
MpegTSBaseClass *ts_class;
element_class = GST_ELEMENT_CLASS (klass);
element_class->pad_removed = mpegts_parse_pad_removed;
element_class->request_new_pad = mpegts_parse_request_new_pad;
element_class->release_pad = mpegts_parse_release_pad;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = mpegts_parse_set_property;
gobject_class->get_property = mpegts_parse_get_property;
gobject_class->finalize = mpegts_parse_finalize;
g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBERS,
g_param_spec_string ("program-numbers",
"Program Numbers",
"Colon separated list of programs", "",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
ts_class = GST_MPEGTS_BASE_CLASS (klass);
ts_class->push = GST_DEBUG_FUNCPTR (mpegts_parse_push);
ts_class->push_event = GST_DEBUG_FUNCPTR (push_event);
ts_class->program_started = GST_DEBUG_FUNCPTR (mpegts_parse_program_started);
ts_class->program_stopped = GST_DEBUG_FUNCPTR (mpegts_parse_program_stopped);
}
static void
mpegts_parse_init (MpegTSParse2 * parse, MpegTSParse2Class * klass)
{
parse->need_sync_program_pads = FALSE;
parse->program_numbers = g_strdup ("");
parse->pads_to_add = NULL;
parse->pads_to_remove = NULL;
GST_MPEGTS_BASE (parse)->program_size = sizeof (MpegTSParseProgram);
}
static void
mpegts_parse_finalize (GObject * object)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (object);
g_free (parse->program_numbers);
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
mpegts_parse_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (object);
switch (prop_id) {
case PROP_PROGRAM_NUMBERS:
mpegts_parse_reset_selected_programs (parse, g_value_dup_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
mpegts_parse_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (object);
switch (prop_id) {
case PROP_PROGRAM_NUMBERS:
g_value_set_string (value, parse->program_numbers);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static GstPad *
mpegts_parse_activate_program (MpegTSParse2 * parse,
MpegTSParseProgram * program)
{
MpegTSParsePad *tspad;
gchar *pad_name;
pad_name =
g_strdup_printf ("program_%d",
((MpegTSBaseProgram *) program)->program_number);
tspad = mpegts_parse_create_tspad (parse, pad_name);
tspad->program_number = ((MpegTSBaseProgram *) program)->program_number;
tspad->program = program;
program->tspad = tspad;
g_free (pad_name);
gst_pad_set_active (tspad->pad, TRUE);
program->active = TRUE;
return tspad->pad;
}
static gboolean
push_event (MpegTSBase * base, GstEvent * event)
{
MpegTSParse2 *parse = (MpegTSParse2 *) base;
GList *tmp;
for (tmp = GST_ELEMENT_CAST (parse)->srcpads; tmp; tmp = tmp->next) {
GstPad *pad = (GstPad *) tmp->data;
if (pad) {
gst_event_ref (event);
gst_pad_push_event (pad, event);
}
}
return TRUE;
}
static GstPad *
mpegts_parse_deactivate_program (MpegTSParse2 * parse,
MpegTSParseProgram * program)
{
MpegTSParsePad *tspad;
tspad = program->tspad;
gst_pad_set_active (tspad->pad, FALSE);
program->active = FALSE;
/* tspad will be destroyed in GstElementClass::pad_removed */
return tspad->pad;
}
static void
mpegts_parse_sync_program_pads (MpegTSParse2 * parse)
{
GList *walk;
GST_INFO_OBJECT (parse, "begin sync pads");
for (walk = parse->pads_to_remove; walk; walk = walk->next)
gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
for (walk = parse->pads_to_add; walk; walk = walk->next)
gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
if (parse->pads_to_add)
g_list_free (parse->pads_to_add);
if (parse->pads_to_remove)
g_list_free (parse->pads_to_remove);
GST_OBJECT_LOCK (parse);
parse->pads_to_remove = NULL;
parse->pads_to_add = NULL;
parse->need_sync_program_pads = FALSE;
GST_OBJECT_UNLOCK (parse);
GST_INFO_OBJECT (parse, "end sync pads");
}
static void
foreach_program_activate_or_deactivate (gpointer key, gpointer value,
gpointer data)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (data);
MpegTSParseProgram *program = (MpegTSParseProgram *) value;
/* at this point selected programs have program->selected == 2,
* unselected programs thay may have to be deactivated have selected == 1 and
* unselected inactive programs have selected == 0 */
switch (--program->selected) {
case 1:
/* selected */
if (!program->active
&& ((MpegTSBaseProgram *) program)->pmt_pid != G_MAXUINT16)
parse->pads_to_add =
g_list_append (parse->pads_to_add,
mpegts_parse_activate_program (parse, program));
else {
program->selected = 2;
}
break;
case 0:
/* unselected */
if (program->active)
parse->pads_to_remove = g_list_append (parse->pads_to_remove,
mpegts_parse_deactivate_program (parse, program));
break;
case -1:
/* was already unselected */
program->selected = 0;
break;
default:
g_return_if_reached ();
}
}
static void
mpegts_parse_reset_selected_programs (MpegTSParse2 * parse,
gchar * program_numbers)
{
GST_OBJECT_LOCK (parse);
if (parse->program_numbers)
g_free (parse->program_numbers);
parse->program_numbers = program_numbers;
if (*parse->program_numbers != '\0') {
gint program_number;
MpegTSParseProgram *program;
gchar **progs, **walk;
progs = g_strsplit (parse->program_numbers, ":", 0);
walk = progs;
while (*walk != NULL) {
program_number = strtol (*walk, NULL, 0);
program =
(MpegTSParseProgram *) mpegts_base_get_program ((MpegTSBase *) parse,
program_number);
if (program == NULL)
/* create the program, it will get activated once we get a PMT for it */
program = (MpegTSParseProgram *) mpegts_base_add_program ((MpegTSBase *)
parse, program_number, G_MAXUINT16);
program->selected = 2;
++walk;
}
g_strfreev (progs);
}
g_hash_table_foreach (((MpegTSBase *) parse)->programs,
foreach_program_activate_or_deactivate, parse);
if (parse->pads_to_remove || parse->pads_to_add)
parse->need_sync_program_pads = TRUE;
GST_OBJECT_UNLOCK (parse);
}
static MpegTSParsePad *
mpegts_parse_create_tspad (MpegTSParse2 * parse, const gchar * pad_name)
{
GstPad *pad;
MpegTSParsePad *tspad;
pad = gst_pad_new_from_static_template (&program_template, pad_name);
gst_pad_set_query_function (pad,
GST_DEBUG_FUNCPTR (mpegts_parse_src_pad_query));
/* create our wrapper */
tspad = g_new0 (MpegTSParsePad, 1);
tspad->pad = pad;
tspad->program_number = -1;
tspad->program = NULL;
tspad->pushed = FALSE;
tspad->flow_return = GST_FLOW_NOT_LINKED;
gst_pad_set_element_private (pad, tspad);
return tspad;
}
static void
mpegts_parse_destroy_tspad (MpegTSParse2 * parse, MpegTSParsePad * tspad)
{
if (tspad->tags) {
gst_tag_list_free (tspad->tags);
}
/* free the wrapper */
g_free (tspad);
}
static void
mpegts_parse_pad_removed (GstElement * element, GstPad * pad)
{
MpegTSParsePad *tspad;
MpegTSParse2 *parse = GST_MPEGTS_PARSE (element);
if (gst_pad_get_direction (pad) == GST_PAD_SINK)
return;
tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad);
mpegts_parse_destroy_tspad (parse, tspad);
if (GST_ELEMENT_CLASS (parent_class)->pad_removed)
GST_ELEMENT_CLASS (parent_class)->pad_removed (element, pad);
}
static GstPad *
mpegts_parse_request_new_pad (GstElement * element, GstPadTemplate * template,
const gchar * unused)
{
MpegTSParse2 *parse;
gchar *name;
GstPad *pad;
g_return_val_if_fail (template != NULL, NULL);
g_return_val_if_fail (GST_IS_MPEGTS_PARSE (element), NULL);
parse = GST_MPEGTS_PARSE (element);
GST_OBJECT_LOCK (element);
name = g_strdup_printf ("src%d", parse->req_pads++);
GST_OBJECT_UNLOCK (element);
pad = mpegts_parse_create_tspad (parse, name)->pad;
gst_pad_set_active (pad, TRUE);
gst_element_add_pad (element, pad);
g_free (name);
return pad;
}
static void
mpegts_parse_release_pad (GstElement * element, GstPad * pad)
{
g_return_if_fail (GST_IS_MPEGTS_PARSE (element));
gst_pad_set_active (pad, FALSE);
/* we do the cleanup in GstElement::pad-removed */
gst_element_remove_pad (element, pad);
}
static GstFlowReturn
mpegts_parse_tspad_push_section (MpegTSParse2 * parse, MpegTSParsePad * tspad,
MpegTSPacketizerSection * section, GstBuffer * buffer)
{
GstFlowReturn ret = GST_FLOW_NOT_LINKED;
gboolean to_push = TRUE;
if (tspad->program_number != -1) {
if (tspad->program) {
/* we push all sections to all pads except PMTs which we
* only push to pads meant to receive that program number */
if (section->table_id == 0x02) {
/* PMT */
if (section->subtable_extension != tspad->program_number)
to_push = FALSE;
}
} else {
/* there's a program filter on the pad but the PMT for the program has not
* been parsed yet, ignore the pad until we get a PMT */
to_push = FALSE;
ret = GST_FLOW_OK;
}
}
GST_DEBUG_OBJECT (parse,
"pushing section: %d program number: %d table_id: %d", to_push,
tspad->program_number, section->table_id);
if (to_push) {
ret = gst_pad_push (tspad->pad, buffer);
} else {
gst_buffer_unref (buffer);
if (gst_pad_is_linked (tspad->pad))
ret = GST_FLOW_OK;
}
return ret;
}
static GstFlowReturn
mpegts_parse_tspad_push (MpegTSParse2 * parse, MpegTSParsePad * tspad,
guint16 pid, GstBuffer * buffer)
{
GstFlowReturn ret = GST_FLOW_NOT_LINKED;
MpegTSBaseStream **pad_pids = NULL;
if (tspad->program_number != -1) {
if (tspad->program) {
MpegTSBaseProgram *bp = (MpegTSBaseProgram *) tspad->program;
pad_pids = bp->streams;
if (bp->tags) {
gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse), tspad->pad,
bp->tags);
bp->tags = NULL;
}
} else {
/* there's a program filter on the pad but the PMT for the program has not
* been parsed yet, ignore the pad until we get a PMT */
gst_buffer_unref (buffer);
ret = GST_FLOW_OK;
goto out;
}
}
if (pad_pids == NULL || pad_pids[pid]) {
/* push if there's no filter or if the pid is in the filter */
ret = gst_pad_push (tspad->pad, buffer);
} else {
gst_buffer_unref (buffer);
if (gst_pad_is_linked (tspad->pad))
ret = GST_FLOW_OK;
}
out:
return ret;
}
static void
pad_clear_for_push (GstPad * pad, MpegTSParse2 * parse)
{
MpegTSParsePad *tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad);
tspad->flow_return = GST_FLOW_NOT_LINKED;
tspad->pushed = FALSE;
}
static GstFlowReturn
mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
MpegTSPacketizerSection * section)
{
MpegTSParse2 *parse = (MpegTSParse2 *) base;
guint32 pads_cookie;
gboolean done = FALSE;
GstPad *pad = NULL;
MpegTSParsePad *tspad;
guint16 pid;
GstBuffer *buffer;
GstFlowReturn ret;
GList *srcpads;
if (G_UNLIKELY (parse->need_sync_program_pads))
mpegts_parse_sync_program_pads (parse);
pid = packet->pid;
buffer = gst_buffer_make_metadata_writable (packet->buffer);
/* we have the same caps on all the src pads */
gst_buffer_set_caps (buffer, base->packetizer->caps);
GST_OBJECT_LOCK (parse);
/* clear tspad->pushed on pads */
g_list_foreach (GST_ELEMENT_CAST (parse)->srcpads,
(GFunc) pad_clear_for_push, parse);
if (GST_ELEMENT_CAST (parse)->srcpads)
ret = GST_FLOW_NOT_LINKED;
else
ret = GST_FLOW_OK;
/* Get cookie and source pads list */
pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
srcpads = GST_ELEMENT_CAST (parse)->srcpads;
if (G_LIKELY (srcpads)) {
pad = GST_PAD_CAST (srcpads->data);
g_object_ref (pad);
}
GST_OBJECT_UNLOCK (parse);
while (pad && !done) {
tspad = gst_pad_get_element_private (pad);
if (G_LIKELY (!tspad->pushed)) {
/* ref the buffer as gst_pad_push takes a ref but we want to reuse the
* same buffer for next pushes */
gst_buffer_ref (buffer);
if (section) {
tspad->flow_return =
mpegts_parse_tspad_push_section (parse, tspad, section, buffer);
} else {
tspad->flow_return =
mpegts_parse_tspad_push (parse, tspad, pid, buffer);
}
tspad->pushed = TRUE;
if (G_UNLIKELY (tspad->flow_return != GST_FLOW_OK
&& tspad->flow_return != GST_FLOW_NOT_LINKED)) {
/* return the error upstream */
ret = tspad->flow_return;
done = TRUE;
}
}
if (ret == GST_FLOW_NOT_LINKED)
ret = tspad->flow_return;
g_object_unref (pad);
if (G_UNLIKELY (!done)) {
GST_OBJECT_LOCK (parse);
if (G_UNLIKELY (pads_cookie != GST_ELEMENT_CAST (parse)->pads_cookie)) {
/* resync */
GST_DEBUG ("resync");
pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
srcpads = GST_ELEMENT_CAST (parse)->srcpads;
} else {
GST_DEBUG ("getting next pad");
/* Get next pad */
srcpads = g_list_next (srcpads);
}
if (srcpads) {
pad = GST_PAD_CAST (srcpads->data);
g_object_ref (pad);
} else
done = TRUE;
GST_OBJECT_UNLOCK (parse);
}
}
gst_buffer_unref (buffer);
packet->buffer = NULL;
return ret;
}
static void
mpegts_parse_program_started (MpegTSBase * base, MpegTSBaseProgram * program)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (base);
MpegTSParseProgram *parseprogram = (MpegTSParseProgram *) program;
if (parseprogram->selected == 2) {
parse->pads_to_add =
g_list_append (parse->pads_to_add,
mpegts_parse_activate_program (parse, parseprogram));
parseprogram->selected = 1;
parse->need_sync_program_pads = TRUE;
}
}
static void
mpegts_parse_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (base);
MpegTSParseProgram *parseprogram = (MpegTSParseProgram *) program;
if (parseprogram->active) {
parse->pads_to_remove =
g_list_append (parse->pads_to_remove,
mpegts_parse_deactivate_program (parse, parseprogram));
parse->need_sync_program_pads = TRUE;
}
}
static gboolean
mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query)
{
MpegTSParse2 *parse = GST_MPEGTS_PARSE (gst_pad_get_parent (pad));
gboolean res;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:
{
if ((res = gst_pad_peer_query (((MpegTSBase *) parse)->sinkpad, query))) {
gboolean is_live;
GstClockTime min_latency, max_latency;
gst_query_parse_latency (query, &is_live, &min_latency, &max_latency);
if (is_live) {
min_latency += TS_LATENCY * GST_MSECOND;
if (max_latency != GST_CLOCK_TIME_NONE)
max_latency += TS_LATENCY * GST_MSECOND;
}
gst_query_set_latency (query, is_live, min_latency, max_latency);
}
break;
}
default:
res = gst_pad_query_default (pad, query);
}
gst_object_unref (parse);
return res;
}
gboolean
gst_mpegtsparse_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (mpegts_parse_debug, "tsparse", 0,
"MPEG transport stream parser");
gst_mpegtsdesc_init_debug ();
return gst_element_register (plugin, "tsparse",
GST_RANK_NONE, GST_TYPE_MPEGTS_PARSE);
}

View file

@ -0,0 +1,71 @@
/*
* mpegts_parse.h - GStreamer MPEG transport stream parser
* Copyright (C) 2007 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef GST_MPEG_TS_PARSE_H
#define GST_MPEG_TS_PARSE_H
#include <gst/gst.h>
#include "mpegtsbase.h"
#include "mpegtspacketizer.h"
G_BEGIN_DECLS
#define GST_TYPE_MPEGTS_PARSE \
(mpegts_parse_get_type())
#define GST_MPEGTS_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEGTS_PARSE,MpegTSParse2))
#define GST_MPEGTS_PARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEGTS_PARSE,MpegTSParse2Class))
#define GST_IS_MPEGTS_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEGTS_PARSE))
#define GST_IS_MPEGTS_PARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEGTS_PARSE))
typedef struct _MpegTSParse2 MpegTSParse2;
typedef struct _MpegTSParse2Class MpegTSParse2Class;
struct _MpegTSParse2 {
MpegTSBase parent;
/* the following vars must be protected with the OBJECT_LOCK as they can be
* accessed from the application thread and the streaming thread */
gchar *program_numbers;
GList *pads_to_add;
GList *pads_to_remove;
guint req_pads;
gboolean need_sync_program_pads;
};
struct _MpegTSParse2Class {
MpegTSBaseClass parent_class;
};
GType mpegts_parse_get_type(void);
gboolean gst_mpegtsparse_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* GST_MPEG_TS_PARSE_H */

1491
gst/mpegtsdemux/tsdemux.c Normal file

File diff suppressed because it is too large Load diff

78
gst/mpegtsdemux/tsdemux.h Normal file
View file

@ -0,0 +1,78 @@
/*
* tsdemux - GStreamer MPEG transport stream demuxer
* Copyright (C) 2009 Zaheer Abbas Merali
* 2010 Edward Hervey
*
* Authors:
* Zaheer Abbas Merali <zaheerabbas at merali dot org>
* Edward Hervey <edward.hervey@collabora.co.uk>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef GST_TS_DEMUX_H
#define GST_TS_DEMUX_H
#include <gst/gst.h>
#include <gst/base/gstbytereader.h>
#include "mpegtsbase.h"
#include "mpegtspacketizer.h"
G_BEGIN_DECLS
#define GST_TYPE_TS_DEMUX \
(gst_ts_demux_get_type())
#define GST_TS_DEMUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TS_DEMUX,GstTSDemux))
#define GST_TS_DEMUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TS_DEMUX,GstTSDemuxClass))
#define GST_IS_TS_DEMUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TS_DEMUX))
#define GST_IS_TS_DEMUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TS_DEMUX))
#define GST_TS_DEMUX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TS_DEMUX, GstTSDemuxClass))
#define GST_TS_DEMUX_CAST(obj) ((GstTSDemux*) obj)
typedef struct _GstTSDemux GstTSDemux;
typedef struct _GstTSDemuxClass GstTSDemuxClass;
struct _GstTSDemux
{
MpegTSBase parent;
/* the following vars must be protected with the OBJECT_LOCK as they can be
* accessed from the application thread and the streaming thread */
guint program_number; /* Required program number (ignore:-1) */
gboolean emit_statistics;
/*< private >*/
MpegTSBaseProgram *program; /* Current program */
guint current_program_number;
gboolean need_newsegment;
GstClockTime duration; /* Total duration */
};
struct _GstTSDemuxClass
{
MpegTSBaseClass parent_class;
};
GType gst_ts_demux_get_type (void);
gboolean gst_ts_demux_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* GST_TS_DEMUX_H */