[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog libbase/Makefile.am libmedia/Au...
From: |
Sandro Santilli |
Subject: |
[Gnash-commit] gnash ChangeLog libbase/Makefile.am libmedia/Au... |
Date: |
Tue, 03 Jun 2008 12:39:55 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Sandro Santilli <strk> 08/06/03 12:39:55
Modified files:
. : ChangeLog
libbase : Makefile.am
libmedia : AudioDecoder.h AudioDecoderNellymoser.h
Makefile.am MediaParser.h SoundInfo.h
VideoDecoder.h
libmedia/ffmpeg: AudioDecoderFfmpeg.cpp VideoDecoderFfmpeg.cpp
VideoDecoderFfmpeg.h
libmedia/gst : VideoDecoderGst.cpp VideoDecoderGst.h
server/asobj : NetConnection.cpp NetConnection.h NetStream.h
NetStreamFfmpeg.cpp
server/parser : video_stream_def.h
Added files:
libmedia : FLVParser.cpp FLVParser.h
Removed files:
libbase : FLVParser.cpp FLVParser.h
libmedia : MediaDecoder.cpp MediaDecoder.h
libmedia/gst : MediaDecoderGst.cpp MediaDecoderGst.h
Log message:
* libbase/FLVParser.{cpp,h} => libmedia/FLVParser.{cpp,h},
libbase/Makefile.am, libmedia/Makefile.am:
Moved FLVParser under libmedia and make it a MediaParser.
* libmedia/AudioDecoder.h, libmedia/AudioDecoderNellymoser.h,
libmedia/SoundInfo.h
Streamline headers inclusion.
* libmedia/VideoDecoder.h: drop EncodedVideoFrame, moved to
MediaParser
* libmedia/MediaDecoder.{cpp,h}, libmedia/gst/MediaDecoderGst.{cpp,h}:
drop unused files.
* libmedia/MediaParser.h: extend MediaParser interface to expose all
needed stuff.
* libmedia/ffmpeg/AudioDecoderFfmpeg.cpp,
libmedia/ffmpeg/VideoDecoderFfmpeg.{cpp,h},
libmedia/gst/VideoDecoderGst.{cpp,h}: minor cleanups
* server/asobj/NetConnection.{cpp,h}: cleanups
* server/asobj/NetStream.h: m_parser is a MediaParser now.
* server/asobj/NetStreamFfmpeg.cpp: update use of the parser
* server/parser/video_stream_def.h: include MediaParser for enums.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.6789&r2=1.6790
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/Makefile.am?cvsroot=gnash&r1=1.115&r2=1.116
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/FLVParser.cpp?cvsroot=gnash&r1=1.43&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/FLVParser.h?cvsroot=gnash&r1=1.32&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoder.h?cvsroot=gnash&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/AudioDecoderNellymoser.h?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/Makefile.am?cvsroot=gnash&r1=1.21&r2=1.22
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/MediaParser.h?cvsroot=gnash&r1=1.15&r2=1.16
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/SoundInfo.h?cvsroot=gnash&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/VideoDecoder.h?cvsroot=gnash&r1=1.16&r2=1.17
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/FLVParser.cpp?cvsroot=gnash&rev=1.9
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/FLVParser.h?cvsroot=gnash&rev=1.11
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/MediaDecoder.cpp?cvsroot=gnash&r1=1.6&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/MediaDecoder.h?cvsroot=gnash&r1=1.8&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/ffmpeg/VideoDecoderFfmpeg.h?cvsroot=gnash&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/VideoDecoderGst.cpp?cvsroot=gnash&r1=1.19&r2=1.20
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/VideoDecoderGst.h?cvsroot=gnash&r1=1.17&r2=1.18
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/MediaDecoderGst.cpp?cvsroot=gnash&r1=1.5&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/gst/MediaDecoderGst.h?cvsroot=gnash&r1=1.4&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetConnection.cpp?cvsroot=gnash&r1=1.62&r2=1.63
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetConnection.h?cvsroot=gnash&r1=1.43&r2=1.44
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStream.h?cvsroot=gnash&r1=1.64&r2=1.65
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.cpp?cvsroot=gnash&r1=1.138&r2=1.139
http://cvs.savannah.gnu.org/viewcvs/gnash/server/parser/video_stream_def.h?cvsroot=gnash&r1=1.27&r2=1.28
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.6789
retrieving revision 1.6790
diff -u -b -r1.6789 -r1.6790
--- ChangeLog 3 Jun 2008 12:27:25 -0000 1.6789
+++ ChangeLog 3 Jun 2008 12:39:51 -0000 1.6790
@@ -1,3 +1,25 @@
+2008-06-03 Sandro Santilli <address@hidden>
+
+ * libbase/FLVParser.{cpp,h} => libmedia/FLVParser.{cpp,h},
+ libbase/Makefile.am, libmedia/Makefile.am:
+ Moved FLVParser under libmedia and make it a MediaParser.
+ * libmedia/AudioDecoder.h, libmedia/AudioDecoderNellymoser.h,
+ libmedia/SoundInfo.h
+ Streamline headers inclusion.
+ * libmedia/VideoDecoder.h: drop EncodedVideoFrame, moved to
+ MediaParser
+ * libmedia/MediaDecoder.{cpp,h}, libmedia/gst/MediaDecoderGst.{cpp,h}:
+ drop unused files.
+ * libmedia/MediaParser.h: extend MediaParser interface to expose all
+ needed stuff.
+ * libmedia/ffmpeg/AudioDecoderFfmpeg.cpp,
+ libmedia/ffmpeg/VideoDecoderFfmpeg.{cpp,h},
+ libmedia/gst/VideoDecoderGst.{cpp,h}: minor cleanups
+ * server/asobj/NetConnection.{cpp,h}: cleanups
+ * server/asobj/NetStream.h: m_parser is a MediaParser now.
+ * server/asobj/NetStreamFfmpeg.cpp: update use of the parser
+ * server/parser/video_stream_def.h: include MediaParser for enums.
+
2008-06-03 Benjamin Wolsey <address@hidden>
* server/cxform.{cpp,h}: drop cxform::print().
Index: libbase/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/libbase/Makefile.am,v
retrieving revision 1.115
retrieving revision 1.116
diff -u -b -r1.115 -r1.116
--- libbase/Makefile.am 27 May 2008 16:13:15 -0000 1.115
+++ libbase/Makefile.am 3 Jun 2008 12:39:52 -0000 1.116
@@ -125,7 +125,6 @@
zlib_adapter.cpp \
URL.cpp \
LoadThread.cpp \
- FLVParser.cpp \
GC.cpp \
BitsReader.cpp \
arg_parser.cpp \
@@ -162,7 +161,6 @@
zlib_adapter.h \
URL.h \
LoadThread.h \
- FLVParser.h \
GC.h \
BitsReader.h \
arg_parser.h \
Index: libmedia/AudioDecoder.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/AudioDecoder.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- libmedia/AudioDecoder.h 6 Mar 2008 05:22:51 -0000 1.10
+++ libmedia/AudioDecoder.h 3 Jun 2008 12:39:52 -0000 1.11
@@ -20,10 +20,16 @@
#ifndef __AUDIODECODER_H__
#define __AUDIODECODER_H__
-#include "MediaParser.h"
#include "SoundInfo.h"
#include "Util.h"
+// Forward declarations
+namespace gnash {
+ namespace media {
+ class AudioInfo;
+ }
+}
+
namespace gnash {
namespace media {
Index: libmedia/AudioDecoderNellymoser.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/AudioDecoderNellymoser.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- libmedia/AudioDecoderNellymoser.h 5 Mar 2008 03:55:53 -0000 1.9
+++ libmedia/AudioDecoderNellymoser.h 3 Jun 2008 12:39:52 -0000 1.10
@@ -59,6 +59,12 @@
#define NELLY_BASE_OFF 4228
#define NELLY_BASE_SHIFT 19
+// Forward declarations
+namespace gnash {
+ namespace media {
+ class AudioInfo;
+ }
+}
typedef struct nelly_handle_struct {
Index: libmedia/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/libmedia/Makefile.am,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- libmedia/Makefile.am 9 May 2008 17:28:21 -0000 1.21
+++ libmedia/Makefile.am 3 Jun 2008 12:39:53 -0000 1.22
@@ -75,6 +75,7 @@
libgnashmedia_la_SOURCES = \
AudioDecoderNellymoser.cpp \
AudioDecoderSimple.cpp \
+ FLVParser.cpp \
Util.cpp \
$(NULL)
@@ -83,6 +84,7 @@
AudioDecoder.h \
VideoDecoder.h \
MediaParser.h \
+ FLVParser.h \
AudioDecoderNellymoser.h \
AudioDecoderSimple.h \
sound_handler.h \
Index: libmedia/MediaParser.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/MediaParser.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -b -r1.15 -r1.16
--- libmedia/MediaParser.h 23 May 2008 05:58:08 -0000 1.15
+++ libmedia/MediaParser.h 3 Jun 2008 12:39:53 -0000 1.16
@@ -24,25 +24,11 @@
#include "gnashconfig.h"
#endif
-#include <boost/shared_ptr.hpp>
-#include "tu_file.h"
-
-#ifdef USE_FFMPEG
-#ifdef HAVE_FFMPEG_AVCODEC_H
-extern "C" {
-# include "ffmpeg/avcodec.h"
-}
-#endif
-
-#ifdef HAVE_LIBAVCODEC_AVCODEC_H
-extern "C" {
-# include "libavcodec/avcodec.h"
-}
-#endif
-#endif // USE_FFMPEG
-
+#include <boost/scoped_array.hpp>
#include <memory>
+#include "tu_file.h"
+
namespace gnash {
namespace media {
@@ -66,6 +52,9 @@
FLASH,
/// Ffmpegs codecs ids
+ //
+ /// TODO: make this media-handler agnostic
+ ///
FFMPEG
};
@@ -110,19 +99,6 @@
AUDIO_CODEC_NELLYMOSER = 6
};
-/// Type of frame in FLVs. Also type of the frame contained in the MediaFrame
class.
-enum tagType
-{
- /// Audio frame
- AUDIO_TAG = 0x08,
-
- /// Video frame
- VIDEO_TAG = 0x09,
-
- /// Meta frame
- META_TAG = 0x12
-};
-
/// \brief
/// The AudioInfo class contains information about the audiostream
/// in the file being parsed. The information stored is codec-id,
@@ -137,9 +113,6 @@
sampleSize(sampleSizei),
stereo(stereoi),
duration(durationi),
-#ifdef USE_FFMPEG
- audioCodecCtx(NULL),
-#endif
type(typei)
{
}
@@ -149,9 +122,6 @@
boost::uint16_t sampleSize;
bool stereo;
boost::uint64_t duration;
-#ifdef USE_FFMPEG
- AVCodecContext* audioCodecCtx; // If videoCodecCtx is ugly, so is this.
-#endif
codecType type;
};
@@ -169,9 +139,6 @@
height(heighti),
frameRate(frameRatei),
duration(durationi),
-#ifdef USE_FFMPEG
- videoCodecCtx(NULL),
-#endif
type(typei)
{
}
@@ -181,35 +148,88 @@
boost::uint16_t height;
boost::uint16_t frameRate;
boost::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
+/// An encoded video frame
+class EncodedVideoFrame
+{
+public:
+
+ /// Create an encoded video frame
+ //
+ /// @param data
+ /// Data buffer, ownership transferred
+ ///
+ /// @param size
+ /// Size of the data buffer
+ ///
+ /// @param frameNum
+ /// Frame number.
+ ///
+ /// @param type
+ /// Video frame type
+ ///
+ /// @param timestamp
+ /// Presentation timestamp, in milliseconds.
+ ///
+ EncodedVideoFrame(boost::uint8_t* data, boost::uint32_t size,
+ unsigned int frameNum,
+ boost::uint64_t timestamp=0)
+ :
+ _size(size),
+ _data(data),
+ _frameNum(frameNum),
+ _timestamp(timestamp)
+ {}
+
+ /// Return pointer to actual data. Ownership retained by this class.
+ const boost::uint8_t* data() const { return _data.get(); }
+
+ /// Return size of data buffer.
+ boost::uint32_t dataSize() const { return _size; }
+
+ /// Return video frame presentation timestamp
+ boost::uint64_t timestamp() const { return _timestamp; }
+
+ /// Return video frame number
+ unsigned frameNum() const { return _frameNum; }
+
+private:
+
+ boost::uint32_t _size;
+ boost::scoped_array<boost::uint8_t> _data;
+ unsigned int _frameNum;
+ boost::uint64_t _timestamp;
+};
+
+/// An encoded audio frame
+class EncodedAudioFrame
{
public:
boost::uint32_t dataSize;
- boost::uint8_t* data;
+ boost::scoped_array<boost::uint8_t> data;
boost::uint64_t timestamp;
- boost::uint8_t tag;
};
-/// \brief
-/// The MediaParser class detects the format of the input file, and parses it
on demand.
+/// The MediaParser class provides cursor-based access to encoded media frames
+//
+/// Cursor-based access allow seeking as close as possible to a specified time
+/// and fetching frames from there on, sequentially.
+/// See seek(), nextVideoFrame(), nextAudioFrame()
+///
+/// Input is received from a tu_file object.
///
class MediaParser
{
public:
- MediaParser(boost::shared_ptr<tu_file> stream)
+
+ MediaParser(std::auto_ptr<tu_file> stream)
:
_isAudioMp3(false),
_isAudioNellymoser(false),
- _stream(stream)
+ _stream(stream),
+ _parsingComplete(false)
{}
// Classes with virtual methods (virtual classes)
@@ -219,62 +239,132 @@
//
virtual ~MediaParser() {};
- /// 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; }
+ /// Returns the "bufferlength", meaning the difference between the
+ /// current frames timestamp and the timestamp of the last parseable
+ /// frame. Returns the difference in milliseconds.
+ //
+ virtual boost::uint32_t getBufferLength()=0;
+
+ /// Get timestamp of the video frame which would be returned on
nextVideoFrame
+ //
+ /// @return false if there no video frame left
+ /// (either none or no more)
+ ///
+ virtual bool nextVideoFrameTimestamp(boost::uint64_t& ts)=0;
+
+ /// Returns the next video frame in the parsed buffer, advancing video
cursor.
+ //
+ /// 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.
+ ///
+ virtual std::auto_ptr<EncodedVideoFrame> nextVideoFrame()=0;
+
+ /// Get timestamp of the audio frame which would be returned on
nextAudioFrame
+ //
+ /// @return false if there no video frame left
+ /// (either none or no more)
+ ///
+ virtual bool nextAudioFrameTimestamp(boost::uint64_t& ts)=0;
+
+ /// Returns the next audio frame in the parsed buffer, advancing audio
cursor.
+ //
+ /// 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.
+ ///
+ virtual std::auto_ptr<EncodedAudioFrame> nextAudioFrame()=0;
/// 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); }
+ /// @return a VideoInfo class about the videostream,
+ /// or zero if stream contains no video
+ ///
+ virtual VideoInfo* getVideoInfo() { return 0; }
/// 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 a AudioInfo class about the audiostream,
+ /// or zero if stream contains no audio
+ ///
+ virtual AudioInfo* getAudioInfo() { return 0; }
+
+ /// Seeks to the closest possible position the given position.
+ //
+ /// Valid seekable position are constrained by key-frames when
+ /// video data is available. Actual seek position should be always
+ /// less of equal the requested one.
+ ///
/// @return the position the seek reached
+ ///
virtual boost::uint32_t seek(boost::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 boost::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 boost::uint32_t videoFrameDelay() { return 0; }
/// Returns the framerate of the video
//
/// @return the framerate of the video
+ ///
virtual boost::uint16_t videoFrameRate() { return 0; }
/// Returns the last parsed position in the file in bytes
virtual boost::uint32_t getLastParsedPos() { return 0; }
+ /// Parse next input chunk
+ //
+ /// Returns true if something was parsed, false otherwise.
+ /// See parsingCompleted().
+ ///
+ virtual bool parseNextChunk() { return false; }
+
+ /// 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; }
+
+ /// Return number of bytes parsed so far
+ virtual boost::uint64_t getBytesLoaded() const { return 0; }
+
+ /// Return total number of bytes in input
+ boost::uint64_t getBytesTotal() const
+ {
+ return _stream->get_size();
+ }
+
protected:
/// Is the input audio MP3?
@@ -284,7 +374,10 @@
bool _isAudioNellymoser;
/// The stream used to access the file
- boost::shared_ptr<tu_file> _stream;
+ std::auto_ptr<tu_file> _stream;
+
+ /// Whether the parsing is complete or not
+ bool _parsingComplete;
};
Index: libmedia/SoundInfo.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/SoundInfo.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- libmedia/SoundInfo.h 5 Mar 2008 03:55:54 -0000 1.6
+++ libmedia/SoundInfo.h 3 Jun 2008 12:39:53 -0000 1.7
@@ -22,7 +22,7 @@
#ifndef __SOUNDINFO_H__
#define __SOUNDINFO_H__
-#include "MediaParser.h"
+#include "MediaParser.h" // for audioCodecType enum
namespace gnash {
namespace media {
Index: libmedia/VideoDecoder.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/VideoDecoder.h,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -b -r1.16 -r1.17
--- libmedia/VideoDecoder.h 5 Mar 2008 03:55:54 -0000 1.16
+++ libmedia/VideoDecoder.h 3 Jun 2008 12:39:53 -0000 1.17
@@ -20,15 +20,19 @@
#ifndef __VIDEODECODER_H__
#define __VIDEODECODER_H__
-#include "MediaParser.h"
#include "image.h"
#include <boost/noncopyable.hpp>
+// Forward declarations
namespace gnash {
-namespace media {
+ namespace media {
+ class EncodedVideoFrame;
+ }
+}
-class EncodedVideoFrame;
+namespace gnash {
+namespace media {
/// Abstract base class for embedded video decoders.
//
@@ -68,44 +72,6 @@
};
-/// This class represents a video frame that has not yet been decoded.
-class EncodedVideoFrame : public boost::noncopyable
-{
-public:
- /// @param buffer Pointer to the video data corresponding to this frame. This
- /// class takes ownership of the pointer.
- /// @param buf_size The size, in bytes, of the data pointed to in the buffer
- /// argument
- /// @param frame_number The number of the frame in the video stream.
- EncodedVideoFrame(boost::uint8_t* buffer, size_t buf_size, size_t frame_num)
- : _buffer(buffer),
- _buffer_size(buf_size),
- _frame_number(frame_num)
- {}
-
- uint8_t* data() const
- {
- return _buffer.get();
- }
-
- size_t dataSize() const
- {
- return _buffer_size;
- }
-
- size_t frameNum() const
- {
- return _frame_number;
- }
-
-private:
- boost::scoped_array<uint8_t> _buffer;
- size_t _buffer_size;
- size_t _frame_number;
-};
-
-
-
} // gnash.media namespace
} // gnash namespace
Index: libmedia/ffmpeg/AudioDecoderFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libmedia/ffmpeg/AudioDecoderFfmpeg.cpp 5 Mar 2008 03:55:54 -0000
1.3
+++ libmedia/ffmpeg/AudioDecoderFfmpeg.cpp 3 Jun 2008 12:39:53 -0000
1.4
@@ -143,16 +143,8 @@
return false;
}
- // Reuse the audioCodecCtx from the ffmpeg parser if exists/possible
- if (info->audioCodecCtx)
- {
- log_debug("re-using the parser's audioCodecCtx");
- _audioCodecCtx = info->audioCodecCtx;
- }
- else
- {
+ // Create an audioCodecCtx from the ffmpeg parser if exists/possible
_audioCodecCtx = avcodec_alloc_context();
- }
if (!_audioCodecCtx) {
log_error(_("libavcodec couldn't allocate context"));
Index: libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- libmedia/ffmpeg/VideoDecoderFfmpeg.cpp 23 May 2008 05:58:09 -0000
1.9
+++ libmedia/ffmpeg/VideoDecoderFfmpeg.cpp 3 Jun 2008 12:39:54 -0000
1.10
@@ -160,7 +160,7 @@
}
std::auto_ptr<image::rgb>
-VideoDecoderFfmpeg::decode(boost::uint8_t* input, boost::uint32_t input_size)
+VideoDecoderFfmpeg::decode(const boost::uint8_t* input, boost::uint32_t
input_size)
{
std::auto_ptr<image::rgb> ret;
@@ -171,7 +171,8 @@
}
int bytes = 0;
- avcodec_decode_video(_videoCodecCtx, frame, &bytes, input, input_size);
+ // no idea why avcodec_decode_video wants a non-const input...
+ avcodec_decode_video(_videoCodecCtx, frame, &bytes,
const_cast<boost::uint8_t*>(input), input_size);
if (!bytes) {
log_error("Decoding of a video frame failed");
Index: libmedia/ffmpeg/VideoDecoderFfmpeg.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/ffmpeg/VideoDecoderFfmpeg.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- libmedia/ffmpeg/VideoDecoderFfmpeg.h 23 May 2008 05:58:09 -0000
1.10
+++ libmedia/ffmpeg/VideoDecoderFfmpeg.h 3 Jun 2008 12:39:54 -0000
1.11
@@ -27,6 +27,7 @@
#include "dsodefs.h" //For DSOEXPORT
#include "log.h"
#include "VideoDecoder.h"
+#include "MediaParser.h" // for videoCodecType enum
#ifdef HAVE_FFMPEG_AVCODEC_H
extern "C" {
@@ -70,7 +71,7 @@
private:
- std::auto_ptr<image::rgb> decode(boost::uint8_t* input, boost::uint32_t
input_size);
+ std::auto_ptr<image::rgb> decode(const boost::uint8_t* input,
boost::uint32_t input_size);
std::auto_ptr<image::rgb> decode(const EncodedVideoFrame* vf)
{
Index: libmedia/gst/VideoDecoderGst.cpp
===================================================================
RCS file: /sources/gnash/gnash/libmedia/gst/VideoDecoderGst.cpp,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -b -r1.19 -r1.20
--- libmedia/gst/VideoDecoderGst.cpp 7 May 2008 01:28:02 -0000 1.19
+++ libmedia/gst/VideoDecoderGst.cpp 3 Jun 2008 12:39:54 -0000 1.20
@@ -133,7 +133,8 @@
GstBuffer* buffer = gst_buffer_new();
- GST_BUFFER_DATA(buffer) = frame.data();
+ // dunno why gst needs non-const here
+ GST_BUFFER_DATA(buffer) = const_cast<uint8_t*>(frame.data());
GST_BUFFER_SIZE(buffer) = frame.dataSize();
GST_BUFFER_OFFSET(buffer) = frame.frameNum();
GST_BUFFER_TIMESTAMP(buffer) = GST_CLOCK_TIME_NONE;
Index: libmedia/gst/VideoDecoderGst.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/gst/VideoDecoderGst.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- libmedia/gst/VideoDecoderGst.h 28 Mar 2008 16:23:07 -0000 1.17
+++ libmedia/gst/VideoDecoderGst.h 3 Jun 2008 12:39:54 -0000 1.18
@@ -26,11 +26,12 @@
#endif
#include "image.h"
-#include <gst/gst.h>
#include "log.h"
-#include "MediaParser.h"
#include "VideoDecoder.h"
#include "dsodefs.h"
+#include "MediaParser.h" // for videoCodecType enum
+
+#include <gst/gst.h>
namespace gnash {
Index: server/asobj/NetConnection.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetConnection.cpp,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -b -r1.62 -r1.63
--- server/asobj/NetConnection.cpp 27 May 2008 11:58:45 -0000 1.62
+++ server/asobj/NetConnection.cpp 3 Jun 2008 12:39:54 -0000 1.63
@@ -194,6 +194,7 @@
/*public*/
+/// TODO: drop
size_t
NetConnection::tell()
{
@@ -203,6 +204,7 @@
/*public*/
+/// TODO: drop
long
NetConnection::getBytesLoaded()
{
@@ -212,6 +214,7 @@
/*public*/
+/// TODO: drop
long
NetConnection::getBytesTotal()
{
@@ -221,6 +224,7 @@
/*public*/
+/// TODO: drop
bool
NetConnection::loadCompleted()
{
@@ -233,20 +237,6 @@
}
-std::auto_ptr<FLVParser>
-NetConnection::getConnectedParser()
-{
- std::auto_ptr<FLVParser> ret;
-
- if ( _loader.get() ) {
- ret.reset( new FLVParser(_loader) ); // transfer loader ownership
- assert(!_loader.get());
- }
-
- return ret;
-}
-
-
/// \brief callback to instantiate a new NetConnection object.
/// \param fn the parameters from the Flash movie
/// \return nothing from the function call.
Index: server/asobj/NetConnection.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetConnection.h,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -b -r1.43 -r1.44
--- server/asobj/NetConnection.h 27 May 2008 11:58:46 -0000 1.43
+++ server/asobj/NetConnection.h 3 Jun 2008 12:39:54 -0000 1.44
@@ -20,8 +20,6 @@
#define __NETCONNECTION_H__
#include "tu_file.h"
-//#include "LoadThread.h"
-//#include "FLVParser.h"
#include <stdexcept>
#include <cstdio>
@@ -39,7 +37,6 @@
// Forward declarations
namespace gnash {
//class NetStream;
- class FLVParser;
}
namespace gnash {
@@ -111,6 +108,8 @@
///
/// Return number of actually read bytes
///
+ /// TODO: drop
+ ///
size_t read(void *dst, size_t bytes);
/// Return true if EOF has been reached
@@ -125,6 +124,8 @@
/// This call never blocks.
/// If not connected, 0 is returned (is this correct behaviour?)
///
+ /// TODO: drop
+ ///
size_t tell();
/// Returns the number of bytes cached
@@ -132,6 +133,8 @@
/// This call never blocks.
/// If not connected, 0 is returned (is this correct behaviour?)
///
+ /// TODO: drop
+ ///
long getBytesLoaded();
/// Returns the total size of the file
@@ -139,18 +142,16 @@
/// This call never blocks.
/// If not connected, 0 is returned (is this correct behaviour?)
///
- long getBytesTotal();
-
- /// Return an FLVParser using our LoadThread for input
- //
- /// If not connected, a NULL auto_ptr is returned.
+ /// TODO: drop
///
- std::auto_ptr<FLVParser> getConnectedParser();
+ long getBytesTotal();
/// Returns whether the load is complete
//
/// This call never blocks.
///
+ /// TODO: drop
+ ///
bool loadCompleted();
private:
@@ -165,6 +166,9 @@
std::string _completeUrl;
/// The file/stream loader thread and interface
+ //
+ /// TODO: drop
+ ///
std::auto_ptr<tu_file> _loader;
/// Attach ActionScript instance properties
Index: server/asobj/NetStream.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStream.h,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -b -r1.64 -r1.65
--- server/asobj/NetStream.h 23 May 2008 15:27:30 -0000 1.64
+++ server/asobj/NetStream.h 3 Jun 2008 12:39:54 -0000 1.65
@@ -31,7 +31,7 @@
#include "impl.h"
#include "video_stream_instance.h"
#include "NetConnection.h"
-#include "FLVParser.h"
+#include "MediaParser.h"
#include "as_function.h" // for visibility of destructor by intrusive_ptr
#include <deque>
@@ -277,8 +277,8 @@
// The video URL
std::string url;
- // The homegrown parser we use for FLV
- std::auto_ptr<FLVParser> m_parser;
+ // The input media parser
+ std::auto_ptr<media::MediaParser> m_parser;
// Are we playing a FLV?
bool m_isFLV;
Index: server/asobj/NetStreamFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.cpp,v
retrieving revision 1.138
retrieving revision 1.139
diff -u -b -r1.138 -r1.139
--- server/asobj/NetStreamFfmpeg.cpp 2 Jun 2008 12:51:07 -0000 1.138
+++ server/asobj/NetStreamFfmpeg.cpp 3 Jun 2008 12:39:55 -0000 1.139
@@ -305,6 +305,9 @@
/// @param codec_id the codec ID to find
/// @return the initialized context, or NULL on failure. The caller is
/// responsible for deallocating!
+///
+/// TODO: drop, let VideoDecoder/AudioDecoder do this !
+///
static AVCodecContext*
initContext(enum CodecID codec_id)
{
@@ -340,10 +343,10 @@
/// @return the initialized context, or NULL on failure. The caller
/// is responsible for deallocating this pointer.
static AVCodecContext*
-initFlvVideo(FLVParser& parser)
+initVideoDecoder(media::MediaParser& parser)
{
// Get video info from the parser
- FLVVideoInfo* videoInfo = parser.getVideoInfo();
+ media::VideoInfo* videoInfo = parser.getVideoInfo();
if (!videoInfo)
{
return NULL;
@@ -374,12 +377,12 @@
}
-/// Like initFlvVideo, but for audio.
+/// Like initVideoDecoder, but for audio.
static AVCodecContext*
-initFlvAudio(FLVParser& parser)
+initAudioDecoder(media::MediaParser& parser)
{
// Get audio info from the parser
- FLVAudioInfo* audioInfo = parser.getAudioInfo();
+ media::AudioInfo* audioInfo = parser.getAudioInfo();
if (!audioInfo)
{
log_debug("No audio in FLV stream");
@@ -451,6 +454,10 @@
return false;
}
+ //
+ // TODO: let all of this be handled by a MediaParserFactory
+ // (ie: inspecting type of input)
+ //
_inputStream->set_position(0);
if (std::string(head) == "FLV")
@@ -458,7 +465,7 @@
m_isFLV = true;
assert ( !m_parser.get() );
- m_parser.reset( new FLVParser(_inputStream) );
+ m_parser.reset( new media::FLVParser(_inputStream) );
assert(! _inputStream.get() ); // TODO: when ownership will be
transferred...
if (! m_parser.get() )
@@ -473,14 +480,14 @@
avcodec_init();
avcodec_register_all();
- m_VCodecCtx = initFlvVideo(*m_parser);
+ m_VCodecCtx = initVideoDecoder(*m_parser); // TODO: let
VideoDecoder do this !
if (!m_VCodecCtx)
{
log_error(_("Failed to initialize FLV video codec"));
return false;
}
- m_ACodecCtx = initFlvAudio(*m_parser);
+ m_ACodecCtx = initAudioDecoder(*m_parser); // TODO: let
AudioDecoder do this !
if (!m_ACodecCtx)
{
// There might simply be no audio, no problem...
@@ -773,21 +780,21 @@
return 0; // no parser, no party
}
- FLVVideoFrameInfo* info = m_parser->peekNextVideoFrameInfo();
- if ( ! info )
+ boost::uint64_t nextTimestamp;
+ if ( ! m_parser->nextVideoFrameTimestamp(nextTimestamp) )
{
#ifdef GNASH_DEBUG_DECODING
- log_debug("getDecodedVideoFrame(%d): no more video frames in
input (peekNextVideoFrameInfo returned false)");
+ log_debug("getDecodedVideoFrame(%d): no more video frames in
input (nextVideoFrameTimestamp returned false)");
#endif // GNASH_DEBUG_DECODING
decodingStatus(DEC_STOPPED);
return 0;
}
- if ( info->timestamp > ts )
+ if ( nextTimestamp > ts )
{
#ifdef GNASH_DEBUG_DECODING
log_debug("%p.getDecodedVideoFrame(%d): next video frame is in
the future (%d)",
- this, ts, info->timestamp);
+ this, ts, nextTimestamp);
#endif // GNASH_DEBUG_DECODING
return 0; // next frame is in the future
}
@@ -799,14 +806,13 @@
video = decodeNextVideoFrame();
if ( ! video )
{
- log_error("peekNextVideoFrameInfo returned some info, "
+ log_error("nextVideoFrameTimestamp returned true, "
"but decodeNextVideoFrame returned null, "
"I don't think this should ever happen");
break;
}
- FLVVideoFrameInfo* info = m_parser->peekNextVideoFrameInfo();
- if ( ! info )
+ if ( ! m_parser->nextVideoFrameTimestamp(nextTimestamp) )
{
// the one we decoded was the last one
#ifdef GNASH_DEBUG_DECODING
@@ -815,7 +821,7 @@
#endif // GNASH_DEBUG_DECODING
break;
}
- if ( info->timestamp > ts )
+ if ( nextTimestamp > ts )
{
// the next one is in the future, we'll return this one.
#ifdef GNASH_DEBUG_DECODING
@@ -840,8 +846,8 @@
return 0; // no parser, no party
}
- FLVFrame* frame = m_parser->nextVideoFrame();
- if (frame == NULL)
+ std::auto_ptr<media::EncodedVideoFrame> frame =
m_parser->nextVideoFrame();
+ if ( ! frame.get() )
{
#ifdef GNASH_DEBUG_DECODING
log_debug("%p.decodeNextVideoFrame(): "
@@ -850,16 +856,15 @@
#endif // GNASH_DEBUG_DECODING
return 0;
}
- assert (frame->type == videoFrame);
AVPacket packet;
packet.destruct = avpacket_destruct; // needed ?
- packet.size = frame->dataSize;
- packet.data = frame->data;
+ packet.size = frame->dataSize();
+ // ffmpeg insist in requiring non-const AVPacket.data ...
+ packet.data = const_cast<boost::uint8_t*>(frame->data());
// FIXME: is this the right value for packet.dts?
- packet.pts = packet.dts = static_cast<boost::int64_t>(frame->timestamp);
- assert (frame->type == videoFrame);
+ packet.pts = packet.dts = frame->timestamp();
packet.stream_index = 0;
return decodeVideo(&packet);
@@ -870,8 +875,8 @@
{
assert ( m_parser.get() );
- FLVFrame* frame = m_parser->nextAudioFrame();
- if (frame == NULL)
+ std::auto_ptr<media::EncodedAudioFrame> frame =
m_parser->nextAudioFrame();
+ if ( ! frame.get() )
{
#ifdef GNASH_DEBUG_DECODING
log_debug("%p.decodeNextAudioFrame: "
@@ -880,16 +885,14 @@
#endif // GNASH_DEBUG_DECODING
return 0;
}
- assert (frame->type == audioFrame);
AVPacket packet;
packet.destruct = avpacket_destruct;
packet.size = frame->dataSize;
- packet.data = frame->data;
+ packet.data = frame->data.get();
// FIXME: is this the right value for packet.dts?
- packet.pts = packet.dts = static_cast<boost::int64_t>(frame->timestamp);
- assert(frame->type == audioFrame);
+ packet.pts = packet.dts = frame->timestamp;
packet.stream_index = 1;
return decodeAudio(&packet);
@@ -1385,9 +1388,7 @@
{
// TODO: parse as much as possible w/out blocking
// (will always block currently..)
- const int tagsPerChunk = 2;
- for (int i=0; i<tagsPerChunk; ++i)
- m_parser->parseNextTag();
+ m_parser->parseNextChunk();
}
void
@@ -1444,15 +1445,15 @@
bool consumed = false;
+ boost::uint64_t nextTimestamp;
while ( 1 )
{
- FLVAudioFrameInfo* info = m_parser->peekNextAudioFrameInfo();
- if ( ! info )
+ if ( ! m_parser->nextAudioFrameTimestamp(nextTimestamp) )
{
#ifdef GNASH_DEBUG_DECODING
log_debug("%p.pushDecodedAudioFrames(%d): "
"no more audio frames in input "
- "(peekNextAudioFrameInfo returned false)",
+ "(nextAudioFrameTimestamp returned false)",
this, ts);
#endif // GNASH_DEBUG_DECODING
consumed = true;
@@ -1464,12 +1465,12 @@
break;
}
- if ( info->timestamp > ts )
+ if ( nextTimestamp > ts )
{
#ifdef GNASH_DEBUG_DECODING
log_debug("%p.pushDecodedAudioFrames(%d): "
"next audio frame is in the future (%d)",
- this, ts, info->timestamp);
+ this, ts, nextTimestamp);
#endif // GNASH_DEBUG_DECODING
consumed = true;
break; // next frame is in the future
@@ -1501,7 +1502,7 @@
media::raw_mediadata_t* audio = decodeNextAudioFrame();
if ( ! audio )
{
- log_error("peekNextAudioFrameInfo returned some info, "
+ log_error("nextAudioFrameTimestamp returned true, "
"but decodeNextAudioFrame returned null, "
"I don't think this should ever happen");
break;
@@ -1510,7 +1511,7 @@
#ifdef GNASH_DEBUG_DECODING
// this one we might avoid :) -- a less intrusive logging could
// be take note about how many things we're pushing over
- log_debug("pushDecodedAudioFrames(%d) pushing frame with
timestamp %d", ts, info->timestamp);
+ log_debug("pushDecodedAudioFrames(%d) pushing frame with
timestamp %d", ts, nextTimestamp);
#endif
_audioQueue.push_back(audio);
}
Index: server/parser/video_stream_def.h
===================================================================
RCS file: /sources/gnash/gnash/server/parser/video_stream_def.h,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -b -r1.27 -r1.28
--- server/parser/video_stream_def.h 5 Mar 2008 03:56:03 -0000 1.27
+++ server/parser/video_stream_def.h 3 Jun 2008 12:39:55 -0000 1.28
@@ -31,6 +31,7 @@
#include "rect.h" // for composition
#include "ControlTag.h"
#include "VideoDecoder.h"
+#include "MediaParser.h" // for videoFrameType and videoCodecType enums
#include "image.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 3 Jun 2008 12:39:52 -0000 1.9
@@ -0,0 +1,747 @@
+// FLVParser.cpp: Flash Video file parser, for Gnash.
+//
+// Copyright (C) 2007, 2008 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 <string>
+#include <iosfwd>
+#include "FLVParser.h"
+#include "amf.h"
+#include "log.h"
+#include "utility.h"
+
+using namespace std;
+
+#define PADDING_BYTES 64
+#define READ_CHUNKS 64
+
+// Define the following macro the have seek() operations printed
+//#define GNASH_DEBUG_SEEK 1
+
+namespace gnash {
+namespace media {
+
+static std::auto_ptr<EncodedVideoFrame>
+makeVideoFrame(tu_file& in, const FLVVideoFrameInfo& frameInfo)
+{
+ std::auto_ptr<EncodedVideoFrame> frame;
+
+ boost::uint32_t dataSize = frameInfo.dataSize;
+ boost::uint64_t timestamp = frameInfo.timestamp;
+
+ if ( in.set_position(frameInfo.dataPosition) )
+ {
+ log_error(_("Failed seeking to videoframe in FLV input"));
+ return frame;
+ }
+
+ unsigned long int chunkSize = smallestMultipleContaining(READ_CHUNKS,
dataSize+PADDING_BYTES);
+
+ boost::uint8_t* data = new boost::uint8_t[chunkSize];
+ size_t bytesread = in.read_bytes(data, dataSize);
+
+ unsigned long int padding = chunkSize-dataSize;
+ assert(padding);
+ memset(data + bytesread, 0, padding);
+
+ // We won't need frameNum, so will set to zero...
+ // TODO: fix this ?
+ // NOTE: ownership of 'data' is transferred here
+ frame.reset( new EncodedVideoFrame(data, dataSize, 0, timestamp) );
+ return frame;
+}
+
+static std::auto_ptr<EncodedAudioFrame>
+makeAudioFrame(tu_file& in, const FLVAudioFrameInfo& frameInfo)
+{
+ std::auto_ptr<EncodedAudioFrame> frame ( new EncodedAudioFrame );
+ frame->dataSize = frameInfo.dataSize;
+ frame->timestamp = frameInfo.timestamp;
+
+
+ if ( in.set_position(frameInfo.dataPosition) )
+ {
+ log_error(_("Failed seeking to audioframe in FLV input"));
+ frame.reset();
+ return frame;
+ }
+
+ unsigned long int dataSize = frameInfo.dataSize;
+ unsigned long int chunkSize = smallestMultipleContaining(READ_CHUNKS,
dataSize+PADDING_BYTES);
+
+ frame->data.reset( new boost::uint8_t[chunkSize] );
+ size_t bytesread = in.read_bytes(frame->data.get(), dataSize);
+
+ unsigned long int padding = chunkSize-dataSize;
+ assert(padding);
+ memset(frame->data.get() + bytesread, 0, padding);
+
+ return frame;
+}
+
+FLVParser::FLVParser(std::auto_ptr<tu_file> lt)
+ :
+ MediaParser(lt),
+ _lastParsedPosition(0),
+ _videoInfo(NULL),
+ _audioInfo(NULL),
+ _nextAudioFrame(0),
+ _nextVideoFrame(0),
+ _audio(false),
+ _video(false)
+{
+}
+
+FLVParser::~FLVParser()
+{
+ _videoFrames.clear();
+
+ _audioFrames.clear();
+}
+
+
+boost::uint32_t
+FLVParser::getBufferLength()
+{
+ 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;
+}
+boost::uint16_t
+FLVParser::videoFrameRate()
+{
+ // Make sure that there are parsed some frames
+ while(_videoFrames.size() < 2 && !_parsingComplete) {
+ parseNextTag();
+ }
+
+ if (_videoFrames.size() < 2) return 0;
+
+ boost::uint32_t framedelay = _videoFrames[1]->timestamp -
_videoFrames[0]->timestamp;
+
+ return static_cast<boost::int16_t>(1000 / framedelay);
+}
+
+
+boost::uint32_t
+FLVParser::videoFrameDelay()
+{
+ // 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) {
+ parseNextTag();
+ }
+
+ // 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;
+}
+
+boost::uint32_t
+FLVParser::audioFrameDelay()
+{
+ // 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) {
+ parseNextTag();
+ }
+
+ // 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;
+}
+
+bool
+FLVParser::nextAudioFrameTimestamp(boost::uint64_t& ts)
+{
+ // If there are no audio in this FLV return NULL
+ if (!_audio && _lastParsedPosition > 0) return false;
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_audioFrames.size() <= _nextAudioFrame && !_parsingComplete) {
+ if (!parseNextTag()) break;
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_audioFrames.empty() || _audioFrames.size() <= _nextAudioFrame)
+ {
+ return false;
+ }
+
+ FLVAudioFrameInfo* info = _audioFrames[_nextAudioFrame];
+ ts = info->timestamp;
+ return true;
+}
+
+std::auto_ptr<EncodedAudioFrame>
+FLVParser::nextAudioFrame()
+{
+ std::auto_ptr<EncodedAudioFrame> frame;
+
+ FLVAudioFrameInfo* frameInfo = peekNextAudioFrameInfo();
+ if ( ! frameInfo ) return frame;
+
+ frame = makeAudioFrame(*_stream, *frameInfo);
+ if ( ! frame.get() )
+ {
+ log_error("Could not make audio frame %d", _nextAudioFrame);
+ return frame;
+ }
+
+ _nextAudioFrame++;
+ return frame;
+}
+
+bool
+FLVParser::nextVideoFrameTimestamp(boost::uint64_t& ts)
+{
+ // If there are no video in this FLV return NULL
+ if (!_video && _lastParsedPosition > 0)
+ {
+ //gnash::log_debug("no video, or lastParserPosition > 0");
+ return false;
+ }
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_videoFrames.size() <=
static_cast<boost::uint32_t>(_nextVideoFrame) && !_parsingComplete)
+ {
+ if (!parseNextTag()) break;
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_videoFrames.empty() || _videoFrames.size() <= _nextVideoFrame)
+ {
+ //gnash::log_debug("The needed frame (%d) can't be parsed (EOF
reached)", _lastVideoFrame);
+ return false;
+ }
+
+ FLVVideoFrameInfo* info = _videoFrames[_nextVideoFrame];
+ ts = info->timestamp;
+ return true;
+}
+
+std::auto_ptr<EncodedVideoFrame>
+FLVParser::nextVideoFrame()
+{
+ FLVVideoFrameInfo* frameInfo = peekNextVideoFrameInfo();
+ std::auto_ptr<EncodedVideoFrame> frame = makeVideoFrame(*_stream,
*frameInfo);
+ if ( ! frame.get() )
+ {
+ log_error("Could not make video frame %d", _nextVideoFrame);
+ return frame;
+ }
+
+ _nextVideoFrame++;
+ return frame;
+}
+
+
+boost::uint32_t
+FLVParser::seekAudio(boost::uint32_t time)
+{
+
+ // If there is no audio data return NULL
+ if (_audioFrames.empty()) return 0;
+
+ // If there are no audio greater than the given time
+ // the last audioframe is returned
+ FLVAudioFrameInfo* 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 = utility::clamp<size_t>(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;
+
+}
+
+
+boost::uint32_t
+FLVParser::seekVideo(boost::uint32_t time)
+{
+ if ( _videoFrames.empty() ) return 0;
+
+ // If there are no videoframe greater than the given time
+ // the last key videoframe is returned
+ FLVVideoFrameInfo* 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 = utility::clamp<size_t>(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;
+ }
+
+ // 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
+ {
+ boost::int32_t forwardDiff =
_videoFrames[forwardKeyframe]->timestamp - time;
+ boost::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;
+}
+
+
+
+VideoInfo*
+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( ! _parsingComplete && !_videoInfo.get() ) parseNextTag();
+
+ return _videoInfo.get(); // may be null
+}
+
+AudioInfo*
+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 (!_parsingComplete && ! _audioInfo.get() )
+ {
+ parseNextTag();
+ }
+
+ return _audioInfo.get(); // may be null
+}
+
+bool
+FLVParser::isTimeLoaded(boost::uint32_t time)
+{
+ // Parse frames until the need time is found, or EOF
+ while (!_parsingComplete) {
+ if (!parseNextTag()) 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;
+
+}
+
+boost::uint32_t
+FLVParser::seek(boost::uint32_t time)
+{
+ GNASH_REPORT_FUNCTION;
+
+ log_debug("FLVParser::seek(%d) ", time);
+
+ if (time == 0) {
+ if (_video) _nextVideoFrame = 0;
+ if (_audio) _nextAudioFrame = 0;
+ }
+
+ // Video, if present, has more constraints
+ // as to where we allow seeking (we only
+ // allow seek to closest *key* frame).
+ // So we first have video seeking tell us
+ // what time is best for that, and next
+ // we seek audio on that time
+
+ if (_video)
+ {
+ time = seekVideo(time);
+#ifdef GNASH_DEBUG_SEEK
+ log_debug(" seekVideo -> %d", time);
+#endif
+ }
+
+ if (_audio)
+ {
+ time = seekAudio(time);
+#ifdef GNASH_DEBUG_SEEK
+ log_debug(" seekAudio -> %d", time);
+#endif
+ }
+
+ return time;
+}
+
+bool FLVParser::parseNextTag()
+{
+ if ( _parsingComplete ) return false;
+
+ // Parse the header if not done already. If unsuccesfull return false.
+ if (_lastParsedPosition == 0 && !parseHeader()) return false;
+
+ // Seek to next frame and skip the size of the last tag
+ if ( _stream->set_position(_lastParsedPosition+4) )
+ {
+ log_error("FLVParser::parseNextTag: can't seek to %d",
_lastParsedPosition+4);
+ _parsingComplete=true;
+ return false;
+ }
+
+ // Read the tag info
+ boost::uint8_t tag[12];
+ int actuallyRead = _stream->read_bytes(tag, 12);
+ if ( actuallyRead < 12 )
+ {
+ if ( actuallyRead )
+ log_error("FLVParser::parseNextTag: can't read tag info
(needed 12 bytes, only got %d)", actuallyRead);
+ // else { assert(_stream->get_eof(); } ?
+ _parsingComplete=true;
+ return false;
+ }
+
+ // Extract length and timestamp
+ boost::uint32_t bodyLength = getUInt24(&tag[1]);
+ boost::uint32_t timestamp = getUInt24(&tag[4]);
+
+ _lastParsedPosition += 15 + bodyLength;
+
+ // check for empty tag
+ if (bodyLength == 0) return true;
+
+ enum tagType
+ {
+ AUDIO_TAG = 0x08,
+ VIDEO_TAG = 0x09,
+ META_TAG = 0x12
+ };
+
+ if (tag[0] == AUDIO_TAG)
+ {
+ FLVAudioFrameInfo* frame = new FLVAudioFrameInfo;
+ frame->dataSize = bodyLength - 1;
+ frame->timestamp = timestamp;
+ frame->dataPosition = _stream->get_position();
+ _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.get() )
+ {
+ 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((tag[11] & 0xf0) >> 4,
samplerate, samplesize, (tag[11] & 0x01) >> 0, 0, FLASH) );
+ }
+
+
+ }
+ else if (tag[0] == VIDEO_TAG)
+ {
+ FLVVideoFrameInfo* frame = new FLVVideoFrameInfo;
+ frame->dataSize = bodyLength - 1;
+ frame->timestamp = timestamp;
+ frame->dataPosition = _stream->get_position();
+ 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.get() )
+ {
+ boost::uint16_t codec = (tag[11] & 0x0f) >> 0;
+ // Set standard guessed size...
+ boost::uint16_t width = 320;
+ boost::uint16_t height = 240;
+
+ // Extract the video size from the videodata header
+ if (codec == VIDEO_CODEC_H263) {
+ if ( _stream->set_position(frame->dataPosition)
)
+ {
+ log_error(" Couldn't seek to VideoTag
data position");
+ _parsingComplete=true;
+ return false;
+ }
+ boost::uint8_t videohead[12];
+ int actuallyRead =
_stream->read_bytes(videohead, 12);
+ if ( actuallyRead < 12 )
+ {
+ log_error("FLVParser::parseNextTag: can't read H263 video
header (needed 12 bytes, only got %d)", actuallyRead);
+ _parsingComplete=true;
+ return false;
+ }
+
+ 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 /*codec type*/) );
+ }
+
+ } else if (tag[0] == META_TAG) {
+ LOG_ONCE( log_unimpl("FLV MetaTag parser") );
+ // Extract information from the meta tag
+ /*_stream->seek(_lastParsedPosition+16);
+ char* metaTag = new char[bodyLength];
+ size_t actuallyRead = _stream->read(metaTag, bodyLength);
+ if ( actuallyRead < bodyLength )
+ {
+ log_error("FLVParser::parseNextTag: can't read metaTag
(%d) body (needed %d bytes, only got %d)",
+ META_TAG, bodyLength, actuallyRead);
+ _parsingComplete=true;
+ return false;
+ }
+ amf::AMF* amfParser = new amf::AMF();
+ amfParser->parseAMF(metaTag);*/
+
+ } else {
+ log_error("Unknown FLV tag type %d", tag[0]);
+ //_parsingComplete = true;
+ //return false;
+ }
+
+ return true;
+}
+
+bool FLVParser::parseHeader()
+{
+ // seek to the begining of the file
+ _stream->set_position(0); // seek back ? really ?
+
+ // Read the header
+ boost::uint8_t header[9];
+ if ( _stream->read_bytes(header, 9) != 9 )
+ {
+ log_error("FLVParser::parseHeader: couldn't read 9 bytes of
header");
+ return false;
+ }
+
+ // Check if this is really a FLV file
+ if (header[0] != 'F' || header[1] != 'L' || header[2] != 'V') return
false;
+
+ int version = header[3];
+
+ // Parse the audio+video bitmask
+ _audio = header[4]&(1<<2);
+ _video = header[4]&(1<<0);
+
+ log_debug("Parsing FLV version %d, audio:%d, video:%d", version,
_audio, _video);
+
+ _lastParsedPosition = 9;
+ return true;
+}
+
+inline boost::uint32_t FLVParser::getUInt24(boost::uint8_t* in)
+{
+ // The bits are in big endian order
+ return (in[0] << 16) | (in[1] << 8) | in[2];
+}
+
+boost::uint64_t
+FLVParser::getBytesLoaded() const
+{
+ return _lastParsedPosition;
+}
+
+/* private */
+FLVAudioFrameInfo*
+FLVParser::peekNextAudioFrameInfo()
+{
+ // If there are no audio in this FLV return NULL
+ if (!_audio && _lastParsedPosition > 0) return 0;
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_audioFrames.size() <= _nextAudioFrame && !_parsingComplete) {
+ if (!parseNextTag()) break;
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_audioFrames.empty() || _audioFrames.size() <= _nextAudioFrame)
+ {
+ return 0;
+ }
+
+ return _audioFrames[_nextAudioFrame];
+}
+
+/*private*/
+FLVVideoFrameInfo*
+FLVParser::peekNextVideoFrameInfo()
+{
+ // If there are no video in this FLV return NULL
+ if (!_video && _lastParsedPosition > 0)
+ {
+ //gnash::log_debug("no video, or lastParserPosition > 0");
+ return 0;
+ }
+
+ // Make sure that there are parsed enough frames to return the need
frame
+ while(_videoFrames.size() <=
static_cast<boost::uint32_t>(_nextVideoFrame) && !_parsingComplete)
+ {
+ if (!parseNextTag()) break;
+ }
+
+ // If the needed frame can't be parsed (EOF reached) return NULL
+ if (_videoFrames.empty() || _videoFrames.size() <= _nextVideoFrame)
+ {
+ //gnash::log_debug("The needed frame (%d) can't be parsed (EOF
reached)", _lastVideoFrame);
+ return 0;
+ }
+
+ return _videoFrames[_nextVideoFrame];
+}
+
+} // end of gnash::media namespace
+} // end of gnash namespace
+
+#undef PADDING_BYTES
+#undef READ_CHUNKS
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 3 Jun 2008 12:39:53 -0000 1.11
@@ -0,0 +1,324 @@
+// FLVParser.h: Flash Video file format parser, for Gnash.
+//
+// Copyright (C) 2007, 2008 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
+//
+
+
+// Information about the FLV format can be found at http://osflash.org/flv
+
+#ifndef __FLVPARSER_H__
+#define __FLVPARSER_H__
+
+#include "dsodefs.h"
+#include "MediaParser.h" // for inheritance
+
+#include <vector>
+#include <memory>
+
+namespace gnash {
+namespace media {
+
+/// Frame type
+enum FrameType {
+
+ /// Video frame
+ videoFrame,
+
+ /// Audio frame
+ audioFrame
+};
+
+/// \brief
+/// The FLVFrame class contains an encoded
+/// video or audio frame, its size, its
+/// timestamp,
+class FLVFrame
+{
+public:
+ /// Size of the encoded frame
+ boost::uint32_t dataSize;
+
+ /// Encoded data
+ boost::uint8_t* data;
+
+ /// Frame timestamp, in milliseconds
+ boost::uint64_t timestamp;
+
+ /// Frame type (audio/video)
+ FrameType type;
+};
+
+/// \brief
+/// The FLVAudioInfo class contains information about the audiostream
+/// in the FLV being parsed. The information stored is codec-type,
+/// samplerate, samplesize, stereo flag and duration.
+//
+/// TODO: drop
+///
+class FLVAudioInfo
+{
+public:
+ FLVAudioInfo(boost::uint16_t codeci, boost::uint16_t sampleRatei,
boost::uint16_t sampleSizei, bool stereoi, boost::uint64_t durationi)
+ : codec(codeci),
+ sampleRate(sampleRatei),
+ sampleSize(sampleSizei),
+ stereo(stereoi),
+ duration(durationi)
+ {
+ }
+
+ boost::uint16_t codec;
+ boost::uint16_t sampleRate;
+ boost::uint16_t sampleSize;
+ bool stereo;
+ boost::uint64_t 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.
+//
+/// TODO: drop
+///
+class FLVVideoInfo
+{
+public:
+ FLVVideoInfo(boost::uint16_t codeci, boost::uint16_t widthi,
boost::uint16_t heighti, boost::uint16_t frameRatei, boost::uint64_t durationi)
+ :
+ codec(codeci),
+ width(widthi),
+ height(heighti),
+ frameRate(frameRatei),
+ duration(durationi)
+ {
+ }
+
+ boost::uint16_t codec;
+ boost::uint16_t width;
+ boost::uint16_t height;
+ boost::uint16_t frameRate;
+ boost::uint64_t duration;
+};
+
+
+/// Information about an FLV Audio Frame
+class FLVVideoFrameInfo
+{
+public:
+
+ /// Type of this frame (should likely be videoFrameType)
+ boost::uint16_t frameType;
+
+ /// Size of the frame in bytes
+ boost::uint32_t dataSize;
+
+ /// Start of frame data in stream
+ boost::uint64_t dataPosition;
+
+ /// Timestamp in milliseconds
+ boost::uint32_t timestamp;
+
+ /// Return true if this video frame is a key frame
+ bool isKeyFrame() const
+ {
+ return frameType == 1 /*KEY_FRAME*/;
+ }
+
+};
+
+/// Information about an FLV Audio Frame
+class FLVAudioFrameInfo
+{
+public:
+ /// Size of the frame in bytes
+ boost::uint32_t dataSize;
+
+ /// Start of frame data in stream
+ boost::uint64_t dataPosition;
+
+ /// Timestamp in milliseconds
+ boost::uint32_t timestamp;
+
+};
+
+/// The FLVParser class parses FLV streams
+class DSOEXPORT FLVParser : public MediaParser
+{
+
+public:
+
+ /// \brief
+ /// Create an FLV parser reading input from
+ /// the given tu_file
+ //
+ /// @param lt
+ /// tu_file to use for input.
+ /// Ownership transferred.
+ ///
+ FLVParser(std::auto_ptr<tu_file> lt);
+
+ /// Kills the parser...
+ ~FLVParser();
+
+ // see dox in MediaParser.h
+ bool nextAudioFrameTimestamp(boost::uint64_t& ts);
+
+ // see dox in MediaParser.h
+ bool nextVideoFrameTimestamp(boost::uint64_t& ts);
+
+ // see dox in MediaParser.h
+ std::auto_ptr<EncodedAudioFrame> nextAudioFrame();
+
+ // see dox in MediaParser.h
+ std::auto_ptr<EncodedVideoFrame> nextVideoFrame();
+
+ /// Returns information about video in the stream.
+ //
+ /// The returned object is owned by the FLVParser object.
+ /// Can return NULL if video contains NO video frames.
+ /// Will block till either parsing finished or a video frame is found.
+ ///
+ VideoInfo* getVideoInfo();
+
+ /// Returns a FLVAudioInfo class about the audiostream
+ //
+ /// TODO: return a more abstract AudioInfo
+ ///
+ 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.
+ ///
+ /// @param time
+ /// Timestamp, in milliseconds.
+ ///
+ bool isTimeLoaded(boost::uint32_t time);
+
+ /// \brief
+ /// Seeks to the closest possible position the given position,
+ /// and returns the new position.
+ //
+ ///
+ /// TODO: throw something for sending Seek.InvalidTime ?
+ /// (triggered by seeks beyond the end of video or beyond what's
+ /// downloaded so far)
+ ///
+ boost::uint32_t seek(boost::uint32_t);
+
+ /// Returns the framedelay from the last to the current
+ /// audioframe in milliseconds. This is used for framerate.
+ //
+ boost::uint32_t audioFrameDelay();
+
+ /// \brief
+ /// Returns the framedelay from the last to the current
+ /// videoframe in milliseconds.
+ //
+ boost::uint32_t videoFrameDelay();
+
+ /// Returns the framerate of the video
+ //
+ boost::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.
+ //
+ boost::uint32_t getBufferLength();
+
+ virtual bool parseNextChunk() {
+ return parseNextTag();
+ }
+
+ /// Parses next tag from the file
+ //
+ /// Returns true if something was parsed, false otherwise.
+ /// Sets _parsingComplete=true on end of file.
+ ///
+ bool parseNextTag();
+
+ /// Return number of bytes parsed so far
+ boost::uint64_t getBytesLoaded() const;
+
+private:
+
+ FLVAudioFrameInfo* peekNextAudioFrameInfo();
+
+ FLVVideoFrameInfo* peekNextVideoFrameInfo();
+
+ /// seeks to the closest possible position the given position,
+ /// and returns the new position.
+ boost::uint32_t seekAudio(boost::uint32_t time);
+
+ /// seeks to the closest possible position the given position,
+ /// and returns the new position.
+ boost::uint32_t seekVideo(boost::uint32_t time);
+
+ /// Parses the header of the file
+ bool parseHeader();
+
+ // Functions used to extract numbers from the file
+ inline boost::uint32_t getUInt24(boost::uint8_t* in);
+
+ // NOTE: FLVVideoFrameInfo is a relatively small structure,
+ // chances are keeping by value here would reduce
+ // memory fragmentation with no big cost
+ typedef std::vector<FLVVideoFrameInfo*> VideoFrames;
+
+ /// list of videoframes, does no contain the frame data.
+ VideoFrames _videoFrames;
+
+ // NOTE: FLVAudioFrameInfo is a relatively small structure,
+ // chances are keeping by value here would reduce
+ // memory fragmentation with no big cost
+ typedef std::vector<FLVAudioFrameInfo*> AudioFrames;
+
+ /// list of audioframes, does no contain the frame data.
+ AudioFrames _audioFrames;
+
+ /// The position where the parsing should continue from.
+ boost::uint64_t _lastParsedPosition;
+
+ /// Info about the video stream (if any)
+ std::auto_ptr<VideoInfo> _videoInfo;
+
+ /// Info about the audio stream (if any)
+ 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;
+};
+
+} // end of gnash::media namespace
+} // end of gnash namespace
+
+#endif // __FLVPARSER_H__
Index: libbase/FLVParser.cpp
===================================================================
RCS file: libbase/FLVParser.cpp
diff -N libbase/FLVParser.cpp
--- libbase/FLVParser.cpp 27 May 2008 13:24:59 -0000 1.43
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,752 +0,0 @@
-// FLVParser.cpp: Flash Video file parser, for Gnash.
-//
-// Copyright (C) 2007, 2008 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 <string>
-#include <iosfwd>
-#include "FLVParser.h"
-#include "amf.h"
-#include "log.h"
-#include "utility.h"
-
-using namespace std;
-
-#define PADDING_BYTES 64
-#define READ_CHUNKS 64
-
-// Define the following macro the have seek() operations printed
-//#define GNASH_DEBUG_SEEK 1
-
-namespace gnash {
-
-static std::auto_ptr<FLVFrame>
-makeVideoFrame(tu_file& in, const FLVVideoFrameInfo& frameInfo)
-{
- std::auto_ptr<FLVFrame> frame ( new FLVFrame );
-
- frame->dataSize = frameInfo.dataSize;
- frame->timestamp = frameInfo.timestamp;
- frame->type = videoFrame;
-
- if ( in.set_position(frameInfo.dataPosition) )
- {
- log_error(_("Failed seeking to videoframe in FLV input"));
- frame.reset();
- return frame;
- }
-
- unsigned long int dataSize = frameInfo.dataSize;
- unsigned long int chunkSize = smallestMultipleContaining(READ_CHUNKS,
dataSize+PADDING_BYTES);
-
- frame->data = new boost::uint8_t[chunkSize];
- size_t bytesread = in.read_bytes(frame->data, dataSize);
-
- unsigned long int padding = chunkSize-dataSize;
- assert(padding);
- memset(frame->data + bytesread, 0, padding);
-
- return frame;
-}
-
-static std::auto_ptr<FLVFrame>
-makeAudioFrame(tu_file& in, const FLVAudioFrameInfo& frameInfo)
-{
- std::auto_ptr<FLVFrame> frame ( new FLVFrame );
- frame->dataSize = frameInfo.dataSize;
- frame->timestamp = frameInfo.timestamp;
- frame->type = audioFrame;
-
-
- if ( in.set_position(frameInfo.dataPosition) )
- {
- log_error(_("Failed seeking to audioframe in FLV input"));
- frame.reset();
- return frame;
- }
-
- unsigned long int dataSize = frameInfo.dataSize;
- unsigned long int chunkSize = smallestMultipleContaining(READ_CHUNKS,
dataSize+PADDING_BYTES);
-
- frame->data = new boost::uint8_t[chunkSize];
- size_t bytesread = in.read_bytes(frame->data, dataSize);
-
- unsigned long int padding = chunkSize-dataSize;
- assert(padding);
- memset(frame->data + bytesread, 0, padding);
-
- return frame;
-}
-
-FLVParser::FLVParser(std::auto_ptr<tu_file> lt)
- :
- _lt(lt),
- _lastParsedPosition(0),
- _parsingComplete(false),
- _videoInfo(NULL),
- _audioInfo(NULL),
- _nextAudioFrame(0),
- _nextVideoFrame(0),
- _audio(false),
- _video(false)
-{
-}
-
-FLVParser::~FLVParser()
-{
- _videoFrames.clear();
-
- _audioFrames.clear();
-}
-
-
-boost::uint32_t
-FLVParser::getBufferLength()
-{
- 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;
-}
-boost::uint16_t
-FLVParser::videoFrameRate()
-{
- // Make sure that there are parsed some frames
- while(_videoFrames.size() < 2 && !_parsingComplete) {
- parseNextTag();
- }
-
- if (_videoFrames.size() < 2) return 0;
-
- boost::uint32_t framedelay = _videoFrames[1]->timestamp -
_videoFrames[0]->timestamp;
-
- return static_cast<boost::int16_t>(1000 / framedelay);
-}
-
-
-boost::uint32_t
-FLVParser::videoFrameDelay()
-{
- // 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) {
- parseNextTag();
- }
-
- // 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;
-}
-
-boost::uint32_t
-FLVParser::audioFrameDelay()
-{
- // 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) {
- parseNextTag();
- }
-
- // 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;
-}
-
-FLVAudioFrameInfo*
-FLVParser::peekNextAudioFrameInfo()
-{
- // If there are no audio in this FLV return NULL
- if (!_audio && _lastParsedPosition > 0) return 0;
-
- // Make sure that there are parsed enough frames to return the need
frame
- while(_audioFrames.size() <= _nextAudioFrame && !_parsingComplete) {
- if (!parseNextTag()) break;
- }
-
- // If the needed frame can't be parsed (EOF reached) return NULL
- if (_audioFrames.empty() || _audioFrames.size() <= _nextAudioFrame)
- {
- return 0;
- }
-
- return _audioFrames[_nextAudioFrame];
-}
-
-FLVFrame*
-FLVParser::nextAudioFrame()
-{
- FLVAudioFrameInfo* frameInfo = peekNextAudioFrameInfo();
- if ( ! frameInfo ) return 0;
-
- std::auto_ptr<FLVFrame> frame = makeAudioFrame(*_lt, *frameInfo);
- if ( ! frame.get() )
- {
- log_error("Could not make audio frame %d", _nextAudioFrame);
- return 0;
- }
-
- _nextAudioFrame++;
- return frame.release(); // TODO: return by auto_ptr
-
-}
-
-FLVVideoFrameInfo*
- FLVParser::peekNextVideoFrameInfo()
-{
- // If there are no video in this FLV return NULL
- if (!_video && _lastParsedPosition > 0)
- {
- //gnash::log_debug("no video, or lastParserPosition > 0");
- return 0;
- }
-
- // Make sure that there are parsed enough frames to return the need
frame
- while(_videoFrames.size() <=
static_cast<boost::uint32_t>(_nextVideoFrame) && !_parsingComplete)
- {
- if (!parseNextTag()) break;
- }
-
- // If the needed frame can't be parsed (EOF reached) return NULL
- if (_videoFrames.empty() || _videoFrames.size() <= _nextVideoFrame)
- {
- //gnash::log_debug("The needed frame (%d) can't be parsed (EOF
reached)", _lastVideoFrame);
- return 0;
- }
-
- return _videoFrames[_nextVideoFrame];
-}
-
-FLVFrame* FLVParser::nextVideoFrame()
-{
- FLVVideoFrameInfo* frameInfo = peekNextVideoFrameInfo();
- std::auto_ptr<FLVFrame> frame = makeVideoFrame(*_lt, *frameInfo);
- if ( ! frame.get() )
- {
- log_error("Could not make video frame %d", _nextVideoFrame);
- return 0;
- }
-
- _nextVideoFrame++;
- return frame.release(); // TODO: return by auto_ptr
-}
-
-
-boost::uint32_t
-FLVParser::seekAudio(boost::uint32_t time)
-{
-
- // If there is no audio data return NULL
- if (_audioFrames.empty()) return 0;
-
- // If there are no audio greater than the given time
- // the last audioframe is returned
- FLVAudioFrameInfo* 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 = utility::clamp<size_t>(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;
-
-}
-
-
-boost::uint32_t
-FLVParser::seekVideo(boost::uint32_t time)
-{
- if ( _videoFrames.empty() ) return 0;
-
- // If there are no videoframe greater than the given time
- // the last key videoframe is returned
- FLVVideoFrameInfo* 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 = utility::clamp<size_t>(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;
- }
-
- // 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
- {
- boost::int32_t forwardDiff =
_videoFrames[forwardKeyframe]->timestamp - time;
- boost::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;
-}
-
-
-
-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( ! _parsingComplete && !_videoInfo.get() ) parseNextTag();
-
- return _videoInfo.get(); // may be null
-}
-
-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 (!_parsingComplete && ! _audioInfo.get() )
- {
- parseNextTag();
- }
-
- return _audioInfo.get(); // may be null
-}
-
-bool
-FLVParser::isTimeLoaded(boost::uint32_t time)
-{
- // Parse frames until the need time is found, or EOF
- while (!_parsingComplete) {
- if (!parseNextTag()) 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;
-
-}
-
-boost::uint32_t
-FLVParser::seek(boost::uint32_t time)
-{
- GNASH_REPORT_FUNCTION;
-
- log_debug("FLVParser::seek(%d) ", time);
-
- if (time == 0) {
- if (_video) _nextVideoFrame = 0;
- if (_audio) _nextAudioFrame = 0;
- }
-
- // Video, if present, has more constraints
- // as to where we allow seeking (we only
- // allow seek to closest *key* frame).
- // So we first have video seeking tell us
- // what time is best for that, and next
- // we seek audio on that time
-
- if (_video)
- {
- time = seekVideo(time);
-#ifdef GNASH_DEBUG_SEEK
- log_debug(" seekVideo -> %d", time);
-#endif
- }
-
- if (_audio)
- {
- time = seekAudio(time);
-#ifdef GNASH_DEBUG_SEEK
- log_debug(" seekAudio -> %d", time);
-#endif
- }
-
- return time;
-}
-
-bool FLVParser::parseNextTag()
-{
- if ( _parsingComplete ) return false;
-
- // Parse the header if not done already. If unsuccesfull return false.
- if (_lastParsedPosition == 0 && !parseHeader()) return false;
-
- // Seek to next frame and skip the size of the last tag
- if ( _lt->set_position(_lastParsedPosition+4) )
- {
- log_error("FLVParser::parseNextTag: can't seek to %d",
_lastParsedPosition+4);
- _parsingComplete=true;
- return false;
- }
-
- // Read the tag info
- boost::uint8_t tag[12];
- int actuallyRead = _lt->read_bytes(tag, 12);
- if ( actuallyRead < 12 )
- {
- if ( actuallyRead )
- log_error("FLVParser::parseNextTag: can't read tag info
(needed 12 bytes, only got %d)", actuallyRead);
- // else { assert(_lt->get_eof(); } ?
- _parsingComplete=true;
- return false;
- }
-
- // Extract length and timestamp
- boost::uint32_t bodyLength = getUInt24(&tag[1]);
- boost::uint32_t timestamp = getUInt24(&tag[4]);
-
- _lastParsedPosition += 15 + bodyLength;
-
- // check for empty tag
- if (bodyLength == 0) return true;
-
- if (tag[0] == AUDIO_TAG)
- {
- FLVAudioFrameInfo* frame = new FLVAudioFrameInfo;
- frame->dataSize = bodyLength - 1;
- frame->timestamp = timestamp;
- frame->dataPosition = _lt->get_position();
- _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.get() )
- {
- 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 FLVAudioInfo((tag[11] & 0xf0) >>
4, samplerate, samplesize, (tag[11] & 0x01) >> 0, 0) );
- }
-
-
- }
- else if (tag[0] == VIDEO_TAG)
- {
- FLVVideoFrameInfo* frame = new FLVVideoFrameInfo;
- frame->dataSize = bodyLength - 1;
- frame->timestamp = timestamp;
- frame->dataPosition = _lt->get_position();
- 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.get() )
- {
- boost::uint16_t codec = (tag[11] & 0x0f) >> 0;
- // Set standard guessed size...
- boost::uint16_t width = 320;
- boost::uint16_t height = 240;
-
- // Extract the video size from the videodata header
- if (codec == VIDEO_CODEC_H263) {
- if ( _lt->set_position(frame->dataPosition) )
- {
- log_error(" Couldn't seek to VideoTag
data position");
- _parsingComplete=true;
- return false;
- }
- boost::uint8_t videohead[12];
- int actuallyRead = _lt->read_bytes(videohead,
12);
- if ( actuallyRead < 12 )
- {
- log_error("FLVParser::parseNextTag: can't read H263 video
header (needed 12 bytes, only got %d)", actuallyRead);
- _parsingComplete=true;
- return false;
- }
-
- 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 FLVVideoInfo(codec, width,
height, 0 /*frameRate*/, 0 /*duration*/) );
- }
-
- } else if (tag[0] == META_TAG) {
- LOG_ONCE( log_unimpl("FLV MetaTag parser") );
- // Extract information from the meta tag
- /*_lt->seek(_lastParsedPosition+16);
- char* metaTag = new char[bodyLength];
- size_t actuallyRead = _lt->read(metaTag, bodyLength);
- if ( actuallyRead < bodyLength )
- {
- log_error("FLVParser::parseNextTag: can't read metaTag
(%d) body (needed %d bytes, only got %d)",
- META_TAG, bodyLength, actuallyRead);
- _parsingComplete=true;
- return false;
- }
- amf::AMF* amfParser = new amf::AMF();
- amfParser->parseAMF(metaTag);*/
-
- } else {
- log_error("Unknown FLV tag type %d", tag[0]);
- //_parsingComplete = true;
- //return false;
- }
-
- return true;
-}
-
-bool FLVParser::parseHeader()
-{
- // seek to the begining of the file
- _lt->set_position(0); // seek back ? really ?
-
- // Read the header
- boost::uint8_t header[9];
- if ( _lt->read_bytes(header, 9) != 9 )
- {
- log_error("FLVParser::parseHeader: couldn't read 9 bytes of
header");
- return false;
- }
-
- // Check if this is really a FLV file
- if (header[0] != 'F' || header[1] != 'L' || header[2] != 'V') return
false;
-
- int version = header[3];
-
- // Parse the audio+video bitmask
- _audio = header[4]&(1<<2);
- _video = header[4]&(1<<0);
-
- log_debug("Parsing FLV version %d, audio:%d, video:%d", version,
_audio, _video);
-
- _lastParsedPosition = 9;
- return true;
-}
-
-inline boost::uint32_t FLVParser::getUInt24(boost::uint8_t* in)
-{
- // The bits are in big endian order
- return (in[0] << 16) | (in[1] << 8) | in[2];
-}
-
-boost::uint64_t
-FLVParser::getBytesLoaded() const
-{
- return _lastParsedPosition;
-}
-
-boost::uint64_t
-FLVParser::getBytesTotal() const
-{
- return _lt->get_size();
-}
-
-FLVFrame* FLVParser::nextMediaFrame()
-{
- boost::uint32_t video_size = _videoFrames.size();
- boost::uint32_t audio_size = _audioFrames.size();
-
- if (audio_size <= _nextAudioFrame && video_size <= _nextVideoFrame)
- {
-
- // Parse a media frame if any left or if needed
- while(_videoFrames.size() <= _nextVideoFrame &&
_audioFrames.size() <= _nextAudioFrame && !_parsingComplete) {
- if (!parseNextTag()) 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) {
-
- FLVAudioFrameInfo* frameInfo = _audioFrames[_nextAudioFrame];
-
- std::auto_ptr<FLVFrame> frame = makeAudioFrame(*_lt,
*frameInfo);
- if ( ! frame.get() )
- {
- log_error("Could not make audio frame %d",
_nextAudioFrame);
- return 0;
- }
-
- _nextAudioFrame++;
- return frame.release(); // TODO: return by auto_ptr
-
- } else {
-
- FLVVideoFrameInfo* frameInfo = _videoFrames[_nextVideoFrame];
- std::auto_ptr<FLVFrame> frame = makeVideoFrame(*_lt,
*frameInfo);
- if ( ! frame.get() )
- {
- log_error("Could not make video frame %d",
_nextVideoFrame);
- return 0;
- }
-
- _nextVideoFrame++;
- return frame.release(); // TODO: return by auto_ptr
- }
-
-
-}
-
-} // end of gnash namespace
-
-#undef PADDING_BYTES
-#undef READ_CHUNKS
Index: libbase/FLVParser.h
===================================================================
RCS file: libbase/FLVParser.h
diff -N libbase/FLVParser.h
--- libbase/FLVParser.h 27 May 2008 11:58:45 -0000 1.32
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,407 +0,0 @@
-// FLVParser.h: Flash Video file format parser, for Gnash.
-//
-// Copyright (C) 2007, 2008 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
-//
-
-
-// Information about the FLV format can be found at http://osflash.org/flv
-
-#ifndef __FLVPARSER_H__
-#define __FLVPARSER_H__
-
-#include "LoadThread.h"
-#include "dsodefs.h"
-#include <vector>
-#include <memory>
-
-namespace gnash {
-
-/// Frame type
-enum FrameType {
-
- /// Video frame
- videoFrame,
-
- /// Audio frame
- audioFrame
-};
-
-/// \brief
-/// The FLVFrame class contains an encoded
-/// video or audio frame, its size, its
-/// timestamp,
-class FLVFrame
-{
-public:
- /// Size of the encoded frame
- boost::uint32_t dataSize;
-
- /// Encoded data
- boost::uint8_t* data;
-
- /// Frame timestamp, in milliseconds
- boost::uint64_t timestamp;
-
- /// Frame type (audio/video)
- FrameType type;
-};
-
-/// \brief
-/// The FLVAudioInfo class contains information about the audiostream
-/// in the FLV being parsed. The information stored is codec-type,
-/// samplerate, samplesize, stereo flag and duration.
-class FLVAudioInfo
-{
-public:
- FLVAudioInfo(boost::uint16_t codeci, boost::uint16_t sampleRatei,
boost::uint16_t sampleSizei, bool stereoi, boost::uint64_t durationi)
- : codec(codeci),
- sampleRate(sampleRatei),
- sampleSize(sampleSizei),
- stereo(stereoi),
- duration(durationi)
- {
- }
-
- boost::uint16_t codec;
- boost::uint16_t sampleRate;
- boost::uint16_t sampleSize;
- bool stereo;
- boost::uint64_t 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.
-class FLVVideoInfo
-{
-public:
- FLVVideoInfo(boost::uint16_t codeci, boost::uint16_t widthi,
boost::uint16_t heighti, boost::uint16_t frameRatei, boost::uint64_t durationi)
- : codec(codeci),
- width(widthi),
- height(heighti),
- frameRate(frameRatei),
- duration(durationi)
- {
- }
-
- boost::uint16_t codec;
- boost::uint16_t width;
- boost::uint16_t height;
- boost::uint16_t frameRate;
- boost::uint64_t duration;
-};
-
-
-/// Information about an FLV Audio Frame
-class FLVVideoFrameInfo
-{
-public:
-
- /// Type of this frame (should likely be videoFrameType)
- boost::uint16_t frameType;
-
- /// Size of the frame in bytes
- boost::uint32_t dataSize;
-
- /// Start of frame data in stream
- boost::uint64_t dataPosition;
-
- /// Timestamp in milliseconds
- boost::uint32_t timestamp;
-
- /// Return true if this video frame is a key frame
- bool isKeyFrame() const
- {
- return frameType == 1 /*KEY_FRAME*/;
- }
-
-};
-
-/// Information about an FLV Audio Frame
-class FLVAudioFrameInfo
-{
-public:
- /// Size of the frame in bytes
- boost::uint32_t dataSize;
-
- /// Start of frame data in stream
- boost::uint64_t dataPosition;
-
- /// Timestamp in milliseconds
- boost::uint32_t timestamp;
-
-};
-
-/// \brief
-/// The FLVParser class parses an FLV stream, buffers 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:
-
- 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
- //
- /// @param lt
- /// LoadThread to use for input.
- /// Ownership transferred.
- ///
- FLVParser(std::auto_ptr<tu_file> lt);
-
- /// Kills the parser...
- ~FLVParser();
-
- /// Return next media frame
- //
- /// Locks the _mutex
- ///
- FLVFrame* nextMediaFrame();
-
- /// \brief
- /// Return the next audio frame info 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.
- ///
- /// TODO: return a more abstract EncodedAudioFrameInfo
- ///
- FLVAudioFrameInfo* peekNextAudioFrameInfo();
-
- /// \brief
- /// Returns the next audio frame in the parsed buffer, advancing audio
cursor.
- //
- /// 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.
- ///
- /// TODO: return a more abstract EncodedAudioFrame
- ///
- FLVFrame* nextAudioFrame();
-
- /// Returns the next video frame info 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.
- ///
- /// TODO: return a more abstract EncodedVideoFrameInfo
- ///
- FLVVideoFrameInfo* peekNextVideoFrameInfo();
-
- /// Returns the next video frame in the parsed buffer, advancing video
cursor.
- //
- /// 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.
- ///
- /// TODO: return a more abstract EncodedVideoFrame
- ///
- FLVFrame* 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 information about video in the stream.
- //
- /// The returned object is owned by the FLVParser object.
- /// Can return NULL if video contains NO video frames.
- /// Will block till either parsing finished or a video frame is found.
- ///
- /// TODO: return a more abstract VideoInfo
- ///
- FLVVideoInfo* getVideoInfo();
-
- /// Returns a FLVAudioInfo class about the audiostream
- //
- /// TODO: return a more abstract AudioInfo
- ///
- FLVAudioInfo* 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.
- ///
- /// @param time
- /// Timestamp, in milliseconds.
- ///
- bool isTimeLoaded(boost::uint32_t time);
-
- /// \brief
- /// Seeks to the closest possible position the given position,
- /// and returns the new position.
- //
- ///
- /// TODO: throw something for sending Seek.InvalidTime ?
- /// (triggered by seeks beyond the end of video or beyond what's
- /// downloaded so far)
- ///
- boost::uint32_t seek(boost::uint32_t);
-
- /// Returns the framedelay from the last to the current
- /// audioframe in milliseconds. This is used for framerate.
- //
- boost::uint32_t audioFrameDelay();
-
- /// \brief
- /// Returns the framedelay from the last to the current
- /// videoframe in milliseconds.
- //
- boost::uint32_t videoFrameDelay();
-
- /// Returns the framerate of the video
- //
- boost::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.
- //
- boost::uint32_t getBufferLength();
-
- /// Parses next tag from the file
- //
- /// Returns true if something was parsed, false otherwise.
- /// Sets _parsingComplete=true on end of file.
- ///
- bool parseNextTag();
-
- /// Return number of bytes parsed so far
- boost::uint64_t getBytesLoaded() const;
-
- /// Return total number of bytes in input
- boost::uint64_t getBytesTotal() const;
-
-private:
-
- /// seeks to the closest possible position the given position,
- /// and returns the new position.
- boost::uint32_t seekAudio(boost::uint32_t time);
-
- /// seeks to the closest possible position the given position,
- /// and returns the new position.
- boost::uint32_t seekVideo(boost::uint32_t time);
-
- /// Parses the header of the file
- bool parseHeader();
-
- // Functions used to extract numbers from the file
- inline boost::uint32_t getUInt24(boost::uint8_t* in);
-
- /// The interface to the file, externally owned
- std::auto_ptr<tu_file> _lt;
-
- // NOTE: FLVVideoFrameInfo is a relatively small structure,
- // chances are keeping by value here would reduce
- // memory fragmentation with no big cost
- typedef std::vector<FLVVideoFrameInfo*> VideoFrames;
-
- /// list of videoframes, does no contain the frame data.
- VideoFrames _videoFrames;
-
- // NOTE: FLVAudioFrameInfo is a relatively small structure,
- // chances are keeping by value here would reduce
- // memory fragmentation with no big cost
- typedef std::vector<FLVAudioFrameInfo*> AudioFrames;
-
- /// list of audioframes, does no contain the frame data.
- AudioFrames _audioFrames;
-
- /// The position where the parsing should continue from.
- boost::uint64_t _lastParsedPosition;
-
- /// Whether the parsing is complete or not
- bool _parsingComplete;
-
- /// Info about the video stream (if any)
- std::auto_ptr<FLVVideoInfo> _videoInfo;
-
- /// Info about the audio stream (if any)
- std::auto_ptr<FLVAudioInfo> _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;
-};
-
-} // end of gnash namespace
-
-#endif // __FLVPARSER_H__
Index: libmedia/MediaDecoder.cpp
===================================================================
RCS file: libmedia/MediaDecoder.cpp
diff -N libmedia/MediaDecoder.cpp
--- libmedia/MediaDecoder.cpp 5 Mar 2008 03:55:54 -0000 1.6
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,176 +0,0 @@
-// MediaDecoder.cpp: Media decoding generic code
-//
-// Copyright (C) 2007, 2008 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 "MediaDecoder.h"
-
-#include "log.h"
-
-namespace gnash {
-namespace media {
-
-std::vector<StatusCode> MediaDecoder::getOnStatusEvents()
-{
- boost::mutex::scoped_lock lock(_onStatusMutex);
-
- const std::vector<StatusCode> statusQueue(_onStatusQueue);
- _onStatusQueue.clear();
- return statusQueue;
-}
-
-void MediaDecoder::decodingLoop()
-{
-
- bool decodingFailed = false;
-
- // The decode loop
- while (_running)
- {
-
- // If the buffer is not full, put something into it!
- if (!_buffer->isFull())
- {
- while (!_buffer->isFull() && _running)
- {
- if (!decodeAndBufferFrame())
- {
- decodingFailed = true;
- break;
- }
- //log_debug("decoded a frame");
- }
-
- }
- // "Warm up" the data.
- else if (_streamSize > _lastConfirmedPosition)
- {
- if (_stream->set_position(_lastConfirmedPosition+2048)
!= 0)
- {
- // We assume we're done now
- // TODO: check for errors
- _lastConfirmedPosition = _streamSize;
- }
- else
- {
- _lastConfirmedPosition += 2048;
- }
- //log_debug("warming up the file");
- }
-
- if (_buffer->isFull())
- {
- pushOnStatus(bufferFull);
-
- // If download is complete there is nothing to do, so
we take a break.
- if (_streamSize <= _lastConfirmedPosition)
- {
- relax();
- continue;
- }
- }
-
- // If decoding failed, there's a good chance playback has
ended, so
- // we take a breake until someone tells us to wake up.
- if (decodingFailed)
- {
- relax();
- }
-
- }
- log_debug("Left the decoding loop");
-}
-
-bool MediaDecoder::decodeAndBufferFrame()
-{
- MediaFrame* frame = _parser->parseMediaFrame();
- boost::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
- pushOnStatus(playStop);
- } else {
- pushOnStatus(streamNotFound);
- log_error("FLV parsing problems! stopping buffering.");
- _running = false;
- }
- return false;
- }
-
- if (frame->tag == 9) {
- decodeVideo(frame);
- } else {
- decodeAudio(frame);
- }
- return true;
-
-}
-
-
-void MediaDecoder::decodeAudio(MediaFrame* packet)
-{
- // We don't handle audio
- if (!_audioDecoder.get()) return;
-
- boost::uint32_t datasize;
- boost::uint32_t bufsize;
-
- boost::uint8_t* ptr = _audioDecoder->decode(packet->data,
packet->dataSize, bufsize, datasize, false);
-
- if (bufsize > 0 && ptr != NULL)
- {
- raw_audiodata_t* raw = new raw_audiodata_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."));
-
-}
-
-void MediaDecoder::decodeVideo(MediaFrame* packet)
-{
- // We don't handle video decoding today
- if (!_videoDecoder.get()) return;
-
- std::auto_ptr<image::image_base> img =
_videoDecoder->decodeToImage(packet->data, packet->dataSize);
-
- if (img.get() != NULL)
- {
- raw_videodata_t* raw = new raw_videodata_t();
-
- raw->image = img;
- raw->timestamp = packet->timestamp;
- _buffer->pushVideo(raw);
- return;
- }
- log_debug(_("Problems decoding video frame."));
-
-}
-
-} // media namespace
-} // gnash namespace
-
Index: libmedia/MediaDecoder.h
===================================================================
RCS file: libmedia/MediaDecoder.h
diff -N libmedia/MediaDecoder.h
--- libmedia/MediaDecoder.h 5 Mar 2008 03:55:54 -0000 1.8
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,275 +0,0 @@
-// MediaDecoder.h: Media decoding base class.
-//
-// Copyright (C) 2007, 2008 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 __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 <boost/shared_ptr.hpp>
-#include <vector>
-
-#include "MediaBuffer.h"
-#include "MediaParser.h"
-#include "FLVParser.h"
-#include "AudioDecoder.h"
-#include "VideoDecoder.h"
-#include "log.h"
-
-#ifdef HAVE_CONFIG_H
-#include "gnashconfig.h"
-#endif
-
-namespace gnash {
-namespace media {
-
-/// Status codes used for NetStream onStatus notifications
-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
-};
-
-/// \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:
- /// 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(boost::shared_ptr<tu_file> stream, MediaBuffer* buffer,
boost::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(false),
- _video(false),
- _running(true),
- _audioDecoder(NULL),
- _videoDecoder(NULL),
- _decodeThread(NULL)
- {
- }
-
- /// Destroys the Decoder
-#if !defined(sgi) || defined(__GNUC__)
- virtual ~MediaDecoder() {}
-#endif
- /// Seeks to pos, returns the new position
- virtual boost::uint32_t seek(boost::uint32_t /*pos*/) { return 0;}
-
- virtual std::pair<boost::uint32_t, boost::uint32_t> getWidthAndHeight()
{ return std::pair<boost::uint32_t, boost::uint32_t>(0,0); }
-
- /// Returns the size of the file being loaded, in bytes
- boost::uint32_t getBytesTotal()
- {
- return _streamSize;
- }
-
- /// Returns the amount of bytes of the current file that has been
loaded.
- boost::uint32_t getBytesLoaded() {
- return _lastConfirmedPosition;
- }
-
- /// Returns a vector with the waiting onStatus events (AS2)
- std::vector<StatusCode> getOnStatusEvents();
-
- /// Returns whether we got audio
- bool gotAudio() {
- return _audio;
- }
-
- /// Returns whether we got video
- bool gotVideo() {
- return _video;
- }
-
- /// Used to wake up the decoder when it is needed
- void wakeUp()
- {
- boost::mutex::scoped_lock lock(_monitor);
- _nothingToDo.notify_all();
- }
-
-protected:
-
- /// Decodes data with the decoders that has been setup and pushes the
data
- /// unto the buffer. Returns when decoding stops.
- void decodingLoop();
-
- /// Decodes a frame and push it unto the buffer
- bool 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);
-
- /// Push an event to the onStatus event queue (AS2)
- void pushOnStatus(StatusCode code) {
- boost::mutex::scoped_lock lock(_onStatusMutex);
- _onStatusQueue.push_back(code);
- }
-
- /// used to wait for something to do
- void relax()
- {
- boost::mutex::scoped_lock lock(_monitor);
- _nothingToDo.wait(lock);
- }
-
- /// The media buffer
- MediaBuffer* _buffer;
-
- /// The stream we decode
- boost::shared_ptr<tu_file> _stream;
-
- /// Version of the SWF playing
- boost::uint16_t _swfVersion;
-
- /// The output format
- int _videoFrameFormat;
-
- /// The parser used
- std::auto_ptr<MediaParser> _parser;
-
- /// The last confirmed size of the downloaded file
- boost::uint32_t _lastConfirmedPosition;
-
- /// total size of the file being downloaded
- boost::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;
-
- /// Used to wait when there is nothing to do
- boost::condition _nothingToDo;
- boost::mutex _monitor;
-
- // Should the decode loop run or not
- volatile bool _running;
-
- // An audio decoder
- std::auto_ptr<AudioDecoder> _audioDecoder;
-
- // A video decoder
- std::auto_ptr<VideoDecoder> _videoDecoder;
-
- // The decoding thread
- boost::thread* _decodeThread;
-};
-
-
-} // gnash.media namespace
-} // namespace gnash
-
-#endif // __MEDIADECODER_H__
Index: libmedia/gst/MediaDecoderGst.cpp
===================================================================
RCS file: libmedia/gst/MediaDecoderGst.cpp
diff -N libmedia/gst/MediaDecoderGst.cpp
--- libmedia/gst/MediaDecoderGst.cpp 5 Mar 2008 03:55:55 -0000 1.5
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,183 +0,0 @@
-// MediaDecoderGst.cpp: Media decoding using Gstreamer
-//
-// Copyright (C) 2007, 2008 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 "MediaDecoderGst.h"
-#include "AudioDecoderNellymoser.h"
-#include "AudioDecoderSimple.h"
-
-#include "AudioDecoderGst.h"
-#include "VideoDecoderGst.h"
-
-#include "log.h"
-
-#include "gnash.h"
-
-namespace gnash {
-namespace media {
-
-MediaDecoderGst::MediaDecoderGst(boost::shared_ptr<tu_file> stream,
MediaBuffer* buffer, boost::uint16_t swfVersion, int format)
- :
- MediaDecoder(stream, buffer, swfVersion, format)
-{
- // Start the decoding thread which will also setup the decoder and
parser
- _decodeThread = new
boost::thread(boost::bind(MediaDecoderGst::decodeThread, this));
-}
-
-MediaDecoderGst::~MediaDecoderGst()
-{
- _running = false;
-
- if (_decodeThread) {
- wakeUp();
- _decodeThread->join();
- delete _decodeThread;
- _decodeThread = NULL;
- }
-}
-
-bool MediaDecoderGst::setupParser()
-{
- // Buffer a bit to make sure the stream is accessable
- if (_stream->set_position(512) != 0) {
- _error = streamError;
- pushOnStatus(streamNotFound);
- return false;
- }
-
- _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
- if (std::string(head) == "FLV") {
- _parser.reset(new FLVParser(_stream));
- return _parser->setupParser();
- } else {
- return false;
- }
-}
-
-bool MediaDecoderGst::setupDecoding()
-{
-#if 0
- std::auto_ptr<VideoInfo> vInfo = _parser->getVideoInfo();
- if (vInfo.get() != NULL) {
-
- _videoDecoder.reset(new VideoDecoderGst());
-
- 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.");
- }
- }
-#endif
- std::auto_ptr<AudioInfo> aInfo = _parser->getAudioInfo();
- if (get_sound_handler() && aInfo.get() != NULL) {
-
- if (_parser->isAudioNellymoser()) {
- _audioDecoder.reset(new AudioDecoderNellymoser());
- }
-
- if (_audioDecoder.get() == NULL) _audioDecoder.reset(new
AudioDecoderGst());
-
- 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);
-}
-
-
-boost::uint32_t MediaDecoderGst::seek(boost::uint32_t pos)
-{
- boost::uint32_t ret = 0;
- if (_parser.get()) ret = _parser->seek(pos);
- else ret = 0;
-
- // Flush the buffer
- _buffer->flush();
-
- return ret;
-}
-
-void MediaDecoderGst::decodeThread(MediaDecoderGst* decoder)
-{
-printf("\t in the decode thread\n");
-
- // If the destructor has been called at this point, exit the thread
- if (!decoder->_running) return;
-
- // Setup the decoder and parser
-
- if (decoder->setupParser()) {
- if (!decoder->setupDecoding()) {
- decoder->pushOnStatus(streamNotFound);
- log_error("Setup of media decoder failed");
- return;
- }
-
- // If the parser setup failed, it is perhaps because it is not a FLV
file,
- // so we set up an gstreamer pipeline instead.
- } else {
-/* if (!decoder->setupGstPipeline()) {
- decoder->pushOnStatus(streamNotFound);*/
- log_error("Setup of media parser failed");
- return;
-// }
- }
-
- // Everything is setup, so let's play!
-
- decoder->pushOnStatus(playStart);
-
- decoder->decodingLoop();
-}
-
-std::pair<boost::uint32_t, boost::uint32_t>
-MediaDecoderGst::getWidthAndHeight()
-{
- if (_parser.get()) {
- std::auto_ptr<VideoInfo> vInfo = _parser->getVideoInfo();
- if (vInfo.get()) return std::pair<boost::uint32_t,
boost::uint32_t>(vInfo->width, vInfo->height);
- }
- return std::pair<boost::uint32_t, boost::uint32_t>(0,0);
-}
-
-
-} // namespace media
-
-} // namespace gnash
Index: libmedia/gst/MediaDecoderGst.h
===================================================================
RCS file: libmedia/gst/MediaDecoderGst.h
diff -N libmedia/gst/MediaDecoderGst.h
--- libmedia/gst/MediaDecoderGst.h 5 Mar 2008 03:55:55 -0000 1.4
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,61 +0,0 @@
-// MediaDecoderGst.h: Media decoding using Gstreamer
-//
-// Copyright (C) 2007, 2008 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 __MEDIADECODERGST_H__
-#define __MEDIADECODERGST_H__
-
-#ifdef HAVE_CONFIG_H
-#include "gnashconfig.h"
-#endif
-
-#include "MediaDecoder.h"
-#include "MediaParser.h"
-#include "AudioDecoder.h"
-#include "VideoDecoder.h"
-
-#include "image.h"
-
-namespace gnash {
-namespace media {
-
-/// Media decoding using Gstreamer
-class MediaDecoderGst: public MediaDecoder {
-public:
- MediaDecoderGst(boost::shared_ptr<tu_file> stream, MediaBuffer* buffer,
boost::uint16_t swfVersion, int format);
- ~MediaDecoderGst();
-
- /// Seeks to pos
- boost::uint32_t seek(boost::uint32_t pos);
-
- std::pair<boost::uint32_t, boost::uint32_t> getWidthAndHeight();
-
-private:
- /// Sets up the parser
- bool setupParser();
-
- /// The decoding thread. Sets up the decoder, and decodes.
- static void decodeThread(MediaDecoderGst* decoder);
-
- /// Sets up the decoder and parser
- bool setupDecoding();
-};
-
-} // namespace media
-} // namespace gnash
-#endif // __MEDIADECODERGST_H__
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] gnash ChangeLog libbase/Makefile.am libmedia/Au...,
Sandro Santilli <=