configure.ac: Check for libdvdnav to build resindvd.

Original commit message from CVS:
* configure.ac:
Check for libdvdnav to build resindvd.
* ext/Makefile.am:
* ext/resindvd/Makefile.am:
* ext/resindvd/gstmpegdefs.h:
* ext/resindvd/gstmpegdemux.c:
* ext/resindvd/gstmpegdemux.h:
* ext/resindvd/gstmpegdesc.c:
* ext/resindvd/gstmpegdesc.h:
* ext/resindvd/gstpesfilter.c:
* ext/resindvd/gstpesfilter.h:
* ext/resindvd/plugin.c:
* ext/resindvd/resin-play:
* ext/resindvd/resindvdbin.c:
* ext/resindvd/resindvdbin.h:
* ext/resindvd/resindvdsrc.c:
* ext/resindvd/resindvdsrc.h:
* ext/resindvd/rsnaudiomunge.c:
* ext/resindvd/rsnaudiomunge.h:
* ext/resindvd/rsnbasesrc.c:
* ext/resindvd/rsnbasesrc.h:
* ext/resindvd/rsnpushsrc.c:
* ext/resindvd/rsnpushsrc.h:
* ext/resindvd/rsnstreamselector.c:
* ext/resindvd/rsnstreamselector.h:
First commit of DVD-Video playback component 'rsndvdbin'
and helper elements.
Use --enable-experimental for now, but feel free to give it a
try using the resin-play script.
* gst/dvdspu/gstdvdspu.c:
Add some extra guards for malformed events.
This commit is contained in:
Jan Schmidt 2008-06-17 01:08:14 +00:00
parent bcc41766b8
commit 0951e00dc0
26 changed files with 10061 additions and 0 deletions

View file

@ -1,3 +1,41 @@
2008-06-17 Jan Schmidt <thaytan@noraisin.net>
* configure.ac:
Check for libdvdnav to build resindvd.
* ext/Makefile.am:
* ext/resindvd/Makefile.am:
* ext/resindvd/gstmpegdefs.h:
* ext/resindvd/gstmpegdemux.c:
* ext/resindvd/gstmpegdemux.h:
* ext/resindvd/gstmpegdesc.c:
* ext/resindvd/gstmpegdesc.h:
* ext/resindvd/gstpesfilter.c:
* ext/resindvd/gstpesfilter.h:
* ext/resindvd/plugin.c:
* ext/resindvd/resin-play:
* ext/resindvd/resindvdbin.c:
* ext/resindvd/resindvdbin.h:
* ext/resindvd/resindvdsrc.c:
* ext/resindvd/resindvdsrc.h:
* ext/resindvd/rsnaudiomunge.c:
* ext/resindvd/rsnaudiomunge.h:
* ext/resindvd/rsnbasesrc.c:
* ext/resindvd/rsnbasesrc.h:
* ext/resindvd/rsnpushsrc.c:
* ext/resindvd/rsnpushsrc.h:
* ext/resindvd/rsnstreamselector.c:
* ext/resindvd/rsnstreamselector.h:
First commit of DVD-Video playback component 'rsndvdbin'
and helper elements.
Use --enable-experimental for now, but feel free to give it a
try using the resin-play script.
* gst/dvdspu/gstdvdspu.c:
Add some extra guards for malformed events.
2008-06-16 David Schleef <ds@schleef.org>
* configure.ac:

View file

