mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
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:
parent
bcc41766b8
commit
0951e00dc0
26 changed files with 10061 additions and 0 deletions
38
ChangeLog
38
ChangeLog
|
@ -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:
|
||||
|
|
33
configure.ac
33
configure.ac
|
@ -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
|
||||
|
|
|
@ -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
30
ext/resindvd/Makefile.am
Normal 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
175
ext/resindvd/gstmpegdefs.h
Normal 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
1943
ext/resindvd/gstmpegdemux.c
Normal file
File diff suppressed because it is too large
Load diff
127
ext/resindvd/gstmpegdemux.h
Normal file
127
ext/resindvd/gstmpegdemux.h
Normal 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
156
ext/resindvd/gstmpegdesc.c
Normal 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
249
ext/resindvd/gstmpegdesc.h
Normal 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
623
ext/resindvd/gstpesfilter.c
Normal 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;
|
||||
}
|
88
ext/resindvd/gstpesfilter.h
Normal file
88
ext/resindvd/gstpesfilter.h
Normal 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
53
ext/resindvd/plugin.c
Normal 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
11
ext/resindvd/resin-play
Executable 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
758
ext/resindvd/resindvdbin.c
Normal 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;
|
||||
}
|
80
ext/resindvd/resindvdbin.h
Normal file
80
ext/resindvd/resindvdbin.h
Normal 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
1426
ext/resindvd/resindvdsrc.c
Normal file
File diff suppressed because it is too large
Load diff
113
ext/resindvd/resindvdsrc.h
Normal file
113
ext/resindvd/resindvdsrc.h
Normal 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__ */
|
378
ext/resindvd/rsnaudiomunge.c
Normal file
378
ext/resindvd/rsnaudiomunge.c
Normal 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;
|
||||
}
|
61
ext/resindvd/rsnaudiomunge.h
Normal file
61
ext/resindvd/rsnaudiomunge.h
Normal 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
2423
ext/resindvd/rsnbasesrc.c
Normal file
File diff suppressed because it is too large
Load diff
257
ext/resindvd/rsnbasesrc.h
Normal file
257
ext/resindvd/rsnbasesrc.h
Normal 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
101
ext/resindvd/rsnpushsrc.c
Normal 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
76
ext/resindvd/rsnpushsrc.h
Normal 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__ */
|
784
ext/resindvd/rsnstreamselector.c
Normal file
784
ext/resindvd/rsnstreamselector.c
Normal 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);
|
||||
}
|
62
ext/resindvd/rsnstreamselector.h
Normal file
62
ext/resindvd/rsnstreamselector.h
Normal 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__ */
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue