[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog Makefile.am configure.ac backen...
From: |
Tomas Groth |
Subject: |
[Gnash-commit] gnash ChangeLog Makefile.am configure.ac backen... |
Date: |
Thu, 27 Sep 2007 23:59:57 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Tomas Groth <tgc> 07/09/27 23:59:57
Modified files:
. : ChangeLog Makefile.am configure.ac
backend : Makefile.am
gui : Makefile.am
libbase : FLVParser.h
server : Makefile.am video_stream_instance.cpp
video_stream_instance.h
server/asobj : Makefile.am
server/parser : Makefile.am video_stream_def.cpp
video_stream_def.h
server/swf : tag_loaders.cpp
server/vm : Makefile.am
testsuite : Makefile.am
testsuite/misc-ming.all: Makefile.am
testsuite/movies.all: Makefile.am
testsuite/samples: Makefile.am
utilities : Makefile.am
Added files:
libmedia : AudioDecoder.h AudioDecoderNellymoser.cpp
AudioDecoderNellymoser.h AudioDecoderSimple.cpp
AudioDecoderSimple.h FLVParser.cpp FLVParser.h
Makefile.am Makefile.in MediaBuffer.h
MediaDecoder.h MediaParser.h SoundInfo.h
VideoDecoder.h sound_handler.h
libmedia/gst : VideoDecoderGst.cpp VideoDecoderGst.h
gstappbuffer.c gstappbuffer.h gstappsink.c
gstappsink.h gstappsrc.c gstappsrc.h
gstgnashsrc.c gstgnashsrc.h
sound_handler_gst.cpp sound_handler_gst.h
libmedia/sdl : AudioDecoderFfmpeg.cpp AudioDecoderFfmpeg.h
AudioDecoderMad.cpp AudioDecoderMad.h
MediaDecoderSdl.cpp MediaDecoderSdl.h
MediaParserFfmpeg.cpp MediaParserFfmpeg.h
VideoDecoderFfmpeg.cpp VideoDecoderFfmpeg.h
sound_handler_sdl.cpp sound_handler_sdl.h
Removed files:
backend : sound_handler.h sound_handler_gst.cpp
sound_handler_gst.h sound_handler_mp3.cpp
sound_handler_sdl.cpp sound_handler_sdl.h
libbase : embedVideoDecoder.h embedVideoDecoderFfmpeg.cpp
embedVideoDecoderFfmpeg.h
embedVideoDecoderGst.cpp embedVideoDecoderGst.h
Log message:
* backend/sound_handler*, libbase/embedVideoDecoder*: Moved to
libmedia.
* Makefile.am, configure.ac, backend/Makefile.am,
gui/Makefile.am,
server/Makefile.am, server/asobj/Makefile.am,
server/parser/Makefile.am,
server/vm/Makefile.am, testsuite/Makefile.am,
testsuite/misc-ming.all/Makefile.am,
testsuite/movies.all/Makefile.am,
testsuite/samples/Makefile.am,
utilities/Makefile.am: Added the new libmedia to the build
system.
* libbase/FLVParser.h: Moved some declerations inside the class
to avoid
conflicts with MediaParser.h.
* server/video_stream_instance.{cpp,h},
server/parser/video_stream_def.{cpp,h}:
Use VideoDecoder instead of embedVideoDecoder.
* server/swf/tag_loaders.cpp: Don't decode and resample the
ADPCM and raw audio
before passing to the soundhandler.
Read more about libmedia here:
http://wiki.gnashdev.org/wiki/index.php/Main_Page
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.4454&r2=1.4455
http://cvs.savannah.gnu.org/viewcvs/gnash/Makefile.am?cvsroot=gnash&r1=1.90&r2=1.91
http://cvs.savannah.gnu.org/viewcvs/gnash/configure.ac?cvsroot=gnash&r1=1.423&r2=1.424
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/Makefile.am?cvsroot=gnash&r1=1.61&r2=1.62
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler.h?cvsroot=gnash&r1=1.31&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler_gst.cpp?cvsroot=gnash&r1=1.65&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler_gst.h?cvsroot=gnash&r1=1.18&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler_mp3.cpp?cvsroot=gnash&r1=1.7&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler_sdl.cpp?cvsroot=gnash&r1=1.85&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler_sdl.h?cvsroot=gnash&r1=1.33&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/Makefile.am?cvsroot=gnash&r1=1.107&r2=1.108
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/FLVParser.h?cvsroot=gnash&r1=1.18&r2=1.19
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/embedVideoDecoder.h?cvsroot=gnash&r1=1.9&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/embedVideoDecoderFfmpeg.cpp?cvsroot=gnash&r1=1.22&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/embedVideoDecoderFfmpeg.h?cvsroot=gnash&r1=1.8&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/embedVideoDecoderGst.cpp?cvsroot=gnash&r1=1.11&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/embedVideoDecoderGst.h?cvsroot=gnash&r1=1.5&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoder.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoderNellymoser.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoderNellymoser.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoderSimple.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoderSimple.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/FLVParser.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/FLVParser.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/Makefile.am?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/Makefile.in?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/MediaBuffer.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/MediaDecoder.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/MediaParser.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/SoundInfo.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/VideoDecoder.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sound_handler.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/VideoDecoderGst.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/VideoDecoderGst.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstappbuffer.c?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstappbuffer.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstappsink.c?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstappsink.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstappsrc.c?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstappsrc.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstgnashsrc.c?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/gstgnashsrc.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/sound_handler_gst.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/sound_handler_gst.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/AudioDecoderFfmpeg.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/AudioDecoderFfmpeg.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/AudioDecoderMad.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/AudioDecoderMad.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/MediaDecoderSdl.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/MediaDecoderSdl.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/MediaParserFfmpeg.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/MediaParserFfmpeg.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/VideoDecoderFfmpeg.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/VideoDecoderFfmpeg.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/sound_handler_sdl.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/sdl/sound_handler_sdl.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/server/Makefile.am?cvsroot=gnash&r1=1.125&r2=1.126
http://cvs.savannah.gnu.org/viewcvs/gnash/server/video_stream_instance.cpp?cvsroot=gnash&r1=1.39&r2=1.40
http://cvs.savannah.gnu.org/viewcvs/gnash/server/video_stream_instance.h?cvsroot=gnash&r1=1.21&r2=1.22
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Makefile.am?cvsroot=gnash&r1=1.45&r2=1.46
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/Makefile.am?cvsroot=gnash&r1=1.39&r2=1.40
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/video_stream_def.cpp?cvsroot=gnash&r1=1.17&r2=1.18
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/video_stream_def.h?cvsroot=gnash&r1=1.11&r2=1.12
http://cvs.savannah.gnu.org/viewcvs/gnash/server/swf/tag_loaders.cpp?cvsroot=gnash&r1=1.144&r2=1.145
http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/Makefile.am?cvsroot=gnash&r1=1.14&r2=1.15
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/Makefile.am?cvsroot=gnash&r1=1.41&r2=1.42
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/Makefile.am?cvsroot=gnash&r1=1.155&r2=1.156
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/movies.all/Makefile.am?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/samples/Makefile.am?cvsroot=gnash&r1=1.20&r2=1.21
http://cvs.savannah.gnu.org/viewcvs/gnash/utilities/Makefile.am?cvsroot=gnash&r1=1.57&r2=1.58
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.4454
retrieving revision 1.4455
diff -u -b -r1.4454 -r1.4455
--- ChangeLog 27 Sep 2007 23:06:55 -0000 1.4454
+++ ChangeLog 27 Sep 2007 23:59:50 -0000 1.4455
@@ -1,3 +1,30 @@
+2007-09-27 Tomas Groth Christensen <address@hidden>
+
+ * libmedia/, libmedia/sdl/, libmedia/gst/,
+ (in libmedia:) AudioDecoder.h, AudioDecoderSimple.{h,cpp},
Makefile.am,
+ AudioDecoderNellymoser.{h,cpp}, FLVParser.{h,cpp}, MediaDecoder.h,
+ MediaParser.h, SoundInfo.h, MediaBuffer.h, VideoDecoder.h,
sound_handler.h,
+ (in libmedia/sdl:) AudioDecoderFfmpeg.{h,cpp},
AudioDecoderMad.{h,cpp},
+ MediaDecoderSdl.{h,cpp}, MediaParserFfmpeg.{cpp,h},
VideoDecoderFfmpeg.{h,cpp},
+ sound_handler_sdl.{h,cpp},
+ (in libmedia/gst:) VideoDecoderGst.{h,cpp}, sound_handler_gst.{h,cpp},
+ gstgnashsrc.{h.c}, gstappbuffer.{c,h}, gstappsink.{c,h},
gstappsrc.{c,h}:
+ Files added for the new libmedia (finally!!). Some og theese files
are moved
+ from the backend/ and libbase/ folders (see below). Not all files are
yet in use.
+ * backend/sound_handler*, libbase/embedVideoDecoder*: Moved to libmedia.
+ * Makefile.am, configure.ac, backend/Makefile.am, gui/Makefile.am,
+ server/Makefile.am, server/asobj/Makefile.am,
server/parser/Makefile.am,
+ server/vm/Makefile.am, testsuite/Makefile.am,
testsuite/misc-ming.all/Makefile.am,
+ testsuite/movies.all/Makefile.am, testsuite/samples/Makefile.am,
+ utilities/Makefile.am: Added the new libmedia to the build system.
+ * libbase/FLVParser.h: Moved some declerations inside the class to avoid
+ conflicts with MediaParser.h.
+ * server/video_stream_instance.{cpp,h},
server/parser/video_stream_def.{cpp,h}:
+ Use VideoDecoder instead of embedVideoDecoder.
+ * server/swf/tag_loaders.cpp: Don't decode and resample the ADPCM and
raw audio
+ before passing to the soundhandler.
+ Read more about libmedia here:
http://wiki.gnashdev.org/wiki/index.php/Main_Page
+
2007-09-28 Sandro Santilli <address@hidden>
* server/character.{cpp,h}: drop the get_text_value override here.
Index: Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/Makefile.am,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -b -r1.90 -r1.91
--- Makefile.am 15 Sep 2007 03:06:37 -0000 1.90
+++ Makefile.am 27 Sep 2007 23:59:50 -0000 1.91
@@ -15,7 +15,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-# $Id: Makefile.am,v 1.90 2007/09/15 03:06:37 rsavoye Exp $
+# $Id: Makefile.am,v 1.91 2007/09/27 23:59:50 tgc Exp $
## Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = 1.6.0
@@ -26,6 +26,7 @@
libbase \
libgeometry \
libamf \
+ libmedia \
server \
backend \
utilities \
Index: configure.ac
===================================================================
RCS file: /sources/gnash/gnash/configure.ac,v
retrieving revision 1.423
retrieving revision 1.424
diff -u -b -r1.423 -r1.424
--- configure.ac 27 Sep 2007 00:29:30 -0000 1.423
+++ configure.ac 27 Sep 2007 23:59:50 -0000 1.424
@@ -15,7 +15,7 @@
dnl Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
dnl
-dnl $Id: configure.ac,v 1.423 2007/09/27 00:29:30 rsavoye Exp $
+dnl $Id: configure.ac,v 1.424 2007/09/27 23:59:50 tgc Exp $
AC_PREREQ(2.50)
AC_INIT(gnash, cvs)
@@ -1446,6 +1446,7 @@
AC_CONFIG_LINKS(testsuite/libbase/gnashrc:testsuite/libbase/gnashrc.in)
AC_OUTPUT(Makefile
+libmedia/Makefile
po/Makefile
libbase/Makefile
libgeometry/Makefile
Index: backend/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/backend/Makefile.am,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -b -r1.61 -r1.62
--- backend/Makefile.am 16 Sep 2007 18:26:49 -0000 1.61
+++ backend/Makefile.am 27 Sep 2007 23:59:50 -0000 1.62
@@ -71,44 +71,21 @@
render_handler_agg_compat.h \
render_handler_agg_style.h \
render_handler_cairo.h \
- render_handler_tri.h \
- sound_handler.h \
- sound_handler_gst.h \
- sound_handler_sdl.h
+ render_handler_tri.h
# bin_PROGRAMS = gnash
pkglib_LTLIBRARIES = libgnashbackend.la
# RENDER_SOURCES = render_handler_tri.cpp
-SOUND_SOURCES =
-
-if USE_SOUND_GST
-SOUND_SOURCES += sound_handler_gst.cpp sound_handler_gst.h
-libgnashbackend_LIBS += $(GSTREAMER_LIBS)
-libgnashbackend_LIBS += $(LIBXML_LIBS)
-AM_CPPFLAGS += $(GSTREAMER_CFLAGS)
-AM_CPPFLAGS += $(LIBXML_CFLAGS)
-endif
-
-if USE_SOUND_SDL
-SOUND_SOURCES += sound_handler_sdl.cpp sound_handler_sdl.h
-if USE_FFMPEG_ENGINE
-libgnashbackend_LIBS += $(FFMPEG_LIBS)
-AM_CPPFLAGS += $(FFMPEG_CFLAGS)
-endif
-if USE_MAD_ENGINE
-libgnashbackend_LIBS += $(MAD_LIBS)
-AM_CPPFLAGS += $(MAD_CFLAGS)
-endif
-endif
libgnashbackend_la_LIBADD = \
$(top_builddir)/libbase/libgnashbase.la \
$(top_builddir)/server/libgnashserver.la \
$(libgnashbackend_LIBS)
-libgnashbackend_la_SOURCES = $(SOUND_SOURCES)
+libgnashbackend_la_SOURCES =
+#$(SOUND_SOURCES)
libgnashbackend_la_LDFLAGS = -release $(VERSION)
Index: gui/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/gui/Makefile.am,v
retrieving revision 1.107
retrieving revision 1.108
diff -u -b -r1.107 -r1.108
--- gui/Makefile.am 15 Sep 2007 03:06:38 -0000 1.107
+++ gui/Makefile.am 27 Sep 2007 23:59:51 -0000 1.108
@@ -41,6 +41,9 @@
-I$(top_srcdir)/libbase \
-I$(top_srcdir)/backend \
-I$(top_srcdir)/libgeometry \
+ -I$(top_srcdir)/libmedia \
+ -I$(top_srcdir)/libmedia/sdl \
+ -I$(top_srcdir)/libmedia/gst \
-DLOCALEDIR=\"$(localedir)\" \
-DPLUGINSDIR=\"$(pluginsdir)\" \
$(LIBXML_CFLAGS) \
@@ -88,6 +91,7 @@
GNASH_LIBS = \
$(top_builddir)/libamf/libgnashamf.la \
$(top_builddir)/backend/libgnashbackend.la \
+ $(top_builddir)/libmedia/libgnashmedia.la \
$(top_builddir)/server/libgnashserver.la \
$(top_builddir)/libgeometry/libgnashgeo.la \
$(top_builddir)/libbase/libgnashbase.la
Index: libbase/FLVParser.h
===================================================================
RCS file: /sources/gnash/gnash/libbase/FLVParser.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -b -r1.18 -r1.19
--- libbase/FLVParser.h 8 Jul 2007 20:27:39 -0000 1.18
+++ libbase/FLVParser.h 27 Sep 2007 23:59:52 -0000 1.19
@@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: FLVParser.h,v 1.18 2007/07/08 20:27:39 martinwguy Exp $
+// $Id: FLVParser.h,v 1.19 2007/09/27 23:59:52 tgc Exp $
// Information about the FLV format can be found at http://osflash.org/flv
@@ -30,38 +30,7 @@
namespace gnash {
-enum videoCodecType
-{
- VIDEO_CODEC_H263 = 2, // H263/SVQ3 video codec
- VIDEO_CODEC_SCREENVIDEO = 3, // Screenvideo codec
- VIDEO_CODEC_VP6 = 4, // On2 VP6 video codec
- VIDEO_CODEC_VP6A = 5, // On2 VP6 Alpha video codec
- VIDEO_CODEC_SCREENVIDEO2 = 6 // Screenvideo2 codec
-};
-enum audioCodecType
-{
- AUDIO_CODEC_RAW = 0, // unspecified format. Useful for
8-bit sounds???
- AUDIO_CODEC_ADPCM = 1, // gnash doesn't pass this through; it
uncompresses and sends FORMAT_NATIVE16
- AUDIO_CODEC_MP3 = 2,
- AUDIO_CODEC_UNCOMPRESSED = 3, // 16 bits/sample, little-endian
- AUDIO_CODEC_NELLYMOSER_8HZ_MONO = 5, // According to ffmpeg
- AUDIO_CODEC_NELLYMOSER = 6 // Mystery proprietary format; see
nellymoser.com
-};
-
-enum tagType
-{
- AUDIO_TAG = 0x08,
- VIDEO_TAG = 0x09,
- META_TAG = 0x12
-};
-
-enum videoFrameType
-{
- KEY_FRAME = 1,
- INTER_FRAME = 2,
- DIS_INTER_FRAME = 3
-};
/// \brief
/// The FLVFrame class contains a video or audio frame, its size, its
@@ -137,7 +106,7 @@
/// Return true if this video frame is a key frame
bool isKeyFrame() const
{
- return frameType == KEY_FRAME;
+ return frameType == 1 /*KEY_FRAME*/;
}
};
@@ -170,6 +139,40 @@
public:
+ enum videoCodecType
+ {
+ VIDEO_CODEC_H263 = 2, // H263/SVQ3 video codec
+ VIDEO_CODEC_SCREENVIDEO = 3, // Screenvideo codec
+ VIDEO_CODEC_VP6 = 4, // On2 VP6 video codec
+ VIDEO_CODEC_VP6A = 5, // On2 VP6 Alpha video codec
+ VIDEO_CODEC_SCREENVIDEO2 = 6 // Screenvideo2 codec
+ };
+
+ enum audioCodecType
+ {
+ AUDIO_CODEC_RAW = 0, // unspecified format. Useful
for 8-bit sounds???
+ AUDIO_CODEC_ADPCM = 1, // gnash doesn't pass this through; it
uncompresses and sends FORMAT_NATIVE16
+ AUDIO_CODEC_MP3 = 2,
+ AUDIO_CODEC_UNCOMPRESSED = 3, // 16 bits/sample, little-endian
+ AUDIO_CODEC_NELLYMOSER_8HZ_MONO = 5, // According to ffmpeg
+ AUDIO_CODEC_NELLYMOSER = 6 // Mystery proprietary format;
see nellymoser.com
+ };
+
+ enum tagType
+ {
+ AUDIO_TAG = 0x08,
+ VIDEO_TAG = 0x09,
+ META_TAG = 0x12
+ };
+
+ enum videoFrameType
+ {
+ KEY_FRAME = 1,
+ INTER_FRAME = 2,
+ DIS_INTER_FRAME = 3
+ };
+
+
/// \brief
/// Create an FLV parser reading input from
/// the given LoadThread
Index: server/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/Makefile.am,v
retrieving revision 1.125
retrieving revision 1.126
diff -u -b -r1.125 -r1.126
--- server/Makefile.am 23 Sep 2007 08:48:17 -0000 1.125
+++ server/Makefile.am 27 Sep 2007 23:59:55 -0000 1.126
@@ -18,7 +18,7 @@
#
#
-# $Id: Makefile.am,v 1.125 2007/09/23 08:48:17 cmusick Exp $
+# $Id: Makefile.am,v 1.126 2007/09/27 23:59:55 tgc Exp $
AUTOMAKE_OPTIONS =
@@ -41,6 +41,9 @@
-I$(top_srcdir)/server/vm \
-I$(top_srcdir)/libbase \
-I$(top_srcdir)/libgeometry \
+ -I$(top_srcdir)/libmedia \
+ -I$(top_srcdir)/libmedia/sdl \
+ -I$(top_srcdir)/libmedia/gst \
-I$(top_srcdir) \
$(PTHREAD_CFLAGS) \
$(DMALLOC_CFLAGS) \
@@ -189,6 +192,7 @@
libgnashserver_la_LIBADD = \
$(top_builddir)/libbase/libgnashbase.la \
+ $(top_builddir)/libmedia/libgnashmedia.la \
$(top_builddir)/server/asobj/libgnashasobjs.la \
$(top_builddir)/server/parser/libgnashparser.la \
$(top_builddir)/server/vm/libgnashvm.la \
Index: server/video_stream_instance.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/video_stream_instance.cpp,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- server/video_stream_instance.cpp 21 Sep 2007 08:29:03 -0000 1.39
+++ server/video_stream_instance.cpp 27 Sep 2007 23:59:56 -0000 1.40
@@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_instance.cpp,v 1.39 2007/09/21 08:29:03 strk Exp $
+// $Id: video_stream_instance.cpp,v 1.40 2007/09/27 23:59:56 tgc Exp $
#include "sprite_instance.h"
#include "video_stream_instance.h"
@@ -213,7 +213,7 @@
if (size > 0 && data) {
- std::auto_ptr<image::image_base> i (
m_decoder->decodeFrame(data, size) );
+ std::auto_ptr<image::image_base>
i(m_decoder->decodeToImage(data, size));
if (i.get())
{
gnash::render::drawVideoFrame(i.get(), &m,
&bounds);
@@ -221,7 +221,7 @@
log_error(_("An error occured while decoding
video frame"));
}
} else {
- log_error(_("An error occured while decoding video
frame"));
+ log_error(_("Video frame data is missing - skipping
decoding"));
}
}
Index: server/video_stream_instance.h
===================================================================
RCS file: /sources/gnash/gnash/server/video_stream_instance.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- server/video_stream_instance.h 21 Sep 2007 08:29:03 -0000 1.21
+++ server/video_stream_instance.h 27 Sep 2007 23:59:56 -0000 1.22
@@ -16,14 +16,14 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_instance.h,v 1.21 2007/09/21 08:29:03 strk Exp $
+// $Id: video_stream_instance.h,v 1.22 2007/09/27 23:59:56 tgc Exp $
#ifndef GNASH_VIDEO_STREAM_INSTANCE_H
#define GNASH_VIDEO_STREAM_INSTANCE_H
#include "character.h" // for inheritance
#include "video_stream_def.h"
-#include "embedVideoDecoder.h"
+#include "VideoDecoder.h"
#include "snappingrange.h"
// Forward declarations
@@ -100,7 +100,7 @@
boost::intrusive_ptr<NetStream> _ns;
/// Decoder for embedded video
- std::auto_ptr<embedVideoDecoder> m_decoder;
+ std::auto_ptr<VideoDecoder> m_decoder;
};
void video_class_init(as_object& global);
Index: server/asobj/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Makefile.am,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -b -r1.45 -r1.46
--- server/asobj/Makefile.am 23 Sep 2007 08:48:18 -0000 1.45
+++ server/asobj/Makefile.am 27 Sep 2007 23:59:56 -0000 1.46
@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-# $Id: Makefile.am,v 1.45 2007/09/23 08:48:18 cmusick Exp $
+# $Id: Makefile.am,v 1.46 2007/09/27 23:59:56 tgc Exp $
AUTOMAKE_OPTIONS =
@@ -31,6 +31,9 @@
-I$(top_srcdir)/libgeometry \
-I$(top_srcdir)/libamf \
-I$(top_srcdir)/libltdl \
+ -I$(top_srcdir)/libmedia \
+ -I$(top_srcdir)/libmedia/gst \
+ -I$(top_srcdir)/libmedia/sdl \
-I$(top_srcdir) \
$(PTHREAD_CFLAGS) \
$(DMALLOC_CFLAGS) \
Index: server/parser/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/parser/Makefile.am,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- server/parser/Makefile.am 24 Sep 2007 15:39:31 -0000 1.39
+++ server/parser/Makefile.am 27 Sep 2007 23:59:56 -0000 1.40
@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-# $Id: Makefile.am,v 1.39 2007/09/24 15:39:31 cmusick Exp $
+# $Id: Makefile.am,v 1.40 2007/09/27 23:59:56 tgc Exp $
AUTOMAKE_OPTIONS =
@@ -35,6 +35,9 @@
-I$(top_srcdir)/server/asobj \
-I$(top_srcdir)/libbase \
-I$(top_srcdir)/libgeometry \
+ -I$(top_srcdir)/libmedia \
+ -I$(top_srcdir)/libmedia/sdl \
+ -I$(top_srcdir)/libmedia/gst \
-I$(top_srcdir)/libamf \
-I$(top_srcdir) \
$(LIBXML_CFLAGS) \
@@ -83,7 +86,8 @@
libgnashparser_la_LIBADD = \
$(top_builddir)/libamf/libgnashamf.la \
$(top_builddir)/libgeometry/libgnashgeo.la \
- $(top_builddir)/libbase/libgnashbase.la
+ $(top_builddir)/libbase/libgnashbase.la \
+ $(top_builddir)/libmedia/libgnashmedia.la
libgnashparser_la_LDFLAGS = $(BOOST_LIBS) -export-dynamic # -release
$(VERSION) -no-undefined
Index: server/parser/video_stream_def.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/parser/video_stream_def.cpp,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- server/parser/video_stream_def.cpp 17 Sep 2007 12:41:22 -0000 1.17
+++ server/parser/video_stream_def.cpp 27 Sep 2007 23:59:56 -0000 1.18
@@ -16,16 +16,16 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_def.cpp,v 1.17 2007/09/17 12:41:22 tgc Exp $
+// $Id: video_stream_def.cpp,v 1.18 2007/09/27 23:59:56 tgc Exp $
#include "video_stream_def.h"
#include "video_stream_instance.h"
#include "render.h"
#ifdef USE_FFMPEG
-#include "embedVideoDecoderFfmpeg.h"
+#include "VideoDecoderFfmpeg.h"
#elif defined(SOUND_GST)
-#include "embedVideoDecoderGst.h"
+#include "VideoDecoderGst.h"
#endif
namespace gnash {
@@ -66,7 +66,7 @@
m_deblocking_flags = in->read_uint(2);
m_smoothing_flags = in->read_bit();
- m_codec_id = in->read_u8();
+ m_codec_id = static_cast<videoCodecType>(in->read_u8());
}
else if (tag == SWF::VIDEOFRAME)
@@ -107,30 +107,31 @@
return ch;
}
-std::auto_ptr<embedVideoDecoder>
+std::auto_ptr<VideoDecoder>
video_stream_definition::get_decoder()
{
- std::auto_ptr<embedVideoDecoder> decoder;
+ std::auto_ptr<VideoDecoder> decoder;
if (m_num_frames == 0) return decoder;
#ifdef USE_FFMPEG
- decoder.reset( new embedVideoDecoderFfmpeg() );
+ decoder.reset( new VideoDecoderFfmpeg() );
#elif defined(SOUND_GST)
- decoder.reset( new embedVideoDecoderGst() );
+ decoder.reset( new VideoDecoderGst() );
#else
- decoder.reset( new embedVideoDecoder() );
+ decoder.reset( new VideoDecoder() );
#endif
- decoder->createDecoder(
+ bool ret = decoder->setup(
static_cast<int>(TWIPS_TO_PIXELS(m_bound.width())),// m_width,
static_cast<int>(TWIPS_TO_PIXELS(m_bound.height())), // m_height,
m_deblocking_flags,
m_smoothing_flags,
m_codec_id,
gnash::render::videoFrameFormat());
+ if (!ret) log_error("The videodecoder cannot decode this video");
return decoder;
}
Index: server/parser/video_stream_def.h
===================================================================
RCS file: /sources/gnash/gnash/server/parser/video_stream_def.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -b -r1.11 -r1.12
--- server/parser/video_stream_def.h 17 Sep 2007 12:41:22 -0000 1.11
+++ server/parser/video_stream_def.h 27 Sep 2007 23:59:56 -0000 1.12
@@ -16,7 +16,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_def.h,v 1.11 2007/09/17 12:41:22 tgc Exp $
+// $Id: video_stream_def.h,v 1.12 2007/09/27 23:59:56 tgc Exp $
#ifndef GNASH_VIDEO_STREAM_DEF_H
#define GNASH_VIDEO_STREAM_DEF_H
@@ -31,7 +31,7 @@
#include "swf.h"
#include "rect.h" // for composition
#include "execute_tag.h"
-#include "embedVideoDecoder.h"
+#include "VideoDecoder.h"
#include "image.h"
#include <map>
#include <boost/shared_array.hpp>
@@ -94,7 +94,7 @@
///
/// This function *never* returns a NULL pointer.
///
- std::auto_ptr<embedVideoDecoder> get_decoder();
+ std::auto_ptr<VideoDecoder> get_decoder();
/// Get the Video frame associated with the given SWF frame number
//
@@ -152,7 +152,7 @@
///
/// TODO: define an enumeration for the above values
///
- uint8_t m_codec_id;
+ videoCodecType m_codec_id;
/// Bounds of the video, as read from the DEFINEVIDEOSTREAM tag.
rect m_bound;
Index: server/swf/tag_loaders.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/swf/tag_loaders.cpp,v
retrieving revision 1.144
retrieving revision 1.145
diff -u -b -r1.144 -r1.145
--- server/swf/tag_loaders.cpp 26 Sep 2007 15:22:12 -0000 1.144
+++ server/swf/tag_loaders.cpp 27 Sep 2007 23:59:56 -0000 1.145
@@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-/* $Id: tag_loaders.cpp,v 1.144 2007/09/26 15:22:12 strk Exp $ */
+/* $Id: tag_loaders.cpp,v 1.145 2007/09/27 23:59:56 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -55,6 +55,7 @@
#include "video_stream_def.h"
#include "sound_definition.h"
#include "abc_block.h"
+#include "SoundInfo.h"
#ifdef HAVE_ZLIB_H
#include <zlib.h>
@@ -70,14 +71,6 @@
namespace gnash {
-// Forward declaration for functions at end of file
-//
-// Both modify "data" parameter, allocating memory for it.
-
-static void u8_expand(unsigned char* &data, stream* in,
- int sample_count, // in stereo, this is number of *pairs* of samples
- bool stereo);
-
namespace SWF {
namespace tag_loaders {
@@ -137,291 +130,6 @@
} // anonymous namespace
-// ----------------------------------------------------------------------------
-// ADPCMDecoder class
-// ----------------------------------------------------------------------------
-
-/// ADPCM decoder utilities
-//
-/// Algo from
http://www.circuitcellar.com/pastissues/articles/richey110/text.htm
-/// And also Jansen.
-/// Here's another reference:
http://www.geocities.com/SiliconValley/8682/aud3.txt
-/// Original IMA spec doesn't seem to be on the web :(
-///
-/// TODO: move in it's own file
-///
-class ADPCMDecoder {
-
-private:
-
- // Data from Alexis' SWF reference
- static int _index_update_table_2bits[2];
- static int _index_update_table_3bits[4];
- static int _index_update_table_4bits[8];
- static int _index_update_table_5bits[16];
-
- static int* s_index_update_tables[4];
-
- // Data from Jansen. http://homepages.cwi.nl/~jack/
- // Check out his Dutch retro punk songs, heh heh :)
- static const int STEPSIZE_CT = 89;
- static int s_stepsize[STEPSIZE_CT];
-
-
- static void doSample(int n_bits, int& sample, int& stepsize_index, int
raw_code)
- {
- assert(raw_code >= 0 && raw_code < (1 << n_bits));
-
- static const int HI_BIT = (1 << (n_bits - 1));
- int* index_update_table = s_index_update_tables[n_bits - 2];
-
- /* Core of ADPCM. */
-
- int code_mag = raw_code & (HI_BIT - 1);
- bool code_sign_bit = (raw_code & HI_BIT) ? 1 : 0;
- int mag = (code_mag << 1) + 1; /* shift in LSB (they
do this so that pos & neg zero are different)*/
-
- int stepsize = s_stepsize[stepsize_index];
-
- /* Compute the new sample. It's the predicted value
*/
- /* (i.e. the previous value), plus a delta. The delta
*/
- /* comes from the code times the stepsize. going for
*/
- /* something like: delta = stepsize * (code * 2 + 1) >>
code_bits */
- int delta = (stepsize * mag) >> (n_bits - 1);
- if (code_sign_bit) delta = -delta;
-
- sample += delta;
- sample = iclamp(sample, -32768, 32767);
-
- /* Update our stepsize index. Use a lookup table. */
- stepsize_index += index_update_table[code_mag];
- stepsize_index = iclamp(stepsize_index, 0, STEPSIZE_CT - 1);
- }
-
- /* Uncompress 4096 mono samples of ADPCM. */
- static void doMonoBlock(int16_t** out_data, int n_bits, int
sample_count, stream* in, int sample, int stepsize_index)
- {
- /* First sample doesn't need to be decompressed. */
- sample_count--;
- *(*out_data)++ = (int16_t) sample;
-
- while (sample_count--)
- {
- int raw_code = in->read_uint(n_bits);
- doSample(n_bits, sample, stepsize_index, raw_code);
/* sample & stepsize_index are in/out params */
- *(*out_data)++ = (int16_t) sample;
- }
- }
-
-
- /* Uncompress 4096 stereo sample pairs of ADPCM. */
- static void doStereoBlock(
- int16_t** out_data, // in/out param
- int n_bits,
- int sample_count,
- stream* in,
- int left_sample,
- int left_stepsize_index,
- int right_sample,
- int right_stepsize_index
- )
- {
- /* First samples don't need to be decompressed. */
- sample_count--;
- *(*out_data)++ = (int16_t) left_sample;
- *(*out_data)++ = (int16_t) right_sample;
-
- while (sample_count--)
- {
- int left_raw_code = in->read_uint(n_bits);
- doSample(n_bits, left_sample, left_stepsize_index,
left_raw_code);
- *(*out_data)++ = (int16_t) left_sample;
-
- int right_raw_code = in->read_uint(n_bits);
- doSample(n_bits, right_sample, right_stepsize_index,
right_raw_code);
- *(*out_data)++ = (int16_t) right_sample;
- }
- }
-
-public:
-
- // Utility function: uncompress ADPCM data from in stream to
- // out_data[]. The output buffer must have (sample_count*2)
- // bytes for mono, or (sample_count*4) bytes for stereo.
- static void adpcm_expand(
- unsigned char* &data,
- stream* in,
- int sample_count, // in stereo, this is number of *pairs*
of samples (TODO: why is this signed at all ??)
- bool stereo)
- {
- int16_t* out_data = new int16_t[stereo ? sample_count*2 :
sample_count];
- data = reinterpret_cast<unsigned char *>(out_data);
-
- // Read header.
- in->ensureBytes(1); // nbits
- unsigned int n_bits = in->read_uint(2) + 2; // 2 to 5 bits
(TODO: use unsigned...)
-
-
-#ifndef GNASH_TRUST_SWF_INPUT
-
- // bitsPerCompSample is the number of bits for each comp sample
- unsigned int bitsPerCompSample = n_bits;
- if (stereo) bitsPerCompSample *= 2;
-
- // There's going to be one block every 4096 samples ...
- unsigned int blocksCount = sample_count/4096;
-
- // ... or fraction
- if ( sample_count%4096 ) ++blocksCount;
-
- // Of the total samples, all but the first sample in a block
are comp
- unsigned int compSamples = sample_count - blocksCount;
-
- // From every block, a fixed 22 bits will be read (16 of which
are the uncomp sample)
- unsigned int fixedBitsPerBlock = 22;
-
- // Total bits needed from stream
- unsigned long bitsNeeded = (compSamples*bitsPerCompSample) +
(fixedBitsPerBlock*blocksCount);
-
- // Now, we convert this number to bytes...
- unsigned long bytesNeeded = bitsNeeded/8;
- // ... requiring one more if the bits in excess are more then
- // the ones still available in last byte read
- unsigned int excessBits = bitsNeeded%8;
- if ( excessBits > 6 ) ++bytesNeeded;
-
- // Take note of the current position to later verify if we got
the
- // number of required bytes right
- unsigned long prevPosition = in->get_position();
-
- // We substract 1 byte as the 6 excessive of a byte are already
in the stream,
- // and we won't require another one unless more then 6
excessive bits are needed
- // WARNING: this is currently disabled due to a bug in this
function often resulting
- // in reads past the end of the stream
- //in->ensureBytes(bytesNeeded-1);
-
-#endif // GNASH_TRUST_SWF_INPUT
-
- while (sample_count)
- {
- // Read initial sample & index values.
-
- int sample = in->read_sint(16);
-
- int stepsize_index = in->read_uint(6);
- assert(STEPSIZE_CT >= (1 << 6)); // ensure we
don't need to clamp.
-
- int samples_this_block = imin(sample_count, 4096);
- sample_count -= samples_this_block;
-
- if (stereo == false)
- {
-#define DO_MONO(n) doMonoBlock(&out_data, n, samples_this_block, in, sample,
stepsize_index)
-
- switch (n_bits)
- {
- default: assert(0); break;
- case 2: DO_MONO(2); break;
- case 3: DO_MONO(3); break;
- case 4: DO_MONO(4); break;
- case 5: DO_MONO(5); break;
- }
- }
- else
- {
- // Stereo.
-
- // Got values for left channel; now get initial
sample
- // & index for right channel.
- int right_sample = in->read_sint(16);
-
- int right_stepsize_index = in->read_uint(6);
- assert(STEPSIZE_CT >= (1 << 6)); //
ensure we don't need to clamp.
-
-#define DO_STEREO(n) \
- doStereoBlock( \
- &out_data, n, samples_this_block, \
- in, sample, stepsize_index, \
- right_sample, right_stepsize_index)
-
- switch (n_bits)
- {
- default: assert(0); break;
- case 2: DO_STEREO(2); break;
- case 3: DO_STEREO(3); break;
- case 4: DO_STEREO(4); break;
- case 5: DO_STEREO(5); break;
- }
- }
- }
-
-#ifndef GNASH_TRUST_SWF_INPUT
- unsigned long curPos = in->get_position();
- unsigned long bytesRead = curPos - prevPosition;
- if ( bytesRead != bytesNeeded )
- {
- // This would happen if the computation of bytesNeeded
doesn't match the current
- // implementation.
- // NOTE That the current implementation seems pretty
much bogus as we *often* end
- // up reading past the end of the tag. Once we fix the
decoding we shoudl also fix
- // the computation of bytes needed
- log_error("admcp_expand: we expected to read %lu bytes,
but we read %lu instead (%ld error)",
- bytesNeeded, bytesRead, bytesNeeded-bytesRead);
- // abort();
- }
-
- unsigned long endTagPos = in->get_tag_end_position();
- if ( curPos > endTagPos )
- {
- // This happens when our decoder reads past the end of
the tag.
- // In general, we should aborth parsing of the current
tag when this happens,
- // anyway, it seems that *some* sound can be heard
nonetheless so we keep going.
- log_error("admcp_expand: read past tag boundary:
current position: %lu, end of tag position: %lu (overflow: %lu bytes)",
- curPos, endTagPos, curPos-endTagPos);
-
-#if 0
- log_debug(" stereo:%d, sample_count:%u,
compressedSamples:%d, bitsPerCompSample:%u, "
- "blocksCount:%u, bitsPerBlock:%u,
bitsNeeded:%lu, excessBits:%u, bytesNeeded:%lu, bytesLeft:%lu",
- stereo, sample_count, compSamples,
bitsPerCompSample, blocksCount, fixedBitsPerBlock,
- bitsNeeded, excessBits, bytesNeeded,
in->get_tag_end_position()-in->get_position());
-#endif
- }
-#endif // GNASH_TRUST_SWF_INPUT
-
- }
-
-
-};
-
-int ADPCMDecoder::_index_update_table_2bits[2] = { -1, 2 };
-int ADPCMDecoder::_index_update_table_3bits[4] = { -1, -1, 2, 4 };
-int ADPCMDecoder::_index_update_table_4bits[8] = { -1, -1, -1, -1, 2, 4, 6,
8 };
-int ADPCMDecoder::_index_update_table_5bits[16] = { -1, -1, -1, -1, -1, -1,
-1, -1, 1, 2, 4, 6, 8, 10, 13, 16 };
-
-int* ADPCMDecoder::s_index_update_tables[4] = {
- ADPCMDecoder::_index_update_table_2bits,
- ADPCMDecoder::_index_update_table_3bits,
- ADPCMDecoder::_index_update_table_4bits,
- ADPCMDecoder::_index_update_table_5bits
-};
-
-int ADPCMDecoder::s_stepsize[STEPSIZE_CT] = {
- 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
- 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
- 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
- 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
- 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
- 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
- 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
- 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
-};
-
-// ----------------------------------------------------------------------------
-// END OF ADPCMDecoder class
-// ----------------------------------------------------------------------------
-
-
//
// Some tag implementations
//
@@ -1435,10 +1143,10 @@
//
// Forward declaration
-static void sound_expand(stream *in, sound_handler::format_type &format,
+/*static void sound_expand(stream *in, sound_handler::format_type &format,
bool sample_16bit, bool stereo, unsigned int &sample_count,
unsigned char* &data, unsigned &data_bytes);
-
+*/
// Common data
static int s_sample_rate_table[] = { 5512, 11025, 22050, 44100 };
@@ -1457,15 +1165,14 @@
uint16_t character_id = in->read_u16();
- sound_handler::format_type format =
static_cast<sound_handler::format_type>(in->read_uint(4));
- sound_handler::format_type orgFormat = format;
+ audioCodecType format = static_cast<audioCodecType>(in->read_uint(4));
int sample_rate = in->read_uint(2); // multiples of 5512.5
bool sample_16bit = in->read_bit();
bool stereo = in->read_bit();
unsigned int sample_count = in->read_u32();
- if (format == sound_handler::FORMAT_MP3) {
+ if (format == AUDIO_CODEC_MP3) {
in->ensureBytes(2);
int16_t delay_seek = in->read_s16(); // FIXME - not
implemented/used
// The DelaySeek field has the following meaning:
@@ -1504,19 +1211,16 @@
return;
}
- unsigned char *data; // Expanded audio data ready for playing
-
// First it is the amount of data from file,
// then the amount allocated at *data (it may grow)
unsigned data_bytes = in->get_tag_end_position() -
in->get_position();
+ unsigned char *data = new unsigned char[data_bytes];
- // sound_expand allocates storage for data[].
- // and modifies 3 parameters: format, data and data_bytes.
- sound_expand(in, format, sample_16bit, stereo, sample_count, data,
data_bytes);
+ in->read((char*)data, data_bytes);
// Store all the data in a SoundInfo object
std::auto_ptr<SoundInfo> sinfo;
- sinfo.reset(new SoundInfo(format, orgFormat, stereo,
s_sample_rate_table[sample_rate], sample_count, sample_16bit));
+ sinfo.reset(new SoundInfo(format, stereo,
s_sample_rate_table[sample_rate], sample_count, sample_16bit));
// Stores the sounddata in the soundhandler, and the ID returned
// can be used to starting, stopping and deleting that sound
@@ -1528,6 +1232,7 @@
sound_sample* sam = new sound_sample(handler_id);
m->add_sound_sample(character_id, sam);
}
+
}
else
{
@@ -1594,8 +1299,7 @@
// extract garbage data
int garbage = in->read_uint(8);
- sound_handler::format_type format =
static_cast<sound_handler::format_type>(in->read_uint(4));
- sound_handler::format_type orgFormat = format;
+ audioCodecType format = static_cast<audioCodecType>(in->read_uint(4));
int sample_rate = in->read_uint(2); // multiples of 5512.5
bool sample_16bit = in->read_bit();
bool stereo = in->read_bit();
@@ -1605,7 +1309,7 @@
unsigned int sample_count = in->read_u16();
int latency = 0;
- if (format == sound_handler::FORMAT_MP3) {
+ if (format == AUDIO_CODEC_MP3) {
latency = in->read_s16();
garbage = in->read_uint(16);
}
@@ -1627,25 +1331,9 @@
return;
}
- // Tell create_sound what format it will be receiving, in case it cares
- // at this stage.
- switch (format) {
- case sound_handler::FORMAT_ADPCM:
- case sound_handler::FORMAT_RAW:
- case sound_handler::FORMAT_UNCOMPRESSED:
- format = sound_handler::FORMAT_NATIVE16;
- break;
- // Shut fussy compilers up...
- case sound_handler::FORMAT_MP3:
- case sound_handler::FORMAT_NELLYMOSER:
- case sound_handler::FORMAT_NATIVE16:
- case sound_handler::FORMAT_NELLYMOSER_8HZ_MONO:
- break;
- }
-
// Store all the data in a SoundInfo object
std::auto_ptr<SoundInfo> sinfo;
- sinfo.reset(new SoundInfo(format, orgFormat, stereo,
s_sample_rate_table[sample_rate], sample_count, sample_16bit));
+ sinfo.reset(new SoundInfo(format, stereo,
s_sample_rate_table[sample_rate], sample_count, sample_16bit));
// Stores the sounddata in the soundhandler, and the ID returned
// can be used to starting, stopping and deleting that sound
@@ -1676,20 +1364,15 @@
// If there is no SoundInfo something is wrong...
if (!sinfo) return;
- sound_handler::format_type format = sinfo->getOrgFormat();
+ audioCodecType format = sinfo->getFormat();
unsigned int sample_count = sinfo->getSampleCount();
// discard garbage data if format is MP3
- if (format == sound_handler::FORMAT_MP3) in->skip_bytes(4);
+ if (format == AUDIO_CODEC_MP3) in->skip_bytes(4);
- unsigned char *data; // Storage is allocated by sound_expand()
unsigned int data_bytes = in->get_tag_end_position() - in->get_position();
-
- sound_expand(in, format,
- sinfo->is16bit(), sinfo->isStereo(), sample_count,
- data, data_bytes);
- // "format" now reflects what we hand(ed) to the sound drivers.
- // "data_bytes" now reflects the size of the uncompressed data.
+ unsigned char *data = new unsigned char[data_bytes];
+ in->read((char*)data, data_bytes);
// Fill the data on the apropiate sound, and receives the starting point
// for later "start playing from this frame" events.
@@ -1702,132 +1385,6 @@
ssst->read(m, handle_id, start);
}
-// sound_expand: Expand audio data to 16-bit host endian.
-//
-// This modifies three of its parameters:
-// On entry, "format" is the format of the original data. If this routine
-// expands that to 16-bit native-endian, it will also modify "format" to
-// FORMAT_NATIVE16. Otherwise it leaves it alone (MP3 and NELLYMOSER).
-//
-// Storage for "data" is allocated here, and the the "data" pointer is
modified.
-//
-// On entry, data_bytes is the amount of sound data to be read from "in";
-// on exit it reflects the number of bytes that "data" now points to.
-static void
-sound_expand(stream *in, sound_handler::format_type &format,
- bool sample_16bit, bool stereo, unsigned int &sample_count,
- unsigned char* &data, unsigned int &data_bytes)
-{
-
- // Make sure that an unassigned pointer cannot get through
- data = NULL;
-
- switch (format) {
-
- case sound_handler::FORMAT_ADPCM:
- {
- //log_debug("ADPCM format");
- // Uncompress the ADPCM before handing data to host.
- if (sample_count == 0) sample_count = data_bytes / ( stereo ? 4 : 2 );
- ADPCMDecoder::adpcm_expand(data, in, sample_count, stereo);
- data_bytes = sample_count * (stereo ? 4 : 2);
- format = sound_handler::FORMAT_NATIVE16;
- break;
- }
- case sound_handler::FORMAT_RAW:
- //log_debug("RAW format");
- // 8- or 16-bit mono or stereo host-endian audio
- // Convert to 16-bit host-endian
- if (sample_16bit) {
- // FORMAT_RAW 16-bit is exactly what we want!
- in->ensureBytes(data_bytes);
- data = new unsigned char[data_bytes];
- in->read((char *)data, data_bytes);
- } else {
- // Convert 8-bit signed to 16-bit range
- // Allocate as many shorts as there are samples
- if (sample_count == 0) sample_count = data_bytes / (stereo ? 2 : 1);
- u8_expand(data, in, sample_count, stereo);
- data_bytes = sample_count * (stereo ? 4 : 2);
- }
- format = sound_handler::FORMAT_NATIVE16;
- break;
-
- case sound_handler::FORMAT_UNCOMPRESSED:
- //log_debug("UNCOMPRESSED format");
- // 8- or 16-bit mono or stereo little-endian audio
- // Convert to 16-bit host-endian.
- if (!sample_16bit)
- {
- // Convert 8-bit signed to 16-bit range
- // Allocate as many shorts as there are 8-bit samples
- if (sample_count == 0) sample_count = data_bytes / (stereo ? 2 : 1);
- u8_expand(data, in, sample_count, stereo);
- data_bytes = sample_count * (stereo ? 4 : 2);
-
- } else {
- // Read 16-bit data into buffer
- in->ensureBytes(data_bytes);
- data = new unsigned char[data_bytes];
- in->read((char *)data, data_bytes);
-
- // Convert 16-bit little-endian data to host-endian.
-
- // Runtime detection of host endianness costs almost
- // nothing and is less of a continual maintenance headache
- // than compile-time detection.
- union u {
- uint16_t s;
- struct {
- uint8_t c0;
- uint8_t c1;
- } c;
- } u = { 0x0001 };
-
- switch (u.c.c0) {
- case 0x01: // Little-endian host: sample is already native.
- break;
- case 0x00: // Big-endian host
- // Swap sample bytes to get big-endian format.
- assert(data_bytes & 1 == 0);
- for (unsigned i = 0; i < data_bytes; i+=2)
- {
- swap(&data[i], &data[i+1]);
- }
- break;
- default: // Impossible
- log_error(_("Host endianness not detected in
define_sound_loader"));
- // Just carry on anyway...
- }
- }
- format = sound_handler::FORMAT_NATIVE16;
- break;
-
- case sound_handler::FORMAT_MP3:
- //log_debug("MP3 format");
- // Decompressed elsewhere
- in->ensureBytes(data_bytes);
- data = new unsigned char[data_bytes];
- in->read((char *)data, data_bytes);
- break;
-
- case sound_handler::FORMAT_NELLYMOSER_8HZ_MONO:
- case sound_handler::FORMAT_NELLYMOSER:
- //log_debug("NELLYMOSER format");
- // One day...
- in->ensureBytes(data_bytes);
- in->skip_bytes(data_bytes);
- data = NULL;
- break;
-
- // This is impossible as an input but stops fussy compilers
- // complaining about unhandled enum values.
- case sound_handler::FORMAT_NATIVE16:
- //log_debug("NATIVE16 format");
- break;
- }
-}
-
void
define_video_loader(stream* in, tag_type tag, movie_definition* m)
{
@@ -1987,52 +1544,6 @@
// indent-tabs-mode: t
// End:
-// Expand ADPCM, 8-bit and non-host-endian 16-bit audio to 16-bit host-endian
-//
-// Provides:
-//
-// void adpcm_expand(unsigned char* &data, stream* in,
-// int sample_count, // in stereo, this is number of *pairs* of samples
-// bool stereo)
-//
-// Uncompress ADPCM data from in stream to out_data[].
-// The output buffer must have (sample_count*2) bytes for mono,
-// or (sample_count*4) bytes for stereo.
-//
-// This code has wandered round the Gnash source tree and has still not found
-// its proper home yet.
-
-
-//
-// Unsigned 8-bit expansion (128 is silence)
-//
-// u8_expand allocates the memory for its "data" pointer.
-//
-
-static void u8_expand(
- unsigned char * &data,
- stream* in,
- int sample_count, // in stereo, this is number of *pairs* of
samples
- bool stereo)
-{
- unsigned total_samples = stereo ? sample_count*2 : sample_count;
-
- in->ensureBytes(total_samples);
-
- boost::scoped_array<uint8_t> in_data ( new uint8_t[total_samples] );
- int16_t *out_data = new int16_t[total_samples];
-
- in->read((char *)in_data.get(), total_samples); // Read 8-bit samples
-
- // Convert 8-bit to 16
- uint8_t *inp = in_data.get();
- int16_t *outp = out_data;
- for (unsigned i=total_samples; i>0; i--) {
- *outp++ = ((int16_t)(*inp++) - 128) * 256;
- }
-
- data = (unsigned char *)out_data;
-}
// @@ lots of macros here! It seems that VC6 can't correctly
Index: server/vm/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/server/vm/Makefile.am,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- server/vm/Makefile.am 1 Jul 2007 10:54:37 -0000 1.14
+++ server/vm/Makefile.am 27 Sep 2007 23:59:56 -0000 1.15
@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-# $Id: Makefile.am,v 1.14 2007/07/01 10:54:37 bjacques Exp $
+# $Id: Makefile.am,v 1.15 2007/09/27 23:59:56 tgc Exp $
AUTOMAKE_OPTIONS =
@@ -30,6 +30,9 @@
-I$(top_srcdir)/libbase \
-I$(top_srcdir)/libgeometry \
-I$(top_srcdir)/libamf \
+ -I$(top_srcdir)/libmedia \
+ -I$(top_srcdir)/libmedia/sdl \
+ -I$(top_srcdir)/libmedia/gst \
-I$(top_srcdir) \
$(GLIB_CFLAGS) \
$(FFMPEG_CFLAGS) \
Index: testsuite/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/testsuite/Makefile.am,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -b -r1.41 -r1.42
--- testsuite/Makefile.am 10 Aug 2007 18:31:01 -0000 1.41
+++ testsuite/Makefile.am 27 Sep 2007 23:59:56 -0000 1.42
@@ -33,11 +33,13 @@
libtestsuite_la_LIBADD = \
$(RENDERER_LIBS) \
$(top_builddir)/backend/libgnashbackend.la \
+ $(top_builddir)/libmedia/libgnashmedia.la \
$(top_builddir)/server/libgnashserver.la \
$(top_builddir)/libbase/libgnashbase.la \
$(NULL)
libtestsuite_la_CXXFLAGS = \
-I$(top_srcdir)/libbase \
+ -I$(top_srcdir)/libmedia \
-I$(top_srcdir)/backend \
-I$(top_srcdir)/libgeometry \
-I$(top_srcdir)/server \
Index: testsuite/misc-ming.all/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/testsuite/misc-ming.all/Makefile.am,v
retrieving revision 1.155
retrieving revision 1.156
diff -u -b -r1.155 -r1.156
--- testsuite/misc-ming.all/Makefile.am 27 Sep 2007 04:40:24 -0000 1.155
+++ testsuite/misc-ming.all/Makefile.am 27 Sep 2007 23:59:56 -0000 1.156
@@ -40,6 +40,7 @@
AM_CPPFLAGS = -I.. \
-I$(top_srcdir) \
-I$(top_srcdir)/libbase \
+ -I$(top_srcdir)/libmedia \
-I$(top_srcdir)/backend \
-I$(top_srcdir)/server \
-I$(top_srcdir)/server/parser \
Index: testsuite/movies.all/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/testsuite/movies.all/Makefile.am,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- testsuite/movies.all/Makefile.am 19 Sep 2007 14:20:52 -0000 1.9
+++ testsuite/movies.all/Makefile.am 27 Sep 2007 23:59:57 -0000 1.10
@@ -39,6 +39,7 @@
AM_CPPFLAGS = -I.. \
-I$(top_srcdir) \
-I$(top_srcdir)/libbase \
+ -I$(top_srcdir)/libmedia \
-I$(top_srcdir)/backend \
-I$(top_srcdir)/server \
-I$(top_srcdir)/server/parser \
Index: testsuite/samples/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/testsuite/samples/Makefile.am,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -b -r1.20 -r1.21
--- testsuite/samples/Makefile.am 30 Jul 2007 22:45:42 -0000 1.20
+++ testsuite/samples/Makefile.am 27 Sep 2007 23:59:57 -0000 1.21
@@ -27,6 +27,7 @@
AM_CPPFLAGS = -I.. \
-I$(top_srcdir) \
-I$(top_srcdir)/libbase \
+ -I$(top_srcdir)/libmedia \
-I$(top_srcdir)/backend \
-I$(top_srcdir)/server \
-I$(top_srcdir)/server/parser \
Index: utilities/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/utilities/Makefile.am,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -b -r1.57 -r1.58
--- utilities/Makefile.am 1 Jul 2007 10:55:15 -0000 1.57
+++ utilities/Makefile.am 27 Sep 2007 23:59:57 -0000 1.58
@@ -26,6 +26,7 @@
GNASH_LIBS = \
$(top_builddir)/server/libgnashserver.la \
$(top_builddir)/libbase/libgnashbase.la \
+ $(top_builddir)/libmedia/libgnashmedia.la \
$(top_builddir)/backend/libgnashbackend.la \
$(top_builddir)/libamf/libgnashamf.la
@@ -52,6 +53,9 @@
-I$(top_srcdir)/server \
-I$(top_srcdir)/server/parser \
-I$(top_srcdir)/server/vm \
+ -I$(top_srcdir)/libmedia \
+ -I$(top_srcdir)/libmedia/sdl \
+ -I$(top_srcdir)/libmedia/gst \
-DLOCALEDIR=\"$(localedir)\" \
$(BOOST_CFLAGS) \
$(LIBXML_CFLAGS) \
Index: libmedia/AudioDecoder.h
===================================================================
RCS file: libmedia/AudioDecoder.h
diff -N libmedia/AudioDecoder.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/AudioDecoder.h 27 Sep 2007 23:59:52 -0000 1.1
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __AUDIODECODER_H__
+#define __AUDIODECODER_H__
+
+#include "MediaParser.h"
+#include "SoundInfo.h"
+
+namespace gnash {
+
+class AudioDecoder {
+
+public:
+ AudioDecoder() {}
+ ~AudioDecoder() {}
+
+ virtual bool setup(AudioInfo* /*info*/) { return false; }
+ virtual bool setup(SoundInfo* /*info*/) { return false; }
+ virtual uint8_t* decode(uint8_t* /*input*/, uint32_t /*inputSize*/,
uint32_t& /*outputSize*/, uint32_t& /*decodedData*/, bool /*parse*/) { return
NULL; }
+
+};
+
+} // gnash namespace
+
+#endif // __AUDIODECODER_H__
Index: libmedia/AudioDecoderNellymoser.cpp
===================================================================
RCS file: libmedia/AudioDecoderNellymoser.cpp
diff -N libmedia/AudioDecoderNellymoser.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/AudioDecoderNellymoser.cpp 27 Sep 2007 23:59:52 -0000 1.1
@@ -0,0 +1,823 @@
+// AudioDecoderNellymoser.cpp: Nellymoser decoding
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// Original copyright notice:
+
+/*
+ * Copyright (c) 2007 a840bda5870ba11f19698ff6eb9581dfb0f95fa5,
+ * 539459aeb7d425140b62a3ec7dbf6dc8e408a306, and
+ * 520e17cd55896441042b14df2566a6eb610ed444
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "AudioDecoderNellymoser.h"
+#include "utility.h"
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+
+namespace gnash {
+
+float nelly_neg_unpack_table[64] = {
+-0.0061359000, -0.0306748003, -0.0551952012, -0.0796824023, -0.1041216031,
+-0.1284981072, -0.1527972072, -0.1770042032, -0.2011045963, -0.2250839025,
+-0.2489275932, -0.2726213932, -0.2961508930, -0.3195019960, -0.3426606953,
+-0.3656130135, -0.3883450031, -0.4108431935, -0.4330937862, -0.4550836086,
+-0.4767991900, -0.4982276857, -0.5193560123, -0.5401715040, -0.5606616139,
+-0.5808140039, -0.6006165147, -0.6200572252, -0.6391243935, -0.6578066945,
+-0.6760926843, -0.6939715147, -0.7114322186, -0.7284644246, -0.7450578213,
+-0.7612023950, -0.7768884897, -0.7921066284, -0.8068475723, -0.8211025000,
+-0.8348628879, -0.8481202722, -0.8608669043, -0.8730949759, -0.8847970963,
+-0.8959661722, -0.9065957069, -0.9166790843, -0.9262102246, -0.9351835251,
+-0.9435935020, -0.9514350295, -0.9587035179, -0.9653943777, -0.9715039134,
+-0.9770280719, -0.9819638729, -0.9863080978, -0.9900581837, -0.9932119250,
+-0.9957674146, -0.9977231026, -0.9990776777, -0.9998306036
+};
+
+float nelly_huff_table[127] = {
+0.0000000000,
+
+-0.8472560048, 0.7224709988,
+
+-1.5247479677, -0.4531480074, 0.3753609955, 1.4717899561,
+
+-1.9822579622, -1.1929379702, -0.5829370022, -0.0693780035, 0.3909569979,
+0.9069200158, 1.4862740040, 2.2215409279,
+
+-2.3887870312, -1.8067539930, -1.4105420113, -1.0773609877, -0.7995010018,
+-0.5558109879, -0.3334020078, -0.1324490011, 0.0568020009, 0.2548770010,
+0.4773550034, 0.7386850119, 1.0443060398, 1.3954459429, 1.8098750114,
+2.3918759823,
+
+-2.3893830776, -1.9884680510, -1.7514040470, -1.5643119812, -1.3922129869,
+-1.2164649963, -1.0469499826, -0.8905100226, -0.7645580173, -0.6454579830,
+-0.5259280205, -0.4059549868, -0.3029719889, -0.2096900046, -0.1239869967,
+-0.0479229987, 0.0257730000, 0.1001340002, 0.1737180054, 0.2585540116,
+0.3522900045, 0.4569880068, 0.5767750144, 0.7003160119, 0.8425520062,
+1.0093879700, 1.1821349859, 1.3534560204, 1.5320819616, 1.7332619429,
+1.9722349644, 2.3978140354,
+
+
+-2.5756309032, -2.0573320389, -1.8984919786, -1.7727810144, -1.6662600040,
+-1.5742180347, -1.4993319511, -1.4316639900, -1.3652280569, -1.3000990152,
+-1.2280930281, -1.1588579416, -1.0921250582, -1.0135740042, -0.9202849865,
+-0.8287050128, -0.7374889851, -0.6447759867, -0.5590940118, -0.4857139885,
+-0.4110319912, -0.3459700048, -0.2851159871, -0.2341620028, -0.1870580018,
+-0.1442500055, -0.1107169986, -0.0739680007, -0.0365610011, -0.0073290002,
+0.0203610007, 0.0479039997, 0.0751969963, 0.0980999991, 0.1220389977,
+0.1458999962, 0.1694349945, 0.1970459968, 0.2252430022, 0.2556869984,
+0.2870100141, 0.3197099864, 0.3525829911, 0.3889069855, 0.4334920049,
+0.4769459963, 0.5204820037, 0.5644530058, 0.6122040153, 0.6685929894,
+0.7341650128, 0.8032159805, 0.8784040213, 0.9566209912, 1.0397069454,
+1.1293770075, 1.2211159468, 1.3080279827, 1.4024800062, 1.5056819916,
+1.6227730513, 1.7724959850, 1.9430880547, 2.2903931141
+};
+
+float nelly_pos_unpack_table[64] = {
+0.9999812245, 0.9995294213, 0.9984756112, 0.9968202710, 0.9945645928,
+0.9917098284, 0.9882575870, 0.9842100739, 0.9795697927, 0.9743394256,
+0.9685220718, 0.9621214271, 0.9551411867, 0.9475855827, 0.9394592047,
+0.9307669997, 0.9215139747, 0.9117059708, 0.9013488293, 0.8904486895,
+0.8790122271, 0.8670461774, 0.8545579910, 0.8415549994, 0.8280450106,
+0.8140363097, 0.7995373011, 0.7845566273, 0.7691032887, 0.7531868219,
+0.7368165851, 0.7200024724, 0.7027546763, 0.6850836873, 0.6669998765,
+0.6485143900, 0.6296381950, 0.6103827953, 0.5907596946, 0.5707806945,
+0.5504580140, 0.5298035741, 0.5088300705, 0.4875501990, 0.4659765065,
+0.4441221058, 0.4220002890, 0.3996241987, 0.3770073950, 0.3541634977,
+0.3311063051, 0.3078495860, 0.2844074965, 0.2607941031, 0.2370236069,
+0.2131102979, 0.1890687048, 0.1649131030, 0.1406581998, 0.1163185984,
+0.0919089988, 0.0674438998, 0.0429382995, 0.0184067003
+};
+
+int nelly_copy_count[23] = {
+2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 12, 14, 15
+};
+
+float nelly_signal_table[64] = {
+0.1250000000, 0.1249623969, 0.1248494014, 0.1246612966, 0.1243980974,
+0.1240599006, 0.1236471012, 0.1231596991, 0.1225982010, 0.1219628006,
+0.1212539002, 0.1204719990, 0.1196174994, 0.1186909974, 0.1176929995,
+0.1166241020, 0.1154849008, 0.1142762005, 0.1129987016, 0.1116530001,
+0.1102401987, 0.1087609008, 0.1072160974, 0.1056066975, 0.1039336994,
+0.1021981016, 0.1004009023, 0.0985433012, 0.0966262966, 0.0946511030,
+0.0926188976, 0.0905309021, 0.0883883014, 0.0861926004, 0.0839449018,
+0.0816465989, 0.0792991966, 0.0769039020, 0.0744623989, 0.0719759986,
+0.0694463030, 0.0668746978, 0.0642627999, 0.0616123006, 0.0589246005,
+0.0562013984, 0.0534444004, 0.0506552011, 0.0478353985, 0.0449868999,
+0.0421111993, 0.0392102003, 0.0362856016, 0.0333391018, 0.0303725004,
+0.0273876991, 0.0243862998, 0.0213702004, 0.0183412991, 0.0153013002,
+0.0122520998, 0.0091955997, 0.0061335000, 0.0030677000
+};
+
+short nelly_init_table[64] = {
+3134, 5342, 6870, 7792, 8569, 9185, 9744, 10191, 10631, 11061, 11434, 11770,
+12116, 12513, 12925, 13300, 13674, 14027, 14352, 14716, 15117, 15477, 15824,
+16157, 16513, 16804, 17090, 17401, 17679, 17948, 18238, 18520, 18764, 19078,
+19381, 19640, 19921, 20205, 20500, 20813, 21162, 21465, 21794, 22137, 22453,
+22756, 23067, 23350, 23636, 23926, 24227, 24521, 24819, 25107, 25414, 25730,
+26120, 26497, 26895, 27344, 27877, 28463, 29426, 31355
+};
+
+float nelly_state_table[128] = {
+0.0061359000, 0.0184067003, 0.0306748003, 0.0429382995, 0.0551952012,
+0.0674438998, 0.0796824023, 0.0919089988, 0.1041216031, 0.1163185984,
+0.1284981072, 0.1406581998, 0.1527972072, 0.1649131030, 0.1770042032,
+0.1890687048, 0.2011045963, 0.2131102979, 0.2250839025, 0.2370236069,
+0.2489275932, 0.2607941031, 0.2726213932, 0.2844074965, 0.2961508930,
+0.3078495860, 0.3195019960, 0.3311063051, 0.3426606953, 0.3541634977,
+0.3656130135, 0.3770073950, 0.3883450031, 0.3996241987, 0.4108431935,
+0.4220002890, 0.4330937862, 0.4441221058, 0.4550836086, 0.4659765065,
+0.4767991900, 0.4875501990, 0.4982276857, 0.5088300705, 0.5193560123,
+0.5298035741, 0.5401715040, 0.5504580140, 0.5606616139, 0.5707806945,
+0.5808140039, 0.5907596946, 0.6006165147, 0.6103827953, 0.6200572252,
+0.6296381950, 0.6391243935, 0.6485143900, 0.6578066945, 0.6669998765,
+0.6760926843, 0.6850836873, 0.6939715147, 0.7027546763, 0.7114322186,
+0.7200024724, 0.7284644246, 0.7368165851, 0.7450578213, 0.7531868219,
+0.7612023950, 0.7691032887, 0.7768884897, 0.7845566273, 0.7921066284,
+0.7995373011, 0.8068475723, 0.8140363097, 0.8211025000, 0.8280450106,
+0.8348628879, 0.8415549994, 0.8481202722, 0.8545579910, 0.8608669043,
+0.8670461774, 0.8730949759, 0.8790122271, 0.8847970963, 0.8904486895,
+0.8959661722, 0.9013488293, 0.9065957069, 0.9117059708, 0.9166790843,
+0.9215139747, 0.9262102246, 0.9307669997, 0.9351835251, 0.9394592047,
+0.9435935020, 0.9475855827, 0.9514350295, 0.9551411867, 0.9587035179,
+0.9621214271, 0.9653943777, 0.9685220718, 0.9715039134, 0.9743394256,
+0.9770280719, 0.9795697927, 0.9819638729, 0.9842100739, 0.9863080978,
+0.9882575870, 0.9900581837, 0.9917098284, 0.9932119250, 0.9945645928,
+0.9957674146, 0.9968202710, 0.9977231026, 0.9984756112, 0.9990776777,
+0.9995294213, 0.9998306036, 0.9999812245
+};
+
+short nelly_delta_table[32] = {
+-11725, -9420, -7910, -6801, -5948, -5233, -4599, -4039, -3507, -3030, -2596,
+-2170, -1774, -1383, -1016, -660, -329, -1, 337, 696, 1085, 1512, 1962, 2433,
+2968, 3569, 4314, 5279, 6622, 8154, 10076, 12975
+};
+
+float nelly_inv_dft_table[129] = {
+0.0000000000, 0.0122715384, 0.0245412290, 0.0368072242, 0.0490676723,
+0.0613207370, 0.0735645667, 0.0857973099, 0.0980171412, 0.1102222130,
+0.1224106774, 0.1345807165, 0.1467304677, 0.1588581353, 0.1709618866,
+0.1830398887, 0.1950903237, 0.2071113735, 0.2191012353, 0.2310581058,
+0.2429801822, 0.2548656464, 0.2667127550, 0.2785196900, 0.2902846932,
+0.3020059466, 0.3136817515, 0.3253102899, 0.3368898630, 0.3484186828,
+0.3598950505, 0.3713171780, 0.3826834261, 0.3939920366, 0.4052413106,
+0.4164295495, 0.4275550842, 0.4386162460, 0.4496113360, 0.4605387151,
+0.4713967443, 0.4821837842, 0.4928981960, 0.5035383701, 0.5141027570,
+0.5245896578, 0.5349976420, 0.5453249812, 0.5555702448, 0.5657318234,
+0.5758081675, 0.5857978463, 0.5956993103, 0.6055110693, 0.6152315736,
+0.6248595119, 0.6343932748, 0.6438315511, 0.6531728506, 0.6624158025,
+0.6715589762, 0.6806010008, 0.6895405650, 0.6983762383, 0.7071067691,
+0.7157308459, 0.7242470980, 0.7326542735, 0.7409511209, 0.7491363883,
+0.7572088242, 0.7651672959, 0.7730104327, 0.7807372212, 0.7883464098,
+0.7958369255, 0.8032075167, 0.8104572296, 0.8175848126, 0.8245893121,
+0.8314695954, 0.8382247090, 0.8448535800, 0.8513551950, 0.8577286005,
+0.8639728427, 0.8700869679, 0.8760700822, 0.8819212317, 0.8876396418,
+0.8932242990, 0.8986744881, 0.9039893150, 0.9091680050, 0.9142097831,
+0.9191138744, 0.9238795042, 0.9285060763, 0.9329928160, 0.9373390079,
+0.9415440559, 0.9456073046, 0.9495281577, 0.9533060193, 0.9569403529,
+0.9604305029, 0.9637760520, 0.9669764638, 0.9700312614, 0.9729399681,
+0.9757021070, 0.9783173800, 0.9807852507, 0.9831054807, 0.9852776527,
+0.9873014092, 0.9891765118, 0.9909026623, 0.9924795032, 0.9939069748,
+0.9951847196, 0.9963126183, 0.9972904325, 0.9981181026, 0.9987954497,
+0.9993223548, 0.9996988177, 0.9999247193, 1.0000000000
+};
+
+unsigned char nelly_center_table[64] = {
+0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120,
+4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124,
+2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122,
+6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126
+};
+
+static void center(float *audio)
+{
+ int i, j;
+ float ftmp;
+
+ for (i = 0; i < NELLY_BUF_LEN; i+=2) {
+ j = nelly_center_table[i/2];
+ if (j > i) {
+ ftmp = audio[j];
+ audio[j] = audio[i];
+ audio[i] = ftmp;
+ ftmp = audio[j+1];
+ audio[j+1] = audio[i+1];
+ audio[i+1] = ftmp;
+ }
+ }
+}
+
+static void inverse_dft(float *audio)
+{
+ int i, j, k, advance;
+ float *aptr, a, b, c, d, e, f;
+
+ aptr = audio;
+ for (i = 0; i < NELLY_BUF_LEN/4; i++) {
+ a = *aptr;
+ b = *(aptr+2);
+ c = *(aptr+1);
+ d = *(aptr+3);
+
+ *(aptr+2) = a-b;
+ *aptr = a+b;
+ *(aptr+3) = c-d;
+ *(aptr+1) = c+d;
+
+ aptr += 4;
+ }
+
+ aptr = audio;
+ for (i = 0; i < NELLY_BUF_LEN/8; i++) {
+ a = *aptr;
+ b = *(aptr+4);
+ c = *(aptr+1);
+ d = *(aptr+5);
+
+ *(aptr+4) = a-b;
+ *(aptr+5) = c-d;
+ *aptr = a+b;
+ *(aptr+1) = c+d;
+
+ aptr += 2;
+
+ a = *aptr;
+ b = *(aptr+5);
+ c = *(aptr+1);
+ d = *(aptr+4);
+
+ *(aptr+4) = a-b;
+ *aptr = a+b;
+ *(aptr+5) = c+d;
+ *(aptr+1) = c-d;
+
+ aptr += 6;
+ }
+
+ i = 0;
+ for (advance = 8; advance < NELLY_BUF_LEN; advance *= 2) {
+ aptr = audio;
+
+ for (k = 0; k < NELLY_BUF_LEN/(2*advance); k++) {
+ for (j = 0; j < advance/4; j++) {
+ a = nelly_inv_dft_table[128-i];
+ b = *(aptr+advance);
+ c = nelly_inv_dft_table[i];
+ d = *(aptr+advance+1);
+ e = *aptr;
+ f = *(aptr+1);
+
+ *(aptr+advance) = e-(a*b+c*d);
+ *aptr = e+(a*b+c*d);
+ *(aptr+advance+1) = f+(b*c-a*d);
+ *(aptr+1) = f-(b*c-a*d);
+
+ i += 512/advance;
+ aptr += 2;
+ }
+
+ for (j = 0; j < advance/4; j++) {
+ a = nelly_inv_dft_table[128-i];
+ b = *(aptr+advance);
+ c = nelly_inv_dft_table[i];
+ d = *(aptr+advance+1);
+ e = *aptr;
+ f = *(aptr+1);
+
+ *(aptr+advance) = e+(a*b-c*d);
+ *aptr = e-(a*b-c*d);
+ *(aptr+advance+1) = f+(a*d+b*c);
+ *(aptr+1) = f-(a*d+b*c);
+
+ i -= 512/advance;
+ aptr += 2;
+ }
+
+ aptr += advance;
+ }
+ }
+}
+
+static void unpack_coeffs(float *buf, float *audio)
+{
+ int i, end, mid_hi, mid_lo;
+ float a, b, c, d, e, f;
+
+ end = NELLY_BUF_LEN-1;
+ mid_hi = NELLY_BUF_LEN/2;
+ mid_lo = mid_hi-1;
+
+ for (i = 0; i < NELLY_BUF_LEN/4; i++) {
+ a = buf[end-(2*i)];
+ b = buf[2*i];
+ c = buf[(2*i)+1];
+ d = buf[end-(2*i)-1];
+ e = nelly_pos_unpack_table[i];
+ f = nelly_neg_unpack_table[i];
+
+ audio[2*i] = b*e-a*f;
+ audio[(2*i)+1] = a*e+b*f;
+
+ a = nelly_neg_unpack_table[mid_lo-i];
+ b = nelly_pos_unpack_table[mid_lo-i];
+
+ audio[end-(2*i)-1] = b*d-a*c;
+ audio[end-(2*i)] = b*c+a*d;
+ }
+}
+
+static void complex2signal(float *audio)
+{
+ int i, end, mid_hi, mid_lo;
+ float *aptr, *sigptr, a, b, c, d, e, f, g;
+
+ end = NELLY_BUF_LEN-1;
+ mid_hi = NELLY_BUF_LEN/2;
+ mid_lo = mid_hi-1;
+
+ a = audio[end];
+ b = audio[end-1];
+ c = audio[1];
+ d = nelly_signal_table[0];
+ e = audio[0];
+ f = nelly_signal_table[mid_lo];
+ g = nelly_signal_table[1];
+
+ audio[0] = d*e;
+ audio[1] = b*g-a*f;
+ audio[end-1] = a*g+b*f;
+ audio[end] = c*(-d);
+
+ aptr = audio+end-2;
+ sigptr = nelly_signal_table+mid_hi-1;
+
+ for (i = 3; i < NELLY_BUF_LEN/2; i += 2) {
+ a = audio[i-1];
+ b = audio[i];
+ c = nelly_signal_table[i/2];
+ d = *sigptr;
+ e = *(aptr-1);
+ f = *aptr;
+
+ audio[i-1] = a*c+b*d;
+ *aptr = a*d-b*c;
+
+ a = nelly_signal_table[(i/2)+1];
+ b = *(sigptr-1);
+
+ *(aptr-1) = b*e+a*f;
+ audio[i] = a*e-b*f;
+
+ sigptr--;
+ aptr -= 2;
+ }
+}
+
+static void apply_state(float *state, float *audio)
+{
+ int bot, mid_up, mid_down, top;
+ float s_bot, s_top;
+ float *t = nelly_state_table;
+
+ bot = 0;
+ top = NELLY_BUF_LEN-1;
+ mid_up = NELLY_BUF_LEN/2;
+ mid_down = (NELLY_BUF_LEN/2)-1;
+
+ while (bot < NELLY_BUF_LEN/4) {
+ s_bot = audio[bot];
+ s_top = audio[top];
+
+ audio[bot] = audio[mid_up]*t[bot]+state[bot]*t[top];
+ audio[top] = state[bot]*t[bot]-audio[mid_up]*t[top];
+ state[bot] = -audio[mid_down];
+
+ audio[mid_down] = s_top*t[mid_down]+state[mid_down]*t[mid_up];
+ audio[mid_up] = state[mid_down]*t[mid_down]-s_top*t[mid_up];
+ state[mid_down] = -s_bot;
+
+ bot++;
+ mid_up++;
+ mid_down--;
+ top--;
+ }
+}
+
+static int sum_bits(short *buf, short shift, short off)
+{
+ int b, i = 0, ret = 0;
+
+ for (i = 0; i < NELLY_FILL_LEN; i++) {
+ b = buf[i] - off;
+ if (b < 0)
+ b = 0;
+ b = ((b>>(shift-1))+1)>>1;
+ if (b > NELLY_BIT_CAP)
+ ret += NELLY_BIT_CAP;
+ else
+ ret += b;
+ }
+
+ return ret;
+}
+
+static int headroom(int *la, short *sa)
+{
+ if (*la == 0)
+ *sa += 31;
+ else if (*la < 0) {
+ while (*la > -1<<30) {
+ *la <<= 1;
+ (*sa)++;
+ }
+ } else {
+ while (*la < 1<<30) {
+ *la <<= 1;
+ (*sa)++;
+ }
+ }
+
+ return *la;
+}
+
+static void get_sample_bits(float *buf, int *bits)
+{
+ int i, j;
+ short sbuf[128];
+ int bitsum = 0, last_bitsum, small_bitsum, big_bitsum;
+ short shift, shift_saved;
+ int tmp;
+ int big_off;
+ int off, diff;
+
+ tmp = 0;
+ for (i = 0; i < NELLY_FILL_LEN; i++) {
+ if (buf[i] > tmp)
+ tmp = buf[i];
+ }
+ shift = -16;
+ headroom(&tmp, &shift);
+
+ if (shift < 0)
+ for (i = 0; i < NELLY_FILL_LEN; i++)
+ sbuf[i] = ((int)buf[i]) >> -shift;
+ else
+ for (i = 0; i < NELLY_FILL_LEN; i++)
+ sbuf[i] = ((int)buf[i]) << shift;
+
+ for (i = 0; i < NELLY_FILL_LEN; i++)
+ sbuf[i] = (3*sbuf[i])>>2;
+
+ tmp = 0;
+ for (i = 0; i < NELLY_FILL_LEN; i++)
+ tmp += sbuf[i];
+
+ shift += 11;
+ shift_saved = shift;
+ tmp -= NELLY_DETAIL_BITS << shift;
+ headroom(&tmp, &shift);
+ off = (NELLY_BASE_OFF * (tmp>>16)) >> 15;
+ shift = shift_saved - (NELLY_BASE_SHIFT+shift-31);
+
+ if (shift < 0)
+ off >>= -shift;
+ else
+ off <<= shift;
+
+ bitsum = sum_bits(sbuf, shift_saved, off);
+
+ if (bitsum != NELLY_DETAIL_BITS) {
+ shift = 0;
+ diff = bitsum - NELLY_DETAIL_BITS;
+
+ if (diff > 0) {
+ while (diff <= 16383) {
+ shift++;
+ diff *= 2;
+ }
+ } else {
+ while (diff >= -16383) {
+ shift++;
+ diff *= 2;
+ }
+ }
+
+ diff = (diff * NELLY_BASE_OFF) >> 15;
+ shift = shift_saved-(NELLY_BASE_SHIFT+shift-15);
+
+ if (shift > 0) {
+ diff <<= shift;
+ } else {
+ diff >>= -shift;
+ }
+
+ for (j = 1; j < 20; j++) {
+ tmp = off;
+ off += diff;
+ last_bitsum = bitsum;
+
+ bitsum = sum_bits(sbuf, shift_saved, off);
+
+ if ((bitsum-NELLY_DETAIL_BITS) *
(last_bitsum-NELLY_DETAIL_BITS) <= 0)
+ break;
+ }
+
+ if (bitsum != NELLY_DETAIL_BITS) {
+ if (bitsum > NELLY_DETAIL_BITS) {
+ big_off = off;
+ off = tmp;
+ big_bitsum=bitsum;
+ small_bitsum=last_bitsum;
+ } else {
+ big_off = tmp;
+ big_bitsum=last_bitsum;
+ small_bitsum=bitsum;
+ }
+
+ while (bitsum != NELLY_DETAIL_BITS && j <= 19) {
+ diff = (big_off+off)>>1;
+ bitsum = sum_bits(sbuf, shift_saved, diff);
+ if (bitsum > NELLY_DETAIL_BITS) {
+ big_off=diff;
+ big_bitsum=bitsum;
+ } else {
+ off = diff;
+ small_bitsum=bitsum;
+ }
+ j++;
+ }
+
+ if (abs(big_bitsum-NELLY_DETAIL_BITS) >=
+ abs(small_bitsum-NELLY_DETAIL_BITS)) {
+ bitsum = small_bitsum;
+ } else {
+ off = big_off;
+ bitsum = big_bitsum;
+ }
+
+ }
+ }
+
+ for (i = 0; i < NELLY_FILL_LEN; i++) {
+ tmp = sbuf[i]-off;
+ if (tmp < 0)
+ tmp = 0;
+ else
+ tmp = ((tmp>>(shift_saved-1))+1)>>1;
+
+ if (tmp > NELLY_BIT_CAP)
+ tmp = NELLY_BIT_CAP;
+ bits[i] = tmp;
+ }
+
+ if (bitsum > NELLY_DETAIL_BITS) {
+ tmp = i = 0;
+ while (tmp < NELLY_DETAIL_BITS) {
+ tmp += bits[i];
+ i++;
+ }
+
+ tmp -= bits[i-1];
+ bits[i-1] = NELLY_DETAIL_BITS-tmp;
+ bitsum = NELLY_DETAIL_BITS;
+ while (i < NELLY_FILL_LEN) {
+ bits[i] = 0;
+ i++;
+ }
+ }
+}
+
+static unsigned char get_bits(unsigned char block[NELLY_BLOCK_LEN], int *off,
int n)
+{
+ char ret;
+ int boff = *off/8, bitpos = *off%8, mask = (1<<n)-1;
+
+ if (bitpos+n > 8) {
+ ret = block[boff%NELLY_BLOCK_LEN] >> bitpos;
+ mask >>= 8-bitpos;
+ ret |= (block[(boff+1)%NELLY_BLOCK_LEN] & mask) << (8-bitpos);
+ } else {
+ ret = (block[boff%NELLY_BLOCK_LEN] >> bitpos) & mask;
+ }
+
+ *off += n;
+ return ret;
+}
+
+static void nelly_decode_block(nelly_handle* nh, unsigned char
block[NELLY_BLOCK_LEN], float audio[256])
+{
+ int i,j;
+ float buf[NELLY_BUF_LEN], pows[NELLY_BUF_LEN];
+ float *aptr, *bptr, *pptr, val, pval;
+ int bits[NELLY_BUF_LEN];
+ unsigned char v;
+ int bit_offset = 0;
+
+ bptr = buf;
+ pptr = pows;
+ val = nelly_init_table[get_bits(block, &bit_offset, 6)];
+ for (i = 0; i < 23; i++) {
+ if (i > 0)
+ val += nelly_delta_table[get_bits(block, &bit_offset,
5)];
+ pval = pow(2, val/2048);
+ for (j = 0; j < nelly_copy_count[i]; j++) {
+ *bptr = val;
+ *pptr = pval;
+ bptr++;
+ pptr++;
+ }
+
+ }
+
+ for (i = NELLY_FILL_LEN; i < NELLY_BUF_LEN; i++)
+ buf[i] = pows[i] = 0.0;
+
+ get_sample_bits(buf, bits);
+
+ for (i = 0; i < 2; i++) {
+ aptr = audio+i*128;
+ bit_offset = NELLY_HEADER_BITS + i*NELLY_DETAIL_BITS;
+
+ for (j = 0; j < NELLY_FILL_LEN; j++) {
+ if (bits[j] <= 0) {
+ buf[j] = M_SQRT1_2*pows[j];
+ if (random() % 2)
+ buf[j] *= -1.0;
+ } else {
+ v = get_bits(block, &bit_offset, bits[j]);
+ buf[j] =
nelly_huff_table[(1<<bits[j])-1+v]*pows[j];
+ }
+ }
+
+ unpack_coeffs(buf, aptr);
+ center(aptr);
+ inverse_dft(aptr);
+ complex2signal(aptr);
+ apply_state(nh->state, aptr);
+ }
+}
+
+static void nelly_util_floats2shorts(float audio[256], short shorts[256])
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (audio[i] >= 32767.0)
+ shorts[i] = 32767;
+ else if (audio[i] <= -32768.0)
+ shorts[i] = -32768;
+ else
+ shorts[i] = (short)audio[i];
+ }
+}
+
+static nelly_handle *nelly_get_handle()
+{
+ static int first = 1;
+ int i;
+ nelly_handle *nh;
+
+ if (first) {
+ srandom(time(NULL));
+ first = 0;
+ }
+
+ nh = new nelly_handle;
+
+ if (nh != NULL)
+ for (i = 0; i < 64; i++)
+ nh->state[i] = 0.0;
+
+ return nh;
+}
+
+static void nelly_free_handle(nelly_handle *nh)
+{
+ delete nh;
+}
+
+AudioDecoderNellymoser::AudioDecoderNellymoser ()
+ :
+ _sampleRate(0),
+ _stereo(false)
+{
+ _nh = nelly_get_handle();
+}
+
+AudioDecoderNellymoser::~AudioDecoderNellymoser()
+{
+ nelly_free_handle(_nh);
+}
+
+bool AudioDecoderNellymoser::setup(SoundInfo* info)
+{
+ if (info->getFormat() == AUDIO_CODEC_NELLYMOSER || info->getFormat() ==
AUDIO_CODEC_NELLYMOSER_8HZ_MONO) {
+ _sampleRate = info->getSampleRate();
+ _stereo = info->isStereo();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioDecoderNellymoser::setup(AudioInfo* info)
+{
+ if (info->type == FLASH && (info->codec == AUDIO_CODEC_NELLYMOSER ||
info->codec == AUDIO_CODEC_NELLYMOSER_8HZ_MONO)) {
+ _sampleRate = info->sampleRate;
+ _stereo = info->stereo;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+uint8_t* AudioDecoderNellymoser::decode(uint8_t* input, uint32_t inputSize,
uint32_t& outputSize, uint32_t& decodedBytes, bool /*parse*/)
+{
+
+ float float_buf[256];
+ uint32_t out_buf_size = (inputSize / 64) * 256;
+ int16_t* out_buf = new int16_t[out_buf_size];
+ int16_t* out_buf_start = out_buf;
+
+ while (inputSize > 0) {
+ nelly_decode_block(_nh, input, float_buf);
+ nelly_util_floats2shorts(float_buf, out_buf);
+ out_buf += 256;
+ input += 64;
+ inputSize -= 64;
+ }
+
+ uint8_t* tmp_raw_buffer = reinterpret_cast<uint8_t*>(out_buf_start);
+ uint32_t tmp_raw_buffer_size = out_buf_size * 2;
+
+ // If we need to convert samplerate or/and from mono to stereo...
+ if (out_buf_size > 0 && (_sampleRate != 44100 || !_stereo)) {
+
+ int16_t* adjusted_data = 0;
+ int adjusted_size = 0;
+ int sample_count = out_buf_size / (_stereo ? 2 : 1);
+
+ // Convert to needed samplerate - this converter only support
standard flash samplerates
+ convert_raw_data(&adjusted_data, &adjusted_size,
tmp_raw_buffer, sample_count, 0,
+ _sampleRate, _stereo,
+ 44100, true /* stereo */);
+
+ // Hopefully this wont happen
+ if (!adjusted_data) {
+ log_error(_("Error in sound sample conversion"));
+ delete[] tmp_raw_buffer;
+ outputSize = 0;
+ decodedBytes = 0;
+ return NULL;
+ }
+
+ // Move the new data to the sound-struct
+ delete[] tmp_raw_buffer;
+ tmp_raw_buffer = reinterpret_cast<uint8_t*>(adjusted_data);
+ tmp_raw_buffer_size = adjusted_size;
+
+ } else {
+ tmp_raw_buffer_size = out_buf_size;
+ }
+
+ outputSize = tmp_raw_buffer_size;
+ decodedBytes = inputSize;
+ return tmp_raw_buffer;
+}
+
+} // namespace gnash
+
Index: libmedia/AudioDecoderNellymoser.h
===================================================================
RCS file: libmedia/AudioDecoderNellymoser.h
diff -N libmedia/AudioDecoderNellymoser.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/AudioDecoderNellymoser.h 27 Sep 2007 23:59:52 -0000 1.1
@@ -0,0 +1,96 @@
+// AudioDecoderNellymoser.h: Nellymoser decoding
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+// Original copyright notice:
+
+/*
+ * Copyright (c) 2007 a840bda5870ba11f19698ff6eb9581dfb0f95fa5,
+ * 539459aeb7d425140b62a3ec7dbf6dc8e408a306, and
+ * 520e17cd55896441042b14df2566a6eb610ed444
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __AUDIODECODERNELLYMOSER_H__
+#define __AUDIODECODERNELLYMOSER_H__
+
+#include "log.h"
+#include "AudioDecoder.h"
+
+#define NELLY_BLOCK_LEN 64
+#define NELLY_HEADER_BITS 116
+#define NELLY_DETAIL_BITS 198
+#define NELLY_BUF_LEN 128
+#define NELLY_FILL_LEN 124
+#define NELLY_BIT_CAP 6
+#define NELLY_BASE_OFF 4228
+#define NELLY_BASE_SHIFT 19
+
+
+
+typedef struct nelly_handle_struct {
+ float state[64];
+} nelly_handle;
+
+namespace gnash {
+
+class AudioDecoderNellymoser : public AudioDecoder {
+
+public:
+ AudioDecoderNellymoser();
+ ~AudioDecoderNellymoser();
+
+ bool setup(AudioInfo* info);
+ bool setup(SoundInfo* info);
+
+ uint8_t* decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize, uint32_t& decodedBytes, bool parse);
+
+private:
+
+ // The handle used by the decoder
+ nelly_handle* _nh;
+
+ // samplerate
+ uint16_t _sampleRate;
+
+ // stereo
+ bool _stereo;
+};
+
+} // gnash namespace
+
+#endif // __AUDIODECODERNELLYMOSER_H__
+
Index: libmedia/AudioDecoderSimple.cpp
===================================================================
RCS file: libmedia/AudioDecoderSimple.cpp
diff -N libmedia/AudioDecoderSimple.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/AudioDecoderSimple.cpp 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,541 @@
+// AudioDecoderSimple.cpp: Audio decoding using "simple" internal decoders.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#include <boost/scoped_array.hpp>
+
+#include "AudioDecoderSimple.h"
+#include "utility.h"
+
+namespace gnash {
+
+class BitReader
+{
+public:
+ typedef unsigned char byte;
+
+ /// Ownership of buffer left to caller
+ BitReader(byte* input, size_t len)
+ :
+ start(input),
+ ptr(input),
+ end(ptr+len),
+ usedBits(0)
+ {
+ }
+
+ ~BitReader() {}
+
+ /// Set a new buffer to work with
+ void setBuffer(byte* input, size_t len)
+ {
+ start = ptr = input;
+ end = start+len;
+ usedBits = 0;
+ }
+
+ bool read_bit()
+ {
+ bool ret = (*ptr&(128>>usedBits));
+ if ( ++usedBits == 8 ) advanceToNextByte();
+ return ret;
+ }
+
+ unsigned int read_uint(unsigned short bitcount)
+ {
+ assert(bitcount <= 32);
+
+ uint32_t value = 0;
+
+ unsigned short bits_needed = bitcount;
+ do
+ {
+ int unusedMask = 0xFF >> usedBits;
+ int unusedBits = 8-usedBits;
+
+ if (bits_needed == unusedBits)
+ {
+ // Consume all the unused bits.
+ value |= (*ptr&unusedMask);
+ advanceToNextByte();
+ break;
+
+ }
+ else if (bits_needed > unusedBits)
+ {
+ // Consume all the unused bits.
+
+ bits_needed -= unusedBits; //
assert(bits_needed>0)
+
+ value |= ((*ptr&unusedMask) << bits_needed);
+ advanceToNextByte();
+ }
+ else
+ {
+ assert(bits_needed <= unusedBits);
+
+ // Consume some of the unused bits.
+
+ unusedBits -= bits_needed;
+
+ value |= ((*ptr&unusedMask) >> unusedBits);
+
+ usedBits += bits_needed;
+ if ( usedBits >= 8 ) advanceToNextByte();
+
+ // We're done.
+ break;
+ }
+ }
+ while (bits_needed > 0);
+
+ return value;
+
+ }
+
+
+ int32_t read_sint(unsigned short bitcount)
+ {
+ int32_t value = int32_t(read_uint(bitcount));
+
+ // Sign extend...
+ if (value & (1 << (bitcount - 1)))
+ value |= -1 << bitcount;
+
+ return value;
+ }
+
+
+private:
+
+ void advanceToNextByte()
+ {
+ if ( ++ptr == end )
+ {
+ log_debug("Going round");
+ ptr=start;
+ }
+ usedBits=0;
+ }
+
+ /// Pointer to first byte
+ byte* start;
+
+ /// Pointer to current byte
+ byte* ptr;
+
+ /// Pointer to one past last byte
+ byte* end;
+
+ /// Number of used bits in current byte
+ unsigned usedBits;
+
+};
+
+// ----------------------------------------------------------------------------
+// ADPCMDecoder class
+// ----------------------------------------------------------------------------
+
+/// ADPCM decoder utilities
+//
+/// Algo from
http://www.circuitcellar.com/pastissues/articles/richey110/text.htm
+/// And also Jansen.
+/// Here's another reference:
http://www.geocities.com/SiliconValley/8682/aud3.txt
+/// Original IMA spec doesn't seem to be on the web :(
+///
+/// TODO: move in it's own file
+///
+class ADPCMDecoder {
+
+private:
+
+ // Data from Alexis' SWF reference
+ static int _index_update_table_2bits[2];
+ static int _index_update_table_3bits[4];
+ static int _index_update_table_4bits[8];
+ static int _index_update_table_5bits[16];
+
+ static int* s_index_update_tables[4];
+
+ // Data from Jansen. http://homepages.cwi.nl/~jack/
+ // Check out his Dutch retro punk songs, heh heh :)
+ static const int STEPSIZE_CT = 89;
+ static int s_stepsize[STEPSIZE_CT];
+
+
+ static void doSample(int n_bits, int& sample, int& stepsize_index, int
raw_code)
+ {
+ assert(raw_code >= 0 && raw_code < (1 << n_bits));
+
+ static const int HI_BIT = (1 << (n_bits - 1));
+ int* index_update_table = s_index_update_tables[n_bits - 2];
+
+ /* Core of ADPCM. */
+
+ int code_mag = raw_code & (HI_BIT - 1);
+ bool code_sign_bit = (raw_code & HI_BIT) ? 1 : 0;
+ int mag = (code_mag << 1) + 1; /* shift in LSB (they
do this so that pos & neg zero are different)*/
+
+ int stepsize = s_stepsize[stepsize_index];
+
+ /* Compute the new sample. It's the predicted value
*/
+ /* (i.e. the previous value), plus a delta. The delta
*/
+ /* comes from the code times the stepsize. going for
*/
+ /* something like: delta = stepsize * (code * 2 + 1) >>
code_bits */
+ int delta = (stepsize * mag) >> (n_bits - 1);
+ if (code_sign_bit) delta = -delta;
+
+ sample += delta;
+ sample = iclamp(sample, -32768, 32767);
+
+ /* Update our stepsize index. Use a lookup table. */
+ stepsize_index += index_update_table[code_mag];
+ stepsize_index = iclamp(stepsize_index, 0, STEPSIZE_CT - 1);
+ }
+
+ /* Uncompress 4096 mono samples of ADPCM. */
+ static void doMonoBlock(int16_t** out_data, int n_bits, int
sample_count, BitReader* in, int sample, int stepsize_index)
+ {
+ /* First sample doesn't need to be decompressed. */
+ sample_count--;
+ *(*out_data)++ = (int16_t) sample;
+
+ while (sample_count--)
+ {
+ int raw_code = in->read_uint(n_bits);
+ doSample(n_bits, sample, stepsize_index, raw_code);
/* sample & stepsize_index are in/out params */
+ *(*out_data)++ = (int16_t) sample;
+ }
+ }
+
+
+ /* Uncompress 4096 stereo sample pairs of ADPCM. */
+ static void doStereoBlock(
+ int16_t** out_data, // in/out param
+ int n_bits,
+ int sample_count,
+ BitReader* in,
+ int left_sample,
+ int left_stepsize_index,
+ int right_sample,
+ int right_stepsize_index
+ )
+ {
+ /* First samples don't need to be decompressed. */
+ sample_count--;
+ *(*out_data)++ = (int16_t) left_sample;
+ *(*out_data)++ = (int16_t) right_sample;
+
+ while (sample_count--)
+ {
+ int left_raw_code = in->read_uint(n_bits);
+ doSample(n_bits, left_sample, left_stepsize_index,
left_raw_code);
+ *(*out_data)++ = (int16_t) left_sample;
+
+ int right_raw_code = in->read_uint(n_bits);
+ doSample(n_bits, right_sample, right_stepsize_index,
right_raw_code);
+ *(*out_data)++ = (int16_t) right_sample;
+ }
+ }
+
+public:
+
+ // Utility function: uncompress ADPCM data from in BitReader to
+ // out_data[]. The output buffer must have (sample_count*2)
+ // bytes for mono, or (sample_count*4) bytes for stereo.
+ static void adpcm_expand(
+ unsigned char* &data,
+ BitReader* in,
+ unsigned int sample_count, // in stereo, this is number of
*pairs* of samples
+ bool stereo)
+ {
+ int16_t* out_data = new int16_t[stereo ? sample_count*2 :
sample_count];
+ data = reinterpret_cast<unsigned char *>(out_data);
+
+ // Read header.
+ //in->ensureBytes(1); // nbits
+ unsigned int n_bits = in->read_uint(2) + 2; // 2 to 5 bits
(TODO: use unsigned...)
+
+ while (sample_count)
+ {
+ // Read initial sample & index values.
+
+ int sample = in->read_sint(16);
+
+ int stepsize_index = in->read_uint(6);
+ assert(STEPSIZE_CT >= (1 << 6)); // ensure we
don't need to clamp.
+
+ int samples_this_block = imin(sample_count, 4096);
+ sample_count -= samples_this_block;
+
+ if (stereo == false)
+ {
+#define DO_MONO(n) doMonoBlock(&out_data, n, samples_this_block, in, sample,
stepsize_index)
+
+ switch (n_bits)
+ {
+ default: assert(0); break;
+ case 2: DO_MONO(2); break;
+ case 3: DO_MONO(3); break;
+ case 4: DO_MONO(4); break;
+ case 5: DO_MONO(5); break;
+ }
+ }
+ else
+ {
+ // Stereo.
+
+ // Got values for left channel; now get initial
sample
+ // & index for right channel.
+ int right_sample = in->read_sint(16);
+
+ int right_stepsize_index = in->read_uint(6);
+ assert(STEPSIZE_CT >= (1 << 6)); //
ensure we don't need to clamp.
+
+#define DO_STEREO(n) \
+ doStereoBlock( \
+ &out_data, n, samples_this_block, \
+ in, sample, stepsize_index, \
+ right_sample, right_stepsize_index)
+
+ switch (n_bits)
+ {
+ default: assert(0); break;
+ case 2: DO_STEREO(2); break;
+ case 3: DO_STEREO(3); break;
+ case 4: DO_STEREO(4); break;
+ case 5: DO_STEREO(5); break;
+ }
+ }
+ }
+
+ }
+
+};
+
+int ADPCMDecoder::_index_update_table_2bits[2] = { -1, 2 };
+int ADPCMDecoder::_index_update_table_3bits[4] = { -1, -1, 2, 4 };
+int ADPCMDecoder::_index_update_table_4bits[8] = { -1, -1, -1, -1, 2, 4, 6,
8 };
+int ADPCMDecoder::_index_update_table_5bits[16] = { -1, -1, -1, -1, -1, -1,
-1, -1, 1, 2, 4, 6, 8, 10, 13, 16 };
+
+int* ADPCMDecoder::s_index_update_tables[4] = {
+ ADPCMDecoder::_index_update_table_2bits,
+ ADPCMDecoder::_index_update_table_3bits,
+ ADPCMDecoder::_index_update_table_4bits,
+ ADPCMDecoder::_index_update_table_5bits
+};
+
+int ADPCMDecoder::s_stepsize[STEPSIZE_CT] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+// ----------------------------------------------------------------------------
+// END OF ADPCMDecoder class
+// ----------------------------------------------------------------------------
+
+//
+// Unsigned 8-bit expansion (128 is silence)
+//
+// u8_expand allocates the memory for its "data" pointer.
+//
+
+static void u8_expand(
+ unsigned char * &data,
+ unsigned char* input,
+ uint32_t input_size) // This is also the number of u8bit samples
+{
+ boost::scoped_array<uint8_t> in_data ( new uint8_t[input_size] );
+ int16_t *out_data = new int16_t[input_size];
+
+ memcpy((char *)in_data.get(), input, input_size);
+
+ // Convert 8-bit to 16
+ uint8_t *inp = in_data.get();
+ int16_t *outp = out_data;
+ for (unsigned int i = input_size; i>0; i--) {
+ *outp++ = ((int16_t)(*inp++) - 128) * 256;
+ }
+
+ data = (unsigned char *)out_data;
+}
+
+
+AudioDecoderSimple::AudioDecoderSimple ()
+ :
+ _sampleRate(0),
+ _sampleCount(0),
+ _stereo(false),
+ _is16bit(true)
+{
+}
+
+AudioDecoderSimple::~AudioDecoderSimple()
+{
+
+}
+
+bool AudioDecoderSimple::setup(SoundInfo* info)
+{
+ if (info->getFormat() == AUDIO_CODEC_ADPCM || info->getFormat() ==
AUDIO_CODEC_RAW || info->getFormat() == AUDIO_CODEC_UNCOMPRESSED) {
+ _codec = info->getFormat();
+ _sampleRate = info->getSampleRate();
+ _sampleCount = info->getSampleCount();
+ _stereo = info->isStereo();
+ _is16bit = info->is16bit();
+ return true;
+ }
+ return false;
+}
+
+bool AudioDecoderSimple::setup(AudioInfo* info)
+{
+ if (info->type == FLASH && (info->codec == AUDIO_CODEC_ADPCM ||
info->codec == AUDIO_CODEC_RAW || info->codec == AUDIO_CODEC_UNCOMPRESSED)) {
+ _codec = static_cast<audioCodecType>(info->codec);
+ _sampleRate = info->sampleRate;
+ _stereo = info->stereo;
+ _is16bit = true; // Fix this?
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint8_t* AudioDecoderSimple::decode(uint8_t* input, uint32_t inputSize,
uint32_t& outputSize, uint32_t& decodedBytes, bool /*parse*/)
+{
+
+ unsigned char* decodedData = NULL;
+ int outsize = 0;
+
+ switch (_codec) {
+ case AUDIO_CODEC_ADPCM:
+ {
+ uint32_t sample_count = inputSize * ( _stereo ? 1 : 2 );
//(_sampleCount == 0 ? inputSize / ( _stereo ? 4 : 2 ) : _sampleCount);
+ ADPCMDecoder::adpcm_expand(decodedData, new
BitReader(input,inputSize), sample_count, _stereo);
+ outsize = sample_count * (_stereo ? 4 : 2);
+ }
+ break;
+ case AUDIO_CODEC_RAW:
+ if (_is16bit) {
+ // FORMAT_RAW 16-bit is exactly what we want!
+ decodedData = new unsigned char[inputSize];
+ memcpy(decodedData, input, inputSize);
+ outsize = inputSize;
+ } else {
+ // Convert 8-bit signed to 16-bit range
+ // Allocate as many shorts as there are samples
+ u8_expand(decodedData, input, inputSize);
+ outsize = inputSize * (_stereo ? 4 : 2);
+ }
+ break;
+ case AUDIO_CODEC_UNCOMPRESSED:
+ // 8- or 16-bit mono or stereo little-endian audio
+ // Convert to 16-bit host-endian.
+ if (!_is16bit)
+ {
+ // Convert 8-bit signed to 16-bit range
+ // Allocate as many shorts as there are 8-bit samples
+ u8_expand(decodedData, input, inputSize);
+ outsize = inputSize * (_stereo ? 4 : 2);
+
+ } else {
+ // Read 16-bit data into buffer
+ decodedData = new unsigned char[inputSize];
+ memcpy((char *)decodedData, input, inputSize);
+
+ // Convert 16-bit little-endian data to host-endian.
+
+ // Runtime detection of host endianness costs almost
+ // nothing and is less of a continual maintenance
headache
+ // than compile-time detection.
+ union u {
+ uint16_t s;
+ struct {
+ uint8_t c0;
+ uint8_t c1;
+ } c;
+ } u = { 0x0001 };
+
+ switch (u.c.c0) {
+ case 0x01: // Little-endian host: sample
is already native.
+ break;
+ case 0x00: // Big-endian host
+ // Swap sample bytes to get big-endian
format.
+ assert(inputSize & 1 == 0);
+ for (unsigned i = 0; i < inputSize;
i+=2)
+ {
+ swap(&decodedData[i],
&decodedData[i+1]);
+ }
+ break;
+ default: // Impossible
+ log_error(_("Host endianness not
detected in AudioDecoderSimple"));
+ // Just carry on anyway...
+ }
+ }
+ break;
+ default:
+ break;
+ // ???, this should only decode ADPCM, RAW and UNCOMPRESSED
+ }
+
+ uint8_t* tmp_raw_buffer = decodedData;
+ uint32_t tmp_raw_buffer_size = 0;
+
+ // If we need to convert samplerate or/and from mono to stereo...
+ if (outsize > 0 && (_sampleRate != 44100 || !_stereo)) {
+
+ int16_t* adjusted_data = 0;
+ int adjusted_size = 0;
+ int sample_count = outsize / 2;// samples are of size 2
+
+ // Convert to needed samplerate - this converter only support
standard flash samplerates
+ convert_raw_data(&adjusted_data, &adjusted_size,
tmp_raw_buffer, sample_count, 0,
+ _sampleRate, _stereo,
+ 44100, true /* stereo */);
+
+ // Hopefully this wont happen
+ if (!adjusted_data) {
+ log_error(_("Error in sound sample conversion"));
+ delete[] tmp_raw_buffer;
+ outputSize = 0;
+ decodedBytes = 0;
+ return NULL;
+ }
+
+ // Move the new data to the sound-struct
+ delete[] tmp_raw_buffer;
+ tmp_raw_buffer = reinterpret_cast<uint8_t*>(adjusted_data);
+ tmp_raw_buffer_size = adjusted_size;
+
+ } else {
+ tmp_raw_buffer_size = outsize;
+ }
+
+ outputSize = tmp_raw_buffer_size;
+ decodedBytes = inputSize;
+ return tmp_raw_buffer;
+}
+
+} // gnash namespace
Index: libmedia/AudioDecoderSimple.h
===================================================================
RCS file: libmedia/AudioDecoderSimple.h
diff -N libmedia/AudioDecoderSimple.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/AudioDecoderSimple.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,69 @@
+// AudioDecoderSimple.h: Audio decoding using "simple" internal decoders.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __AUDIODECODERSIMPLE_H__
+#define __AUDIODECODERSIMPLE_H__
+
+#include "log.h"
+#include "AudioDecoder.h"
+
+namespace gnash {
+ class SoundInfo;
+}
+
+namespace gnash {
+
+class AudioDecoderSimple : public AudioDecoder {
+
+public:
+ AudioDecoderSimple();
+ ~AudioDecoderSimple();
+
+ bool setup(AudioInfo* info);
+
+ bool setup(SoundInfo* info);
+
+ uint8_t* decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize, uint32_t& decodedBytes, bool parse);
+
+private:
+
+ // codec
+ audioCodecType _codec;
+
+ // samplerate
+ uint16_t _sampleRate;
+
+ // sampleCount
+ uint32_t _sampleCount;
+
+ // stereo
+ bool _stereo;
+
+ // samplesize: 8 or 16 bit
+ bool _is16bit;
+
+
+ //
+};
+
+} // gnash namespace
+
+#endif // __AUDIODECODERSIMPLE_H__
+
Index: libmedia/FLVParser.cpp
===================================================================
RCS file: libmedia/FLVParser.cpp
diff -N libmedia/FLVParser.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/FLVParser.cpp 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,702 @@
+// FLVParser.cpp: Flash Video file parser, for Gnash.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// $Id: FLVParser.cpp,v 1.1 2007/09/27 23:59:53 tgc Exp $
+
+#include "FLVParser.h"
+#include "amf.h"
+#include "log.h"
+
+#define PADDING_BYTES 8
+
+// Define the following macro the have seek() operations printed
+//#define GNASH_DEBUG_SEEK 1
+
+namespace gnash {
+
+FLVParser::FLVParser(tu_file* stream)
+ :
+ MediaParser(stream),
+ _lastParsedPosition(0),
+ _parsingComplete(false),
+ _videoInfo(NULL),
+ _audioInfo(NULL),
+ _nextAudioFrame(0),
+ _nextVideoFrame(0),
+ _audio(false),
+ _video(false)
+{
+}
+
+FLVParser::~FLVParser()
+{
+ _videoFrames.clear();
+
+ _audioFrames.clear();
+}
+
+
+uint32_t FLVParser::getBufferLength()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ if (_video) {
+ size_t size = _videoFrames.size();
+ if (size > 1 && size > _nextVideoFrame) {
+ return _videoFrames.back()->timestamp -
_videoFrames[_nextVideoFrame]->timestamp;
+ }
+ }
+ if (_audio) {
+ size_t size = _audioFrames.size();
+ if (size > 1 && size > _nextAudioFrame) {
+ return _audioFrames.back()->timestamp -
_audioFrames[_nextAudioFrame]->timestamp;
+ }
+ }
+ return 0;
+}
+uint16_t FLVParser::videoFrameRate()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Make sure that there are parsed some frames
+ while(_videoFrames.size() < 2 && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ if (_videoFrames.size() < 2) return 0;
+
+ uint32_t framedelay = _videoFrames[1]->timestamp -
_videoFrames[0]->timestamp;
+
+ return static_cast<int16_t>(1000 / framedelay);
+}
+
+
+uint32_t FLVParser::videoFrameDelay()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // If there are no video in this FLV return 0
+ if (!_video && _lastParsedPosition > 0) return 0;
+
+ // Make sure that there are parsed some frames
+ while(_videoFrames.size() < 2 && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there is no video data return 0
+ if (_videoFrames.size() == 0 || !_video || _nextVideoFrame < 2) return
0;
+
+ return _videoFrames[_nextVideoFrame-1]->timestamp -
_videoFrames[_nextVideoFrame-2]->timestamp;
+}
+
+uint32_t FLVParser::audioFrameDelay()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // If there are no audio in this FLV return 0
+ if (!_audio && _lastParsedPosition > 0) return 0;
+
+ // Make sure that there are parsed some frames
+ while(_audioFrames.size() < 2 && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there is no video data return 0
+ if (_audioFrames.size() == 0 || !_audio || _nextAudioFrame < 2) return
0;
+
+ return _audioFrames[_nextAudioFrame-1]->timestamp -
_audioFrames[_nextAudioFrame-2]->timestamp;
+}
+
+MediaFrame* FLVParser::parseMediaFrame()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ uint32_t video_size = _videoFrames.size();
+ uint32_t audio_size = _audioFrames.size();
+
+ if (_audio && audio_size <= _nextAudioFrame)
+ {
+ // Parse a media frame if any left or if needed
+ while(_audioFrames.size() <= _nextAudioFrame &&
!_parsingComplete) {
+ if (!parseNextFrame()) break;
+ }
+ }
+
+ if (_video && video_size <= _nextVideoFrame)
+ {
+ // Parse a media frame if any left or if needed
+ while(_videoFrames.size() <= _nextVideoFrame &&
!_parsingComplete) {
+ if (!parseNextFrame()) break;
+ }
+ }
+
+ // Find the next frame in the file
+ bool audioReady = _audioFrames.size() > _nextAudioFrame;
+ bool videoReady = _videoFrames.size() > _nextVideoFrame;
+ bool useAudio = false;
+
+ if (audioReady && videoReady) {
+ useAudio = _audioFrames[_nextAudioFrame]->dataPosition <
_videoFrames[_nextVideoFrame]->dataPosition;
+ } else if (!audioReady && videoReady) {
+ useAudio = false;
+ } else if (audioReady && !videoReady) {
+ useAudio = true;
+ } else {
+ // If no frames are next we have reached EOF
+ return NULL;
+ }
+
+ // Find the next frame in the file a return it
+
+ if (useAudio) {
+
+ MediaFrame* frame = new MediaFrame;
+ frame->dataSize = _audioFrames[_nextAudioFrame]->dataSize;
+ frame->timestamp = _audioFrames[_nextAudioFrame]->timestamp;
+
+
_stream->set_position(_audioFrames[_nextAudioFrame]->dataPosition);
//_lt.seek(_audioFrames[_nextAudioFrame]->dataPosition);
+ frame->data = new uint8_t[frame->dataSize + PADDING_BYTES];
+ size_t bytesread = _stream->read_bytes(frame->data,
frame->dataSize); //_lt.read(frame->data, frame->dataSize);
+ memset(frame->data + bytesread, 0, PADDING_BYTES);
+
+ frame->tag = 8;
+ _nextAudioFrame++;
+
+ return frame;
+
+ } else {
+ MediaFrame* frame = new MediaFrame;
+ frame->dataSize = _videoFrames[_nextVideoFrame]->dataSize;
+ frame->timestamp = _videoFrames[_nextVideoFrame]->timestamp;
+
+
_stream->set_position(_videoFrames[_nextVideoFrame]->dataPosition);
//_lt.seek(_videoFrames[_nextVideoFrame]->dataPosition);
+ frame->data = new uint8_t[frame->dataSize + PADDING_BYTES];
+ size_t bytesread = _stream->read_bytes(frame->data,
frame->dataSize); //_lt.read(frame->data, frame->dataSize);
+ memset(frame->data + bytesread, 0, PADDING_BYTES);
+
+ frame->tag = 9;
+ _nextVideoFrame++;
+
+ return frame;
+ }
+}
+
+MediaFrame* FLVParser::nextAudioFrame()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // If there are no audio in this FLV return NULL
+ if (!_audio && _lastParsedPosition > 0) return NULL;
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_audioFrames.size() <= _nextAudioFrame && !_parsingComplete) {
+ if (!parseNextFrame()) break;
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_audioFrames.size() <= _nextAudioFrame || _audioFrames.size() == 0)
return NULL;
+
+ MediaFrame* frame = new MediaFrame;
+ frame->dataSize = _audioFrames[_nextAudioFrame]->dataSize;
+ frame->timestamp = _audioFrames[_nextAudioFrame]->timestamp;
+ frame->tag = 8;
+
+ _stream->set_position(_audioFrames[_nextAudioFrame]->dataPosition);
//_lt.seek(_audioFrames[_nextAudioFrame]->dataPosition);
+ frame->data = new uint8_t[_audioFrames[_nextAudioFrame]->dataSize +
+ PADDING_BYTES];
+ size_t bytesread = _stream->read_bytes(frame->data,
_audioFrames[_nextAudioFrame]->dataSize); //_lt.read(frame->data,
_audioFrames[_nextAudioFrame]->dataSize);
+ memset(frame->data + bytesread, 0, PADDING_BYTES);
+
+ _nextAudioFrame++;
+ return frame;
+
+}
+
+MediaFrame* FLVParser::nextVideoFrame()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // If there are no video in this FLV return NULL
+ if (!_video && _lastParsedPosition > 0)
+ {
+ //gnash::log_debug("no video, or lastParserPosition > 0");
+ return NULL;
+ }
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_videoFrames.size() <= static_cast<uint32_t>(_nextVideoFrame) &&
!_parsingComplete)
+ {
+ if (!parseNextFrame()) break;
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_videoFrames.size() <= _nextVideoFrame || _videoFrames.size() == 0)
+ {
+ //gnash::log_debug("The needed frame (%d) can't be parsed (EOF
reached)", _lastVideoFrame);
+ return NULL;
+ }
+
+
+ MediaFrame* frame = new MediaFrame;
+ frame->dataSize = _videoFrames[_nextVideoFrame]->dataSize;
+ frame->timestamp = _videoFrames[_nextVideoFrame]->timestamp;
+ frame->tag = 9;
+
+ _stream->set_position(_videoFrames[_nextVideoFrame]->dataPosition);
//_lt.seek(_videoFrames[_nextVideoFrame]->dataPosition);
+ frame->data = new uint8_t[_videoFrames[_nextVideoFrame]->dataSize +
+ PADDING_BYTES];
+ size_t bytesread = _stream->read_bytes(frame->data,
_videoFrames[_nextVideoFrame]->dataSize); //_lt.read(frame->data,
_videoFrames[_nextVideoFrame]->dataSize);
+ memset(frame->data + bytesread, 0, PADDING_BYTES);
+
+ _nextVideoFrame++;
+ return frame;
+}
+
+
+uint32_t FLVParser::seekAudio(uint32_t time)
+{
+
+ // Make sure that there are parsed some frames
+ while(_audioFrames.size() < 1 && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there is no audio data return NULL
+ if (_audioFrames.size() == 0) return 0;
+
+ // Make sure that there are parsed some enough frames
+ // to get the right frame.
+ while(_audioFrames.back()->timestamp < time && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there are no audio greater than the given time
+ // the last audioframe is returned
+ FLVAudioFrame* lastFrame = _audioFrames.back();
+ if (lastFrame->timestamp < time) {
+ _nextAudioFrame = _audioFrames.size() - 1;
+ return lastFrame->timestamp;
+ }
+
+ // We try to guess where in the vector the audioframe
+ // with the correct timestamp is
+ size_t numFrames = _audioFrames.size();
+ double tpf = lastFrame->timestamp / numFrames; // time per frame
+ size_t guess = size_t(time / tpf);
+
+ // Here we test if the guess was ok, and adjust if needed.
+ size_t bestFrame = iclamp(guess, 0, _audioFrames.size()-1);
+
+ // Here we test if the guess was ok, and adjust if needed.
+ long diff = _audioFrames[bestFrame]->timestamp - time;
+ if ( diff > 0 ) // our guess was too long
+ {
+ while ( bestFrame > 0 && _audioFrames[bestFrame-1]->timestamp >
time ) --bestFrame;
+ }
+ else // our guess was too short
+ {
+ while ( bestFrame < _audioFrames.size()-1 &&
_audioFrames[bestFrame+1]->timestamp < time ) ++bestFrame;
+ }
+
+#ifdef GNASH_DEBUG_SEEK
+ gnash::log_debug("Seek (audio): " SIZET_FMT "/" SIZET_FMT " (%u/%u)",
bestFrame, numFrames, _audioFrames[bestFrame]->timestamp, time);
+#endif
+ _nextAudioFrame = bestFrame;
+ return _audioFrames[bestFrame]->timestamp;
+
+}
+
+
+uint32_t FLVParser::seekVideo(uint32_t time)
+{
+ // Make sure that there are parsed some frames
+ while(_videoFrames.size() < 1 && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there is no video data return NULL
+ if (_videoFrames.size() == 0) return 0;
+
+ // Make sure that there are parsed some enough frames
+ // to get the right frame.
+ while(_videoFrames.back()->timestamp < time && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there are no videoframe greater than the given time
+ // the last key videoframe is returned
+ FLVVideoFrame* lastFrame = _videoFrames.back();
+ size_t numFrames = _videoFrames.size();
+ if (lastFrame->timestamp < time)
+ {
+ size_t lastFrameNum = numFrames -1;
+ while (! lastFrame->isKeyFrame() )
+ {
+ lastFrameNum--;
+ lastFrame = _videoFrames[lastFrameNum];
+ }
+
+ _nextVideoFrame = lastFrameNum;
+ return lastFrame->timestamp;
+
+ }
+
+ // We try to guess where in the vector the videoframe
+ // with the correct timestamp is
+ double tpf = lastFrame->timestamp / numFrames; // time per frame
+ size_t guess = size_t(time / tpf);
+
+ size_t bestFrame = iclamp(guess, 0, _videoFrames.size()-1);
+
+ // Here we test if the guess was ok, and adjust if needed.
+ long diff = _videoFrames[bestFrame]->timestamp - time;
+ if ( diff > 0 ) // our guess was too long
+ {
+ while ( bestFrame > 0 && _videoFrames[bestFrame-1]->timestamp >
time ) --bestFrame;
+ }
+ else // our guess was too short
+ {
+ while ( bestFrame < _videoFrames.size()-1 &&
_videoFrames[bestFrame+1]->timestamp < time ) ++bestFrame;
+ }
+
+#if 0
+ uint32_t diff = abs(_videoFrames[bestFrame]->timestamp - time);
+ while (true)
+ {
+ if (bestFrame+1 < numFrames &&
static_cast<uint32_t>(abs(_videoFrames[bestFrame+1]->timestamp - time)) < diff)
{
+ diff = abs(_videoFrames[bestFrame+1]->timestamp - time);
+ bestFrame = bestFrame + 1;
+ } else if (bestFrame > 0 &&
static_cast<uint32_t>(abs(_videoFrames[bestFrame-1]->timestamp - time)) < diff)
{
+ diff = abs(_videoFrames[bestFrame-1]->timestamp - time);
+ bestFrame = bestFrame - 1;
+ } else {
+ break;
+ }
+ }
+#endif
+
+
+ // Find closest backward keyframe
+ size_t rewindKeyframe = bestFrame;
+ while ( rewindKeyframe && ! _videoFrames[rewindKeyframe]->isKeyFrame() )
+ {
+ rewindKeyframe--;
+ }
+
+ // Find closest forward keyframe
+ size_t forwardKeyframe = bestFrame;
+ size_t size = _videoFrames.size();
+ while (size > forwardKeyframe+1 && !
_videoFrames[forwardKeyframe]->isKeyFrame() )
+ {
+ forwardKeyframe++;
+ }
+
+ // We can't ensure we were able to find a key frame *after* the best
position
+ // in that case we just use any previous keyframe instead..
+ if ( ! _videoFrames[forwardKeyframe]->isKeyFrame() )
+ {
+ bestFrame = rewindKeyframe;
+ }
+ else
+ {
+ int32_t forwardDiff = _videoFrames[forwardKeyframe]->timestamp
- time;
+ int32_t rewindDiff = time -
_videoFrames[rewindKeyframe]->timestamp;
+
+ if (forwardDiff < rewindDiff) bestFrame = forwardKeyframe;
+ else bestFrame = rewindKeyframe;
+ }
+
+#ifdef GNASH_DEBUG_SEEK
+ gnash::log_debug("Seek (video): " SIZET_FMT "/" SIZET_FMT " (%u/%u)",
bestFrame, numFrames, _videoFrames[bestFrame]->timestamp, time);
+#endif
+
+ _nextVideoFrame = bestFrame;
+ assert( _videoFrames[bestFrame]->isKeyFrame() );
+ return _videoFrames[bestFrame]->timestamp;
+}
+
+
+
+std::auto_ptr<VideoInfo> FLVParser::getVideoInfo()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // If there are no video in this FLV return NULL
+ if (!_video && _lastParsedPosition > 0) return
std::auto_ptr<VideoInfo>(NULL);
+
+ // Make sure that there are parsed some video frames
+ while(_videoInfo.get() == NULL && !_parsingComplete && !(!_video &&
_lastParsedPosition > 0)) {
+ if (parseNextFrame() == false) break;
+ }
+
+ // If there are no video data return NULL
+ if (_videoInfo.get() == NULL) {
+ log_debug("No audio data");
+ return std::auto_ptr<VideoInfo>(NULL);
+ }
+
+ std::auto_ptr<VideoInfo> info(new VideoInfo(_videoInfo->codec,
_videoInfo->width, _videoInfo->height, _videoInfo->frameRate,
_videoInfo->duration, FLASH));
+ return info;
+
+}
+
+std::auto_ptr<AudioInfo> FLVParser::getAudioInfo()
+{
+
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // If there are no audio in this FLV return NULL
+ if (!_audio && _lastParsedPosition > 0) return
std::auto_ptr<AudioInfo>(NULL);
+
+ // Make sure that there are parsed some audio frames
+ while(_audioInfo.get() == NULL && !_parsingComplete && !(!_video &&
_lastParsedPosition > 0)) {
+ if (parseNextFrame() == false) break;
+ }
+
+ // If there are no audio data return NULL
+ if (_audioInfo.get() == NULL) return std::auto_ptr<AudioInfo>(NULL);
+
+ if (_audioInfo->codec == AUDIO_CODEC_MP3) _isAudioMp3 = true;
+ else if (_audioInfo->codec == AUDIO_CODEC_NELLYMOSER ||
_audioInfo->codec == AUDIO_CODEC_NELLYMOSER_8HZ_MONO) _isAudioNellymoser = true;
+
+ std::auto_ptr<AudioInfo> info(new AudioInfo(_audioInfo->codec,
_audioInfo->sampleRate, _audioInfo->sampleSize, _audioInfo->stereo,
_audioInfo->duration, FLASH));
+ return info;
+
+}
+
+bool FLVParser::isTimeLoaded(uint32_t time)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Parse frames until the need time is found, or EOF
+ while (!_parsingComplete) {
+ if (!parseNextFrame()) break;
+ if ((_videoFrames.size() > 0 && _videoFrames.back()->timestamp
>= time)
+ || (_audioFrames.size() > 0 &&
_audioFrames.back()->timestamp >= time)) {
+ return true;
+ }
+ }
+
+ if (_videoFrames.size() > 0 && _videoFrames.back()->timestamp >= time) {
+ return true;
+ }
+
+ if (_audioFrames.size() > 0 && _audioFrames.back()->timestamp >= time) {
+ return true;
+ }
+
+ return false;
+
+}
+
+uint32_t FLVParser::seek(uint32_t time)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ if (time == 0) {
+ if (_video) _nextVideoFrame = 0;
+ if (_audio) _nextAudioFrame = 0;
+ }
+
+ if (_video) time = seekVideo(time);
+ if (_audio) time = seekAudio(time);
+ return time;
+}
+
+bool FLVParser::parseNextFrame()
+{
+ // Parse the header if not done already. If unsuccesfull return false.
+ if (_lastParsedPosition == 0 && !parseHeader()) return false;
+
+ // Check if there is enough data to parse the header of the frame
+ //if (!_lt.isPositionConfirmed(_lastParsedPosition+14)) return false;
+
+ // Seek to next frame and skip the size of the last tag,
+ // return false on error
+ if (_stream->set_position(_lastParsedPosition+4) != 0) return false;
+ //_lt.seek(_lastParsedPosition+4);
+
+ // Read the tag info
+ uint8_t tag[12];
+ _stream->read_bytes(tag, 12);
+ //_lt.read(tag, 12);
+
+ // Extract length and timestamp
+ uint32_t bodyLength = getUInt24(&tag[1]);
+ uint32_t timestamp = getUInt24(&tag[4]);
+
+ // Check if there is enough data to parse the body of the frame
+ //if (!_lt.isPositionConfirmed(_lastParsedPosition+15+bodyLength))
return false;
+ /*if (_stream->set_position(_lastParsedPosition+15+bodyLength) != 0)
return false;*/
+ //_stream->set_position(_lastParsedPosition + HEADER_SKIP + bodyLength);
+
+ // check for empty tag
+ if (bodyLength == 0) {
+ _lastParsedPosition += HEADER_SKIP + bodyLength;
+ return true;
+ }
+
+ if (tag[0] == AUDIO_TAG) {
+ FLVAudioFrame* frame = new FLVAudioFrame;
+ frame->dataSize = bodyLength - 1;
+ frame->timestamp = timestamp;
+ frame->dataPosition = _lastParsedPosition + HEADER_SKIP + 1; //
_stream->get_position(); //_lt.tell();
+ _audioFrames.push_back(frame);
+//log_debug("audio tag, timestamp: %d", timestamp);
+
+ // If this is the first audioframe no info about the
+ // audio format has been noted, so we do that now
+ if (_audioInfo.get() == NULL) {
+ int samplerate = (tag[11] & 0x0C) >> 2;
+ if (samplerate == 0) samplerate = 5500;
+ else if (samplerate == 1) samplerate = 11000;
+ else if (samplerate == 2) samplerate = 22050;
+ else if (samplerate == 3) samplerate = 44100;
+
+ int samplesize = (tag[11] & 0x02) >> 1;
+ if (samplesize == 0) samplesize = 1;
+ else samplesize = 2;
+
+ _audioInfo.reset(new
AudioInfo(static_cast<audioCodecType>((tag[11] & 0xf0) >> 4), samplerate,
samplesize, (tag[11] & 0x01) >> 0, 0, FLASH));
+ }
+ _lastParsedPosition += HEADER_SKIP + bodyLength;
+
+ } else if (tag[0] == VIDEO_TAG) {
+ FLVVideoFrame* frame = new FLVVideoFrame;
+ frame->dataSize = bodyLength - 1;
+ frame->timestamp = timestamp;
+ frame->dataPosition = _lastParsedPosition + HEADER_SKIP + 1;
//_stream->get_position(); //_lt.tell();
+ frame->frameType = (tag[11] & 0xf0) >> 4;
+ _videoFrames.push_back(frame);
+
+//log_debug("video tag, timestamp: %d", timestamp);
+
+ // If this is the first videoframe no info about the
+ // video format has been noted, so we do that now
+ if (_videoInfo.get() == NULL) {
+ videoCodecType codec =
static_cast<videoCodecType>((tag[11] & 0x0f) >> 0);
+ // Set standard guessed size...
+ uint16_t width = 320;
+ uint16_t height = 240;
+
+ // Extract the video size from the videodata header
+ if (codec == VIDEO_CODEC_H263) {
+ _stream->set_position(frame->dataPosition);
//_lt.seek(frame->dataPosition);
+ uint8_t videohead[12];
+ _stream->read_bytes(videohead, 12);
//_lt.read(videohead, 12);
+
+ bool sizebit1 = (videohead[3] & 0x02);
+ bool sizebit2 = (videohead[3] & 0x01);
+ bool sizebit3 = (videohead[4] & 0x80);
+
+ // First some predefined sizes
+ if (!sizebit1 && sizebit2 && !sizebit3 ) {
+ width = 352;
+ height = 288;
+ } else if (!sizebit1 && sizebit2 && sizebit3 ) {
+ width = 176;
+ height = 144;
+ } else if (sizebit1 && !sizebit2 && !sizebit3 )
{
+ width = 128;
+ height = 96;
+ } else if (sizebit1 && !sizebit2 && sizebit3 ) {
+ width = 320;
+ height = 240;
+ } else if (sizebit1 && sizebit2 && !sizebit3 ) {
+ width = 160;
+ height = 120;
+
+ // Then the custom sizes (1 byte - untested and
ugly)
+ } else if (!sizebit1 && !sizebit2 && !sizebit3
) {
+ width = (videohead[4] & 0x40) |
(videohead[4] & 0x20) | (videohead[4] & 0x20) | (videohead[4] & 0x08) |
(videohead[4] & 0x04) | (videohead[4] & 0x02) | (videohead[4] & 0x01) |
(videohead[5] & 0x80);
+
+ height = (videohead[5] & 0x40) |
(videohead[5] & 0x20) | (videohead[5] & 0x20) | (videohead[5] & 0x08) |
(videohead[5] & 0x04) | (videohead[5] & 0x02) | (videohead[5] & 0x01) |
(videohead[6] & 0x80);
+
+ // Then the custom sizes (2 byte - untested and
ugly)
+ } else if (!sizebit1 && !sizebit2 && sizebit3 )
{
+ width = (videohead[4] & 0x40) |
(videohead[4] & 0x20) | (videohead[4] & 0x20) | (videohead[4] & 0x08) |
(videohead[4] & 0x04) | (videohead[4] & 0x02) | (videohead[4] & 0x01) |
(videohead[5] & 0x80) | (videohead[5] & 0x40) | (videohead[5] & 0x20) |
(videohead[5] & 0x20) | (videohead[5] & 0x08) | (videohead[5] & 0x04) |
(videohead[5] & 0x02) | (videohead[5] & 0x01) | (videohead[6] & 0x80);
+
+ height = (videohead[6] & 0x40) |
(videohead[6] & 0x20) | (videohead[6] & 0x20) | (videohead[6] & 0x08) |
(videohead[6] & 0x04) | (videohead[6] & 0x02) | (videohead[6] & 0x01) |
(videohead[7] & 0x80) | (videohead[7] & 0x40) | (videohead[7] & 0x20) |
(videohead[7] & 0x20) | (videohead[7] & 0x08) | (videohead[7] & 0x04) |
(videohead[7] & 0x02) | (videohead[7] & 0x01) | (videohead[8] & 0x80);
+ }
+ }
+
+ // Create the videoinfo
+ _videoInfo.reset(new VideoInfo(codec, width, height, 0
/*frameRate*/, 0 /*duration*/, FLASH));
+ }
+ _lastParsedPosition += HEADER_SKIP + bodyLength;
+
+ } else if (tag[0] == META_TAG) {
+//log_debug("meta tag");
+ // Extract information from the meta tag
+ /*_lt.seek(_lastParsedPosition+16);
+ char* metaTag = new char[bodyLength];
+ _lt.read(metaTag, bodyLength);
+ amf::AMF* amfParser = new amf::AMF();
+ amfParser->parseAMF(metaTag);*/
+ _lastParsedPosition += HEADER_SKIP + bodyLength;
+
+ } else {
+log_debug("no tag - the end?");
+ // We can't be sure that the parsing is really complete,
+ // maybe it's a corrupt FLV.
+ _parsingComplete = true;
+ return false;
+ }
+
+ return true;
+}
+
+bool FLVParser::parseHeader()
+{
+ // seek to the begining of the file
+ _stream->set_position(0); //_lt.seek(0);
+
+ // Read the header
+ uint8_t header[9];
+ _stream->read_bytes(header, 9); //_lt.read(header, 9);
+
+ // Check if this is really a FLV file
+ if (header[0] != 'F' || header[1] != 'L' || header[2] != 'V') return
false;
+
+ _audio = false;
+ _video = false;
+
+ // Parse the audio+video bitmask
+ if (header[4] & CONTAINS_AUDIO) {
+ _audio = true;
+ }
+ if (header[4] & CONTAINS_VIDEO) {
+ _video = true;
+ }
+
+ gnash::log_debug("FLV bit mask: %#x", header[4]);
+
+ _lastParsedPosition = 9;
+ return true;
+}
+
+inline uint32_t FLVParser::getUInt24(uint8_t* in)
+{
+ // The bits are in big endian order
+ return (in[0] << 16) | (in[1] << 8) | in[2];
+}
+
+} // end of gnash namespace
+
+#undef PADDING_BYTES
Index: libmedia/FLVParser.h
===================================================================
RCS file: libmedia/FLVParser.h
diff -N libmedia/FLVParser.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/FLVParser.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,277 @@
+// FLVParser.h: Flash Video file format parser, for Gnash.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// $Id: FLVParser.h,v 1.1 2007/09/27 23:59:53 tgc Exp $
+
+// Information about the FLV format can be found at http://osflash.org/flv
+
+#ifndef __FLVPARSER_H__
+#define __FLVPARSER_H__
+
+#include <tu_file.h>
+#include <vector>
+#include <boost/thread/mutex.hpp>
+#include "MediaParser.h"
+
+#define HEADER_SKIP 15
+
+namespace gnash {
+
+enum videoFrameType
+{
+ KEY_FRAME = 1,
+ INTER_FRAME = 2,
+ DIS_INTER_FRAME = 3
+};
+
+enum {
+ CONTAINS_VIDEO = 1,
+ CONTAINS_AUDIO = 4,
+};
+
+class FLVVideoFrame
+{
+public:
+ uint16_t frameType;
+ uint32_t dataSize;
+ uint64_t dataPosition;
+
+ /// in milliseconds
+ uint32_t timestamp;
+
+ /// Return true if this video frame is a key frame
+ bool isKeyFrame() const
+ {
+ return frameType == KEY_FRAME;
+ }
+
+};
+
+class FLVAudioFrame
+{
+public:
+ uint32_t dataSize;
+ uint64_t dataPosition;
+
+ /// in milliseconds
+ uint32_t timestamp;
+
+};
+
+/// \brief
+/// The FLVParser class parses an FLV stream, buffers information about
+/// audio/video frames and provides cursor-based access to them.
+//
+/// Cursor-based access allow seeking as close as possible to a specified time
+/// and fetching frames from there on, sequentially.
+/// See seek(), nextVideoFrame(), nextAudioFrame() and nextMediaFrame().
+///
+/// Input is received from a tu_file object.
+///
+class DSOEXPORT FLVParser : public MediaParser
+{
+
+public:
+
+ /// \brief
+ /// Create an FLV parser reading input from
+ /// the given tu_file
+ //
+ /// @param stream
+ /// tu_file to use for input.
+ /// Ownership left to the caller.
+ ///
+ FLVParser(tu_file* stream);
+
+ /// Kills the parser...
+ ~FLVParser();
+
+ /// Return next media frame
+ //
+ /// Locks the _mutex
+ ///
+ MediaFrame* parseMediaFrame();
+
+ /// \brief
+ /// Returns the next audio frame in the parsed buffer.
+ //
+ /// If no frame has been played before the first frame is returned.
+ /// If there is no more frames in the parsed buffer NULL is returned,
+ /// you can check with parsingCompleted() to know wheter this is due to
+ /// EOF reached.
+ ///
+ /// Locks the _mutex
+ ///
+ MediaFrame* nextAudioFrame();
+
+ /// \brief
+ /// Returns the next video frame in the parsed buffer.
+ //
+ /// If no frame has been played before the first frame is returned.
+ /// If there is no more frames in the parsed buffer NULL is returned.
+ /// you can check with parsingCompleted() to know wheter this is due to
+ /// EOF reached.
+ ///
+ /// Locks the _mutex
+ ///
+ MediaFrame* nextVideoFrame();
+
+ /// Return true of parsing is completed
+ //
+ /// If this function returns true, any call to nextVideoFrame() or
nextAudioFrame
+ /// will always return NULL
+ ///
+ bool parsingCompleted() const { return _parsingComplete; }
+
+ /// Returns a VideoInfo class about the videostream
+ //
+ /// Locks the _mutex
+ ///
+ std::auto_ptr<VideoInfo> getVideoInfo();
+
+ /// Returns a AudioInfo class about the audiostream
+ //
+ /// Locks the _mutex
+ ///
+ std::auto_ptr<AudioInfo> getAudioInfo();
+
+ /// \brief
+ /// Asks if a frame with with a timestamp larger than
+ /// the given time is available.
+ //
+ /// If such a frame is not
+ /// available in list of already the parsed frames, we
+ /// parse some more. This is used to check how much is buffered.
+ ///
+ /// Locks the _mutex
+ ///
+ /// @param time
+ /// Timestamp, in milliseconds.
+ ///
+ bool isTimeLoaded(uint32_t time);
+
+ /// \brief
+ /// Seeks to the closest possible position the given position,
+ /// and returns the new position.
+ //
+ /// Locks the _mutex
+ ///
+ uint32_t seek(uint32_t);
+
+ /// Returns the framedelay from the last to the current
+ /// audioframe in milliseconds. This is used for framerate.
+ //
+ /// Locks the _mutex
+ ///
+ uint32_t audioFrameDelay();
+
+ /// \brief
+ /// Returns the framedelay from the last to the current
+ /// videoframe in milliseconds.
+ //
+ /// Locks the _mutex
+ ///
+ uint32_t videoFrameDelay();
+
+ /// Returns the framerate of the video
+ //
+ /// Locks the _mutex
+ ///
+ uint16_t videoFrameRate();
+
+ /// Returns the "bufferlength", meaning the differens between the
+ /// current frames timestamp and the timestamp of the last parseable
+ /// frame. Returns the difference in milliseconds.
+ //
+ /// Locks the _mutex
+ ///
+ uint32_t getBufferLength();
+
+ /// Setup the parser
+ //
+ /// @return whether we'll be able to parse the file.
+ bool setupParser() { return true; }
+
+ uint32_t getLastParsedPos() { return _lastParsedPosition; }
+
+private:
+
+ /// seeks to the closest possible position the given position,
+ /// and returns the new position.
+ uint32_t seekAudio(uint32_t time);
+
+ /// seeks to the closest possible position the given position,
+ /// and returns the new position.
+ uint32_t seekVideo(uint32_t time);
+
+
+ /// Parses next frame from the file, returns true if a frame
+ /// was succesfully parsed, or false if not enough data was present.
+ bool parseNextFrame();
+
+ /// Parses the header of the file
+ bool parseHeader();
+
+ // Functions used to extract numbers from the file
+ inline uint32_t getUInt24(uint8_t* in);
+
+ /// The interface to the file, externally owned
+// tu_file* _stream;
+
+ typedef std::vector<FLVVideoFrame*> VideoFrames;
+
+ /// list of videoframes, does no contain the frame data.
+ VideoFrames _videoFrames;
+
+ typedef std::vector<FLVAudioFrame*> AudioFrames;
+
+ /// list of audioframes, does no contain the frame data.
+ AudioFrames _audioFrames;
+
+ /// The position where the parsing should continue from.
+ uint32_t _lastParsedPosition;
+
+ /// Whether the parsing is complete or not
+ bool _parsingComplete;
+
+ /// Info about the video stream
+ std::auto_ptr<VideoInfo> _videoInfo;
+
+ /// Info about the audio stream
+ std::auto_ptr<AudioInfo> _audioInfo;
+
+ /// Last audio frame returned
+ size_t _nextAudioFrame;
+
+ /// Last video frame returned
+ size_t _nextVideoFrame;
+
+ /// Audio stream is present
+ bool _audio;
+
+ /// Audio stream is present
+ bool _video;
+
+ /// Mutex to avoid problems with threads using the parser
+ boost::mutex _mutex;
+};
+
+} // end of gnash namespace
+
+#endif // __FLVPARSER_H__
Index: libmedia/Makefile.am
===================================================================
RCS file: libmedia/Makefile.am
diff -N libmedia/Makefile.am
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/Makefile.am 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,130 @@
+#
+# Copyright (C) 2007 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+AUTOMAKE_OPTIONS = no-dependencies foreign
+
+EXTRA_DIST =
+
+# this is where Gnash plugins get installed
+pluginsdir = $(prefix)/lib/gnash/plugins
+
+if INSTALL_LTDL
+include_HEADERS = $(top_srcdir)/libltdl/ltdl.h
+LIBLTDLLIB = libltdl.la
+LIBLTDLHEAD = $(top_srcdir)/libltdl/ltdl.h
+endif
+
+# If we are using an installable libltdl, then it needs to be built
+# before libgnash, as libgnash depends on it for extensions.
+pkglib_LTLIBRARIES = $(LIBLTDLLIB) libgnashmedia.la
+
+libgnashmedia_la_CPPFLAGS = \
+ -I.. -I$(srcdir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libamf \
+ -I$(top_srcdir)/backend \
+ -I$(top_srcdir)/libbase \
+ -I$(top_srcdir)/server \
+ $(PTHREAD_CFLAGS) \
+ $(OPENGL_CFLAGS) \
+ $(LIBXML_CFLAGS) \
+ $(PNG_CFLAGS) \
+ $(SDL_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GSTREAMER_CFLAGS) \
+ $(CURL_CFLAGS) \
+ $(Z_CFLAGS) \
+ $(JPEG_CFLAGS) \
+ $(BOOST_CFLAGS) \
+ $(INCLTDL) \
+ $(NULL)
+
+# These headers get installed
+# include_HEADERS = log.h err.h proc.h serial.h xantrex.h outback.h
+
+# Don't build Dmalloc support if it's not configured in
+if HAVE_DMALLOC
+DMALLOC_FILE = dlmalloc.c
+endif
+
+libgnashmedia_la_LIBADD = \
+ $(JPEG_LIBS) \
+ $(Z_LIBS) \
+ $(CURL_LIBS) \
+ $(OPENGL_LIBS) \
+ $(LIBINTL) \
+ $(LIBLTDL) \
+ $(BOOST_LIBS) \
+ $(PTHREAD_LIBS) \
+ $(SDL_LIBS) \
+ $(NULL)
+
+libgnashmedia_la_SOURCES = \
+ AudioDecoderNellymoser.cpp \
+ AudioDecoderSimple.cpp \
+ $(NULL)
+
+noinst_HEADERS = \
+ MediaBuffer.h \
+ MediaDecoder.h \
+ AudioDecoder.h \
+ VideoDecoder.h \
+ MediaParser.h \
+ AudioDecoderNellymoser.h \
+ AudioDecoderSimple.h \
+ sound_handler.h \
+ SoundInfo.h \
+ $(NULL)
+
+
+if USE_SOUND_GST
+#libgnashmedia_la_SOURCES += gst/gstgnashsrc.c gst/VideoDecoderGst.cpp
gst/gstappbuffer.c gst/gstappsink.c gst/gstappsrc.c gst/sound_handler_gst.cpp
+libgnashmedia_la_SOURCES += gst/VideoDecoderGst.cpp gst/sound_handler_gst.cpp
+#noinst_HEADERS += gst/gstgnashsrc.h gst/gstappbuffer.h gst/VideoDecoderGst.h
gst/gstappsink.h gst/gstappsrc.h gst/sound_handler_gst.h
+noinst_HEADERS += gst/VideoDecoderGst.h gst/sound_handler_gst.h
+libgnashmedia_la_CPPFLAGS += $(GSTREAMER_CFLAGS)
+libgnashmedia_la_LIBADD += $(GSTREAMER_LIBS) -lgstbase-0.10
+endif
+
+if USE_FFMPEG_ENGINE
+#libgnashmedia_la_SOURCES += sdl/MediaDecoderSdl.cpp
sdl/AudioDecoderFfmpeg.cpp sdl/VideoDecoderFfmpeg.cpp sdl/MediaParserFfmpeg.cpp
sdl/sound_handler_sdl.cpp
+libgnashmedia_la_SOURCES += sdl/VideoDecoderFfmpeg.cpp
sdl/AudioDecoderFfmpeg.cpp sdl/sound_handler_sdl.cpp
+#noinst_HEADERS += sdl/MediaDecoderSdl.h sdl/AudioDecoderFfmpeg.h
sdl/VideoDecoderFfmpeg.h sdl/MediaParserFfmpeg.h sdl/sound_handler_sdl.h
+noinst_HEADERS += sdl/AudioDecoderFfmpeg.h sdl/VideoDecoderFfmpeg.h
sdl/sound_handler_sdl.h
+libgnashmedia_la_LIBADD += $(FFMPEG_LIBS)
+libgnashmedia_la_CPPFLAGS += $(FFMPEG_CFLAGS)
+endif
+
+if USE_MAD_ENGINE
+#libgnashmedia_la_SOURCES += sdl/MediaDecoderSdl.cpp sdl/AudioDecoderMad.cpp
sdl/sound_handler_sdl.cpp
+libgnashmedia_la_SOURCES += sdl/AudioDecoderMad.cpp sdl/sound_handler_sdl.cpp
+#noinst_HEADERS += sdl/MediaDecoderSdl.h sdl/AudioDecoderMad.h
sdl/sound_handler_sdl.h
+noinst_HEADERS += sdl/AudioDecoderMad.h sdl/sound_handler_sdl.h
+libgnashmedia_la_LIBADD += $(MAD_LIBS)
+libgnashmedia_la_CPPFLAGS += $(MAD_CFLAGS)
+endif
+
+libgnashmedia_la_LDFLAGS = -release $(VERSION)
+
+
+# Rebuild with GCC 4.x Mudflap support
+mudflap:
+ @echo "Rebuilding with GCC Mudflap support"
+ $(MAKE) CXXFLAGS="$(CXXFLAGS) -fmudflap" LDFLAGS="$(LDFLAGS) -lmudflap"
+
+clean-hook:
+ -rm -f core.* *.obj
+
Index: libmedia/Makefile.in
===================================================================
RCS file: libmedia/Makefile.in
diff -N libmedia/Makefile.in
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/Makefile.in 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,777 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
address@hidden@
+
+#
+# Copyright (C) 2007 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+
+#libgnashmedia_la_SOURCES += gst/gstgnashsrc.c gst/VideoDecoderGst.cpp
gst/gstappbuffer.c gst/gstappsink.c gst/gstappsrc.c gst/sound_handler_gst.cpp
address@hidden@am__append_1 = gst/VideoDecoderGst.cpp gst/sound_handler_gst.cpp
+#noinst_HEADERS += gst/gstgnashsrc.h gst/gstappbuffer.h gst/VideoDecoderGst.h
gst/gstappsink.h gst/gstappsrc.h gst/sound_handler_gst.h
address@hidden@am__append_2 = gst/VideoDecoderGst.h gst/sound_handler_gst.h
address@hidden@am__append_3 = $(GSTREAMER_CFLAGS)
address@hidden@am__append_4 = $(GSTREAMER_LIBS) -lgstbase-0.10
+
+#libgnashmedia_la_SOURCES += sdl/MediaDecoderSdl.cpp
sdl/AudioDecoderFfmpeg.cpp sdl/VideoDecoderFfmpeg.cpp sdl/MediaParserFfmpeg.cpp
sdl/sound_handler_sdl.cpp
address@hidden@am__append_5 = sdl/VideoDecoderFfmpeg.cpp
sdl/AudioDecoderFfmpeg.cpp sdl/sound_handler_sdl.cpp
+#noinst_HEADERS += sdl/MediaDecoderSdl.h sdl/AudioDecoderFfmpeg.h
sdl/VideoDecoderFfmpeg.h sdl/MediaParserFfmpeg.h sdl/sound_handler_sdl.h
address@hidden@am__append_6 = sdl/AudioDecoderFfmpeg.h sdl/VideoDecoderFfmpeg.h
sdl/sound_handler_sdl.h
address@hidden@am__append_7 = $(FFMPEG_LIBS)
address@hidden@am__append_8 = $(FFMPEG_CFLAGS)
+
+#libgnashmedia_la_SOURCES += sdl/MediaDecoderSdl.cpp sdl/AudioDecoderMad.cpp
sdl/sound_handler_sdl.cpp
address@hidden@am__append_9 = sdl/AudioDecoderMad.cpp sdl/sound_handler_sdl.cpp
+#noinst_HEADERS += sdl/MediaDecoderSdl.h sdl/AudioDecoderMad.h
sdl/sound_handler_sdl.h
address@hidden@am__append_10 = sdl/AudioDecoderMad.h sdl/sound_handler_sdl.h
address@hidden@am__append_11 = $(MAD_LIBS)
address@hidden@am__append_12 = $(MAD_CFLAGS)
+subdir = libmedia
+DIST_COMMON = $(am__include_HEADERS_DIST) $(am__noinst_HEADERS_DIST) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/macros/agg.m4 \
+ $(top_srcdir)/macros/archflag.m4 $(top_srcdir)/macros/boost.m4 \
+ $(top_srcdir)/macros/curl.m4 $(top_srcdir)/macros/dbus.m4 \
+ $(top_srcdir)/macros/docbook.m4 $(top_srcdir)/macros/ffmpeg.m4 \
+ $(top_srcdir)/macros/firefox.m4 \
+ $(top_srcdir)/macros/freetype.m4 \
+ $(top_srcdir)/macros/gettext.m4 $(top_srcdir)/macros/glib.m4 \
+ $(top_srcdir)/macros/gnashpkgtool.m4 \
+ $(top_srcdir)/macros/gtk2.m4 $(top_srcdir)/macros/gtkglext.m4 \
+ $(top_srcdir)/macros/iconv.m4 $(top_srcdir)/macros/kde.m4 \
+ $(top_srcdir)/macros/lib-link.m4 \
+ $(top_srcdir)/macros/lib-prefix.m4 \
+ $(top_srcdir)/macros/libXML.m4 $(top_srcdir)/macros/libexe.m4 \
+ $(top_srcdir)/macros/libltdl.m4 $(top_srcdir)/macros/ming.m4 \
+ $(top_srcdir)/macros/mtasc.m4 $(top_srcdir)/macros/mysql.m4 \
+ $(top_srcdir)/macros/nls.m4 $(top_srcdir)/macros/opengl.m4 \
+ $(top_srcdir)/macros/pango.m4 $(top_srcdir)/macros/pkg.m4 \
+ $(top_srcdir)/macros/po.m4 $(top_srcdir)/macros/progtest.m4 \
+ $(top_srcdir)/macros/pthreads.m4 $(top_srcdir)/macros/sdl.m4 \
+ $(top_srcdir)/macros/x11.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(includedir)"
+pkglibLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
address@hidden@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
address@hidden@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
address@hidden@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+libgnashmedia_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_4)
+am__libgnashmedia_la_SOURCES_DIST = AudioDecoderNellymoser.cpp \
+ AudioDecoderSimple.cpp gst/VideoDecoderGst.cpp \
+ gst/sound_handler_gst.cpp sdl/VideoDecoderFfmpeg.cpp \
+ sdl/AudioDecoderFfmpeg.cpp sdl/sound_handler_sdl.cpp \
+ sdl/AudioDecoderMad.cpp
address@hidden@am__objects_1 = \
address@hidden@ libgnashmedia_la-VideoDecoderGst.lo \
address@hidden@ libgnashmedia_la-sound_handler_gst.lo
address@hidden@am__objects_2 = libgnashmedia_la-VideoDecoderFfmpeg.lo \
address@hidden@ libgnashmedia_la-AudioDecoderFfmpeg.lo \
address@hidden@ libgnashmedia_la-sound_handler_sdl.lo
address@hidden@am__objects_3 = \
address@hidden@ libgnashmedia_la-AudioDecoderMad.lo \
address@hidden@ libgnashmedia_la-sound_handler_sdl.lo
+am_libgnashmedia_la_OBJECTS = \
+ libgnashmedia_la-AudioDecoderNellymoser.lo \
+ libgnashmedia_la-AudioDecoderSimple.lo $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3)
+libgnashmedia_la_OBJECTS = $(am_libgnashmedia_la_OBJECTS)
+libgnashmedia_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libgnashmedia_la_LDFLAGS) $(LDFLAGS) -o $@
+libltdl_la_LIBADD =
+libltdl_la_SOURCES = libltdl.c
+libltdl_la_OBJECTS = libltdl.lo
address@hidden@am_libltdl_la_rpath = -rpath $(pkglibdir)
+DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libgnashmedia_la_SOURCES) libltdl.c
+DIST_SOURCES = $(am__libgnashmedia_la_SOURCES_DIST) libltdl.c
+am__include_HEADERS_DIST = $(top_srcdir)/libltdl/ltdl.h
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+am__noinst_HEADERS_DIST = MediaBuffer.h MediaDecoder.h AudioDecoder.h \
+ VideoDecoder.h MediaParser.h AudioDecoderNellymoser.h \
+ AudioDecoderSimple.h sound_handler.h SoundInfo.h \
+ gst/VideoDecoderGst.h gst/sound_handler_gst.h \
+ sdl/AudioDecoderFfmpeg.h sdl/VideoDecoderFfmpeg.h \
+ sdl/sound_handler_sdl.h sdl/AudioDecoderMad.h
+HEADERS = $(include_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AGG_CFLAGS = @AGG_CFLAGS@
+AGG_LIBS = @AGG_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AUTOTRACE = @AUTOTRACE@
+AWK = @AWK@
+BOOST_CFLAGS = @BOOST_CFLAGS@
+BOOST_LIBS = @BOOST_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CFLAGS = @CURL_CFLAGS@
+CURL_LIBS = @CURL_LIBS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DB2X_MANXML = @DB2X_MANXML@
+DB2X_TEXIXML = @DB2X_TEXIXML@
+DB2X_VERSION = @DB2X_VERSION@
+DB2X_XSLTPROC = @DB2X_XSLTPROC@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEJAGNU_CFLAGS = @DEJAGNU_CFLAGS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DLOPEN = @DLOPEN@
+DLPREOPEN = @DLPREOPEN@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_CFLAGS = @EXPAT_CFLAGS@
+EXPAT_LIBS = @EXPAT_LIBS@
+EXTENSIONS_LIST = @EXTENSIONS_LIST@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FFMPEG_CFLAGS = @FFMPEG_CFLAGS@
+FFMPEG_LIBS = @FFMPEG_LIBS@
+FIREFOX_PLUGINS = @FIREFOX_PLUGINS@
+FLTK2_CFLAGS = @FLTK2_CFLAGS@
+FLTK2_LIBS = @FLTK2_LIBS@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FOP = @FOP@
+FREETYPE2_CFLAGS = @FREETYPE2_CFLAGS@
+FREETYPE2_LIBS = @FREETYPE2_LIBS@
+GLEXT_CFLAGS = @GLEXT_CFLAGS@
+GLEXT_LIBS = @GLEXT_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GTK2_CFLAGS = @GTK2_CFLAGS@
+GTK2_LIBS = @GTK2_LIBS@
+INCLTDL = @INCLTDL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JAVA = @JAVA@
+JPEG_CFLAGS = @JPEG_CFLAGS@
+JPEG_LIBS = @JPEG_LIBS@
+KDE_CFLAGS = @KDE_CFLAGS@
+KDE_CONFIG = @KDE_CONFIG@
+KDE_LIBS = @KDE_LIBS@
+KLASH_PLUGIN = @KLASH_PLUGIN@
+LDFLAGS = @LDFLAGS@
+LIBADD_DL = @LIBADD_DL@
+LIBEXT = @LIBEXT@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBLTDL = @LIBLTDL@
+LIBOBJS = @LIBOBJS@
+LIBPRE = @LIBPRE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LIBXML_CFLAGS = @LIBXML_CFLAGS@
+LIBXML_LIBS = @LIBXML_LIBS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKESWF = @MAKESWF@
+MEDIA_CONFIG = @MEDIA_CONFIG@
+MING_CFLAGS = @MING_CFLAGS@
+MING_CONFIG = @MING_CONFIG@
+MING_LIBS = @MING_LIBS@
+MING_VERSION = @MING_VERSION@
+MING_VERSION_CODE = @MING_VERSION_CODE@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+MTASC = @MTASC@
+MTASC_CLASSPATH = @MTASC_CLASSPATH@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENGL_CFLAGS = @OPENGL_CFLAGS@
+OPENGL_LIBS = @OPENGL_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGO_CFLAGS = @PANGO_CFLAGS@
+PANGO_LIBS = @PANGO_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFXMLTEX = @PDFXMLTEX@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRTDIAG = @PRTDIAG@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+RENDERER_CONFIG = @RENDERER_CONFIG@
+RENDERER_LIBS = @RENDERER_LIBS@
+SCROLLINSTALL = @SCROLLINSTALL@
+SCROLLKEEPER = @SCROLLKEEPER@
+SCROLLUPDATE = @SCROLLUPDATE@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SUPPORTED_GUIS = @SUPPORTED_GUIS@
+SWFC = @SWFC@
+SWFDEC_TESTSUITE = @SWFDEC_TESTSUITE@
+SWFMILL = @SWFMILL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+X11_CFLAGS = @X11_CFLAGS@
+X11_LIBS = @X11_LIBS@
+XFT_CFLAGS = @XFT_CFLAGS@
+XFT_LIBS = @XFT_LIBS@
+XGETTEXT = @XGETTEXT@
+XML2_CONFIG = @XML2_CONFIG@
+XSLTPROC = @XSLTPROC@
+Z_CFLAGS = @Z_CFLAGS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+curlconfig = @curlconfig@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docbook_styles = @docbook_styles@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mconfig = @mconfig@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pth_config = @pth_config@
+pthread_config = @pthread_config@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = no-dependencies foreign
+EXTRA_DIST =
+
+# this is where Gnash plugins get installed
+pluginsdir = $(prefix)/lib/gnash/plugins
address@hidden@include_HEADERS = $(top_srcdir)/libltdl/ltdl.h
address@hidden@LIBLTDLLIB = libltdl.la
address@hidden@LIBLTDLHEAD = $(top_srcdir)/libltdl/ltdl.h
+
+# If we are using an installable libltdl, then it needs to be built
+# before libgnash, as libgnash depends on it for extensions.
+pkglib_LTLIBRARIES = $(LIBLTDLLIB) libgnashmedia.la
+libgnashmedia_la_CPPFLAGS = -I.. -I$(srcdir) -I$(top_srcdir) \
+ -I$(top_srcdir)/libamf -I$(top_srcdir)/backend \
+ -I$(top_srcdir)/libbase -I$(top_srcdir)/server \
+ $(PTHREAD_CFLAGS) $(OPENGL_CFLAGS) $(LIBXML_CFLAGS) \
+ $(PNG_CFLAGS) $(SDL_CFLAGS) $(GLIB_CFLAGS) $(GSTREAMER_CFLAGS) \
+ $(CURL_CFLAGS) $(Z_CFLAGS) $(JPEG_CFLAGS) $(BOOST_CFLAGS) \
+ $(INCLTDL) $(NULL) $(am__append_3) $(am__append_8) \
+ $(am__append_12)
+
+# These headers get installed
+# include_HEADERS = log.h err.h proc.h serial.h xantrex.h outback.h
+
+# Don't build Dmalloc support if it's not configured in
address@hidden@DMALLOC_FILE = dlmalloc.c
+libgnashmedia_la_LIBADD = $(JPEG_LIBS) $(Z_LIBS) $(CURL_LIBS) \
+ $(OPENGL_LIBS) $(LIBINTL) $(LIBLTDL) $(BOOST_LIBS) \
+ $(PTHREAD_LIBS) $(SDL_LIBS) $(NULL) $(am__append_4) \
+ $(am__append_7) $(am__append_11)
+libgnashmedia_la_SOURCES = AudioDecoderNellymoser.cpp \
+ AudioDecoderSimple.cpp $(NULL) $(am__append_1) $(am__append_5) \
+ $(am__append_9)
+noinst_HEADERS = MediaBuffer.h MediaDecoder.h AudioDecoder.h \
+ VideoDecoder.h MediaParser.h AudioDecoderNellymoser.h \
+ AudioDecoderSimple.h sound_handler.h SoundInfo.h $(NULL) \
+ $(am__append_2) $(am__append_6) $(am__append_10)
+libgnashmedia_la_LDFLAGS = -release $(VERSION)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cpp .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am
$(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libmedia/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libmedia/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
$(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
$(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure
$(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+ @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(pkglibLTLIBRARIES_INSTALL)
$(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(pkglibLTLIBRARIES_INSTALL)
$(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(pkglibdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f
'$(DESTDIR)$(pkglibdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgnashmedia.la: $(libgnashmedia_la_OBJECTS) $(libgnashmedia_la_DEPENDENCIES)
+ $(libgnashmedia_la_LINK) -rpath $(pkglibdir)
$(libgnashmedia_la_OBJECTS) $(libgnashmedia_la_LIBADD) $(LIBS)
+libltdl.la: $(libltdl_la_OBJECTS) $(libltdl_la_DEPENDENCIES)
+ $(LINK) $(am_libltdl_la_rpath) $(libltdl_la_OBJECTS)
$(libltdl_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+.c.o:
+ $(COMPILE) -c $<
+
+.c.obj:
+ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ $(LTCOMPILE) -c -o $@ $<
+
+.cpp.o:
+ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+ $(LTCXXCOMPILE) -c -o $@ $<
+
+libgnashmedia_la-AudioDecoderNellymoser.lo: AudioDecoderNellymoser.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-AudioDecoderNellymoser.lo `test -f
'AudioDecoderNellymoser.cpp' || echo '$(srcdir)/'`AudioDecoderNellymoser.cpp
+
+libgnashmedia_la-AudioDecoderSimple.lo: AudioDecoderSimple.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-AudioDecoderSimple.lo `test -f 'AudioDecoderSimple.cpp' ||
echo '$(srcdir)/'`AudioDecoderSimple.cpp
+
+libgnashmedia_la-VideoDecoderGst.lo: gst/VideoDecoderGst.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-VideoDecoderGst.lo `test -f 'gst/VideoDecoderGst.cpp' || echo
'$(srcdir)/'`gst/VideoDecoderGst.cpp
+
+libgnashmedia_la-sound_handler_gst.lo: gst/sound_handler_gst.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-sound_handler_gst.lo `test -f 'gst/sound_handler_gst.cpp' ||
echo '$(srcdir)/'`gst/sound_handler_gst.cpp
+
+libgnashmedia_la-VideoDecoderFfmpeg.lo: sdl/VideoDecoderFfmpeg.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-VideoDecoderFfmpeg.lo `test -f 'sdl/VideoDecoderFfmpeg.cpp' ||
echo '$(srcdir)/'`sdl/VideoDecoderFfmpeg.cpp
+
+libgnashmedia_la-AudioDecoderFfmpeg.lo: sdl/AudioDecoderFfmpeg.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-AudioDecoderFfmpeg.lo `test -f 'sdl/AudioDecoderFfmpeg.cpp' ||
echo '$(srcdir)/'`sdl/AudioDecoderFfmpeg.cpp
+
+libgnashmedia_la-sound_handler_sdl.lo: sdl/sound_handler_sdl.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-sound_handler_sdl.lo `test -f 'sdl/sound_handler_sdl.cpp' ||
echo '$(srcdir)/'`sdl/sound_handler_sdl.cpp
+
+libgnashmedia_la-AudioDecoderMad.lo: sdl/AudioDecoderMad.cpp
+ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnashmedia_la_CPPFLAGS)
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o
libgnashmedia_la-AudioDecoderMad.lo `test -f 'sdl/AudioDecoderMad.cpp' || echo
'$(srcdir)/'`sdl/AudioDecoderMad.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(includeHEADERS_INSTALL) '$$d$$p'
'$(DESTDIR)$(includedir)/$$f'"; \
+ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-includeHEADERS install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-includeHEADERS uninstall-pkglibLTLIBRARIES
+
+
+# Rebuild with GCC 4.x Mudflap support
+mudflap:
+ @echo "Rebuilding with GCC Mudflap support"
+ $(MAKE) CXXFLAGS="$(CXXFLAGS) -fmudflap" LDFLAGS="$(LDFLAGS) -lmudflap"
+
+clean-hook:
+ -rm -f core.* *.obj
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: libmedia/MediaBuffer.h
===================================================================
RCS file: libmedia/MediaBuffer.h
diff -N libmedia/MediaBuffer.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/MediaBuffer.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,247 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __MEDIABUFFER_H__
+#define __MEDIABUFFER_H__
+
+#include <boost/thread/mutex.hpp>
+#include <queue>
+
+namespace gnash {
+
+class raw_mediadata_t
+{
+public:
+ raw_mediadata_t():
+ m_stream_index(-1),
+ m_size(0),
+ m_data(NULL),
+ m_ptr(NULL),
+ m_pts(0)
+ {
+ }
+
+ ~raw_mediadata_t()
+ {
+ if (m_data) delete [] m_data;
+ }
+
+ int m_stream_index;
+ uint32_t m_size;
+ uint8_t* m_data;
+ uint8_t* m_ptr;
+ uint32_t m_pts; // presentation timestamp in millisec
+};
+
+/// Threadsafe elements-owning queue
+//
+/// This class is a threadsafe queue, using std:queue and locking.
+/// It is used to store decoded audio and video data which are waiting to be
"played"
+/// Elements of the queue are owned by instances of this class.
+///
+class MediaBuffer
+{
+public:
+ MediaBuffer()
+ :
+ _bufferTime(100) // Deafault value is 100 milliseconds
+ {
+ }
+
+ ~MediaBuffer()
+ {
+ flush();
+ }
+
+ /// Returns the size if the audio queue. Locks.
+ //
+ /// @return the size of the audio queue
+ ///
+ size_t audioSize() {
+ boost::mutex::scoped_lock lock(_mutex);
+ return audioQueue.size();
+ }
+
+ /// Returns the size if the video queue. Locks.
+ //
+ /// @return the size of the video queue
+ ///
+ size_t videoSize() {
+ boost::mutex::scoped_lock lock(_mutex);
+ return videoQueue.size();
+ }
+
+ /// Pushes an element to the audio queue. Locks.
+ //
+ /// @param member
+ /// The element to be pushed unto the audio queue.
+ ///
+ void pushAudio(raw_mediadata_t* member) {
+ boost::mutex::scoped_lock lock(_mutex);
+ audioQueue.push(member);
+ }
+
+ /// Pushes an element to the video queue. Locks.
+ //
+ /// @param member
+ /// The element to be pushed unto the video queue.
+ ///
+ void pushVideo(raw_mediadata_t* member) {
+ boost::mutex::scoped_lock lock(_mutex);
+ videoQueue.push(member);
+ }
+
+ /// Returns a pointer to the first element on the audio queue. Locks.
+ //
+ /// If no elements are available this function returns NULL.
+ ///
+ /// @return a pointer to the first element on the audio queue, NULL if
queue is empty.
+ ///
+ raw_mediadata_t* audioFront() {
+ boost::mutex::scoped_lock lock(_mutex);
+ if (audioQueue.empty()) return NULL;
+ return audioQueue.front();
+ }
+
+ /// Returns a pointer to the first element on the video queue. Locks.
+ //
+ /// If no elements are available this function returns NULL.
+ ///
+ /// @return a pointer to the first element on the video queue, NULL if
queue is empty.
+ ///
+ raw_mediadata_t* videoFront() {
+ boost::mutex::scoped_lock lock(_mutex);
+ if (videoQueue.empty()) return NULL;
+ return videoQueue.front();
+ }
+
+ /// Pops the first element from the audio queue. Locks.
+ //
+ /// If no elements are available this function is a noop.
+ ///
+ void audioPop() {
+ boost::mutex::scoped_lock lock(_mutex);
+ if (!audioQueue.empty()) audioQueue.pop();
+ }
+
+ /// Pops the first element from the video queue. Locks.
+ //
+ /// If no elements are available this function is a noop.
+ ///
+ void videoPop() {
+ boost::mutex::scoped_lock lock(_mutex);
+ if (!videoQueue.empty()) videoQueue.pop();
+ }
+
+ /// Fluses the buffer/queues
+ void flush() {
+ boost::mutex::scoped_lock lock(_mutex);
+ while (!videoQueue.empty() > 0)
+ {
+ delete videoQueue.front();
+ videoQueue.pop();
+ }
+
+ while (!audioQueue.empty() > 0)
+ {
+ delete audioQueue.front();
+ audioQueue.pop();
+ }
+ }
+
+ /// Sets the size of the buffer in milliseconds. Locks.
+ //
+ /// @param size
+ /// The size of the buffer.
+ ///
+ void setBufferTime(uint32_t size) {
+ boost::mutex::scoped_lock lock(_mutex);
+ _bufferTime = size;
+ }
+
+ /// Gets the requested size of the buffer in milliseconds. Locks.
+ //
+ /// @return the requested size of the buffer.
+ ///
+ uint32_t getReqBufferTime() {
+ boost::mutex::scoped_lock lock(_mutex);
+ return _bufferTime;
+ }
+
+ /// Gets the real size of the buffer in milliseconds. The size of
+ /// the audio and video buffer is compared and the biggest is returned.
Locks.
+ //
+ /// @return the real size of the buffer in milliseconds.
+ ///
+ uint32_t getBufferTime() {
+ boost::mutex::scoped_lock lock(_mutex);
+ bool ret = calcBufferTime();
+ return ret;
+ }
+
+ /// Checks if the contents of the buffer span a timeframe larger than
+ /// than the requested size. Locks.
+ //
+ /// @return the real size of the buffer in milliseconds.
+ ///
+ bool isFull() {
+ boost::mutex::scoped_lock lock(_mutex);
+ bool ret = (calcBufferTime() >= _bufferTime);
+ return ret;
+ }
+
+private:
+
+ /// Calculates the real size of the buffer in milliseconds. The size of
+ /// the audio and video buffer is compared and the biggest is returned.
+ //
+ /// @return the real size of the buffer in milliseconds.
+ ///
+ uint32_t calcBufferTime() {
+ uint32_t size = 0;
+
+ // Get the size of audio buffer
+ if (!audioQueue.empty()) {
+ size = audioQueue.back()->m_pts -
audioQueue.front()->m_pts;
+ }
+
+ // Get the size of video buffer, and use that if it is bigger
than
+ // the vaule from the audio buffer.
+ if (!videoQueue.empty()) {
+ uint32_t vSize = videoQueue.back()->m_pts -
videoQueue.front()->m_pts;
+ if (vSize > size) size = vSize;
+ }
+ return size;
+ }
+
+
+ /// Mutex used for locking
+ boost::mutex _mutex;
+
+ /// The queues of audio and video data.
+ std::queue <raw_mediadata_t*> audioQueue;
+ std::queue <raw_mediadata_t*> videoQueue;
+
+ /// The requested size of the buffer in milliseconds
+ uint32_t _bufferTime;
+};
+
+} // gnash namespace
+
+#endif // __MEDIABUFFER_H__
Index: libmedia/MediaDecoder.h
===================================================================
RCS file: libmedia/MediaDecoder.h
diff -N libmedia/MediaDecoder.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/MediaDecoder.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,237 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __MEDIADECODER_H__
+#define __MEDIADECODER_H__
+
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <vector>
+
+#include "MediaBuffer.h"
+#include "MediaParser.h"
+#include "FLVParser.h"
+#include "log.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+namespace gnash {
+
+
+/// \brief
+/// The MediaDecoder class decodes media data and puts it on a given buffer.
+///
+/// We need to be able to handle event stuff, so we store the events that
+/// need to be handled, and then NetStream can ask for it on ::advance()
+/// or whenever it is appropriate. Eventhandling is different from AS2 to AS3,
+/// but in this first draft only AS2 will be supported.
+///
+class MediaDecoder
+{
+
+public:
+ /// Status codes used for NetStream onStatus notifications
+ // Copied from NetSteam.h, so it should be updated it the orginal
+ // is changed.
+ enum StatusCode {
+
+ // Internal status, not a valid ActionScript value
+ invalidStatus,
+
+ /// NetStream.Buffer.Empty (level: status)
+ bufferEmpty,
+
+ /// NetStream.Buffer.Full (level: status)
+ bufferFull,
+
+ /// NetStream.Buffer.Flush (level: status)
+ bufferFlush,
+
+ /// NetStream.Play.Start (level: status)
+ playStart,
+
+ /// NetStream.Play.Stop (level: status)
+ playStop,
+
+ /// NetStream.Seek.Notify (level: status)
+ seekNotify,
+
+ /// NetStream.Play.StreamNotFound (level: error)
+ streamNotFound,
+
+ /// NetStream.Seek.InvalidTime (level: error)
+ invalidTime
+ };
+
+ /// This is copied from the render and should be changed if the
original is.
+ enum videoOutputFormat
+ {
+ NONE,
+ YUV,
+ RGB
+ };
+
+ /// Internal error codes
+ enum MediaDecoderErrorCode {
+
+ /// All is fine
+ noError,
+
+ /// Stream/connection error
+ streamError,
+
+ /// Error while decoding
+ decodingError,
+
+ /// Error while parsing
+ parsingError
+ };
+
+ /// \brief
+ /// Create a MediaDecoder reading input from
+ /// the given tu_file
+ //
+ /// @param stream
+ /// tu_file to use for input.
+ /// Ownership left to the caller.
+ ///
+ /// @param buffer
+ /// The buffer we will use.
+ /// Ownership left to the caller.
+ ///
+ MediaDecoder(tu_file* stream, MediaBuffer* buffer, uint16_t swfVersion,
int format)
+ :
+ _buffer(buffer),
+ _stream(stream),
+ _swfVersion(swfVersion),
+ _videoFrameFormat(format),
+ _parser(NULL),
+ _lastConfirmedPosition(0),
+ _streamSize(0),
+ _error(noError),
+ _isFLV(true),
+ _inputPos(0),
+ _audio(true),
+ _video(true)
+ {
+ }
+
+ /// Destroys the Decoder
+ ~MediaDecoder() {}
+
+ /// Pause decoding (needed ?)
+ virtual void pause() {}
+
+ /// Resume/start decoding (needed ?)
+ virtual void decode() {}
+
+ /// Seeks to pos, returns the new position
+ virtual uint32_t seek(uint32_t /*pos*/) { return 0;}
+
+ virtual std::pair<uint32_t, uint32_t> getWidthAndHeight() { return
std::pair<uint32_t, uint32_t>(0,0); }
+
+ /// Returns the size of the file being loaded, in bytes
+ uint32_t getBytesTotal()
+ {
+ return _streamSize;
+ }
+
+ /// Returns the amount of bytes of the current file that has been
loaded.
+ uint32_t getBytesLoaded() {
+ return _lastConfirmedPosition;
+ }
+
+ /// Returns a vector with the waiting onStatus events (AS2)
+ std::vector<StatusCode> getOnStatusEvents() {
+ boost::mutex::scoped_lock lock(_onStatusMutex);
+
+ const std::vector<StatusCode> statusQueue(_onStatusQueue);
+ _onStatusQueue.clear();
+ return statusQueue;
+ }
+
+ /// Returns whether we got audio
+ bool gotAudio() {
+ return _audio;
+ }
+
+ /// Returns whether we got video
+ bool gotVideo() {
+ return _video;
+ }
+
+protected:
+ /// Push an event to the onStatus event queue (AS2)
+ void pushOnStatus(StatusCode code) {
+ boost::mutex::scoped_lock lock(_onStatusMutex);
+ _onStatusQueue.push_back(code);
+ }
+
+ /// The media buffer
+ MediaBuffer* _buffer;
+
+ /// The stream we decode
+ tu_file* _stream;
+
+ /// Version of the SWF playing
+ uint16_t _swfVersion;
+
+ /// The output format
+ int _videoFrameFormat;
+
+ /// The parser used
+ std::auto_ptr<MediaParser> _parser;
+
+ /// The last confirmed size of the downloaded file
+ uint32_t _lastConfirmedPosition;
+
+ /// total size of the file being downloaded
+ uint32_t _streamSize;
+
+ /// Is everything ok?
+ MediaDecoderErrorCode _error;
+
+ /// Waiting NetStream onStatus events (AS2)
+ std::vector<StatusCode> _onStatusQueue;
+
+ /// Mutex protecting _onStatusQueue
+ boost::mutex _onStatusMutex;
+
+ /// Are we decoding a FLV?
+ bool _isFLV;
+
+ /// The position in the inputfile, only used when not playing a FLV
+ long _inputPos;
+
+ /// Do we have audio ?
+ bool _audio;
+
+ /// Do we have video ?
+ bool _video;
+
+};
+
+
+} // namespace gnash
+
+#endif // __MEDIADECODER_H__
Index: libmedia/MediaParser.h
===================================================================
RCS file: libmedia/MediaParser.h
diff -N libmedia/MediaParser.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/MediaParser.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,220 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __MEDIAPARSER_H__
+#define __MEDIAPARSER_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tu_file.h"
+
+#ifdef USE_FFMPEG
+#include <ffmpeg/avcodec.h>
+#endif
+namespace gnash {
+
+enum codecType
+{
+ FLASH,
+ FFMPEG
+};
+
+enum videoCodecType
+{
+ VIDEO_CODEC_H263 = 2, // H263/SVQ3 video codec
+ VIDEO_CODEC_SCREENVIDEO = 3, // Screenvideo codec
+ VIDEO_CODEC_VP6 = 4, // On2 VP6 video codec
+ VIDEO_CODEC_VP6A = 5, // On2 VP6 Alpha video codec
+ VIDEO_CODEC_SCREENVIDEO2 = 6 // Screenvideo2 codec
+};
+
+enum audioCodecType
+{
+ AUDIO_CODEC_RAW = 0, // unspecified format. Useful for
8-bit sounds???
+ AUDIO_CODEC_ADPCM = 1, // gnash doesn't pass this through; it
uncompresses and sends FORMAT_NATIVE16
+ AUDIO_CODEC_MP3 = 2,
+ AUDIO_CODEC_UNCOMPRESSED = 3, // 16 bits/sample, little-endian
+ AUDIO_CODEC_NELLYMOSER_8HZ_MONO = 5, // According to ffmpeg
+ AUDIO_CODEC_NELLYMOSER = 6 // Mystery proprietary format; see
nellymoser.com
+};
+
+enum tagType
+{
+ AUDIO_TAG = 0x08,
+ VIDEO_TAG = 0x09,
+ META_TAG = 0x12
+};
+
+/// \brief
+/// The AudioInfo class contains information about the audiostream
+/// in the file being parsed. The information stored is codec-id,
+/// samplerate, samplesize, stereo, duration and codec-type.
+/// timestamp,
+class AudioInfo
+{
+public:
+ AudioInfo(int codeci, uint16_t sampleRatei, uint16_t sampleSizei, bool
stereoi, uint64_t durationi, codecType typei)
+ : codec(codeci),
+ sampleRate(sampleRatei),
+ sampleSize(sampleSizei),
+ stereo(stereoi),
+ duration(durationi),
+ type(typei)
+ {
+ }
+
+ int codec;
+ uint16_t sampleRate;
+ uint16_t sampleSize;
+ bool stereo;
+ uint64_t duration;
+ codecType type;
+};
+
+/// \brief
+/// The VideoInfo class contains information about the videostream
+/// in the file being parsed. The information stored is codec-id,
+/// width, height, framerate, duration and codec-type.
+/// timestamp,
+class VideoInfo
+{
+public:
+ VideoInfo(int codeci, uint16_t widthi, uint16_t heighti, uint16_t
frameRatei, uint64_t durationi, codecType typei)
+ : codec(codeci),
+ width(widthi),
+ height(heighti),
+ frameRate(frameRatei),
+ duration(durationi),
+#ifdef USE_FFMPEG
+ videoCodecCtx(NULL),
+#endif
+ type(typei)
+ {
+ }
+
+ int codec;
+ uint16_t width;
+ uint16_t height;
+ uint16_t frameRate;
+ uint64_t duration;
+#ifdef USE_FFMPEG
+ AVCodecContext* videoCodecCtx; // UGLY!!
+#endif
+ codecType type;
+};
+
+/// \brief
+/// The MediaFrame class contains a video or audio frame, its size, its
+/// timestamp. Ownership of the data is in the parser.
+class MediaFrame
+{
+public:
+ uint32_t dataSize;
+ uint8_t* data;
+ uint64_t timestamp;
+ uint8_t tag;
+};
+
+/// \brief
+/// The MediaParser class detects the format of the input file, and parses it
on demand.
+///
+class MediaParser
+{
+public:
+ MediaParser(tu_file* stream)
+ :
+ _isAudioMp3(false),
+ _isAudioNellymoser(false),
+ _stream(stream)
+ {}
+
+ /// Used to parse the next media frame in the stream and return it
+ //
+ /// @return a pointer to a MediaFrame in which the undecoded frame data
is.
+ virtual MediaFrame* parseMediaFrame() { return NULL; }
+
+ /// Is the input MP3?
+ //
+ /// @return if the input audio is MP3
+ bool isAudioMp3() { return _isAudioMp3; }
+
+ /// Is the input Nellymoser?
+ //
+ /// @return if the input audio is Nellymoser
+ bool isAudioNellymoser() { return _isAudioNellymoser; }
+
+ /// Setup the parser
+ //
+ /// @return whether we'll be able to parse the file.
+ virtual bool setupParser() { return false; }
+
+ /// Returns a VideoInfo class about the videostream
+ //
+ /// @return a VideoInfo class about the videostream
+ virtual std::auto_ptr<VideoInfo> getVideoInfo() { return
std::auto_ptr<VideoInfo>(NULL); }
+
+ /// Returns a AudioInfo class about the audiostream
+ //
+ /// @return a AudioInfo class about the audiostream
+ virtual std::auto_ptr<AudioInfo> getAudioInfo() { return
std::auto_ptr<AudioInfo>(NULL); }
+
+ /// Seeks to the closest possible position the given position,
+ /// and returns the new position.
+ //
+ /// @return the position the seek reached
+ virtual uint32_t seek(uint32_t) { return 0; }
+
+ /// Returns the framedelay from the last to the current
+ /// audioframe in milliseconds. This is used for framerate.
+ //
+ /// @return the diff between the current and last frame
+ virtual uint32_t audioFrameDelay() { return 0; }
+
+ /// Returns the framedelay from the last to the current
+ /// videoframe in milliseconds.
+ //
+ /// @return the diff between the current and last frame
+ virtual uint32_t videoFrameDelay() { return 0; }
+
+ /// Returns the framerate of the video
+ //
+ /// @return the framerate of the video
+ virtual uint16_t videoFrameRate() { return 0; }
+
+ /// Returns the last parsed position in the file in bytes
+ virtual uint32_t getLastParsedPos() { return 0; }
+
+protected:
+
+ /// Is the input audio MP3?
+ bool _isAudioMp3;
+
+ /// Is the input audio Nellymoser?
+ bool _isAudioNellymoser;
+
+ /// The stream used to access the file
+ tu_file* _stream;
+};
+
+
+} // namespace gnash
+
+#endif // __MEDIAPARSER_H__
Index: libmedia/SoundInfo.h
===================================================================
RCS file: libmedia/SoundInfo.h
diff -N libmedia/SoundInfo.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/SoundInfo.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,114 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+//
+//
+
+// $Id:
+
+#ifndef __SOUNDINFO_H__
+#define __SOUNDINFO_H__
+
+#include "MediaParser.h"
+
+namespace gnash {
+
+///
+/// Class containing information about a sound. Is created by the parser while
+/// parsing, and ownership is then transfered to sound_data. When the parser is
+/// parsing streams, it will ask the soundhandler for this to know what
properties
+/// the stream has.
+///
+class SoundInfo {
+public:
+ /// Constructor
+ //
+ /// @param format
+ /// The format of the sound. Can be MP3, ADPCM, uncompressed or
Nellymoser
+ ///
+ /// @param stero
+ /// Defines whether the sound is in stereo.
+ ///
+ /// @param sampleRate
+ /// The sample rate of the sound.
+ ///
+ /// @param sampleCount
+ /// The sample count in the sound. In soundstreams this is an average
for each frame.
+ ///
+ /// @param is16bit
+ /// Defines whether the sound is in stereo.
+ /// Defines whether the sound is in 16bit format (samplesize == 2)?
else it
+ /// is 8bit (samplesize == 1). Used for streams when decoding adpcm.
+ ///
+ SoundInfo(audioCodecType format, bool stereo, uint32_t sampleRate,
uint32_t sampleCount, bool is16bit)
+ : _format(format),
+ _stereo(stereo),
+ _sampleRate(sampleRate),
+ _sampleCount(sampleCount),
+ _is16bit(is16bit)
+ {
+ }
+
+ /// Returns the current format of the sound
+ ///
+ /// @return the current format of the sound
+ audioCodecType getFormat() { return _format; }
+
+ /// Returns the stereo status of the sound
+ ///
+ /// @return the stereo status of the sound
+ bool isStereo() { return _stereo; }
+
+ /// Returns the samplerate of the sound
+ ///
+ /// @return the samplerate of the sound
+ unsigned long getSampleRate() { return _sampleRate; }
+
+ /// Returns the samplecount of the sound
+ ///
+ /// @return the samplecount of the sound
+ unsigned long getSampleCount() { return _sampleCount; }
+
+ /// Returns the 16bit status of the sound
+ ///
+ /// @return the 16bit status of the sound
+ bool is16bit() { return _is16bit; }
+
+private:
+ /// Current format of the sound (MP3, raw, etc).
+ audioCodecType _format;
+
+ /// The size of the undecoded data
+ unsigned long _dataSize;
+
+ /// Stereo or not
+ bool _stereo;
+
+ /// Sample rate, one of 5512, 11025, 22050, 44100
+ uint32_t _sampleRate;
+
+ /// Number of samples
+ uint32_t _sampleCount;
+
+ /// Is the audio in 16bit format (samplesize == 2)? else it
+ /// is 8bit (samplesize == 1). Used for streams when decoding adpcm.
+ bool _is16bit;
+};
+
+} // namespace gnash
+
+#endif // __SOUNDINFO_H__
Index: libmedia/VideoDecoder.h
===================================================================
RCS file: libmedia/VideoDecoder.h
diff -N libmedia/VideoDecoder.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/VideoDecoder.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,107 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __VIDEODECODER_H__
+#define __VIDEODECODER_H__
+
+#include "MediaParser.h"
+#include "image.h"
+
+namespace gnash {
+
+class VideoDecoder {
+
+public:
+ VideoDecoder() {}
+ ~VideoDecoder() {}
+
+ /// Sets up the decoder.
+ //
+ /// @param info
+ /// VideoInfo class with all the info needed to decode
+ /// the video correctly.
+ ///
+ /// @return true if succesfull else false
+ ///
+ virtual bool setup(VideoInfo* /*info*/) { return false; }
+
+ /// Sets up the decoder.
+ //
+ /// @param width
+ /// The width of the video
+ ///
+ /// @param height
+ /// The height of the video
+ ///
+ /// @param deblocking
+ /// Should a deblocking filter be used? 1 = off, 2 = on
+ ///
+ /// @param smoothing
+ /// Should the video be smoothed?
+ ///
+ /// @param format
+ /// The codec of the video, see codecType
+ ///
+ /// @param outputFormat
+ /// The outputFormat of the video, see videoOutputFormat
+ ///
+ /// @return true if succesfull else false
+ ///
+ virtual bool setup(
+ int /*width*/,
+ int /*height*/,
+ int /*deblocking*/,
+ bool /*smoothing*/,
+ videoCodecType /*format*/,
+ int /*outputFormat*/) /* should this argument be of
VideoOutputFormat type ?*/ { return false; }
+
+ /// Decodes a frame and returns a pointer to the data
+ //
+ /// @param input
+ /// The video data
+ ///
+ /// @param inputSize
+ /// The size of the video data
+ ///
+ /// @param outputSize
+ /// The output size of the video data, is passed by reference.
+ ///
+ /// @return a pointer to the decoded data, or NULL if decoding fails.
+ /// The caller owns the decoded data.
+ ///
+ virtual uint8_t* decode(uint8_t* /*input*/, uint32_t /*inputSize*/,
uint32_t& /*outputSize*/) { return NULL; }
+
+ /// Decodes a frame and returns an image::base containing it
+ //
+ /// @param input
+ /// The video data
+ ///
+ /// @param inputSize
+ /// The size of the video data
+ ///
+ /// @return a pointer to the image with the decoded data, or NULL if
decoding fails.
+ /// The caller owns the decoded data.
+ ///
+ virtual std::auto_ptr<image::image_base> decodeToImage(uint8_t*
/*input*/, uint32_t /*inputSize*/) { return
std::auto_ptr<image::image_base>(NULL); }
+
+};
+
+} // gnash namespace
+
+#endif // __VIDEODECODER_H__
Index: libmedia/sound_handler.h
===================================================================
RCS file: libmedia/sound_handler.h
diff -N libmedia/sound_handler.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sound_handler.h 27 Sep 2007 23:59:53 -0000 1.1
@@ -0,0 +1,532 @@
+//
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+//
+//
+
+/* $Id: sound_handler.h,v 1.1 2007/09/27 23:59:53 tgc Exp $ */
+
+/// \page sound_handler_intro Sound handler introduction
+///
+/// This page must be written, volunteers ? :)
+///
+
+#ifndef SOUND_HANDLER_H
+#define SOUND_HANDLER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tu_config.h" // for DSOEXPORT
+#include "tu_types.h"
+#include "SoundInfo.h"
+
+#include <vector>
+#include <memory>
+#include <cassert>
+
+namespace gnash {
+ class stream;
+// class SoundInfo;
+}
+
+namespace gnash {
+
+/// A buffer of bytes
+class Buffer {
+public:
+ Buffer()
+ :
+ _capacity(0),
+ _data(0),
+ _size(0)
+ {}
+
+ /// Create a Buffer with the given initial content
+ //
+ /// @param newData data to assign to this buffer.
+ /// Allocated with new[]. Ownership transferred.
+ ///
+ /// @param size number of bytes in the new data
+ ///
+ Buffer(uint8_t* newData, size_t size)
+ :
+ _capacity(size),
+ _data(newData),
+ _size(size)
+ {}
+
+ /// Append data to this buffer
+ //
+ /// @param newData data to append to this buffer.
+ /// Allocated with new[]. Ownership transferred.
+ ///
+ /// @param size number of bytes in the new data
+ ///
+ void append(uint8_t* newData, size_t size)
+ {
+ if ( ! _capacity )
+ {
+ _data = newData;
+ _size = size;
+ _capacity = _size;
+ return;
+ }
+
+ reserve(_size+size);
+
+ assert(_capacity >= _size+size);
+ memcpy(_data+_size, newData, size);
+ _size += size;
+ delete [] newData;
+ }
+
+ /// Assign data to this buffer
+ //
+ /// @param newData data to assign to this buffer.
+ /// Allocated with new[]. Ownership transferred.
+ ///
+ /// @param size number of bytes in the new data
+ ///
+ void assign(uint8_t* newData, size_t size)
+ {
+ if ( ! _capacity )
+ {
+ _data = newData;
+ _size = size;
+ _capacity = _size;
+ return;
+ }
+
+ _size=0; // so reserve won't memcpy...
+ reserve(size);
+
+ assert(_capacity >= size);
+
+ memcpy(_data, newData, size);
+ _size = size;
+
+ delete [] newData;
+ }
+
+ const uint8_t* data() const
+ {
+ return _data;
+ }
+
+ uint8_t* data()
+ {
+ return _data;
+ }
+
+ const uint8_t* data(size_t pos) const
+ {
+ assert(pos < _capacity);
+ return _data+pos;
+ }
+
+ uint8_t* data(size_t pos)
+ {
+ assert(pos < _capacity);
+ return _data+pos;
+ }
+
+ void resize(size_t newSize)
+ {
+ // we won't change capacity here
+ // (should we?)
+ _size = newSize;
+ }
+
+ void reserve(size_t newCapacity)
+ {
+ if ( _capacity > newCapacity ) return;
+
+ // TODO: use smalles power of 2 bigger then newCapacity
+ _capacity = std::max(newCapacity, _capacity*2);
+
+ uint8_t* tmp = _data;
+ _data = new uint8_t[_capacity];
+ if ( tmp )
+ {
+ if ( _size ) memcpy(_data, tmp, _size);
+ delete [] tmp;
+ }
+ }
+
+ size_t size() const
+ {
+ return _size;
+ }
+
+ ~Buffer()
+ {
+ delete [] _data;
+ }
+
+private:
+
+ size_t _capacity;
+
+ uint8_t* _data;
+
+ size_t _size;
+
+};
+
+
+/// Sound handler.
+//
+/// Stores the audio found by the parser and plays on demand.
+/// Can also play sound from AS classes NetStream and Sound using callbacks
+/// (see attach_aux_streamer and dettach_aux_streamer).
+///
+/// You may define a subclass of this, and pass an instance to
+/// set_sound_handler().
+///
+class DSOEXPORT sound_handler
+{
+public:
+
+ // See attach_aux_streamer
+ // TODO: change third parameter type to unsigned
+ typedef bool (*aux_streamer_ptr)(void *udata, uint8_t *stream, int len);
+
+ /// Used to control volume for event sounds. It basically tells that
from
+ /// sample X the volume for left out is Y and for right out is Z.
Several
+ /// envelopes can be assigned to a sound to make a fade out or similar
stuff.
+ struct sound_envelope
+ {
+ uint32_t m_mark44;
+ uint16_t m_level0;
+ uint16_t m_level1;
+ };
+
+ // If stereo is true, samples are interleaved w/ left sample first.
+
+ /// gnash's parser calls this to create sounds to be played later.
+ //
+ /// @param data
+ /// The data to be stored. For soundstream this is NULL.
+ /// If not NULL, ownership of the data is transferred.
+ /// The data is assumed to have been allocated using new[].
+ ///
+ /// @param data_bytes
+ /// The size of the data to be stored. For soundstream this is 0.
+ ///
+ /// @param sinfo
+ /// A SoundInfo object contained in an auto_ptr, which contains
info about samplerate,
+ /// samplecount, stereo and more. The SoundObject must be not-NULL!
+ ///
+ /// @return the id given by the soundhandler for later identification.
+ ///
+ virtual int create_sound(
+ void* data,
+ unsigned int data_bytes,
+ std::auto_ptr<SoundInfo> sinfo
+ ) = 0;
+
+ /// gnash's parser calls this to fill up soundstreams data
+ //
+ /// @param data
+ /// The sound data to be saved, allocated by new[]. Ownership is
transferred.
+ /// TODO: define a class for containing both data and data_bytes ?
or use vector ?
+ ///
+ /// @param data_bytes
+ /// Size of the data in bytes
+ ///
+ /// @param sample_count
+ /// Number of samples in the data
+ ///
+ /// @param handle_id
+ /// The soundhandlers id of the sound we want some info about.
+ ///
+ /// @return size of the data buffer before the new data is appended
+ ///
+ virtual long fill_stream_data(unsigned char* data, unsigned int
data_bytes, unsigned int sample_count, int handle_id) = 0;
+
+ /// Returns a pointer to the SoundInfo object for the sound with the
given id.
+ /// The SoundInfo object is still owned by the soundhandler.
+ //
+ /// @param soundhandle
+ /// The soundhandlers id of the sound we want some info about.
+ ///
+ /// @return a pointer to the SoundInfo object for the sound with the
given id.
+ ///
+ virtual SoundInfo* get_sound_info(int sound_handle) = 0;
+
+ /// gnash calls this when it wants you to play the defined sound.
+ //
+ /// @param sound_handle
+ /// The sound_handlers id for the sound to start playing
+ ///
+ /// @param loop_count
+ /// loop_count == 0 means play the sound once (1 means play it twice,
etc)
+ ///
+ /// @param secondOffset
+ /// When starting soundstreams there sometimes is a offset to make the
sound
+ /// start at the exact right moment.
+ ///
+ /// @param start
+ /// When starting a soundstream from a random frame, this tells where
in the
+ /// data the decoding should start.
+ ///
+ /// @param envelopes
+ /// Some eventsounds have some volume control mechanism called
envelopes.
+ /// They basically tells that from sample X the volume should be Y.
+ ///
+ virtual void play_sound(int sound_handle, int loop_count, int
secondOffset, long start, const std::vector<sound_envelope>* envelopes) = 0;
+
+ /// stops all sounds currently playing in a SWF file without stopping
the playhead.
+ /// Sounds set to stream will resume playing as the playhead moves over
the frames they are in.
+ virtual void stop_all_sounds() = 0;
+
+ /// Gets the volume for a given sound. Only used by the AS Sound class
+ //
+ /// @param sound_handle
+ /// The sound_handlers id for the sound to be deleted
+ ///
+ /// @return the sound volume level as an integer from 0 to 100,
+ /// where 0 is off and 100 is full volume. The default setting is 100.
+ virtual int get_volume(int sound_handle) = 0;
+
+ /// Sets the volume for a given sound. Only used by the AS Sound class
+ //
+ /// @param sound_handle
+ /// The sound_handlers id for the sound to be deleted
+ ///
+ /// @param volume
+ /// A number from 0 to 100 representing a volume level.
+ /// 100 is full volume and 0 is no volume. The default setting is 100.
+ ///
+ virtual void set_volume(int sound_handle, int volume) = 0;
+
+ /// Stop the specified sound if it's playing.
+ /// (Normally a full-featured sound API would take a
+ /// handle specifying the *instance* of a playing
+ /// sample, but SWF is not expressive that way.)
+ //
+ /// @param sound_handle
+ /// The sound_handlers id for the sound to be deleted
+ ///
+ virtual void stop_sound(int sound_handle) = 0;
+
+ /// gnash calls this when it's done with a particular sound.
+ //
+ /// @param sound_handle
+ /// The sound_handlers id for the sound to be deleted
+ ///
+ virtual void delete_sound(int sound_handle) = 0;
+
+ /// gnash calls this to mute audio
+ virtual void mute() = 0;
+
+ /// gnash calls this to unmute audio
+ virtual void unmute() = 0;
+
+ /// Returns whether or not sound is muted.
+ //
+ /// @return true if muted, false if not
+ ///
+ virtual bool is_muted() = 0;
+
+ /// This is called by AS classes NetStream or Sound to attach callback,
so
+ /// that audio from the classes will be played through the soundhandler.
+ //
+ /// This is actually only used by the SDL sound_handler. It uses these
"auxiliary"
+ /// streamers to fetch decoded audio data to mix and send to the output
channel.
+ ///
+ /// The "aux streamer" will be called with the 'udata' pointer as first
argument,
+ /// then will be passed a buffer pointer as second argument and it's
length
+ /// as third. The callbacks should fill the given buffer if possible.
+ /// The callback should return true if wants to remain attached, false
if wants
+ /// to be detached.
+ ///
+ /// @param ptr
+ /// The pointer to the callback function
+ ///
+ /// @param udata
+ /// User data pointer, passed as first argument to the registered
callback.
+ /// WARNING: this is currently also used to *identify* the callback
for later
+ /// removal, see detach_aux_streamer. TODO: stop using the data
pointer for
+ /// identification purposes and use the callback pointer directly
instead.
+ ///
+ virtual void attach_aux_streamer(aux_streamer_ptr ptr, void* owner)
= 0;
+
+ /// This is called by AS classes NetStream or Sound to dettach
callback, so
+ /// that audio from the classes no longer will be played through the
+ /// soundhandler.
+ //
+ /// @param udata
+ /// The key identifying the auxiliary streamer.
+ /// WARNING: this need currently be the 'udata' pointer passed to
attach_aux_streamer.
+ /// TODO: get the aux_streamer_ptr as key !!
+ ///
+ virtual void detach_aux_streamer(void* udata) = 0;
+
+ sound_handler()
+ :
+ _soundsStarted(0),
+ _soundsStopped(0)
+ {}
+
+ virtual ~sound_handler() {};
+
+ /// \brief
+ /// Gets the duration in milliseconds of an event sound connected
+ /// to an AS Sound obejct.
+ //
+ /// @param sound_handle
+ /// The id of the event sound
+ ///
+ /// @return the duration of the sound in milliseconds
+ virtual unsigned int get_duration(int sound_handle) = 0;
+
+ /// \brief
+ /// Gets the playhead position in milliseconds of an event sound
connected
+ /// to an AS Sound obejct.
+ //
+ /// @param sound_handle
+ /// The id of the event sound
+ ///
+ /// @return the duration of the sound in milliseconds
+ virtual unsigned int get_position(int sound_handle) = 0;
+
+ /// Special test-fuction. Reports how many times a sound has been
started
+ size_t numSoundsStarted() const { return _soundsStarted; }
+
+ /// Special test-fuction. Reports how many times a sound has been
stopped
+ size_t numSoundsStopped() const { return _soundsStopped; }
+
+protected:
+
+ /// Special test-member. Stores count of started sounds.
+ size_t _soundsStarted;
+
+ /// Special test-member. Stores count of stopped sounds.
+ size_t _soundsStopped;
+};
+
+/*
+///
+/// Class containing information about a sound. Is created by the parser while
+/// parsing, and ownership is then transfered to sound_data. When the parser is
+/// parsing streams, it will ask the soundhandler for this to know what
properties
+/// the stream has.
+///
+class SoundInfo {
+public:
+ /// Constructor
+ //
+ /// @param format
+ /// The format of the sound. Can be MP3, ADPCM, uncompressed or
Nellymoser
+ ///
+ /// @param stero
+ /// Defines whether the sound is in stereo.
+ ///
+ /// @param sampleRate
+ /// The sample rate of the sound.
+ ///
+ /// @param sampleCount
+ /// The sample count in the sound. In soundstreams this is an average
for each frame.
+ ///
+ /// @param is16bit
+ /// Defines whether the sound is in stereo.
+ /// Defines whether the sound is in 16bit format (samplesize == 2)?
else it
+ /// is 8bit (samplesize == 1). Used for streams when decoding adpcm.
+ ///
+ SoundInfo(sound_handler::format_type format, sound_handler::format_type
orgFormat, bool stereo, uint32_t sampleRate, uint32_t sampleCount, bool is16bit)
+ : _format(format),
+ _orgFormat(orgFormat),
+ _stereo(stereo),
+ _sampleRate(sampleRate),
+ _sampleCount(sampleCount),
+ _is16bit(is16bit)
+ {
+ }
+
+ /// Returns the current format of the sound
+ ///
+ /// @return the current format of the sound
+ sound_handler::format_type getFormat() { return _format; }
+
+ /// Returns the original format of the sound
+ ///
+ /// @return the original format of the sound
+ sound_handler::format_type getOrgFormat() { return _orgFormat; }
+
+ /// Returns the stereo status of the sound
+ ///
+ /// @return the stereo status of the sound
+ bool isStereo() { return _stereo; }
+
+ /// Returns the samplerate of the sound
+ ///
+ /// @return the samplerate of the sound
+ unsigned long getSampleRate() { return _sampleRate; }
+
+ /// Returns the samplecount of the sound
+ ///
+ /// @return the samplecount of the sound
+ unsigned long getSampleCount() { return _sampleCount; }
+
+ /// Returns the 16bit status of the sound
+ ///
+ /// @return the 16bit status of the sound
+ bool is16bit() { return _is16bit; }
+
+private:
+ /// Current format of the sound (MP3, raw, etc).
+ sound_handler::format_type _format;
+
+ /// Original format of the sound (ADPCM, etc).
+ sound_handler::format_type _orgFormat;
+
+ /// The size of the undecoded data
+ unsigned long _dataSize;
+
+ /// Stereo or not
+ bool _stereo;
+
+ /// Sample rate, one of 5512, 11025, 22050, 44100
+ uint32_t _sampleRate;
+
+ /// Number of samples
+ uint32_t _sampleCount;
+
+ /// Is the audio in 16bit format (samplesize == 2)? else it
+ /// is 8bit (samplesize == 1). Used for streams when decoding adpcm.
+ bool _is16bit;
+};*/
+
+// TODO: move to appropriate specific sound handlers
+DSOEXPORT sound_handler* create_sound_handler_sdl();
+DSOEXPORT sound_handler* create_sound_handler_gst();
+DSOEXPORT sound_handler* create_sound_handler_test();
+
+
+
+} // namespace gnash
+
+#endif // SOUND_HANDLER_H
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
Index: libmedia/gst/VideoDecoderGst.cpp
===================================================================
RCS file: libmedia/gst/VideoDecoderGst.cpp
diff -N libmedia/gst/VideoDecoderGst.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/VideoDecoderGst.cpp 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,266 @@
+//
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id: VideoDecoderGst.cpp,v 1.1 2007/09/27 23:59:54 tgc Exp $
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef SOUND_GST
+
+#include "VideoDecoderGst.h"
+
+namespace gnash {
+
+VideoDecoderGst::VideoDecoderGst() :
+ pipeline(NULL),
+ input(NULL),
+ inputcaps(NULL),
+ videocaps(NULL),
+ output(NULL),
+ decoder(NULL),
+ colorspace(NULL),
+ decodedFrame(NULL),
+ stop(false)
+
+{
+}
+
+VideoDecoderGst::~VideoDecoderGst()
+{
+
+ if (pipeline) {
+ stop = true;
+ delete input_lock;
+ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (pipeline));
+ }
+}
+
+bool
+VideoDecoderGst::setup(int widthi, int heighti, int deblockingi, bool
smoothingi, videoCodecType formati, int outputFormati)
+{
+ // Save video attributes
+ width = widthi;
+ height = heighti;
+ deblocking = deblockingi;
+ smoothing = smoothingi;
+ format = formati;
+ outputFormat = outputFormati;
+
+ // For now only H263/SVQ3, VP6 and screenvideo1 is supported
+ if (format != VIDEO_CODEC_H263 && format != VIDEO_CODEC_VP6 && format
!= VIDEO_CODEC_SCREENVIDEO) return false;
+
+ // init GStreamer
+ gst_init (NULL, NULL);
+
+ // setup the pipeline
+ pipeline = gst_pipeline_new (NULL);
+
+ // Setup the pipeline elements
+
+ // setup fake source
+ input = gst_element_factory_make ("fakesrc", NULL);
+ g_object_set (G_OBJECT (input), "sizetype", 3, /*"can-activate-pull",
FALSE,*/ "signal-handoffs", TRUE, NULL);
+ // Setup the callback
+ g_signal_connect (input, "handoff", G_CALLBACK
(VideoDecoderGst::callback_handoff), this);
+
+ // Setup the input capsfilter
+ inputcaps = gst_element_factory_make ("capsfilter", NULL);
+ GstCaps* caps = NULL;
+ if (format == VIDEO_CODEC_H263) {
+ caps = gst_caps_new_simple ("video/x-flash-video",
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ "flvversion", G_TYPE_INT, 1,
+ NULL);
+ } else if (format == VIDEO_CODEC_VP6) {
+ caps = gst_caps_new_simple ("video/x-vp6-flash",
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ NULL);
+ } else if (format == VIDEO_CODEC_SCREENVIDEO) {
+ caps = gst_caps_new_simple ("video/x-flash-screen",
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, 25, 1,
+ NULL);
+ }
+
+ if ( caps )
+ {
+ g_object_set (G_OBJECT (inputcaps), "caps", caps, NULL);
+ gst_caps_unref (caps);
+#ifndef NDEBUG
+ caps = NULL; // to check it is not null on next use ...
+#endif
+ }
+ else
+ {
+ log_error("Unknown codec format %d", format);
+ }
+
+ // Setup the capsfilter which demands either YUV or RGB videoframe
format
+ videocaps = gst_element_factory_make ("capsfilter", NULL);
+ caps = gst_caps_new_simple ("video/x-raw-rgb", NULL);
+
+ assert(caps); // ok, this is a silly assertion *now*, but as long as
+ // the code is implemented with such long function bodies
+ // a day will come in which someone will change something
+ // a few screefulls above and the assertion would make
+ // sense (maybe boost compile-time assertions could help
+ // in this reguard).
+
+ g_object_set (G_OBJECT (videocaps), "caps", caps, NULL);
+ gst_caps_unref (caps);
+
+ // setup the videosink with callback
+ output = gst_element_factory_make ("fakesink", NULL);
+ g_object_set (G_OBJECT (output), "signal-handoffs", TRUE, NULL);
+ g_signal_connect (output, "handoff", G_CALLBACK
(VideoDecoderGst::callback_output), this);
+
+ // setup the video colorspaceconverter converter
+ colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
+
+ // Find the decoder, use auto plugin loader? use plugin-downloader?
+ if (format == VIDEO_CODEC_H263) {
+ decoder = gst_element_factory_make ("ffdec_flv", NULL);
+ } else if (format == VIDEO_CODEC_VP6) {
+ decoder = gst_element_factory_make ("ffdec_vp6f", NULL);
+ } else if (format == VIDEO_CODEC_SCREENVIDEO) {
+ decoder = gst_element_factory_make ("ffdec_flashsv", NULL);
+ } else {
+ gnash::log_error("Unsupported embedded video format");
+ return false;
+ }
+
+ if (!pipeline || !input || !inputcaps || !videocaps || !output ||
!colorspace) {
+ gnash::log_error("Creation of Gstreamer baisc elements failed,
is your Gstreamer installation complete?");
+ return false;
+ }
+
+ if (!decoder) {
+ gnash::log_error("Creation of decoder element failed, do you
have gstreamer-0.10-ffmpeg installed?");
+ return false;
+ }
+
+ // Put the elemets in the pipeline and link them
+ gst_bin_add_many (GST_BIN (pipeline), input, inputcaps, decoder,
colorspace, videocaps, output, NULL);
+
+ // link the elements
+ gst_element_link_many(input, inputcaps, decoder, colorspace, videocaps,
output, NULL);
+
+ // This make callback_handoff wait for data
+ input_lock = new boost::mutex::scoped_lock(input_mutex);
+
+ // This make decodeFrame wait for data
+ output_lock = new boost::mutex::scoped_lock(output_mutex);
+
+ // Determine required buffer size and allocate buffer
+ decodedFrame.reset(new image::rgb(width, height));
+
+ // Start "playing"
+ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
+
+ return true;
+}
+
+
+// gnash calls this when it wants you to decode the given videoframe
+std::auto_ptr<image::image_base>
+VideoDecoderGst::decodeToImage(uint8_t* data, uint32_t size)
+{
+
+ std::auto_ptr<image::image_base> ret_image;
+
+ ret_image.reset(new image::rgb(width, height));
+
+ // If there is nothing to decode in the new frame
+ // we just return the lastest.
+ if (data == NULL || size == 0 || !decoder)
+ {
+ // If we never decoded any frame return a NULL
+ // auto pointer ..
+ if ( ! decodedFrame.get() )
+ {
+ ret_image.reset(NULL);
+ return ret_image;
+ }
+
+ // return decodedFrame->clone() ?
+ ret_image->update(*decodedFrame);
+ return ret_image;
+ }
+
+ frame = data;
+ frameSize = size;
+
+ delete input_lock;
+
+ output_lock = new boost::mutex::scoped_lock(output_mutex);
+
+ // If we never decoded any frame return a NULL
+ // auto pointer ..
+ if ( ! decodedFrame.get() )
+ {
+ ret_image.reset(NULL);
+ return ret_image;
+ }
+
+ // return decodedFrame->clone() ?
+ ret_image->update(*decodedFrame);
+ return ret_image;
+}
+
+// The callback function which refills the buffer with data
+void
+VideoDecoderGst::callback_handoff (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data)
+{
+ VideoDecoderGst* decoder = static_cast<VideoDecoderGst*>(user_data);
+
+ if (decoder->stop) return;
+
+ decoder->input_lock = new
boost::mutex::scoped_lock(decoder->input_mutex);
+
+ GST_BUFFER_SIZE(buffer) = decoder->frameSize;
+
+ GST_BUFFER_DATA(buffer) = decoder->frame;
+}
+
+// The callback function which passes the decoded video frame
+void
+VideoDecoderGst::callback_output (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data)
+{
+ VideoDecoderGst* decoder = static_cast<VideoDecoderGst*>(user_data);
+
+ if (decoder->stop) return;
+
+ if (decoder->decodedFrame.get())
+ {
+ decoder->decodedFrame->update(GST_BUFFER_DATA(buffer));
+ }
+
+ delete decoder->output_lock;
+
+}
+
+} // end of gnash namespace
+
+#endif // SOUND_GST
Index: libmedia/gst/VideoDecoderGst.h
===================================================================
RCS file: libmedia/gst/VideoDecoderGst.h
diff -N libmedia/gst/VideoDecoderGst.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/VideoDecoderGst.h 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,103 @@
+// VideoDecoderGst.h: Video decoding using the FFMPEG library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __VIDEODECODERGST_H__
+#define __VIDEODECODERGST_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "log.h"
+#include "VideoDecoder.h"
+
+#include <gst/gst.h>
+#include "image.h"
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+
+namespace gnash {
+
+
+class VideoDecoderGst : public VideoDecoder {
+
+public:
+ VideoDecoderGst();
+ ~VideoDecoderGst();
+
+ bool setup(
+ int /*width*/,
+ int /*height*/,
+ int /*deblocking*/,
+ bool /*smoothing*/,
+ videoCodecType /*format*/, // should this argument be of
codecType type ?
+ int /*outputFormat*/);
+
+// uint8_t* decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize);
+
+ std::auto_ptr<image::image_base> decodeToImage(uint8_t* /*input*/,
uint32_t /*inputSize*/);
+
+ static void callback_handoff (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data);
+ static void callback_output (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data);
+private:
+
+ // gstreamer pipeline objects
+
+ /// the main bin containing the elements
+ GstElement *pipeline;
+
+ /// Gstreamer objects
+ GstElement *input;
+ GstElement *inputcaps;
+ GstElement *videocaps;
+ GstElement *output;
+ GstElement *decoder;
+ GstElement *colorspace;
+
+ /// mutexes and locks used to handle input and output.
+ boost::mutex input_mutex;
+ boost::mutex output_mutex;
+ boost::mutex::scoped_lock* input_lock;
+ boost::mutex::scoped_lock* output_lock;
+
+ /// Info from the video tag header. Might be usefull...
+ uint32_t width;
+ uint32_t height;
+ int deblocking;
+ bool smoothing;
+ videoCodecType format;
+ int outputFormat;
+
+ /// Input data and size for current frame
+ uint8_t* frame;
+ int frameSize;
+
+ /// Last decoded frame
+ std::auto_ptr<image::image_base> decodedFrame;
+
+ /// If we should stop this will be true
+ volatile bool stop;
+
+};
+
+} // gnash namespace
+
+#endif // __VIDEODECODERGST_H__
Index: libmedia/gst/gstappbuffer.c
===================================================================
RCS file: libmedia/gst/gstappbuffer.c
diff -N libmedia/gst/gstappbuffer.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstappbuffer.c 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,108 @@
+/* GStreamer
+ * Copyright (C) 2007 David Schleef <address@hidden>
+ *
+ * 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 <gst/base/gstpushsrc.h>
+
+#include <string.h>
+
+#include "gstappbuffer.h"
+
+static void gst_app_buffer_init (GstAppBuffer * buffer, gpointer g_class);
+static void gst_app_buffer_class_init (gpointer g_class, gpointer class_data);
+static void gst_app_buffer_finalize (GstAppBuffer * buffer);
+
+static GstBufferClass *parent_class;
+
+GType
+gst_app_buffer_get_type (void)
+{
+ static GType _gst_app_buffer_type;
+
+ if (G_UNLIKELY (_gst_app_buffer_type == 0)) {
+ static const GTypeInfo app_buffer_info = {
+ sizeof (GstBufferClass),
+ NULL,
+ NULL,
+ gst_app_buffer_class_init,
+ NULL,
+ NULL,
+ sizeof (GstAppBuffer),
+ 0,
+ (GInstanceInitFunc) gst_app_buffer_init,
+ NULL
+ };
+ _gst_app_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
+ "GstAppBuffer", &app_buffer_info, 0);
+ }
+ return _gst_app_buffer_type;
+}
+
+static void
+gst_app_buffer_init (GstAppBuffer * buffer, gpointer g_class)
+{
+ UNUSEDPAR(buffer);
+ UNUSEDPAR(g_class);
+}
+
+static void
+gst_app_buffer_class_init (gpointer g_class, gpointer class_data)
+{
+ UNUSEDPAR(class_data);
+ GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+ mini_object_class->finalize =
+ (GstMiniObjectFinalizeFunction) gst_app_buffer_finalize;
+
+ parent_class = g_type_class_peek_parent (g_class);
+}
+
+static void
+gst_app_buffer_finalize (GstAppBuffer * buffer)
+{
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (GST_IS_APP_BUFFER (buffer));
+
+ if (buffer->finalize) {
+ buffer->finalize (buffer->priv);
+ }
+
+ GST_MINI_OBJECT_CLASS (parent_class)->finalize (GST_MINI_OBJECT (buffer));
+}
+
+GstBuffer *
+gst_app_buffer_new (void *data, int length,
+ GstAppBufferFinalizeFunc finalize, void *priv)
+{
+ GstAppBuffer *buffer;
+
+ buffer = (GstAppBuffer *) gst_mini_object_new (GST_TYPE_APP_BUFFER);
+
+ GST_BUFFER_DATA (buffer) = data;
+ GST_BUFFER_SIZE (buffer) = length;
+
+ buffer->finalize = finalize;
+ buffer->priv = priv;
+
+ return GST_BUFFER (buffer);
+}
Index: libmedia/gst/gstappbuffer.h
===================================================================
RCS file: libmedia/gst/gstappbuffer.h
diff -N libmedia/gst/gstappbuffer.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstappbuffer.h 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) 2007 David Schleef <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_APP_BUFFER_H_
+#define _GST_APP_BUFFER_H_
+
+#include <gst/gst.h>
+
+#define UNUSEDPAR(x) { x = x; }
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_APP_BUFFER \
+ (gst_app_buffer_get_type())
+#define GST_APP_BUFFER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APP_BUFFER,GstAppBuffer))
+#define GST_APP_BUFFER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APP_BUFFER,GstAppBufferClass))
+#define GST_IS_APP_BUFFER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APP_BUFFER))
+#define GST_IS_APP_BUFFER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APP_BUFFER))
+
+typedef struct _GstAppBuffer GstAppBuffer;
+typedef struct _GstAppBufferClass GstAppBufferClass;
+typedef void (*GstAppBufferFinalizeFunc) (void *priv);
+
+struct _GstAppBuffer
+{
+ GstBuffer buffer;
+
+ /*< private >*/
+ GstAppBufferFinalizeFunc finalize;
+ void *priv;
+};
+
+struct _GstAppBufferClass
+{
+ GstBufferClass buffer_class;
+};
+
+GType gst_app_buffer_get_type(void);
+
+GstBuffer *gst_app_buffer_new (void *data, int length,
+ GstAppBufferFinalizeFunc finalize, void *priv);
+
+G_END_DECLS
+
+#endif
+
Index: libmedia/gst/gstappsink.c
===================================================================
RCS file: libmedia/gst/gstappsink.c
diff -N libmedia/gst/gstappsink.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstappsink.c 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,273 @@
+/* GStreamer
+ * Copyright (C) 2007 David Schleef <address@hidden>
+ *
+ * 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 <gst/base/gstbasesink.h>
+
+#include <string.h>
+
+#include "gstappsink.h"
+
+
+GST_DEBUG_CATEGORY (app_sink_debug);
+#define GST_CAT_DEFAULT app_sink_debug
+
+static const GstElementDetails app_sink_details =
+GST_ELEMENT_DETAILS ("AppSink",
+ "FIXME",
+ "FIXME",
+ "autogenerated by makefilter");
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_app_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static void gst_app_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_app_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_app_sink_dispose (GObject * object);
+static gboolean gst_app_sink_start (GstBaseSink * psink);
+static gboolean gst_app_sink_stop (GstBaseSink * psink);
+static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
+static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
+ GstBuffer * buffer);
+
+GST_BOILERPLATE (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK);
+
+static void
+gst_app_sink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ //GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
+
+ GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
+
+ gst_element_class_set_details (element_class, &app_sink_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_app_sink_template));
+
+}
+
+static void
+gst_app_sink_class_init (GstAppSinkClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
+
+ gobject_class->set_property = gst_app_sink_set_property;
+ gobject_class->get_property = gst_app_sink_get_property;
+ gobject_class->dispose = gst_app_sink_dispose;
+
+ basesink_class->start = gst_app_sink_start;
+ basesink_class->stop = gst_app_sink_stop;
+ basesink_class->event = gst_app_sink_event;
+ basesink_class->render = gst_app_sink_render;
+}
+
+static void
+gst_app_sink_dispose (GObject * obj)
+{
+ GstAppSink *appsink = GST_APP_SINK (obj);
+
+ if (appsink->caps) {
+ gst_caps_unref (appsink->caps);
+ appsink->caps = NULL;
+ }
+ if (appsink->mutex) {
+ g_mutex_free (appsink->mutex);
+ appsink->mutex = NULL;
+ }
+ if (appsink->cond) {
+ g_cond_free (appsink->cond);
+ appsink->cond = NULL;
+ }
+ if (appsink->queue) {
+ g_queue_free (appsink->queue);
+ appsink->queue = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+gst_app_sink_init (GstAppSink * appsink, GstAppSinkClass * klass)
+{
+ UNUSEDPAR(klass);
+ appsink->mutex = g_mutex_new ();
+ appsink->cond = g_cond_new ();
+ appsink->queue = g_queue_new ();
+}
+
+static void
+gst_app_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ UNUSEDPAR(value);
+ GstAppSink *appsink = GST_APP_SINK (object);
+
+ GST_OBJECT_LOCK (appsink);
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (appsink);
+}
+
+static void
+gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ UNUSEDPAR(value);
+ GstAppSink *appsink = GST_APP_SINK (object);
+
+ GST_OBJECT_LOCK (appsink);
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (appsink);
+}
+
+static gboolean
+gst_app_sink_start (GstBaseSink * psink)
+{
+ GstAppSink *appsink = GST_APP_SINK (psink);
+
+ appsink->end_of_stream = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_app_sink_stop (GstBaseSink * psink)
+{
+ UNUSEDPAR(psink);
+ //GstAppSink *appsink = GST_APP_SINK(psink);
+
+ return TRUE;
+}
+
+static gboolean
+gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
+{
+ GstAppSink *appsink = GST_APP_SINK (sink);
+
+ switch (event->type) {
+ case GST_EVENT_EOS:
+ appsink->end_of_stream = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ gst_object_unref (sink);
+ return FALSE;
+}
+
+static GstFlowReturn
+gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
+{
+ GstAppSink *appsink = GST_APP_SINK (psink);
+
+ g_mutex_lock (appsink->mutex);
+ g_queue_push_tail (appsink->queue, gst_buffer_ref (buffer));
+ g_cond_signal (appsink->cond);
+ g_mutex_unlock (appsink->mutex);
+
+ return GST_FLOW_OK;
+}
+
+
+
+
+/* external API */
+
+/**
+ * gst_app_sink_set_caps:
+ * @appsink:
+ * @caps:
+ *
+ * Set the capabilities on the appsink element. This function takes
+ * ownership of the caps structure.
+ */
+void
+gst_app_sink_set_caps (GstAppSink * appsink, GstCaps * caps)
+{
+ g_return_if_fail (appsink != NULL);
+ g_return_if_fail (GST_IS_APP_SINK (appsink));
+
+ gst_caps_replace (&appsink->caps, caps);
+}
+
+gboolean
+gst_app_sink_end_of_stream (GstAppSink * appsink)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (appsink != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE);
+
+ g_mutex_lock (appsink->mutex);
+ if (appsink->end_of_stream && g_queue_is_empty (appsink->queue)) {
+ ret = TRUE;
+ } else {
+ ret = FALSE;
+ }
+ g_mutex_unlock (appsink->mutex);
+
+ return ret;
+}
+
+GstBuffer *
+gst_app_sink_pull_buffer (GstAppSink * appsink)
+{
+ GstBuffer *buf = NULL;
+
+ g_return_val_if_fail (appsink != NULL, NULL);
+ g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
+
+ g_mutex_lock (appsink->mutex);
+ while (g_queue_is_empty (appsink->queue)) {
+ if (appsink->end_of_stream)
+ goto out;
+
+ g_cond_wait (appsink->cond, appsink->mutex);
+ }
+ buf = g_queue_pop_head (appsink->queue);
+out:
+ g_mutex_unlock (appsink->mutex);
+
+ return buf;
+}
Index: libmedia/gst/gstappsink.h
===================================================================
RCS file: libmedia/gst/gstappsink.h
diff -N libmedia/gst/gstappsink.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstappsink.h 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,73 @@
+/* GStreamer
+ * Copyright (C) 2007 David Schleef <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_APP_SINK_H_
+#define _GST_APP_SINK_H_
+
+#define UNUSEDPAR(x) { x = x; }
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_APP_SINK \
+ (gst_app_sink_get_type())
+#define GST_APP_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APP_SINK,GstAppSink))
+#define GST_APP_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APP_SINK,GstAppSinkClass))
+#define GST_IS_APP_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APP_SINK))
+#define GST_IS_APP_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APP_SINK))
+
+typedef struct _GstAppSink GstAppSink;
+typedef struct _GstAppSinkClass GstAppSinkClass;
+
+struct _GstAppSink
+{
+ GstBaseSink basesink;
+
+ /*< private >*/
+ GstCaps *caps;
+
+ GCond *cond;
+ GMutex *mutex;
+ GQueue *queue;
+ gboolean end_of_stream;
+};
+
+struct _GstAppSinkClass
+{
+ GstBaseSinkClass basesink_class;
+};
+
+GType gst_app_sink_get_type(void);
+
+GST_DEBUG_CATEGORY_EXTERN (app_sink_debug);
+
+void gst_app_sink_set_caps (GstAppSink *appsink, GstCaps *caps);
+gboolean gst_app_sink_end_of_stream (GstAppSink *appsink);
+GstBuffer *gst_app_sink_pull_buffer (GstAppSink *appsink);
+
+G_END_DECLS
+
+#endif
+
Index: libmedia/gst/gstappsrc.c
===================================================================
RCS file: libmedia/gst/gstappsrc.c
diff -N libmedia/gst/gstappsrc.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstappsrc.c 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,323 @@
+/* GStreamer
+ * Copyright (C) 2007 David Schleef <address@hidden>
+ *
+ * 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 <gst/base/gstpushsrc.h>
+
+#include <string.h>
+
+#include "gstappsrc.h"
+
+
+GST_DEBUG_CATEGORY (app_src_debug);
+#define GST_CAT_DEFAULT app_src_debug
+
+static const GstElementDetails app_src_details = GST_ELEMENT_DETAILS ("AppSrc",
+ "FIXME",
+ "FIXME",
+ "autogenerated by makefilter");
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_app_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static void gst_app_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_app_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_app_src_dispose (GObject * object);
+static GstFlowReturn gst_app_src_create (GstPushSrc * psrc, GstBuffer ** buf);
+static gboolean gst_app_src_start (GstBaseSrc * psrc);
+static gboolean gst_app_src_stop (GstBaseSrc * psrc);
+static gboolean gst_app_src_unlock (GstBaseSrc * psrc);
+
+GST_BOILERPLATE (GstAppSrc, gst_app_src, GstPushSrc, GST_TYPE_PUSH_SRC);
+
+static void
+gst_app_src_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ //GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
+
+ GST_DEBUG_CATEGORY_INIT (app_src_debug, "appsrc", 0, "appsrc element");
+
+ gst_element_class_set_details (element_class, &app_src_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_app_src_template));
+
+}
+
+static void
+gst_app_src_class_init (GstAppSrcClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstPushSrcClass *pushsrc_class = (GstPushSrcClass *) klass;
+ GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass;
+
+ gobject_class->set_property = gst_app_src_set_property;
+ gobject_class->get_property = gst_app_src_get_property;
+ gobject_class->dispose = gst_app_src_dispose;
+
+ pushsrc_class->create = gst_app_src_create;
+ basesrc_class->start = gst_app_src_start;
+ basesrc_class->stop = gst_app_src_stop;
+ basesrc_class->unlock = gst_app_src_unlock;
+}
+
+static void
+gst_app_src_dispose (GObject * obj)
+{
+ GstAppSrc *appsrc = GST_APP_SRC (obj);
+
+ if (appsrc->caps) {
+ gst_caps_unref (appsrc->caps);
+ appsrc->caps = NULL;
+ }
+ if (appsrc->mutex) {
+ g_mutex_free (appsrc->mutex);
+ appsrc->mutex = NULL;
+ }
+ if (appsrc->cond) {
+ g_cond_free (appsrc->cond);
+ appsrc->cond = NULL;
+ }
+ if (appsrc->queue) {
+ g_queue_free (appsrc->queue);
+ appsrc->queue = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+gst_app_src_init (GstAppSrc * appsrc, GstAppSrcClass * klass)
+{
+ UNUSEDPAR(klass);
+ appsrc->mutex = g_mutex_new ();
+ appsrc->cond = g_cond_new ();
+ appsrc->queue = g_queue_new ();
+}
+
+static void
+gst_app_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ UNUSEDPAR(value);
+ GstAppSrc *appsrc = GST_APP_SRC (object);
+
+ GST_OBJECT_LOCK (appsrc);
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (appsrc);
+}
+
+static void
+gst_app_src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ UNUSEDPAR(value);
+ GstAppSrc *appsrc = GST_APP_SRC (object);
+
+ GST_OBJECT_LOCK (appsrc);
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (appsrc);
+}
+
+static gboolean
+gst_app_src_start (GstBaseSrc * psrc)
+{
+ GstAppSrc *appsrc = GST_APP_SRC (psrc);
+
+ appsrc->unlock = FALSE;
+
+#if 0
+ /* FIXME: I don't know if this makes sense */
+ appsrc->end_of_stream = FALSE;
+ appsrc->flush = FALSE;
+#endif
+
+ return TRUE;
+}
+
+static gboolean
+gst_app_src_stop (GstBaseSrc * psrc)
+{
+ UNUSEDPAR(psrc);
+ //GstAppSrc *appsrc = GST_APP_SRC(psrc);
+
+ return TRUE;
+}
+
+static gboolean
+gst_app_src_unlock (GstBaseSrc * psrc)
+{
+ GstAppSrc *appsrc = GST_APP_SRC (psrc);
+
+ appsrc->unlock = TRUE;
+ g_cond_signal (appsrc->cond);
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_app_src_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+ GstAppSrc *appsrc = GST_APP_SRC (psrc);
+ int ret = GST_FLOW_ERROR;
+
+ g_mutex_lock (appsrc->mutex);
+
+ while (1) {
+ if (appsrc->unlock) {
+ ret = GST_FLOW_WRONG_STATE;
+ break;
+ }
+ if (!g_queue_is_empty (appsrc->queue)) {
+ *buf = g_queue_pop_head (appsrc->queue);
+
+ gst_buffer_set_caps (*buf, appsrc->caps);
+
+ ret = GST_FLOW_OK;
+ break;
+ }
+ if (appsrc->end_of_stream) {
+ appsrc->end_of_stream = FALSE;
+ ret = GST_FLOW_UNEXPECTED;
+ break;
+ }
+ if (appsrc->flush) {
+ appsrc->flush = FALSE;
+ /* FIXME: I don't really know how to do this */
+ break;
+ }
+ g_cond_wait (appsrc->cond, appsrc->mutex);
+ }
+
+ g_mutex_unlock (appsrc->mutex);
+
+ return ret;
+}
+
+
+/* external API */
+
+/**
+ * gst_app_src_push_buffer:
+ * @appsrc:
+ * @buffer:
+ *
+ * Adds a buffer to the queue of buffers that the appsrc element will
+ * push to its source pad. This function takes ownership of the buffer.
+ */
+void
+gst_app_src_push_buffer (GstAppSrc * appsrc, GstBuffer * buffer)
+{
+ g_return_if_fail (appsrc);
+ g_return_if_fail (GST_IS_APP_SRC (appsrc));
+
+ g_mutex_lock (appsrc->mutex);
+
+ g_queue_push_tail (appsrc->queue, buffer);
+
+ g_cond_signal (appsrc->cond);
+ g_mutex_unlock (appsrc->mutex);
+}
+
+/**
+ * gst_app_src_set_caps:
+ * @appsrc:
+ * @caps:
+ *
+ * Set the capabilities on the appsrc element. This function takes
+ * ownership of the caps structure.
+ */
+void
+gst_app_src_set_caps (GstAppSrc * appsrc, GstCaps * caps)
+{
+ g_return_if_fail (appsrc);
+ g_return_if_fail (GST_IS_APP_SRC (appsrc));
+
+ gst_caps_replace (&appsrc->caps, caps);
+}
+
+/**
+ * gst_app_src_flush:
+ * @appsrc:
+ *
+ * Flushes all queued buffers from the appsrc element.
+ */
+void
+gst_app_src_flush (GstAppSrc * appsrc)
+{
+ GstBuffer *buffer;
+
+ g_return_if_fail (appsrc);
+ g_return_if_fail (GST_IS_APP_SRC (appsrc));
+
+ g_mutex_lock (appsrc->mutex);
+
+ while ((buffer = g_queue_pop_head (appsrc->queue))) {
+ gst_buffer_unref (buffer);
+ }
+ appsrc->flush = TRUE;
+
+ g_cond_signal (appsrc->cond);
+ g_mutex_unlock (appsrc->mutex);
+}
+
+/**
+ * gst_app_src_end_of_stream:
+ * @appsrc:
+ *
+ * Indicates to the appsrc element that the last buffer queued in the
+ * element is the last buffer of the stream.
+ */
+void
+gst_app_src_end_of_stream (GstAppSrc * appsrc)
+{
+ g_return_if_fail (appsrc);
+ g_return_if_fail (GST_IS_APP_SRC (appsrc));
+
+ g_mutex_lock (appsrc->mutex);
+
+ appsrc->end_of_stream = TRUE;
+
+ g_cond_signal (appsrc->cond);
+ g_mutex_unlock (appsrc->mutex);
+}
Index: libmedia/gst/gstappsrc.h
===================================================================
RCS file: libmedia/gst/gstappsrc.h
diff -N libmedia/gst/gstappsrc.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstappsrc.h 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,76 @@
+/* GStreamer
+ * Copyright (C) 2007 David Schleef <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_APP_SRC_H_
+#define _GST_APP_SRC_H_
+
+#define UNUSEDPAR(x) { x = x; }
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_APP_SRC \
+ (gst_app_src_get_type())
+#define GST_APP_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APP_SRC,GstAppSrc))
+#define GST_APP_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APP_SRC,GstAppSrcClass))
+#define GST_IS_APP_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APP_SRC))
+#define GST_IS_APP_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APP_SRC))
+
+typedef struct _GstAppSrc GstAppSrc;
+typedef struct _GstAppSrcClass GstAppSrcClass;
+
+struct _GstAppSrc
+{
+ GstPushSrc pushsrc;
+
+ /*< private >*/
+ gboolean unlock;
+ GCond *cond;
+ GMutex *mutex;
+ GQueue *queue;
+ GstCaps *caps;
+ gboolean end_of_stream;
+ gboolean flush;
+};
+
+struct _GstAppSrcClass
+{
+ GstPushSrcClass pushsrc_class;
+};
+
+GType gst_app_src_get_type(void);
+
+GST_DEBUG_CATEGORY_EXTERN (app_src_debug);
+
+
+void gst_app_src_push_buffer (GstAppSrc *appsrc, GstBuffer *buffer);
+void gst_app_src_set_caps (GstAppSrc *appsrc, GstCaps *caps);
+void gst_app_src_flush (GstAppSrc *appsrc);
+void gst_app_src_end_of_stream (GstAppSrc *appsrc);
+
+G_END_DECLS
+
+#endif
+
Index: libmedia/gst/gstgnashsrc.c
===================================================================
RCS file: libmedia/gst/gstgnashsrc.c
diff -N libmedia/gst/gstgnashsrc.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstgnashsrc.c 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,328 @@
+//
+// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// Based on the filesrc and fdsrc element in Gstreamer-core.
+//
+
+/* $Id: gstgnashsrc.c,v 1.1 2007/09/27 23:59:54 tgc Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgnashsrc.h"
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+
+GST_DEBUG_CATEGORY_STATIC (gst_gnash_src_debug);
+#define GST_CAT_DEFAULT gst_gnash_src_debug
+
+static const GstElementDetails gst_gnash_src_details =
+GST_ELEMENT_DETAILS ("Gnash source",
+ "Gnash",
+ "Use callback to read from Gnash",
+ "Gnash team");
+
+/* GnashSrc signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_BLOCKSIZE 4*1024
+#define DEFAULT_DATA NULL
+#define DEFAULT_CALLBACKS NULL
+
+enum
+{
+ ARG_0,
+ ARG_DATA,
+ ARG_CALLBACKS
+};
+
+static void gst_gnash_src_finalize (GObject * object);
+
+static void gst_gnash_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gnash_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gnash_src_start (GstBaseSrc * basesrc);
+static gboolean gst_gnash_src_stop (GstBaseSrc * basesrc);
+
+static gboolean gst_gnash_src_is_seekable (GstBaseSrc * src);
+static gboolean gst_gnash_src_get_size (GstBaseSrc * src, guint64 * size);
+static GstFlowReturn gst_gnash_src_create (GstPushSrc * src, GstBuffer **
buffer);
+static gboolean gst_gnash_src_do_seek (GstBaseSrc * src, GstSegment * s);
+
+static void
+_do_init (GType gnashsrc_type)
+{
+ UNUSEDPAR(gnashsrc_type);
+/* static const GInterfaceInfo urihandler_info = {
+ gst_gnash_src_uri_handler_init,
+ NULL,
+ NULL
+ };*/
+
+ GST_DEBUG_CATEGORY_INIT (gst_gnash_src_debug, "gnashsrc", 0, "gnashsrc
element");
+}
+
+GST_BOILERPLATE_FULL (GstGnashSrc, gst_gnash_src, GstElement,
GST_TYPE_PUSH_SRC, _do_init);
+
+static void
+gst_gnash_src_base_init (gpointer g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&srctemplate));
+
+ gst_element_class_set_details (gstelement_class, &gst_gnash_src_details);
+}
+
+static void
+gst_gnash_src_class_init (GstGnashSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSrcClass *gstbasesrc_class;
+ GstPushSrcClass *gstpush_src_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstelement_class = GST_ELEMENT_CLASS (klass);
+ gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+ gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
+
+ gobject_class->set_property = gst_gnash_src_set_property;
+ gobject_class->get_property = gst_gnash_src_get_property;
+
+ g_object_class_install_property (gobject_class, ARG_DATA,
+ g_param_spec_pointer ("data", NULL, NULL,
(GParamFlags)G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, ARG_CALLBACKS,
+ g_param_spec_pointer ("callbacks", NULL, NULL,
(GParamFlags)G_PARAM_READWRITE));
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gnash_src_finalize);
+
+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gnash_src_start);
+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gnash_src_stop);
+ gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR
(gst_gnash_src_is_seekable);
+ gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gnash_src_get_size);
+ gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_gnash_src_do_seek);
+
+ gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_gnash_src_create);
+}
+
+static void
+gst_gnash_src_init (GstGnashSrc * src, GstGnashSrcClass * g_class)
+{
+ UNUSEDPAR(g_class);
+ src->data = NULL;
+ src->callbacks = NULL;
+ src->read_position = 0;
+}
+
+static void
+gst_gnash_src_finalize (GObject * object)
+{
+ GstGnashSrc *src;
+
+ src = GST_GNASH_SRC (object);
+
+ free (src->callbacks);
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_gnash_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstGnashSrc *src;
+
+ g_return_if_fail (GST_IS_GNASH_SRC (object));
+
+ src = GST_GNASH_SRC (object);
+
+ switch (prop_id) {
+ case ARG_DATA:
+ src->data = g_value_get_pointer (value);
+ break;
+ case ARG_CALLBACKS:
+ src->callbacks = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gnash_src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstGnashSrc *src;
+ UNUSEDPAR(value);
+ g_return_if_fail (GST_IS_GNASH_SRC (object));
+
+ src = GST_GNASH_SRC (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+//
+// Below is the functions used get make this plugin work.
+//
+
+// Used for seeking
+static gboolean
+gst_gnash_src_do_seek (GstBaseSrc * basesrc, GstSegment * seg)
+{
+
+ GstGnashSrc *src;
+ off_t res;
+ src = GST_GNASH_SRC (basesrc);
+
+ if (seg->format != GST_FORMAT_BYTES) return FALSE;
+
+ struct gnashsrc_callback *gc;
+ gc = src->callbacks;
+ res = gc->seek (src->data, seg->start, SEEK_CUR);
+ return TRUE;
+
+}
+
+// Output the next buffer
+static GstFlowReturn
+gst_gnash_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
+{
+ GstGnashSrc *src;
+ src = GST_GNASH_SRC (psrc);
+ int ret, blocksize;
+ GstBuffer *buf;
+
+ struct gnashsrc_callback *gc;
+ gc = src->callbacks;
+
+ blocksize = GST_BASE_SRC (src)->blocksize;
+ buf = gst_buffer_new_and_alloc (blocksize);
+
+ GST_LOG_OBJECT (src, "Reading %d bytes", blocksize);
+
+ ret = gc->read(src->data, (void*)GST_BUFFER_DATA(buf), blocksize);
+
+ if (G_UNLIKELY (ret < 0)) goto could_not_read;
+
+ /* other files should eos if they read 0 and more was requested */
+ if (G_UNLIKELY (ret == 0 && blocksize > 0))
+ goto eos;
+
+ blocksize = ret;
+
+ GST_BUFFER_SIZE (buf) = blocksize;
+ GST_BUFFER_OFFSET (buf) = src->read_position;
+ GST_BUFFER_OFFSET_END (buf) = src->read_position + blocksize;
+
+ *outbuf = buf;
+
+ src->read_position += blocksize;
+
+ return GST_FLOW_OK;
+
+ /* ERROR */
+could_not_read:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+eos:
+ {
+ GST_DEBUG ("non-regular file hits EOS");
+ gst_buffer_unref (buf);
+ return GST_FLOW_UNEXPECTED;
+ }
+}
+
+static gboolean
+gst_gnash_src_is_seekable (GstBaseSrc * basesrc)
+{
+ GstGnashSrc *src = GST_GNASH_SRC (basesrc);
+
+ return src->seekable;
+}
+
+// Get size of the file. Not sure how we shall handles this...
+static gboolean
+gst_gnash_src_get_size (GstBaseSrc * basesrc, guint64 * size)
+{
+ GstGnashSrc *src;
+
+ src = GST_GNASH_SRC (basesrc);
+
+ if (!src->seekable) {
+ /* If it isn't seekable, we won't know the length (but fstat will still
+ * succeed, and wrongly say our length is zero. */
+ return FALSE;
+ }
+ return FALSE;
+
+ // Since it's a streamed video file we probably don't know the length, so we
+ // tell it's 50000. Maybe we should just return FALSE?
+ *size = 500000;
+ return TRUE;
+
+}
+
+/* open the file and mmap it, necessary to go to READY state */
+static gboolean
+gst_gnash_src_start (GstBaseSrc * basesrc)
+{
+ GstGnashSrc *src = GST_GNASH_SRC (basesrc);
+
+ if (src->data == NULL || src->callbacks == NULL) {
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,(("No data or callback struct
supplied.")), (NULL));
+ return FALSE;
+ }
+
+ src->read_position = 0;
+ GST_INFO_OBJECT (src, "Ready for reading using callbacks");
+
+ // TODO: set seekable to false when real streaming
+ src->seekable = TRUE;
+
+ return TRUE;
+
+}
+
+/* stop and free */
+static gboolean
+gst_gnash_src_stop (GstBaseSrc * basesrc)
+{
+ GstGnashSrc *src = GST_GNASH_SRC (basesrc);
+ UNUSEDPAR(src);
+ return TRUE;
+}
+
Index: libmedia/gst/gstgnashsrc.h
===================================================================
RCS file: libmedia/gst/gstgnashsrc.h
diff -N libmedia/gst/gstgnashsrc.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/gstgnashsrc.h 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,81 @@
+//
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// Based on the filesrc and fdsrc element in Gstreamer-core
+//
+
+/* $Id: gstgnashsrc.h,v 1.1 2007/09/27 23:59:54 tgc Exp $ */
+
+#ifndef __GST_GNASH_SRC_H__
+#define __GST_GNASH_SRC_H__
+
+#define UNUSEDPAR(x) { x = x; }
+
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+// Struct to contain the callback functions
+struct gnashsrc_callback {
+ int (*read)(void* data, char* buf, int buf_size);
+ int (*seek)(void* data, int offset, int whence);
+};
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GNASH_SRC \
+ (gst_gnash_src_get_type())
+#define GST_GNASH_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GNASH_SRC,GstGnashSrc))
+#define GST_GNASH_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GNASH_SRC,GstGnashSrcClass))
+#define GST_IS_GNASH_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GNASH_SRC))
+#define GST_IS_GNASH_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GNASH_SRC))
+
+typedef struct _GstGnashSrc GstGnashSrc;
+typedef struct _GstGnashSrcClass GstGnashSrcClass;
+
+/**
+ * GstGnashSrc:
+ *
+ * Opaque #GstGnashSrc structure.
+ */
+struct _GstGnashSrc {
+ GstPushSrc element;
+
+ /*< private >*/
+
+ guint64 read_position; // position in the stream
+
+ gpointer data; // data passes with the callbacks
+ gpointer callbacks; // struct with the callbacks
+
+ gboolean seekable; // seekable or not
+
+};
+
+struct _GstGnashSrcClass {
+ GstPushSrcClass parent_class;
+};
+
+GType gst_gnash_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GNASH_SRC_H__ */
Index: libmedia/gst/sound_handler_gst.cpp
===================================================================
RCS file: libmedia/gst/sound_handler_gst.cpp
diff -N libmedia/gst/sound_handler_gst.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/sound_handler_gst.cpp 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,712 @@
+// sound_handler_gst.cpp: Audio output via GStreamer, for Gnash.
+//
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// Based on sound_handler_sdl.cpp by Thatcher Ulrich http://tulrich.com 2003
+// which has been donated to the Public Domain.
+
+/* $Id: sound_handler_gst.cpp,v 1.1 2007/09/27 23:59:54 tgc Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "utility.h" // for convert_raw_data
+
+// Assume people running --enable-media=gst know what they are doing
+// (HAVE_GST_GST_H seems broken atm, specifically when an older glib
+// install is around)
+//
+
+#ifdef SOUND_GST
+
+#include "sound_handler_gst.h"
+#include "gnash.h"
+#include "container.h"
+#include "log.h"
+#include "types.h" // for IF_VERBOSE_* macros
+#include <cmath>
+#include <vector>
+
+#include <gst/gst.h>
+
+#define BUFFER_SIZE 5000
+
+using namespace boost;
+
+namespace gnash {
+
+GST_sound_handler::GST_sound_handler()
+ : looping(false),
+ muted(false)
+{
+ // init gstreamer
+ gst_init(NULL, NULL);
+}
+
+GST_sound_handler::~GST_sound_handler()
+{
+
+ for (size_t i=0, e=m_sound_data.size(); i < e; ++i) {
+ stop_sound(i);
+ delete_sound(i);
+ }
+}
+
+
+int GST_sound_handler::create_sound(
+ void* data_,
+ unsigned int data_bytes,
+ std::auto_ptr<SoundInfo> sinfo)
+// Called to create a sample. We'll return a sample ID that
+// can be use for playing it.
+{
+
+ try_mutex::scoped_lock lock(_mutex);
+
+ unsigned char* data = static_cast<unsigned char*>(data_);
+
+ assert(sinfo.get());
+ sound_data *sounddata = new sound_data;
+ if (!sounddata) {
+ log_error(_("could not allocate memory for sound data"));
+ return -1;
+ }
+
+ sounddata->volume = 100;
+ sounddata->soundinfo = sinfo;
+
+ switch (sounddata->soundinfo->getFormat())
+ {
+ case AUDIO_CODEC_MP3:
+ case AUDIO_CODEC_RAW:
+ case AUDIO_CODEC_ADPCM:
+ case AUDIO_CODEC_UNCOMPRESSED:
+ case AUDIO_CODEC_NELLYMOSER:
+ case AUDIO_CODEC_NELLYMOSER_8HZ_MONO:
+ if ( data ) sounddata->append(data, data_bytes);
+ break;
+
+
+ default:
+ // Unhandled format.
+ log_error(_("Unknown sound format %d requested; gnash does not
handle it"), (int)sounddata->soundinfo->getFormat());
+ return -1; // Unhandled format, set to NULL.
+ }
+
+ m_sound_data.push_back(sounddata);
+
+ return m_sound_data.size()-1;
+}
+
+
+// this gets called when a stream gets more data
+long GST_sound_handler::fill_stream_data(unsigned char* data, unsigned int
data_bytes, unsigned int /*sample_count*/, int handle_id)
+{
+ try_mutex::scoped_lock lock(_mutex);
+
+ // @@ does a negative handle_id have any meaning ?
+ // should we change it to unsigned instead ?
+ if (handle_id >= 0 && (unsigned int) handle_id < m_sound_data.size())
+ {
+ sound_data* sounddata = m_sound_data[handle_id];
+
+ long startSize = sounddata->dataSize();
+
+ sounddata->append(data, data_bytes);
+
+ // If playback has already started, we also update the active
sounds
+ for (size_t i=0, e=sounddata->m_gst_elements.size(); i < e;
++i) {
+ gst_elements* sound = sounddata->m_gst_elements[i];
+ sound->data_size = sounddata->dataSize();
+ sound->set_data(sounddata->data());
+ }
+
+ return startSize;
+ }
+ else
+ {
+ delete [] data;
+ return 0;
+ }
+}
+
+// This stops sounds when they are done playing
+static gboolean sound_killer (gpointer user_data)
+{
+ gst_elements *gstelements = static_cast<gst_elements*>(user_data);
+ gst_element_set_state (GST_ELEMENT (gstelements->pipeline),
GST_STATE_NULL);
+ return false;
+}
+
+// The callback function which refills the buffer with data
+void GST_sound_handler::callback_handoff (GstElement * /*c*/, GstBuffer
*buffer, GstPad* /*pad*/, gpointer user_data)
+{
+ gst_elements *gstelements = static_cast<gst_elements*>(user_data);
+
+ try_mutex::scoped_try_lock lock(gstelements->handler->_mutex);
+
+ // If we couldn't obtain a lock return to avoid a deadlock
+ if (!lock.locked()) {
+
+ // We return nothing in this case to avoid noise being decoded
and played
+ if (GST_BUFFER_SIZE(buffer) != 0 && GST_BUFFER_DATA(buffer)) {
+ GST_BUFFER_DATA(buffer) = 0;
+ GST_BUFFER_SIZE(buffer) = 0;
+ }
+ return;
+ }
+
+ // First callback or after a couldn't-get-lock-return
+ if (GST_BUFFER_SIZE(buffer) == 0) {
+ if (gstelements->data_size > BUFFER_SIZE) {
+ GST_BUFFER_SIZE(buffer) = BUFFER_SIZE;
+ } else {
+ GST_BUFFER_SIZE(buffer) = gstelements->data_size;
+ }
+
+ // Reallocate the required memory.
+ guint8* tmp_buf = new guint8[GST_BUFFER_SIZE(buffer)];
+ memcpy(tmp_buf, GST_BUFFER_DATA(buffer), sizeof(buffer));
+
+ delete [] GST_BUFFER_DATA(buffer);
+ GST_BUFFER_DATA(buffer) = tmp_buf;
+ }
+
+ // All the data has been given to the pipeline, so now we need to stop
+ // the pipeline. g_idle_add() makes sure sound_killer is called soon.
+ if (gstelements->position > gstelements->data_size) {
+ g_idle_add(sound_killer, user_data);
+ GST_BUFFER_SIZE(buffer) = 0;
+ GST_BUFFER_DATA(buffer) = 0;
+ return;
+ }
+
+ const guint8* data_pos =
gstelements->get_data_ptr(gstelements->position);
+
+ // Last callback - the last re-fill
+ if (gstelements->position+BUFFER_SIZE > gstelements->data_size) {
+
+ unsigned int chunk_size =
gstelements->data_size-gstelements->position;
+ // Check if we should loop. If loop_count is 0 we have we just
+ // played the sound for the last (and perhaps first) time.
+ // If loop_count is anything else we continue to loop.
+ if (gstelements->loop_count == 0) {
+ GST_BUFFER_SIZE(buffer) = chunk_size;
+ memcpy(GST_BUFFER_DATA(buffer), data_pos, chunk_size);
+ gstelements->position += BUFFER_SIZE;
+
+ gst_element_set_state (GST_ELEMENT
(gstelements->input), GST_STATE_PAUSED);
+
+ } else {
+ // Copy what's left of the data, and then fill the rest
with "new" data.
+ memcpy(GST_BUFFER_DATA(buffer), data_pos, chunk_size);
+ memcpy(GST_BUFFER_DATA(buffer) + chunk_size,
gstelements->get_data_ptr(0), GST_BUFFER_SIZE(buffer)- chunk_size);
+ gstelements->position = GST_BUFFER_SIZE(buffer) -
chunk_size;
+ gstelements->loop_count--;
+
+ }
+
+ return;
+
+ }
+
+ // Standard re-fill
+ memcpy(GST_BUFFER_DATA(buffer), data_pos, BUFFER_SIZE);
+ gstelements->position += BUFFER_SIZE;
+
+}
+
+
+void GST_sound_handler::play_sound(int sound_handle, int loop_count, int
/*offset*/, long start_position, const std::vector<sound_envelope>*
/*envelopes*/)
+// Play the index'd sample.
+{
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists, or if audio is muted
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size() || muted)
+ {
+ // Invalid handle, or audio is muted.
+ return;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ // If this is called from a streamsoundblocktag, we only start if this
+ // sound isn't already playing.
+ if (start_position > 0 && sounddata->m_gst_elements.size() > 0) {
+ return;
+ }
+ // Make sure sound actually got some data
+ if (sounddata->dataSize() < 1) {
+ IF_VERBOSE_MALFORMED_SWF(
+ log_swferror(_("Trying to play sound with size 0"));
+ );
+ return;
+ }
+
+ // Make a "gst_elements" for this sound which is latter placed on the
vector of instances of this sound being played
+ gst_elements* gst_element = new gst_elements;
+ if (gst_element == NULL) {
+ log_error (_("Could not allocate memory for gst_element"));
+ return;
+ }
+
+ // Set the handler
+ gst_element->handler = this;
+
+ // Copy data-info to the "gst_elements"
+ gst_element->data_size = sounddata->dataSize();
+ gst_element->set_data(sounddata->data());
+ gst_element->position = start_position;
+
+ // Set number of loop we should do. -1 is infinte loop, 0 plays it
once, 1 twice etc.
+ gst_element->loop_count = loop_count;
+
+ // create main pipeline
+ gst_element->pipeline = gst_pipeline_new (NULL);
+
+ // create an audio sink - use oss, alsa or...? make a commandline
option?
+ // we first try atudetect, then alsa, then oss, then esd, then...?
+#if !defined(__NetBSD__)
+ gst_element->audiosink = gst_element_factory_make ("autoaudiosink",
NULL);
+ if (!gst_element->audiosink) gst_element->audiosink =
gst_element_factory_make ("alsasink", NULL);
+ if (!gst_element->audiosink) gst_element->audiosink =
gst_element_factory_make ("osssink", NULL);
+#endif
+ if (!gst_element->audiosink) gst_element->audiosink =
gst_element_factory_make ("esdsink", NULL);
+
+ // Check if the creation of the gstreamer pipeline, adder and audiosink
was a succes
+ if (!gst_element->pipeline) {
+ log_error(_("The gstreamer pipeline element could not be
created"));
+ }
+ if (!gst_element->audiosink) {
+ log_error(_("The gstreamer audiosink element could not be
created"));
+ }
+
+ // link adder and output to bin
+ gst_bin_add (GST_BIN (gst_element->pipeline), gst_element->audiosink);
+
+ gst_element->bin = gst_bin_new(NULL);
+ gst_element->input = gst_element_factory_make ("fakesrc", NULL);
+ gst_element->capsfilter = gst_element_factory_make ("capsfilter", NULL);
+ gst_element->audioconvert = gst_element_factory_make ("audioconvert",
NULL);
+ gst_element->audioresample = gst_element_factory_make ("audioresample",
NULL);
+ gst_element->volume = gst_element_factory_make ("volume", NULL);
+
+ // Put the gstreamer elements in the pipeline
+ gst_bin_add_many (GST_BIN (gst_element->bin), gst_element->input,
+ gst_element->capsfilter,
+ gst_element->audioconvert,
+ gst_element->audioresample,
+ gst_element->volume, NULL);
+
+ // Test if the fakesrc, typefind and audio* elements was correctly
created
+ if (!gst_element->input
+ || !gst_element->capsfilter
+ || !gst_element->audioconvert
+ || !gst_element->audioresample) {
+
+ log_error(_("Gstreamer element for audio handling could not be
created"));
+ return;
+ }
+
+ // Create a gstreamer decoder for the chosen sound.
+
+ // Temp variables to make the code simpler and easier to read
+ audioCodecType soundFormat = sounddata->soundinfo->getFormat();
+ bool soundStereo = sounddata->soundinfo->isStereo();
+ uint32_t soundSampleRate = sounddata->soundinfo->getSampleRate();
+
+ if (soundFormat == AUDIO_CODEC_MP3) {
+
+ gst_element->decoder = gst_element_factory_make ("mad", NULL);
+ if (gst_element->decoder == NULL) {
+ gst_element->decoder = gst_element_factory_make
("flump3dec", NULL);
+ if (gst_element->decoder != NULL &&
!gst_default_registry_check_feature_version("flump3dec", 0, 10, 4))
+ {
+ static bool warned=false;
+ if ( ! warned )
+ {
+ // I keep getting these messages even
if I hear sound... too much paranoia ?
+ log_debug(_("This version of fluendos
mp3 plugin does not support flash streaming sounds, please upgrade to version
0.10.4 or higher"));
+ warned=true;
+ }
+ }
+ }
+ // Check if the element was correctly created
+ if (!gst_element->decoder) {
+ log_error(_("A gstreamer mp3-decoder element could not
be created. You probably need to install a mp3-decoder plugin like
gstreamer0.10-mad or gstreamer0.10-fluendo-mp3."));
+ return;
+ }
+ gst_bin_add (GST_BIN (gst_element->bin), gst_element->decoder);
+
+ // Set the info about the stream so that gstreamer knows what
it is.
+ GstCaps *caps = gst_caps_new_simple ("audio/mpeg",
+ "mpegversion", G_TYPE_INT, 1,
+ "layer", G_TYPE_INT, 3,
+ "rate", G_TYPE_INT, soundSampleRate,
+ "channels", G_TYPE_INT, soundStereo ? 2 : 1, NULL);
+ g_object_set (G_OBJECT (gst_element->capsfilter), "caps", caps,
NULL);
+ gst_caps_unref (caps);
+
+ // setup fake source
+ g_object_set (G_OBJECT (gst_element->input),
+ "sizetype", 2, "can-activate-pull",
FALSE, "signal-handoffs", TRUE,
+ "sizemax", BUFFER_SIZE, NULL);
+ // Setup the callback
+ gst_element->handoff_signal_id = g_signal_connect
(gst_element->input, "handoff", G_CALLBACK (callback_handoff), gst_element);
+
+ // link data, decoder, audio* and adder
+ gst_element_link_many (gst_element->input,
+ gst_element->capsfilter,
+ gst_element->decoder,
+ gst_element->audioconvert,
+ gst_element->audioresample,
+ gst_element->volume, NULL);
+
+ } else if (soundFormat == AUDIO_CODEC_ADPCM) {
+ gst_element->decoder = gst_element_factory_make
("ffdec_adpcm_swf", NULL);
+
+ // Check if the element was correctly created
+ if (!gst_element->decoder) {
+ log_error(_("A gstreamer adpcm-decoder element could
not be created. You probably need to install gst-ffmpeg."));
+ return;
+ }
+ gst_bin_add (GST_BIN (gst_element->bin), gst_element->decoder);
+
+ // Set the info about the stream so that gstreamer knows what
it is.
+ GstCaps *caps = gst_caps_new_simple ("audio/x-adpcm",
+ "rate", G_TYPE_INT, soundSampleRate,
+ "channels", G_TYPE_INT, soundStereo ? 2 : 1, NULL);
+ g_object_set (G_OBJECT (gst_element->capsfilter), "caps", caps,
NULL);
+ gst_caps_unref (caps);
+
+ // setup fake source
+ g_object_set (G_OBJECT (gst_element->input),
+ "sizetype", 2, "can-activate-pull",
FALSE, "signal-handoffs", TRUE,
+ "sizemax", BUFFER_SIZE, NULL);
+ // Setup the callback
+ gst_element->handoff_signal_id = g_signal_connect
(gst_element->input, "handoff", G_CALLBACK (callback_handoff), gst_element);
+
+ // link data, decoder, audio* and adder
+ gst_element_link_many (gst_element->input,
+ gst_element->capsfilter,
+ gst_element->decoder,
+ gst_element->audioconvert,
+ gst_element->audioresample,
+ gst_element->volume, NULL);
+
+ } else if (soundFormat == AUDIO_CODEC_NELLYMOSER_8HZ_MONO ||
soundFormat == AUDIO_CODEC_NELLYMOSER) {
+ return;
+ } else {
+
+ // Set the info about the stream so that gstreamer knows what
it is.
+ GstCaps *caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, soundSampleRate,
+ "channels", G_TYPE_INT, soundStereo ? 2 : 1,
+ "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+ "width", G_TYPE_INT, (sounddata->soundinfo->is16bit() ?
16 : 8),
+ "depth", G_TYPE_INT, 16,
+ //"signed", G_TYPE_INT, 1,
+ NULL);
+ g_object_set (G_OBJECT (gst_element->capsfilter), "caps", caps,
NULL);
+ gst_caps_unref (caps);
+
+ // setup fake source
+ g_object_set (G_OBJECT (gst_element->input),
+ "sizetype", 2, "can-activate-pull",
FALSE, "signal-handoffs", TRUE,
+ "sizemax", BUFFER_SIZE, NULL);
+ // Setup the callback
+ gst_element->handoff_signal_id = g_signal_connect
(gst_element->input, "handoff", G_CALLBACK (callback_handoff), gst_element);
+
+ // Raw native sound-data, output directly
+ gst_element_link_many (gst_element->input,
+ gst_element->capsfilter,
+ gst_element->audioconvert,
+ gst_element->audioresample,
+ gst_element->volume, NULL);
+ }
+ // Add ghostpad
+ GstPad *pad = gst_element_get_pad (gst_element->volume, "src");
+ gst_element_add_pad (gst_element->bin, gst_ghost_pad_new ("src", pad));
+ gst_object_unref (GST_OBJECT (pad));
+
+ // Add the bin to the main pipeline
+ gst_bin_add(GST_BIN (gst_element->pipeline), gst_element->bin);
+ // Link to the adder sink pad
+ GstPad *sinkpad = gst_element_get_pad (gst_element->audiosink, "sink");
+ GstPad *srcpad = gst_element_get_pad (gst_element->bin, "src");
+ gst_pad_link (srcpad, sinkpad);
+ gst_object_unref (GST_OBJECT (srcpad));
+ gst_object_unref (GST_OBJECT (sinkpad));
+
+ // Set the volume
+ g_object_set (G_OBJECT (gst_element->volume), "volume",
static_cast<double>(sounddata->volume) / 100.0, NULL);
+
+ //gst_pad_add_event_probe(pad, G_CALLBACK(event_callback), sounddata);
+
+ // Put the gst_element on the vector
+ sounddata->m_gst_elements.push_back(gst_element);
+
+ // If not already playing, start doing it
+ gst_element_set_state (GST_ELEMENT (gst_element->pipeline),
GST_STATE_PLAYING);
+
+ ++_soundsStarted;
+
+}
+
+
+void GST_sound_handler::stop_sound(int sound_handle)
+{
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ return;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ // Stop all the instances of this sound.
+ // TODO: fix the loop to use size_t instead of i
+ for (int i = sounddata->m_gst_elements.size()-1; i >= 0 ; i--)
+ {
+ gst_elements* elements = sounddata->m_gst_elements[i];
+
+ // Check if we can succesfully stop the elements
+ // playback - if not we skip cleaning this for now
+ // FIXME: what if it ain't possible to stop an element when
this is called from ~GST_sound_handler
+
+ // Disconnect signals
+ g_signal_handler_disconnect (elements->input,
elements->handoff_signal_id);
+
+ gst_element_set_state (GST_ELEMENT (elements->pipeline),
GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (elements->pipeline));
+
+ // Delete the gst_element struct
+ // @@ we're deleting the elements from the start, so half-way
of the loop we will be referring to undefined elements. Is this intended ?
--strk;
+ delete elements;
+
sounddata->m_gst_elements.erase(sounddata->m_gst_elements.begin() + i);
+ }
+
+ ++_soundsStopped;
+}
+
+
+void GST_sound_handler::delete_sound(int sound_handle)
+// this gets called when it's done with a sample.
+{
+ try_mutex::scoped_lock lock(_mutex);
+
+ if (sound_handle >= 0 && (unsigned int) sound_handle <
m_sound_data.size())
+ {
+ delete m_sound_data[sound_handle];
+ m_sound_data.erase (m_sound_data.begin() + sound_handle);
+ }
+
+}
+
+// This will stop all sounds playing. Will cause problems if the soundhandler
is made static
+// and supplys sound_handling for many SWF's, since it will stop all sounds
with no regard
+// for what sounds is associated with what SWF.
+void GST_sound_handler::stop_all_sounds()
+{
+ for (size_t i=0, e=m_sound_data.size(); i < e; ++i)
+ stop_sound(i);
+}
+
+
+// returns the sound volume level as an integer from 0 to 100,
+// where 0 is off and 100 is full volume. The default setting is 100.
+int GST_sound_handler::get_volume(int sound_handle) {
+
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle >= 0 && (unsigned int) sound_handle <
m_sound_data.size())
+ {
+ return m_sound_data[sound_handle]->volume;
+ } else {
+ return 0; // Invalid handle
+ }
+}
+
+
+// A number from 0 to 100 representing a volume level.
+// 100 is full volume and 0 is no volume. The default setting is 100.
+void GST_sound_handler::set_volume(int sound_handle, int volume) {
+
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ return;
+ }
+
+ sound_data* sd = m_sound_data[sound_handle];
+
+ // Set volume for this sound. Should this only apply to the active
sounds?
+
+ sd->volume = volume;
+
+ for (size_t i=0, n=sd->m_gst_elements.size(); i<n; ++i)
+ {
+ g_object_set (
+ G_OBJECT (sd->m_gst_elements[i]->volume),
+ "volume",
+ static_cast<double>(volume/100.0),
+ NULL);
+ }
+
+}
+
+SoundInfo* GST_sound_handler::get_sound_info(int sound_handle) {
+
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
+ {
+ return m_sound_data[sound_handle]->soundinfo.get();
+ } else {
+ return NULL;
+ }
+
+}
+
+// gnash calls this to mute audio
+void GST_sound_handler::mute() {
+ stop_all_sounds();
+ muted = true;
+}
+
+// gnash calls this to unmute audio
+void GST_sound_handler::unmute() {
+ muted = false;
+}
+
+bool GST_sound_handler::is_muted() {
+ return muted;
+}
+
+void GST_sound_handler::attach_aux_streamer(aux_streamer_ptr /*ptr*/, void*
/*owner*/)
+{
+ log_unimpl(__PRETTY_FUNCTION__);
+}
+
+void GST_sound_handler::detach_aux_streamer(void* /*owner*/)
+{
+ log_unimpl(__PRETTY_FUNCTION__);
+}
+
+unsigned int GST_sound_handler::get_duration(int sound_handle)
+{
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ return 0;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ uint32_t sampleCount = sounddata->soundinfo->getSampleCount();
+ uint32_t sampleRate = sounddata->soundinfo->getSampleRate();
+
+ // Return the sound duration in milliseconds
+ if (sampleCount > 0 && sampleRate > 0) {
+ unsigned int ret = sampleCount / sampleRate * 1000;
+ ret += ((sampleCount % sampleRate) * 1000) / sampleRate;
+ if (sounddata->soundinfo->isStereo()) ret = ret / 2;
+ return ret;
+ } else {
+ return 0;
+ }
+}
+
+unsigned int GST_sound_handler::get_position(int sound_handle)
+{
+ try_mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ return 0;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ // If there is no active sounds, return 0
+ if (sounddata->m_gst_elements.size() == 0) {
+ return 0;
+ }
+
+ // return the position of the last element added
+ GstElement *pipeline,*audioconvert;
+ GstStateChangeReturn ret;
+ GstState current, pending;
+ int64_t pos;
+ GstFormat fmt = GST_FORMAT_TIME;
+
+ pipeline =
sounddata->m_gst_elements[sounddata->m_gst_elements.size()-1]->pipeline;
+
+ ret = gst_element_get_state (GST_ELEMENT (pipeline), ¤t,
&pending, 0);
+
+ if (current != GST_STATE_NULL) {
+ audioconvert =
sounddata->m_gst_elements[sounddata->m_gst_elements.size()-1]->audioconvert;
+ if (gst_element_query_position (audioconvert, &fmt, &pos)) {
+ return static_cast<unsigned int>(pos / GST_MSECOND);
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+// Pointer handling and checking functions
+const uint8_t* gst_elements::get_data_ptr(unsigned long int pos)
+{
+ assert(data_size > pos);
+ return data + pos;
+}
+
+void gst_elements::set_data(const uint8_t* idata) {
+ data = idata;
+}
+
+sound_handler* create_sound_handler_gst()
+// Factory.
+{
+ return new GST_sound_handler;
+}
+
+} // namespace gnash
+
+#endif // SOUND_GST
+
+// Local Variables:
+// mode: C++
+// End:
+
Index: libmedia/gst/sound_handler_gst.h
===================================================================
RCS file: libmedia/gst/sound_handler_gst.h
diff -N libmedia/gst/sound_handler_gst.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/gst/sound_handler_gst.h 27 Sep 2007 23:59:54 -0000 1.1
@@ -0,0 +1,204 @@
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef SOUND_HANDLER_GST_H
+#define SOUND_HANDLER_GST_H
+
+//#include "gnash.h"
+#include "sound_handler.h" // for inheritance
+
+#include <vector>
+
+#include <gst/gst.h>
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+
+#define BUFFER_SIZE 5000
+
+namespace gnash {
+
+// forward declaration
+class GST_sound_handler;
+
+// Used to hold the gstreamer when doing on-demand-decoding
+class gst_elements
+{
+public:
+ // gstreamer pipeline objects
+
+ // the main bin containing the adder and output (sink)
+ GstElement *pipeline;
+ GstElement *audiosink;
+
+ // gstreamer objects
+ GstElement *input;
+ GstElement *decoder;
+ GstElement *capsfilter;
+ GstElement *audioconvert;
+ GstElement *audioresample;
+ GstElement *volume;
+ GstElement *bin;
+ GstPad *addersinkpad;
+
+ // position in the stream
+ unsigned long position;
+
+ // data size
+ unsigned long data_size;
+
+ long loop_count;
+
+ // signal id
+ guint handoff_signal_id;
+
+ // The sound handler. Used to get access to the
GST_sound_handler->_mutex
+ GST_sound_handler* handler;
+
+ /// Returns the data pointer in the undecoded datastream
+ /// for the given position. Boundaries are checked.
+ const uint8_t* get_data_ptr(unsigned long int pos);
+
+ /// Set the undecoded data pointer
+ void set_data(const uint8_t*);
+
+private:
+ // The (un)compressed data
+ const guint8* data;
+
+};
+
+
+// Used to hold the sounddata when doing on-demand-decoding
+class sound_data
+{
+ // The (un)compressed data
+ Buffer _data;
+
+public:
+
+ sound_data()
+ {}
+
+ /// Append size bytes to this sound
+ //
+ /// @param data
+ /// Data bytes, allocated with new[]. Ownership transferred.
+ ///
+ /// @param size
+ /// Size of the 'data' buffer.
+ ///
+ void append(unsigned char* data, unsigned int size)
+ {
+ _data.append(data, size);
+ }
+
+ /// Return data size
+ size_t dataSize() const { return _data.size(); }
+
+ /// Return data buffer
+ const uint8_t* data() { return _data.data(); }
+
+ // Object holding information about the sound
+ std::auto_ptr<SoundInfo> soundinfo;
+
+ // Volume, SWF range: 0-100, GST range 0-10 (we only use 0-1, the rest
is amplified)
+ // It's the SWF range that is represented here
+ int volume;
+
+ // gstreamer objects
+ std::vector<gst_elements*> m_gst_elements;
+
+};
+
+// Use gstreamer to handle sounds.
+class GST_sound_handler : public gnash::sound_handler
+{
+private:
+ /// Vector containing all the sounds
+ std::vector<sound_data*> m_sound_data;
+
+ /// Is the loop running?
+ bool looping;
+
+ /// Is the audio muted?
+ bool muted;
+
+ /// Mutex for making sure threads doesn't mess things up
+ boost::try_mutex _mutex;
+
+public:
+
+ /// Gstreamer callback function
+ static void callback_handoff (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data);
+
+ GST_sound_handler();
+ virtual ~GST_sound_handler();
+
+ /// Called to create a sound.
+ virtual int create_sound(void* data, unsigned int data_bytes,
+ std::auto_ptr<SoundInfo> sinfo);
+
+ /// this gets called when a stream gets more data
+ virtual long fill_stream_data(unsigned char* data, unsigned int
data_bytes,
+ unsigned int sample_count, int
handle_id);
+
+ /// Play the index'd sample.
+ virtual void play_sound(int sound_handle, int loop_count, int offset,
+ long start_position, const
std::vector<sound_envelope>* envelopes);
+
+ /// Stop the index'd sample.
+ virtual void stop_sound(int sound_handle);
+
+ /// This gets called when it's done with a sample.
+ virtual void delete_sound(int sound_handle);
+
+ /// This will stop all sounds playing.
+ virtual void stop_all_sounds();
+
+ /// Returns the sound volume level as an integer from 0 to 100.
AS-script only.
+ virtual int get_volume(int sound_handle);
+
+ /// Sets the sound volume level as an integer from 0 to 100. AS-script
only.
+ virtual void set_volume(int sound_handle, int volume);
+
+ /// Gnash uses this to get info about a sound. Used when a stream needs
more data.
+ virtual SoundInfo* get_sound_info(int sound_handle);
+
+ /// Gnash calls this to mute audio.
+ virtual void mute();
+
+ /// Gnash calls this to unmute audio.
+ virtual void unmute();
+
+ /// Gnash calls this to get the mute state.
+ virtual bool is_muted();
+
+ /// Gets the duration in milliseconds of an event sound connected to an
AS Sound obejct.
+ virtual unsigned int get_duration(int sound_handle);
+
+ /// Gets the playhead position in milliseconds of an event sound
connected to an AS Soound obejct.
+ virtual unsigned int get_position(int sound_handle);
+
+ virtual void attach_aux_streamer(aux_streamer_ptr ptr, void* owner);
//vv
+ virtual void detach_aux_streamer(void* owner); //vv
+
+};
+
+} // namespace gnash
+
+#endif // SOUND_HANDLER_GST_H
+
Index: libmedia/sdl/AudioDecoderFfmpeg.cpp
===================================================================
RCS file: libmedia/sdl/AudioDecoderFfmpeg.cpp
diff -N libmedia/sdl/AudioDecoderFfmpeg.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/AudioDecoderFfmpeg.cpp 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,251 @@
+// AudioDecoderFfmpeg.cpp: Audio decoding using the FFMPEG library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#include "AudioDecoderFfmpeg.h"
+
+namespace gnash {
+
+AudioDecoderFfmpeg::AudioDecoderFfmpeg ()
+ :
+ _audioCodec(NULL),
+ _audioCodecCtx(NULL),
+ _parser(NULL)
+{}
+
+AudioDecoderFfmpeg::~AudioDecoderFfmpeg()
+{
+ if (_audioCodec) avcodec_close(_audioCodecCtx);
+ if (_parser) av_parser_close(_parser);
+}
+
+bool AudioDecoderFfmpeg::setup(SoundInfo* info)
+{
+ // Init the avdecoder-decoder
+ avcodec_init();
+ avcodec_register_all();// change this to only register need codec?
+
+ enum CodecID codec_id;
+
+ switch(info->getFormat()) {
+ case AUDIO_CODEC_RAW:
+ codec_id = CODEC_ID_PCM_U16LE;
+ break;
+ case AUDIO_CODEC_ADPCM:
+ codec_id = CODEC_ID_ADPCM_SWF;
+ break;
+ case AUDIO_CODEC_MP3:
+ codec_id = CODEC_ID_MP3;
+ // Init the parser
+ _parser = av_parser_init(codec_id);
+
+ if (!_parser) {
+ log_error(_("libavcodec can't parse the current
audio format"));
+ return false;
+ }
+ break;
+ default:
+ log_error(_("Unsupported audio codec %d"),
static_cast<int>(info->getFormat()));
+ return false;
+ }
+ _audioCodec = avcodec_find_decoder(codec_id);
+
+ if (!_audioCodec) {
+ log_error(_("libavcodec can't decode the current audio
format"));
+ return false;
+ }
+
+ _audioCodecCtx = avcodec_alloc_context();
+ if (!_audioCodecCtx) {
+ log_error(_("libavcodec couldn't allocate context"));
+ return false;
+ }
+
+ int ret = avcodec_open(_audioCodecCtx, _audioCodec);
+ if (ret < 0) {
+ avcodec_close(_audioCodecCtx);
+ log_error(_("libavcodec failed to initialize codec"));
+ return false;
+ }
+
+ if (_audioCodecCtx->codec->id != CODEC_ID_MP3) {
+ _audioCodecCtx->channels = (info->isStereo() ? 2 : 1);
+ _audioCodecCtx->sample_rate = info->getSampleRate();
+ _audioCodecCtx->sample_fmt = SAMPLE_FMT_S16;
+ }
+
+ return true;
+}
+
+bool AudioDecoderFfmpeg::setup(AudioInfo* info)
+{
+ // Init the avdecoder-decoder
+ avcodec_init();
+ avcodec_register_all();// change this to only register need codec?
+
+ if (info->type == FLASH) {
+ enum CodecID codec_id;
+
+ switch(info->codec) {
+ case AUDIO_CODEC_RAW:
+ codec_id = CODEC_ID_PCM_U16LE;
+ break;
+ case AUDIO_CODEC_ADPCM:
+ codec_id = CODEC_ID_ADPCM_SWF;
+ break;
+ case AUDIO_CODEC_MP3:
+ codec_id = CODEC_ID_MP3;
+ break;
+ default:
+ log_error(_("Unsupported audio codec %d"),
static_cast<int>(info->codec));
+ return false;
+ }
+ _audioCodec = avcodec_find_decoder(codec_id);
+ // Init the parser
+ _parser = av_parser_init(codec_id);
+ } else if (info->type == FFMPEG) {
+ _audioCodec =
avcodec_find_decoder(static_cast<CodecID>(info->codec));
+ // Init the parser
+ _parser = av_parser_init(static_cast<CodecID>(info->codec));
+ } else {
+ return false;
+ }
+
+ if (!_parser) {
+ log_error(_("libavcodec can't parse the current audio format"));
+ return false;
+ }
+
+ if (!_audioCodec) {
+ log_error(_("libavcodec can't decode the current audio
format"));
+ return false;
+ }
+
+ _audioCodecCtx = avcodec_alloc_context();
+ if (!_audioCodecCtx) {
+ log_error(_("libavcodec couldn't allocate context"));
+ return false;
+ }
+
+ int ret = avcodec_open(_audioCodecCtx, _audioCodec);
+ if (ret < 0) {
+ avcodec_close(_audioCodecCtx);
+ log_error(_("libavcodec failed to initialize codec"));
+ return false;
+ }
+
+ if (_audioCodecCtx->codec->id != CODEC_ID_MP3) {
+ _audioCodecCtx->channels = (info->stereo ? 2 : 1);
+ _audioCodecCtx->sample_rate = info->sampleRate;
+ //_audioCodecCtx->sample_fmt = SAMPLE_FMT_S16;
+ }
+
+ return true;
+}
+
+uint8_t* AudioDecoderFfmpeg::decode(uint8_t* input, uint32_t inputSize,
uint32_t& outputSize, uint32_t& decodedBytes, bool parse)
+{
+
+ long bytes_decoded = 0;
+ int bufsize = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
+ uint8_t* output = new uint8_t[bufsize];
+ uint32_t orgbufsize = bufsize;
+ decodedBytes = 0;
+
+ if (parse) {
+ bufsize = 0;
+ while (bufsize == 0 && decodedBytes < inputSize) {
+ uint8_t* frame;
+ int framesize;
+
+ bytes_decoded = av_parser_parse(_parser,
_audioCodecCtx, &frame, &framesize, input+decodedBytes, inputSize-decodedBytes,
0, 0); //the last 2 is pts & dts
+
+ int tmp = 0;
+#ifdef FFMPEG_AUDIO2
+ bufsize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ tmp = avcodec_decode_audio2(_audioCodecCtx,
reinterpret_cast<int16_t*>(output), &bufsize, frame, framesize);
+#else
+ tmp = avcodec_decode_audio(_audioCodecCtx,
reinterpret_cast<int16_t*>(output), &bufsize, frame, framesize);
+#endif
+
+ if (bytes_decoded < 0 || tmp < 0 || bufsize < 0) {
+ log_error(_("Error while decoding audio data.
Upgrading ffmpeg/libavcodec might fix this issue."));
+ // Setting data position to data size will get
the sound removed
+ // from the active sound list later on.
+ decodedBytes = inputSize;
+ break;
+ }
+
+ decodedBytes += bytes_decoded;
+ }
+
+ } else {
+
+ int tmp = 0;
+#ifdef FFMPEG_AUDIO2
+ tmp = avcodec_decode_audio2(_audioCodecCtx,
reinterpret_cast<int16_t*>(output), &bufsize, input, inputSize);
+#else
+ tmp = avcodec_decode_audio(_audioCodecCtx,
reinterpret_cast<int16_t*>(output), &bufsize, input, inputSize);
+#endif
+
+ if (bytes_decoded < 0 || tmp < 0 || bufsize < 0) {
+ log_error(_("Error while decoding audio data. Upgrading
ffmpeg/libavcodec might fix this issue."));
+ // Setting data position to data size will get the
sound removed
+ // from the active sound list later on.
+ decodedBytes = 0;
+ outputSize = 0;
+ return NULL;
+ }
+
+ decodedBytes = inputSize;
+ }
+
+ // Error handling
+ if (bufsize < 1) {
+ decodedBytes = 0;
+ outputSize = 0;
+ return NULL;
+ }
+
+ // Resampling is needed.
+ if (_resampler.init(_audioCodecCtx)) {
+ bool stereo = _audioCodecCtx->channels > 1 ? true : false;
+ int samples = stereo ? bufsize >> 2 : bufsize >> 1;
+
+ uint8_t* tmp = new uint8_t[orgbufsize];
+
+ samples =
_resampler.resample(reinterpret_cast<int16_t*>(output),
+
reinterpret_cast<int16_t*>(tmp),
+ samples);
+ outputSize = samples *2 *2; // the resampled audio has
samplesize 2, and is stereo
+ uint8_t* ret = new uint8_t[outputSize];
+ memcpy(ret, tmp, outputSize);
+ delete [] tmp;
+ delete [] output;
+ return ret;
+ } else {
+ outputSize = bufsize;
+ uint8_t* ret = new uint8_t[outputSize];
+ memcpy(ret, output, outputSize);
+ delete [] output;
+ return ret;
+ }
+}
+
+
+}
Index: libmedia/sdl/AudioDecoderFfmpeg.h
===================================================================
RCS file: libmedia/sdl/AudioDecoderFfmpeg.h
diff -N libmedia/sdl/AudioDecoderFfmpeg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/AudioDecoderFfmpeg.h 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,115 @@
+// AudioDecoderFfmpeg.h: Audio decoding using the FFMPEG library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __AUDIODECODERFFMPEG_H__
+#define __AUDIODECODERFFMPEG_H__
+
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+extern "C" {
+#include <ffmpeg/avcodec.h>
+}
+
+#include "log.h"
+#include "AudioDecoder.h"
+
+namespace gnash {
+
+/// This class is used to provide an easy interface to libavcodecs audio
resampler.
+///
+class AudioResampler
+{
+public:
+ AudioResampler() : _context(NULL) {}
+ ~AudioResampler()
+ {
+ if(_context) {
+ audio_resample_close (_context);
+ }
+ }
+
+ /// Initializes the resampler
+ //
+ /// @param ctx
+ /// The audio format container.
+ ///
+ /// @return true if resampling is needed, if not false
+ ///
+ bool init(AVCodecContext* ctx)
+ {
+ if (ctx->sample_rate != 44100 || ctx->channels != 2) {
+ if (!_context) {
+ _context = audio_resample_init(2,
ctx->channels,
+ 44100, ctx->sample_rate);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /// Resamples audio
+ //
+ /// @param input
+ /// A pointer to the audio data that needs resampling
+ ///
+ /// @param output
+ /// A pointer to where the resampled output should be placed
+ ///
+ /// @param samples
+ /// Number of samples in the audio
+ ///
+ /// @return the number of samples in the output data.
+ ///
+ int resample(int16_t* input, int16_t* output, int samples)
+ {
+ return audio_resample (_context, output, input, samples);
+ }
+
+private:
+ /// The container of the resample format information.
+ ReSampleContext* _context;
+};
+
+class AudioDecoderFfmpeg : public AudioDecoder {
+
+public:
+ AudioDecoderFfmpeg();
+ ~AudioDecoderFfmpeg();
+
+ bool setup(AudioInfo* info);
+ bool setup(SoundInfo* info);
+
+ uint8_t* decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize, uint32_t& decodedBytes, bool parse);
+
+private:
+
+ AVCodec* _audioCodec;
+ AVCodecContext* _audioCodecCtx;
+ AVCodecParserContext* _parser;
+
+ // Use for resampling audio
+ AudioResampler _resampler;
+};
+
+} // gnash namespace
+
+#endif // __AUDIODECODERFFMPEG_H__
Index: libmedia/sdl/AudioDecoderMad.cpp
===================================================================
RCS file: libmedia/sdl/AudioDecoderMad.cpp
diff -N libmedia/sdl/AudioDecoderMad.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/AudioDecoderMad.cpp 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,172 @@
+// AudioDecoderMad.cpp: Audio decoding using the mad library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#include "AudioDecoderMad.h"
+#include "utility.h"
+#ifdef USE_FFMPEG
+#include <ffmpeg/avcodec.h>
+#endif
+
+namespace gnash {
+
+AudioDecoderMad::AudioDecoderMad ()
+{
+ // Init the mad decoder
+ mad_stream_init(&_stream);
+ mad_frame_init(&_frame);
+ mad_synth_init(&_synth);
+}
+
+AudioDecoderMad::~AudioDecoderMad()
+{
+ mad_synth_finish(&_synth);
+ mad_frame_finish(&_frame);
+ mad_stream_finish(&_stream);
+}
+
+
+bool AudioDecoderMad::setup(SoundInfo* info)
+{
+ if (info->getFormat() == FORMAT_MP3) return true;
+ else return false;
+}
+
+bool AudioDecoderMad::setup(AudioInfo* info)
+{
+#ifdef USE_FFMPEG
+ if (info->type == FFMPEG && info->codec == CODEC_ID_MP3) {
+ return true;
+ }
+#endif
+ if (info->type == FLASH && info->codec == AUDIO_CODEC_MP3) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint8_t* AudioDecoderMad::decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize, uint32_t& decodedBytes, bool parse)
+{
+ // Setup the mad decoder
+ mad_stream_buffer(&_stream, input, inputSize);
+
+ int ret;
+ const unsigned char* old_next_frame = _stream.next_frame;
+ int loops = 0;
+ while(true) {
+
+ ret = mad_frame_decode(&_frame, &_stream);
+ loops++;
+
+ // There is always some junk in front of the data,
+ // so we continue until we get past it.
+ if (ret && _stream.error == MAD_ERROR_LOSTSYNC) continue;
+
+ // Error handling is done by relooping (max. 8 times) and just
hooping that it will work...
+ if (loops > 8) break;
+ if (ret == -1 && _stream.error != MAD_ERROR_BUFLEN &&
MAD_RECOVERABLE(_stream.error)) {
+ log_debug(_("Recoverable error while decoding
MP3-stream, MAD error: %s"), mad_stream_errorstr (&_stream));
+ continue;
+ }
+
+ break;
+ }
+
+ if (ret == -1 && _stream.error != MAD_ERROR_BUFLEN) {
+ log_error(_("Unrecoverable error while decoding MP3-stream, MAD
error: %s"), mad_stream_errorstr (&_stream));
+ outputSize = 0;
+ decodedBytes = 0;
+ return NULL;
+ } else if (ret == -1 && _stream.error == MAD_ERROR_BUFLEN) {
+ // the buffer is empty, no more to decode!
+ decodedBytes = inputSize;
+ } else {
+ decodedBytes = _stream.next_frame - old_next_frame;
+ }
+
+ mad_synth_frame (&_synth, &_frame);
+
+ uint32_t outsize = _synth.pcm.length * _synth.pcm.channels * 2;
+
+ uint8_t* tmp_raw_buffer = new uint8_t[outsize];
+ uint32_t tmp_raw_buffer_size = 0;
+ int sample;
+
+ int16_t* dst = reinterpret_cast<int16_t*>(tmp_raw_buffer);
+
+ // transfer the decoded samples into the sound-struct, and do some
+ // scaling while we're at it.
+ for(int f = 0; f < _synth.pcm.length; f++)
+ {
+ for (int e = 0; e < _synth.pcm.channels; e++) { // channels
(stereo/mono)
+
+ mad_fixed_t mad_sample = _synth.pcm.samples[e][f];
+
+ // round
+ mad_sample += (1L << (MAD_F_FRACBITS - 16));
+
+ // clip
+ if (mad_sample >= MAD_F_ONE) mad_sample = MAD_F_ONE - 1;
+ else if (mad_sample < -MAD_F_ONE) mad_sample =
-MAD_F_ONE;
+
+ // quantize
+ sample = mad_sample >> (MAD_F_FRACBITS + 1 - 16);
+
+ if ( sample != static_cast<int16_t>(sample) ) sample =
sample < 0 ? -32768 : 32767;
+
+ *dst++ = sample;
+ }
+ }
+
+ // If we need to convert samplerate or/and from mono to stereo...
+ if (outsize > 0 && ( _synth.pcm.samplerate != 44100 ||
_synth.pcm.channels != 2)) {
+
+ int16_t* adjusted_data = 0;
+ int adjusted_size = 0;
+ int sample_count = outsize / 2; // samples are of size 2
+
+ // Convert to needed samplerate - this converter only support
standard flash samplerates
+ convert_raw_data(&adjusted_data, &adjusted_size,
tmp_raw_buffer, sample_count, 0,
+ _synth.pcm.samplerate, (_synth.pcm.channels ==
2 ? true : false),
+ 44100, true /* stereo */);
+
+ // Hopefully this wont happen
+ if (!adjusted_data) {
+ log_error(_("Error in sound sample conversion"));
+ delete[] tmp_raw_buffer;
+ outputSize = 0;
+ decodedBytes = 0;
+ return NULL;
+ }
+
+ // Move the new data to the sound-struct
+ delete[] tmp_raw_buffer;
+ tmp_raw_buffer = reinterpret_cast<uint8_t*>(adjusted_data);
+ tmp_raw_buffer_size = adjusted_size;
+
+ } else {
+ tmp_raw_buffer_size = outsize;
+ }
+
+ outputSize = tmp_raw_buffer_size;
+ return tmp_raw_buffer;
+}
+
+} // gnash namespace
+
Index: libmedia/sdl/AudioDecoderMad.h
===================================================================
RCS file: libmedia/sdl/AudioDecoderMad.h
diff -N libmedia/sdl/AudioDecoderMad.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/AudioDecoderMad.h 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,54 @@
+// AudioDecoderMad.h: Audio decoding using the mad library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __AUDIODECODERMAD_H__
+#define __AUDIODECODERMAD_H__
+
+#include "log.h"
+#include "AudioDecoder.h"
+
+#include <mad.h>
+
+
+namespace gnash {
+
+class AudioDecoderMad : public AudioDecoder {
+
+public:
+ AudioDecoderMad();
+ ~AudioDecoderMad();
+
+ bool setup(AudioInfo* info);
+ bool setup(SoundInfo* info);
+
+ uint8_t* decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize, uint32_t& decodedBytes, bool parse);
+
+private:
+
+ /// mad stuff
+ mad_stream _stream;
+ mad_frame _frame;
+ mad_synth _synth;
+};
+
+} // gnash namespace
+
+#endif // __AUDIODECODERMAD_H__
+
Index: libmedia/sdl/MediaDecoderSdl.cpp
===================================================================
RCS file: libmedia/sdl/MediaDecoderSdl.cpp
diff -N libmedia/sdl/MediaDecoderSdl.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/MediaDecoderSdl.cpp 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,306 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#include "MediaDecoderSdl.h"
+#include "AudioDecoderNellymoser.h"
+
+#ifdef USE_FFMPEG
+#include "AudioDecoderFfmpeg.h"
+#include "VideoDecoderFfmpeg.h"
+#include "MediaParserFfmpeg.h"
+#endif
+
+#ifdef USE_MAD
+#include "AudioDecoderMad.h"
+#endif
+
+#include "log.h"
+
+#include <boost/scoped_array.hpp>
+
+#if defined(_WIN32) || defined(WIN32)
+# include <windows.h> // for sleep()
+# define usleep(x) Sleep(x/1000)
+#else
+# include "unistd.h" // for usleep()
+#endif
+
+namespace gnash {
+
+MediaDecoderSdl::MediaDecoderSdl(tu_file* stream, MediaBuffer* buffer,
uint16_t swfVersion, int format)
+ :
+ MediaDecoder(stream, buffer, swfVersion, format),
+
+ _decodeThread(NULL),
+
+ _running(true),
+ _audioDecoder(NULL),
+ _videoDecoder(NULL)
+{
+ // Buffer a bit to make sure the stream is accessable
+ if (_stream->set_position(512) != 0) {
+ _error = streamError;
+ pushOnStatus(streamNotFound);
+ return;
+ }
+ _lastConfirmedPosition = 512;
+ _streamSize = _stream->get_size();
+
+ // Check if the file is a FLV, in which case we use our own parser
+ char head[4] = {0, 0, 0, 0};
+ _stream->set_position(0);
+ _stream->read_bytes(head, 3);
+ _stream->set_position(0);
+
+ // Setup the decoding and parser
+ bool ret = false;
+ if (std::string(head) == "FLV") {
+ _parser.reset(new FLVParser(_stream));
+#ifdef USE_FFMPEG
+ } else {
+ _parser.reset(new MediaParserFfmpeg(_stream));
+#endif
+ }
+
+ ret = _parser->setupParser();
+
+ if (ret) {
+ ret = setupDecoding();
+ } else {
+ log_error("Setup of media parser failed");
+ return;
+ }
+
+ // If the setup failed, there is no reason to start the decoding thread
+ if (ret) {
+ // Start the decoding thread which will also setup the decoder
and parser
+ _decodeThread = new
boost::thread(boost::bind(MediaDecoderSdl::decodeThread, this));
+ } else {
+ log_error("Setup of media decoder failed");
+ }
+}
+
+MediaDecoderSdl::~MediaDecoderSdl()
+{
+ _running = false;
+printf("waiting for thread to stop\n");
+ _decodeThread->join();
+printf("thread stopped\n");
+
+ delete _decodeThread;
+ printf("MediaDecoderSdl deleted!");
+}
+
+void MediaDecoderSdl::pause()
+{
+}
+
+void MediaDecoderSdl::decode()
+{
+}
+
+bool MediaDecoderSdl::setupDecoding()
+{
+ bool video = false;
+ bool audio = false;
+
+ std::auto_ptr<VideoInfo> vInfo = _parser->getVideoInfo();
+ if (vInfo.get() != NULL) {
+#ifdef USE_FFMPEG
+ _videoDecoder.reset(new VideoDecoderFfmpeg());
+#endif
+ if (_videoDecoder.get() != NULL) {
+ if (!_videoDecoder->setup(vInfo.get())) {
+ _videoDecoder.reset(NULL); // Delete the
videoDecoder if it is of no use
+ log_error("No video decoder could be created,
since no decoder for this format is available.");
+ }
+ video = true;
+ } else {
+ log_error("No video decoder could be created, since no
decoder is enabled.");
+ }
+ }
+
+ std::auto_ptr<AudioInfo> aInfo = _parser->getAudioInfo();
+ if (aInfo.get() != NULL) {
+#ifdef USE_MAD
+ if (_parser->isAudioMp3()) {
+ _audioDecoder.reset(new AudioDecoderMad());
+ }
+#endif
+ if (_parser->isAudioNellymoser()) {
+ _audioDecoder.reset(new AudioDecoderNellymoser());
+ }
+
+#ifdef USE_FFMPEG
+ if (_audioDecoder.get() == NULL) _audioDecoder.reset(new
AudioDecoderFfmpeg());
+#endif
+ if (_audioDecoder.get() != NULL) {
+ if (!_audioDecoder->setup(aInfo.get())) {
+ _audioDecoder.reset(NULL); // Delete the
audioDecoder if it is of no use
+ log_error("No audio decoder could be created,
since no decoder for this format is available.");
+ }
+ audio = true;
+ } else {
+ log_error("No audio decoder could be created, since no
decoder is enabled.");
+ }
+ }
+
+ // We don't need both audio and video to be happy :)
+ return (audio || video);
+}
+
+
+uint32_t MediaDecoderSdl::seek(uint32_t pos)
+{
+ uint32_t ret = 0;
+ if (_parser.get()) ret = _parser->seek(pos);
+ else ret = 0;
+
+ // Flush the buffer
+ _buffer->flush();
+
+ return ret;
+}
+
+void MediaDecoderSdl::decodeThread(MediaDecoderSdl* decoder)
+{
+printf("\t in the decode thread\n");
+ // The decode loop
+ while (decoder->_running) {
+
+ // If the buffer is not full, put something into it!
+ if (!decoder->_buffer->isFull()) {
+ decoder->decodeAndBufferFrame();
+ //log_debug("decoded a frame");
+
+ // "Warm up" the data.
+ } else if (decoder->_streamSize >
decoder->_lastConfirmedPosition) {
+ if
(decoder->_stream->set_position(decoder->_lastConfirmedPosition+10000) != 0) {
+ // We assume we're done now
+ // TODO: check for errors
+ decoder->_lastConfirmedPosition =
decoder->_streamSize;
+ } else {
+ decoder->_lastConfirmedPosition += 10000;
+ }
+ //log_debug("warming up the file");
+
+ }
+ usleep(1); // task switch, to avoid 100% CPU
+ }
+ log_debug("Left the decoding loop");
+}
+
+
+void MediaDecoderSdl::decodeAndBufferFrame()
+{
+
+ MediaFrame* frame = _parser->parseMediaFrame();
+ uint32_t parserPosition = _parser->getLastParsedPos();
+ if (parserPosition > _lastConfirmedPosition) _lastConfirmedPosition =
parserPosition;
+
+ if (frame == NULL) {
+ if (_lastConfirmedPosition+1 >= _streamSize)
+ {
+#ifdef GNASH_DEBUG_THREADS
+ log_debug("decodeFLVFrame: load completed, stopping");
+#endif
+ // Stop!
+ //m_go = false;
+ } else {
+ log_error("FLV parsing problems! stopping buffering.");
+ _running = false;
+ }
+//log_error("FLV parsing problems!");
+ return;
+ }
+
+ if (frame->tag == 9) {
+ decodeVideo(frame);
+ } else {
+ decodeAudio(frame);
+ }
+
+}
+
+void MediaDecoderSdl::decodeAudio(MediaFrame* packet)
+{
+ // We don't handle audio
+ if (!_audioDecoder.get()) return;
+
+ uint32_t datasize;
+ uint32_t bufsize;
+
+ uint8_t* ptr = _audioDecoder->decode(packet->data, packet->dataSize,
bufsize, datasize, false);
+
+ if (bufsize > 0 && ptr != NULL)
+ {
+ raw_mediadata_t* raw = new raw_mediadata_t();
+
+ raw->m_data = ptr;
+ raw->m_ptr = raw->m_data;
+ raw->m_size = bufsize;
+ raw->m_pts = packet->timestamp;
+ _buffer->pushAudio(raw);
+ return;
+ }
+ log_debug(_("Problems decoding audio frame."));
+ /*_running = false;
+ _error = decodingError;
+ pushOnStatus(playStop);*/
+}
+
+void MediaDecoderSdl::decodeVideo(MediaFrame* packet)
+{
+ // We don't handle video decoding today
+ if (!_videoDecoder.get()) return;
+
+ uint32_t bufsize;
+
+ uint8_t* ptr = _videoDecoder->decode(packet->data, packet->dataSize,
bufsize);
+
+ if (bufsize > 0 && ptr != NULL)
+ {
+ raw_mediadata_t* raw = new raw_mediadata_t();
+
+ raw->m_data = ptr;
+ raw->m_ptr = raw->m_data;
+ raw->m_size = bufsize;
+ raw->m_pts = packet->timestamp;
+ _buffer->pushVideo(raw);
+ return;
+ }
+ log_debug(_("Problems decoding video frame."));
+/* _running = false;
+ _error = decodingError;
+ pushOnStatus(playStop);*/
+}
+
+
+std::pair<uint32_t, uint32_t>
+MediaDecoderSdl::getWidthAndHeight()
+{
+ if (_parser.get()) {
+ std::auto_ptr<VideoInfo> vInfo = _parser->getVideoInfo();
+ if (vInfo.get()) return std::pair<uint32_t,
uint32_t>(vInfo->width, vInfo->height);
+ }
+ return std::pair<uint32_t, uint32_t>(0,0);
+}
+
+
+} // namespace gnash
Index: libmedia/sdl/MediaDecoderSdl.h
===================================================================
RCS file: libmedia/sdl/MediaDecoderSdl.h
diff -N libmedia/sdl/MediaDecoderSdl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/MediaDecoderSdl.h 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,155 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __MEDIADECODERFFMPEG_H__
+#define __MEDIADECODERFFMPEG_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include "MediaDecoder.h"
+#include "MediaParser.h"
+#include "AudioDecoder.h"
+#include "VideoDecoder.h"
+
+#include "image.h"
+
+namespace gnash {
+
+class MediaDecoderSdl: public MediaDecoder {
+public:
+ MediaDecoderSdl(tu_file* stream, MediaBuffer* buffer, uint16_t
swfVersion, int format);
+ ~MediaDecoderSdl();
+
+ /// Pause decoding (needed ?)
+ void pause();
+
+ /// Resume/start decoding (needed ?)
+ void decode();
+
+ /// Seeks to pos
+ uint32_t seek(uint32_t pos);
+
+ std::pair<uint32_t, uint32_t> getWidthAndHeight();
+
+/* // Used for ffmpeg data read and seek callbacks with non-FLV
+ static int readPacket(void* opaque, uint8_t* buf, int buf_size);
+
+ // Used for ffmpeg data read and seek callbacks with non-FLV
+ static offset_t seekMedia(void *opaque, offset_t offset, int whence);*/
+
+private:
+ /// The decoding thread. Sets up the decoder, and decodes.
+ static void decodeThread(MediaDecoderSdl* decoder);
+
+ /// Decodes a frame and push it unto the buffer
+ void decodeAndBufferFrame();
+
+ // Used to decode a video frame and push it on the videoqueue
+ void decodeVideo(MediaFrame* packet);
+
+ // Used to decode a audio frame and push it on the audioqueue
+ void decodeAudio(MediaFrame* packet);
+
+ /// Sets up the decoder and parser
+ bool setupDecoding();
+
+#if 0
+ /// Sets up the decoder and parser for FLVs
+ bool setupFLVdecoding();
+
+ // Used to decode and push the next available (non-FLV) frame to the
audio or video queue
+ void decodeMediaFrame();
+
+ /// Used to decode push the next available FLV frame to the audio or
video queue
+ //
+ /// Called by ::av_streamer to buffer more a/v frames when possible.
+ ///
+ /// This is a non-blocking call, if data isn't available in the parser
no
+ /// new frame is decoded and this method returns false. Note that this
doesn't
+ /// necessarely means the FLV stream is ended, rather it is possible
the loader
+ /// thread is starving.
+ ///
+ /// TODO: return a more informative value to distinguish between EOF
and starving
+ /// conditions ?
+ ///
+ void decodeFLVFrame();
+
+ // Used to decode a video frame and push it on the videoqueue
+ void decodeVideo(AVPacket* packet);
+
+ // Used to decode a audio frame and push it on the audioqueue
+ void decodeAudio(AVPacket* packet);
+
+ // Used to calculate a decimal value from a ffmpeg fraction
+ inline double as_double(AVRational time)
+ {
+ return time.num / (double) time.den;
+ }
+
+ int _videoIndex;
+ int _audioIndex;
+
+ // video
+ AVCodecContext* _videoCodecCtx;
+ AVStream* _videoStream;
+
+ // audio
+ AVCodecContext* _audioCodecCtx;
+ AVStream* _audioStream;
+
+ // the format (mp3, avi, etc.)
+ AVFormatContext *_formatCtx;
+
+ // A ffmpeg frame
+ AVFrame* _frame;
+#endif
+ // The decoding thread
+ boost::thread* _decodeThread;
+
+ // The timestamp of the last decoded video frame, in seconds.
+ volatile uint32_t _lastVideoTimestamp;
+
+ // The timestamp of the last decoded audio frame, in seconds.
+ volatile uint32_t _lastAudioTimestamp;
+
+ // The time we started playing in seconds (since VM start ?)
+ volatile uint64_t _startClock;
+
+ // A ffmpeg thingy
+ //ByteIOContext _byteIOCxt;
+
+ // Should the decode loop run or not
+ volatile bool _running;
+
+ // An audio decoder, either using ffmpeg or mad
+ std::auto_ptr<AudioDecoder> _audioDecoder;
+
+ // A video decoder, using ffmpeg
+ std::auto_ptr<VideoDecoder> _videoDecoder;
+};
+
+} // namespace gnash
+
+#endif // __MEDIADECODERFFMPEG_H__
Index: libmedia/sdl/MediaParserFfmpeg.cpp
===================================================================
RCS file: libmedia/sdl/MediaParserFfmpeg.cpp
diff -N libmedia/sdl/MediaParserFfmpeg.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/MediaParserFfmpeg.cpp 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,406 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#include "MediaParserFfmpeg.h"
+#include "log.h"
+#include <boost/scoped_array.hpp>
+
+namespace gnash {
+
+MediaParserFfmpeg::MediaParserFfmpeg(tu_file* stream)
+ :
+ MediaParser(stream),
+ _videoIndex(-1),
+ _audioIndex(-1),
+
+ _videoCodecCtx(NULL),
+ _audioCodecCtx(NULL),
+ _formatCtx(NULL),
+ _frame(NULL),
+
+ _lastVideoTimestamp(0),
+ _lastAudioTimestamp(0),
+
+ _inputPos(0),
+ _maxInputPos(0)
+{
+}
+
+MediaParserFfmpeg::~MediaParserFfmpeg()
+{
+
+}
+
+
+/// Probe the stream and try to figure out what the format is.
+//
+/// @param stream the tu_file to use for reading
+/// @return a pointer to the AVInputFormat structure containing
+/// information about the input format, or NULL.
+static AVInputFormat*
+probeStream(tu_file* stream)
+{
+ boost::scoped_array<uint8_t> buffer(new uint8_t[4096]);
+
+ // Probe the file to detect the format
+ AVProbeData probe_data;
+ probe_data.filename = "";
+ probe_data.buf = buffer.get();
+ probe_data.buf_size = 4096;
+
+ // Check if the needed amount of data is available
+ if (stream->set_position(probe_data.buf_size) != 0) {
+ log_error(_("Gnash could not read from movie url"));
+ return NULL;
+ }
+
+ stream->read_bytes(probe_data.buf, probe_data.buf_size);
+
+ return av_probe_input_format(&probe_data, 1);
+}
+
+bool MediaParserFfmpeg::setupParser()
+{
+
+ // This registers all available file formats and codecs
+ // with the library so they will be used automatically when
+ // a file with the corresponding format/codec is opened
+ // XXX should we call avcodec_init() first?
+ av_register_all();
+
+ AVInputFormat* inputFmt = probeStream(_stream);
+ if (!inputFmt) {
+ log_error(_("Couldn't determine stream input format"));
+ //pushOnStatus(streamNotFound);
+ return false;
+ }
+
+ // After the format probe, reset to the beginning of the file.
+ _stream->set_position(0);
+
+ // Setup the filereader/seeker mechanism. 7th argument (NULL) is the
writer function,
+ // which isn't needed.
+ init_put_byte(&_byteIOCxt, new uint8_t[500000], 500000, 0, this,
MediaParserFfmpeg::readPacket, NULL, MediaParserFfmpeg::seekMedia);
+ _byteIOCxt.is_streamed = 1;
+
+ _formatCtx = av_alloc_format_context();
+
+ // Open the stream. the 4th argument is the filename, which we ignore.
+ if(av_open_input_stream(&_formatCtx, &_byteIOCxt, "", inputFmt, NULL) <
0){
+ log_error(_("Couldn't open stream for decoding"));
+ //pushOnStatus(streamNotFound);
+ return false;
+ }
+
+ // Next, we need to retrieve information about the streams contained in
the file
+ // This fills the streams field of the AVFormatContext with valid
information
+ int ret = av_find_stream_info(_formatCtx);
+ if (ret < 0)
+ {
+ log_error(_("Couldn't find stream information, error code:
%d"), ret);
+ //pushOnStatus(streamNotFound);
+ return false;
+ }
+
+// _formatCtx->pb.eof_reached = 0;
+// av_read_play(_formatCtx);
+
+ // Find the first video & audio stream
+ _videoIndex = -1;
+ _audioIndex = -1;
+ //assert(_formatCtx->nb_streams >= 0); useless assert.
+ for (unsigned int i = 0; i < static_cast<unsigned
int>(_formatCtx->nb_streams); i++)
+ {
+ AVCodecContext* enc = _formatCtx->streams[i]->codec;
+
+ switch (enc->codec_type)
+ {
+ case CODEC_TYPE_AUDIO:
+ if (_audioIndex < 0)
+ {
+ _audioIndex = i;
+ _audioStream = _formatCtx->streams[i];
+ }
+ break;
+
+ case CODEC_TYPE_VIDEO:
+ if (_videoIndex < 0)
+ {
+ _videoIndex = i;
+ _videoStream = _formatCtx->streams[i];
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_videoIndex >= 0)
+ {
+
+ // Get a pointer to the codec context for the video stream
+ _videoCodecCtx = _formatCtx->streams[_videoIndex]->codec;
+
+/* // Find the decoder for the video stream
+ AVCodec* pCodec =
avcodec_find_decoder(_videoCodecCtx->codec_id);
+ if (pCodec == NULL)
+ {
+ _videoCodecCtx = NULL;
+ log_error(_("Video decoder %d not found"),
_videoCodecCtx->codec_id);
+ return false;
+ }
+
+ // Open codec
+ if (avcodec_open(_videoCodecCtx, pCodec) < 0)
+ {
+ log_error(_("Could not open codec %d"),
_videoCodecCtx->codec_id);
+ return false;
+ }
+
+ // Allocate a frame to store the decoded frame in
+ _frame = avcodec_alloc_frame();*/
+
+ }
+
+ if (_audioIndex >= 0) {
+ // Get a pointer to the audio codec context for the video stream
+ _audioCodecCtx = _formatCtx->streams[_audioIndex]->codec;
+
+/* // Find the decoder for the audio stream
+ AVCodec* pACodec =
avcodec_find_decoder(_audioCodecCtx->codec_id);
+ if(pACodec == NULL)
+ {
+ log_error(_("No available audio decoder %d to process
stream"), _audioCodecCtx->codec_id);
+ return false;
+ }
+
+ // Open codec
+ if (avcodec_open(_audioCodecCtx, pACodec) < 0)
+ {
+ log_error(_("Could not open audio codec %d for
stream"),_audioCodecCtx->codec_id);
+ return false;
+ }*/
+
+ }
+ return true;
+}
+
+MediaFrame* MediaParserFfmpeg::parseMediaFrame()
+{
+ AVPacket packet;
+ int rc = av_read_frame(_formatCtx, &packet);
+
+ if (rc >= 0)
+ {
+ MediaFrame* ret = new MediaFrame;
+ ret->dataSize = packet.size;
+ ret->data = new uint8_t[packet.size];
+ memcpy(ret->data, packet.data, packet.size);
+
+ if (packet.stream_index == _audioIndex)
+ {
+ ret->tag = AUDIO_TAG;
+
+ // set presentation timestamp
+ if (packet.dts != static_cast<signed
long>(AV_NOPTS_VALUE))
+ {
+ ret->timestamp =
static_cast<uint64_t>(as_double(_audioStream->time_base) * packet.dts * 1000.0);
+ }
+
+ if (ret->timestamp != 0)
+ {
+ // update audio clock with pts, if present
+ _lastAudioTimestamp = ret->timestamp;
+ } else {
+ ret->timestamp = _lastAudioTimestamp;
+ }
+
+ // update video clock for next frame
+ uint32_t frame_delay;
+ frame_delay =
static_cast<uint32_t>((as_double(_audioStream->time_base) * packet.dts) *
1000.0);
+
+ _lastAudioTimestamp += frame_delay;
+
+ } else if (packet.stream_index == _videoIndex) {
+ ret->tag = VIDEO_TAG;
+
+ ret->timestamp = 0;
+
+ // set presentation timestamp
+ if (packet.dts != static_cast<signed
long>(AV_NOPTS_VALUE))
+ {
+ ret->timestamp =
static_cast<uint32_t>((as_double(_videoStream->time_base) * packet.dts) *
1000.0);
+ }
+
+ if (ret->timestamp != 0)
+ {
+ // update video clock with pts, if present
+ _lastVideoTimestamp = ret->timestamp;
+ } else {
+ ret->timestamp = _lastVideoTimestamp;
+ }
+
+ // update video clock for next frame
+ uint32_t frame_delay;
+ frame_delay =
static_cast<uint32_t>(as_double(_videoStream->codec->time_base) * 1000.0);
+
+ // for MPEG2, the frame can be repeated, so we update
the clock accordingly
+ //frame_delay +=
static_cast<uint32_t>(_frame->repeat_pict * (frame_delay * 0.5) * 1000.0);
+
+ _lastVideoTimestamp += frame_delay;
+
+ } else {
+ delete ret;
+ return NULL;
+ }
+ av_free_packet(&packet);
+ return ret;
+ } else {
+ return NULL;
+ }
+
+}
+
+uint32_t MediaParserFfmpeg::seek(uint32_t pos)
+{
+ long newpos = 0;
+ double timebase = 0;
+ uint32_t ret = 0;
+
+ AVStream* videostream = _formatCtx->streams[_videoIndex];
+ timebase = static_cast<double>(videostream->time_base.num /
videostream->time_base.den);
+ newpos = static_cast<long>(pos / timebase);
+
+ if (av_seek_frame(_formatCtx, _videoIndex, newpos, 0) < 0) {
+ log_error(_("%s: seeking failed"), __FUNCTION__);
+ return 0;
+ }
+ // We have to do parse a new frame to get
+ // the new position. This is kindof hackish and ugly :-(
+ AVPacket Packet;
+ av_init_packet(&Packet);
+ double newtime = 0;
+ while (newtime == 0) {
+ if ( av_read_frame(_formatCtx, &Packet) < 0) {
+ av_seek_frame(_formatCtx, -1, 0,AVSEEK_FLAG_BACKWARD);
+ av_free_packet(&Packet);
+ return 0;
+ }
+
+ newtime = timebase *
static_cast<double>(_formatCtx->streams[_videoIndex]->cur_dts);
+ }
+
+ av_free_packet(&Packet);
+ av_seek_frame(_formatCtx, _videoIndex, newpos, 0);
+ uint32_t newtime_ms = static_cast<int32_t>(newtime / 1000.0);
+
+ _lastAudioTimestamp = newtime_ms;
+ _lastVideoTimestamp = newtime_ms;
+ ret = newtime_ms;
+
+ return ret;
+}
+
+std::auto_ptr<VideoInfo>
+MediaParserFfmpeg::getVideoInfo()
+{
+ if (!_videoCodecCtx || !_videoStream) return
std::auto_ptr<VideoInfo>(NULL);
+
+ std::auto_ptr<VideoInfo> ret (new VideoInfo(_videoCodecCtx->codec_id,
+
_videoCodecCtx->width,
+
_videoCodecCtx->height,
+
static_cast<int16_t>(as_double(_videoStream->r_frame_rate)), //
Is this correct? What do we use the framerate for?
+
_videoStream->duration,
+
FFMPEG));
+ ret->videoCodecCtx = _videoCodecCtx;
+ return ret;
+}
+
+std::auto_ptr<AudioInfo>
+MediaParserFfmpeg::getAudioInfo()
+{
+ if (!_audioCodecCtx || !_audioStream) return
std::auto_ptr<AudioInfo>(NULL);
+
+ if (_audioCodecCtx->codec_id == CODEC_ID_MP3) _isAudioMp3 = true;
+
+ return std::auto_ptr<AudioInfo>(new AudioInfo(_audioCodecCtx->codec_id,
+
_audioCodecCtx->sample_rate,
+
_audioCodecCtx->sample_fmt + 1, // see definition of
SampleFormat in avcodec.h
+
_audioCodecCtx->channels > 1 ? true : false,
+
_audioStream->duration,
+
FFMPEG));
+}
+
+
+// ffmpeg callback function
+int
+MediaParserFfmpeg::readPacket(void* opaque, uint8_t* buf, int buf_size)
+{
+
+ MediaParserFfmpeg* decoder = static_cast<MediaParserFfmpeg*>(opaque);
+
+ size_t ret = decoder->_stream->read_bytes(static_cast<void*>(buf),
buf_size);
+ decoder->_inputPos += ret;
+
+ if (decoder->_inputPos > decoder->_maxInputPos) decoder->_maxInputPos =
decoder->_inputPos;
+
+ return ret;
+
+}
+
+// ffmpeg callback function
+offset_t
+MediaParserFfmpeg::seekMedia(void *opaque, offset_t offset, int whence){
+
+ MediaParserFfmpeg* decoder = static_cast<MediaParserFfmpeg*>(opaque);
+
+ // Offset is absolute new position in the file
+ if (whence == SEEK_SET) {
+ if (decoder->_stream->set_position(offset) != 0) {
+ decoder->_inputPos = decoder->_stream->get_position();
+ } else {
+ decoder->_inputPos = offset;
+ }
+
+ // New position is offset + old position
+ } else if (whence == SEEK_CUR) {
+ if (decoder->_stream->set_position(decoder->_inputPos + offset)
!= 0) {
+ decoder->_inputPos = decoder->_stream->get_position();
+ } else {
+ decoder->_inputPos += offset;
+ }
+
+ // // New position is offset + end of file
+ } else if (whence == SEEK_END) {
+ // This is (most likely) a file being downloaded, so we can't
seek to the end
+ // without causing big delays! Instead we seek to 50.000
bytes... seems to work fine...
+ if (decoder->_stream->set_position(50000) != 0) {
+ decoder->_inputPos = decoder->_stream->get_position();
+ } else {
+ decoder->_inputPos = 50000;
+ }
+
+ }
+
+ if (decoder->_inputPos > decoder->_maxInputPos) decoder->_maxInputPos =
decoder->_inputPos;
+
+ return decoder->_inputPos;
+}
+
+} // namespace gnash
Index: libmedia/sdl/MediaParserFfmpeg.h
===================================================================
RCS file: libmedia/sdl/MediaParserFfmpeg.h
diff -N libmedia/sdl/MediaParserFfmpeg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/MediaParserFfmpeg.h 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,127 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __MEDIAPARSERFFMPEG_H__
+#define __MEDIAPARSERFFMPEG_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include "MediaParser.h"
+#include "MediaBuffer.h"
+
+extern "C" {
+#include <ffmpeg/avformat.h>
+}
+
+namespace gnash {
+
+
+
+/// \brief
+/// The MediaParser class detects the format of the input file, and parses it
on demand.
+///
+class MediaParserFfmpeg : public MediaParser
+{
+public:
+ MediaParserFfmpeg(tu_file* stream);
+ ~MediaParserFfmpeg();
+
+ /// Setup the parser
+ //
+ /// @return whether we'll be able to parse the file.
+ bool setupParser();
+
+ /// Used to parse the next media frame in the stream and return it
+ MediaFrame* parseMediaFrame();
+
+ /// Try to seek to the given millisecond. Returns the millisecond where
the
+ /// seek got to.
+ uint32_t seek(uint32_t);
+
+ /// Returns a VideoInfo class about the videostream
+ //
+ /// @return a VideoInfo class about the videostream
+ std::auto_ptr<VideoInfo> getVideoInfo();
+
+ /// Returns a AudioInfo class about the audiostream
+ //
+ /// @return a AudioInfo class about the audiostream
+ std::auto_ptr<AudioInfo> getAudioInfo();
+
+ // Used for ffmpeg data read and seek callbacks
+ static int readPacket(void* opaque, uint8_t* buf, int buf_size);
+
+ // Used for ffmpeg data read and seek callbacks
+ static offset_t seekMedia(void *opaque, offset_t offset, int whence);
+
+ /// Returns the last parsed position in the file in bytes
+ uint32_t getLastParsedPos() { return _maxInputPos; }
+
+private:
+
+ // Used to calculate a decimal value from a ffmpeg fraction
+ inline double as_double(AVRational time)
+ {
+ return time.num / (double) time.den;
+ }
+
+ int _videoIndex;
+ int _audioIndex;
+
+ // video
+ AVCodecContext* _videoCodecCtx;
+ AVStream* _videoStream;
+
+ // audio
+ AVCodecContext* _audioCodecCtx;
+ AVStream* _audioStream;
+
+ // the format (mp3, avi, etc.)
+ AVFormatContext *_formatCtx;
+
+ // A ffmpeg frame
+ AVFrame* _frame;
+
+ // A ffmpeg thingy
+ ByteIOContext _byteIOCxt;
+
+ // The timestamp of the last parsed video frame, in milseconds.
+ uint32_t _lastVideoTimestamp;
+
+ // The timestamp of the last parsed audio frame, in seconds.
+ uint32_t _lastAudioTimestamp;
+
+ // The position of the parserhead.
+ uint32_t _inputPos;
+
+ // The max value inputPos ever had.
+ uint32_t _maxInputPos;
+};
+
+
+
+} // namespace gnash
+
+#endif // __MEDIAPARSERFFMPEG_H__
Index: libmedia/sdl/VideoDecoderFfmpeg.cpp
===================================================================
RCS file: libmedia/sdl/VideoDecoderFfmpeg.cpp
diff -N libmedia/sdl/VideoDecoderFfmpeg.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/VideoDecoderFfmpeg.cpp 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,330 @@
+// VideoDecoderFfmpeg.cpp: Video decoding using the FFMPEG library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#include "VideoDecoderFfmpeg.h"
+
+#ifdef HAVE_SWSCALE_H
+extern "C" {
+#include <ffmpeg/swscale.h>
+}
+#endif
+#include <boost/scoped_array.hpp>
+
+namespace gnash {
+
+VideoDecoderFfmpeg::VideoDecoderFfmpeg ()
+ :
+ _videoCodec(NULL),
+ _videoCodecCtx(NULL)
+{}
+
+VideoDecoderFfmpeg::~VideoDecoderFfmpeg()
+{
+ if (_videoCodec) avcodec_close(_videoCodecCtx);
+}
+
+bool VideoDecoderFfmpeg::setup(
+ int width,
+ int height,
+ int /*deblocking*/,
+ bool /*smoothing*/,
+ videoCodecType format, // should this argument be of codecType
type ?
+ int /*outputFormat*/)
+{
+ // Init the avdecoder-decoder
+ avcodec_init();
+ avcodec_register_all();// change this to only register need codec?
+
+ enum CodecID codec_id;
+
+ // Find the decoder and init the parser
+ switch(format) {
+ case VIDEO_CODEC_H263:
+ codec_id = CODEC_ID_FLV1;
+ break;
+#ifdef FFMPEG_VP6
+ case VIDEO_CODEC_VP6:
+ codec_id = CODEC_ID_VP6F;
+ break;
+#endif
+ case VIDEO_CODEC_SCREENVIDEO:
+ codec_id = CODEC_ID_FLASHSV;
+ break;
+ default:
+ log_error(_("Unsupported audio codec %d"),
static_cast<int>(format));
+ return false;
+ }
+
+ _videoCodec = avcodec_find_decoder(static_cast<CodecID>(codec_id));
+
+ if (!_videoCodec) {
+ log_error(_("libavcodec can't decode the current video
format"));
+ return false;
+ }
+
+ _videoCodecCtx = avcodec_alloc_context();
+ if (!_videoCodecCtx) {
+ log_error(_("libavcodec couldn't allocate context"));
+ return false;
+ }
+
+ int ret = avcodec_open(_videoCodecCtx, _videoCodec);
+ if (ret < 0) {
+ avcodec_close(_videoCodecCtx);
+ log_error(_("libavcodec failed to initialize codec"));
+ return false;
+ }
+ _videoCodecCtx->width = width;
+ _videoCodecCtx->height = height;
+
+ assert(_videoCodecCtx->width > 0);
+ assert(_videoCodecCtx->height > 0);
+ return true;
+}
+
+bool VideoDecoderFfmpeg::setup(VideoInfo* info)
+{
+ // Init the avdecoder-decoder
+ avcodec_init();
+ avcodec_register_all();// change this to only register need codec?
+
+ if (info->type == FLASH) {
+ enum CodecID codec_id;
+
+ // Find the decoder and init the parser
+ switch(info->codec) {
+ case VIDEO_CODEC_H263:
+ codec_id = CODEC_ID_FLV1;
+ break;
+#ifdef FFMPEG_VP6
+ case VIDEO_CODEC_VP6:
+ codec_id = CODEC_ID_VP6F;
+ break;
+#endif
+ case VIDEO_CODEC_SCREENVIDEO:
+ codec_id = CODEC_ID_FLASHSV;
+ break;
+ default:
+ log_error(_("Unsupported audio codec %d"),
static_cast<int>(info->codec));
+ return false;
+ }
+ _videoCodec =
avcodec_find_decoder(static_cast<CodecID>(codec_id));
+ } else if (info->type == FFMPEG) {
+ _videoCodec =
avcodec_find_decoder(static_cast<CodecID>(info->codec));
+ } else {
+ //log_error("Video codecType unknown: %d, %d, %d", info->type,
FLASH, FFMPEG);
+ return false;
+ }
+
+ if (!_videoCodec) {
+ log_error(_("libavcodec can't decode the current video
format"));
+ return false;
+ }
+
+ // Reuse the videoCodecCtx from the ffmpeg parser if exists/possible
+ if (info->videoCodecCtx) {
+ printf("re-using the parsers videoCodecCtx\n");
+ _videoCodecCtx = info->videoCodecCtx;
+ } else {
+ _videoCodecCtx = avcodec_alloc_context();
+ }
+
+ if (!_videoCodecCtx) {
+ log_error(_("libavcodec couldn't allocate context"));
+ return false;
+ }
+
+ int ret = avcodec_open(_videoCodecCtx, _videoCodec);
+ if (ret < 0) {
+ avcodec_close(_videoCodecCtx);
+ log_error(_("libavcodec failed to initialize codec"));
+ return false;
+ }
+
+ return true;
+}
+
+uint8_t*
+VideoDecoderFfmpeg::convertRGB24(AVCodecContext* srcCtx, AVFrame* srcFrame)
+{
+ int width = srcCtx->width, height = srcCtx->height;
+
+ int bufsize = avpicture_get_size(PIX_FMT_RGB24, width, height);
+ if (bufsize == -1) {
+ return NULL;
+ }
+
+ uint8_t* buffer = new uint8_t[bufsize];
+ if (!buffer) {
+ return NULL;
+ }
+
+ AVPicture picture;
+
+ avpicture_fill(&picture, buffer, PIX_FMT_RGB24, width, height);
+#ifndef HAVE_SWSCALE_H
+ img_convert(&picture, PIX_FMT_RGB24, (AVPicture*) srcFrame,
srcCtx->pix_fmt,
+ width, height);
+#else
+ static SwsContext* context = NULL;
+
+ if (!context) {
+ context = sws_getContext(width, height, srcCtx->pix_fmt,
+ width, height, PIX_FMT_RGB24,
+ SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ if (!context) {
+ delete [] buffer;
+ return NULL;
+ }
+ }
+
+ int rv = sws_scale(context, srcFrame->data, srcFrame->linesize, 0,
+ width, picture.data, picture.linesize);
+ if (rv == -1) {
+ delete [] buffer;
+ return NULL;
+ }
+
+#endif // HAVE_SWSCALE_H
+
+ srcFrame->linesize[0] = picture.linesize[0];
+ srcFrame->data[0] = picture.data[0];
+
+ return buffer;
+}
+
+uint8_t* VideoDecoderFfmpeg::decode(uint8_t* input, uint32_t inputSize,
uint32_t& outputSize)
+{
+ // Allocate a frame to store the decoded frame in
+ AVFrame* frame = avcodec_alloc_frame();
+
+ int got = 0;
+ avcodec_decode_video(_videoCodecCtx, frame, &got, input, inputSize);
+ if (got) {
+ boost::scoped_array<uint8_t> buffer;
+
+ uint8_t* decodedData = new uint8_t[_videoCodecCtx->width *
_videoCodecCtx->height * 3];
+ buffer.reset(convertRGB24(_videoCodecCtx, frame));
+
+
+ // Copy the data to the buffer in the correct RGB format
+ uint8_t* srcptr = frame->data[0];
+ uint8_t* srcend = frame->data[0] + frame->linesize[0] *
_videoCodecCtx->height;
+ uint8_t* dstptr = decodedData;
+ unsigned int srcwidth = _videoCodecCtx->width * 3;
+
+ outputSize = 0;
+
+ while (srcptr < srcend) {
+ memcpy(dstptr, srcptr, srcwidth);
+ srcptr += frame->linesize[0];
+ dstptr += srcwidth;
+ outputSize += srcwidth;
+ }
+
+ return decodedData;
+
+/* if (_videoFrameFormat == NONE) { // NullGui?
+ return;
+
+ } else if (_videoFrameFormat == YUV && _videoCodecCtx->pix_fmt
!= PIX_FMT_YUV420P) {
+ assert(0); // TODO
+ //img_convert((AVPicture*) pFrameYUV, PIX_FMT_YUV420P,
(AVPicture*) pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
+ // Don't use depreceted img_convert, use sws_scale
+
+ } else if (_videoFrameFormat == RGB && _videoCodecCtx->pix_fmt
!= PIX_FMT_RGB24) {
+ buffer.reset(convertRGB24(_videoCodecCtx, frame));
+ }
+
+ raw_mediadata_t* video = new raw_mediadata_t;
+ if (_videoFrameFormat == YUV) {
+ assert(0); // See image.cpp to see what yuv size is
+ //video->m_data = new
uint8_t[static_cast<image::yuv*>(m_imageframe)->size()];
+ } else if (_videoFrameFormat == RGB) {
+ video->m_data = new uint8_t[_videoCodecCtx->width *
_videoCodecCtx->height * 3];
+ //}
+
+ video->m_ptr = video->m_data;
+ video->m_stream_index = _videoIndex;
+ video->m_pts = 0;
+
+ video->m_pts =
static_cast<uint32_t>((as_double(_videoStream->time_base) * packet->dts) *
1000.0);
+
+
+ if (_videoFrameFormat == YUV) {
+ //image::yuv* yuvframe =
static_cast<image::yuv*>(_imageframe);
+ int copied = 0;
+ uint8_t* ptr = video->m_data;
+ for (int i = 0; i < 3 ; i++)
+ {
+ int shift = (i == 0 ? 0 : 1);
+ uint8_t* yuv_factor = _frame->data[i];
+ int h = _videoCodecCtx->height >> shift;
+ int w = _videoCodecCtx->width >> shift;
+ for (int j = 0; j < h; j++)
+ {
+ copied += w;
+ //assert(copied <= yuvframe->size());
+ memcpy(ptr, yuv_factor, w);
+ yuv_factor += _frame->linesize[i];
+ ptr += w;
+ }
+ }
+ video->m_size = copied;
+ } else if (_videoFrameFormat == RGB) {
+
+ uint8_t* srcptr = _frame->data[0];
+ uint8_t* srcend = _frame->data[0] + _frame->linesize[0]
* _videoCodecCtx->height;
+ uint8_t* dstptr = video->m_data;
+ unsigned int srcwidth = _videoCodecCtx->width * 3;
+
+ video->m_size = 0;
+
+ while (srcptr < srcend) {
+ memcpy(dstptr, srcptr, srcwidth);
+ srcptr += _frame->linesize[0];
+ dstptr += srcwidth;
+ video->m_size += srcwidth;
+ }
+
+ }*/
+ } else {
+ log_error("Decoding of a video frame failed");
+ return NULL;
+ }
+}
+
+std::auto_ptr<image::image_base>
+VideoDecoderFfmpeg::decodeToImage(uint8_t* input, uint32_t inputSize)
+{
+ uint32_t outputSize = 0;
+ uint8_t* decodedData = decode(input, inputSize, outputSize);
+
+ if (!decodedData || outputSize == 0) {
+ return std::auto_ptr<image::image_base>(NULL);
+ }
+
+ std::auto_ptr<image::image_base> ret;
+ ret.reset(new image::rgb(_videoCodecCtx->width,
_videoCodecCtx->height));
+ ret->update(decodedData);
+ return ret;
+
+}
+
+}
Index: libmedia/sdl/VideoDecoderFfmpeg.h
===================================================================
RCS file: libmedia/sdl/VideoDecoderFfmpeg.h
diff -N libmedia/sdl/VideoDecoderFfmpeg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/VideoDecoderFfmpeg.h 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,69 @@
+// VideoDecoderFfmpeg.h: Video decoding using the FFMPEG library.
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id:
+
+#ifndef __VIDEODECODERFFMPEG_H__
+#define __VIDEODECODERFFMPEG_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "log.h"
+#include "VideoDecoder.h"
+
+extern "C" {
+#include <ffmpeg/avcodec.h>
+}
+
+
+namespace gnash {
+
+
+class VideoDecoderFfmpeg : public VideoDecoder {
+
+public:
+ VideoDecoderFfmpeg();
+ ~VideoDecoderFfmpeg();
+
+ bool setup(VideoInfo* info);
+
+ bool setup(
+ int /*width*/,
+ int /*height*/,
+ int /*deblocking*/,
+ bool /*smoothing*/,
+ videoCodecType /*format*/, // should this argument be of
codecType type ?
+ int /*outputFormat*/);
+
+ uint8_t* decode(uint8_t* input, uint32_t inputSize, uint32_t&
outputSize);
+
+ std::auto_ptr<image::image_base> decodeToImage(uint8_t* /*input*/,
uint32_t /*inputSize*/);
+private:
+
+ uint8_t* convertRGB24(AVCodecContext* srcCtx, AVFrame* srcFrame);
+
+ AVCodec* _videoCodec;
+ AVCodecContext* _videoCodecCtx;
+
+};
+
+} // gnash namespace
+
+#endif // __VIDEODECODERFFMPEG_H__
Index: libmedia/sdl/sound_handler_sdl.cpp
===================================================================
RCS file: libmedia/sdl/sound_handler_sdl.cpp
diff -N libmedia/sdl/sound_handler_sdl.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/sound_handler_sdl.cpp 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,807 @@
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// Based on sound_handler_sdl.cpp by Thatcher Ulrich http://tulrich.com 2003
+// which has been donated to the Public Domain.
+
+// $Id: sound_handler_sdl.cpp,v 1.1 2007/09/27 23:59:55 tgc Exp $
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sound_handler_sdl.h"
+#include "utility.h" // for convert_raw_data
+#include "AudioDecoderSimple.h"
+#include "AudioDecoderNellymoser.h"
+
+#ifdef USE_FFMPEG
+#include "AudioDecoderFfmpeg.h"
+#endif
+
+#ifdef USE_MAD
+#include "AudioDecoderMad.h"
+#endif
+
+#include "log.h"
+#include <cmath>
+#include <vector>
+#include <SDL.h>
+
+namespace gnash {
+
+SDL_sound_handler::SDL_sound_handler()
+ : soundOpened(false),
+ soundsPlaying(0),
+ muted(false)
+{
+ // This is our sound settings
+ audioSpec.freq = 44100;
+ audioSpec.format = AUDIO_S16SYS; // AUDIO_S8 AUDIO_U8;
+ audioSpec.channels = 2;
+ audioSpec.callback = SDL_sound_handler::sdl_audio_callback;
+ audioSpec.userdata = this;
+ audioSpec.samples = 2048; //512 - not enough for
videostream
+}
+
+SDL_sound_handler::~SDL_sound_handler()
+{
+ for (size_t i=0, e=m_sound_data.size(); i < e; ++i)
+ {
+ stop_sound(i);
+ delete_sound(i);
+ }
+ if (soundOpened) SDL_CloseAudio();
+}
+
+
+int SDL_sound_handler::create_sound(
+ void* data,
+ unsigned int data_bytes,
+ std::auto_ptr<SoundInfo> sinfo)
+// Called to create a sample. We'll return a sample ID that
+// can be use for playing it.
+{
+
+ assert(sinfo.get());
+ std::auto_ptr<sound_data> sounddata ( new sound_data );
+
+ //sounddata->data_size = data_bytes;
+ sounddata->volume = 100;
+ sounddata->soundinfo = sinfo;
+
+ int16_t* adjusted_data = 0;
+ int adjusted_size = 0;
+
+ boost::mutex::scoped_lock lock(_mutex);
+
+ switch (sounddata->soundinfo->getFormat())
+ {
+ case AUDIO_CODEC_MP3:
+#ifndef USE_FFMPEG
+#ifndef USE_MAD
+ log_error(_("gnash has not been compiled to handle mp3 audio"));
+ return -1;
+#endif
+#endif
+ sounddata->append(reinterpret_cast<uint8_t*>(data), data_bytes);
+ break;
+
+ case AUDIO_CODEC_RAW:
+ case AUDIO_CODEC_ADPCM:
+ case AUDIO_CODEC_UNCOMPRESSED:
+ case AUDIO_CODEC_NELLYMOSER:
+ sounddata->append(reinterpret_cast<uint8_t*>(data), data_bytes);
+ break;
+
+ default:
+ // Unhandled format.
+ log_error(_("unknown sound format %d requested; gnash does not
handle it"), (int)sounddata->soundinfo->getFormat());
+ return -1; // Unhandled format, set to NULL.
+ }
+
+ m_sound_data.push_back(sounddata.release()); // the vector takes
ownership
+ int sound_id = m_sound_data.size()-1;
+
+ return sound_id;
+
+}
+
+// this gets called when a stream gets more data
+long SDL_sound_handler::fill_stream_data(unsigned char* data, unsigned int
data_bytes, unsigned int /*sample_count*/, int handle_id)
+
+{
+
+ boost::mutex::scoped_lock lock(_mutex);
+ // @@ does a negative handle_id have any meaning ?
+ // should we change it to unsigned instead ?
+ if (handle_id < 0 || (unsigned int) handle_id+1 > m_sound_data.size())
+ {
+ delete [] data;
+ return -1;
+ }
+ sound_data* sounddata = m_sound_data[handle_id];
+
+ // If doing ADPCM, knowing the framesize is needed to decode!
+ if (sounddata->soundinfo->getFormat() == AUDIO_CODEC_ADPCM) {
+ sounddata->m_frames_size[sounddata->size()] = data_bytes;
+ }
+
+ // Handling of the sound data
+ size_t start_size = sounddata->size();
+ sounddata->append(reinterpret_cast<uint8_t*>(data), data_bytes);
+
+ return start_size;
+}
+
+
+void SDL_sound_handler::play_sound(int sound_handle, int loop_count, int
offset, long start_position, const std::vector<sound_envelope>* envelopes)
+// Play the index'd sample.
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists, or if audio is muted
+ if (sound_handle < 0 || static_cast<unsigned int>(sound_handle) >=
m_sound_data.size() || muted)
+ {
+ // Invalid handle or muted
+ return;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ // If this is called from a streamsoundblocktag, we only start if this
+ // sound isn't already playing.
+ if (start_position > 0 && sounddata->m_active_sounds.size() > 0) {
+ return;
+ }
+
+ // Make sure sound actually got some data
+ if (sounddata->size() < 1) {
+ IF_VERBOSE_MALFORMED_SWF(
+ log_swferror(_("Trying to play sound with size 0"));
+ );
+ return;
+ }
+
+ // Make a "active_sound" for this sound which is later placed on the
vector of instances of this sound being played
+ std::auto_ptr<active_sound> sound ( new active_sound );
+
+ // Set source data to the active_sound
+ sound->set_data(sounddata);
+
+ // Set the given options of the sound
+ if (start_position < 0) sound->position = 0;
+ else sound->position = start_position;
+
+ if (offset < 0) sound->offset = 0;
+ else sound->offset = (sounddata->soundinfo->isStereo() ? offset :
offset*2); // offset is stored as stereo
+
+ sound->envelopes = envelopes;
+
+ // Set number of loop we should do. -1 is infinte loop, 0 plays it
once, 1 twice etc.
+ sound->loop_count = loop_count;
+
+ sound->decoder = NULL;
+
+ switch (sounddata->soundinfo->getFormat()) {
+ case AUDIO_CODEC_NELLYMOSER:
+ case AUDIO_CODEC_NELLYMOSER_8HZ_MONO:
+ sound->decoder = new AudioDecoderNellymoser();
+
+ if (!sound->decoder->setup(sounddata->soundinfo.get())) {
+ log_error("The audio decoder can't decode the audio");
+ delete sound->decoder;
+ sound->decoder = NULL;
+ }
+
+ break;
+ case AUDIO_CODEC_MP3:
+#ifdef USE_MAD
+ sound->decoder = new AudioDecoderMad();
+
+ if (!sound->decoder->setup(sounddata->soundinfo.get())) {
+ log_error("The audio decoder can't decode the audio");
+ delete sound->decoder;
+ sound->decoder = NULL;
+ }
+
+ break;
+#endif
+ case AUDIO_CODEC_ADPCM:
+#ifdef USE_FFMPEG
+ sound->decoder = new AudioDecoderFfmpeg();
+
+ if (!sound->decoder->setup(sounddata->soundinfo.get())) {
+ log_error("The audio decoder can't decode the audio");
+ delete sound->decoder;
+ sound->decoder = NULL;
+ }
+
+ break;
+#endif
+ default:
+
+ sound->decoder = new AudioDecoderSimple();
+
+ if (!sound->decoder->setup(sounddata->soundinfo.get())) {
+ log_error("The audio decoder can't decode the audio");
+ delete sound->decoder;
+ sound->decoder = NULL;
+ }
+
+ }
+
+ if (!soundOpened) {
+ if (SDL_OpenAudio(&audioSpec, NULL) < 0 ) {
+ log_error(_("Unable to start SDL sound: %s"),
SDL_GetError());
+ return;
+ }
+ soundOpened = true;
+
+ }
+
+ ++soundsPlaying;
+ ++_soundsStarted;
+ sounddata->m_active_sounds.push_back(sound.release());
+
+ if (soundsPlaying == 1) {
+ SDL_PauseAudio(0);
+ }
+
+}
+
+
+void SDL_sound_handler::stop_sound(int sound_handle)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ } else {
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ for (int32_t i = (int32_t) sounddata->m_active_sounds.size()-1;
i >-1; i--) {
+
+ //active_sound* sound = sounddata->m_active_sounds[i];
+
+ // Stop sound, remove it from the active list
+ //sound->delete_raw_data();
+ //delete sound->decoder;
+
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + i);
+
+ --soundsPlaying;
+ ++_soundsStopped;
+ }
+ }
+
+}
+
+
+// this gets called when it's done with a sample.
+void SDL_sound_handler::delete_sound(int sound_handle)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
+ {
+ delete m_sound_data[sound_handle];
+ m_sound_data[sound_handle] = NULL;
+ }
+
+}
+
+// This will stop all sounds playing. Will cause problems if the soundhandler
is made static
+// and supplys sound_handling for many SWF's, since it will stop all sounds
with no regard
+// for what sounds is associated with what SWF.
+void SDL_sound_handler::stop_all_sounds()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ int32_t num_sounds = (int32_t) m_sound_data.size()-1;
+ for (int32_t j = num_sounds; j > -1; j--) {//Optimized
+ sound_data* sounddata = m_sound_data[j];
+ int32_t num_active_sounds = (int32_t)
sounddata->m_active_sounds.size()-1;
+ for (int32_t i = num_active_sounds; i > -1; i--) {
+
+ //active_sound* sound = sounddata->m_active_sounds[i];
+
+ // Stop sound, remove it from the active list
+ //delete sound->decoder;
+
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + i);
+
+ --soundsPlaying;
+ ++_soundsStopped;
+ }
+ }
+}
+
+
+// returns the sound volume level as an integer from 0 to 100,
+// where 0 is off and 100 is full volume. The default setting is 100.
+int SDL_sound_handler::get_volume(int sound_handle) {
+
+ boost::mutex::scoped_lock lock(_mutex);
+
+ int ret;
+ // Check if the sound exists.
+ if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
+ {
+ ret = m_sound_data[sound_handle]->volume;
+ } else {
+ ret = 0; // Invalid handle
+ }
+ return ret;
+}
+
+
+// A number from 0 to 100 representing a volume level.
+// 100 is full volume and 0 is no volume. The default setting is 100.
+void SDL_sound_handler::set_volume(int sound_handle, int volume) {
+
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || static_cast<unsigned int>(sound_handle) >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ } else {
+
+ // Set volume for this sound. Should this only apply to the
active sounds?
+ m_sound_data[sound_handle]->volume = volume;
+ }
+
+
+}
+
+SoundInfo* SDL_sound_handler::get_sound_info(int sound_handle) {
+
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
+ {
+ return m_sound_data[sound_handle]->soundinfo.get();
+ } else {
+ return NULL;
+ }
+
+}
+
+// gnash calls this to mute audio
+void SDL_sound_handler::mute() {
+ stop_all_sounds();
+ muted = true;
+}
+
+// gnash calls this to unmute audio
+void SDL_sound_handler::unmute() {
+ muted = false;
+}
+
+bool SDL_sound_handler::is_muted()
+{
+ return muted;
+}
+
+void SDL_sound_handler::attach_aux_streamer(aux_streamer_ptr ptr, void*
owner)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+ assert(owner);
+ assert(ptr);
+
+ aux_streamer_ptr p;
+ if (m_aux_streamer.get(owner, &p))
+ {
+ // Already in the hash.
+ return;
+ }
+ m_aux_streamer[owner] = ptr;
+
+ ++soundsPlaying;
+
+ if (!soundOpened) {
+ if (SDL_OpenAudio(&audioSpec, NULL) < 0 ) {
+ log_error(_("Unable to start aux SDL sound: %s"),
SDL_GetError());
+ return;
+ }
+ soundOpened = true;
+ }
+ SDL_PauseAudio(0);
+
+}
+
+void SDL_sound_handler::detach_aux_streamer(void* owner)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+ aux_streamer_ptr p;
+ if (m_aux_streamer.get(owner, &p))
+ {
+ --soundsPlaying;
+ m_aux_streamer.erase(owner);
+ }
+
+}
+
+unsigned int SDL_sound_handler::get_duration(int sound_handle)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ return 0;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ uint32_t sampleCount = sounddata->soundinfo->getSampleCount();
+ uint32_t sampleRate = sounddata->soundinfo->getSampleRate();
+
+ // Return the sound duration in milliseconds
+ if (sampleCount > 0 && sampleRate > 0) {
+ unsigned int ret = sampleCount / sampleRate * 1000;
+ ret += ((sampleCount % sampleRate) * 1000) / sampleRate;
+ if (sounddata->soundinfo->isStereo()) ret = ret / 2;
+ return ret;
+ } else {
+ return 0;
+ }
+}
+
+unsigned int SDL_sound_handler::get_position(int sound_handle)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ // Check if the sound exists.
+ if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
+ {
+ // Invalid handle.
+ return 0;
+ }
+
+ sound_data* sounddata = m_sound_data[sound_handle];
+
+ // If there is no active sounds, return 0
+ if (sounddata->m_active_sounds.size() == 0) return 0;
+
+ // We use the first active sound of this.
+ active_sound* asound = sounddata->m_active_sounds[0];
+
+ // Return the playhead position in milliseconds
+ unsigned int ret = asound->samples_played / audioSpec.freq * 1000;
+ ret += ((asound->samples_played % audioSpec.freq) * 1000) /
audioSpec.freq;
+ if (audioSpec.channels > 1) ret = ret / audioSpec.channels;
+ return ret;
+}
+
+sound_handler*
+create_sound_handler_sdl()
+// Factory.
+{
+ return new SDL_sound_handler;
+}
+
+// Pointer handling and checking functions
+uint8_t*
+active_sound::get_raw_data_ptr(unsigned long int pos)
+{
+ if ( _decodedData.get() )
+ {
+ return _decodedData->data(pos);
+ }
+ else return 0;
+}
+
+uint8_t*
+active_sound::get_data_ptr(unsigned long int pos)
+{
+ assert(_undecodedData);
+ return _undecodedData->data(pos);
+}
+
+void active_sound::set_data(sound_data* idata)
+{
+ _undecodedData = idata;
+}
+
+void active_sound::deleteDecodedData()
+{
+ _decodedData.reset();
+}
+
+// AS-volume adjustment
+void adjust_volume(int16_t* data, int size, int volume)
+{
+ for (int i=0; i < size*0.5; i++) {
+ data[i] = data[i] * volume/100;
+ }
+}
+
+// envelope-volume adjustment
+static void
+use_envelopes(active_sound* sound, unsigned int length)
+{
+ // Check if this is the time to use envelopes yet
+ if (sound->current_env == 0 && (*sound->envelopes)[0].m_mark44 >
sound->samples_played+length/2)
+ {
+ return;
+
+ }
+ // switch to the next envelope if needed and possible
+ else if (sound->current_env < sound->envelopes->size()-1 &&
(*sound->envelopes)[sound->current_env+1].m_mark44 >= sound->samples_played)
+ {
+ sound->current_env++;
+ }
+
+ // Current envelope position
+ int32_t cur_env_pos =
sound->envelopes->operator[](sound->current_env).m_mark44;
+
+ // Next envelope position
+ uint32_t next_env_pos = 0;
+ if (sound->current_env == (sound->envelopes->size()-1)) {
+ // If there is no "next envelope" then set the next envelope
start point to be unreachable
+ next_env_pos = cur_env_pos + length;
+ } else {
+ next_env_pos =
(*sound->envelopes)[sound->current_env+1].m_mark44;
+ }
+
+ unsigned int startpos = 0;
+ // Make sure we start adjusting at the right sample
+ if (sound->current_env == 0 &&
(*sound->envelopes)[sound->current_env].m_mark44 > sound->samples_played) {
+ startpos = sound->raw_position +
((*sound->envelopes)[sound->current_env].m_mark44 - sound->samples_played)*2;
+ } else {
+ startpos = sound->raw_position;
+ }
+
+ int16_t* data =
reinterpret_cast<int16_t*>(sound->get_raw_data_ptr(startpos));
+
+ for (unsigned int i=0; i < length/2; i+=2) {
+ float left =
static_cast<float>((*sound->envelopes)[sound->current_env].m_level0 / 32768.0);
+ float right =
static_cast<float>((*sound->envelopes)[sound->current_env].m_level1 / 32768.0);
+
+ data[i] = static_cast<int16_t>(data[i] * left); // Left
+ data[i+1] = static_cast<int16_t>(data[i+1] * right); // Right
+
+ if ((sound->samples_played+(length/2-i)) >= next_env_pos &&
sound->current_env != (sound->envelopes->size()-1)) {
+ sound->current_env++;
+ // Next envelope position
+ if (sound->current_env == (sound->envelopes->size()-1))
{
+ // If there is no "next envelope" then set the
next envelope start point to be unreachable
+ next_env_pos = cur_env_pos + length;
+ } else {
+ next_env_pos =
(*sound->envelopes)[sound->current_env+1].m_mark44;
+ }
+ }
+ }
+}
+
+
+// Prepare for mixing/adding (volume adjustments) and mix/add.
+static void
+do_mixing(Uint8* stream, active_sound* sound, Uint8* data, unsigned int
mix_length, unsigned int volume) {
+ // If the volume needs adjustments we call a function to do that
+ if (volume != 100) {
+ adjust_volume(reinterpret_cast<int16_t*>(data), mix_length,
volume);
+ } else if (sound->envelopes != NULL) {
+ use_envelopes(sound, mix_length);
+ }
+
+ // Mix the raw data
+ SDL_MixAudio(static_cast<Uint8*>(stream),static_cast<const
Uint8*>(data), mix_length, SDL_MIX_MAXVOLUME);
+
+ // Update sound info
+ sound->raw_position += mix_length;
+
+ // Sample size is always 2
+ sound->samples_played += mix_length / 2;
+}
+
+
+// Callback invoked by the SDL audio thread.
+void SDL_sound_handler::sdl_audio_callback (void *udata, Uint8 *stream, int
buffer_length_in)
+{
+ if ( buffer_length_in < 0 )
+ {
+ log_error(_("Negative buffer length in sdl_audio_callback
(%d)"), buffer_length_in);
+ return;
+ }
+
+ if ( buffer_length_in == 0 )
+ {
+ log_error(_("Zero buffer length in sdl_audio_callback"));
+ return;
+ }
+
+ unsigned int buffer_length = static_cast<unsigned
int>(buffer_length_in);
+
+ // Get the soundhandler
+ SDL_sound_handler* handler = static_cast<SDL_sound_handler*>(udata);
+
+ // If nothing to play there is no reason to play
+ // Is this a potential deadlock problem?
+ if (handler->soundsPlaying == 0 && handler->m_aux_streamer.size() == 0)
{
+ SDL_PauseAudio(1);
+ return;
+ }
+
+ boost::mutex::scoped_lock lock(handler->_mutex);
+
+ // Mixed sounddata buffer
+ Uint8* buffer = stream;
+ memset(buffer, 0, buffer_length);
+
+ // call NetStream or Sound audio callbacks
+ if (handler->m_aux_streamer.size() > 0)
+ {
+ uint8_t* buf = new uint8_t[buffer_length];
+
+ // Loop through the attached sounds
+ hash_wrapper< void*, sound_handler::aux_streamer_ptr
>::iterator it = handler->m_aux_streamer.begin();
+ hash_wrapper< void*, sound_handler::aux_streamer_ptr
>::iterator end = handler->m_aux_streamer.end();
+ while (it != end) {
+ memset(buf, 0, buffer_length);
+
+ SDL_sound_handler::aux_streamer_ptr aux_streamer =
it->second; //handler->m_aux_streamer[i]->ptr;
+ void* owner = it->first;
+
+ // If false is returned the sound doesn't want to be
attached anymore
+ bool ret = (aux_streamer)(owner, buf, buffer_length);
+ if (!ret) {
+ handler->m_aux_streamer.erase(it++);
+ handler->soundsPlaying--;
+ } else {
+ ++it;
+ }
+ SDL_MixAudio(stream, buf, buffer_length,
SDL_MIX_MAXVOLUME);
+
+ }
+ delete [] buf;
+ }
+
+ // Run through all the sounds.
+ for(uint32_t i=0; i < handler->m_sound_data.size(); i++) {
+ sound_data* sounddata = handler->m_sound_data[i];
+ for(uint32_t j = 0; j < sounddata->m_active_sounds.size(); j++)
{
+
+ // Temp variables to make the code simpler and easier
to read
+ active_sound* sound = sounddata->m_active_sounds[j];
+
+ // If there exist no decoder, then we can't decode!
+ if (sound->decoder == NULL) continue;
+
+ // When the current sound dont have enough decoded data
to fill the buffer,
+ // we first mix what is already decoded, then decode
some more data, and
+ // mix some more until the buffer is full. If a sound
loops the magic
+ // happens here ;)
+ if (sound->rawDataSize() - sound->raw_position <
buffer_length
+ && (sound->position < sound->dataSize() ||
sound->loop_count != 0)) {
+ // First we mix what is decoded
+ unsigned int index = 0;
+ if (sound->rawDataSize() - sound->raw_position
> 0)
+ {
+ index = sound->rawDataSize() -
sound->raw_position;
+
+ do_mixing(stream, sound,
sound->get_raw_data_ptr(sound->raw_position),
+ index, sounddata->volume);
+
+ }
+
+ // Then we decode some data
+ // We loop until the size of the decoded sound
is greater than the buffer size,
+ // or there is no more to decode.
+ unsigned int decoded_size = 0;
+ // TODO: should we delete any previous raw_data
?
+ while(decoded_size < buffer_length)
+ {
+
+ // If we need to loop, we reset the
data pointer
+ if (sound->dataSize() ==
sound->position && sound->loop_count != 0) {
+ sound->loop_count--;
+ sound->position = 0;
+ sound->samples_played = 0;
+ }
+
+ // Test if we will get problems...
Should not happen...
+ assert(sound->dataSize() >
sound->position);
+
+ // temp raw buffer
+ Uint8* tmp_raw_buffer;
+ uint32_t tmp_raw_buffer_size = 0;
+ uint32_t decodedBytes = 0;
+
+ uint32_t inputSize = 0;
+ bool parse = true;
+ if (sounddata->soundinfo->getFormat()
== AUDIO_CODEC_ADPCM) {
+ parse = false;
+ if
(sounddata->m_frames_size.size() > 0) inputSize =
sounddata->m_frames_size[sound->position];
+ else inputSize =
sound->dataSize() - sound->position;
+ } else {
+ inputSize = sound->dataSize() -
sound->position;
+ }
+
+ tmp_raw_buffer =
sound->decoder->decode(sound->get_data_ptr(sound->position),
+
inputSize, tmp_raw_buffer_size, decodedBytes, parse);
+
+ sound->position += decodedBytes;
+
+ sound->deleteDecodedData();
+
sound->appendDecodedData(tmp_raw_buffer, tmp_raw_buffer_size);
+
+ decoded_size += tmp_raw_buffer_size;
+
+ // no more to decode from this sound,
so we break the loop
+ if (sound->dataSize() <=
sound->position && sound->loop_count == 0) {
+ break;
+ }
+
+ } // end of "decode min. bufferlength data"
while loop
+
+ sound->raw_position = 0;
+
+ // Determine how much should be mixed
+ unsigned int mix_length = 0;
+ if (decoded_size >= buffer_length - index) {
+ mix_length = buffer_length - index;
+ } else {
+ mix_length = decoded_size;
+ }
+ if (sound->rawDataSize() < 2) continue; //
something went terrible wrong
+ do_mixing(stream+index, sound,
sound->get_raw_data_ptr(0), mix_length, sounddata->volume);
+
+ // When the current sound has enough decoded data to
fill
+ // the buffer, we do just that.
+ } else if (sound->rawDataSize() > sound->raw_position
&& sound->rawDataSize() - sound->raw_position > buffer_length ) {
+
+ do_mixing(stream, sound,
sound->get_raw_data_ptr(sound->raw_position),
+ buffer_length, sounddata->volume);
+
+ // When the current sound doesn't have anymore data to
decode,
+ // and doesn't loop (anymore), but still got unplayed
data,
+ // we put the last data on the stream
+ } else if (sound->rawDataSize() - sound->raw_position
<= buffer_length && sound->rawDataSize() > sound->raw_position+1) {
+
+
+ do_mixing(stream, sound,
sound->get_raw_data_ptr(sound->raw_position),
+ sound->rawDataSize() -
sound->raw_position, sounddata->volume);
+
+ sound->raw_position = sound->rawDataSize();
+ }
+
+ // Sound is done, remove it from the active list
+ if (sound->position == sound->dataSize() &&
sound->loop_count == 0) {
+ /*delete sound->decoder;
+ sound->deleteDecodedData();*/
+
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + j);
+ handler->soundsPlaying--;
+ handler->_soundsStopped++;
+
+ }
+ } // active sounds loop
+ } // existing sounds loop
+
+}
+
+} // namespace gnash
+
+// Local Variables:
+// mode: C++
+// End:
+
Index: libmedia/sdl/sound_handler_sdl.h
===================================================================
RCS file: libmedia/sdl/sound_handler_sdl.h
diff -N libmedia/sdl/sound_handler_sdl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libmedia/sdl/sound_handler_sdl.h 27 Sep 2007 23:59:55 -0000 1.1
@@ -0,0 +1,390 @@
+// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+// $Id: sound_handler_sdl.h,v 1.1 2007/09/27 23:59:55 tgc Exp $
+
+#ifndef SOUND_HANDLER_SDL_H
+#define SOUND_HANDLER_SDL_H
+
+
+#include "sound_handler.h" // for inheritance
+#include "hash_wrapper.h"
+#include "AudioDecoder.h"
+
+#include "log.h"
+
+#ifdef USE_FFMPEG
+extern "C" {
+#include <ffmpeg/avcodec.h>
+}
+#elif defined(USE_MAD)
+#include <mad.h>
+#endif
+
+#include <vector>
+
+#include <SDL_audio.h>
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+
+namespace gnash {
+
+class active_sound;
+
+/// Used to hold the sounddata when doing on-demand-decoding
+class sound_data
+{
+ /// The undecoded data
+ Buffer _buf;
+
+public:
+
+ sound_data()
+ {}
+
+ ~sound_data();
+
+ /// Object holding information about the sound
+ std::auto_ptr<SoundInfo> soundinfo;
+
+ std::map<uint32_t,uint32_t> m_frames_size;
+
+ /// Append size bytes to this sound
+ //
+ /// @param data
+ /// Data bytes, allocated with new[]. Ownership transferred.
+ ///
+ /// @param size
+ /// Size of the 'data' buffer.
+ ///
+ void append(uint8_t* data, unsigned int size)
+ {
+ _buf.append(data, size);
+ }
+
+ /// Return size of the data buffer
+ size_t size() const
+ {
+ return _buf.size();
+ }
+
+ /// Return a pointer to the underlying buffer
+ const uint8_t* data() const {
+ return _buf.data();
+ }
+
+ /// Return a pointer to the underlying buffer
+ uint8_t* data() {
+ return _buf.data();
+ }
+
+ /// Return a pointer to an offset in the underlying buffer
+ //
+ /// @param pos The offset value.
+ /// An assertion will fail if pos > size()
+ ///
+ const uint8_t* data(size_t pos) const {
+ return _buf.data(pos);
+ }
+
+ /// Return a pointer to an offset in the underlying buffer
+ //
+ /// @param pos The offset value.
+ /// An assertion will fail if pos > size()
+ ///
+ uint8_t* data(size_t pos) {
+ return _buf.data(pos);
+ }
+
+ /// Volume for AS-sounds, range: 0-100.
+ /// It's the SWF range that is represented here.
+ int volume;
+
+ /// Vector containing the active instances of this sounds being played
+ //
+ /// NOTE: This class *owns* all active sounds
+ ///
+ typedef std::vector<active_sound*> ActiveSounds;
+
+ ActiveSounds m_active_sounds;
+
+};
+
+/// Used to hold the info about active sounds
+//
+/// This class contains a pointer to the sound_data used for playing
+/// and an optional Buffer to use when decoding is needed.
+///
+/// When the Buffer is NULL we'll play the sound_data bytes directly
+/// (we assume they are decoded already)
+///
+class active_sound
+{
+public:
+ active_sound()
+ :
+ position(0),
+ raw_position(0),
+ loop_count(0),
+ offset(0),
+ current_env(0),
+ samples_played(0),
+ _undecodedData(0)
+ {}
+
+ ~active_sound()
+ {
+ deleteDecodedData();
+ delete decoder;
+ }
+
+ /// The decoder object used to convert the data into the playable format
+ AudioDecoder* decoder;
+
+ /// Current decoding position in the stream
+ unsigned long position;
+
+ /// Current playing position in the decoded stream
+ unsigned long raw_position;
+
+ /// Numbers of loops: -1 means loop forever, 0 means play once.
+ /// For every loop completed, it is decremented.
+ long loop_count;
+
+ /// Offset to make playback start in-sync, only used with mp3 streams.
+ unsigned int offset;
+
+ /// Sound envelopes for the current sound, which determine the volume
level
+ /// from a given position. Only used with sound events.
+ const std::vector<gnash::sound_handler::sound_envelope>* envelopes;
+
+ /// Index of current envelope.
+ uint32_t current_env;
+
+ /// Number of samples played so far.
+ unsigned long samples_played;
+
+ /// Set the undecoded data pointer
+ //
+ /// @param newUndecodedData
+ /// Pointer to a sound_data being the undecoded data
+ /// Ownership will NOT be transferred.
+ ///
+ void set_data(sound_data* newUndecodedData);
+
+ /// Returns the data pointer in the undecoded datastream
+ /// for the given position. Boundaries are checked.
+ uint8_t* get_data_ptr(unsigned long int pos);
+
+ /// Returns the data pointer in the decoded datastream
+ /// for the given position. Boundaries are checked.
+ uint8_t* get_raw_data_ptr(unsigned long int pos);
+
+ /// Release resources associated with decoded data, if any.
+ //
+ /// After this call, the active_sound will have no decoded data
+ /// buffer, thus any pointer to the decoded data will be fetched
+ /// from the undecoded one.
+ ///
+ void deleteDecodedData();
+
+ /// Append size bytes to this raw data
+ //
+ /// @param data
+ /// Data bytes, allocated with new[]. Ownership transferred.
+ ///
+ /// @param size
+ /// Size of the 'data' buffer.
+ ///
+ void appendDecodedData(uint8_t* data, unsigned int size)
+ {
+ if ( ! _decodedData.get() )
+ {
+ _decodedData.reset( new Buffer );
+ }
+
+ _decodedData->append(data, size);
+ }
+
+ /// Set decoded data
+ //
+ /// @param data
+ /// Data bytes, allocated with new[]. Ownership transferred.
+ ///
+ /// @param size
+ /// Size of the 'data' buffer.
+ ///
+ void setDecodedData(uint8_t* data, unsigned int size)
+ {
+ if ( ! _decodedData.get() )
+ {
+ _decodedData.reset( new Buffer(data, size) );
+ }
+ else
+ {
+ _decodedData->assign(data, size);
+ }
+ }
+
+ size_t rawDataSize() const
+ {
+ if ( _decodedData.get() )
+ {
+ return _decodedData->size();
+ }
+ else return 0;
+ }
+
+ size_t dataSize() const
+ {
+ return _undecodedData ? _undecodedData->size() : 0;
+ }
+
+private:
+
+ /// The undecoded data
+ sound_data* _undecodedData;
+
+ /// The decoded buffer
+ //
+ /// If NULL, the _undecodedData will be considered
+ /// decoded instead
+ ///
+ std::auto_ptr<Buffer> _decodedData;
+
+};
+
+// This is here as it needs definition of active_sound
+sound_data::~sound_data()
+{
+ for (ActiveSounds::iterator i=m_active_sounds.begin(),
e=m_active_sounds.end(); i!=e; ++i)
+ {
+ delete *i;
+ }
+}
+
+// Use SDL and ffmpeg/mad/nothing to handle sounds.
+class SDL_sound_handler : public gnash::sound_handler
+{
+private:
+ /// NetStream audio callbacks
+ hash_wrapper< void* /* owner */, aux_streamer_ptr /* callback */>
m_aux_streamer; //vv
+
+ /// Vector containing all sounds.
+ //
+ /// Elemenst of the vector are owned by this class
+ ///
+ std::vector<sound_data*> m_sound_data;
+
+ /// Is sound device opened?
+ bool soundOpened;
+
+ /// The SDL_audio specs
+ SDL_AudioSpec audioSpec;
+
+ /// Keeps track of numbers of playing sounds
+ int soundsPlaying;
+
+ /// Is the audio muted?
+ bool muted;
+
+ /// Mutex for making sure threads doesn't mess things up
+ boost::mutex _mutex;
+
+public:
+ SDL_sound_handler();
+ virtual ~SDL_sound_handler();
+
+ /// Called to create a sound.
+ virtual int create_sound(void* data, unsigned int data_bytes,
std::auto_ptr<SoundInfo> sinfo);
+
+ /// this gets called when a stream gets more data
+ virtual long fill_stream_data(unsigned char* data, unsigned int
data_bytes,
+ unsigned int sample_count, int
handle_id);
+
+ /// Play the index'd sample.
+ virtual void play_sound(int sound_handle, int loop_count, int offset,
+ long start_position, const
std::vector<sound_envelope>* envelopes);
+
+ /// Stop the index'd sample.
+ virtual void stop_sound(int sound_handle);
+
+ /// This gets called when it's done with a sample.
+ virtual void delete_sound(int sound_handle);
+
+ /// This will stop all sounds playing.
+ virtual void stop_all_sounds();
+
+ /// Returns the sound volume level as an integer from 0 to 100.
AS-script only.
+ virtual int get_volume(int sound_handle);
+
+ /// Sets the sound volume level as an integer from 0 to 100. AS-script
only.
+ virtual void set_volume(int sound_handle, int volume);
+
+ /// Gnash uses this to get info about a sound. Used when a stream needs
more data.
+ virtual SoundInfo* get_sound_info(int sound_handle);
+
+ /// Gnash calls this to mute audio.
+ virtual void mute();
+
+ /// Gnash calls this to unmute audio.
+ virtual void unmute();
+
+ /// Gnash calls this to get the mute state.
+ virtual bool is_muted();
+
+ /// Gets the duration in milliseconds of an event sound connected to an
AS Sound obejct.
+ virtual unsigned int get_duration(int sound_handle);
+
+ /// Gets the playhead position in milliseconds of an event sound
connected to an AS Soound obejct.
+ virtual unsigned int get_position(int sound_handle);
+
+ virtual void attach_aux_streamer(aux_streamer_ptr ptr, void* owner);
//vv
+ virtual void detach_aux_streamer(void* owner); //vv
+
+ /// Callback invoked by the SDL audio thread.
+ //
+ /// Refills the output stream/buffer with data.
+ ///
+ /// We run trough all the attached auxiliary streamers fetching decoded
+ /// audio blocks and mixing them into the given output stream.
+ ///
+ /// If sound is compresssed (mp3) a mp3-frame is decoded into a buffer,
+ /// and resampled if needed. When the buffer has been sampled, another
+ /// frame is decoded until all frames has been decoded.
+ /// If a sound is looping it will be decoded from the beginning again.
+ ///
+ /// TODO: make a static method of the SDL_sound_handler class
+ ///
+ /// @param udata
+ /// User data pointer (SDL_sound_handler instance in our case).
+ /// We'll lock the SDL_sound_handler::_mutex during operations.
+ ///
+ /// @param stream
+ /// The output stream/buffer to fill
+ ///
+ /// @param buffer_length_in
+ /// Length of the buffer.
+ /// If zero or negative we log an error and return
+ /// (negative is probably an SDL bug, zero dunno yet).
+ ///
+ static void sdl_audio_callback (void *udata, Uint8 *stream, int
buffer_length_in);
+};
+
+} // namespace gnash
+
+#endif // SOUND_HANDLER_SDL_H
Index: backend/sound_handler.h
===================================================================
RCS file: backend/sound_handler.h
diff -N backend/sound_handler.h
--- backend/sound_handler.h 26 Sep 2007 10:15:52 -0000 1.31
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,543 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-//
-//
-
-/* $Id: sound_handler.h,v 1.31 2007/09/26 10:15:52 strk Exp $ */
-
-/// \page sound_handler_intro Sound handler introduction
-///
-/// This page must be written, volunteers ? :)
-///
-
-#ifndef SOUND_HANDLER_H
-#define SOUND_HANDLER_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "tu_config.h" // for DSOEXPORT
-#include "tu_types.h"
-
-#include <vector>
-#include <memory>
-#include <cassert>
-
-namespace gnash {
- class stream;
- class SoundInfo;
-}
-
-namespace gnash {
-
-/// A buffer of bytes
-class Buffer {
-public:
- Buffer()
- :
- _capacity(0),
- _data(0),
- _size(0)
- {}
-
- /// Create a Buffer with the given initial content
- //
- /// @param newData data to assign to this buffer.
- /// Allocated with new[]. Ownership transferred.
- ///
- /// @param size number of bytes in the new data
- ///
- Buffer(uint8_t* newData, size_t size)
- :
- _capacity(size),
- _data(newData),
- _size(size)
- {}
-
- /// Append data to this buffer
- //
- /// @param newData data to append to this buffer.
- /// Allocated with new[]. Ownership transferred.
- ///
- /// @param size number of bytes in the new data
- ///
- void append(uint8_t* newData, size_t size)
- {
- if ( ! _capacity )
- {
- _data = newData;
- _size = size;
- _capacity = _size;
- return;
- }
-
- reserve(_size+size);
-
- assert(_capacity >= _size+size);
- memcpy(_data+_size, newData, size);
- _size += size;
- delete [] newData;
- }
-
- /// Assign data to this buffer
- //
- /// @param newData data to assign to this buffer.
- /// Allocated with new[]. Ownership transferred.
- ///
- /// @param size number of bytes in the new data
- ///
- void assign(uint8_t* newData, size_t size)
- {
- if ( ! _capacity )
- {
- _data = newData;
- _size = size;
- _capacity = _size;
- return;
- }
-
- _size=0; // so reserve won't memcpy...
- reserve(size);
-
- assert(_capacity >= size);
-
- memcpy(_data, newData, size);
- _size = size;
-
- delete [] newData;
- }
-
- const uint8_t* data() const
- {
- return _data;
- }
-
- uint8_t* data()
- {
- return _data;
- }
-
- const uint8_t* data(size_t pos) const
- {
- assert(pos < _capacity);
- return _data+pos;
- }
-
- uint8_t* data(size_t pos)
- {
- assert(pos < _capacity);
- return _data+pos;
- }
-
- void resize(size_t newSize)
- {
- // we won't change capacity here
- // (should we?)
- _size = newSize;
- }
-
- void reserve(size_t newCapacity)
- {
- if ( _capacity > newCapacity ) return;
-
- // TODO: use smalles power of 2 bigger then newCapacity
- _capacity = std::max(newCapacity, _capacity*2);
-
- uint8_t* tmp = _data;
- _data = new uint8_t[_capacity];
- if ( tmp )
- {
- if ( _size ) memcpy(_data, tmp, _size);
- delete [] tmp;
- }
- }
-
- size_t size() const
- {
- return _size;
- }
-
- ~Buffer()
- {
- delete [] _data;
- }
-
-private:
-
- size_t _capacity;
-
- uint8_t* _data;
-
- size_t _size;
-
-};
-
-
-/// Sound handler.
-//
-/// Stores the audio found by the parser and plays on demand.
-/// Can also play sound from AS classes NetStream and Sound using callbacks
-/// (see attach_aux_streamer and dettach_aux_streamer).
-///
-/// You may define a subclass of this, and pass an instance to
-/// set_sound_handler().
-///
-class DSOEXPORT sound_handler
-{
-public:
-
- // See attach_aux_streamer
- // TODO: change third parameter type to unsigned
- typedef bool (*aux_streamer_ptr)(void *udata, uint8_t *stream, int len);
-
- /// Used to control volume for event sounds. It basically tells that
from
- /// sample X the volume for left out is Y and for right out is Z.
Several
- /// envelopes can be assigned to a sound to make a fade out or similar
stuff.
- struct sound_envelope
- {
- uint32_t m_mark44;
- uint16_t m_level0;
- uint16_t m_level1;
- };
-
- /// Format type that the sound can be.
- enum format_type
- {
- FORMAT_RAW = 0, // Host-endian 8- or 16-bit
- FORMAT_ADPCM = 1, // decoded in the tag loader and passed
through as NATIVE16
- FORMAT_MP3 = 2,
- FORMAT_UNCOMPRESSED = 3,// Little-endian 8- or 16-bit, should
be passed through as FORMAT_NATIVE16
- FORMAT_NELLYMOSER_8HZ_MONO = 5, // According to ffmpeg
- FORMAT_NELLYMOSER = 6, // Mystery proprietary format; see
nellymoser.com
-
- // gnash tries to convert data to this format when possible:
- FORMAT_NATIVE16 = 7 // gnash extension: 16 bits/sample,
native-endian
- };
- // If stereo is true, samples are interleaved w/ left sample first.
-
- /// gnash's parser calls this to create sounds to be played later.
- //
- /// @param data
- /// The data to be stored. For soundstream this is NULL.
- /// If not NULL, ownership of the data is transferred.
- /// The data is assumed to have been allocated using new[].
- ///
- /// @param data_bytes
- /// The size of the data to be stored. For soundstream this is 0.
- ///
- /// @param sinfo
- /// A SoundInfo object contained in an auto_ptr, which contains
info about samplerate,
- /// samplecount, stereo and more. The SoundObject must be not-NULL!
- ///
- /// @return the id given by the soundhandler for later identification.
- ///
- virtual int create_sound(
- void* data,
- unsigned int data_bytes,
- std::auto_ptr<SoundInfo> sinfo
- ) = 0;
-
- /// gnash's parser calls this to fill up soundstreams data
- //
- /// @param data
- /// The sound data to be saved, allocated by new[]. Ownership is
transferred.
- /// TODO: define a class for containing both data and data_bytes ?
or use vector ?
- ///
- /// @param data_bytes
- /// Size of the data in bytes
- ///
- /// @param sample_count
- /// Number of samples in the data
- ///
- /// @param handle_id
- /// The soundhandlers id of the sound we want some info about.
- ///
- /// @return size of the data buffer before the new data is appended
- ///
- virtual long fill_stream_data(unsigned char* data, unsigned int
data_bytes, unsigned int sample_count, int handle_id) = 0;
-
- /// Returns a pointer to the SoundInfo object for the sound with the
given id.
- /// The SoundInfo object is still owned by the soundhandler.
- //
- /// @param soundhandle
- /// The soundhandlers id of the sound we want some info about.
- ///
- /// @return a pointer to the SoundInfo object for the sound with the
given id.
- ///
- virtual SoundInfo* get_sound_info(int sound_handle) = 0;
-
- /// gnash calls this when it wants you to play the defined sound.
- //
- /// @param sound_handle
- /// The sound_handlers id for the sound to start playing
- ///
- /// @param loop_count
- /// loop_count == 0 means play the sound once (1 means play it twice,
etc)
- ///
- /// @param secondOffset
- /// When starting soundstreams there sometimes is a offset to make the
sound
- /// start at the exact right moment.
- ///
- /// @param start
- /// When starting a soundstream from a random frame, this tells where
in the
- /// data the decoding should start.
- ///
- /// @param envelopes
- /// Some eventsounds have some volume control mechanism called
envelopes.
- /// They basically tells that from sample X the volume should be Y.
- ///
- virtual void play_sound(int sound_handle, int loop_count, int
secondOffset, long start, const std::vector<sound_envelope>* envelopes) = 0;
-
- /// stops all sounds currently playing in a SWF file without stopping
the playhead.
- /// Sounds set to stream will resume playing as the playhead moves over
the frames they are in.
- virtual void stop_all_sounds() = 0;
-
- /// Gets the volume for a given sound. Only used by the AS Sound class
- //
- /// @param sound_handle
- /// The sound_handlers id for the sound to be deleted
- ///
- /// @return the sound volume level as an integer from 0 to 100,
- /// where 0 is off and 100 is full volume. The default setting is 100.
- virtual int get_volume(int sound_handle) = 0;
-
- /// Sets the volume for a given sound. Only used by the AS Sound class
- //
- /// @param sound_handle
- /// The sound_handlers id for the sound to be deleted
- ///
- /// @param volume
- /// A number from 0 to 100 representing a volume level.
- /// 100 is full volume and 0 is no volume. The default setting is 100.
- ///
- virtual void set_volume(int sound_handle, int volume) = 0;
-
- /// Stop the specified sound if it's playing.
- /// (Normally a full-featured sound API would take a
- /// handle specifying the *instance* of a playing
- /// sample, but SWF is not expressive that way.)
- //
- /// @param sound_handle
- /// The sound_handlers id for the sound to be deleted
- ///
- virtual void stop_sound(int sound_handle) = 0;
-
- /// gnash calls this when it's done with a particular sound.
- //
- /// @param sound_handle
- /// The sound_handlers id for the sound to be deleted
- ///
- virtual void delete_sound(int sound_handle) = 0;
-
- /// gnash calls this to mute audio
- virtual void mute() = 0;
-
- /// gnash calls this to unmute audio
- virtual void unmute() = 0;
-
- /// Returns whether or not sound is muted.
- //
- /// @return true if muted, false if not
- ///
- virtual bool is_muted() = 0;
-
- /// This is called by AS classes NetStream or Sound to attach callback,
so
- /// that audio from the classes will be played through the soundhandler.
- //
- /// This is actually only used by the SDL sound_handler. It uses these
"auxiliary"
- /// streamers to fetch decoded audio data to mix and send to the output
channel.
- ///
- /// The "aux streamer" will be called with the 'udata' pointer as first
argument,
- /// then will be passed a buffer pointer as second argument and it's
length
- /// as third. The callbacks should fill the given buffer if possible.
- /// The callback should return true if wants to remain attached, false
if wants
- /// to be detached.
- ///
- /// @param ptr
- /// The pointer to the callback function
- ///
- /// @param udata
- /// User data pointer, passed as first argument to the registered
callback.
- /// WARNING: this is currently also used to *identify* the callback
for later
- /// removal, see detach_aux_streamer. TODO: stop using the data
pointer for
- /// identification purposes and use the callback pointer directly
instead.
- ///
- virtual void attach_aux_streamer(aux_streamer_ptr ptr, void* owner)
= 0;
-
- /// This is called by AS classes NetStream or Sound to dettach
callback, so
- /// that audio from the classes no longer will be played through the
- /// soundhandler.
- //
- /// @param udata
- /// The key identifying the auxiliary streamer.
- /// WARNING: this need currently be the 'udata' pointer passed to
attach_aux_streamer.
- /// TODO: get the aux_streamer_ptr as key !!
- ///
- virtual void detach_aux_streamer(void* udata) = 0;
-
- sound_handler()
- :
- _soundsStarted(0),
- _soundsStopped(0)
- {}
-
- virtual ~sound_handler() {};
-
- /// \brief
- /// Gets the duration in milliseconds of an event sound connected
- /// to an AS Sound obejct.
- //
- /// @param sound_handle
- /// The id of the event sound
- ///
- /// @return the duration of the sound in milliseconds
- virtual unsigned int get_duration(int sound_handle) = 0;
-
- /// \brief
- /// Gets the playhead position in milliseconds of an event sound
connected
- /// to an AS Sound obejct.
- //
- /// @param sound_handle
- /// The id of the event sound
- ///
- /// @return the duration of the sound in milliseconds
- virtual unsigned int get_position(int sound_handle) = 0;
-
- /// Special test-fuction. Reports how many times a sound has been
started
- size_t numSoundsStarted() const { return _soundsStarted; }
-
- /// Special test-fuction. Reports how many times a sound has been
stopped
- size_t numSoundsStopped() const { return _soundsStopped; }
-
-protected:
-
- /// Special test-member. Stores count of started sounds.
- size_t _soundsStarted;
-
- /// Special test-member. Stores count of stopped sounds.
- size_t _soundsStopped;
-};
-
-///
-/// Class containing information about a sound. Is created by the parser while
-/// parsing, and ownership is then transfered to sound_data. When the parser is
-/// parsing streams, it will ask the soundhandler for this to know what
properties
-/// the stream has.
-///
-class SoundInfo {
-public:
- /// Constructor
- //
- /// @param format
- /// The format of the sound. Can be MP3, ADPCM, uncompressed or
Nellymoser
- ///
- /// @param stero
- /// Defines whether the sound is in stereo.
- ///
- /// @param sampleRate
- /// The sample rate of the sound.
- ///
- /// @param sampleCount
- /// The sample count in the sound. In soundstreams this is an average
for each frame.
- ///
- /// @param is16bit
- /// Defines whether the sound is in stereo.
- /// Defines whether the sound is in 16bit format (samplesize == 2)?
else it
- /// is 8bit (samplesize == 1). Used for streams when decoding adpcm.
- ///
- SoundInfo(sound_handler::format_type format, sound_handler::format_type
orgFormat, bool stereo, uint32_t sampleRate, uint32_t sampleCount, bool is16bit)
- : _format(format),
- _orgFormat(orgFormat),
- _stereo(stereo),
- _sampleRate(sampleRate),
- _sampleCount(sampleCount),
- _is16bit(is16bit)
- {
- }
-
- /// Returns the current format of the sound
- ///
- /// @return the current format of the sound
- sound_handler::format_type getFormat() { return _format; }
-
- /// Returns the original format of the sound
- ///
- /// @return the original format of the sound
- sound_handler::format_type getOrgFormat() { return _orgFormat; }
-
- /// Returns the stereo status of the sound
- ///
- /// @return the stereo status of the sound
- bool isStereo() { return _stereo; }
-
- /// Returns the samplerate of the sound
- ///
- /// @return the samplerate of the sound
- unsigned long getSampleRate() { return _sampleRate; }
-
- /// Returns the samplecount of the sound
- ///
- /// @return the samplecount of the sound
- unsigned long getSampleCount() { return _sampleCount; }
-
- /// Returns the 16bit status of the sound
- ///
- /// @return the 16bit status of the sound
- bool is16bit() { return _is16bit; }
-
-private:
- /// Current format of the sound (MP3, raw, etc).
- sound_handler::format_type _format;
-
- /// Original format of the sound (ADPCM, etc).
- sound_handler::format_type _orgFormat;
-
- /// The size of the undecoded data
- unsigned long _dataSize;
-
- /// Stereo or not
- bool _stereo;
-
- /// Sample rate, one of 5512, 11025, 22050, 44100
- uint32_t _sampleRate;
-
- /// Number of samples
- uint32_t _sampleCount;
-
- /// Is the audio in 16bit format (samplesize == 2)? else it
- /// is 8bit (samplesize == 1). Used for streams when decoding adpcm.
- bool _is16bit;
-};
-
-// TODO: move to appropriate specific sound handlers
-DSOEXPORT sound_handler* create_sound_handler_sdl();
-DSOEXPORT sound_handler* create_sound_handler_gst();
-DSOEXPORT sound_handler* create_sound_handler_test();
-
-
-
-} // namespace gnash
-
-#endif // SOUND_HANDLER_H
-
-
-// Local Variables:
-// mode: C++
-// indent-tabs-mode: t
-// End:
Index: backend/sound_handler_gst.cpp
===================================================================
RCS file: backend/sound_handler_gst.cpp
diff -N backend/sound_handler_gst.cpp
--- backend/sound_handler_gst.cpp 26 Sep 2007 10:15:52 -0000 1.65
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,696 +0,0 @@
-// sound_handler_gst.cpp: Audio output via GStreamer, for Gnash.
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-// Based on sound_handler_sdl.cpp by Thatcher Ulrich http://tulrich.com 2003
-// which has been donated to the Public Domain.
-
-/* $Id: sound_handler_gst.cpp,v 1.65 2007/09/26 10:15:52 strk Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "utility.h" // for convert_raw_data
-
-// Assume people running --enable-media=gst know what they are doing
-// (HAVE_GST_GST_H seems broken atm, specifically when an older glib
-// install is around)
-//
-
-#ifdef SOUND_GST
-
-#include "sound_handler_gst.h"
-#include "gnash.h"
-#include "container.h"
-#include "log.h"
-#include "types.h" // for IF_VERBOSE_* macros
-#include <cmath>
-#include <vector>
-
-#include <gst/gst.h>
-
-#define BUFFER_SIZE 5000
-
-using namespace boost;
-
-namespace gnash {
-
-GST_sound_handler::GST_sound_handler()
- : looping(false),
- muted(false)
-{
- // init gstreamer
- gst_init(NULL, NULL);
-}
-
-GST_sound_handler::~GST_sound_handler()
-{
-
- for (size_t i=0, e=m_sound_data.size(); i < e; ++i) {
- stop_sound(i);
- delete_sound(i);
- }
-}
-
-
-int GST_sound_handler::create_sound(
- void* data_,
- unsigned int data_bytes,
- std::auto_ptr<SoundInfo> sinfo)
-// Called to create a sample. We'll return a sample ID that
-// can be use for playing it.
-{
-
- try_mutex::scoped_lock lock(_mutex);
-
- unsigned char* data = static_cast<unsigned char*>(data_);
-
- assert(sinfo.get());
- sound_data *sounddata = new sound_data;
- if (!sounddata) {
- log_error(_("could not allocate memory for sound data"));
- return -1;
- }
-
- sounddata->volume = 100;
- sounddata->soundinfo = sinfo;
-
- switch (sounddata->soundinfo->getFormat())
- {
- case FORMAT_NATIVE16:
- if ( data ) sounddata->append(data, data_bytes);
- break;
-
- case FORMAT_MP3:
- //case FORMAT_VORBIS:
- if ( data ) sounddata->append(data, data_bytes);
- break;
-
- case FORMAT_RAW:
- case FORMAT_ADPCM:
- case FORMAT_UNCOMPRESSED:
- // These should have been converted to FORMAT_NATIVE16
- log_error(_("Sound data format not properly converted"));
- assert(0);
- break;
-
- case FORMAT_NELLYMOSER:
- log_unimpl(_("Nellymoser sound format requested; gnash does not
handle it"));
- return -1;
-
- default:
- // Unhandled format.
- log_error(_("Unknown sound format %d requested; gnash does not
handle it"), (int)sounddata->soundinfo->getFormat());
- return -1; // Unhandled format, set to NULL.
- }
-
- m_sound_data.push_back(sounddata);
-
- return m_sound_data.size()-1;
-}
-
-
-// this gets called when a stream gets more data
-long GST_sound_handler::fill_stream_data(unsigned char* data, unsigned int
data_bytes, unsigned int /*sample_count*/, int handle_id)
-{
- try_mutex::scoped_lock lock(_mutex);
-
- // @@ does a negative handle_id have any meaning ?
- // should we change it to unsigned instead ?
- if (handle_id >= 0 && (unsigned int) handle_id < m_sound_data.size())
- {
- sound_data* sounddata = m_sound_data[handle_id];
-
- long startSize = sounddata->dataSize();
-
- sounddata->append(data, data_bytes);
-
- // If playback has already started, we also update the active
sounds
- for (size_t i=0, e=sounddata->m_gst_elements.size(); i < e;
++i) {
- gst_elements* sound = sounddata->m_gst_elements[i];
- sound->data_size = sounddata->dataSize();
- sound->set_data(sounddata->data());
- }
-
- return startSize;
- }
- else
- {
- delete [] data;
- return 0;
- }
-}
-
-// This stops sounds when they are done playing
-static gboolean sound_killer (gpointer user_data)
-{
- gst_elements *gstelements = static_cast<gst_elements*>(user_data);
- gst_element_set_state (GST_ELEMENT (gstelements->pipeline),
GST_STATE_NULL);
- return false;
-}
-
-// The callback function which refills the buffer with data
-void GST_sound_handler::callback_handoff (GstElement * /*c*/, GstBuffer
*buffer, GstPad* /*pad*/, gpointer user_data)
-{
- gst_elements *gstelements = static_cast<gst_elements*>(user_data);
-
- try_mutex::scoped_try_lock lock(gstelements->handler->_mutex);
-
- // If we couldn't obtain a lock return to avoid a deadlock
- if (!lock.locked()) {
-
- // We return nothing in this case to avoid noise being decoded
and played
- if (GST_BUFFER_SIZE(buffer) != 0 && GST_BUFFER_DATA(buffer)) {
- GST_BUFFER_DATA(buffer) = 0;
- GST_BUFFER_SIZE(buffer) = 0;
- }
- return;
- }
-
- // First callback or after a couldn't-get-lock-return
- if (GST_BUFFER_SIZE(buffer) == 0) {
- if (gstelements->data_size > BUFFER_SIZE) {
- GST_BUFFER_SIZE(buffer) = BUFFER_SIZE;
- } else {
- GST_BUFFER_SIZE(buffer) = gstelements->data_size;
- }
-
- // Reallocate the required memory.
- guint8* tmp_buf = new guint8[GST_BUFFER_SIZE(buffer)];
- memcpy(tmp_buf, GST_BUFFER_DATA(buffer), sizeof(buffer));
-
- delete [] GST_BUFFER_DATA(buffer);
- GST_BUFFER_DATA(buffer) = tmp_buf;
- }
-
- // All the data has been given to the pipeline, so now we need to stop
- // the pipeline. g_idle_add() makes sure sound_killer is called soon.
- if (gstelements->position > gstelements->data_size) {
- g_idle_add(sound_killer, user_data);
- GST_BUFFER_SIZE(buffer) = 0;
- GST_BUFFER_DATA(buffer) = 0;
- return;
- }
-
- const guint8* data_pos =
gstelements->get_data_ptr(gstelements->position);
-
- // Last callback - the last re-fill
- if (gstelements->position+BUFFER_SIZE > gstelements->data_size) {
-
- unsigned int chunk_size =
gstelements->data_size-gstelements->position;
- // Check if we should loop. If loop_count is 0 we have we just
- // played the sound for the last (and perhaps first) time.
- // If loop_count is anything else we continue to loop.
- if (gstelements->loop_count == 0) {
- GST_BUFFER_SIZE(buffer) = chunk_size;
- memcpy(GST_BUFFER_DATA(buffer), data_pos, chunk_size);
- gstelements->position += BUFFER_SIZE;
-
- gst_element_set_state (GST_ELEMENT
(gstelements->input), GST_STATE_PAUSED);
-
- } else {
- // Copy what's left of the data, and then fill the rest
with "new" data.
- memcpy(GST_BUFFER_DATA(buffer), data_pos, chunk_size);
- memcpy(GST_BUFFER_DATA(buffer) + chunk_size,
gstelements->get_data_ptr(0), GST_BUFFER_SIZE(buffer)- chunk_size);
- gstelements->position = GST_BUFFER_SIZE(buffer) -
chunk_size;
- gstelements->loop_count--;
-
- }
-
- return;
-
- }
-
- // Standard re-fill
- memcpy(GST_BUFFER_DATA(buffer), data_pos, BUFFER_SIZE);
- gstelements->position += BUFFER_SIZE;
-
-}
-
-
-void GST_sound_handler::play_sound(int sound_handle, int loop_count, int
/*offset*/, long start_position, const std::vector<sound_envelope>*
/*envelopes*/)
-// Play the index'd sample.
-{
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists, or if audio is muted
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size() || muted)
- {
- // Invalid handle, or audio is muted.
- return;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- // If this is called from a streamsoundblocktag, we only start if this
- // sound isn't already playing.
- if (start_position > 0 && sounddata->m_gst_elements.size() > 0) {
- return;
- }
- // Make sure sound actually got some data
- if (sounddata->dataSize() < 1) {
- IF_VERBOSE_MALFORMED_SWF(
- log_swferror(_("Trying to play sound with size 0"));
- );
- return;
- }
-
- // Make a "gst_elements" for this sound which is latter placed on the
vector of instances of this sound being played
- gst_elements* gst_element = new gst_elements;
- if (gst_element == NULL) {
- log_error (_("Could not allocate memory for gst_element"));
- return;
- }
-
- // Set the handler
- gst_element->handler = this;
-
- // Copy data-info to the "gst_elements"
- gst_element->data_size = sounddata->dataSize();
- gst_element->set_data(sounddata->data());
- gst_element->position = start_position;
-
- // Set number of loop we should do. -1 is infinte loop, 0 plays it
once, 1 twice etc.
- gst_element->loop_count = loop_count;
-
- // create main pipeline
- gst_element->pipeline = gst_pipeline_new (NULL);
-
- // create an audio sink - use oss, alsa or...? make a commandline
option?
- // we first try atudetect, then alsa, then oss, then esd, then...?
-#if !defined(__NetBSD__)
- gst_element->audiosink = gst_element_factory_make ("autoaudiosink",
NULL);
- if (!gst_element->audiosink) gst_element->audiosink =
gst_element_factory_make ("alsasink", NULL);
- if (!gst_element->audiosink) gst_element->audiosink =
gst_element_factory_make ("osssink", NULL);
-#endif
- if (!gst_element->audiosink) gst_element->audiosink =
gst_element_factory_make ("esdsink", NULL);
-
- // Check if the creation of the gstreamer pipeline, adder and audiosink
was a succes
- if (!gst_element->pipeline) {
- log_error(_("The gstreamer pipeline element could not be
created"));
- }
- if (!gst_element->audiosink) {
- log_error(_("The gstreamer audiosink element could not be
created"));
- }
-
- // link adder and output to bin
- gst_bin_add (GST_BIN (gst_element->pipeline), gst_element->audiosink);
-
- gst_element->bin = gst_bin_new(NULL);
- gst_element->input = gst_element_factory_make ("fakesrc", NULL);
- gst_element->capsfilter = gst_element_factory_make ("capsfilter", NULL);
- gst_element->audioconvert = gst_element_factory_make ("audioconvert",
NULL);
- gst_element->audioresample = gst_element_factory_make ("audioresample",
NULL);
- gst_element->volume = gst_element_factory_make ("volume", NULL);
-
- // Put the gstreamer elements in the pipeline
- gst_bin_add_many (GST_BIN (gst_element->bin), gst_element->input,
- gst_element->capsfilter,
- gst_element->audioconvert,
- gst_element->audioresample,
- gst_element->volume, NULL);
-
- // Test if the fakesrc, typefind and audio* elements was correctly
created
- if (!gst_element->input
- || !gst_element->capsfilter
- || !gst_element->audioconvert
- || !gst_element->audioresample) {
-
- log_error(_("Gstreamer element for audio handling could not be
created"));
- return;
- }
-
- // Create a gstreamer decoder for the chosen sound.
-
- // Temp variables to make the code simpler and easier to read
- format_type soundFormat = sounddata->soundinfo->getFormat();
- bool soundStereo = sounddata->soundinfo->isStereo();
- uint32_t soundSampleRate = sounddata->soundinfo->getSampleRate();
-
- if (soundFormat == FORMAT_MP3) {
-
- gst_element->decoder = gst_element_factory_make ("mad", NULL);
- if (gst_element->decoder == NULL) {
- gst_element->decoder = gst_element_factory_make
("flump3dec", NULL);
- if (gst_element->decoder != NULL &&
!gst_default_registry_check_feature_version("flump3dec", 0, 10, 4))
- {
- static bool warned=false;
- if ( ! warned )
- {
- // I keep getting these messages even
if I hear sound... too much paranoia ?
- log_debug(_("This version of fluendos
mp3 plugin does not support flash streaming sounds, please upgrade to version
0.10.4 or higher"));
- warned=true;
- }
- }
- }
- // Check if the element was correctly created
- if (!gst_element->decoder) {
- log_error(_("A gstreamer mp3-decoder element could not
be created. You probably need to install a mp3-decoder plugin like
gstreamer0.10-mad or gstreamer0.10-fluendo-mp3."));
- return;
- }
- gst_bin_add (GST_BIN (gst_element->bin), gst_element->decoder);
-
- // Set the info about the stream so that gstreamer knows what
it is.
- GstCaps *caps = gst_caps_new_simple ("audio/mpeg",
- "mpegversion", G_TYPE_INT, 1,
- "layer", G_TYPE_INT, 3,
- "rate", G_TYPE_INT, soundSampleRate,
- "channels", G_TYPE_INT, soundStereo ? 2 : 1, NULL);
- g_object_set (G_OBJECT (gst_element->capsfilter), "caps", caps,
NULL);
- gst_caps_unref (caps);
-
- // setup fake source
- g_object_set (G_OBJECT (gst_element->input),
- "sizetype", 2, "can-activate-pull",
FALSE, "signal-handoffs", TRUE,
- "sizemax", BUFFER_SIZE, NULL);
- // Setup the callback
- gst_element->handoff_signal_id = g_signal_connect
(gst_element->input, "handoff", G_CALLBACK (callback_handoff), gst_element);
-
- // link data, decoder, audio* and adder
- gst_element_link_many (gst_element->input,
- gst_element->capsfilter,
- gst_element->decoder,
- gst_element->audioconvert,
- gst_element->audioresample,
- gst_element->volume, NULL);
-
- } else if (soundFormat == FORMAT_NATIVE16) {
-
- // Set the info about the stream so that gstreamer knows what
it is.
- GstCaps *caps = gst_caps_new_simple ("audio/x-raw-int",
- "rate", G_TYPE_INT, soundSampleRate,
- "channels", G_TYPE_INT, soundStereo ? 2 : 1,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "width", G_TYPE_INT, 16,
- "depth", G_TYPE_INT, 16,
- /*"signed", G_TYPE_INT, 1,*/ NULL);
- g_object_set (G_OBJECT (gst_element->capsfilter), "caps", caps,
NULL);
- gst_caps_unref (caps);
-
- // setup fake source
- g_object_set (G_OBJECT (gst_element->input),
- "sizetype", 2, "can-activate-pull",
FALSE, "signal-handoffs", TRUE,
- "sizemax", BUFFER_SIZE, NULL);
- // Setup the callback
- gst_element->handoff_signal_id = g_signal_connect
(gst_element->input, "handoff", G_CALLBACK (callback_handoff), gst_element);
-
-/* caps info:
- audio/x-raw-int
- rate: [ 1, 2147483647 ]
- channels: [ 1, 8 ]
- endianness: { 1234, 4321 }
- width: 16
- depth: [ 1, 16 ]
- signed: { true, false }*/
- // Raw native sound-data, output directly
- gst_element_link_many (gst_element->input,
- gst_element->capsfilter,
- gst_element->audioconvert,
- gst_element->audioresample,
- gst_element->volume, NULL);
- }
- // Add ghostpad
- GstPad *pad = gst_element_get_pad (gst_element->volume, "src");
- gst_element_add_pad (gst_element->bin, gst_ghost_pad_new ("src", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- // Add the bin to the main pipeline
- gst_bin_add(GST_BIN (gst_element->pipeline), gst_element->bin);
- // Link to the adder sink pad
- GstPad *sinkpad = gst_element_get_pad (gst_element->audiosink, "sink");
- GstPad *srcpad = gst_element_get_pad (gst_element->bin, "src");
- gst_pad_link (srcpad, sinkpad);
- gst_object_unref (GST_OBJECT (srcpad));
- gst_object_unref (GST_OBJECT (sinkpad));
-
- // Set the volume
- g_object_set (G_OBJECT (gst_element->volume), "volume",
static_cast<double>(sounddata->volume) / 100.0, NULL);
-
- //gst_pad_add_event_probe(pad, G_CALLBACK(event_callback), sounddata);
-
- // Put the gst_element on the vector
- sounddata->m_gst_elements.push_back(gst_element);
-
- // If not already playing, start doing it
- gst_element_set_state (GST_ELEMENT (gst_element->pipeline),
GST_STATE_PLAYING);
-
- ++_soundsStarted;
-
-}
-
-
-void GST_sound_handler::stop_sound(int sound_handle)
-{
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- return;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- // Stop all the instances of this sound.
- // TODO: fix the loop to use size_t instead of i
- for (int i = sounddata->m_gst_elements.size()-1; i >= 0 ; i--)
- {
- gst_elements* elements = sounddata->m_gst_elements[i];
-
- // Check if we can succesfully stop the elements
- // playback - if not we skip cleaning this for now
- // FIXME: what if it ain't possible to stop an element when
this is called from ~GST_sound_handler
-
- // Disconnect signals
- g_signal_handler_disconnect (elements->input,
elements->handoff_signal_id);
-
- gst_element_set_state (GST_ELEMENT (elements->pipeline),
GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (elements->pipeline));
-
- // Delete the gst_element struct
- // @@ we're deleting the elements from the start, so half-way
of the loop we will be referring to undefined elements. Is this intended ?
--strk;
- delete elements;
-
sounddata->m_gst_elements.erase(sounddata->m_gst_elements.begin() + i);
- }
-
- ++_soundsStopped;
-}
-
-
-void GST_sound_handler::delete_sound(int sound_handle)
-// this gets called when it's done with a sample.
-{
- try_mutex::scoped_lock lock(_mutex);
-
- if (sound_handle >= 0 && (unsigned int) sound_handle <
m_sound_data.size())
- {
- delete m_sound_data[sound_handle];
- m_sound_data.erase (m_sound_data.begin() + sound_handle);
- }
-
-}
-
-// This will stop all sounds playing. Will cause problems if the soundhandler
is made static
-// and supplys sound_handling for many SWF's, since it will stop all sounds
with no regard
-// for what sounds is associated with what SWF.
-void GST_sound_handler::stop_all_sounds()
-{
- for (size_t i=0, e=m_sound_data.size(); i < e; ++i)
- stop_sound(i);
-}
-
-
-// returns the sound volume level as an integer from 0 to 100,
-// where 0 is off and 100 is full volume. The default setting is 100.
-int GST_sound_handler::get_volume(int sound_handle) {
-
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle >= 0 && (unsigned int) sound_handle <
m_sound_data.size())
- {
- return m_sound_data[sound_handle]->volume;
- } else {
- return 0; // Invalid handle
- }
-}
-
-
-// A number from 0 to 100 representing a volume level.
-// 100 is full volume and 0 is no volume. The default setting is 100.
-void GST_sound_handler::set_volume(int sound_handle, int volume) {
-
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- return;
- }
-
- sound_data* sd = m_sound_data[sound_handle];
-
- // Set volume for this sound. Should this only apply to the active
sounds?
-
- sd->volume = volume;
-
- for (size_t i=0, n=sd->m_gst_elements.size(); i<n; ++i)
- {
- g_object_set (
- G_OBJECT (sd->m_gst_elements[i]->volume),
- "volume",
- static_cast<double>(volume/100.0),
- NULL);
- }
-
-}
-
-SoundInfo* GST_sound_handler::get_sound_info(int sound_handle) {
-
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
- {
- return m_sound_data[sound_handle]->soundinfo.get();
- } else {
- return NULL;
- }
-
-}
-
-// gnash calls this to mute audio
-void GST_sound_handler::mute() {
- stop_all_sounds();
- muted = true;
-}
-
-// gnash calls this to unmute audio
-void GST_sound_handler::unmute() {
- muted = false;
-}
-
-bool GST_sound_handler::is_muted() {
- return muted;
-}
-
-void GST_sound_handler::attach_aux_streamer(aux_streamer_ptr /*ptr*/, void*
/*owner*/)
-{
- log_unimpl(__PRETTY_FUNCTION__);
-}
-
-void GST_sound_handler::detach_aux_streamer(void* /*owner*/)
-{
- log_unimpl(__PRETTY_FUNCTION__);
-}
-
-unsigned int GST_sound_handler::get_duration(int sound_handle)
-{
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- return 0;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- uint32_t sampleCount = sounddata->soundinfo->getSampleCount();
- uint32_t sampleRate = sounddata->soundinfo->getSampleRate();
-
- // Return the sound duration in milliseconds
- if (sampleCount > 0 && sampleRate > 0) {
- unsigned int ret = sampleCount / sampleRate * 1000;
- ret += ((sampleCount % sampleRate) * 1000) / sampleRate;
- if (sounddata->soundinfo->isStereo()) ret = ret / 2;
- return ret;
- } else {
- return 0;
- }
-}
-
-unsigned int GST_sound_handler::get_position(int sound_handle)
-{
- try_mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- return 0;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- // If there is no active sounds, return 0
- if (sounddata->m_gst_elements.size() == 0) {
- return 0;
- }
-
- // return the position of the last element added
- GstElement *pipeline,*audioconvert;
- GstStateChangeReturn ret;
- GstState current, pending;
- int64_t pos;
- GstFormat fmt = GST_FORMAT_TIME;
-
- pipeline =
sounddata->m_gst_elements[sounddata->m_gst_elements.size()-1]->pipeline;
-
- ret = gst_element_get_state (GST_ELEMENT (pipeline), ¤t,
&pending, 0);
-
- if (current != GST_STATE_NULL) {
- audioconvert =
sounddata->m_gst_elements[sounddata->m_gst_elements.size()-1]->audioconvert;
- if (gst_element_query_position (audioconvert, &fmt, &pos)) {
- return static_cast<unsigned int>(pos / GST_MSECOND);
- } else {
- return 0;
- }
- }
- return 0;
-}
-
-// Pointer handling and checking functions
-const uint8_t* gst_elements::get_data_ptr(unsigned long int pos)
-{
- assert(data_size > pos);
- return data + pos;
-}
-
-void gst_elements::set_data(const uint8_t* idata) {
- data = idata;
-}
-
-sound_handler* create_sound_handler_gst()
-// Factory.
-{
- return new GST_sound_handler;
-}
-
-} // namespace gnash
-
-#endif // SOUND_GST
-
-// Local Variables:
-// mode: C++
-// End:
-
Index: backend/sound_handler_gst.h
===================================================================
RCS file: backend/sound_handler_gst.h
diff -N backend/sound_handler_gst.h
--- backend/sound_handler_gst.h 26 Sep 2007 07:09:02 -0000 1.18
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,204 +0,0 @@
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-#ifndef SOUND_HANDLER_GST_H
-#define SOUND_HANDLER_GST_H
-
-//#include "gnash.h"
-#include "sound_handler.h" // for inheritance
-
-#include <vector>
-
-#include <gst/gst.h>
-#include <boost/thread/thread.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread/mutex.hpp>
-
-#define BUFFER_SIZE 5000
-
-namespace gnash {
-
-// forward declaration
-class GST_sound_handler;
-
-// Used to hold the gstreamer when doing on-demand-decoding
-class gst_elements
-{
-public:
- // gstreamer pipeline objects
-
- // the main bin containing the adder and output (sink)
- GstElement *pipeline;
- GstElement *audiosink;
-
- // gstreamer objects
- GstElement *input;
- GstElement *decoder;
- GstElement *capsfilter;
- GstElement *audioconvert;
- GstElement *audioresample;
- GstElement *volume;
- GstElement *bin;
- GstPad *addersinkpad;
-
- // position in the stream
- unsigned long position;
-
- // data size
- unsigned long data_size;
-
- long loop_count;
-
- // signal id
- guint handoff_signal_id;
-
- // The sound handler. Used to get access to the
GST_sound_handler->_mutex
- GST_sound_handler* handler;
-
- /// Returns the data pointer in the undecoded datastream
- /// for the given position. Boundaries are checked.
- const uint8_t* get_data_ptr(unsigned long int pos);
-
- /// Set the undecoded data pointer
- void set_data(const uint8_t*);
-
-private:
- // The (un)compressed data
- const guint8* data;
-
-};
-
-
-// Used to hold the sounddata when doing on-demand-decoding
-class sound_data
-{
- // The (un)compressed data
- Buffer _data;
-
-public:
-
- sound_data()
- {}
-
- /// Append size bytes to this sound
- //
- /// @param data
- /// Data bytes, allocated with new[]. Ownership transferred.
- ///
- /// @param size
- /// Size of the 'data' buffer.
- ///
- void append(unsigned char* data, unsigned int size)
- {
- _data.append(data, size);
- }
-
- /// Return data size
- size_t dataSize() const { return _data.size(); }
-
- /// Return data buffer
- const uint8_t* data() { return _data.data(); }
-
- // Object holding information about the sound
- std::auto_ptr<SoundInfo> soundinfo;
-
- // Volume, SWF range: 0-100, GST range 0-10 (we only use 0-1, the rest
is amplified)
- // It's the SWF range that is represented here
- int volume;
-
- // gstreamer objects
- std::vector<gst_elements*> m_gst_elements;
-
-};
-
-// Use gstreamer to handle sounds.
-class GST_sound_handler : public gnash::sound_handler
-{
-private:
- /// Vector containing all the sounds
- std::vector<sound_data*> m_sound_data;
-
- /// Is the loop running?
- bool looping;
-
- /// Is the audio muted?
- bool muted;
-
- /// Mutex for making sure threads doesn't mess things up
- boost::try_mutex _mutex;
-
-public:
-
- /// Gstreamer callback function
- static void callback_handoff (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data);
-
- GST_sound_handler();
- virtual ~GST_sound_handler();
-
- /// Called to create a sound.
- virtual int create_sound(void* data, unsigned int data_bytes,
- std::auto_ptr<SoundInfo> sinfo);
-
- /// this gets called when a stream gets more data
- virtual long fill_stream_data(unsigned char* data, unsigned int
data_bytes,
- unsigned int sample_count, int
handle_id);
-
- /// Play the index'd sample.
- virtual void play_sound(int sound_handle, int loop_count, int offset,
- long start_position, const
std::vector<sound_envelope>* envelopes);
-
- /// Stop the index'd sample.
- virtual void stop_sound(int sound_handle);
-
- /// This gets called when it's done with a sample.
- virtual void delete_sound(int sound_handle);
-
- /// This will stop all sounds playing.
- virtual void stop_all_sounds();
-
- /// Returns the sound volume level as an integer from 0 to 100.
AS-script only.
- virtual int get_volume(int sound_handle);
-
- /// Sets the sound volume level as an integer from 0 to 100. AS-script
only.
- virtual void set_volume(int sound_handle, int volume);
-
- /// Gnash uses this to get info about a sound. Used when a stream needs
more data.
- virtual SoundInfo* get_sound_info(int sound_handle);
-
- /// Gnash calls this to mute audio.
- virtual void mute();
-
- /// Gnash calls this to unmute audio.
- virtual void unmute();
-
- /// Gnash calls this to get the mute state.
- virtual bool is_muted();
-
- /// Gets the duration in milliseconds of an event sound connected to an
AS Sound obejct.
- virtual unsigned int get_duration(int sound_handle);
-
- /// Gets the playhead position in milliseconds of an event sound
connected to an AS Soound obejct.
- virtual unsigned int get_position(int sound_handle);
-
- virtual void attach_aux_streamer(aux_streamer_ptr ptr, void* owner);
//vv
- virtual void detach_aux_streamer(void* owner); //vv
-
-};
-
-} // namespace gnash
-
-#endif // SOUND_HANDLER_GST_H
-
Index: backend/sound_handler_mp3.cpp
===================================================================
RCS file: backend/sound_handler_mp3.cpp
diff -N backend/sound_handler_mp3.cpp
--- backend/sound_handler_mp3.cpp 1 Jul 2007 10:53:49 -0000 1.7
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,250 +0,0 @@
-// sound_handler_mp3.cpp: Audio output via libmad (MP3), for Gnash.
-//
-// Copyright (C) 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-// Based on sound_handler_mp3.cpp by "tbp", 2003
-// which has been donated to the Public Domain.
-
-/*
- * Some brain damaged helpers to decode mp3 streams for use in
- * a gnash::sound_handler that uses SDL for output.
- * (even comments are cut&paste compliant)
- */
-
-/* $Id: sound_handler_mp3.cpp,v 1.7 2007/07/01 10:53:49 bjacques Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef HAVE_MAD_H
-#error "You need to have the libmad development package installed\
-to compile this file. You can either reconfigure without --enable-mp3,\
- or install libmad0-dev (using apt-get) or libmad (using yum)."
-#else
-
-#include "gnash.h"
-#include "container.h"
-#include "log.h"
-
-#include <cstdio>
-
-#include <mad.h>
-#ifdef _MSC_VER
- #pragma comment(lib, "libmad")
- #define snprintf _snprintf
-#endif
-
-using gnash::log_error;
-using gnash::log_msg;
-
-namespace mad_helpers {
- static const char *parse_layer(const mad_header& h)
- {
- switch(h.layer) {
- case MAD_LAYER_I: return "I";
- case MAD_LAYER_II: return "II";
- case MAD_LAYER_III: return "III";
- default: return "bogus";
- }
- }
-
- static const char *parse_channel_mode(const mad_header& h)
- {
- switch (h.mode) {
- case MAD_MODE_SINGLE_CHANNEL:
- return "single channel";
- case MAD_MODE_DUAL_CHANNEL:
- return "dual channel";
- case MAD_MODE_JOINT_STEREO:
- return "joint (MS/intensity) stereo";
- case MAD_MODE_STEREO:
- return "normal LR stereo";
- default:
- return "bogus";
- }
- }
-
- static const char *parse_emphasis(const mad_header& h)
- {
- switch (h.emphasis) {
- case MAD_EMPHASIS_NONE:
- return "none";
- case MAD_EMPHASIS_50_15_US:
- return "50/15 us";
- case MAD_EMPHASIS_CCITT_J_17:
- return "CCITT J.17";
- default:
- return "bogus";
- }
- }
-
-#if 1
- static const char* parse_frame_info(const mad_header& h)
- {
- static char buf[1024];
- size_t len = 1024;
-
- snprintf(buf, len, "%lu kb/s audio mpeg layer %s "
- "stream crc [%s] mode '%s' with '%s' "
- "emphasis at %u Hz sample rate",
- h.bitrate, parse_layer(h),
- (h.flags&MAD_FLAG_PROTECTION) ? "X" : " ",
- parse_channel_mode(h), parse_emphasis(h),
- h.samplerate);
- buf[len-1] = 0;
- return buf;
- }
-#endif
-
- template <const unsigned int stride> static void
pcm_fixed_to_native(const mad_fixed_t *src, int16_t *dst, const unsigned int
count)
- {
- assert(count > 0);
- unsigned int
- dec = count,
- idx = 0;
- do {
- dst[idx*stride] = src[idx] >> (MAD_F_FRACBITS-15); //
no fancy dithering...
- ++idx;
- } while (--dec);
- }
-
-}
-
-// some intermediary buffer to hold a frame worth of samples
-// fugly.
-class pcm_buff_t {
-public:
- //enum { frame_payload = 1152 };
- int16_t *samples;
- unsigned int count;
-
- ~pcm_buff_t() {
- delete samples;
- }
-
- // from mad fixed point to native 16 bits in a temp. buffer
- unsigned int transmogrify(const mad_synth &synth, const bool stereo) {
- count = synth.pcm.length;
- if (stereo) {
- samples = new int16_t[count*2];
-
mad_helpers::pcm_fixed_to_native<2>(&synth.pcm.samples[0][0], &samples[0],
count);
-
mad_helpers::pcm_fixed_to_native<2>(&synth.pcm.samples[1][0], &samples[1],
count);
- return count * 2;
- }
- else {
- samples = new int16_t[count];
-
mad_helpers::pcm_fixed_to_native<1>(&synth.pcm.samples[0][0], samples, count);
- return count;
- }
- }
-
- void *collate(void *p, const bool stereo) const
- {
- const unsigned int bytes = count * (stereo ? 2 : 1) *
sizeof(int16_t);
- memcpy(p, samples, bytes);
- return (void *) (((char *)p) + bytes); // geez
- }
-};
-
-// there's quite some (useless) copying around since there's no infrastructure
-// for streaming and we need to decode it all at once
-void convert_mp3_data(int16_t **adjusted_data, int *adjusted_size, void *data,
- const int sample_count, const int /*sample_size*/,
- const int sample_rate, const bool stereo)
-{
-
- //log_msg("convert_mp3_data sample count %d rate %d stereo %s",
sample_count, sample_rate, stereo?"yes":"no");
-
- mad_stream stream;
- mad_frame frame;
- mad_synth synth;
- mad_timer_t timer;
-
- mad_stream_init(&stream);
- mad_frame_init(&frame);
- mad_synth_init(&synth);
- mad_timer_reset(&timer);
-
- // decode stream
- mad_stream_buffer(&stream, (const unsigned char *)data, sample_count);
- stream.error = MAD_ERROR_NONE;
-
- // decode frames
- unsigned int fc = 0, total = 0;
- std::vector<pcm_buff_t *> out; // holds decoded frames
-
- while (true)
- {
- if (mad_frame_decode(&frame, &stream)) {
- // there's always some garbage in front of the buffer
- // so i guess, it's not so garbagish. anyway, skip.
- if (fc == 0 && stream.error == MAD_ERROR_LOSTSYNC)
- {
- continue;
- }
- else
- {
- // kludge as we stop decoding on LOSTSYNC.
- if (stream.error != MAD_ERROR_LOSTSYNC)
- {
- log_error(_("** MP3 frame error: %s"),
mad_stream_errorstr(&stream));
- }
- break;
- }
- }
-
- if (fc == 0)
- {
- log_msg("%s",
mad_helpers::parse_frame_info(frame.header));
- }
-
- ++fc;
- mad_timer_add(&timer,frame.header.duration);
-
- mad_synth_frame(&synth,&frame);
- pcm_buff_t *pcm = new pcm_buff_t;
- total += pcm->transmogrify(synth, stereo);
- out.push_back(pcm);
- }
-
- if (total == 0) goto cleanup; // yay
-
- log_msg("decoded frames %d bytes %d (diff %d) -- original rate %d", fc,
total, total - sample_count, sample_rate);
-
- // assemble together all decoded frames. another round of memcpy.
- {
- void *p = new int16_t[total];
- *adjusted_data = (int16_t*) p;
- *adjusted_size = total * sizeof(int16_t);
- // stuff all that crap together
- {for (unsigned int i=0; i<out.size(); ++i)
- p = out[i]->collate(p,stereo);
- }
- }
-
-cleanup:
- {for (unsigned int i=0; i<out.size(); ++i) delete out[i]; }
- mad_synth_finish(&synth);
- mad_frame_finish(&frame);
- mad_stream_finish(&stream);
-}
-
-// HAVE_MAD_H
-#endif
-
Index: backend/sound_handler_sdl.cpp
===================================================================
RCS file: backend/sound_handler_sdl.cpp
diff -N backend/sound_handler_sdl.cpp
--- backend/sound_handler_sdl.cpp 25 Sep 2007 18:58:43 -0000 1.85
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,1053 +0,0 @@
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-// Based on sound_handler_sdl.cpp by Thatcher Ulrich http://tulrich.com 2003
-// which has been donated to the Public Domain.
-
-// $Id: sound_handler_sdl.cpp,v 1.85 2007/09/25 18:58:43 strk Exp $
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sound_handler_sdl.h"
-#include "utility.h" // for convert_raw_data
-
-#include "log.h"
-#include <cmath>
-#include <vector>
-#include <SDL.h>
-
-namespace gnash {
-
-SDL_sound_handler::SDL_sound_handler()
- : soundOpened(false),
- soundsPlaying(0),
- muted(false)
-{
- // This is our sound settings
- audioSpec.freq = 44100;
- audioSpec.format = AUDIO_S16SYS; // AUDIO_S8 AUDIO_U8;
- audioSpec.channels = 2;
- audioSpec.callback = SDL_sound_handler::sdl_audio_callback;
- audioSpec.userdata = this;
- audioSpec.samples = 2048; //512 - not enough for
videostream
-}
-
-SDL_sound_handler::~SDL_sound_handler()
-{
- for (size_t i=0, e=m_sound_data.size(); i < e; ++i)
- {
- stop_sound(i);
- delete_sound(i);
- }
- if (soundOpened) SDL_CloseAudio();
-}
-
-
-int SDL_sound_handler::create_sound(
- void* data,
- unsigned int data_bytes,
- std::auto_ptr<SoundInfo> sinfo)
-// Called to create a sample. We'll return a sample ID that
-// can be use for playing it.
-{
-
- assert(sinfo.get());
- sound_data *sounddata = new sound_data;
- if (!sounddata) {
- log_error(_("could not allocate memory for sound data"));
- return -1;
- }
-
- sounddata->data_size = data_bytes;
- sounddata->volume = 100;
- sounddata->soundinfo = sinfo;
-
- int16_t* adjusted_data = 0;
- int adjusted_size = 0;
-
- boost::mutex::scoped_lock lock(_mutex);
-
- switch (sounddata->soundinfo->getFormat())
- {
- case FORMAT_NATIVE16:
-
- if (sounddata->data_size > 0) {
- convert_raw_data(&adjusted_data, &adjusted_size, data,
sounddata->soundinfo->getSampleCount(),
- 2,
sounddata->soundinfo->getSampleRate(), sounddata->soundinfo->isStereo(),
- audioSpec.freq, (audioSpec.channels ==
2 ? true : false));
- if (!adjusted_data) {
- log_error(_("Some kind of error occurred with
sound data"));
- return -1;
- }
- sounddata->data_size = adjusted_size;
- sounddata->data =
reinterpret_cast<uint8_t*>(adjusted_data);
- }
- break;
-
- case FORMAT_MP3:
-#ifndef USE_FFMPEG
-#ifndef USE_MAD
- log_error(_("gnash has not been compiled to handle mp3 audio"));
- return -1;
-#endif
-#endif
- sounddata->data = new Uint8[data_bytes];
- if (!sounddata->data) {
- log_error(_("could not allocate space for data in sound
handler"));
- return -1;
- }
- memcpy(sounddata->data, data, data_bytes);
- break;
-
- //case FORMAT_VORBIS:
-
- case FORMAT_RAW:
- case FORMAT_ADPCM:
- case FORMAT_UNCOMPRESSED:
- // These should have been converted to FORMAT_NATIVE16
- log_error(_("Sound data format not properly converted"));
- return -1;
- break;
-
- case FORMAT_NELLYMOSER:
- log_unimpl("Nellymoser sound format requested, gnash does not
handle it.");
- return -1;
-
- default:
- // Unhandled format.
- log_error(_("unknown sound format %d requested; gnash does not
handle it"), (int)sounddata->soundinfo->getFormat());
- return -1; // Unhandled format, set to NULL.
- }
-
- m_sound_data.push_back(sounddata);
- int sound_id = m_sound_data.size()-1;
-
- return sound_id;
-
-}
-
-// this gets called when a stream gets more data
-long SDL_sound_handler::fill_stream_data(unsigned char* data, unsigned int
data_bytes, unsigned int sample_count, int handle_id)
-{
-
- boost::mutex::scoped_lock lock(_mutex);
- // @@ does a negative handle_id have any meaning ?
- // should we change it to unsigned instead ?
- if (handle_id < 0 || (unsigned int) handle_id+1 > m_sound_data.size())
- {
- delete [] data;
- return -1;
- }
- int start_size = 0;
- sound_data* sounddata = m_sound_data[handle_id];
-
- // Handling of the sound data
- switch (sounddata->soundinfo->getFormat()) {
- case FORMAT_NATIVE16:
- {
- int16_t* adjusted_data = 0;
- int adjusted_size = 0;
-
- convert_raw_data(&adjusted_data, &adjusted_size,
- data, sample_count, 2 /*sample size*/,
- sounddata->soundinfo->getSampleRate(),
sounddata->soundinfo->isStereo(),
- audioSpec.freq, (audioSpec.channels == 2));
- if (!adjusted_data || adjusted_size < 1)
- {
- log_error(_("Some kind of error with resampling sound
data"));
- delete [] data;
- return -1;
- }
-
- // Reallocate the required memory.
- Uint8* tmp_data = new Uint8[adjusted_size +
sounddata->data_size];
- memcpy(tmp_data, sounddata->data, sounddata->data_size);
- memcpy(tmp_data + sounddata->data_size, adjusted_data,
adjusted_size);
- if (sounddata->data_size > 0) delete [] sounddata->data;
- sounddata->data = tmp_data;
-
- start_size = sounddata->data_size;
- sounddata->data_size += adjusted_size;
- std::vector<active_sound*> asounds = sounddata->m_active_sounds;
-
- // If playback has already started, we also update the active
sounds
- for(uint32_t i=0; i < asounds.size(); i++) {
- active_sound* sound = asounds[i];
- sound->raw_data_size = sounddata->data_size;
- sound->set_raw_data(sounddata->data);
- }
- }
- break;
-
- case FORMAT_MP3:
- {
-
- // Reallocate the required memory.
- Uint8* tmp_data = new Uint8[data_bytes + sounddata->data_size];
- memcpy(tmp_data, sounddata->data, sounddata->data_size);
- memcpy(tmp_data + sounddata->data_size, data, data_bytes);
- if (sounddata->data_size > 0) delete [] sounddata->data;
- sounddata->data = tmp_data;
-
- start_size = sounddata->data_size;
- sounddata->data_size += data_bytes;
- std::vector<active_sound*> asounds = sounddata->m_active_sounds;
-
- // If playback has already started, we also update the active
sounds
- for(uint32_t i=0; i < asounds.size(); i++) {
- active_sound* sound = asounds[i];
- sound->set_data(sounddata->data);
- sound->data_size = sounddata->data_size;
- }
-
- }
- break;
-
- default:
- log_error(_("Behavior for this audio codec %d is unknown.
Please send this SWF to the developers"),
(int)(sounddata->soundinfo->getFormat()));
- }
-
- delete [] data;
- return start_size;
-}
-
-
-void SDL_sound_handler::play_sound(int sound_handle, int loop_count, int
offset, long start_position, const std::vector<sound_envelope>* envelopes)
-// Play the index'd sample.
-{
- boost::mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists, or if audio is muted
- if (sound_handle < 0 || static_cast<unsigned int>(sound_handle) >=
m_sound_data.size() || muted)
- {
- // Invalid handle or muted
- return;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- // If this is called from a streamsoundblocktag, we only start if this
- // sound isn't already playing.
- if (start_position > 0 && sounddata->m_active_sounds.size() > 0) {
- return;
- }
-
- // Make sure sound actually got some data
- if (sounddata->data_size < 1) {
- IF_VERBOSE_MALFORMED_SWF(
- log_swferror(_("Trying to play sound with size 0"));
- );
- return;
- }
-
- // Make a "active_sound" for this sound which is later placed on the
vector of instances of this sound being played
- active_sound* sound = new active_sound;
-
- // Copy data-info to the active_sound
- sound->data_size = sounddata->data_size;
- sound->set_data(sounddata->data);
-
- // Set the given options of the sound
- if (start_position < 0) sound->position = 0;
- else sound->position = start_position;
-
- if (offset < 0) sound->offset = 0;
- else sound->offset = (sounddata->soundinfo->isStereo() ? offset :
offset*2); // offset is stored as stereo
-
- sound->envelopes = envelopes;
- sound->current_env = 0;
- sound->samples_played = 0;
-
- // Set number of loop we should do. -1 is infinte loop, 0 plays it
once, 1 twice etc.
- sound->loop_count = loop_count;
-
- if (sounddata->soundinfo->getFormat() == FORMAT_MP3) {
-
-#ifdef USE_FFMPEG
- // Init the avdecoder-decoder
- avcodec_init();
- avcodec_register_all();// change this to only register mp3?
- sound->codec = avcodec_find_decoder(CODEC_ID_MP3);
-
- // Init the parser
- sound->parser = av_parser_init(CODEC_ID_MP3);
-
- if (!sound->codec) {
- log_error(_("Your FFMPEG can't decode MP3?!"));
- return;
- }
-
- sound->cc = avcodec_alloc_context();
- avcodec_open(sound->cc, sound->codec);
-
-#elif defined(USE_MAD)
- // Init the mad decoder
- mad_stream_init(&sound->stream);
- mad_frame_init(&sound->frame);
- mad_synth_init(&sound->synth);
-#endif
-
- sound->set_raw_data(NULL);
- sound->raw_position = 0;
- sound->raw_data_size = 0;
-
- } else {
- sound->raw_data_size = sounddata->data_size;
- sound->set_raw_data(sounddata->data);
- sound->raw_position = 0;
- sound->position = 0;
- sound->data_size = 0;
-
- }
-
- if (!soundOpened) {
- if (SDL_OpenAudio(&audioSpec, NULL) < 0 ) {
- log_error(_("Unable to start SDL sound: %s"),
SDL_GetError());
- return;
- }
- soundOpened = true;
-
- }
-
- ++soundsPlaying;
- ++_soundsStarted;
- sounddata->m_active_sounds.push_back(sound);
-
- if (soundsPlaying == 1) {
- SDL_PauseAudio(0);
- }
-
-}
-
-
-void SDL_sound_handler::stop_sound(int sound_handle)
-{
- boost::mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- } else {
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- for (int32_t i = (int32_t) sounddata->m_active_sounds.size()-1;
i >-1; i--) {
-
- active_sound* sound = sounddata->m_active_sounds[i];
-
- // Stop sound, remove it from the active list (mp3)
- if (sounddata->soundinfo->getFormat() == FORMAT_MP3) {
-#ifdef USE_FFMPEG
- avcodec_close(sound->cc);
- av_parser_close(sound->parser);
-#elif defined(USE_MAD)
- mad_synth_finish(&sound->synth);
- mad_frame_finish(&sound->frame);
- mad_stream_finish(&sound->stream);
-#endif
- sound->delete_raw_data();
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + i);
-
- // Stop sound, remove it from the active list
(adpcm/native16)
- } else {
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + i);
- }
- --soundsPlaying;
- ++_soundsStopped;
- }
- }
-
-}
-
-
-// this gets called when it's done with a sample.
-void SDL_sound_handler::delete_sound(int sound_handle)
-{
- boost::mutex::scoped_lock lock(_mutex);
-
- if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
- {
- delete m_sound_data[sound_handle];
- m_sound_data[sound_handle] = NULL;
- }
-
-}
-
-// This will stop all sounds playing. Will cause problems if the soundhandler
is made static
-// and supplys sound_handling for many SWF's, since it will stop all sounds
with no regard
-// for what sounds is associated with what SWF.
-void SDL_sound_handler::stop_all_sounds()
-{
- boost::mutex::scoped_lock lock(_mutex);
-
- int32_t num_sounds = (int32_t) m_sound_data.size()-1;
- for (int32_t j = num_sounds; j > -1; j--) {//Optimized
- sound_data* sounddata = m_sound_data[j];
- int32_t num_active_sounds = (int32_t)
sounddata->m_active_sounds.size()-1;
- for (int32_t i = num_active_sounds; i > -1; i--) {
-
- active_sound* sound = sounddata->m_active_sounds[i];
-
- // Stop sound, remove it from the active list (mp3)
- if (sounddata->soundinfo->getFormat() == FORMAT_MP3) {
-#ifdef USE_FFMPEG
- avcodec_close(sound->cc);
- av_parser_close(sound->parser);
-#elif defined(USE_MAD)
- mad_synth_finish(&sound->synth);
- mad_frame_finish(&sound->frame);
- mad_stream_finish(&sound->stream);
-#endif
- sound->delete_raw_data();
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + i);
- soundsPlaying--;
-
- // Stop sound, remove it from the active list
(adpcm/native16)
- } else {
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + i);
- soundsPlaying--;
- }
- }
- }
-}
-
-
-// returns the sound volume level as an integer from 0 to 100,
-// where 0 is off and 100 is full volume. The default setting is 100.
-int SDL_sound_handler::get_volume(int sound_handle) {
-
- boost::mutex::scoped_lock lock(_mutex);
-
- int ret;
- // Check if the sound exists.
- if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
- {
- ret = m_sound_data[sound_handle]->volume;
- } else {
- ret = 0; // Invalid handle
- }
- return ret;
-}
-
-
-// A number from 0 to 100 representing a volume level.
-// 100 is full volume and 0 is no volume. The default setting is 100.
-void SDL_sound_handler::set_volume(int sound_handle, int volume) {
-
- boost::mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || static_cast<unsigned int>(sound_handle) >=
m_sound_data.size())
- {
- // Invalid handle.
- } else {
-
- // Set volume for this sound. Should this only apply to the
active sounds?
- m_sound_data[sound_handle]->volume = volume;
- }
-
-
-}
-
-SoundInfo* SDL_sound_handler::get_sound_info(int sound_handle) {
-
- boost::mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle >= 0 && static_cast<unsigned int>(sound_handle) <
m_sound_data.size())
- {
- return m_sound_data[sound_handle]->soundinfo.get();
- } else {
- return NULL;
- }
-
-}
-
-// gnash calls this to mute audio
-void SDL_sound_handler::mute() {
- stop_all_sounds();
- muted = true;
-}
-
-// gnash calls this to unmute audio
-void SDL_sound_handler::unmute() {
- muted = false;
-}
-
-bool SDL_sound_handler::is_muted()
-{
- return muted;
-}
-
-void SDL_sound_handler::attach_aux_streamer(aux_streamer_ptr ptr, void*
owner)
-{
- boost::mutex::scoped_lock lock(_mutex);
- assert(owner);
- assert(ptr);
-
- aux_streamer_ptr p;
- if (m_aux_streamer.get(owner, &p))
- {
- // Already in the hash.
- return;
- }
- m_aux_streamer[owner] = ptr;
-
- ++soundsPlaying;
-
- if (!soundOpened) {
- if (SDL_OpenAudio(&audioSpec, NULL) < 0 ) {
- log_error(_("Unable to start aux SDL sound: %s"),
SDL_GetError());
- return;
- }
- soundOpened = true;
- }
- SDL_PauseAudio(0);
-
-}
-
-void SDL_sound_handler::detach_aux_streamer(void* owner)
-{
- boost::mutex::scoped_lock lock(_mutex);
- aux_streamer_ptr p;
- if (m_aux_streamer.get(owner, &p))
- {
- --soundsPlaying;
- m_aux_streamer.erase(owner);
- }
-
-}
-
-unsigned int SDL_sound_handler::get_duration(int sound_handle)
-{
- boost::mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- return 0;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- uint32_t sampleCount = sounddata->soundinfo->getSampleCount();
- uint32_t sampleRate = sounddata->soundinfo->getSampleRate();
-
- // Return the sound duration in milliseconds
- if (sampleCount > 0 && sampleRate > 0) {
- unsigned int ret = sampleCount / sampleRate * 1000;
- ret += ((sampleCount % sampleRate) * 1000) / sampleRate;
- if (sounddata->soundinfo->isStereo()) ret = ret / 2;
- return ret;
- } else {
- return 0;
- }
-}
-
-unsigned int SDL_sound_handler::get_position(int sound_handle)
-{
- boost::mutex::scoped_lock lock(_mutex);
-
- // Check if the sound exists.
- if (sound_handle < 0 || (unsigned int) sound_handle >=
m_sound_data.size())
- {
- // Invalid handle.
- return 0;
- }
-
- sound_data* sounddata = m_sound_data[sound_handle];
-
- // If there is no active sounds, return 0
- if (sounddata->m_active_sounds.size() == 0) return 0;
-
- // We use the first active sound of this.
- active_sound* asound = sounddata->m_active_sounds[0];
-
- // Return the playhead position in milliseconds
- unsigned int ret = asound->samples_played / audioSpec.freq * 1000;
- ret += ((asound->samples_played % audioSpec.freq) * 1000) /
audioSpec.freq;
- if (audioSpec.channels > 1) ret = ret / audioSpec.channels;
- return ret;
-}
-
-sound_handler*
-create_sound_handler_sdl()
-// Factory.
-{
- return new SDL_sound_handler;
-}
-
-
-// Pointer handling and checking functions
-uint8_t* active_sound::get_raw_data_ptr(unsigned long int pos) {
- assert(raw_data_size > pos);
- return raw_data + pos;
-}
-
-uint8_t* active_sound::get_data_ptr(unsigned long int pos) {
- assert(data_size > pos);
- return data + pos;
-}
-
-void active_sound::set_raw_data(uint8_t* iraw_data) {
- raw_data = iraw_data;
-}
-
-void active_sound::set_data(uint8_t* idata) {
- data = idata;
-}
-
-void active_sound::delete_raw_data() {
- delete [] raw_data;
-}
-
-// AS-volume adjustment
-void adjust_volume(int16_t* data, int size, int volume)
-{
- for (int i=0; i < size*0.5; i++) {
- data[i] = data[i] * volume/100;
- }
-}
-
-// envelope-volume adjustment
-static void
-use_envelopes(active_sound* sound, unsigned int length)
-{
- // Check if this is the time to use envelopes yet
- if (sound->current_env == 0 && (*sound->envelopes)[0].m_mark44 >
sound->samples_played+length/2)
- {
- return;
-
- }
- // switch to the next envelope if needed and possible
- else if (sound->current_env < sound->envelopes->size()-1 &&
(*sound->envelopes)[sound->current_env+1].m_mark44 >= sound->samples_played)
- {
- sound->current_env++;
- }
-
- // Current envelope position
- int32_t cur_env_pos =
sound->envelopes->operator[](sound->current_env).m_mark44;
-
- // Next envelope position
- uint32_t next_env_pos = 0;
- if (sound->current_env == (sound->envelopes->size()-1)) {
- // If there is no "next envelope" then set the next envelope
start point to be unreachable
- next_env_pos = cur_env_pos + length;
- } else {
- next_env_pos =
(*sound->envelopes)[sound->current_env+1].m_mark44;
- }
-
- unsigned int startpos = 0;
- // Make sure we start adjusting at the right sample
- if (sound->current_env == 0 &&
(*sound->envelopes)[sound->current_env].m_mark44 > sound->samples_played) {
- startpos = sound->raw_position +
((*sound->envelopes)[sound->current_env].m_mark44 - sound->samples_played)*2;
- } else {
- startpos = sound->raw_position;
- }
-
- int16_t* data =
reinterpret_cast<int16_t*>(sound->get_raw_data_ptr(startpos));
-
- for (unsigned int i=0; i < length/2; i+=2) {
- float left =
static_cast<float>((*sound->envelopes)[sound->current_env].m_level0 / 32768.0);
- float right =
static_cast<float>((*sound->envelopes)[sound->current_env].m_level1 / 32768.0);
-
- data[i] = static_cast<int16_t>(data[i] * left); // Left
- data[i+1] = static_cast<int16_t>(data[i+1] * right); // Right
-
- if ((sound->samples_played+(length/2-i)) >= next_env_pos &&
sound->current_env != (sound->envelopes->size()-1)) {
- sound->current_env++;
- // Next envelope position
- if (sound->current_env == (sound->envelopes->size()-1))
{
- // If there is no "next envelope" then set the
next envelope start point to be unreachable
- next_env_pos = cur_env_pos + length;
- } else {
- next_env_pos =
(*sound->envelopes)[sound->current_env+1].m_mark44;
- }
- }
- }
-}
-
-
-// Prepare for mixing/adding (volume adjustments) and mix/add.
-static void
-do_mixing(Uint8* stream, active_sound* sound, Uint8* data, unsigned int
mix_length, unsigned int volume) {
- // If the volume needs adjustments we call a function to do that
- if (volume != 100) {
- adjust_volume(reinterpret_cast<int16_t*>(data), mix_length,
volume);
- } else if (sound->envelopes != NULL) {
- use_envelopes(sound, mix_length);
- }
-
- // Mix the raw data
- SDL_MixAudio(static_cast<Uint8*>(stream),static_cast<const
Uint8*>(data), mix_length, SDL_MIX_MAXVOLUME);
-
- // Update sound info
- sound->raw_position += mix_length;
-
- // Sample size is always 2
- sound->samples_played += mix_length / 2;
-}
-
-
-// Callback invoked by the SDL audio thread.
-void SDL_sound_handler::sdl_audio_callback (void *udata, Uint8 *stream, int
buffer_length_in)
-{
- if ( buffer_length_in < 0 )
- {
- log_error(_("Negative buffer length in sdl_audio_callback
(%d)"), buffer_length_in);
- return;
- }
-
- if ( buffer_length_in == 0 )
- {
- log_error(_("Zero buffer length in sdl_audio_callback"));
- return;
- }
-
- unsigned int buffer_length = static_cast<unsigned
int>(buffer_length_in);
-
- // Get the soundhandler
- SDL_sound_handler* handler = static_cast<SDL_sound_handler*>(udata);
-
- // If nothing to play there is no reason to play
- // Is this a potential deadlock problem?
- if (handler->soundsPlaying == 0 && handler->m_aux_streamer.size() == 0)
{
- SDL_PauseAudio(1);
- return;
- }
-
- boost::mutex::scoped_lock lock(handler->_mutex);
-
- // Mixed sounddata buffer
- Uint8* buffer = stream;
- memset(buffer, 0, buffer_length);
-
- // call NetStream or Sound audio callbacks
- if (handler->m_aux_streamer.size() > 0)
- {
- uint8_t* buf = new uint8_t[buffer_length];
-
- // Loop through the attached sounds
- hash_wrapper< void*, sound_handler::aux_streamer_ptr
>::iterator it = handler->m_aux_streamer.begin();
- hash_wrapper< void*, sound_handler::aux_streamer_ptr
>::iterator end = handler->m_aux_streamer.end();
- while (it != end) {
- memset(buf, 0, buffer_length);
-
- SDL_sound_handler::aux_streamer_ptr aux_streamer =
it->second; //handler->m_aux_streamer[i]->ptr;
- void* owner = it->first;
-
- // If false is returned the sound doesn't want to be
attached anymore
- bool ret = (aux_streamer)(owner, buf, buffer_length);
- if (!ret) {
- handler->m_aux_streamer.erase(it++);
- handler->soundsPlaying--;
- } else {
- ++it;
- }
- SDL_MixAudio(stream, buf, buffer_length,
SDL_MIX_MAXVOLUME);
-
- }
- delete [] buf;
- }
-
- // Run through all the sounds.
- for(uint32_t i=0; i < handler->m_sound_data.size(); i++) {
- sound_data* sounddata = handler->m_sound_data[i];
- for(uint32_t j = 0; j < sounddata->m_active_sounds.size(); j++)
{
-
- // Temp variables to make the code simpler and easier
to read
- active_sound* sound = sounddata->m_active_sounds[j];
- format_type soundFormat =
sounddata->soundinfo->getFormat();
- bool soundStereo = sounddata->soundinfo->isStereo();
- uint32_t soundSampleRate =
sounddata->soundinfo->getSampleRate();
-
- // When the current sound dont have enough decoded data
to fill the buffer,
- // we first mix what is already decoded, then decode
some more data, and
- // mix some more until the buffer is full. If a sound
loops the magic
- // happens here ;)
- if (sound->raw_data_size - sound->raw_position <
buffer_length
- && (sound->position < sound->data_size ||
sound->loop_count != 0)) {
-
- // First we mix what is decoded
- unsigned int index = 0;
- if (sound->raw_data_size - sound->raw_position
> 0) {
- index = sound->raw_data_size -
sound->raw_position;
-
- do_mixing(stream, sound,
sound->get_raw_data_ptr(sound->raw_position),
- index, sounddata->volume);
-
- }
-
- // If this isn't MP3 (which means its NATIVE16)
there is nothing to decode,
- // reusing the available data is the only
option.
- if (soundFormat != FORMAT_MP3) {
- if (index < buffer_length) {
- sound->loop_count--;
- sound->raw_position = 0;
- sound->samples_played = 0;
- unsigned int mix_length =
((buffer_length - index) > sound->raw_data_size ? sound->raw_data_size :
(buffer_length - index));
- do_mixing(stream+index, sound,
sound->get_raw_data_ptr(sound->raw_position),
- mix_length,
sounddata->volume);
- }
- continue;
- }
-
- // Then we decode some data
- // We loop until the size of the decoded sound
is greater than the buffer size,
- // or there is no more to decode.
- unsigned int decoded_size = 0;
- sound->raw_data_size = 0;
- while(decoded_size < buffer_length) {
-
- // If we need to loop, we reset the
data pointer
- if (sound->data_size == sound->position
&& sound->loop_count != 0) {
- sound->loop_count--;
- sound->position = 0;
- sound->samples_played = 0;
- }
-
- // Test if we will get problems...
Should not happen...
- assert(sound->data_size >
sound->position);
-
- // temp raw buffer
- Uint8* tmp_raw_buffer;
- unsigned int tmp_raw_buffer_size;
- int outsize = 0;
-
-#ifdef USE_FFMPEG
- tmp_raw_buffer = new
Uint8[AVCODEC_MAX_AUDIO_FRAME_SIZE];
- tmp_raw_buffer_size =
AVCODEC_MAX_AUDIO_FRAME_SIZE;
-
- long bytes_decoded = 0;
-
- while (outsize == 0 && sound->position
< sound->data_size) {
- uint8_t* frame;
- int framesize;
-
- bytes_decoded =
av_parser_parse(sound->parser, sound->cc, &frame, &framesize,
-
static_cast<uint8_t *>(sound->get_data_ptr(sound->position)), sound->data_size
- sound->position,
- 0 ,0);
//pts, dts
-
- int tmp = 0;
-#ifdef FFMPEG_AUDIO2
- outsize =
AVCODEC_MAX_AUDIO_FRAME_SIZE;
- tmp =
avcodec_decode_audio2(sound->cc, (int16_t*)(tmp_raw_buffer), &outsize, frame,
framesize);
-#else
- tmp =
avcodec_decode_audio(sound->cc, (int16_t*)(tmp_raw_buffer), &outsize, frame,
framesize);
-#endif
-
- if (bytes_decoded < 0 || tmp <
0 || outsize < 0) {
- log_error(_("Error
while decoding MP3-stream. Upgrading ffmpeg/libavcodec might fix this
issue."));
- // Setting data
position to data size will get the sound removed
- // from the active
sound list later on.
- sound->position =
sound->data_size;
- break;
- }
-
- sound->position +=
bytes_decoded;
- }
-
-#elif defined(USE_MAD)
-
- // Setup the mad decoder
- mad_stream_buffer(&sound->stream,
sound->get_data_ptr(sound->position), sound->data_size-sound->position);
-
- int ret;
- const unsigned char* old_next_frame =
sound->stream.next_frame;
- int loops = 0;
- while(true) {
-
- ret =
mad_frame_decode(&sound->frame, &sound->stream);
- loops++;
-
- // There is always some junk in
front of the data,
- // so we continue until we get
past it.
- if (ret && sound->stream.error
== MAD_ERROR_LOSTSYNC) continue;
-
- // Error handling is done by
relooping (max. 8 times) and just hooping that it will work...
- if (loops > 8) break;
- if (ret == -1 &&
sound->stream.error != MAD_ERROR_BUFLEN &&
MAD_RECOVERABLE(sound->stream.error)) {
-
log_error(_("Recoverable error while decoding MP3-stream, MAD error: %s"),
mad_stream_errorstr (&sound->stream));
- continue;
- }
-
- break;
- }
-
- if (ret == -1 && sound->stream.error !=
MAD_ERROR_BUFLEN) {
- log_error(_("Unrecoverable
error while decoding MP3-stream, MAD error: %s"), mad_stream_errorstr
(&sound->stream));
- sound->position =
sound->data_size;
- continue;
- } else if (ret == -1 &&
sound->stream.error == MAD_ERROR_BUFLEN) {
- // the buffer is empty, no more
to decode!
- sound->position =
sound->data_size;
- } else {
- sound->position +=
sound->stream.next_frame - old_next_frame;
- }
-
- mad_synth_frame (&sound->synth,
&sound->frame);
-
- outsize = sound->synth.pcm.length *
((soundStereo == true) ? 4 : 2);
-
- tmp_raw_buffer = new Uint8[outsize];
- int sample;
-
- int16_t* dst =
reinterpret_cast<int16_t*>(tmp_raw_buffer);
-
- // transfer the decoded samples into
the sound-struct, and do some
- // scaling while we're at it.
- for(int f = 0; f <
sound->synth.pcm.length; f++)
- {
- for (int e = 0; e <
((soundStereo == true) ? 2 : 1); e++){ // channels (stereo/mono)
-
- mad_fixed_t mad_sample
= sound->synth.pcm.samples[e][f];
-
- // round
- mad_sample += (1L <<
(MAD_F_FRACBITS - 16));
-
- // clip
- if (mad_sample >=
MAD_F_ONE) mad_sample = MAD_F_ONE - 1;
- else if (mad_sample <
-MAD_F_ONE) mad_sample = -MAD_F_ONE;
-
- // quantize
- sample = mad_sample >>
(MAD_F_FRACBITS + 1 - 16);
-
- if ( sample !=
static_cast<int16_t>(sample) ) sample = sample < 0 ? -32768 : 32767;
-
- *dst++ = sample;
- }
- }
-#endif // defined(USE_MAD)
-
- // If we need to convert samplerate
or/and from mono to stereo...
- if (outsize > 0 &&
(static_cast<int>(soundSampleRate) != handler->audioSpec.freq || !soundStereo))
{
-
- int16_t* adjusted_data = 0;
- int adjusted_size = 0;
- int sample_count = outsize /
((soundStereo == true) ? 4 : 2);
-
- // Convert to needed samplerate
-
convert_raw_data(&adjusted_data, &adjusted_size, tmp_raw_buffer, sample_count,
0,
-
soundSampleRate, soundStereo,
-
handler->audioSpec.freq, (handler->audioSpec.channels == 2 ? true : false));
-
- // Hopefully this wont happen
- if (!adjusted_data) {
- log_error(_("Error in
sound sample conversion"));
- continue;
- }
-
- // Move the new data to the
sound-struct
- delete[] tmp_raw_buffer;
- tmp_raw_buffer =
reinterpret_cast<Uint8*>(adjusted_data);
- tmp_raw_buffer_size =
adjusted_size;
-
- } else {
- tmp_raw_buffer_size = outsize;
- }
-
- Uint8* tmp_buf = new Uint8[decoded_size
+ tmp_raw_buffer_size];
- sound->raw_data_size = 1;
- memcpy(tmp_buf,
sound->get_raw_data_ptr(0), decoded_size);
- memcpy(tmp_buf+decoded_size,
tmp_raw_buffer, tmp_raw_buffer_size);
- decoded_size += tmp_raw_buffer_size;
- sound->delete_raw_data();
- sound->set_raw_data(tmp_buf);
- delete[] tmp_raw_buffer;
-
- // no more to decode from this sound,
so we break the loop
- if (sound->data_size <= sound->position
&& sound->loop_count == 0) {
- break;
- }
-
- } // end of "decode min. bufferlength data"
while loop
-
- sound->raw_data_size = decoded_size;
-
- sound->raw_position = 0;
-
- // Determine how much should be mixed
- unsigned int mix_length = 0;
- if (decoded_size >= buffer_length - index) {
- mix_length = buffer_length - index;
- } else {
- mix_length = decoded_size;
- }
- if (sound->raw_data_size < 2) continue; //
something went terrible wrong
- do_mixing(stream+index, sound,
sound->get_raw_data_ptr(0), mix_length, sounddata->volume);
-
- // When the current sound has enough decoded data to
fill
- // the buffer, we do just that.
- } else if (sound->raw_data_size - sound->raw_position >
buffer_length ) {
-
- do_mixing(stream, sound,
sound->get_raw_data_ptr(sound->raw_position),
- buffer_length, sounddata->volume);
-
- // When the current sound doesn't have anymore data to
decode,
- // and doesn't loop (anymore), but still got unplayed
data,
- // we put the last data on the stream
- } else if (sound->raw_data_size - sound->raw_position
<= buffer_length && sound->raw_data_size > sound->raw_position+1) {
-
-
- do_mixing(stream, sound,
sound->get_raw_data_ptr(sound->raw_position),
- sound->raw_data_size -
sound->raw_position, sounddata->volume);
-
- sound->raw_position = sound->raw_data_size;
- }
-
- // Sound is done, remove it from the active list (mp3)
- if (sound->position == sound->data_size &&
sound->loop_count == 0 && soundFormat == FORMAT_MP3) {
-#ifdef USE_FFMPEG
- avcodec_close(sound->cc);
- av_parser_close(sound->parser);
-#elif defined(USE_MAD)
- mad_synth_finish(&sound->synth);
- mad_frame_finish(&sound->frame);
- mad_stream_finish(&sound->stream);
-#endif
- sound->delete_raw_data();
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + j);
- handler->soundsPlaying--;
- handler->_soundsStopped++;
-
-
- // Sound is done, remove it from the active list
(adpcm/native16)
- } else if (sound->loop_count == 0 && soundFormat ==
FORMAT_NATIVE16 && sound->raw_position >= sound->raw_data_size &&
sound->raw_data_size != 0) {
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + j);
- handler->soundsPlaying--;
- handler->_soundsStopped++;
- } else if (sound->raw_position == 0 &&
sound->raw_data_size == 0) {
-
sounddata->m_active_sounds.erase(sounddata->m_active_sounds.begin() + j);
- handler->soundsPlaying--;
- handler->_soundsStopped++;
- }
-
- } // active sounds loop
- } // existing sounds loop
-
-}
-
-} // namespace gnash
-
-// Local Variables:
-// mode: C++
-// End:
-
Index: backend/sound_handler_sdl.h
===================================================================
RCS file: backend/sound_handler_sdl.h
diff -N backend/sound_handler_sdl.h
--- backend/sound_handler_sdl.h 25 Sep 2007 18:58:43 -0000 1.33
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,258 +0,0 @@
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-// $Id: sound_handler_sdl.h,v 1.33 2007/09/25 18:58:43 strk Exp $
-
-#ifndef SOUND_HANDLER_SDL_H
-#define SOUND_HANDLER_SDL_H
-
-
-#include "sound_handler.h" // for inheritance
-#include "hash_wrapper.h"
-
-#include "log.h"
-
-#ifdef USE_FFMPEG
-extern "C" {
-#include <ffmpeg/avcodec.h>
-}
-#elif defined(USE_MAD)
-#include <mad.h>
-#endif
-
-#include <vector>
-
-#include <SDL_audio.h>
-#include <boost/thread/thread.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread/mutex.hpp>
-
-namespace gnash {
-
-/// Used to hold the info about active sounds
-class active_sound
-{
-public:
-#ifdef USE_FFMPEG
- /// ffmpeg stuff
- AVCodec *codec;
- AVCodecContext *cc;
- AVCodecParserContext* parser;
-#elif defined(USE_MAD)
- /// mad stuff
- mad_stream stream;
- mad_frame frame;
- mad_synth synth;
-#endif
-
- /// The size of the undecoded data
- unsigned long data_size;
-
- /// Current decoding position in the stream
- unsigned long position;
-
- /// Size of the decoded data
- unsigned long raw_data_size;
-
- /// Current playing position in the decoded stream
- unsigned long raw_position;
-
- /// Numbers of loops: -1 means loop forever, 0 means play once.
- /// For every loop completed, it is decremented.
- long loop_count;
-
- /// Offset to make playback start in-sync, only used with mp3 streams.
- unsigned int offset;
-
- /// Sound envelopes for the current sound, which determine the volume
level
- /// from a given position. Only used with sound events.
- const std::vector<gnash::sound_handler::sound_envelope>* envelopes;
-
- /// Index of current envelope.
- uint32_t current_env;
-
- /// Number of samples played so far.
- unsigned long samples_played;
-
- /// Returns the data pointer in the undecoded datastream
- /// for the given position. Boundaries are checked.
- uint8_t* get_data_ptr(unsigned long int pos);
-
- /// Returns the data pointer in the decoded datastream
- /// for the given position. Boundaries are checked.
- uint8_t* get_raw_data_ptr(unsigned long int pos);
-
- /// Set the undecoded data pointer
- void set_data(uint8_t*);
-
- /// Set the decoded data pointer
- void set_raw_data(uint8_t*);
-
- /// Deletes the decoded data
- void delete_raw_data();
-
-private:
- /// The undecoded data
- uint8_t* data;
-
- /// The decoded data
- uint8_t* raw_data;
-
-};
-
-
-/// Used to hold the sounddata when doing on-demand-decoding
-class sound_data
-{
-public:
- /// The undecoded data
- //
- /// TODO: use boost::scoped_array
- uint8_t* data;
-
- /// Object holding information about the sound
- std::auto_ptr<SoundInfo> soundinfo;
-
- /// The size of the undecoded data
- unsigned int data_size;
-
- /// Volume for AS-sounds, range: 0-100.
- /// It's the SWF range that is represented here.
- int volume;
-
- /// Vector containing the active instances of this sounds being played
- //
- /// TODO: define ownership of the active_sound elements
- ///
- std::vector<active_sound*> m_active_sounds;
-
- ~sound_data()
- {
- // TODO: use boost::scoped_array
- delete [] data;
- }
-
-};
-
-
-// Use SDL and ffmpeg/mad/nothing to handle sounds.
-class SDL_sound_handler : public gnash::sound_handler
-{
-private:
- /// NetStream audio callbacks
- hash_wrapper< void* /* owner */, aux_streamer_ptr /* callback */>
m_aux_streamer; //vv
-
- /// Vector containing all sounds.
- std::vector<sound_data*> m_sound_data;
-
- /// Is sound device opened?
- bool soundOpened;
-
- /// The SDL_audio specs
- SDL_AudioSpec audioSpec;
-
- /// Keeps track of numbers of playing sounds
- int soundsPlaying;
-
- /// Is the audio muted?
- bool muted;
-
- /// Mutex for making sure threads doesn't mess things up
- boost::mutex _mutex;
-
-public:
- SDL_sound_handler();
- virtual ~SDL_sound_handler();
-
- /// Called to create a sound.
- virtual int create_sound(void* data, unsigned int data_bytes,
std::auto_ptr<SoundInfo> sinfo);
-
- /// this gets called when a stream gets more data
- virtual long fill_stream_data(unsigned char* data, unsigned int
data_bytes,
- unsigned int sample_count, int
handle_id);
-
- /// Play the index'd sample.
- virtual void play_sound(int sound_handle, int loop_count, int offset,
- long start_position, const
std::vector<sound_envelope>* envelopes);
-
- /// Stop the index'd sample.
- virtual void stop_sound(int sound_handle);
-
- /// This gets called when it's done with a sample.
- virtual void delete_sound(int sound_handle);
-
- /// This will stop all sounds playing.
- virtual void stop_all_sounds();
-
- /// Returns the sound volume level as an integer from 0 to 100.
AS-script only.
- virtual int get_volume(int sound_handle);
-
- /// Sets the sound volume level as an integer from 0 to 100. AS-script
only.
- virtual void set_volume(int sound_handle, int volume);
-
- /// Gnash uses this to get info about a sound. Used when a stream needs
more data.
- virtual SoundInfo* get_sound_info(int sound_handle);
-
- /// Gnash calls this to mute audio.
- virtual void mute();
-
- /// Gnash calls this to unmute audio.
- virtual void unmute();
-
- /// Gnash calls this to get the mute state.
- virtual bool is_muted();
-
- /// Gets the duration in milliseconds of an event sound connected to an
AS Sound obejct.
- virtual unsigned int get_duration(int sound_handle);
-
- /// Gets the playhead position in milliseconds of an event sound
connected to an AS Soound obejct.
- virtual unsigned int get_position(int sound_handle);
-
- virtual void attach_aux_streamer(aux_streamer_ptr ptr, void* owner);
//vv
- virtual void detach_aux_streamer(void* owner); //vv
-
- /// Callback invoked by the SDL audio thread.
- //
- /// Refills the output stream/buffer with data.
- ///
- /// We run trough all the attached auxiliary streamers fetching decoded
- /// audio blocks and mixing them into the given output stream.
- ///
- /// If sound is compresssed (mp3) a mp3-frame is decoded into a buffer,
- /// and resampled if needed. When the buffer has been sampled, another
- /// frame is decoded until all frames has been decoded.
- /// If a sound is looping it will be decoded from the beginning again.
- ///
- /// TODO: make a static method of the SDL_sound_handler class
- ///
- /// @param udata
- /// User data pointer (SDL_sound_handler instance in our case).
- /// We'll lock the SDL_sound_handler::_mutex during operations.
- ///
- /// @param stream
- /// The output stream/buffer to fill
- ///
- /// @param buffer_length_in
- /// Length of the buffer.
- /// If zero or negative we log an error and return
- /// (negative is probably an SDL bug, zero dunno yet).
- ///
- static void sdl_audio_callback (void *udata, Uint8 *stream, int
buffer_length_in);
-};
-
-} // namespace gnash
-
-#endif // SOUND_HANDLER_SDL_H
Index: libbase/embedVideoDecoder.h
===================================================================
RCS file: libbase/embedVideoDecoder.h
diff -N libbase/embedVideoDecoder.h
--- libbase/embedVideoDecoder.h 1 Jul 2007 10:54:07 -0000 1.9
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,120 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-//
-//
-//
-
-// $Id: embedVideoDecoder.h,v 1.9 2007/07/01 10:54:07 bjacques Exp $
-
-#ifndef __EMBEDVIDEODECODER_H__
-#define __EMBEDVIDEODECODER_H__
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "image.h"
-#include "log.h"
-
-namespace gnash {
-
-///
-/// \brief
-/// The embedVideoDecoder is used to decodes a video frame which has been
-/// embedded in a SWF.
-///
-class embedVideoDecoder
-{
-public:
-
- /// This is copied from the render and should be changed if the
original is.
- enum videoOutputFormat
- {
- NONE,
- YUV,
- RGB
- };
-
- /// Codecs type we know of
- enum codecType
- {
- CODEC_H263 = 2, // H263/SVQ3 video codec
- CODEC_SCREENVIDEO = 3, // Screenvideo codec
- CODEC_VP6 = 4, // On2 VP6 video codec
- CODEC_VP6A = 5, // On2 VP6 Alpha video codec
- CODEC_SCREENVIDEO2 = 6 // Screenvideo2 codec
- };
-
- /// Sets up the decoder.
- //
- /// @param width
- /// The width of the video
- ///
- /// @param height
- /// The height of the video
- ///
- /// @param deblocking
- /// Should a deblocking filter be used? 1 = off, 2 = on
- ///
- /// @param smoothing
- /// Should the video be smoothed?
- ///
- /// @param format
- /// The codec of the video, see codecType
- ///
- /// @param outputFormat
- /// The outputFormat of the video, see videoOutputFormat
- ///
- /// The default implementation is a no-op
- ///
- /// TODO: shouldn't this initialization be done by the constructor ?
- ///
- virtual void createDecoder(int /*width*/,
- int /*height*/,
- int /*deblocking*/,
- bool /*smoothing*/,
- int /*format*/, // should this argument be of codecType type ?
- int /*outputFormat*/) // should this argument be of
VideoOutputFormat type ?
- {}
-
- /// gnash calls this when it wants to decode the given videoframe.
- //
- /// @param data
- /// The video frame that is to be decoded.
- /// Data is expected to be in the format specified with the
- /// "format" parameter in the createDecoder call.
- ///
- /// @param size
- /// The sizes of the undecoded videoframe in bytes.
- ///
- /// @return
- /// An auto_ptr containing the image which is a result of the
decoding.
- /// A NULL one on error.
- ///
- /// The default implementation always returns a NULL auto pointer.
- ///
- virtual std::auto_ptr<image::image_base> decodeFrame(uint8_t* /*data*/,
int /*size*/)
- {
- return std::auto_ptr<image::image_base>(NULL);
- }
-
- virtual ~embedVideoDecoder() {};
-};
-
-} // end of gnash namespace
-#endif // __EMBEDVIDEODECODER_H__
Index: libbase/embedVideoDecoderFfmpeg.cpp
===================================================================
RCS file: libbase/embedVideoDecoderFfmpeg.cpp
diff -N libbase/embedVideoDecoderFfmpeg.cpp
--- libbase/embedVideoDecoderFfmpeg.cpp 10 Sep 2007 16:53:29 -0000 1.22
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,282 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef USE_FFMPEG
-
-#include <cstring>
-
-#include "embedVideoDecoderFfmpeg.h"
-
-#ifdef HAVE_SWSCALE_H
-extern "C" {
-#include <ffmpeg/swscale.h>
-}
-#endif
-
-#include <boost/scoped_array.hpp>
-
-namespace gnash {
-
-embedVideoDecoderFfmpeg::embedVideoDecoderFfmpeg() :
- codec(NULL),
- cc(NULL),
- decodedFrame(NULL)
-{
-}
-
-embedVideoDecoderFfmpeg::~embedVideoDecoderFfmpeg()
-{
- if (cc) avcodec_close(cc);
-
-}
-
-void
-embedVideoDecoderFfmpeg::createDecoder(int widthi, int heighti, int
deblockingi, bool smoothingi, int formati, int outputFormati)
-{
- // Init the avdecoder-decoder
- avcodec_init();
- avcodec_register_all();
-
- // Save video attributes
- width = widthi;
- height = heighti;
- deblocking = deblockingi;
- smoothing = smoothingi;
- format = formati;
- outputFormat = outputFormati;
-
- // Find the decoder and init the parser
- if (format == CODEC_H263) {
- codec = avcodec_find_decoder(CODEC_ID_FLV1);
-#ifdef FFMPEG_VP6
- } else if (format == CODEC_VP6) {
- codec = avcodec_find_decoder(CODEC_ID_VP6F);
-#endif
- } else if (format == CODEC_SCREENVIDEO) {
- codec = avcodec_find_decoder(CODEC_ID_FLASHSV);
- } else {
- gnash::log_error("Unsupported embedded video format, it might
help if you upgrade ffmpeg and recompile gnash");
- return;
- }
-
- if (codec == NULL) {
- gnash::log_error("Unsupported embedded video format, it might
help if you upgrade ffmpeg and recompile gnash");
- return;
- }
-
- cc = avcodec_alloc_context();
- avcodec_open(cc, codec);
- cc->width = width;
- cc->height = height;
-
- assert(cc->width > 0);
- assert(cc->height > 0);
-
- // Determine required buffer size and allocate buffer
- if (outputFormat == YUV) {
- decodedFrame.reset(new image::yuv(width, height));
- } else if (outputFormat == RGB) {
- decodedFrame.reset(new image::rgb(width, height));
- }
-}
-
-uint8_t*
-embedVideoDecoderFfmpeg::convertRGB24(AVCodecContext* srcCtx, AVFrame*
srcFrame)
-{
- int width = srcCtx->width, height = srcCtx->height;
-
- int bufsize = avpicture_get_size(PIX_FMT_RGB24, width, height);
- if (bufsize == -1) {
- return NULL;
- }
-
- uint8_t* buffer = new uint8_t[bufsize];
- if (!buffer) {
- return NULL;
- }
-
- AVPicture picture;
-
- avpicture_fill(&picture, buffer, PIX_FMT_RGB24, width, height);
-#ifndef HAVE_SWSCALE_H
- img_convert(&picture, PIX_FMT_RGB24, (AVPicture*) srcFrame,
srcCtx->pix_fmt,
- width, height);
-#else
- static SwsContext* context = NULL;
-
- if (!context) {
- context = sws_getContext(width, height, srcCtx->pix_fmt,
- width, height, PIX_FMT_RGB24,
- SWS_FAST_BILINEAR, NULL, NULL, NULL);
- if (!context) {
- delete [] buffer;
- return NULL;
- }
- }
-
- int rv = sws_scale(context, srcFrame->data, srcFrame->linesize, 0,
- width, picture.data, picture.linesize);
- if (rv == -1) {
- delete [] buffer;
- return NULL;
- }
-
-#endif // HAVE_SWSCALE_H
-
- srcFrame->linesize[0] = picture.linesize[0];
- srcFrame->data[0] = picture.data[0];
-
- return buffer;
-}
-
-// gnash calls this when it wants you to decode the given videoframe
-std::auto_ptr<image::image_base>
-embedVideoDecoderFfmpeg::decodeFrame(uint8_t* data, int size)
-{
-
- std::auto_ptr<image::image_base> ret_image;
-
- if (outputFormat == YUV) {
- ret_image.reset(new image::yuv(width, height));
- } else if (outputFormat == RGB) {
- ret_image.reset(new image::rgb(width, height));
- } else {
- ret_image.reset(NULL);
- return ret_image;
- }
-
- // If there is nothing to decode in the new frame
- // we just return the lastest.
- if (data == NULL || codec == NULL || size == 0)
- {
- // If haven't decoded any frame yet, return
- // the null pointer.
- if ( ! decodedFrame.get() )
- {
- ret_image.reset(NULL);
- return ret_image;
- }
-
- // clone decodedFrame instead ?
- ret_image->update(*decodedFrame);
- return ret_image;
- }
-
-
- // Allocate a frame to store the decoded frame in
- AVFrame* frame = avcodec_alloc_frame();
-
- int got = 0;
- avcodec_decode_video(cc, frame, &got, data, size);
-
- // If the size of the video frame changed, adjust.
- // This could happen if the decoded video frame is
- // bigger than the defined SWF videoframe.
- if (static_cast<uint32_t>(cc->width) != width ||
static_cast<uint32_t>(cc->height) != height) {
- width = cc->width;
- height = cc->height;
- if (outputFormat == YUV) {
- decodedFrame.reset(new image::yuv(width, height));
- ret_image.reset(new image::yuv(width, height));
- } else if (outputFormat == RGB) {
- decodedFrame.reset(new image::rgb(width, height));
- ret_image.reset(new image::rgb(width, height));
- }
- }
-
- if (got) {
- log_debug("Got");
- boost::scoped_array<uint8_t> buffer;
-
- if (outputFormat == NONE) { // NullGui?
- av_free(frame);
- ret_image->update(*decodedFrame);
- return ret_image;
-
- } else if (outputFormat == YUV && cc->pix_fmt !=
PIX_FMT_YUV420P) {
- //assert(0); // TODO
- //img_convert((AVPicture*) pFrameYUV, PIX_FMT_YUV420P,
(AVPicture*) pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
- // Don't use depreceted img_convert, use sws_scale
-
- } else if (outputFormat == RGB && cc->pix_fmt != PIX_FMT_RGB24)
{
- buffer.reset(convertRGB24(cc, frame));
- }
-
- if (outputFormat == YUV) {
- image::yuv* yuvframe =
static_cast<image::yuv*>(decodedFrame.get());
- size_t copied = 0;
- uint8_t* ptr = yuvframe->data();
- for (int i = 0; i < 3 ; i++)
- {
- int shift = (i == 0 ? 0 : 1);
- uint8_t* yuv_factor = frame->data[i];
- int h = cc->height >> shift;
- int w = cc->width >> shift;
- for (int j = 0; j < h; j++)
- {
- copied += w;
- //assert(copied <= yuvframe->size());
- memcpy(ptr, yuv_factor, w);
- yuv_factor += frame->linesize[i];
- ptr += w;
- }
- }
- //yuvframe->m_size = copied;
- assert(yuvframe->size() == copied); // correct ?
- } else if (outputFormat == RGB) {
-
- log_debug("updating decodedFrame with data from ffmpeg");
-
- uint8_t* srcptr = frame->data[0];
- uint8_t* srcend = frame->data[0] + frame->linesize[0] *
cc->height;
- uint8_t* dstptr = decodedFrame->data();
- uint8_t* dstend =
decodedFrame->data()+decodedFrame->size();
- unsigned int srcwidth = cc->width * 3;
-
- while (srcptr < srcend) {
- assert( dstptr < dstend );
- memcpy(dstptr, srcptr, srcwidth);
- srcptr += frame->linesize[0];
- dstptr += srcwidth;
- }
-
- }
- }
- else log_debug("Didn't get");
-
- av_free(frame);
- // If haven't decoded any frame yet, return
- // the null pointer.
- if ( ! decodedFrame.get() )
- {
- ret_image.reset(NULL);
- return ret_image;
- }
-
- log_debug("Returning a clone of decodedFrame");
- return decodedFrame->clone();
- //ret_image->update(*decodedFrame);
- //return ret_image;
-}
-
-} // end of gnash namespace
-
-#endif // USE_FFMPEG
Index: libbase/embedVideoDecoderFfmpeg.h
===================================================================
RCS file: libbase/embedVideoDecoderFfmpeg.h
diff -N libbase/embedVideoDecoderFfmpeg.h
--- libbase/embedVideoDecoderFfmpeg.h 17 Jul 2007 22:05:03 -0000 1.8
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,89 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-// $Id: embedVideoDecoderFfmpeg.h,v 1.8 2007/07/17 22:05:03 nihilus Exp $
-
-#ifndef __EMBEDVIDEODECODERFFMPEG_H__
-#define __EMBEDVIDEODECODERFFMPEG_H__
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef USE_FFMPEG
-
-#include <vector>
-#include "embedVideoDecoder.h"
-extern "C" {
-#include <ffmpeg/avcodec.h>
-}
-#include "image.h"
-
-namespace gnash {
-
-class DSOEXPORT embedVideoDecoderFfmpeg: public embedVideoDecoder {
-public:
- embedVideoDecoderFfmpeg();
-
- ~embedVideoDecoderFfmpeg();
-
- void createDecoder(
- int width,
- int height,
- int deblocking,
- bool smoothing,
- int format,
- int outputFormat);
-
- // gnash calls this when it wants you to decode the given videoframe
- std::auto_ptr<image::image_base> decodeFrame(uint8_t* data, int size);
-
- /// Convert the given srcFrame to RGB24 pixel format.
- //
- /// @param srcCtx The codec context with which srcFrame is associated.
- /// @param srcFrame The source frame to convert. The data and linesize
members
- /// of srcFrame will be changed to match the conversion.
- /// @return A pointer to the newly allocated and freshly converted
video data.
- /// The caller owns the pointer! It must be freed with delete
[] when
- /// the frame has been processed.
- ///
- static uint8_t* convertRGB24(AVCodecContext* srcCtx, AVFrame* srcFrame);
-
-private:
-
- /// ffmpeg stuff
- AVCodec *codec;
- AVCodecContext *cc;
-
- /// Info from the video tag header. Might be usefull...
- uint32_t width;
- uint32_t height;
- int deblocking;
- bool smoothing;
- int format;
- int outputFormat;
-
- /// Last decoded frame
- std::auto_ptr<image::image_base> decodedFrame;
-
-};
-
-} // end of gnash namespace
-
-#endif // USE_FFMPEG
-
-#endif // __EMBEDVIDEODECODERFFMPEG_H__
Index: libbase/embedVideoDecoderGst.cpp
===================================================================
RCS file: libbase/embedVideoDecoderGst.cpp
diff -N libbase/embedVideoDecoderGst.cpp
--- libbase/embedVideoDecoderGst.cpp 10 Sep 2007 16:53:29 -0000 1.11
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,309 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-// $Id: embedVideoDecoderGst.cpp,v 1.11 2007/09/10 16:53:29 strk Exp $
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef SOUND_GST
-
-#include "embedVideoDecoderGst.h"
-
-namespace gnash {
-
-embedVideoDecoderGst::embedVideoDecoderGst() :
- pipeline(NULL),
- input(NULL),
- inputcaps(NULL),
- videocaps(NULL),
- output(NULL),
- decoder(NULL),
- colorspace(NULL),
- decodedFrame(NULL),
- stop(false)
-
-{
-}
-
-embedVideoDecoderGst::~embedVideoDecoderGst()
-{
-
- if (pipeline) {
- stop = true;
- delete input_lock;
- gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (pipeline));
- }
-}
-
-void
-embedVideoDecoderGst::createDecoder(int widthi, int heighti, int deblockingi,
bool smoothingi, int formati, int outputFormati)
-{
- // Save video attributes
- width = widthi;
- height = heighti;
- deblocking = deblockingi;
- smoothing = smoothingi;
- format = formati;
- outputFormat = outputFormati;
-
- // For now only H263/SVQ3, VP6 and screenvideo1 is supported
- if (format != CODEC_H263 && format != CODEC_VP6 && format !=
CODEC_SCREENVIDEO) return;
-
- // init GStreamer
- gst_init (NULL, NULL);
-
- // setup the pipeline
- pipeline = gst_pipeline_new (NULL);
-
- // Setup the pipeline elements
-
- // setup fake source
- input = gst_element_factory_make ("fakesrc", NULL);
- g_object_set (G_OBJECT (input), "sizetype", 3, /*"can-activate-pull",
FALSE,*/ "signal-handoffs", TRUE, NULL);
- // Setup the callback
- g_signal_connect (input, "handoff", G_CALLBACK
(embedVideoDecoderGst::callback_handoff), this);
-
- // Setup the input capsfilter
- inputcaps = gst_element_factory_make ("capsfilter", NULL);
- GstCaps* caps = NULL;
- if (format == CODEC_H263) {
- caps = gst_caps_new_simple ("video/x-flash-video",
- "width", G_TYPE_INT, width,
- "height", G_TYPE_INT, height,
- "framerate", GST_TYPE_FRACTION, 25, 1,
- "flvversion", G_TYPE_INT, 1,
- NULL);
- } else if (format == CODEC_VP6) {
- caps = gst_caps_new_simple ("video/x-vp6-flash",
- "width", G_TYPE_INT, width,
- "height", G_TYPE_INT, height,
- "framerate", GST_TYPE_FRACTION, 25, 1,
- NULL);
- } else if (format == CODEC_SCREENVIDEO) {
- caps = gst_caps_new_simple ("video/x-flash-screen",
- "width", G_TYPE_INT, width,
- "height", G_TYPE_INT, height,
- "framerate", GST_TYPE_FRACTION, 25, 1,
- NULL);
- }
-
- if ( caps )
- {
- g_object_set (G_OBJECT (inputcaps), "caps", caps, NULL);
- gst_caps_unref (caps);
-#ifndef NDEBUG
- caps = NULL; // to check it is not null on next use ...
-#endif
- }
- else
- {
- log_error("Unknown codec format %d", format);
- }
-
- // Setup the capsfilter which demands either YUV or RGB videoframe
format
- videocaps = gst_element_factory_make ("capsfilter", NULL);
- if (outputFormat == YUV) {
- caps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
- } else if ( outputFormat == RGB ) {
- caps = gst_caps_new_simple ("video/x-raw-rgb", NULL);
- }
- else
- {
- assert(outputFormat == NONE);
- return; // nothing to do, right ? TODO: some cleanup ?
- }
-
- assert(caps); // ok, this is a silly assertion *now*, but as long as
- // the code is implemented with such long function bodies
- // a day will come in which someone will change something
- // a few screefulls above and the assertion would make
- // sense (maybe boost compile-time assertions could help
- // in this reguard).
-
- g_object_set (G_OBJECT (videocaps), "caps", caps, NULL);
- gst_caps_unref (caps);
-
- // setup the videosink with callback
- output = gst_element_factory_make ("fakesink", NULL);
- g_object_set (G_OBJECT (output), "signal-handoffs", TRUE, NULL);
- g_signal_connect (output, "handoff", G_CALLBACK
(embedVideoDecoderGst::callback_output), this);
-
- // setup the video colorspaceconverter converter
- colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
-
- // Find the decoder
- if (format == CODEC_H263) {
- decoder = gst_element_factory_make ("ffdec_flv", NULL);
- } else if (format == CODEC_VP6) {
- decoder = gst_element_factory_make ("ffdec_vp6f", NULL);
- } else if (format == CODEC_SCREENVIDEO) {
- decoder = gst_element_factory_make ("ffdec_flashsv", NULL);
- } else {
- gnash::log_error("Unsupported embedded video format");
- return;
- }
-
- if (!pipeline || !input || !inputcaps || !videocaps || !output ||
!colorspace) {
- gnash::log_error("Creation of Gstreamer baisc elements failed,
is your Gstreamer installation complete?");
- return;
- }
-
- if (!decoder) {
- gnash::log_error("Creation of decoder element failed, do you
have gstreamer-0.10-ffmpeg installed?");
- return;
- }
-
- // Put the elemets in the pipeline and link them
- gst_bin_add_many (GST_BIN (pipeline), input, inputcaps, decoder,
colorspace, videocaps, output, NULL);
-
- // link the elements
- gst_element_link_many(input, inputcaps, decoder, colorspace, videocaps,
output, NULL);
-
- // This make callback_handoff wait for data
- input_lock = new boost::mutex::scoped_lock(input_mutex);
-
- // This make decodeFrame wait for data
- output_lock = new boost::mutex::scoped_lock(output_mutex);
-
- // Determine required buffer size and allocate buffer
- if (outputFormat == YUV) {
- decodedFrame.reset(new image::yuv(width, height));
- } else if (outputFormat == RGB) {
- decodedFrame.reset(new image::rgb(width, height));
- }
-
- // Start "playing"
- gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
-}
-
-
-// gnash calls this when it wants you to decode the given videoframe
-std::auto_ptr<image::image_base>
-embedVideoDecoderGst::decodeFrame(uint8_t* data, int size)
-{
-
- std::auto_ptr<image::image_base> ret_image;
-
- if (outputFormat == YUV) {
- ret_image.reset(new image::yuv(width, height));
- } else if (outputFormat == RGB) {
- ret_image.reset(new image::rgb(width, height));
- } else {
- ret_image.reset(NULL);
- return ret_image;
- }
-
- // If there is nothing to decode in the new frame
- // we just return the lastest.
- if (data == NULL || size == 0 || !decoder)
- {
- // If we never decoded any frame return a NULL
- // auto pointer ..
- if ( ! decodedFrame.get() )
- {
- ret_image.reset(NULL);
- return ret_image;
- }
-
- // return decodedFrame->clone() ?
- ret_image->update(*decodedFrame);
- return ret_image;
- }
-
- frame = data;
- frameSize = size;
-
- delete input_lock;
-
- output_lock = new boost::mutex::scoped_lock(output_mutex);
-
- // If we never decoded any frame return a NULL
- // auto pointer ..
- if ( ! decodedFrame.get() )
- {
- ret_image.reset(NULL);
- return ret_image;
- }
-
- // return decodedFrame->clone() ?
- ret_image->update(*decodedFrame);
- return ret_image;
-}
-
-// The callback function which refills the buffer with data
-void
-embedVideoDecoderGst::callback_handoff (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data)
-{
- embedVideoDecoderGst* decoder =
static_cast<embedVideoDecoderGst*>(user_data);
-
- if (decoder->stop) return;
-
- decoder->input_lock = new
boost::mutex::scoped_lock(decoder->input_mutex);
-
- GST_BUFFER_SIZE(buffer) = decoder->frameSize;
-
- GST_BUFFER_DATA(buffer) = decoder->frame;
-}
-
-// The callback function which passes the decoded video frame
-void
-embedVideoDecoderGst::callback_output (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data)
-{
- embedVideoDecoderGst* decoder =
static_cast<embedVideoDecoderGst*>(user_data);
-
- if (decoder->stop) return;
-
- if (decoder->decodedFrame.get())
- {
-
- if (decoder->outputFormat == YUV) {
- assert(0);
-
- /* image::yuv* yuvframe =
static_cast<image::yuv*>(decoder->decodedFrame);
- int copied = 0;
- uint8_t* ptr = GST_BUFFER_DATA(buffer);
- for (int i = 0; i < 3 ; i++)
- {
- int shift = (i == 0 ? 0 : 1);
- uint8_t* yuv_factor = m_Frame->data[i];
- int h = ns->videoheight >> shift;
- int w = ns->videowidth >> shift;
- for (int j = 0; j < h; j++)
- {
- copied += w;
- assert(copied <= yuvframe->size());
- memcpy(ptr, yuv_factor, w);
- yuv_factor += m_Frame->linesize[i];
- ptr += w;
- }
- }
- video->m_size = copied;*/
- } else {
- decoder->decodedFrame->update(GST_BUFFER_DATA(buffer));
- }
- }
-
- delete decoder->output_lock;
-
-}
-
-} // end of gnash namespace
-
-#endif // SOUND_GST
Index: libbase/embedVideoDecoderGst.h
===================================================================
RCS file: libbase/embedVideoDecoderGst.h
diff -N libbase/embedVideoDecoderGst.h
--- libbase/embedVideoDecoderGst.h 1 Jul 2007 10:54:08 -0000 1.5
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,103 +0,0 @@
-//
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-// $Id: embedVideoDecoderGst.h,v 1.5 2007/07/01 10:54:08 bjacques Exp $
-
-#ifndef __EMBEDVIDEODECODERGST_H__
-#define __EMBEDVIDEODECODERGST_H__
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef SOUND_GST
-
-#include "embedVideoDecoder.h"
-#include <gst/gst.h>
-#include "image.h"
-#include <boost/thread/thread.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread/mutex.hpp>
-
-namespace gnash {
-
-class embedVideoDecoderGst : public embedVideoDecoder {
-public:
- embedVideoDecoderGst();
-
- ~embedVideoDecoderGst();
-
- void createDecoder(
- int width,
- int height,
- int deblocking,
- bool smoothing,
- int format,
- int outputFormat);
-
- // gnash calls this when it wants you to decode the given videoframe
- std::auto_ptr<image::image_base> decodeFrame(uint8_t* data, int size);
-
- // Callback functions used to handle input and output
- static void callback_handoff (GstElement * /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data);
- static void callback_output (GstElement* /*c*/, GstBuffer *buffer,
GstPad* /*pad*/, gpointer user_data);
-
-private:
-
- // gstreamer pipeline objects
-
- /// the main bin containing the elements
- GstElement *pipeline;
-
- /// Gstreamer objects
- GstElement *input;
- GstElement *inputcaps;
- GstElement *videocaps;
- GstElement *output;
- GstElement *decoder;
- GstElement *colorspace;
-
- /// mutexes and locks used to handle input and output.
- boost::mutex input_mutex;
- boost::mutex output_mutex;
- boost::mutex::scoped_lock *input_lock;
- boost::mutex::scoped_lock *output_lock;
-
- /// Info from the video tag header. Might be usefull...
- uint32_t width;
- uint32_t height;
- int deblocking;
- bool smoothing;
- int format;
- int outputFormat;
-
- /// Input data and size for current frame
- uint8_t* frame;
- int frameSize;
-
- /// Last decoded frame
- std::auto_ptr<image::image_base> decodedFrame;
-
- /// If we should stop this will be true
- volatile bool stop;
-};
-
-} // end of gnash namespace
-
-#endif // SOUND_GST
-
-#endif // __EMBEDVIDEODECODERGST_H__
- [Gnash-commit] gnash ChangeLog Makefile.am configure.ac backen...,
Tomas Groth <=