@ -477,6 +477,38 @@ return 0;
fi
])
dnl *** dvdnav for resindvd ***
USE_DVDNAV=$BUILD_EXPERIMENTAL
translit(dnm, m, l) AM_CONDITIONAL(USE_DVDNAV, true)
AG_GST_CHECK_FEATURE(DVDNAV, [dvdnav library], resindvd, [
translit(dnm, m, l) AC_SUBST(DVDNAV_LIBS)
translit(dnm, m, l) AC_SUBST(DVDNAV_CFLAGS)
AG_GST_CHECK_CONFIGPROG(DVDNAV, dvdnav-config)
if test x"$HAVE_DVDNAV" = x"yes"; then
dnl check version
DVDNAV_VERSION=`dvdnav-config --version|head -n 1|sed 's/^.*) //'|sed 's/ (.*)//'`
DVDNAV_MAJOR=`echo $DVDNAV_VERSION | cut -d. -f1 | sed s/[a-zA-Z\-].*//g`
DVDNAV_MINOR=`echo $DVDNAV_VERSION | cut -d. -f2 | sed s/[a-zA-Z\-].*//g`
DVDNAV_MICRO=`echo $DVDNAV_VERSION | cut -d. -f3 | sed s/[a-zA-Z\-].*//g`
if [[ "$DVDNAV_MAJOR" -eq "0" ]] && \
[[ "$DVDNAV_MINOR" -lt "1" ]]; then
AC_MSG_WARN([libdvdnav >= 0.1.7 is required, you have $DVDNAV_VERSION])
HAVE_DVDNAV="no"
elif [[ "$DVDNAV_MAJOR" -eq "0" ]] && \
[[ "$DVDNAV_MINOR" -eq "1" ]] && \
[[ "$DVDNAV_MICRO" -lt "7" ]]; then
AC_MSG_WARN([libdvdnav >= 0.1.7 is required, you have $DVDNAV_VERSION])
HAVE_DVDNAV="no"
fi
fi
dnl now check for dvdread/nav_print.h - see #133002
AC_CHECK_HEADER(dvdread/nav_print.h, , [
AC_MSG_WARN([header dvdread/nav_print.h from dvdread missing])
HAVE_DVDNAV="no"
])
AS_SCRUB_INCLUDE(DVDNAV_CFLAGS)
])
dnl *** METADATA ***
translit(dnm, m, l) AM_CONDITIONAL(USE_METADATA, true)
AG_GST_CHECK_FEATURE(METADATA, [METADATA muxer and demuxer], metadata, [
@ -1225,6 +1257,7 @@ ext/musicbrainz/Makefile
ext/mythtv/Makefile
ext/neon/Makefile
ext/ofa/Makefile
ext/resindvd/Makefile
ext/sdl/Makefile
ext/sndfile/Makefile
ext/soundtouch/Makefile

View file

@ -76,6 +76,12 @@ else
DTS_DIR=
endif
if USE_DVDNAV
DVDNAV_DIR = resindvd
else
DVDNAV_DIR =
endif
if USE_FAAC
FAAC_DIR=faac
else

30
ext/resindvd/Makefile.am Normal file
View file

@ -0,0 +1,30 @@
# plugindir is set in configure
plugin_LTLIBRARIES = libresindvd.la
libresindvd_la_SOURCES = \
plugin.c \
resindvdbin.c \
rsnaudiomunge.c \
rsnbasesrc.c \
rsnpushsrc.c \
rsnstreamselector.c \
resindvdsrc.c \
gstmpegdesc.c \
gstmpegdemux.c \
gstpesfilter.c
libresindvd_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(DVDNAV_CFLAGS)
libresindvd_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(DVDNAV_LIBS)
libresindvd_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = resindvdbin.h \
rsnaudiomunge.h \
rsnbasesrc.h \
rsnpushsrc.h \
rsnstreamselector.h \
resindvdsrc.h \
gstmpegdefs.h \
gstmpegdesc.h \
gstmpegdemux.h \
gstpesfilter.h

175
ext/resindvd/gstmpegdefs.h Normal file
View file

@ -0,0 +1,175 @@
/*
* 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>
* Jan Schmidt <thaytan@noraisin.net>
*/
#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
/* 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 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
/* some extra GstFlowReturn values used internally */
#define GST_FLOW_NEED_MORE_DATA -100
#define GST_FLOW_LOST_SYNC -101
#endif /* __GST_MPEG_DEFS_H__ */

1943
ext/resindvd/gstmpegdemux.c Normal file

File diff suppressed because it is too large Load diff

127
ext/resindvd/gstmpegdemux.h Normal file
View file

@ -0,0 +1,127 @@
/*
* 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>
* Jan Schmidt <thaytan@noraisin.net>
*/
#ifndef __GST_FLUPS_DEMUX_H__
#define __GST_FLUPS_DEMUX_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "gstpesfilter.h"
G_BEGIN_DECLS
#define GST_TYPE_FLUPS_DEMUX (gst_flups_demux_get_type())
#define GST_FLUPS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLUPS_DEMUX,GstFluPSDemux))
#define GST_FLUPS_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLUPS_DEMUX,GstFluPSDemuxClass))
#define GST_FLUPS_DEMUX_GET_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS((klass),GST_TYPE_FLUPS_DEMUX,GstFluPSDemuxClass))
#define GST_IS_FLUPS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLUPS_DEMUX))
#define GST_IS_FLUPS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLUPS_DEMUX))
typedef struct _GstFluPSStream GstFluPSStream;
typedef struct _GstFluPSDemux GstFluPSDemux;
typedef struct _GstFluPSDemuxClass GstFluPSDemuxClass;
#define GST_FLUPS_DEMUX_MAX_STREAMS 256
#define GST_FLUPS_DEMUX_MAX_PSM 256
typedef enum {
STATE_FLUPS_DEMUX_NEED_SYNC,
STATE_FLUPS_DEMUX_SYNCED,
STATE_FLUPS_DEMUX_NEED_MORE_DATA,
} GstFluPSDemuxState;
/* Information associated with a single FluPS stream. */
struct _GstFluPSStream {
GstPad * pad;
gint id;
gint type;
gint size_bound;
gboolean discont;
gboolean notlinked;
gboolean need_segment;
GstClockTime last_ts;
};
struct _GstFluPSDemux {
GstElement parent;
GstPad * sinkpad;
GstAdapter * adapter;
GstAdapter * rev_adapter;
guint64 adapter_offset;
guint32 last_sync_code;
GstPESFilter filter;
gint64 mux_rate;
guint64 first_scr;
guint64 first_dts;
guint64 base_time;
guint64 current_scr;
guint64 next_scr;
guint64 bytes_since_scr;
gint64 scr_adjust;
guint64 scr_rate_n;
guint64 scr_rate_d;
guint64 first_scr_offset;
guint64 last_scr_offset;
gint16 psm[GST_FLUPS_DEMUX_MAX_PSM];
GstSegment sink_segment;
GstSegment src_segment;
/* stream output */
GstFluPSStream * current_stream;
guint64 next_pts;
guint64 next_dts;
GstFluPSStream ** streams;
gboolean need_no_more_pads;
/* Indicates an MPEG-2 stream */
gboolean is_mpeg2_pack;
/* Language codes event is stored when a dvd-lang-codes
* custom event arrives from upstream */
GstEvent * lang_codes;
};
struct _GstFluPSDemuxClass {
GstElementClass parent_class;
GstPadTemplate *sink_template;
GstPadTemplate *video_template;
GstPadTemplate *audio_template;
GstPadTemplate *private_template;
GstPadTemplate *subpicture_template;
};
GType gst_flups_demux_get_type (void);
gboolean gst_flups_demux_plugin_init (GstPlugin *plugin);
G_END_DECLS
#endif /* __GST_FLUPS_DEMUX_H__ */

156
ext/resindvd/gstmpegdesc.c Normal file
View file

@ -0,0 +1,156 @@
/*
* 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>
* Jan Schmidt <thaytan@noraisin.net>
*/
#include <string.h>
#include <gst/gst.h>
#include "gstmpegdesc.h"
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;
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)
{
gint 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;
}
guint8 *
gst_mpeg_descriptor_nth (GstMPEGDescriptor * desc, guint i)
{
gint 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;
}

249
ext/resindvd/gstmpegdesc.h Normal file
View file

@ -0,0 +1,249 @@
/*
* 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>
* Jan Schmidt <thaytan@noraisin.net>
*/
#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_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 */
/* 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)
typedef struct {
guint n_desc;
guint8 data_length;
guint8 *data;
} GstMPEGDescriptor;
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);
guint8* gst_mpeg_descriptor_nth (GstMPEGDescriptor *desc, guint i);
#endif /* __GST_MPEG_DESC_H__ */

623
ext/resindvd/gstpesfilter.c Normal file
View file

@ -0,0 +1,623 @@
/*
* 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>
* Jan Schmidt <thaytan@noraisin.net>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstmpegdefs.h"
#include "gstpesfilter.h"
GST_DEBUG_CATEGORY (gstflupesfilter_debug);
#define GST_CAT_DEFAULT (gstflupesfilter_debug)
static GstFlowReturn gst_pes_filter_data_push (GstPESFilter * filter,
gboolean first, GstBuffer * buffer);
#define ADAPTER_OFFSET_FLUSH(_bytes_) if (filter->adapter_offset) *filter->adapter_offset = *filter->adapter_offset + (_bytes_)
/* May pass null for adapter to have the filter create one */
void
gst_pes_filter_init (GstPESFilter * filter, GstAdapter * adapter,
guint64 * adapter_offset)
{
g_return_if_fail (filter != NULL);
if (adapter != NULL)
g_object_ref (adapter);
else
adapter = gst_adapter_new ();
filter->adapter = adapter;
filter->adapter_offset = adapter_offset;
filter->state = STATE_HEADER_PARSE;
filter->gather_pes = FALSE;
filter->allow_unbounded = FALSE;
}
void
gst_pes_filter_uninit (GstPESFilter * filter)
{
g_return_if_fail (filter != NULL);
if (filter->adapter)
g_object_unref (filter->adapter);
filter->adapter = NULL;
filter->adapter_offset = NULL;
}
void
gst_pes_filter_set_callbacks (GstPESFilter * filter,
GstPESFilterData data_cb, GstPESFilterResync resync_cb, gpointer user_data)
{
g_return_if_fail (filter != NULL);
filter->data_cb = data_cb;
filter->resync_cb = resync_cb;
filter->user_data = user_data;
}
/* 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;
static gboolean
gst_pes_filter_is_sync (guint32 sync)
{
return ((sync & 0xfffffffc) == 0x000001bc) ||
((sync & 0xffffffe0) == 0x000001c0) ||
((sync & 0xfffffff0) == 0x000001f0) ||
((sync & 0xfffffff0) == 0x000001e0);
}
static GstFlowReturn
gst_pes_filter_parse (GstPESFilter * filter)
{
GstFlowReturn ret;
guint32 start_code;
gboolean STD_buffer_bound_scale;
guint16 STD_buffer_size_bound;
const guint8 *data;
gint avail, datalen;
gboolean have_size = FALSE;
/* read start code and length */
if (!(data = gst_adapter_peek (filter->adapter, 6)))
goto need_more_data;
/* get start code */
start_code = GST_READ_UINT32_BE (data);
if (!gst_pes_filter_is_sync (start_code))
goto lost_sync;
filter->start_code = start_code;
filter->id = data[3];
/* skip start code */
data += 4;
/* start parsing length */
filter->length = GST_READ_UINT16_BE (data);
/* see how much is available */
avail = gst_adapter_available (filter->adapter);
GST_DEBUG ("id 0x%02x length %d, avail %d start code 0x%02x", filter->id,
filter->length, avail, filter->start_code);
/* A data length of 0 indicates an unbounded packet in transport
* streams, but actually a 0 sized packet in program streams or
* for anything except video packets */
/* FIXME: Remove this hack that is checking start_code. Instead, we need
* a callback that a start_code has been collected, giving the caller a chance
* to set the allow_unbounded flag if they want */
if (filter->length == 0 &&
((filter->start_code & 0xFFFFFFF0) == PACKET_VIDEO_START_CODE ||
filter->allow_unbounded)) {
GST_DEBUG ("id 0x%02x, unbounded length", filter->id);
filter->unbounded_packet = TRUE;
} else {
filter->unbounded_packet = FALSE;
if (filter->gather_pes && avail < filter->length + 6) {
GST_DEBUG ("id 0x%02x, bounded length %d, only have %d",
filter->id, filter->length + 6, avail);
goto need_more_data;
}
/* if we need more data from now on, we lost sync */
avail = MIN (avail, filter->length + 6);
}
/* read more data, either the whole packet if there is a length
* or whatever we have available if this in an unbounded packet. */
if (!(data = gst_adapter_peek (filter->adapter, avail)))
goto need_more_data;
/* This will make us flag LOST_SYNC if we run out of data from here onward */
have_size = TRUE;
/* skip start code and length */
data += 6;
datalen = avail - 6;
GST_DEBUG ("datalen %d", datalen);
switch (filter->start_code) {
case ID_PS_PROGRAM_STREAM_MAP:
case ID_PRIVATE_STREAM_2:
case ID_ECM_STREAM:
case ID_EMM_STREAM:
case ID_PROGRAM_STREAM_DIRECTORY:
case ID_DSMCC_STREAM:
case ID_ITU_TREC_H222_TYPE_E_STREAM:
goto skip;
case ID_PADDING_STREAM:
GST_DEBUG ("skipping padding stream");
goto skip;
default:
break;
}
if (datalen < 1)
goto need_more_data;
filter->pts = filter->dts = -1;
/* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
* not triggered. */
while (TRUE) {
if (*data != 0xff)
break;
data++;
datalen--;
GST_DEBUG ("got stuffing bit");
if (datalen < 1)
goto need_more_data;
}
/* STD buffer size, never for mpeg2 */
if ((*data & 0xc0) == 0x40) {
GST_DEBUG ("have STD");
if (datalen < 3)
goto need_more_data;
STD_buffer_bound_scale = *data & 0x20;
STD_buffer_size_bound = ((guint16) (*data++ & 0x1F)) << 8;
STD_buffer_size_bound |= *data++;
datalen -= 2;
}
/* PTS but no DTS, never for mpeg2 */
if ((*data & 0xf0) == 0x20) {
GST_DEBUG ("PTS without DTS");
if (datalen < 5)
goto need_more_data;
READ_TS (data, filter->pts, lost_sync);
GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
datalen -= 5;
}
/* PTS and DTS, never for mpeg2 */
else if ((*data & 0xf0) == 0x30) {
GST_DEBUG ("PTS and DTS");
if (datalen < 10)
goto need_more_data;
READ_TS (data, filter->pts, lost_sync);
READ_TS (data, filter->dts, lost_sync);
GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
datalen -= 10;
} else if ((*data & 0xc0) == 0x80) {
/* mpeg2 case */
guchar flags;
guint8 header_data_length = 0;
GST_DEBUG ("MPEG2 PES packet");
if (datalen < 3)
goto need_more_data;
/* 2: '10'
* 2: PES_scrambling_control
* 1: PES_priority
* 1: data_alignment_indicator
* 1: copyright
* 1: original_or_copy
*/
flags = *data++;
GST_DEBUG ("flags: 0x%02x", flags);
if ((flags & 0xc0) != 0x80)
goto lost_sync;
/* check PES scrambling control */
if ((flags & 0x30) != 0)
goto encrypted;
/* 2: PTS_DTS_flags
* 1: ESCR_flag
* 1: ES_rate_flag
* 1: DSM_trick_mode_flag
* 1: additional_copy_info_flag
* 1: PES_CRC_flag
* 1: PES_extension_flag
*/
flags = *data++;
/* 8: PES_header_data_length */
header_data_length = *data++;
datalen -= 3;
GST_DEBUG ("header_data_length: %d, flags 0x%02x",
header_data_length, flags);
if (header_data_length > datalen)
goto need_more_data;
/* only DTS: this is invalid */
if ((flags & 0xc0) == 0x40)
goto lost_sync;
/* check for PTS */
if ((flags & 0x80)) {
if (datalen < 5)
goto need_more_data;
READ_TS (data, filter->pts, lost_sync);
GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
header_data_length -= 5;
datalen -= 5;
}
/* check for DTS */
if ((flags & 0x40)) {
READ_TS (data, filter->dts, lost_sync);
if (datalen < 5)
goto need_more_data;
GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
header_data_length -= 5;
datalen -= 5;
}
/* ESCR_flag */
if ((flags & 0x20)) {
GST_DEBUG ("%x ESCR found", filter->id);
if (datalen < 6)
goto need_more_data;
data += 6;
header_data_length -= 6;
datalen -= 6;
}
/* ES_rate_flag */
if ((flags & 0x10)) {
guint32 es_rate;
if (datalen < 3)
goto need_more_data;
es_rate = ((guint32) (*data++ & 0x07)) << 14;
es_rate |= ((guint32) (*data++)) << 7;
es_rate |= ((guint32) (*data++ & 0xFE)) >> 1;
GST_DEBUG ("%x ES Rate found %u", filter->id, es_rate);
header_data_length -= 3;
datalen -= 3;
}
/* DSM_trick_mode_flag */
if ((flags & 0x08)) {
guint8 trick_mode_flags;
if (datalen < 1)
goto need_more_data;
/* 3: trick_mode_control */
trick_mode_flags = *data++;
GST_DEBUG ("%x DSM trick mode found, flags 0x%02x", filter->id,
trick_mode_flags);
/* fast_forward */
if ((trick_mode_flags & 0xe0) == 0x00) {
}
/* slow motion */
else if ((trick_mode_flags & 0xe0) == 0x20) {
}
/* freeze frame */
else if ((trick_mode_flags & 0xe0) == 0x40) {
}
/* fast reverse */
else if ((trick_mode_flags & 0xe0) == 0x60) {
}
/* slow reverse */
else if ((trick_mode_flags & 0xe0) == 0x80) {
}
/* reserved */
else {
}
header_data_length -= 1;
datalen -= 1;
}
/* additional_copy_info_flag */
if ((flags & 0x04)) {
GST_DEBUG ("%x additional copy info, flags 0x%02x", filter->id, *data);
}
/* PES_CRC_flag */
if ((flags & 0x02)) {
GST_DEBUG ("%x PES_CRC", filter->id);
}
/* PES_extension_flag */
if ((flags & 0x01)) {
GST_DEBUG ("%x PES_extension", filter->id);
}
/* calculate the amount of real data in this PES packet */
data += header_data_length;
datalen -= header_data_length;
} else if (*data == 0x0f) {
/* Not sure what this clause is for */
data++;
datalen--;
} else {
/* Data byte wasn't recognised as a flags byte */
GST_DEBUG ("Unrecognised flags byte 0x%02x\n", *data);
goto lost_sync;
}
{
GstBuffer *out;
guint16 consumed;
consumed = avail - 6 - datalen;
if (filter->unbounded_packet == FALSE) {
filter->length -= avail - 6;
GST_DEBUG ("pushing %d, need %d more, consumed %d",
datalen, filter->length, consumed);
} else {
GST_DEBUG ("pushing %d, unbounded packet, consumed %d",
datalen, consumed);
}
if (datalen > 0) {
out = gst_buffer_new ();
GST_BUFFER_DATA (out) = g_memdup (data, datalen);
GST_BUFFER_SIZE (out) = datalen;
GST_BUFFER_MALLOCDATA (out) = GST_BUFFER_DATA (out);
ret = gst_pes_filter_data_push (filter, TRUE, out);
filter->first = FALSE;
} else {
GST_LOG ("first being set to TRUE");
filter->first = TRUE;
ret = GST_FLOW_OK;
}
if (filter->length > 0 || filter->unbounded_packet)
filter->state = STATE_DATA_PUSH;
}
gst_adapter_flush (filter->adapter, avail);
ADAPTER_OFFSET_FLUSH (avail);
return ret;
need_more_data:
{
if (filter->unbounded_packet == FALSE) {
if (have_size == TRUE) {
GST_DEBUG ("bounded need more data %d, lost sync",
gst_adapter_available (filter->adapter));
ret = GST_FLOW_LOST_SYNC;
} else {
GST_DEBUG ("bounded need more data %d, breaking for more",
gst_adapter_available (filter->adapter));
ret = GST_FLOW_NEED_MORE_DATA;
}
} else {
GST_DEBUG ("unbounded need more data %d",
gst_adapter_available (filter->adapter));
ret = GST_FLOW_NEED_MORE_DATA;
}
return ret;
}
skip:
{
GST_DEBUG ("skipping 0x%02x", filter->id);
gst_adapter_flush (filter->adapter, avail);
ADAPTER_OFFSET_FLUSH (avail);
filter->length -= avail - 6;
if (filter->length > 0 || filter->unbounded_packet)
filter->state = STATE_DATA_SKIP;
return GST_FLOW_OK;
}
encrypted:
{
GST_DEBUG ("skipping encrypted 0x%02x", filter->id);
gst_adapter_flush (filter->adapter, avail);
ADAPTER_OFFSET_FLUSH (avail);
filter->length -= avail - 6;
if (filter->length > 0 || filter->unbounded_packet)
filter->state = STATE_DATA_SKIP;
return GST_FLOW_OK;
}
lost_sync:
{
GST_DEBUG ("lost sync");
gst_adapter_flush (filter->adapter, 4);
ADAPTER_OFFSET_FLUSH (4);
return GST_FLOW_LOST_SYNC;
}
}
static GstFlowReturn
gst_pes_filter_data_push (GstPESFilter * filter, gboolean first,
GstBuffer * buffer)
{
GstFlowReturn ret;
GST_LOG ("pushing, first: %d", first);
if (filter->data_cb) {
ret = filter->data_cb (filter, first, buffer, filter->user_data);
} else {
gst_buffer_unref (buffer);
ret = GST_FLOW_OK;
}
return ret;
}
GstFlowReturn
gst_pes_filter_push (GstPESFilter * filter, GstBuffer * buffer)
{
GstFlowReturn ret;
g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
switch (filter->state) {
case STATE_HEADER_PARSE:
gst_adapter_push (filter->adapter, buffer);
ret = gst_pes_filter_parse (filter);
break;
case STATE_DATA_PUSH:
ret = gst_pes_filter_data_push (filter, filter->first, buffer);
filter->first = FALSE;
break;
case STATE_DATA_SKIP:
gst_buffer_unref (buffer);
ret = GST_FLOW_OK;
break;
default:
goto wrong_state;
}
return ret;
/* ERROR */
wrong_state:
{
GST_DEBUG ("wrong internal state %d", filter->state);
return GST_FLOW_ERROR;
}
}
GstFlowReturn
gst_pes_filter_process (GstPESFilter * filter)
{
GstFlowReturn ret;
gboolean skip = FALSE;
g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
switch (filter->state) {
case STATE_HEADER_PARSE:
ret = gst_pes_filter_parse (filter);
break;
case STATE_DATA_SKIP:
skip = TRUE;
/* fallthrough */
case STATE_DATA_PUSH:
if (filter->length > 0 || filter->unbounded_packet) {
gint avail;
avail = gst_adapter_available (filter->adapter);
if (filter->unbounded_packet == FALSE)
avail = MIN (avail, filter->length);
if (skip) {
gst_adapter_flush (filter->adapter, avail);
ADAPTER_OFFSET_FLUSH (avail);
ret = GST_FLOW_OK;
} else {
GstBuffer *out;
guint8 *data;
data = gst_adapter_take (filter->adapter, avail);
out = gst_buffer_new ();
GST_BUFFER_DATA (out) = data;
GST_BUFFER_SIZE (out) = avail;
GST_BUFFER_MALLOCDATA (out) = data;
ret = gst_pes_filter_data_push (filter, filter->first, out);
filter->first = FALSE;
}
if (filter->unbounded_packet == FALSE) {
filter->length -= avail;
if (filter->length == 0)
filter->state = STATE_HEADER_PARSE;
}
} else {
filter->state = STATE_HEADER_PARSE;
ret = GST_FLOW_OK;
}
break;
default:
goto wrong_state;
}
return ret;
/* ERROR */
wrong_state:
{
GST_DEBUG ("wrong internal state %d", filter->state);
return GST_FLOW_ERROR;
}
}
void
gst_pes_filter_flush (GstPESFilter * filter)
{
g_return_if_fail (filter != NULL);
if (filter->adapter) {
gst_adapter_clear (filter->adapter);
if (filter->adapter_offset)
*filter->adapter_offset = G_MAXUINT64;
}
filter->state = STATE_HEADER_PARSE;
}
GstFlowReturn
gst_pes_filter_drain (GstPESFilter * filter)
{
g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
gst_pes_filter_flush (filter);
return GST_FLOW_OK;
}

