[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog backend/sound_handler_sdl.cpp l...
From: |
Tomas Groth |
Subject: |
[Gnash-commit] gnash ChangeLog backend/sound_handler_sdl.cpp l... |
Date: |
Fri, 23 Mar 2007 00:30:10 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Tomas Groth <tgc> 07/03/23 00:30:10
Modified files:
. : ChangeLog
backend : sound_handler_sdl.cpp
libbase : LoadThread.cpp LoadThread.h Makefile.am
macros : libXML.m4
server : video_stream_instance.cpp
server/asobj : NetConnection.cpp NetConnection.h NetStream.cpp
NetStream.h NetStreamFfmpeg.cpp
NetStreamFfmpeg.h NetStreamGst.cpp
NetStreamGst.h SoundGst.cpp
Added files:
libbase : FLVParser.cpp FLVParser.h
Log message:
* backend/sound_handler_sdl.cpp: Count videos sounds.
* libbase/FLVParser.{h,cpp}: Added. Our own homegrown FLV parser.
* libbase/LoadThread.{h,cpp}: Use auto_ptr<tu_file> instead of tu_file,
and added the isPositionConfirmed() function.
* libbase/Makefile.am: Added FLVParser.{h,cpp}.
* macros/libXML.m4: A fix for when using --with-libxml-incl
* server/video_stream_instance.cpp: Use Advance to investigate if a new
video frame is ready, and decide if the bouds should be invalidated.
* server/asobj/NetConnection.{h,cpp}: Pass a auto_ptr<tu_file> to
LoadThread. Always check if the loader exists before using it.
Added connectParser to make it possible for the parser to access the
file.
* server/asobj/NetStream.{h,cpp}: Implemented setBufferTime and
onStatus.
* server/asobj/NetStreamFfmpeg.{h,cpp}: Use the new FLVParser when we
play a FLV. Added more comments. Implemented setBufferTime, and made
things ready for onStatus.
* server/asobj/NetStreamGst.{cpp,h}: Added stubs and small updates to
keep up with NetStreamFfmpeg. Some work on supporting the -r1 switch.
* server/asobj/SoundGst.cpp: Removed a printf.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.2677&r2=1.2678
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/sound_handler_sdl.cpp?cvsroot=gnash&r1=1.48&r2=1.49
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/LoadThread.cpp?cvsroot=gnash&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/LoadThread.h?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/Makefile.am?cvsroot=gnash&r1=1.60&r2=1.61
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/FLVParser.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/FLVParser.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/macros/libXML.m4?cvsroot=gnash&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/gnash/server/video_stream_instance.cpp?cvsroot=gnash&r1=1.16&r2=1.17
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetConnection.cpp?cvsroot=gnash&r1=1.31&r2=1.32
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetConnection.h?cvsroot=gnash&r1=1.21&r2=1.22
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStream.cpp?cvsroot=gnash&r1=1.32&r2=1.33
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStream.h?cvsroot=gnash&r1=1.23&r2=1.24
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.cpp?cvsroot=gnash&r1=1.22&r2=1.23
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.h?cvsroot=gnash&r1=1.14&r2=1.15
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamGst.cpp?cvsroot=gnash&r1=1.14&r2=1.15
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamGst.h?cvsroot=gnash&r1=1.8&r2=1.9
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/SoundGst.cpp?cvsroot=gnash&r1=1.3&r2=1.4
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.2677
retrieving revision 1.2678
diff -u -b -r1.2677 -r1.2678
--- ChangeLog 22 Mar 2007 22:37:45 -0000 1.2677
+++ ChangeLog 23 Mar 2007 00:30:10 -0000 1.2678
@@ -1,3 +1,24 @@
+2007-03-23 Tomas Groth Christensen <address@hidden>
+
+ * backend/sound_handler_sdl.cpp: Count videos sounds.
+ * libbase/FLVParser.{h,cpp}: Added. Our own homegrown FLV parser.
+ * libbase/LoadThread.{h,cpp}: Use auto_ptr<tu_file> instead of tu_file,
+ and added the isPositionConfirmed() function.
+ * libbase/Makefile.am: Added FLVParser.{h,cpp}.
+ * macros/libXML.m4: A fix for when using --with-libxml-incl
+ * server/video_stream_instance.cpp: Use Advance to investigate if a new
+ video frame is ready, and decide if the bouds should be invalidated.
+ * server/asobj/NetConnection.{h,cpp}: Pass a auto_ptr<tu_file> to
+ LoadThread. Always check if the loader exists before using it.
+ Added connectParser to make it possible for the parser to access the
file.
+ * server/asobj/NetStream.{h,cpp}: Implemented setBufferTime and
onStatus.
+ * server/asobj/NetStreamFfmpeg.{h,cpp}: Use the new FLVParser when we
+ play a FLV. Added more comments. Implemented setBufferTime, and made
+ things ready for onStatus.
+ * server/asobj/NetStreamGst.{cpp,h}: Added stubs and small updates to
+ keep up with NetStreamFfmpeg. Some work on supporting the -r1 switch.
+ * server/asobj/SoundGst.cpp: Removed a printf.
+
2007-03-22 Sandro Santilli <address@hidden>
* testsuite/swfdec/PASSING: two more successes.
Index: backend/sound_handler_sdl.cpp
===================================================================
RCS file: /sources/gnash/gnash/backend/sound_handler_sdl.cpp,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -b -r1.48 -r1.49
--- backend/sound_handler_sdl.cpp 21 Feb 2007 19:18:45 -0000 1.48
+++ backend/sound_handler_sdl.cpp 23 Mar 2007 00:30:10 -0000 1.49
@@ -18,7 +18,7 @@
// 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.48 2007/02/21 19:18:45 tgc Exp $
+// $Id: sound_handler_sdl.cpp,v 1.49 2007/03/23 00:30:10 tgc Exp $
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -490,6 +490,8 @@
}
m_aux_streamer[owner] = ptr;
+ ++soundsPlaying;
+
if (!soundOpened) {
if (SDL_OpenAudio(&audioSpec, NULL) < 0 ) {
gnash::log_error("Unable to START SOUND: %s.",
SDL_GetError());
@@ -503,6 +505,7 @@
void SDL_sound_handler::detach_aux_streamer(void* owner)
{
+ --soundsPlaying;
m_aux_streamer.erase(owner);
}
@@ -760,7 +763,10 @@
SDL_sound_handler::aux_streamer_ptr aux_streamer =
it->second; //handler->m_aux_streamer[i]->ptr;
void* owner = it->first;
bool ret = (aux_streamer)(owner, buf, buffer_length);
- if (!ret) handler->m_aux_streamer.erase(it);
+ if (!ret) {
+ handler->m_aux_streamer.erase(it);
+ handler->soundsPlaying--;
+ }
SDL_MixAudio(stream, buf, buffer_length,
SDL_MIX_MAXVOLUME);
}
Index: libbase/LoadThread.cpp
===================================================================
RCS file: /sources/gnash/gnash/libbase/LoadThread.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libbase/LoadThread.cpp 9 Mar 2007 14:38:29 -0000 1.1
+++ libbase/LoadThread.cpp 23 Mar 2007 00:30:10 -0000 1.2
@@ -16,11 +16,11 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: LoadThread.cpp,v 1.1 2007/03/09 14:38:29 tgc Exp $
+// $Id: LoadThread.cpp,v 1.2 2007/03/23 00:30:10 tgc Exp $
#include "LoadThread.h"
-LoadThread::LoadThread(tu_file* stream)
+LoadThread::LoadThread(std::auto_ptr<tu_file> stream)
:
_stream(stream),
_bytesLoaded(0),
@@ -146,3 +146,9 @@
_loadPosition = pos;
_actualPosition = pos;
}
+
+bool LoadThread::isPositionConfirmed(size_t pos)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+ return (static_cast<uint32_t>(pos) <= _loadPosition);
+}
Index: libbase/LoadThread.h
===================================================================
RCS file: /sources/gnash/gnash/libbase/LoadThread.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libbase/LoadThread.h 9 Mar 2007 23:15:57 -0000 1.2
+++ libbase/LoadThread.h 23 Mar 2007 00:30:10 -0000 1.3
@@ -16,7 +16,10 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: LoadThread.h,v 1.2 2007/03/09 23:15:57 tgc Exp $
+#ifndef __LOADTHREAD_H__
+#define __LOADTHREAD_H__
+
+// $Id: LoadThread.h,v 1.3 2007/03/23 00:30:10 tgc Exp $
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
@@ -27,9 +30,12 @@
/// \brief
/// The LoadThread class can be used to download from a file
/// or stream using a thread, without having to block.
-/// When the object is created it starts a thread which downloads
-/// from the tu_file given as an argument to the constructor, and
-/// keeps downloading until the download is complete. It is possible
+///
+/// When the object is created it starts a thread which seeks forward
+/// in the tu_file given as an argument to the constructor, which will
+/// make cause the tu_file backend to download the amount of data needed
+/// to complete the seek. This is repeated until the complete file is
+/// downloaded. It is possible
/// for the object owner to query for data, position, loaded data,
/// total data while downloading, without blocking. Though if there has
/// not been downloaded enough data to accomendate a request (seek/read)
@@ -47,7 +53,9 @@
public:
/// Creating the object starts the threaded loading
/// of the stream/file passed as an argument.
- LoadThread(tu_file* stream);
+ LoadThread(std::auto_ptr<tu_file> stream);
+
+ /// Stops the download if still running
~LoadThread();
/// Put read pointer at given position
@@ -67,7 +75,7 @@
/// Report global position within the file
size_t tell();
- /// Returns the number of bytes cached
+ /// Returns the number of bytes known to be accessable
long getBytesLoaded();
/// Returns the total size of the file
@@ -76,6 +84,9 @@
/// Check if the load is completed
bool completed();
+ /// Check if given position is confirmed to be accessable
+ bool isPositionConfirmed(size_t pos);
+
private:
/// The thread function used to download from the stream
@@ -100,3 +111,4 @@
long _actualPosition;
};
+#endif // __LOADTHREAD_H__
Index: libbase/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/libbase/Makefile.am,v
retrieving revision 1.60
retrieving revision 1.61
diff -u -b -r1.60 -r1.61
--- libbase/Makefile.am 9 Mar 2007 14:38:29 -0000 1.60
+++ libbase/Makefile.am 23 Mar 2007 00:30:10 -0000 1.61
@@ -21,11 +21,14 @@
# this is where Gnash plugins get installed
pluginsdir = $(prefix)/lib/gnash/plugins
-lib_LTLIBRARIES = libgnashbase.la
+lib_LTLIBRARIES = \
+ libgnashbase.la
+ libgnashamf.la
libgnashbase_la_CPPFLAGS = -DPLUGINSDIR=\"$(pluginsdir)\" \
-I.. -I$(srcdir) \
-I$(top_srcdir) \
+ -I$(top_srcdir)/libamf \
-I$(top_srcdir)/server \
-I$(top_srcdir)/server/swf \
$(PTHREAD_CFLAGS) \
@@ -96,8 +99,8 @@
zlib_adapter.cpp \
Thread.cpp \
URL.cpp \
- LoadThread.cpp
-
+ LoadThread.cpp \
+ FLVParser.cpp
noinst_HEADERS = \
container.h \
@@ -136,7 +139,8 @@
zlib_adapter.h \
Thread.h \
URL.h \
- LoadThread.h
+ LoadThread.h \
+ FLVParser.h
if USE_SOUND_GST
libgnashbase_la_SOURCES += gstgnashsrc.c embedVideoDecoderGst.cpp
Index: macros/libXML.m4
===================================================================
RCS file: /sources/gnash/gnash/macros/libXML.m4,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- macros/libXML.m4 21 Jan 2007 22:41:03 -0000 1.28
+++ macros/libXML.m4 23 Mar 2007 00:30:10 -0000 1.29
@@ -14,7 +14,7 @@
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-dnl $Id: libXML.m4,v 1.28 2007/01/21 22:41:03 rsavoye Exp $
+dnl $Id: libXML.m4,v 1.29 2007/03/23 00:30:10 tgc Exp $
AC_DEFUN([GNASH_PATH_LIBXML], [
has_xml=no
@@ -22,10 +22,10 @@
AC_ARG_WITH(libxml-incl, AC_HELP_STRING([--with-libxml-incl], [directory
where libxml2 header is]), with_libxml_incl=${withval})
AC_CACHE_VAL(ac_cv_path_libxml_incl, [
if test x"${with_libxml_incl}" != x ; then
- if test -f ${with_libxml_incl}/xmlmemory.h ; then
+ if test -f ${with_libxml_incl}/libxml/xmlmemory.h ; then
ac_cv_path_libxml_incl=-I`(cd ${with_libxml_incl}; pwd)`
else
- AC_MSG_ERROR([${with_libxml_incl} directory doesn't contain
xmlmemory.h])
+ AC_MSG_ERROR([${with_libxml_incl} directory doesn't contain
libxml/xmlmemory.h])
fi
fi
])
Index: server/video_stream_instance.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/video_stream_instance.cpp,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -b -r1.16 -r1.17
--- server/video_stream_instance.cpp 20 Mar 2007 15:01:20 -0000 1.16
+++ server/video_stream_instance.cpp 23 Mar 2007 00:30:10 -0000 1.17
@@ -15,7 +15,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_instance.cpp,v 1.16 2007/03/20 15:01:20 strk Exp $
+// $Id: video_stream_instance.cpp,v 1.17 2007/03/23 00:30:10 tgc Exp $
#include "sprite_instance.h"
#include "video_stream_instance.h"
@@ -26,6 +26,7 @@
#include "render.h"
#include "Range2d.h"
#include "builtin_function.h" // for getter/setter properties
+#include "VM.h"
namespace gnash {
@@ -83,7 +84,6 @@
matrix m = get_world_matrix();
rect bounds(0.0f, 0.0f, PIXELS_TO_TWIPS(m_def->m_width),
PIXELS_TO_TWIPS(m_def->m_height));
-
// If this is a video from a NetStream object, retrieve a video frame
from there.
if (_ns)
{
@@ -119,6 +119,10 @@
void
video_stream_instance::advance(float /*delta_time*/)
{
+ if (_ns) {
+ _ns->advance();
+ if (_ns->newFrameReady()) set_invalidated();
+ }
}
void
Index: server/asobj/NetConnection.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetConnection.cpp,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -b -r1.31 -r1.32
--- server/asobj/NetConnection.cpp 20 Mar 2007 15:01:20 -0000 1.31
+++ server/asobj/NetConnection.cpp 23 Mar 2007 00:30:10 -0000 1.32
@@ -14,7 +14,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: NetConnection.cpp,v 1.31 2007/03/20 15:01:20 strk Exp $ */
+/* $Id: NetConnection.cpp,v 1.32 2007/03/23 00:30:10 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -61,7 +61,7 @@
}
NetConnection::~NetConnection() {
-
+ if (_loader) delete _loader;
}
/// Open a connection to stream FLV files.
@@ -95,7 +95,7 @@
return false;
}
- _loader = new
LoadThread(StreamProvider::getDefaultInstance().getStream(uri));
+ _loader = new
LoadThread(std::auto_ptr<tu_file>(StreamProvider::getDefaultInstance().getStream(uri)));
return true;
}
@@ -113,7 +113,7 @@
bool
NetConnection::eof()
{
-
+ if (!_loader) return true;
return _loader->eof();
}
@@ -121,6 +121,7 @@
size_t
NetConnection::read(void *dst, size_t bytes)
{
+ if (!_loader) return 0;
return _loader->read(dst, bytes);
}
@@ -128,6 +129,7 @@
bool
NetConnection::seek(size_t pos)
{
+ if (!_loader) return false;
return _loader->seek(pos);
}
@@ -136,6 +138,7 @@
size_t
NetConnection::tell()
{
+ if (!_loader) return 0;
return _loader->tell();
}
@@ -144,6 +147,7 @@
long
NetConnection::getBytesLoaded()
{
+ if (!_loader) return 0;
return _loader->getBytesLoaded();
}
@@ -152,9 +156,18 @@
long
NetConnection::getBytesTotal()
{
+ if (!_loader) return 0;
return _loader->getBytesLoaded();
}
+bool
+NetConnection::connectParser(FLVParser* parser)
+{
+ if (_loader == NULL) return false;
+
+ parser->setLoadThread(_loader);
+ return true;
+}
/// \brief callback to instantiate a new NetConnection object.
/// \param fn the parameters from the Flash movie
Index: server/asobj/NetConnection.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetConnection.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- server/asobj/NetConnection.h 20 Mar 2007 15:01:20 -0000 1.21
+++ server/asobj/NetConnection.h 23 Mar 2007 00:30:10 -0000 1.22
@@ -14,7 +14,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: NetConnection.h,v 1.21 2007/03/20 15:01:20 strk Exp $ */
+/* $Id: NetConnection.h,v 1.22 2007/03/23 00:30:10 tgc Exp $ */
#ifndef __NETCONNECTION_H__
#define __NETCONNECTION_H__
@@ -25,6 +25,7 @@
#include "tu_file.h"
#include "LoadThread.h"
+#include "FLVParser.h"
#include <stdexcept>
#include <cstdio>
@@ -79,6 +80,8 @@
/// Returns the total size of the file
long getBytesTotal();
+ /// Connects FLV parser with the LoadThread
+ bool connectParser(FLVParser* parser);
private:
@@ -86,7 +89,7 @@
std::string _url;
/// the as_object which owns the connection
- as_object* _owner;
+ boost::intrusive_ptr<as_object> _owner;
/// The file/stream loader thread and interface
LoadThread* _loader;
Index: server/asobj/NetStream.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStream.cpp,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -b -r1.32 -r1.33
--- server/asobj/NetStream.cpp 20 Mar 2007 15:01:20 -0000 1.32
+++ server/asobj/NetStream.cpp 23 Mar 2007 00:30:10 -0000 1.33
@@ -15,7 +15,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-/* $Id: NetStream.cpp,v 1.32 2007/03/20 15:01:20 strk Exp $ */
+/* $Id: NetStream.cpp,v 1.33 2007/03/23 00:30:10 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -58,7 +58,7 @@
netstream_new(const fn_call& fn)
{
- NetStream *netstream_obj;
+ boost::intrusive_ptr<NetStream> netstream_obj;
#ifdef SOUND_GST
netstream_obj = new NetStreamGst();
@@ -86,7 +86,7 @@
);
}
}
- return as_value(netstream_obj);
+ return as_value(netstream_obj.get());
}
@@ -144,8 +144,14 @@
}
static as_value netstream_setbuffertime(const fn_call& fn) {
boost::intrusive_ptr<NetStream> ns = ensureType<NetStream>(fn.this_ptr);
- UNUSED(ns);
- log_msg("%s:unimplemented \n", __FUNCTION__);
+
+ double time = 0;
+ if (fn.nargs > 0)
+ {
+ time = fn.arg(0).to_number();
+ }
+ ns->setBufferTime(time);
+
return as_value();
}
@@ -209,6 +215,27 @@
return as_value();
}
+// Both a getter and a setter for onStatus
+static as_value
+netstream_onstatus(const fn_call& fn)
+{
+
+ boost::intrusive_ptr<NetStream> ns = ensureType<NetStream>(fn.this_ptr);
+
+ if ( fn.nargs == 0 ) // getter
+ {
+ as_function* h = ns->getStatusHandler();
+ if ( h ) return as_value(h);
+ else return as_value();
+ }
+ else // setter
+ {
+ as_function* h = fn.arg(0).to_as_function();
+ if ( h ) ns->setStatusHandler(h);
+ }
+ return as_value();
+}
+
void
attachNetStreamInterface(as_object& o)
{
@@ -233,6 +260,8 @@
gettersetter = new builtin_function(&netstream_bytestotal, NULL);
o.init_property("bytesTotal", *gettersetter, *gettersetter);
+ gettersetter = new builtin_function(&netstream_onstatus, NULL);
+ o.init_property("onStatus", *gettersetter, *gettersetter);
}
static as_object*
Index: server/asobj/NetStream.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStream.h,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -b -r1.23 -r1.24
--- server/asobj/NetStream.h 20 Mar 2007 15:01:20 -0000 1.23
+++ server/asobj/NetStream.h 23 Mar 2007 00:30:10 -0000 1.24
@@ -18,7 +18,7 @@
//
//
-/* $Id: NetStream.h,v 1.23 2007/03/20 15:01:20 strk Exp $ */
+/* $Id: NetStream.h,v 1.24 2007/03/23 00:30:10 tgc Exp $ */
#ifndef __NETSTREAM_H__
#define __NETSTREAM_H__
@@ -63,7 +63,7 @@
virtual void seek(double /*pos*/){}
- virtual void setBufferTime(unsigned int /*pos*/){}
+ virtual void setBufferTime(double /*time*/){}
virtual void set_status(const char* /*code*/){}
@@ -85,6 +85,13 @@
return false;
}
+ virtual void advance(){}
+
+ virtual bool newFrameReady() { return false; }
+
+ virtual as_function* getStatusHandler() { return NULL; }
+
+ virtual void setStatusHandler(as_function*) { }
};
Index: server/asobj/NetStreamFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.cpp,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -b -r1.22 -r1.23
--- server/asobj/NetStreamFfmpeg.cpp 20 Mar 2007 15:57:56 -0000 1.22
+++ server/asobj/NetStreamFfmpeg.cpp 23 Mar 2007 00:30:10 -0000 1.23
@@ -14,7 +14,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: NetStreamFfmpeg.cpp,v 1.22 2007/03/20 15:57:56 bjacques Exp $ */
+/* $Id: NetStreamFfmpeg.cpp,v 1.23 2007/03/23 00:30:10 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -38,6 +38,10 @@
#include "unistd.h" // for usleep()
#endif
+// Used to free data in the AVPackets we create our self
+static void avpacket_destruct(AVPacket* av) {
+ delete av->data;
+}
namespace gnash {
@@ -61,20 +65,26 @@
m_video_clock(0),
m_pause(false),
m_unqueued_data(NULL),
- inputPos(0)
+ inputPos(0),
+ m_parser(NULL),
+ m_isFLV(false),
+ m_newFrameReady(false),
+ m_bufferTime(100),
+ m_statusChanged(false)
{
}
NetStreamFfmpeg::~NetStreamFfmpeg()
{
close();
+ if (m_parser) delete m_parser;
}
-// called from avstreamer thread
-void NetStreamFfmpeg::set_status(const char* /*code*/)
+// called from avstreamer thread, and a few other places... (thread safe?)
+void NetStreamFfmpeg::set_status(const char* status)
{
- //m_netstream_object->init_member("onStatus_Code", code);
- //push_video_event(this);
+ m_status = status;
+ m_statusChanged = true;
}
void NetStreamFfmpeg::pause(int mode)
@@ -221,12 +231,23 @@
}
m_go = true;
+ m_pause = true;
+ if (!m_parser && !m_FormatCtx) {
// To avoid blocking while connecting, we use a thread.
startThread = new
boost::thread(boost::bind(NetStreamFfmpeg::startPlayback, this));
- // This starts the decoding thread
+ // This lock prevents the decoding from starting before the
Connection
+ // and decoder is ready.
lock = new boost::mutex::scoped_lock(start_mutex);
+ } else {
+ // We need to restart the audio
+ sound_handler* s = get_sound_handler();
+ if (s) s->attach_aux_streamer(audio_streamer, (void*) this);
+
+ }
+
+ // This starts the decoding thread
m_thread = new boost::thread(boost::bind(NetStreamFfmpeg::av_streamer,
this));
return 0;
@@ -243,11 +264,92 @@
assert(ns);
if ( !nc->openConnection(ns->url.c_str(), ns) ) {
log_warning("Gnash could not open movie url: %s",
ns->url.c_str());
+ ns->set_status("NetStream.Buffer.StreamNotFound");
return;
}
ns->inputPos = 0;
+ // Check if the file is a FLV, in which case we use our own parser
+ uint8_t head[3];
+ nc->read(head, 3);
+ nc->seek(0);
+ if (head[0] == 'F' && head[1] == 'L' && head[2] == 'V') {
+
+ ns->m_isFLV = true;
+
+ ns->m_parser = new FLVParser();
+ nc->connectParser(ns->m_parser);
+
+ // Init the avdecoder-decoder
+ avcodec_init();
+ avcodec_register_all();
+
+ // Get video info from the parser
+ FLVVideoInfo* videoInfo = ns->m_parser->getVideoInfo();
+ if (videoInfo != NULL) {
+ // Find the decoder and init the parser
+ AVCodec* vcodec;
+ if (videoInfo->codec == VIDEO_CODEC_H263) {
+ vcodec = avcodec_find_decoder(CODEC_ID_FLV1);
+#ifdef FFMPEG_VP6
+ } else if (videoInfo->codec == VIDEO_CODEC_VP6) {
+ vcodec = avcodec_find_decoder(CODEC_ID_VP6F);
+#endif
+ } else if (videoInfo->codec == VIDEO_CODEC_SCREENVIDEO)
{
+ vcodec = avcodec_find_decoder(CODEC_ID_FLASHSV);
+ } else {
+ log_error("Unsupported video codec");
+ return;
+ }
+
+ if (vcodec == NULL) {
+ return;
+ }
+
+ ns->m_VCodecCtx = avcodec_alloc_context();
+ avcodec_open(ns->m_VCodecCtx, vcodec);
+ }
+
+ // Get audio info from the parser
+ FLVAudioInfo* audioInfo = ns->m_parser->getAudioInfo();
+ if (audioInfo != NULL) {
+
+ AVCodec* acodec;
+ if (audioInfo->codec == AUDIO_CODEC_RAW) {
+ acodec =
avcodec_find_decoder(CODEC_ID_PCM_U16LE);
+ } else if (audioInfo->codec == AUDIO_CODEC_ADPCM) {
+ acodec =
avcodec_find_decoder(CODEC_ID_ADPCM_SWF);
+ } else if (audioInfo->codec == AUDIO_CODEC_MP3) {
+ acodec = avcodec_find_decoder(CODEC_ID_MP3);
+ } else {
+ log_error("Unsupported audio codec");
+ return;
+ }
+
+ ns->m_ACodecCtx = avcodec_alloc_context();
+ avcodec_open(ns->m_ACodecCtx, acodec);
+ }
+
+ // We just define the indexes here, they're not really used when
+ // the file format is FLV
+ ns->m_video_index = 0;
+ ns->m_audio_index = 1;
+
+ sound_handler* s = get_sound_handler();
+ if (s) s->attach_aux_streamer(audio_streamer, (void*) ns);
+
+// ns->m_pause = false;
+
+ // Allocate a frame to store the decoded frame in
+ ns->m_Frame = avcodec_alloc_frame();
+
+ // By deleting this lock we allow the av_streamer-thread to
start its work
+ delete ns->lock;
+ return;
+ }
+
+
// 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
@@ -269,6 +371,7 @@
}
AVInputFormat* inputFmt = av_probe_input_format(pd, 1);
+ delete[] pd->buf;
// After the format probe, reset to the beginning of the file.
nc->seek(0);
@@ -324,9 +427,6 @@
ns->m_video_stream =
ns->m_FormatCtx->streams[i];
}
break;
- /*case CODEC_TYPE_DATA:
- case CODEC_TYPE_SUBTITLE:
- case CODEC_TYPE_UNKNOWN:*/
default:
break;
}
@@ -454,10 +554,11 @@
ns->m_qvideo.pop();
delete video;
delay = 0;
+ ns->m_newFrameReady = true;
}
else
{
- delay = int((video_clock - clock)*10000000);
+ delay = int((video_clock - clock)*1000000);
}
// Don't hog the CPU.
@@ -470,6 +571,7 @@
}
}
}
+ ns->m_go = false;
ns->set_status("NetStream.Play.Stop");
}
@@ -481,6 +583,8 @@
boost::mutex::scoped_lock lock(ns->decoding_mutex);
+ if (!ns->m_go) return false;
+
while (len > 0 && ns->m_qaudio.size() > 0)
{
raw_videodata_t* samples = ns->m_qaudio.front();
@@ -525,21 +629,38 @@
{
log_warning("read_frame: not audio & video stream\n");
}
-
return true;
}
AVPacket packet;
- int rc = av_read_frame(m_FormatCtx, &packet);
+ int rc;
+ if (m_isFLV) {
+ FLVFrame* frame = m_parser->nextMediaFrame();
+ if (frame == NULL) {
+ set_status("NetStream.Buffer.Empty");
+ return false;
+ }
+
+ if (frame->tag == 9) {
+ packet.stream_index = 0;
+ } else {
+ packet.stream_index = 1;
+ }
+ packet.destruct = avpacket_destruct;
+ packet.size = frame->dataSize;
+ packet.data = frame->data;
+ packet.pts = static_cast<int64_t>(frame->timestamp);
+ rc = 0;
+ } else {
+ rc = av_read_frame(m_FormatCtx, &packet);
+ }
+
if (rc >= 0)
{
- if (packet.stream_index == m_audio_index)
- {
- sound_handler* s = get_sound_handler();
- if (s)
+ if (packet.stream_index == m_audio_index && get_sound_handler())
{
int frame_size;
- uint8_t* ptr = (uint8_t*)
malloc((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2);
+ uint8_t* ptr = new
uint8_t[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
#ifdef FFMPEG_AUDIO2
frame_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3)
/ 2;
if (avcodec_decode_audio2(m_ACodecCtx,
(int16_t*) ptr, &frame_size, packet.data, packet.size) >= 0)
@@ -568,17 +689,25 @@
m_unqueued_data = m_qaudio.push(raw) ?
NULL : raw;
}
- free(ptr);
- }
+ delete[] ptr;
}
else
if (packet.stream_index == m_video_index)
{
+
int got = 0;
avcodec_decode_video(m_VCodecCtx, m_Frame, &got,
packet.data, packet.size);
if (got) {
uint8_t *buffer = NULL;
+
int videoFrameFormat =
gnash::render::videoFrameFormat();
+ if (m_imageframe == NULL) {
+ if (videoFrameFormat == render::YUV) {
+ m_imageframe = new
image::yuv(m_VCodecCtx->width, m_VCodecCtx->height);
+ } else if (videoFrameFormat ==
render::RGB) {
+ m_imageframe = new
image::rgb(m_VCodecCtx->width, m_VCodecCtx->height);
+ }
+ }
if (videoFrameFormat == render::NONE) { //
NullGui?
av_free_packet(&packet);
@@ -612,7 +741,8 @@
// set presentation timestamp
if (packet.dts != static_cast<signed
long>(AV_NOPTS_VALUE))
{
- video->m_pts =
as_double(m_video_stream->time_base) * packet.dts;
+ if (!m_isFLV) video->m_pts =
as_double(m_video_stream->time_base) * packet.dts;
+ else video->m_pts =
as_double(m_VCodecCtx->time_base) * packet.dts;
}
if (video->m_pts != 0)
@@ -626,7 +756,9 @@
}
// update video clock for next frame
- double frame_delay =
as_double(m_video_stream->codec->time_base);
+ double frame_delay;
+ if (!m_isFLV) frame_delay =
as_double(m_video_stream->codec->time_base);
+ else frame_delay =
static_cast<double>(m_parser->videoFrameDelay())/1000.0;
// for MPEG2, the frame can be repeated, so we
update the clock accordingly
frame_delay += m_Frame->repeat_pict *
(frame_delay * 0.5);
@@ -688,22 +820,34 @@
{
boost::mutex::scoped_lock lock(decoding_mutex);
+ long newpos;
+ double timebase;
+
// Seek to new position
- double timebase =
(double)m_FormatCtx->streams[m_video_index]->time_base.num /
(double)m_FormatCtx->streams[m_video_index]->time_base.den;
+ if (m_isFLV) {
+ newpos = m_parser->seek(static_cast<uint32_t>(pos*1000));
+ } else {
- long newpos = (long)(pos / timebase);
+ timebase =
static_cast<double>(m_FormatCtx->streams[m_video_index]->time_base.num) /
static_cast<double>(m_FormatCtx->streams[m_video_index]->time_base.den);
+ newpos = static_cast<long>(pos / timebase);
if (av_seek_frame(m_FormatCtx, m_video_index, newpos, 0) < 0) {
log_warning("seeking failed");
return;
}
+ }
// This is kindof hackish and ugly :-(
if (newpos == 0) {
m_video_clock = 0;
m_start_clock =
tu_timer::ticks_to_seconds(tu_timer::get_ticks());
- } else {
+ } else if (m_isFLV) {
+ double newtime = static_cast<double>(newpos) / 1000.0;
+ m_start_clock += m_video_clock - newtime;
+
+ m_video_clock = newtime;
+ } else {
AVPacket Packet;
av_init_packet(&Packet);
double newtime = 0;
@@ -736,12 +880,34 @@
delete m_qaudio.front();
m_qaudio.pop();
}
+
}
void
-NetStreamFfmpeg::setBufferTime()
+NetStreamFfmpeg::setBufferTime(double time)
{
- log_msg("%s:unimplemented \n", __FUNCTION__);
+ // The argument is in seconds, but we store in milliseconds
+ m_bufferTime = static_cast<uint32_t>(time*1000);
+}
+
+void
+NetStreamFfmpeg::advance()
+{
+ if (m_go && m_pause && !m_imageframe && m_parser &&
m_parser->isTimeLoaded(m_bufferTime)) {
+ set_status("NetStream.Buffer.Full");
+ m_pause = false;
+ }
+
+ if (m_statusChanged) {
+/* fn_call dummy(NULL, NULL, 0, 0);
+ as_value info_asv(infoobject_new(dummy));
+ boost::intrusive_ptr<as_object> info = info_asv.to_object();
+
+ fn_call fn(this, v, 0, 0);
+
+ m_statusHandler.get()->call(fn);*/
+
+ }
}
int64_t
@@ -751,6 +917,8 @@
if (m_FormatCtx && m_FormatCtx->nb_streams > 0) {
double time = (double)m_FormatCtx->streams[0]->time_base.num /
(double)m_FormatCtx->streams[0]->time_base.den *
(double)m_FormatCtx->streams[0]->cur_dts;
return static_cast<int64_t>(time);
+ } else if (m_isFLV) {
+ return static_cast<int64_t>(m_video_clock / 1000);
} else {
return 0;
}
@@ -759,14 +927,41 @@
long
NetStreamFfmpeg::bytesLoaded()
{
+ if (_netCon == NULL) return 0;
return _netCon->getBytesLoaded();
}
long
NetStreamFfmpeg::bytesTotal()
{
+ if (_netCon == NULL) return 0;
return _netCon->getBytesTotal();
}
+
+bool
+NetStreamFfmpeg::newFrameReady()
+{
+ if (m_newFrameReady) {
+ m_newFrameReady = false;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+as_function*
+NetStreamFfmpeg::getStatusHandler()
+{
+ return m_statusHandler.get();
+}
+
+void
+NetStreamFfmpeg::setStatusHandler(as_function* handler)
+{
+ m_statusHandler = handler;
+}
+
+
} // gnash namespcae
#endif // USE_FFMPEG
Index: server/asobj/NetStreamFfmpeg.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- server/asobj/NetStreamFfmpeg.h 9 Mar 2007 14:38:29 -0000 1.14
+++ server/asobj/NetStreamFfmpeg.h 23 Mar 2007 00:30:10 -0000 1.15
@@ -14,7 +14,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: NetStreamFfmpeg.h,v 1.14 2007/03/09 14:38:29 tgc Exp $ */
+/* $Id: NetStreamFfmpeg.h,v 1.15 2007/03/23 00:30:10 tgc Exp $ */
#ifndef __NETSTREAMFFMPEG_H__
#define __NETSTREAMFFMPEG_H__
@@ -43,6 +43,8 @@
#include "StreamProvider.h"
#include "NetStream.h" // for inheritance
+#include "FLVParser.h"
+
namespace gnash {
struct raw_videodata_t
@@ -58,7 +60,7 @@
~raw_videodata_t()
{
- delete [] m_data;
+ if (m_size > 0) delete [] m_data;
};
int m_stream_index;
@@ -144,12 +146,16 @@
void pause(int mode);
int play(const char* source);
void seek(double pos);
- void setBufferTime();
+ void setBufferTime(double time);
void set_status(const char* code);
void setNetCon(as_object* nc);
int64_t time();
long bytesLoaded();
long bytesTotal();
+ void advance();
+ bool newFrameReady();
+ as_function* getStatusHandler();
+ void setStatusHandler(as_function*);
// Used for ffmpeg data read and seek callbacks
static int readPacket(void* opaque, uint8_t* buf, int buf_size);
@@ -194,10 +200,12 @@
AVCodecContext *m_ACodecCtx;
AVStream* m_audio_stream;
+ // the format (mp3, avi, etc.)
AVFormatContext *m_FormatCtx;
AVFrame* m_Frame;
+ // Use for resampling audio
ReSampleContext *m_Resample;
boost::thread *m_thread;
@@ -206,24 +214,55 @@
boost::mutex start_mutex;
boost::mutex::scoped_lock *lock;
+ // Are the playing loop running or not
volatile bool m_go;
unsigned int runtime;
+ // The image/videoframe which is given to the renderer
image::image_base* m_imageframe;
+ // The current time-position of the video
double m_video_clock;
+ // The queues of audio and video data.
multithread_queue <raw_videodata_t*> m_qaudio;
multithread_queue <raw_videodata_t*> m_qvideo;
+
+ // paused or not
bool m_pause;
+
+ // The time ws started playing
double m_start_clock;
raw_videodata_t* m_unqueued_data;
ByteIOContext ByteIOCxt;
- tu_file* input;
+
+ // The position in the inputfile, only used when not playing a FLV
long inputPos;
- StreamProvider streamProvider;
+
std::string url;
+
+ // The homegrown parser we use for FLV
+ FLVParser* m_parser;
+
+ // Are we playing a FLV?
+ bool m_isFLV;
+
+ // Are a new frame ready to be returned?
+ volatile bool m_newFrameReady;
+
+ // The size of the buffer in milliseconds
+ uint32_t m_bufferTime;
+
+ // The status message
+ std::string m_status;
+
+ // Has the status message been updated?
+ volatile bool m_statusChanged;
+
+ // The handler which is invoked on status change
+ boost::intrusive_ptr<as_function> m_statusHandler;
+
};
} // gnash namespace
Index: server/asobj/NetStreamGst.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamGst.cpp,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- server/asobj/NetStreamGst.cpp 20 Mar 2007 15:01:20 -0000 1.14
+++ server/asobj/NetStreamGst.cpp 23 Mar 2007 00:30:10 -0000 1.15
@@ -76,8 +76,8 @@
m_pause(false),
inputPos(0),
videowidth(0),
- videoheight(0)
-
+ videoheight(0),
+ m_newFrameReady(false)
{
}
@@ -89,8 +89,7 @@
// called from avstreamer thread
void NetStreamGst::set_status(const char* /*code*/)
{
- //m_netstream_object->init_member("onStatus_Code", code);
- //push_video_event(this);
+
}
void NetStreamGst::pause(int mode)
@@ -254,6 +253,7 @@
video->m_size = copied;*/
} else {
ns->m_imageframe->update(GST_BUFFER_DATA(buffer));
+ ns->m_newFrameReady = true;
}
}
@@ -285,8 +285,17 @@
// setup the pipeline
ns->pipeline = gst_pipeline_new (NULL);
+ // Check if the creation of the gstreamer pipeline and audiosink was a
succes
+ if (!ns->pipeline) {
+ gnash::log_error("The gstreamer pipeline element could not be
created\n");
+ return;
+ }
+
+ // If sound is enabled we set it up
+ sound_handler* sound = get_sound_handler();
+ if (sound) {
// create an audio sink - use oss, alsa or...? make a commandline
option?
- // we first try atudetect, then alsa, then oss, then esd, then...?
+ // we first try autodetect, then alsa, then oss, then esd,
then...?
// If the gstreamer adder ever gets fixed this should be connected to
the
// adder in the soundhandler.
#if !defined(__NetBSD__)
@@ -296,15 +305,26 @@
#endif
if (!ns->audiosink) ns->audiosink = gst_element_factory_make
("esdsink", NULL);
- // Check if the creation of the gstreamer pipeline and audiosink was a
succes
- if (!ns->pipeline) {
- gnash::log_error("The gstreamer pipeline element could not be
created\n");
- return;
- }
if (!ns->audiosink) {
gnash::log_error("The gstreamer audiosink element could not be
created\n");
return;
}
+ } else {
+ ns->audiosink = gst_element_factory_make ("fakesink", NULL);
+ }
+
+ // setup the audio converter
+ ns->audioconv = gst_element_factory_make ("audioconvert", NULL);
+
+ // setup the volume controller
+ ns->volume = gst_element_factory_make ("volume", NULL);
+
+ if (!ns->audioconv || !ns->volume) {
+ gnash::log_error("Gstreamer audio element(s) for movie handling
could not be created\n");
+ return;
+ }
+
+ gst_bin_add_many (GST_BIN (ns->pipeline),ns->audiosink, ns->audioconv,
NULL);
// setup gnashnc source (our homegrown source element)
ns->source = gst_element_factory_make ("gnashsrc", NULL);
@@ -313,11 +333,6 @@
gc->seek = NetStreamGst::seekMedia;
g_object_set (G_OBJECT (ns->source), "data", ns, "callbacks", gc, NULL);
- // setup the audio converter
- ns->audioconv = gst_element_factory_make ("audioconvert", NULL);
-
- // setup the volume controller
- ns->volume = gst_element_factory_make ("volume", NULL);
// setup the decoder with callback
ns->decoder = gst_element_factory_make ("decodebin", NULL);
@@ -345,21 +360,23 @@
g_object_set (G_OBJECT (ns->videosink), "signal-handoffs", TRUE,
"sync", TRUE, NULL);
g_signal_connect (ns->videosink, "handoff", G_CALLBACK
(NetStreamGst::callback_output), ns);
- if (!ns->source || !ns->audioconv || !ns->volume || !ns->decoder ||
!ns->colorspace || !ns->videocaps || !ns->videorate || !ns->videosink) {
- gnash::log_error("Gstreamer element(s) for movie handling could
not be created\n");
+ if (!ns->source || !ns->decoder || !ns->colorspace || !ns->videocaps ||
!ns->videorate || !ns->videosink) {
+ gnash::log_error("Gstreamer element(s) for video movie handling
could not be created\n");
return;
}
// put it all in the pipeline
- gst_bin_add_many (GST_BIN (ns->pipeline), ns->source, ns->decoder,
ns->audiosink, ns->audioconv, ns->colorspace, ns->videosink, ns->videorate,
ns->videocaps, ns->volume, NULL);
+ gst_bin_add_many (GST_BIN (ns->pipeline), ns->source, ns->decoder,
ns->colorspace, ns->videosink, ns->videorate, ns->videocaps, ns->volume, NULL);
// link the elements
gst_element_link(ns->source, ns->decoder);
- gst_element_link_many(ns->audioconv, ns->volume, ns->audiosink, NULL);
gst_element_link_many(ns->colorspace, ns->videocaps, ns->videorate,
ns->videosink, NULL);
+ gst_element_link_many(ns->audioconv, ns->volume, ns->audiosink, NULL);
+
// start playing
gst_element_set_state (ns->pipeline, GST_STATE_PLAYING);
+
return;
}
@@ -371,18 +388,39 @@
void
NetStreamGst::seek(double pos)
{
-
if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET, GST_SECOND * static_cast<long>(pos),
GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
log_warning("Seek failed");
}
+
}
void
-NetStreamGst::setBufferTime()
+NetStreamGst::setBufferTime(double time)
{
- log_msg("%s:unimplemented \n", __FUNCTION__);
+ // The argument is in seconds, but we store in milliseconds
+ m_bufferTime = static_cast<uint32_t>(time*1000);
+}
+
+void
+NetStreamGst::advance()
+{
+/* if (m_go && m_pause && !m_imageframe && m_parser &&
m_parser->isTimeLoaded(m_bufferTime)) {
+ set_status("NetStream.Buffer.Full");
+ m_pause = false;
+ }
+*/
+ if (m_statusChanged) {
+/* fn_call dummy(NULL, NULL, 0, 0);
+ as_value info_asv(infoobject_new(dummy));
+ boost::intrusive_ptr<as_object> info = info_asv.to_object();
+
+ fn_call fn(this, v, 0, 0);
+
+ m_statusHandler.get()->call(fn);*/
+
+ }
}
int64_t
@@ -399,6 +437,8 @@
ret = gst_element_get_state (GST_ELEMENT (pipeline), ¤t,
&pending, 0);
if (current != GST_STATE_NULL && gst_element_query_position (pipeline,
&fmt, &pos)) {
+ pos = pos / 1000000000;
+
return pos;
} else {
return 0;
@@ -417,6 +457,29 @@
return _netCon->getBytesTotal();
}
+bool
+NetStreamGst::newFrameReady()
+{
+ if (m_newFrameReady) {
+ m_newFrameReady = false;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+as_function*
+NetStreamGst::getStatusHandler()
+{
+ return m_statusHandler.get();
+}
+
+void
+NetStreamGst::setStatusHandler(as_function* handler)
+{
+ m_statusHandler = handler;
+}
+
// Gstreamer callback function
int
NetStreamGst::readPacket(void* opaque, char* buf, int buf_size){
Index: server/asobj/NetStreamGst.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamGst.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- server/asobj/NetStreamGst.h 4 Mar 2007 21:35:31 -0000 1.8
+++ server/asobj/NetStreamGst.h 23 Mar 2007 00:30:10 -0000 1.9
@@ -44,12 +44,16 @@
void pause(int mode);
int play(const char* source);
void seek(double pos);
- void setBufferTime();
+ void setBufferTime(double time);
void set_status(const char* code);
void setNetCon(as_object* nc);
int64_t time();
long bytesLoaded();
long bytesTotal();
+ void advance();
+ bool newFrameReady();
+ as_function* getStatusHandler();
+ void setStatusHandler(as_function*);
// Used for gstreamer data read and seek callbacks
static int readPacket(void* opaque, char* buf, int buf_size);
@@ -88,8 +92,10 @@
GstElement *videoflip;
GstElement *audioconv;
+ // Are the playing loop running or not
volatile bool m_go;
+ // The image/videoframe which is given to the renderer
image::image_base* m_imageframe;
boost::thread *startThread;
@@ -101,6 +107,21 @@
// video info
int videowidth;
int videoheight;
+
+ volatile bool m_newFrameReady;
+
+ // The size of the buffer in milliseconds
+ uint32_t m_bufferTime;
+
+ // The status message
+ std::string m_status;
+
+ // Has the status message been updated?
+ volatile bool m_statusChanged;
+
+ // The handler which is invoked on status change
+ boost::intrusive_ptr<as_function> m_statusHandler;
+
};
} // gnash namespace
Index: server/asobj/SoundGst.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/SoundGst.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- server/asobj/SoundGst.cpp 27 Feb 2007 09:10:20 -0000 1.3
+++ server/asobj/SoundGst.cpp 23 Mar 2007 00:30:10 -0000 1.4
@@ -263,7 +263,6 @@
}
// start playing
gst_element_set_state (pipeline, GST_STATE_PLAYING);
-printf("playback started\n");
}
Index: libbase/FLVParser.cpp
===================================================================
RCS file: libbase/FLVParser.cpp
diff -N libbase/FLVParser.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libbase/FLVParser.cpp 23 Mar 2007 00:30:10 -0000 1.1
@@ -0,0 +1,458 @@
+//
+// 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 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// $Id: FLVParser.cpp,v 1.1 2007/03/23 00:30:10 tgc Exp $
+
+#include "FLVParser.h"
+#include "amf.h"
+
+FLVParser::FLVParser()
+ :
+ _lt(NULL),
+ _lastParsedPosition(0),
+ _parsingComplete(false),
+ _videoInfo(NULL),
+ _audioInfo(NULL),
+ _lastAudioFrame(-1),
+ _lastVideoFrame(-1),
+ _audio(false),
+ _video(false)
+{
+}
+
+FLVParser::~FLVParser()
+{
+ _videoFrames.clear();
+
+ _audioFrames.clear();
+}
+
+uint32_t FLVParser::videoFrameDelay()
+{
+ if (!_video || _lastVideoFrame < 1) return 0;
+
+ return _videoFrames[_lastVideoFrame]->timestamp -
_videoFrames[_lastVideoFrame-1]->timestamp;
+}
+
+FLVFrame* FLVParser::nextMediaFrame()
+{
+ uint32_t video_size = _videoFrames.size();
+ uint32_t audio_size = _audioFrames.size();
+
+
+ // Parse a media frame if any left or if needed
+ while(video_size == _videoFrames.size() && audio_size ==
_audioFrames.size() && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // Find the next frame in the file
+ bool audioReady = _audioFrames.size() > _lastAudioFrame+1;
+ bool videoReady = _videoFrames.size() > _lastVideoFrame+1;
+ bool useAudio = false;
+
+ if (audioReady && videoReady) {
+ useAudio = _audioFrames[_lastAudioFrame+1]->dataPosition <
_videoFrames[_lastVideoFrame+1]->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) {
+ _lastAudioFrame++;
+
+ FLVFrame* frame = new FLVFrame;
+ frame->dataSize = _audioFrames[_lastAudioFrame]->dataSize;
+ frame->timestamp = _audioFrames[_lastAudioFrame]->timestamp;
+
+ _lt->seek(_audioFrames[_lastAudioFrame]->dataPosition);
+ frame->data = new
uint8_t[_audioFrames[_lastAudioFrame]->dataSize];
+ _lt->read(frame->data, _audioFrames[_lastAudioFrame]->dataSize);
+ frame->tag = 8;
+ return frame;
+
+ } else {
+ _lastVideoFrame++;
+
+ FLVFrame* frame = new FLVFrame;
+ frame->dataSize = _videoFrames[_lastVideoFrame]->dataSize;
+ frame->timestamp = _videoFrames[_lastVideoFrame]->timestamp;
+
+ _lt->seek(_videoFrames[_lastVideoFrame]->dataPosition);
+ frame->data = new
uint8_t[_videoFrames[_lastVideoFrame]->dataSize];
+ _lt->read(frame->data, _videoFrames[_lastVideoFrame]->dataSize);
+ frame->tag = 9;
+ return frame;
+ }
+
+}
+
+FLVFrame* FLVParser::nextAudioFrame()
+{
+ // 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() <= static_cast<uint32_t>(_lastAudioFrame+1)
&& !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_audioFrames.size() < static_cast<uint32_t>(_lastAudioFrame+1))
return NULL;
+
+ _lastAudioFrame++;
+
+ FLVFrame* frame = new FLVFrame;
+ frame->dataSize = _audioFrames[_lastAudioFrame]->dataSize;
+ frame->timestamp = _audioFrames[_lastAudioFrame]->timestamp;
+
+ _lt->seek(_audioFrames[_lastAudioFrame]->dataPosition);
+ frame->data = new uint8_t[_audioFrames[_lastAudioFrame]->dataSize];
+ _lt->read(frame->data, _audioFrames[_lastAudioFrame]->dataSize);
+ return frame;
+
+}
+
+FLVFrame* FLVParser::nextVideoFrame()
+{
+ // If there are no video in this FLV return NULL
+ if (!_video && _lastParsedPosition > 0) return NULL;
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_videoFrames.size() <= static_cast<uint32_t>(_lastVideoFrame+1)
&& !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_videoFrames.size() < static_cast<uint32_t>(_lastVideoFrame+1))
return NULL;
+
+ _lastVideoFrame++;
+
+ FLVFrame* frame = new FLVFrame;
+ frame->dataSize = _videoFrames[_lastVideoFrame]->dataSize;
+ frame->timestamp = _videoFrames[_lastVideoFrame]->timestamp;
+
+ _lt->seek(_videoFrames[_lastVideoFrame]->dataPosition);
+ frame->data = new uint8_t[_videoFrames[_lastVideoFrame]->dataSize];
+ _lt->read(frame->data, _videoFrames[_lastVideoFrame]->dataSize);
+ 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
+ if (_audioFrames.back()->timestamp < time) {
+ _lastVideoFrame = _audioFrames.size() - 2;
+ return _audioFrames.back()->timestamp;
+ }
+
+ // We try to guess where in the vector the audioframe
+ // with the correct timestamp is
+ uint32_t numFrames = _audioFrames.size();
+ uint32_t guess = _audioFrames[numFrames-1]->timestamp / numFrames *
time;
+
+ // Here we test if the guess was ok, and adjust if needed.
+ uint32_t bestFrame = guess;
+ uint32_t diff = abs(_audioFrames[bestFrame]->timestamp - time);
+ while (true) {
+ if (bestFrame+1 < numFrames &&
static_cast<uint32_t>(abs(_audioFrames[bestFrame+1]->timestamp - time)) < diff)
{
+ bestFrame = bestFrame + 1;
+ diff = abs(_audioFrames[bestFrame+1]->timestamp - time);
+ } else if (bestFrame-1 > 0 &&
static_cast<uint32_t>(abs(_audioFrames[bestFrame+1]->timestamp - time)) < diff)
{
+ bestFrame = bestFrame - 1;
+ diff = abs(_audioFrames[bestFrame-1]->timestamp - time);
+ } else {
+ break;
+ }
+ }
+
+ _lastAudioFrame = bestFrame -1;
+ 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();
+ uint32_t numFrames = _audioFrames.size();
+ if (lastFrame->timestamp < time) {
+ uint32_t lastFrameNum = numFrames -1;
+ while (lastFrame->frameType != KEY_FRAME) {
+ lastFrameNum--;
+ lastFrame = _videoFrames[lastFrameNum];
+ }
+
+ _lastVideoFrame = lastFrameNum-1;
+ return lastFrame->timestamp;
+
+ }
+
+ // We try to guess where in the vector the videoframe
+ // with the correct timestamp is
+ uint32_t guess = lastFrame->timestamp / numFrames * time;
+
+ // Here we test if the guess was ok, and adjust if needed.
+ uint32_t bestFrame = guess;
+ uint32_t diff = abs(_audioFrames[bestFrame]->timestamp - time);
+ while (true) {
+ if (bestFrame+1 < numFrames &&
static_cast<uint32_t>(abs(_audioFrames[bestFrame+1]->timestamp - time)) < diff)
{
+ bestFrame = bestFrame + 1;
+ diff = abs(_audioFrames[bestFrame+1]->timestamp - time);
+ } else if (bestFrame-1 > 0 &&
static_cast<uint32_t>(abs(_audioFrames[bestFrame+1]->timestamp - time)) < diff)
{
+ bestFrame = bestFrame - 1;
+ diff = abs(_audioFrames[bestFrame-1]->timestamp - time);
+ } else {
+ break;
+ }
+ }
+
+ uint32_t rewindKeyframe = bestFrame;
+ uint32_t forwardKeyframe = bestFrame;
+
+ // Rewind to the lastest keyframe
+ while (_videoFrames[rewindKeyframe]->frameType != KEY_FRAME) {
+ rewindKeyframe--;
+ }
+
+ // Forward to the next keyframe
+ uint32_t size = _videoFrames.size();
+ while (size > forwardKeyframe &&
_videoFrames[forwardKeyframe]->frameType != KEY_FRAME) {
+ forwardKeyframe++;
+ }
+
+ int32_t forwardDiff = _videoFrames[forwardKeyframe]->timestamp - time;
+ int32_t rewindDiff = time - _videoFrames[rewindKeyframe]->timestamp;
+
+ if (forwardDiff < rewindDiff) bestFrame = forwardKeyframe;
+ else bestFrame = rewindKeyframe;
+
+ _lastVideoFrame = bestFrame - 1;
+ return _audioFrames[bestFrame]->timestamp;
+}
+
+
+
+FLVVideoInfo* FLVParser::getVideoInfo()
+{
+ // If there are no video in this FLV return NULL
+ if (!_video && _lastParsedPosition > 0) return NULL;
+
+ // Make sure that there are parsed some video frames
+ while(_videoInfo == NULL && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there are no audio data return NULL
+ if (_videoInfo == NULL) return NULL;
+
+ FLVVideoInfo* info = new FLVVideoInfo(_videoInfo->codec,
_videoInfo->width, _videoInfo->height, _videoInfo->frameRate,
_videoInfo->duration);
+ return info;
+
+}
+
+FLVAudioInfo* FLVParser::getAudioInfo()
+{
+ // If there are no audio in this FLV return NULL
+ if (!_audio && _lastParsedPosition > 0) return NULL;
+
+ // Make sure that there are parsed some audio frames
+ while(_audioInfo == NULL && !_parsingComplete) {
+ parseNextFrame();
+ }
+
+ // If there are no audio data return NULL
+ if (_audioInfo == NULL) return NULL;
+
+ FLVAudioInfo* info = new FLVAudioInfo(_audioInfo->codec,
_audioInfo->sampleRate, _audioInfo->sampleSize, _audioInfo->stereo,
_audioInfo->duration);
+ return info;
+
+}
+
+bool FLVParser::isTimeLoaded(uint32_t time)
+{
+ // Parse frames until the need time is found, or EOF
+ while (!_parsingComplete && (_videoFrames.size() > 0 &&
_videoFrames.back()->timestamp < time) && (_audioFrames.size() > 0 &&
_audioFrames.back()->timestamp < time)) {
+ parseNextFrame();
+ }
+
+ 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)
+{
+
+ 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
+ _lt->seek(_lastParsedPosition+4);
+
+ // Read the tag info
+ uint8_t 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 (tag[0] == AUDIO_TAG) {
+ FLVAudioFrame* frame = new FLVAudioFrame;
+ frame->dataSize = bodyLength - 1;
+ frame->timestamp = timestamp;
+ frame->dataPosition = _lt->tell();
+ _audioFrames.push_back(frame);
+
+ // If this is the first audioframe no info about the
+ // audio format has been noted, so we do that now
+ if (_audioInfo == NULL) {
+ _audioInfo = new FLVAudioInfo((tag[11] & 0xf0) >> 4,
(tag[11] & 0x0C) >> 2, (tag[11] & 0x02) >> 1, (tag[11] & 0x01) >> 0, 0);
+ }
+ _lastParsedPosition += 15 + bodyLength;
+
+ } else if (tag[0] == VIDEO_TAG) {
+ FLVVideoFrame* frame = new FLVVideoFrame;
+ frame->dataSize = bodyLength - 1;
+ frame->timestamp = timestamp;
+ frame->dataPosition = _lt->tell();
+ frame->frameType = (tag[11] & 0xf0) >> 4;
+ _videoFrames.push_back(frame);
+
+ // If this is the first videoframe no info about the
+ // video format has been noted, so we do that now
+ if (_videoInfo == NULL) {
+
+ // TODO: parse the video frame header to extract info
about the width and height.
+ _videoInfo = new FLVVideoInfo((tag[11] & 0x0f) >> 0, 0
/*width*/, 0 /*height*/, 0 /*frameRate*/, 0 /*duration*/);
+ }
+ _lastParsedPosition += 15 + bodyLength;
+
+ } else if (tag[0] == 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 += 15 + bodyLength;
+ } else {
+ _parsingComplete = true;
+ }
+ return true;
+}
+
+bool FLVParser::parseHeader()
+{
+ // seek to the begining of the file
+ _lt->seek(0);
+
+ // Read the header
+ uint8_t 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;
+
+ // Parse the audio+video bitmask
+ if (header[4] == 5) {
+ _audio = true;
+ _video = true;
+ } else if (header[4] == 4) {
+ _audio = true;
+ _video = false;
+ } else if (header[4] == 4) {
+ _audio = false;
+ _video = true;
+ } else {
+ printf("Weird bit mask\n");
+ }
+
+ _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];
+}
+
+void FLVParser::setLoadThread(LoadThread* lt)
+{
+ _lt = lt;
+}
Index: libbase/FLVParser.h
===================================================================
RCS file: libbase/FLVParser.h
diff -N libbase/FLVParser.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libbase/FLVParser.h 23 Mar 2007 00:30:10 -0000 1.1
@@ -0,0 +1,246 @@
+//
+// 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 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+// $Id: FLVParser.h,v 1.1 2007/03/23 00:30:10 tgc Exp $
+
+// Information about the FLV format can be found at http://osflash.org/flv
+
+#ifndef __FLVPARSER_H__
+#define __FLVPARSER_H__
+
+#include "LoadThread.h"
+#include <vector>
+
+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 = 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
+/// timestamp,
+class FLVFrame
+{
+public:
+ int dataSize;
+ uint8_t* data;
+ uint32_t timestamp;
+ uint8_t tag;
+};
+
+/// \brief
+/// The FLVAudioInfo class contains information about the audiostream
+/// in the FLV being parsed. The information stored is codec-type,
+/// samplerate, samplesize, stereo and duration.
+/// timestamp,
+class FLVAudioInfo
+{
+public:
+ FLVAudioInfo(int codeci, int sampleRatei, int sampleSizei, bool
stereoi, long durationi)
+ : codec(codeci),
+ sampleRate(sampleRatei),
+ sampleSize(sampleSizei),
+ stereo(stereoi),
+ duration(durationi)
+ {
+ }
+
+ int codec;
+ int sampleRate;
+ int sampleSize;
+ bool stereo;
+ long duration;
+};
+
+/// \brief
+/// The FLVVideoInfo class contains information about the videostream
+/// in the FLV being parsed. The information stored is codec-type,
+/// width, height, framerate and duration.
+/// timestamp,
+class FLVVideoInfo
+{
+public:
+ FLVVideoInfo(int codeci, int widthi, int heighti, int frameRatei, long
durationi)
+ : codec(codeci),
+ width(widthi),
+ height(heighti),
+ frameRate(frameRatei),
+ duration(durationi)
+ {
+ }
+
+ uint16_t codec;
+ uint16_t width;
+ uint16_t height;
+ uint16_t frameRate;
+ long duration;
+};
+
+
+class FLVVideoFrame
+{
+public:
+ uint16_t frameType;
+ uint32_t dataSize;
+ long dataPosition;
+ uint32_t timestamp;
+
+};
+
+class FLVAudioFrame
+{
+public:
+ uint32_t dataSize;
+ long dataPosition;
+ uint32_t timestamp;
+
+};
+
+/// \brief
+/// The FLVParser class parses a FLV file, and can return
+/// video or audio frames for a specific time, or just
+/// get the next in the timeline.
+
+class FLVParser
+{
+
+public:
+ /// Creating the object...
+ FLVParser();
+
+ /// Kills the parser...
+ ~FLVParser();
+
+ FLVFrame* nextMediaFrame();
+
+ /// Returns the next audio frame in the timeline. If no frame has been
+ /// played before the first frame is returned. If there is no more
frames
+ /// in the timeline NULL is returned.
+ FLVFrame* nextAudioFrame();
+
+ /// Returns the next video frame in the timeline. If no frame has been
+ /// played before the first frame is returned. If there is no more
frames
+ /// in the timeline NULL is returned.
+ FLVFrame* nextVideoFrame();
+
+ /// Returns a FLVVideoInfo class about the videostream
+ FLVVideoInfo* getVideoInfo();
+
+ /// Returns a FLVAudioInfo class about the audiostream
+ FLVAudioInfo* getAudioInfo();
+
+ /// Sets the LoadThread which is used as interface
+ void setLoadThread(LoadThread* lt);
+
+ /// 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.
+ bool isTimeLoaded(uint32_t time);
+
+ /// seeks to the closest possible position the given position,
+ /// and returns the new position.
+ uint32_t seek(uint32_t);
+
+ /// Returns the framedelay from the last to the current
+ /// videoframe in milliseconds. This is used for framerate.
+ uint32_t videoFrameDelay();
+
+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 is 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
+ LoadThread* _lt;
+
+ /// list of videoframes, does no contain the frame data.
+ std::vector<FLVVideoFrame*> _videoFrames;
+
+ /// list of audioframes, does no contain the frame data.
+ std::vector<FLVAudioFrame*> _audioFrames;
+
+ /// The position where the parsing should continue from.
+ long _lastParsedPosition;
+
+ /// Whether the parsing is complete or not
+ bool _parsingComplete;
+
+ /// Info about the video stream
+ FLVVideoInfo* _videoInfo;
+
+ /// Info about the audio stream
+ FLVAudioInfo* _audioInfo;
+
+ /// Last audio frame returned
+ int _lastAudioFrame;
+
+ /// Last video frame returned
+ int _lastVideoFrame;
+
+ /// Audio stream is present
+ bool _audio;
+
+ /// Audio stream is present
+ bool _video;
+};
+
+#endif // __FLVPARSER_H__
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] gnash ChangeLog backend/sound_handler_sdl.cpp l...,
Tomas Groth <=