View file

@ -0,0 +1,88 @@
/*
* 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>
* Jan Schmidt <thaytan@noraisin.net>
*/
#ifndef __GST_PES_FILTER_H__
#define __GST_PES_FILTER_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
typedef struct _GstPESFilter GstPESFilter;
typedef GstFlowReturn (*GstPESFilterData) (GstPESFilter * filter, gboolean first, GstBuffer * buffer,
gpointer user_data);
typedef void (*GstPESFilterResync) (GstPESFilter * filter, gpointer user_data);
typedef void (*GstPESFilterIndex) (GstPESFilter * filter, gpointer user_data);
typedef enum {
STATE_HEADER_PARSE,
STATE_DATA_PUSH,
STATE_DATA_SKIP
} GstPESFilterState;
struct _GstPESFilter {
GstAdapter * adapter;
guint64 * adapter_offset;
GstPESFilterState state;
/* Whether to collect entire PES packets before
* outputting */
gboolean gather_pes;
/* Whether unbounded packets are allowed in this
* stream */
gboolean allow_unbounded;
gboolean first;
GstPESFilterData data_cb;
GstPESFilterResync resync_cb;
gpointer user_data;
guint32 start_code;
guint8 id;
gboolean unbounded_packet;
guint16 length;
guint8 type;
gint64 pts;
gint64 dts;
};
void gst_pes_filter_init (GstPESFilter * filter, GstAdapter * adapter, guint64 * adapter_offset);
void gst_pes_filter_uninit (GstPESFilter * filter);
void gst_pes_filter_set_callbacks (GstPESFilter * filter,
GstPESFilterData data_cb,
GstPESFilterResync resync_cb,
gpointer user_data);
GstFlowReturn gst_pes_filter_push (GstPESFilter * filter, GstBuffer * buffer);
GstFlowReturn gst_pes_filter_process (GstPESFilter * filter);
void gst_pes_filter_flush (GstPESFilter * filter);
GstFlowReturn gst_pes_filter_drain (GstPESFilter * filter);
G_END_DECLS
#endif /* __GST_PES_FILTER_H__ */

53
ext/resindvd/plugin.c Normal file
View file

@ -0,0 +1,53 @@
/* GStreamer
* Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
*
* 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 <gst/gst.h>
#include "resindvdbin.h"
#include "gstmpegdemux.h"
GST_DEBUG_CATEGORY (resindvd_debug);
#define GST_CAT_DEFAULT resindvd_debug
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean result = TRUE;
GST_DEBUG_CATEGORY_INIT (resindvd_debug, "resindvd elements",
0, "DVD playback elements from resindvd");
result &= gst_element_register (plugin, "rsndvdbin",
GST_RANK_PRIMARY, RESIN_TYPE_DVDBIN);
result &= gst_flups_demux_plugin_init (plugin);
return result;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"resindvd",
"Resin DVD playback elements",
plugin_init, VERSION, "GPL", "GStreamer", "http://gstreamer.net/")

11
ext/resindvd/resin-play Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
if [ $# -ge 1 ]; then
DEVICE_OPT="device=$1"
else
DEVICE_OPT=""
fi
gst-launch rsndvdbin name=dvd "$DEVICE_OPT" \
dvd. ! ffmpegcolorspace ! videoscale ! autovideosink \
dvd. ! audioconvert ! autoaudiosink

758
ext/resindvd/resindvdbin.c Normal file
View file

@ -0,0 +1,758 @@
/* GStreamer
* Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
*
* 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 <string.h>
#include <gst/gst.h>
#include "resindvdbin.h"
#include "resindvdsrc.h"
#include "rsnstreamselector.h"
#include "rsnaudiomunge.h"
#include "gstmpegdemux.h"
GST_DEBUG_CATEGORY_EXTERN (resindvd_debug);
#define GST_CAT_DEFAULT resindvd_debug
#define DECODEBIN_AUDIO 0
#define DVDBIN_LOCK(d) g_mutex_lock((d)->dvd_lock)
#define DVDBIN_UNLOCK(d) g_mutex_unlock((d)->dvd_lock)
#define DEFAULT_DEVICE "/dev/dvd"
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_DEVICE
};
/* FIXME: Could list specific video and audio caps: */
static GstStaticPadTemplate video_src_template =
GST_STATIC_PAD_TEMPLATE ("video",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate audio_src_template =
GST_STATIC_PAD_TEMPLATE ("audio",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS_ANY);
static void rsn_dvdbin_do_init (GType rsn_dvdbin_type);
static void rsn_dvdbin_finalize (GObject * object);
static void rsn_dvdbin_uri_handler_init (gpointer g_iface, gpointer iface_data);
GST_BOILERPLATE_FULL (RsnDvdBin, rsn_dvdbin, GstBin,
GST_TYPE_BIN, rsn_dvdbin_do_init);
static void demux_pad_added (GstElement * element, GstPad * pad,
RsnDvdBin * dvdbin);
static void viddec_pad_added (GstElement * element, GstPad * pad,
gboolean last, RsnDvdBin * dvdbin);
#if DECODEBIN_AUDIO
static void auddec_pad_added (GstElement * element, GstPad * pad,
gboolean last, RsnDvdBin * dvdbin);
#endif
static void rsn_dvdbin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void rsn_dvdbin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstStateChangeReturn rsn_dvdbin_change_state (GstElement * element,
GstStateChange transition);
static void
rsn_dvdbin_base_init (gpointer gclass)
{
static GstElementDetails element_details = {
"rsndvdbin",
"Generic/Bin/Player",
"DVD playback element",
"Jan Schmidt <thaytan@noraisin.net>"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&video_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&audio_src_template));
gst_element_class_set_details (element_class, &element_details);
element_class->change_state = GST_DEBUG_FUNCPTR (rsn_dvdbin_change_state);
}
static void
rsn_dvdbin_class_init (RsnDvdBinClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = rsn_dvdbin_finalize;
gobject_class->set_property = rsn_dvdbin_set_property;
gobject_class->get_property = rsn_dvdbin_get_property;
g_object_class_install_property (gobject_class, ARG_DEVICE,
g_param_spec_string ("device", "Device", "DVD device location",
NULL, G_PARAM_READWRITE));
}
static void
rsn_dvdbin_do_init (GType rsn_dvdbin_type)
{
static const GInterfaceInfo urihandler_info = {
rsn_dvdbin_uri_handler_init,
NULL,
NULL
};
g_type_add_interface_static (rsn_dvdbin_type, GST_TYPE_URI_HANDLER,
&urihandler_info);
}
static void
rsn_dvdbin_init (RsnDvdBin * dvdbin, RsnDvdBinClass * gclass)
{
dvdbin->dvd_lock = g_mutex_new ();
}
static void
rsn_dvdbin_finalize (GObject * object)
{
RsnDvdBin *dvdbin = RESINDVDBIN (object);
g_mutex_free (dvdbin->dvd_lock);
g_free (dvdbin->last_uri);
g_free (dvdbin->device);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/* URI interface */
static guint
rsn_dvdbin_uri_get_type (void)
{
return GST_URI_SRC;
}
static gchar **
rsn_dvdbin_uri_get_protocols (void)
{
static gchar *protocols[] = { "dvd", NULL };
return protocols;
}
static const gchar *
rsn_dvdbin_uri_get_uri (GstURIHandler * handler)
{
RsnDvdBin *dvdbin = RESINDVDBIN (handler);
DVDBIN_LOCK (dvdbin);
g_free (dvdbin->last_uri);
if (dvdbin->device)
dvdbin->last_uri = g_strdup_printf ("dvd://%s", dvdbin->device);
else
dvdbin->last_uri = g_strdup ("dvd://");
DVDBIN_UNLOCK (dvdbin);
return dvdbin->last_uri;
}
static gboolean
rsn_dvdbin_uri_set_uri (GstURIHandler * handler, const gchar * uri)
{
// RsnDvdBin *dvdbin = RESINDVDBIN (handler);
gboolean ret;
gchar *protocol, *location;
protocol = gst_uri_get_protocol (uri);
ret = (protocol && !strcmp (protocol, "dvd")) ? TRUE : FALSE;
g_free (protocol);
protocol = NULL;
if (!ret)
return ret;
location = gst_uri_get_location (uri);
if (!location)
return ret;
/*
* Parse out the device name
*/
#if 0
/*
* Parse out the new t/c/a and seek to them
*/
{
gchar **strs;
gchar **strcur;
gint pos = 0;
location = gst_uri_get_location (uri);
if (!location)
return ret;
strcur = strs = g_strsplit (location, ",", 0);
while (strcur && *strcur) {
gint val;
if (!sscanf (*strcur, "%d", &val))
break;
switch (pos) {
case 0:
if (val != dvdbin->uri_title) {
dvdbin->uri_title = val;
dvdbin->new_seek = TRUE;
}
break;
case 1:
if (val != dvdbin->uri_chapter) {
dvdbin->uri_chapter = val;
dvdbin->new_seek = TRUE;
}
break;
case 2:
dvdbin->uri_angle = val;
break;
}
strcur++;
pos++;
}
g_strfreev (strs);
}
#endif
g_free (location);
return ret;
}
static void
rsn_dvdbin_uri_handler_init (gpointer g_iface, gpointer iface_data)
{
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
iface->get_type = rsn_dvdbin_uri_get_type;
iface->get_protocols = rsn_dvdbin_uri_get_protocols;
iface->get_uri = rsn_dvdbin_uri_get_uri;
iface->set_uri = rsn_dvdbin_uri_set_uri;
}
static gboolean
try_create_piece (RsnDvdBin * dvdbin, gint index,
const gchar * factory, GType type, const gchar * name, const gchar * descr)
{
GstElement *e;
DVDBIN_LOCK (dvdbin);
if (dvdbin->pieces[index] != NULL) {
DVDBIN_UNLOCK (dvdbin);
return TRUE; /* Already exists */
}
DVDBIN_UNLOCK (dvdbin);
if (factory != NULL) {
e = gst_element_factory_make (factory, name);
} else {
if (name)
e = g_object_new (type, "name", name, NULL);
else
e = g_object_new (type, NULL);
}
if (e == NULL)
goto create_failed;
if (!gst_bin_add (GST_BIN (dvdbin), e))
goto add_failed;
GST_DEBUG_OBJECT (dvdbin, "Added %s element: %" GST_PTR_FORMAT, descr, e);
DVDBIN_LOCK (dvdbin);
dvdbin->pieces[index] = e;
DVDBIN_UNLOCK (dvdbin);
return TRUE;
create_failed:
GST_ELEMENT_ERROR (dvdbin, CORE, MISSING_PLUGIN, (NULL),
("Could not create %s element '%s'", descr, factory));
return FALSE;
add_failed:
gst_object_unref (e);
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not add %s element to bin", descr));
return FALSE;
}
static gboolean
create_elements (RsnDvdBin * dvdbin)
{
GstPad *src = NULL;
GstPad *sink = NULL;
GstPad *ghost = NULL;
if (!try_create_piece (dvdbin, DVD_ELEM_SOURCE, NULL,
RESIN_TYPE_DVDSRC, "dvdsrc", "DVD source")) {
return FALSE;
}
/* FIXME: Locking */
if (dvdbin->device) {
g_object_set (G_OBJECT (dvdbin->pieces[DVD_ELEM_SOURCE]),
"device", dvdbin->device, NULL);
}
if (!try_create_piece (dvdbin, DVD_ELEM_DEMUX,
NULL, GST_TYPE_FLUPS_DEMUX, "dvddemux", "DVD demuxer"))
return FALSE;
if (gst_element_link (dvdbin->pieces[DVD_ELEM_SOURCE],
dvdbin->pieces[DVD_ELEM_DEMUX]) == FALSE)
goto failed_connect;
/* Listen for new pads from the demuxer */
g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_DEMUX]), "pad-added",
G_CALLBACK (demux_pad_added), dvdbin);
if (!try_create_piece (dvdbin, DVD_ELEM_MQUEUE, "multiqueue", 0, "mq",
"multiqueue"))
return FALSE;
g_object_set (dvdbin->pieces[DVD_ELEM_MQUEUE],
"max-size-time", (7 * GST_SECOND / 10), "max-size-bytes", 0,
"max-size-buffers", 0, NULL);
/* Decodebin will throw a missing element message to find an MPEG decoder */
if (!try_create_piece (dvdbin, DVD_ELEM_VIDDEC, "decodebin", 0, "viddec",
"video decoder"))
return FALSE;
g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_VIDDEC]),
"new-decoded-pad", G_CALLBACK (viddec_pad_added), dvdbin);
if (!try_create_piece (dvdbin, DVD_ELEM_VIDQ, "queue", 0, "vid_q",
"video decoder buffer"))
return FALSE;
g_object_set (dvdbin->pieces[DVD_ELEM_VIDQ],
"max-size-time", G_GUINT64_CONSTANT (0), "max-size-bytes", 0,
"max-size-buffers", 3, NULL);
if (!try_create_piece (dvdbin, DVD_ELEM_SPU_SELECT, NULL,
RSN_TYPE_STREAM_SELECTOR, "subpselect", "Subpicture stream selector"))
return FALSE;
if (!try_create_piece (dvdbin, DVD_ELEM_SPU, "dvdspu", 0, "spu",
"Subpicture overlay"))
return FALSE;
sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU], "video");
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "src");
if (src == NULL || sink == NULL)
goto failed_spu_connect;
if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
goto failed_spu_connect;
gst_object_unref (sink);
gst_object_unref (src);
src = sink = NULL;
sink =
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU], "subpicture");
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT], "src");
if (src == NULL || sink == NULL)
goto failed_spu_connect;
if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
goto failed_spu_connect;
gst_object_unref (sink);
gst_object_unref (src);
src = sink = NULL;
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU], "src");
if (src == NULL)
goto failed_spu_ghost;
ghost = gst_ghost_pad_new ("video", src);
if (ghost == NULL)
goto failed_spu_ghost;
if (!gst_element_add_pad (GST_ELEMENT (dvdbin), ghost))
goto failed_spu_ghost;
gst_object_unref (src);
src = sink = NULL;
if (!try_create_piece (dvdbin, DVD_ELEM_AUD_SELECT, NULL,
RSN_TYPE_STREAM_SELECTOR, "audioselect", "Audio stream selector"))
return FALSE;
/* rsnaudiomunge goes after the audio decoding to regulate the stream */
if (!try_create_piece (dvdbin, DVD_ELEM_AUD_MUNGE, NULL,
RSN_TYPE_AUDIOMUNGE, "audiomunge", "Audio output filter"))
return FALSE;
#if DECODEBIN_AUDIO
/* Decodebin will throw a missing element message to find a suitable
* decoder */
if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, "decodebin", 0, "auddec",
"audio decoder"))
return FALSE;
g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_AUDDEC]),
"new-decoded-pad", G_CALLBACK (auddec_pad_added), dvdbin);
#else
if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, "a52dec", 0, "auddec",
"audio decoder"))
return FALSE;
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "src");
sink =
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "sink");
if (src == NULL || sink == NULL)
goto failed_aud_connect;
if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
goto failed_aud_connect;
gst_object_unref (sink);
gst_object_unref (src);
src = sink = NULL;
#endif
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT], "src");
sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "sink");
if (src == NULL || sink == NULL)
goto failed_aud_connect;
if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
goto failed_aud_connect;
gst_object_unref (sink);
gst_object_unref (src);
src = sink = NULL;
/* ghost audio munge output pad onto bin */
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "src");
if (src == NULL)
goto failed_aud_ghost;
ghost = gst_ghost_pad_new ("audio", src);
if (ghost == NULL)
goto failed_aud_ghost;
if (!gst_element_add_pad (GST_ELEMENT (dvdbin), ghost))
goto failed_aud_ghost;
gst_object_unref (src);
src = sink = NULL;
return TRUE;
failed_connect:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not connect DVD source and demuxer elements"));
return FALSE;
failed_spu_connect:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not connect DVD video buffer and spu elements"));
if (src != NULL)
gst_object_unref (src);
if (sink != NULL)
gst_object_unref (sink);
return FALSE;
failed_spu_ghost:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not ghost SPU output pad"));
if (src != NULL)
gst_object_unref (src);
if (ghost != NULL)
gst_object_unref (ghost);
return FALSE;
failed_aud_connect:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not connect DVD audio decoder"));
if (src != NULL)
gst_object_unref (src);
if (sink != NULL)
gst_object_unref (sink);
return FALSE;
failed_aud_ghost:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not ghost audio output pad"));
if (ghost != NULL)
gst_object_unref (ghost);
return FALSE;
}
static void
remove_elements (RsnDvdBin * dvdbin)
{
gint i;
GList *tmp;
if (dvdbin->pieces[DVD_ELEM_MQUEUE] != NULL) {
for (tmp = dvdbin->mq_req_pads; tmp; tmp = g_list_next (tmp)) {
gst_element_release_request_pad (dvdbin->pieces[DVD_ELEM_MQUEUE],
GST_PAD (tmp->data));
}
}
g_list_free (dvdbin->mq_req_pads);
dvdbin->mq_req_pads = NULL;
for (i = 0; i < DVD_ELEM_LAST; i++) {
DVDBIN_LOCK (dvdbin);
if (dvdbin->pieces[i] != NULL) {
GstElement *piece = dvdbin->pieces[i];
dvdbin->pieces[i] = NULL;
DVDBIN_UNLOCK (dvdbin);
gst_element_set_state (piece, GST_STATE_NULL);
gst_bin_remove (GST_BIN (dvdbin), piece);
} else
DVDBIN_UNLOCK (dvdbin);
}
}
static GstPad *
connect_thru_mq (RsnDvdBin * dvdbin, GstPad * pad)
{
GstPad *mq_sink;
GstPad *mq_src;
gchar *tmp, *sinkname, *srcname;
/* Request a pad from multiqueue, then connect this one, then
* discover the corresponding output pad and return it */
mq_sink = gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_MQUEUE],
"sink%d");
if (mq_sink == NULL)
return FALSE;
dvdbin->mq_req_pads = g_list_prepend (dvdbin->mq_req_pads, mq_sink);
if (gst_pad_link (pad, mq_sink) != GST_PAD_LINK_OK)
return FALSE;
sinkname = gst_pad_get_name (mq_sink);
tmp = sinkname + 4;
srcname = g_strdup_printf ("src%s", tmp);
mq_src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_MQUEUE],
srcname);
g_free (sinkname);
g_free (srcname);
return mq_src;
}
static void
demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
{
gboolean skip_mq = FALSE;
GstPad *mq_pad = NULL;
GstPad *dest_pad = NULL;
GstCaps *caps;
GstStructure *s;
GST_ERROR_OBJECT (dvdbin, "New pad: %" GST_PTR_FORMAT, pad);
caps = gst_pad_get_caps (pad);
if (caps == NULL) {
GST_WARNING_OBJECT (dvdbin, "NULL caps from pad %" GST_PTR_FORMAT, pad);
return;
}
if (!gst_caps_is_fixed (caps)) {
GST_WARNING_OBJECT (dvdbin, "Unfixed caps %" GST_PTR_FORMAT
" on pad %" GST_PTR_FORMAT, caps, pad);
gst_caps_unref (caps);
return;
}
s = gst_caps_get_structure (caps, 0);
g_return_if_fail (s != NULL);
if (g_str_equal (gst_structure_get_name (s), "video/mpeg")) {
dest_pad =
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDDEC], "sink");
} else if (g_str_equal (gst_structure_get_name (s), "video/x-dvd-subpicture")) {
dest_pad =
gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT],
"sink%d");
skip_mq = TRUE;
} else if (g_str_equal (gst_structure_get_name (s), "audio/x-private1-ac3")) {
dest_pad =
gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT],
"sink%d");
}
gst_caps_unref (caps);
if (dest_pad == NULL) {
GST_DEBUG_OBJECT (dvdbin, "Don't know how to handle pad. Ignoring");
return;
}
if (skip_mq) {
mq_pad = gst_object_ref (pad);
} else {
mq_pad = connect_thru_mq (dvdbin, pad);
if (mq_pad == NULL)
goto failed;
GST_ERROR_OBJECT (dvdbin, "Linking new pad %" GST_PTR_FORMAT
" through multiqueue to %" GST_PTR_FORMAT, pad, dest_pad);
}
gst_pad_link (mq_pad, dest_pad);
gst_object_unref (mq_pad);
gst_object_unref (dest_pad);
return;
failed:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Failed to handle new demuxer pad %s", GST_PAD_NAME (pad)));
if (mq_pad)
gst_object_unref (mq_pad);
if (dest_pad)
gst_object_unref (dest_pad);
return;
}
static void
viddec_pad_added (GstElement * element, GstPad * pad, gboolean last,
RsnDvdBin * dvdbin)
{
GstPad *q_pad;
GST_ERROR_OBJECT (dvdbin, "New video pad: %" GST_PTR_FORMAT, pad);
q_pad = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "sink");
gst_pad_link (pad, q_pad);
gst_object_unref (q_pad);
}
#if DECODEBIN_AUDIO
static void
auddec_pad_added (GstElement * element, GstPad * pad, gboolean last,
RsnDvdBin * dvdbin)
{
GstPad *out_pad;
GST_ERROR_OBJECT (dvdbin, "New audio pad: %" GST_PTR_FORMAT, pad);
out_pad =
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "sink");
gst_pad_link (pad, out_pad);
gst_object_unref (out_pad);
}
#endif
static void
rsn_dvdbin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
RsnDvdBin *dvdbin = RESINDVDBIN (object);
switch (prop_id) {
case ARG_DEVICE:
DVDBIN_LOCK (dvdbin);
g_free (dvdbin->device);
if (g_value_get_string (value) == NULL)
dvdbin->device = g_strdup (DEFAULT_DEVICE);
else
dvdbin->device = g_value_dup_string (value);
if (dvdbin->pieces[DVD_ELEM_SOURCE]) {
g_object_set_property (G_OBJECT (dvdbin->pieces[DVD_ELEM_SOURCE]),
"device", value);
}
DVDBIN_UNLOCK (dvdbin);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
rsn_dvdbin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
RsnDvdBin *dvdbin = RESINDVDBIN (object);
switch (prop_id) {
case ARG_DEVICE:
DVDBIN_LOCK (dvdbin);
if (dvdbin->device)
g_value_set_string (value, dvdbin->device);
else if (dvdbin->pieces[DVD_ELEM_SOURCE])
g_object_get_property (G_OBJECT (dvdbin->pieces[DVD_ELEM_SOURCE]),
"device", value);
else
g_value_set_string (value, DEFAULT_DEVICE);
DVDBIN_UNLOCK (dvdbin);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstStateChangeReturn
rsn_dvdbin_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
RsnDvdBin *dvdbin = RESINDVDBIN (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!create_elements (dvdbin)) {
remove_elements (dvdbin);
return GST_STATE_CHANGE_FAILURE;
}
gst_element_no_more_pads (GST_ELEMENT (dvdbin));
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
case GST_STATE_CHANGE_READY_TO_NULL:
remove_elements (dvdbin);
break;
default:
break;
}
return ret;
}

View file

@ -0,0 +1,80 @@
/* GStreamer
* Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
*
* 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 __RESINDVDBIN_H__
#define __RESINDVDBIN_H__
#include <gst/gst.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define RESIN_TYPE_DVDBIN \
(rsn_dvdbin_get_type())
#define RESINDVDBIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),RESIN_TYPE_DVDBIN,RsnDvdBin))
#define RESINDVDBIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),RESIN_TYPE_DVDBIN,RsnDvdBinClass))
#define IS_RESINDVDBIN(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),RESIN_TYPE_DVDBIN))
#define IS_RESINDVDBIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),RESIN_TYPE_DVDBIN))
typedef struct _RsnDvdBin RsnDvdBin;
typedef struct _RsnDvdBinClass RsnDvdBinClass;
#define DVD_ELEM_SOURCE 0
#define DVD_ELEM_DEMUX 1
#define DVD_ELEM_MQUEUE 2
#define DVD_ELEM_SPU 3
#define DVD_ELEM_VIDDEC 4
#define DVD_ELEM_AUDDEC 5
#define DVD_ELEM_VIDQ 6
#define DVD_ELEM_SPU_SELECT 7
#define DVD_ELEM_AUD_SELECT 8
#define DVD_ELEM_AUD_MUNGE 9
#define DVD_ELEM_LAST 10
struct _RsnDvdBin
{
GstBin element;
/* Protects pieces list and properties */
GMutex *dvd_lock;
gchar *device;
gchar *last_uri;
GstElement *pieces[DVD_ELEM_LAST];
GstPad *video_pad;
GstPad *audio_pad;
GList *mq_req_pads;
};
struct _RsnDvdBinClass
{
GstBinClass parent_class;
};
GType rsn_dvdbin_get_type (void);
G_END_DECLS
#endif /* __RESINDVDBIN_H__ */

1426
ext/resindvd/resindvdsrc.c Normal file

File diff suppressed because it is too large Load diff

113
ext/resindvd/resindvdsrc.h Normal file
View file

@ -0,0 +1,113 @@
/* GStreamer
* Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
*
* 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 __RESINDVDSRC_H__
#define __RESINDVDSRC_H__
#include <gst/gst.h>
#include "rsnpushsrc.h"
#include "_stdint.h"
#include <dvdnav/dvd_reader.h>
#include <dvdnav/ifo_read.h>
#include <dvdnav/dvdnav.h>
#include <dvdnav/nav_print.h>
G_BEGIN_DECLS
#define RESIN_TYPE_DVDSRC (rsn_dvdsrc_get_type())
#define RESINDVDSRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),RESIN_TYPE_DVDSRC,resinDvdSrc))
#define RESINDVDSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),RESIN_TYPE_DVDSRC,resinDvdSrcClass))
#define IS_RESINDVDSRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),RESIN_TYPE_DVDSRC))
#define IS_RESINDVDSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),RESIN_TYPE_DVDSRC))
typedef struct _resinDvdSrc resinDvdSrc;
typedef struct _resinDvdSrcClass resinDvdSrcClass;
struct _resinDvdSrc
{
RsnPushSrc parent;
GMutex *dvd_lock;
GCond *still_cond;
GMutex *branch_lock;
gboolean branching;
gchar *device;
dvdnav_t *dvdnav;
/* dvd_reader instance is used to load and cache VTS/VMG ifo info */
dvd_reader_t *dvdread;
/* vmgi_mat_t from the VMG ifo: */
vmgi_mat_t vmgm_attr; /* VMGM domain info */
/* Array of cached vtsi_mat_t strctures from each IFO: */
GArray *vts_attrs;
ifo_handle_t *vmg_file;
ifo_handle_t *vts_file;
/* Current playback location: VTS 0 = VMG, plus in_menu or not */
gint vts_n;
gboolean in_menu;
gboolean running;
gboolean discont;
gboolean need_segment;
gboolean active_highlight;
GstBuffer *alloc_buf;
GstBuffer *next_buf;
/* Start timestamp of the previous NAV block */
GstClockTime cur_start_ts;
/* End timestamp of the previous NAV block */
GstClockTime cur_end_ts;
/* Position info of the previous NAV block */
GstClockTime cur_position;
/* Duration of the current PGC */
GstClockTime pgc_duration;
gint active_button;
dvdnav_highlight_area_t area;
/* Pending events to output */
GstEvent *streams_event;
GstEvent *clut_event;
GstEvent *spu_select_event;
GstEvent *audio_select_event;
GstEvent *highlight_event;
};
struct _resinDvdSrcClass
{
RsnPushSrcClass parent_class;
};
GType rsn_dvdsrc_get_type (void);
G_END_DECLS
#endif /* __RESINDVDSRC_H__ */

View file

@ -0,0 +1,378 @@
/* GStreamer
* Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
*
* 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 <string.h>
#include <gst/gst.h>
#include "rsnaudiomunge.h"
GST_DEBUG_CATEGORY_STATIC (rsn_audiomunge_debug);
#define GST_CAT_DEFAULT rsn_audiomunge_debug
#define AUDIO_FILL_THRESHOLD (GST_SECOND/5)
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_SILENT
};
/* the capabilities of the inputs and outputs.
*
* describe the real formats here.
*/
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("ANY")
);
GST_BOILERPLATE (RsnAudioMunge, rsn_audiomunge, GstElement, GST_TYPE_ELEMENT);
static void rsn_audiomunge_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void rsn_audiomunge_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean rsn_audiomunge_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn rsn_audiomunge_chain (GstPad * pad, GstBuffer * buf);
static gboolean rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event);
static GstStateChangeReturn
rsn_audiomunge_change_state (GstElement * element, GstStateChange transition);
static void
rsn_audiomunge_base_init (gpointer gclass)
{
static GstElementDetails element_details = {
"RsnAudioMunge",
"Audio/Filter",
"Resin DVD audio stream regulator",
"Jan Schmidt <thaytan@noraisin.net>"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
GST_DEBUG_CATEGORY_INIT (rsn_audiomunge_debug, "rsn_audiomunge",
0, "Resin audio stream regulator");
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 (&sink_template));
gst_element_class_set_details (element_class, &element_details);
}
static void
rsn_audiomunge_class_init (RsnAudioMungeClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = rsn_audiomunge_set_property;
gobject_class->get_property = rsn_audiomunge_get_property;
gstelement_class->change_state = rsn_audiomunge_change_state;
}
static void
rsn_audiomunge_init (RsnAudioMunge * munge, RsnAudioMungeClass * gclass)
{
munge->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
gst_pad_set_setcaps_function (munge->sinkpad,
GST_DEBUG_FUNCPTR (rsn_audiomunge_set_caps));
gst_pad_set_getcaps_function (munge->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_pad_set_chain_function (munge->sinkpad,
GST_DEBUG_FUNCPTR (rsn_audiomunge_chain));
gst_pad_set_event_function (munge->sinkpad,
GST_DEBUG_FUNCPTR (rsn_audiomunge_sink_event));
gst_element_add_pad (GST_ELEMENT (munge), munge->sinkpad);
munge->srcpad = gst_pad_new_from_static_template (&src_template, "src");
gst_pad_set_getcaps_function (munge->srcpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_element_add_pad (GST_ELEMENT (munge), munge->srcpad);
}
static void
rsn_audiomunge_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
//RsnAudioMunge *munge = RSN_AUDIOMUNGE (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
rsn_audiomunge_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//RsnAudioMunge *munge = RSN_AUDIOMUNGE (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
rsn_audiomunge_set_caps (GstPad * pad, GstCaps * caps)
{
RsnAudioMunge *munge = RSN_AUDIOMUNGE (gst_pad_get_parent (pad));
GstPad *otherpad;
gboolean ret;
g_return_val_if_fail (munge != NULL, FALSE);
otherpad = (pad == munge->srcpad) ? munge->sinkpad : munge->srcpad;
gst_object_unref (munge);
ret = gst_pad_set_caps (otherpad, caps);
return ret;
}
static void
rsn_audiomunge_reset (RsnAudioMunge * munge)
{
munge->have_audio = FALSE;
munge->in_still = FALSE;
gst_segment_init (&munge->sink_segment, GST_FORMAT_TIME);
}
static GstFlowReturn
rsn_audiomunge_chain (GstPad * pad, GstBuffer * buf)
{
RsnAudioMunge *munge = RSN_AUDIOMUNGE (GST_OBJECT_PARENT (pad));
if (!munge->have_audio) {
g_print ("First audio after flush has TS %" GST_TIME_FORMAT "\n",
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
}
munge->have_audio = TRUE;
/* just push out the incoming buffer without touching it */
return gst_pad_push (munge->srcpad, buf);
}
/* Create and send a silence buffer downstream */
static GstFlowReturn
rsn_audiomunge_make_audio (RsnAudioMunge * munge,
GstClockTime start, GstClockTime fill_time)
{
GstFlowReturn ret;
GstBuffer *audio_buf;
GstCaps *caps;
guint buf_size;
/* Just generate a 48khz stereo buffer for now */
#if 0
caps =
gst_caps_from_string
("audio/x-raw-int,rate=48000,channels=2,width=16,depth=16,signed=(boolean)true,endianness=1234");
buf_size = 4 * (48000 * fill_time / GST_SECOND);
#else
caps = gst_caps_from_string ("audio/x-raw-float, endianness=(int)1234,"
"width=(int)32, channels=(int)2, rate=(int)48000");
buf_size = 2 * 4 * (48000 * fill_time / GST_SECOND);
#endif
audio_buf = gst_buffer_new_and_alloc (buf_size);
gst_buffer_set_caps (audio_buf, caps);
gst_caps_unref (caps);
GST_BUFFER_TIMESTAMP (audio_buf) = start;
GST_BUFFER_DURATION (audio_buf) = fill_time;
GST_BUFFER_FLAG_SET (audio_buf, GST_BUFFER_FLAG_DISCONT);
memset (GST_BUFFER_DATA (audio_buf), 0, buf_size);
g_print ("Sending %u bytes (%" GST_TIME_FORMAT ") of audio data "
"with TS %" GST_TIME_FORMAT "\n",
buf_size, GST_TIME_ARGS (fill_time), GST_TIME_ARGS (start));
ret = gst_pad_push (munge->srcpad, audio_buf);
return ret;
}
static void
rsn_audiomunge_handle_dvd_event (RsnAudioMunge * munge, GstEvent * event)
{
const GstStructure *s;
const gchar *event_type;
s = gst_event_get_structure (event);
event_type = gst_structure_get_string (s, "event");
if (event_type == NULL)
return;
if (strcmp (event_type, "dvd-still") == 0) {
gboolean in_still;
if (!gst_structure_get_boolean (s, "still-state", &in_still))
return;
/* Remember the still-frame state, so we can generate a pre-roll buffer
* when a new-segment arrives */
munge->in_still = in_still;
g_print ("**** AUDIO MUNGE: still-state now %d\n", munge->in_still);
}
}
static gboolean
rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
{
gboolean ret = FALSE;
RsnAudioMunge *munge = RSN_AUDIOMUNGE (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
rsn_audiomunge_reset (munge);
g_print ("*********** AUDIO MUNGE: FLUSH\n");
ret = gst_pad_push_event (munge->srcpad, event);
break;
case GST_EVENT_NEWSEGMENT:
{
GstSegment *segment;
gboolean update;
GstFormat format;
gdouble rate, arate;
gint64 start, stop, time;
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
&start, &stop, &time);
/* we need TIME format */
if (format != GST_FORMAT_TIME)
goto newseg_wrong_format;
/* now configure the values */
segment = &munge->sink_segment;
gst_segment_set_newsegment_full (segment, update,
rate, arate, format, start, stop, time);
if (munge->have_audio) {
g_print ("*********** AUDIO MUNGE NEWSEG: start %" GST_TIME_FORMAT
" stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT
"\n", GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
GST_TIME_ARGS (segment->accum));
ret = gst_pad_push_event (munge->srcpad, event);
break;
}
/*
* FIXME:
* If the accum >= threshold or we're in a still frame and there's been
* no audio received, then we need to generate some audio data.
* If caused by a segment start update (time advancing in a gap) adjust
* the new-segment and send the buffer.
*
* Otherwise, send the buffer before the newsegment, so that it appears
* in the closing segment.
*/
if (segment->accum >= AUDIO_FILL_THRESHOLD || munge->in_still) {
g_print ("*********** Send audio mebbe: accum = %" GST_TIME_FORMAT
" still-state=%d\n", GST_TIME_ARGS (segment->accum),
munge->in_still);
/* Just generate a 100ms silence buffer for now. FIXME: Fill the gap */
if (rsn_audiomunge_make_audio (munge, segment->start,
GST_SECOND / 10) == GST_FLOW_OK)
munge->have_audio = TRUE;
} else {
g_print ("*********** below thresh: accum = %" GST_TIME_FORMAT
"\n", GST_TIME_ARGS (segment->accum));
}
g_print ("*********** AUDIO MUNGE NEWSEG: start %" GST_TIME_FORMAT
" stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT
"\n", GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
GST_TIME_ARGS (segment->accum));
ret = gst_pad_push_event (munge->srcpad, event);
break;
}
case GST_EVENT_CUSTOM_DOWNSTREAM:
{
const GstStructure *s = gst_event_get_structure (event);
if (s && gst_structure_has_name (s, "application/x-gst-dvd"))
rsn_audiomunge_handle_dvd_event (munge, event);
ret = gst_pad_push_event (munge->srcpad, event);
break;
}
default:
ret = gst_pad_push_event (munge->srcpad, event);
break;
}
return ret;
newseg_wrong_format:
GST_DEBUG_OBJECT (munge, "received non TIME newsegment");
gst_event_unref (event);
gst_object_unref (munge);
return FALSE;
}
static GstStateChangeReturn
rsn_audiomunge_change_state (GstElement * element, GstStateChange transition)
{
RsnAudioMunge *munge = RSN_AUDIOMUNGE (element);
GstStateChangeReturn ret;
if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
rsn_audiomunge_reset (munge);
ret = parent_class->change_state (element, transition);
return ret;
}

View file

@ -0,0 +1,61 @@
/* GStreamer
* Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
*
* 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 __RSNAUDIOMUNGE_H__
#define __RSNAUDIOMUNGE_H__
#include <gst/gst.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define RSN_TYPE_AUDIOMUNGE (rsn_audiomunge_get_type())
#define RSN_AUDIOMUNGE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),RSN_TYPE_AUDIOMUNGE,RsnAudioMunge))
#define RSN_AUDIOMUNGE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),RSN_TYPE_AUDIOMUNGE,RsnAudioMungeClass))
#define RSN_IS_AUDIOMUNGE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),RSN_TYPE_AUDIOMUNGE))
#define RSN_IS_AUDIOMUNGE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),RSN_TYPE_AUDIOMUNGE))
typedef struct _RsnAudioMunge RsnAudioMunge;
typedef struct _RsnAudioMungeClass RsnAudioMungeClass;
struct _RsnAudioMunge
{
GstElement element;
GstPad *sinkpad, *srcpad;
GstSegment sink_segment;
gboolean have_audio;
gboolean in_still;
};
struct _RsnAudioMungeClass
{
GstElementClass parent_class;
};
GType rsn_audiomunge_get_type (void);
G_END_DECLS
#endif /* __RSNAUDIOMUNGE_H__ */

2423
ext/resindvd/rsnbasesrc.c Normal file

File diff suppressed because it is too large Load diff

257
ext/resindvd/rsnbasesrc.h Normal file
View file

@ -0,0 +1,257 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstbasesrc.h:
*
* 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.
*/
/*
*
* This is a temporary copy of GstBaseSrc/GstPushSrc for the resin
* DVD components, to work around a deadlock with source elements that
* send seeks to themselves.
*
*/
#ifndef __GST_BASE_SRC_H__
#define __GST_BASE_SRC_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define RSN_TYPE_BASE_SRC (rsn_base_src_get_type())
#define GST_BASE_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RSN_TYPE_BASE_SRC,RsnBaseSrc))
#define GST_BASE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RSN_TYPE_BASE_SRC,RsnBaseSrcClass))
#define GST_BASE_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RSN_TYPE_BASE_SRC, RsnBaseSrcClass))
#define GST_IS_BASE_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RSN_TYPE_BASE_SRC))
#define GST_IS_BASE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RSN_TYPE_BASE_SRC))
#define GST_BASE_SRC_CAST(obj) ((RsnBaseSrc *)(obj))
/**
* RsnBaseSrcFlags:
* @GST_BASE_SRC_STARTED: has source been started
* @GST_BASE_SRC_FLAG_LAST: offset to define more flags
*
* The #GstElement flags that a basesrc element may have.
*/
typedef enum {
GST_BASE_SRC_STARTED = (GST_ELEMENT_FLAG_LAST << 0),
/* padding */
GST_BASE_SRC_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2)
} RsnBaseSrcFlags;
typedef struct _RsnBaseSrc RsnBaseSrc;
typedef struct _RsnBaseSrcClass RsnBaseSrcClass;
typedef struct _RsnBaseSrcPrivate RsnBaseSrcPrivate;
/**
* GST_BASE_SRC_PAD:
* @obj: base source instance
*
* Gives the pointer to the #GstPad object of the element.
*/
#define GST_BASE_SRC_PAD(obj) (GST_BASE_SRC_CAST (obj)->srcpad)
/**
* RsnBaseSrc:
* @element: the parent element.
*
* The opaque #RsnBaseSrc data structure.
*/
struct _RsnBaseSrc {
GstElement element;
/*< protected >*/
GstPad *srcpad;
/* available to subclass implementations */
/* MT-protected (with LIVE_LOCK) */
GMutex *live_lock;
GCond *live_cond;
gboolean is_live;
gboolean live_running;
/* MT-protected (with LOCK) */
gint blocksize; /* size of buffers when operating push based */
gboolean can_activate_push; /* some scheduling properties */
GstActivateMode pad_mode;
gboolean seekable;
gboolean random_access;
GstClockID clock_id; /* for syncing */
GstClockTime end_time;
/* MT-protected (with STREAM_LOCK) */
GstSegment segment;
gboolean need_newsegment;
guint64 offset; /* current offset in the resource, unused */
guint64 size; /* total size of the resource, unused */
gint num_buffers;
gint num_buffers_left;
/*< private >*/
union {
struct {
/* FIXME: those fields should be moved into the private struct */
gboolean typefind;
gboolean running;
GstEvent *pending_seek;
} ABI;
gpointer _gst_reserved[GST_PADDING_LARGE-1];
} data;
RsnBaseSrcPrivate *priv;
};
/**
* RsnBaseSrcClass:
* @parent_class: Element parent class
* @get_caps: Called to get the caps to report
* @set_caps: Notify subclass of changed output caps
* @negotiate: Negotiated the caps with the peer.
* @newsegment: Generate and send a new_segment event (UNUSED)
* @start: Start processing. Subclasses should open resources and prepare
* to produce data.
* @stop: Stop processing. Subclasses should use this to close resources.
* @get_times: Given a buffer, return the start and stop time when it
* should be pushed out. The base class will sync on the clock using
* these times.
* @get_size: Return the total size of the resource, in the configured format.
* @is_seekable: Check if the source can seek
* @unlock: Unlock any pending access to the resource. Subclasses should
* unblock any blocked function ASAP
* @unlock_stop: Clear the previous unlock request. Subclasses should clear
* any state they set during unlock(), such as clearing command queues.
* @event: Override this to implement custom event handling.
* @create: Ask the subclass to create a buffer with offset and size.
* @do_seek: Perform seeking on the resource to the indicated segment.
* @prepare_seek_segment: Prepare the GstSegment that will be passed to the
* do_seek vmethod for executing a seek request. Sub-classes should override
* this if they support seeking in formats other than the configured native
* format. By default, it tries to convert the seek arguments to the
* configured native format and prepare a segment in that format.
* Since: 0.10.13
* @query: Handle a requested query.
* @check_get_range: Check whether the source would support pull-based
* operation if it were to be opened now. This vfunc is optional, but
* should be implemented if possible to avoid unnecessary start/stop
* cycles. The default implementation will open and close the resource
* to find out whether get_range is supported, and that is usually
* undesirable.
* @fixate: Called during negotation if caps need fixating. Implement instead of
* setting a fixate function on the source pad.
*
* Subclasses can override any of the available virtual methods or not, as
* needed. At the minimum, the @create method should be overridden to produce
* buffers.
*/
struct _RsnBaseSrcClass {
GstElementClass parent_class;
/*< public >*/
/* virtual methods for subclasses */
/* get caps from subclass */
GstCaps* (*get_caps) (RsnBaseSrc *src);
/* notify the subclass of new caps */
gboolean (*set_caps) (RsnBaseSrc *src, GstCaps *caps);
/* decide on caps */
gboolean (*negotiate) (RsnBaseSrc *src);
/* generate and send a newsegment (UNUSED) */
gboolean (*newsegment) (RsnBaseSrc *src);
/* start and stop processing, ideal for opening/closing the resource */
gboolean (*start) (RsnBaseSrc *src);
gboolean (*stop) (RsnBaseSrc *src);
/* given a buffer, return start and stop time when it should be pushed
* out. The base class will sync on the clock using these times. */
void (*get_times) (RsnBaseSrc *src, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
/* get the total size of the resource in bytes */
gboolean (*get_size) (RsnBaseSrc *src, guint64 *size);
/* check if the resource is seekable */
gboolean (*is_seekable) (RsnBaseSrc *src);
/* unlock any pending access to the resource. subclasses should unlock
* any function ASAP. */
gboolean (*unlock) (RsnBaseSrc *src);
/* notify subclasses of an event */
gboolean (*event) (RsnBaseSrc *src, GstEvent *event);
/* ask the subclass to create a buffer with offset and size */
GstFlowReturn (*create) (RsnBaseSrc *src, guint64 offset, guint size,
GstBuffer **buf);
/* additions that change padding... */
/* notify subclasses of a seek */
gboolean (*do_seek) (RsnBaseSrc *src, GstSegment *segment);
/* notify subclasses of a query */
gboolean (*query) (RsnBaseSrc *src, GstQuery *query);
/* check whether the source would support pull-based operation if
* it were to be opened now. This vfunc is optional, but should be
* implemented if possible to avoid unnecessary start/stop cycles.
* The default implementation will open and close the resource to
* find out whether get_range is supported and that is usually
* undesirable. */
gboolean (*check_get_range) (RsnBaseSrc *src);
/* called if, in negotation, caps need fixating */
void (*fixate) (RsnBaseSrc *src, GstCaps *caps);
/* Clear any pending unlock request, as we succeeded in unlocking */
gboolean (*unlock_stop) (RsnBaseSrc *src);
/* Prepare the segment on which to perform do_seek(), converting to the
* current basesrc format. */
gboolean (*prepare_seek_segment) (RsnBaseSrc *src, GstEvent *seek,
GstSegment *segment);
/*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE - 6];
};
GType rsn_base_src_get_type (void);
GstFlowReturn rsn_base_src_wait_playing (RsnBaseSrc *src);
void rsn_base_src_set_live (RsnBaseSrc *src, gboolean live);
gboolean rsn_base_src_is_live (RsnBaseSrc *src);
void rsn_base_src_set_format (RsnBaseSrc *src, GstFormat format);
gboolean rsn_base_src_query_latency (RsnBaseSrc *src, gboolean * live,
GstClockTime * min_latency,
GstClockTime * max_latency);
void rsn_base_src_set_do_timestamp (RsnBaseSrc *src, gboolean live);
gboolean rsn_base_src_get_do_timestamp (RsnBaseSrc *src);
G_END_DECLS
#endif /* __GST_BASE_SRC_H__ */

101
ext/resindvd/rsnpushsrc.c Normal file
View file

@ -0,0 +1,101 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* gstpushsrc.c:
*
* 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.
*/
/*
*
* This is a temporary copy of GstBaseSrc/GstPushSrc for the resin
* DVD components, to work around a deadlock with source elements that
* send seeks to themselves.
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "rsnpushsrc.h"
#include <gst/gstmarshal.h>
GST_DEBUG_CATEGORY_STATIC (rsn_push_src_debug);
#define GST_CAT_DEFAULT rsn_push_src_debug
#define _do_init(type) \
GST_DEBUG_CATEGORY_INIT (rsn_push_src_debug, "pushsrc", 0, \
"pushsrc element");
GST_BOILERPLATE_FULL (RsnPushSrc, rsn_push_src, RsnBaseSrc, RSN_TYPE_BASE_SRC,
_do_init);
static gboolean rsn_push_src_check_get_range (RsnBaseSrc * src);
static GstFlowReturn rsn_push_src_create (RsnBaseSrc * bsrc, guint64 offset,
guint length, GstBuffer ** ret);
static void
rsn_push_src_base_init (gpointer g_class)
{
/* nop */
}
static void
rsn_push_src_class_init (RsnPushSrcClass * klass)
{
RsnBaseSrcClass *gstbasesrc_class = (RsnBaseSrcClass *) klass;
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (rsn_push_src_create);
gstbasesrc_class->check_get_range =
GST_DEBUG_FUNCPTR (rsn_push_src_check_get_range);
}
static void
rsn_push_src_init (RsnPushSrc * pushsrc, RsnPushSrcClass * klass)
{
/* nop */
}
static gboolean
rsn_push_src_check_get_range (RsnBaseSrc * src)
{
/* a pushsrc can by default never operate in pull mode override
* if you want something different. */
return FALSE;
}
static GstFlowReturn
rsn_push_src_create (RsnBaseSrc * bsrc, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
RsnPushSrc *src;
RsnPushSrcClass *pclass;
src = GST_PUSH_SRC (bsrc);
pclass = GST_PUSH_SRC_GET_CLASS (src);
if (pclass->create)
fret = pclass->create (src, ret);
else
fret = GST_FLOW_ERROR;
return fret;
}

76
ext/resindvd/rsnpushsrc.h Normal file
View file

@ -0,0 +1,76 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstpushsrc.h:
*
* 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.
*/
/*
*
* This is a temporary copy of GstBaseSrc/GstPushSrc for the resin
* DVD components, to work around a deadlock with source elements that
* send seeks to themselves.
*
*/
#ifndef __GST_PUSH_SRC_H__
#define __GST_PUSH_SRC_H__
#include <gst/gst.h>
#include "rsnbasesrc.h"
G_BEGIN_DECLS
#define RSN_TYPE_PUSH_SRC (rsn_push_src_get_type())
#define GST_PUSH_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RSN_TYPE_PUSH_SRC,RsnPushSrc))
#define GST_PUSH_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RSN_TYPE_PUSH_SRC,RsnPushSrcClass))
#define GST_PUSH_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RSN_TYPE_PUSH_SRC, RsnPushSrcClass))
#define GST_IS_PUSH_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RSN_TYPE_PUSH_SRC))
#define GST_IS_PUSH_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RSN_TYPE_PUSH_SRC))
typedef struct _RsnPushSrc RsnPushSrc;
typedef struct _RsnPushSrcClass RsnPushSrcClass;
/**
* RsnPushSrc:
* @parent: the parent base source object.
*
* The opaque #RsnPushSrc data structure.
*/
struct _RsnPushSrc {
RsnBaseSrc parent;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
struct _RsnPushSrcClass {
RsnBaseSrcClass parent_class;
/* ask the subclass to create a buffer */
GstFlowReturn (*create) (RsnPushSrc *src, GstBuffer **buf);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType rsn_push_src_get_type(void);
G_END_DECLS
#endif /* __GST_PUSH_SRC_H__ */

View file

@ -0,0 +1,784 @@
/* GStreamer
* Copyright (C) 2003 Julien Moutte <julien@moutte.net>
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
* Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
*
* 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 <string.h>
#include "rsnstreamselector.h"
GST_DEBUG_CATEGORY_STATIC (stream_selector_debug);
#define GST_CAT_DEFAULT stream_selector_debug
static const GstElementDetails rsn_stream_selector_details =
GST_ELEMENT_DETAILS ("StreamSelector",
"Generic",
"N-to-1 input stream_selectoring",
"Julien Moutte <julien@moutte.net>\n"
"Ronald S. Bultje <rbultje@ronald.bitfreak.net>\n"
"Jan Schmidt <thaytan@mad.scientist.com>\n"
"Wim Taymans <wim.taymans@gmail.com>");
static GstStaticPadTemplate rsn_stream_selector_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate rsn_stream_selector_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
enum
{
PROP_0,
PROP_N_PADS,
PROP_ACTIVE_PAD,
PROP_LAST
};
static gboolean rsn_stream_selector_is_active_sinkpad (RsnStreamSelector * sel,
GstPad * pad);
static GstPad *rsn_stream_selector_activate_sinkpad (RsnStreamSelector * sel,
GstPad * pad);
static GstPad *rsn_stream_selector_get_linked_pad (GstPad * pad,
gboolean strict);
#define RSN_TYPE_SELECTOR_PAD \
(gst_selector_pad_get_type())
#define GST_SELECTOR_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), RSN_TYPE_SELECTOR_PAD, RsnSelectorPad))
#define GST_SELECTOR_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), RSN_TYPE_SELECTOR_PAD, RsnSelectorPadClass))
#define RSN_IS_SELECTOR_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), RSN_TYPE_SELECTOR_PAD))
#define RSN_IS_SELECTOR_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), RSN_TYPE_SELECTOR_PAD))
#define GST_SELECTOR_PAD_CAST(obj) \
((RsnSelectorPad *)(obj))
typedef struct _RsnSelectorPad RsnSelectorPad;
typedef struct _RsnSelectorPadClass RsnSelectorPadClass;
struct _RsnSelectorPad
{
GstPad parent;
gboolean active;
gboolean eos;
gboolean segment_pending;
GstSegment segment;
GstTagList *tags;
};
struct _RsnSelectorPadClass
{
GstPadClass parent;
};
static void gst_selector_pad_class_init (RsnSelectorPadClass * klass);
static void gst_selector_pad_init (RsnSelectorPad * pad);
static void gst_selector_pad_finalize (GObject * object);
static void gst_selector_pad_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static GstPadClass *selector_pad_parent_class = NULL;
static void gst_selector_pad_reset (RsnSelectorPad * pad);
static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
static GList *gst_selector_pad_get_linked_pads (GstPad * pad);
static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
enum
{
PROP_PAD_0,
PROP_PAD_TAGS,
PROP_PAD_ACTIVE,
PROP_PAD_LAST
};
static GType
gst_selector_pad_get_type (void)
{
static GType selector_pad_type = 0;
if (!selector_pad_type) {
static const GTypeInfo selector_pad_info = {
sizeof (RsnSelectorPadClass),
NULL,
NULL,
(GClassInitFunc) gst_selector_pad_class_init,
NULL,
NULL,
sizeof (RsnSelectorPad),
0,
(GInstanceInitFunc) gst_selector_pad_init,
};
selector_pad_type =
g_type_register_static (GST_TYPE_PAD, "RsnSelectorPad",
&selector_pad_info, 0);
}
return selector_pad_type;
}
static void
gst_selector_pad_class_init (RsnSelectorPadClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
selector_pad_parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = gst_selector_pad_finalize;
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_selector_pad_get_property);
g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
g_param_spec_boxed ("tags", "Tags",
"The currently active tags on the pad", GST_TYPE_TAG_LIST,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
g_param_spec_boolean ("active", "Active",
"If the pad is currently active", FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
static void
gst_selector_pad_init (RsnSelectorPad * pad)
{
gst_selector_pad_reset (pad);
}
static void
gst_selector_pad_finalize (GObject * object)
{
RsnSelectorPad *pad;
pad = GST_SELECTOR_PAD_CAST (object);
if (pad->tags)
gst_tag_list_free (pad->tags);
G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object);
}
static void
gst_selector_pad_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
RsnSelectorPad *pad;
pad = GST_SELECTOR_PAD (object);
switch (prop_id) {
case PROP_PAD_TAGS:
GST_OBJECT_LOCK (object);
g_value_set_boxed (value, pad->tags);
GST_OBJECT_UNLOCK (object);
break;
case PROP_PAD_ACTIVE:
{
RsnStreamSelector *sel;
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
g_value_set_boolean (value, rsn_stream_selector_is_active_sinkpad (sel,
GST_PAD_CAST (pad)));
gst_object_unref (sel);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_selector_pad_reset (RsnSelectorPad * pad)
{
pad->active = FALSE;
pad->eos = FALSE;
gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
}
/* strictly get the linked pad from the sinkpad. If the pad is active we return
* the srcpad else we return NULL */
static GList *
gst_selector_pad_get_linked_pads (GstPad * pad)
{
GstPad *otherpad;
otherpad = rsn_stream_selector_get_linked_pad (pad, TRUE);
if (!otherpad)
return NULL;
/* need to drop the ref, internal linked pads is not MT safe */
gst_object_unref (otherpad);
return g_list_append (NULL, otherpad);
}
static gboolean
gst_selector_pad_event (GstPad * pad, GstEvent * event)
{
gboolean res = TRUE;
gboolean forward = TRUE;
RsnStreamSelector *sel;
RsnSelectorPad *selpad;
GstPad *active_sinkpad;
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
selpad = GST_SELECTOR_PAD_CAST (pad);
/* only forward if we are dealing with the active sinkpad */
active_sinkpad = rsn_stream_selector_activate_sinkpad (sel, pad);
forward = (active_sinkpad == pad);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
gst_selector_pad_reset (selpad);
break;
case GST_EVENT_NEWSEGMENT:
{
gboolean update;
GstFormat format;
gdouble rate, arate;
gint64 start, stop, time;
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
&start, &stop, &time);
GST_DEBUG_OBJECT (selpad,
"configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
"format %d, "
"%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
gst_segment_set_newsegment_full (&selpad->segment, update,
rate, arate, format, start, stop, time);
/* if we are not going to forward the segment, mark the segment as
* pending */
if (!forward)
selpad->segment_pending = TRUE;
break;
}
case GST_EVENT_TAG:
{
GstTagList *tags;
GST_OBJECT_LOCK (selpad);
if (selpad->tags)
gst_tag_list_free (selpad->tags);
gst_event_parse_tag (event, &tags);
if (tags)
tags = gst_tag_list_copy (tags);
selpad->tags = tags;
GST_DEBUG_OBJECT (sel, "received tags %" GST_PTR_FORMAT, selpad->tags);
GST_OBJECT_UNLOCK (selpad);
break;
}
case GST_EVENT_EOS:
selpad->eos = TRUE;
break;
default:
break;
}
if (forward)
res = gst_pad_push_event (sel->srcpad, event);
else
gst_event_unref (event);
gst_object_unref (sel);
return res;
}
static GstCaps *
gst_selector_pad_getcaps (GstPad * pad)
{
RsnStreamSelector *sel;
GstCaps *caps;
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
caps = gst_pad_peer_get_caps (sel->srcpad);
if (caps == NULL)
caps = gst_caps_new_any ();
gst_object_unref (sel);
return caps;
}
static GstFlowReturn
gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
guint size, GstCaps * caps, GstBuffer ** buf)
{
RsnStreamSelector *sel;
GstFlowReturn result;
GstPad *active_sinkpad;
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
active_sinkpad = rsn_stream_selector_activate_sinkpad (sel, pad);
/* Fallback allocation for buffers from pads except the selected one */
if (pad != active_sinkpad) {
GST_DEBUG_OBJECT (sel,
"Pad %s:%s is not selected. Performing fallback allocation",
GST_DEBUG_PAD_NAME (pad));
*buf = NULL;
result = GST_FLOW_OK;
} else {
result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf);
/* FIXME: HACK. If buffer alloc returns not-linked, perform a fallback
* allocation. This should NOT be necessary, because playbin should
* properly block the source pad from running until it's finished hooking
* everything up, but playbin needs refactoring first. */
if (result == GST_FLOW_NOT_LINKED) {
GST_DEBUG_OBJECT (sel,
"No peer pad yet - performing fallback allocation for pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
*buf = NULL;
result = GST_FLOW_OK;
}
}
gst_object_unref (sel);
return result;
}
static GstFlowReturn
gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
{
RsnStreamSelector *sel;
GstFlowReturn res;
GstPad *active_sinkpad;
RsnSelectorPad *selpad;
GstClockTime timestamp;
GstSegment *seg;
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
selpad = GST_SELECTOR_PAD_CAST (pad);
seg = &selpad->segment;
active_sinkpad = rsn_stream_selector_activate_sinkpad (sel, pad);
timestamp = GST_BUFFER_TIMESTAMP (buf);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
GST_DEBUG_OBJECT (sel, "received timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
gst_segment_set_last_stop (seg, seg->format, timestamp);
}
/* Ignore buffers from pads except the selected one */
if (pad != active_sinkpad)
goto ignore;
/* if we have a pending segment, push it out now */
if (selpad->segment_pending) {
gst_pad_push_event (sel->srcpad, gst_event_new_new_segment_full (FALSE,
seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop,
seg->time));
selpad->segment_pending = FALSE;
}
/* forward */
GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s:%s", buf,
GST_DEBUG_PAD_NAME (pad));
res = gst_pad_push (sel->srcpad, buf);
done:
gst_object_unref (sel);
return res;
/* dropped buffers */
ignore:
{
GST_DEBUG_OBJECT (sel, "Ignoring buffer %p from pad %s:%s",
buf, GST_DEBUG_PAD_NAME (pad));
gst_buffer_unref (buf);
res = GST_FLOW_NOT_LINKED;
goto done;
}
}
static void rsn_stream_selector_dispose (GObject * object);
static void rsn_stream_selector_finalize (GObject * object);
static void rsn_stream_selector_init (RsnStreamSelector * sel);
static void rsn_stream_selector_base_init (RsnStreamSelectorClass * klass);
static void rsn_stream_selector_class_init (RsnStreamSelectorClass * klass);
static void rsn_stream_selector_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void rsn_stream_selector_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static GstPad *rsn_stream_selector_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static void rsn_stream_selector_release_pad (GstElement * element,
GstPad * pad);
static GList *rsn_stream_selector_get_linked_pads (GstPad * pad);
static GstCaps *rsn_stream_selector_getcaps (GstPad * pad);
static GstElementClass *parent_class = NULL;
GType
rsn_stream_selector_get_type (void)
{
static GType stream_selector_type = 0;
if (!stream_selector_type) {
static const GTypeInfo stream_selector_info = {
sizeof (RsnStreamSelectorClass),
(GBaseInitFunc) rsn_stream_selector_base_init,
NULL,
(GClassInitFunc) rsn_stream_selector_class_init,
NULL,
NULL,
sizeof (RsnStreamSelector),
0,
(GInstanceInitFunc) rsn_stream_selector_init,
};
stream_selector_type =
g_type_register_static (GST_TYPE_ELEMENT,
"RsnStreamSelector", &stream_selector_info, 0);
GST_DEBUG_CATEGORY_INIT (stream_selector_debug,
"streamselector", 0, "A stream-selector element");
}
return stream_selector_type;
}
static void
rsn_stream_selector_base_init (RsnStreamSelectorClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_set_details (element_class, &rsn_stream_selector_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&rsn_stream_selector_sink_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&rsn_stream_selector_src_factory));
}
static void
rsn_stream_selector_class_init (RsnStreamSelectorClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = rsn_stream_selector_dispose;
gobject_class->finalize = rsn_stream_selector_finalize;
gobject_class->set_property =
GST_DEBUG_FUNCPTR (rsn_stream_selector_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (rsn_stream_selector_get_property);
g_object_class_install_property (gobject_class, PROP_N_PADS,
g_param_spec_uint ("n-pads", "Number of Pads",
"The number of sink pads", 0, G_MAXUINT, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
g_param_spec_object ("active-pad", "Active Pad",
"The currently active sink pad", GST_TYPE_PAD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->request_new_pad = rsn_stream_selector_request_new_pad;
gstelement_class->release_pad = rsn_stream_selector_release_pad;
}
static void
rsn_stream_selector_init (RsnStreamSelector * sel)
{
sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_pad_set_internal_link_function (sel->srcpad,
GST_DEBUG_FUNCPTR (rsn_stream_selector_get_linked_pads));
gst_pad_set_getcaps_function (sel->srcpad,
GST_DEBUG_FUNCPTR (rsn_stream_selector_getcaps));
gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
/* sinkpad management */
sel->padcount = 0;
sel->active_sinkpad = NULL;
gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
}
static void
rsn_stream_selector_dispose (GObject * object)
{
RsnStreamSelector *sel = RSN_STREAM_SELECTOR (object);
if (sel->active_sinkpad) {
gst_object_unref (sel->active_sinkpad);
sel->active_sinkpad = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
rsn_stream_selector_finalize (GObject * object)
{
RsnStreamSelector *sel;
sel = RSN_STREAM_SELECTOR (object);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
rsn_stream_selector_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
RsnStreamSelector *sel = RSN_STREAM_SELECTOR (object);
switch (prop_id) {
case PROP_ACTIVE_PAD:
{
GstPad *pad = NULL;
GstPad **active_pad_p;
pad = g_value_get_object (value);
GST_OBJECT_LOCK (object);
if (pad != sel->active_sinkpad) {
RsnSelectorPad *selpad;
selpad = GST_SELECTOR_PAD_CAST (pad);
/* we can only activate pads that have data received */
if (selpad && !selpad->active) {
GST_DEBUG_OBJECT (sel, "No data received on pad %" GST_PTR_FORMAT,
pad);
} else {
active_pad_p = &sel->active_sinkpad;
gst_object_replace ((GstObject **) active_pad_p,
GST_OBJECT_CAST (pad));
GST_DEBUG_OBJECT (sel, "New active pad is %" GST_PTR_FORMAT,
sel->active_sinkpad);
}
}
GST_OBJECT_UNLOCK (object);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
rsn_stream_selector_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
RsnStreamSelector *sel = RSN_STREAM_SELECTOR (object);
switch (prop_id) {
case PROP_N_PADS:
GST_OBJECT_LOCK (object);
g_value_set_uint (value, sel->n_pads);
GST_OBJECT_UNLOCK (object);
break;
case PROP_ACTIVE_PAD:{
GST_OBJECT_LOCK (object);
g_value_set_object (value, sel->active_sinkpad);
GST_OBJECT_UNLOCK (object);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstPad *
rsn_stream_selector_get_linked_pad (GstPad * pad, gboolean strict)
{
RsnStreamSelector *sel;
GstPad *otherpad = NULL;
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
GST_OBJECT_LOCK (sel);
if (pad == sel->srcpad)
otherpad = sel->active_sinkpad;
else if (pad == sel->active_sinkpad || !strict)
otherpad = sel->srcpad;
if (otherpad)
gst_object_ref (otherpad);
GST_OBJECT_UNLOCK (sel);
gst_object_unref (sel);
return otherpad;
}
static GstCaps *
rsn_stream_selector_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstObject *parent;
GstCaps *caps;
otherpad = rsn_stream_selector_get_linked_pad (pad, FALSE);
parent = gst_object_get_parent (GST_OBJECT (pad));
if (!otherpad) {
GST_DEBUG_OBJECT (parent,
"Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad));
caps = gst_caps_new_any ();
} else {
GST_DEBUG_OBJECT (parent,
"Pad %s:%s is linked (to %s:%s), returning peer caps",
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad));
/* if the peer has caps, use those. If the pad is not linked, this function
* returns NULL and we return ANY */
if (!(caps = gst_pad_peer_get_caps (otherpad)))
caps = gst_caps_new_any ();
gst_object_unref (otherpad);
}
gst_object_unref (parent);
return caps;
}
/* check if the pad is the active sinkpad */
static gboolean
rsn_stream_selector_is_active_sinkpad (RsnStreamSelector * sel, GstPad * pad)
{
RsnSelectorPad *selpad;
gboolean res;
selpad = GST_SELECTOR_PAD_CAST (pad);
GST_OBJECT_LOCK (sel);
res = (pad == sel->active_sinkpad);
GST_OBJECT_UNLOCK (sel);
return res;
}
/* Get or create the active sinkpad */
static GstPad *
rsn_stream_selector_activate_sinkpad (RsnStreamSelector * sel, GstPad * pad)
{
GstPad *active_sinkpad;
RsnSelectorPad *selpad;
selpad = GST_SELECTOR_PAD_CAST (pad);
GST_OBJECT_LOCK (sel);
selpad->active = TRUE;
active_sinkpad = sel->active_sinkpad;
if (active_sinkpad == NULL) {
/* first pad we get an alloc on becomes the activated pad by default */
active_sinkpad = sel->active_sinkpad = gst_object_ref (pad);
GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
}
GST_OBJECT_UNLOCK (sel);
return active_sinkpad;
}
static GList *
rsn_stream_selector_get_linked_pads (GstPad * pad)
{
GstPad *otherpad;
otherpad = rsn_stream_selector_get_linked_pad (pad, TRUE);
if (!otherpad)
return NULL;
/* need to drop the ref, internal linked pads is not MT safe */
gst_object_unref (otherpad);
return g_list_append (NULL, otherpad);
}
static GstPad *
rsn_stream_selector_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused)
{
RsnStreamSelector *sel;
gchar *name = NULL;
GstPad *sinkpad = NULL;
sel = RSN_STREAM_SELECTOR (element);
g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
GST_OBJECT_LOCK (sel);
name = g_strdup_printf ("sink%d", sel->padcount++);
sinkpad = g_object_new (RSN_TYPE_SELECTOR_PAD,
"name", name, "direction", templ->direction, "template", templ, NULL);
g_free (name);
sel->n_pads++;
GST_OBJECT_UNLOCK (sel);
gst_pad_set_event_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_selector_pad_event));
gst_pad_set_getcaps_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
gst_pad_set_chain_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
gst_pad_set_internal_link_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_selector_pad_get_linked_pads));
gst_pad_set_bufferalloc_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc));
gst_pad_set_active (sinkpad, TRUE);
gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
return sinkpad;
}
static void
rsn_stream_selector_release_pad (GstElement * element, GstPad * pad)
{
RsnStreamSelector *sel;
sel = RSN_STREAM_SELECTOR (element);
GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
GST_OBJECT_LOCK (sel);
/* if the pad was the active pad, makes us select a new one */
if (sel->active_sinkpad == pad) {
GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
sel->active_sinkpad = NULL;
}
sel->n_pads--;
GST_OBJECT_UNLOCK (sel);
gst_pad_set_active (pad, FALSE);
gst_element_remove_pad (GST_ELEMENT (sel), pad);
}

View file

@ -0,0 +1,62 @@
/* GStreamer
* Copyright (C) 2003 Julien Moutte <julien@moutte.net>
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
*
* 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 __RSN_STREAM_SELECTOR_H__
#define __RSN_STREAM_SELECTOR_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define RSN_TYPE_STREAM_SELECTOR \
(rsn_stream_selector_get_type())
#define RSN_STREAM_SELECTOR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), RSN_TYPE_STREAM_SELECTOR, RsnStreamSelector))
#define RSN_STREAM_SELECTOR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), RSN_TYPE_STREAM_SELECTOR, RsnStreamSelectorClass))
#define RSN_IS_STREAM_SELECTOR(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), RSN_TYPE_STREAM_SELECTOR))
#define RSN_IS_STREAM_SELECTOR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), RSN_TYPE_STREAM_SELECTOR))
typedef struct _RsnStreamSelector RsnStreamSelector;
typedef struct _RsnStreamSelectorClass RsnStreamSelectorClass;
struct _RsnStreamSelector {
GstElement element;
GstPad *srcpad;
GstPad *active_sinkpad;
guint n_pads;
guint padcount;
GstSegment segment;
};
struct _RsnStreamSelectorClass {
GstElementClass parent_class;
};
GType rsn_stream_selector_get_type (void);
G_END_DECLS
#endif /* __RSN_STREAM_SELECTOR_H__ */

View file

@ -395,12 +395,22 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event)
const GstStructure *structure = gst_event_get_structure (event);
const char *event_type;
if (structure == NULL) {
res = gst_pad_event_default (pad, event);
break;
}
if (!gst_structure_has_name (structure, "application/x-gst-dvd")) {
res = gst_pad_event_default (pad, event);
break;
}
event_type = gst_structure_get_string (structure, "event");
if (event_type == NULL) {
res = gst_pad_event_default (pad, event);
break;
}
GST_DEBUG_OBJECT (dvdspu,
"DVD event of type %s on video pad", event_type);