[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog libmedia/ffmpeg/MediaParserFfmp...
From: |
Sandro Santilli |
Subject: |
[Gnash-commit] gnash ChangeLog libmedia/ffmpeg/MediaParserFfmp... |
Date: |
Wed, 04 Jun 2008 14:06:58 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Sandro Santilli <strk> 08/06/04 14:06:57
Modified files:
. : ChangeLog
libmedia/ffmpeg: MediaParserFfmpeg.cpp MediaParserFfmpeg.h
server/asobj : NetStreamFfmpeg.cpp
Log message:
* libmedia/ffmpeg/MediaParserFfmpeg.{cpp,h}: implement frame parsing.
* server/asobj/NetStreamFfmpeg.cpp (refreshVideoFrame): don't do
anything if video decoder wasn't initialized.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.6809&r2=1.6810
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/ffmpeg/MediaParserFfmpeg.cpp?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/ffmpeg/MediaParserFfmpeg.h?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.cpp?cvsroot=gnash&r1=1.141&r2=1.142
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.6809
retrieving revision 1.6810
diff -u -b -r1.6809 -r1.6810
--- ChangeLog 4 Jun 2008 14:02:01 -0000 1.6809
+++ ChangeLog 4 Jun 2008 14:06:56 -0000 1.6810
@@ -1,3 +1,9 @@
+2008-06-04 Sandro Santilli <address@hidden>
+
+ * libmedia/ffmpeg/MediaParserFfmpeg.{cpp,h}: implement frame parsing.
+ * server/asobj/NetStreamFfmpeg.cpp (refreshVideoFrame): don't do
+ anything if video decoder wasn't initialized.
+
2008-06-04 Benjamin Wolsey <address@hidden>
* server/movie_root.cpp: add metadata to Movie Properties tree.
Index: libmedia/ffmpeg/MediaParserFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/libmedia/ffmpeg/MediaParserFfmpeg.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libmedia/ffmpeg/MediaParserFfmpeg.cpp 4 Jun 2008 11:40:46 -0000
1.2
+++ libmedia/ffmpeg/MediaParserFfmpeg.cpp 4 Jun 2008 14:06:57 -0000
1.3
@@ -30,6 +30,16 @@
namespace gnash {
namespace media {
+namespace { // anonymous namespace
+
+ // Used to calculate a decimal value from a ffmpeg fraction
+ inline double as_double(AVRational time)
+ {
+ return time.num / (double) time.den;
+ }
+
+} // anonymous namespace
+
int
MediaParserFfmpeg::readPacketWrapper(void* opaque, boost::uint8_t* buf, int
buf_size)
@@ -114,6 +124,7 @@
VideoInfo*
MediaParserFfmpeg::getVideoInfo()
{
+ //VideoInfo(int codeci, boost::uint16_t widthi, boost::uint16_t
heighti, boost::uint16_t frameRatei, boost::uint64_t durationi, codecType typei)
LOG_ONCE( log_unimpl("%s", __PRETTY_FUNCTION__) );
return 0;
}
@@ -130,11 +141,11 @@
{
log_debug("MediaParserFfmpeg::seek(%d) TESTING", pos);
- AVStream* videostream = _formatCtx->streams[_videoIndex];
+ AVStream* videostream = _formatCtx->streams[_videoStreamIndex];
double timebase = static_cast<double>(videostream->time_base.num /
videostream->time_base.den);
long newpos = static_cast<long>(pos / timebase);
- if (av_seek_frame(_formatCtx, _videoIndex, newpos, 0) < 0)
+ if (av_seek_frame(_formatCtx, _videoStreamIndex, newpos, 0) < 0)
{
log_error(_("%s: seeking failed"), __FUNCTION__);
return 0;
@@ -153,21 +164,123 @@
return 0; // ??
}
- newtime = timebase *
(double)_formatCtx->streams[_videoIndex]->cur_dts;
+ newtime = timebase *
(double)_formatCtx->streams[_videoStreamIndex]->cur_dts;
}
//av_free_packet( &Packet );
- av_seek_frame(_formatCtx, _videoIndex, newpos, 0);
+ av_seek_frame(_formatCtx, _videoStreamIndex, newpos, 0);
newtime = static_cast<boost::int32_t>(newtime / 1000.0);
return newtime;
}
bool
-MediaParserFfmpeg::parseNextChunk()
+MediaParserFfmpeg::parseVideoFrame(AVPacket& packet)
{
- LOG_ONCE( log_unimpl("%s", __PRETTY_FUNCTION__) );
+ assert(packet.stream_index == _videoStreamIndex);
+ assert(_videoStream);
+
+ // packet.dts is "decompression" timestamp
+ // packet.pts is "presentation" timestamp
+ // Dunno why we use dts, and don't understand the magic formula
either...
+ boost::uint64_t timestamp = static_cast<boost::uint64_t>(packet.dts *
as_double(_videoStream->time_base) * 1000.0);
+
+ // flags, for keyframe
+ bool isKeyFrame = packet.flags&PKT_FLAG_KEY;
+
+ // Frame offset in input
+ boost::int64_t offset = packet.pos;
+ if ( offset < 0 )
+ {
+ log_error("Unknown offset of video frame, what to use here ?");
+ return false;
+ }
+
+ VideoFrameInfo* info = new VideoFrameInfo;
+ info->dataSize = packet.size;
+ info->isKeyFrame = isKeyFrame;
+ info->dataPosition = offset;
+ info->timestamp = timestamp;
+
+ _videoFrames.push_back(info); // takes ownership
+
+ return true;
+}
+
+bool
+MediaParserFfmpeg::parseAudioFrame(AVPacket& packet)
+{
+ assert(packet.stream_index == _audioStreamIndex);
+ assert(_audioStream);
+
+ // packet.dts is "decompression" timestamp
+ // packet.pts is "presentation" timestamp
+ // Dunno why we use dts, and don't understand the magic formula
either...
+ boost::uint64_t timestamp = static_cast<boost::uint64_t>(packet.dts *
as_double(_audioStream->time_base) * 1000.0);
+
+ // Frame offset in input
+ boost::int64_t offset = packet.pos;
+ if ( offset < 0 )
+ {
+ log_error("Unknown offset of audio frame, what to use here ?");
return false;
+ }
+
+ AudioFrameInfo* info = new AudioFrameInfo;
+ info->dataSize = packet.size;
+ info->dataPosition = offset;
+ info->timestamp = timestamp;
+
+ _audioFrames.push_back(info); // takes ownership
+
+ return true;
+}
+
+bool
+MediaParserFfmpeg::parseNextFrame()
+{
+ if ( _parsingComplete ) return false;
+
+ assert(_formatCtx);
+
+ AVPacket packet;
+
+ int rc = av_read_frame(_formatCtx, &packet);
+ if ( rc < 0 )
+ {
+ log_error(_("MediaParserFfmpeg::parseNextChunk: Problems
parsing next frame"));
+ return false;
+ }
+
+ bool ret=false;
+
+ if ( packet.stream_index == _videoStreamIndex )
+ {
+ ret = parseVideoFrame(packet);
+ }
+ else if ( packet.stream_index == _audioStreamIndex )
+ {
+ ret = parseAudioFrame(packet);
+ }
+ else
+ {
+ ret = false; // redundant..
+ log_debug("MediaParserFfmpeg::parseNextFrame: unknown stream
index %d", packet.stream_index);
+ }
+
+ av_free_packet(&packet);
+
+ return ret;
+
+}
+
+bool
+MediaParserFfmpeg::parseNextChunk()
+{
+ // parse 2 frames...
+ if ( ! parseNextFrame() ) return false;
+ if ( ! parseNextFrame() ) return false;
+ return true;
}
boost::uint64_t
@@ -182,9 +295,9 @@
MediaParser(stream),
_inputFmt(0),
_formatCtx(0),
- _videoIndex(-1),
+ _videoStreamIndex(-1),
_videoStream(0),
- _audioIndex(-1),
+ _audioStreamIndex(-1),
_audioStream(0),
_lastParsedPosition(0)
{
@@ -229,17 +342,17 @@
switch (enc->codec_type)
{
case CODEC_TYPE_AUDIO:
- if (_audioIndex < 0)
+ if (_audioStreamIndex < 0)
{
- _audioIndex = i;
+ _audioStreamIndex = i;
_audioStream = _formatCtx->streams[i];
}
break;
case CODEC_TYPE_VIDEO:
- if (_videoIndex < 0)
+ if (_videoStreamIndex < 0)
{
- _videoIndex = i;
+ _videoStreamIndex = i;
_videoStream = _formatCtx->streams[i];
}
break;
@@ -247,17 +360,10 @@
break;
}
}
-
- LOG_ONCE( log_unimpl("MediaParserFfmpeg") );
}
MediaParserFfmpeg::~MediaParserFfmpeg()
{
- if ( _inputFmt )
- {
- // TODO: check if this is correct (should we create RIIA
classes for ffmpeg stuff?)
- av_free(_inputFmt);
- }
if ( _formatCtx )
{
@@ -265,6 +371,24 @@
//av_close_input_file(_formatCtx); // NOTE: this one triggers a
mismatched free/delete on _byteIOBuffer !
av_free(_formatCtx);
}
+
+ if ( _inputFmt )
+ {
+ // TODO: check if this is correct (should we create RIIA
classes for ffmpeg stuff?)
+ //av_free(_inputFmt); // it seems this one blows up, could be
due to av_free(_formatCtx) above
+ }
+
+ for (VideoFrames::iterator i=_videoFrames.begin(),
+ e=_videoFrames.end(); i!=e; ++i)
+ {
+ delete (*i);
+ }
+
+ for (AudioFrames::iterator i=_audioFrames.begin(),
+ e=_audioFrames.end(); i!=e; ++i)
+ {
+ delete (*i);
+ }
}
int
@@ -280,6 +404,9 @@
boost::uint64_t curPos = in.get_position();
if ( curPos > _lastParsedPosition ) _lastParsedPosition = curPos;
+ // Check if EOF was reached
+ if ( in.get_eof() ) _parsingComplete=true;
+
return ret;
}
Index: libmedia/ffmpeg/MediaParserFfmpeg.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/ffmpeg/MediaParserFfmpeg.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libmedia/ffmpeg/MediaParserFfmpeg.h 4 Jun 2008 11:40:46 -0000 1.2
+++ libmedia/ffmpeg/MediaParserFfmpeg.h 4 Jun 2008 14:06:57 -0000 1.3
@@ -26,6 +26,7 @@
#include "MediaParser.h" // for inheritance
+#include <vector>
#include <boost/scoped_array.hpp>
#include <memory>
@@ -87,6 +88,101 @@
private:
+ /// Information about an FFMPEG Video Frame
+ class VideoFrameInfo
+ {
+ public:
+
+ VideoFrameInfo()
+ :
+ isKeyFrame(false),
+ dataSize(0),
+ dataPosition(0),
+ timestamp(0)
+ {}
+
+ /// Type of this frame
+ bool isKeyFrame;
+
+ /// Size of the frame in bytes (needed?)
+ boost::uint32_t dataSize;
+
+ /// Start of frame data in stream
+ boost::uint64_t dataPosition;
+
+ /// Timestamp in milliseconds
+ boost::uint32_t timestamp;
+
+ };
+
+ /// Information about an FFMPEG Audio Frame
+ class AudioFrameInfo
+ {
+ public:
+
+ AudioFrameInfo()
+ :
+ dataSize(0),
+ dataPosition(0),
+ timestamp(0)
+ {}
+
+ /// Size of the frame in bytes (needed?)
+ boost::uint32_t dataSize;
+
+ /// Start of frame data in stream
+ boost::uint64_t dataPosition;
+
+ /// Timestamp in milliseconds
+ boost::uint32_t timestamp;
+
+ };
+
+ // NOTE: VideoFrameInfo is a relatively small structure,
+ // chances are keeping by value here would reduce
+ // memory fragmentation with no big cost
+ typedef std::vector<VideoFrameInfo*> VideoFrames;
+
+ /// list of videoframes, does no contain the frame data.
+ //
+ /// Elements owned by this class.
+ ///
+ VideoFrames _videoFrames;
+
+ // NOTE: AudioFrameInfo is a relatively small structure,
+ // chances are keeping by value here would reduce
+ // memory fragmentation with no big cost
+ typedef std::vector<AudioFrameInfo*> AudioFrames;
+
+ /// list of audioframes, does no contain the frame data.
+ //
+ /// Elements owned by this class.
+ AudioFrames _audioFrames;
+
+ /// Parse next media frame
+ //
+ /// @return false on error or eof, true otherwise
+ ///
+ bool parseNextFrame();
+
+ /// Parse a video frame
+ //
+ /// Basically create a VideoFrameInfo out of the AVPacket and push
+ /// it on the container.
+ ///
+ /// @return false on error
+ ///
+ bool parseVideoFrame(AVPacket& packet);
+
+ /// Parse an audio frame
+ //
+ /// Basically create a AudioFrameInfo out of the AVPacket and push
+ /// it on the container.
+ ///
+ /// @return false on error
+ ///
+ bool parseAudioFrame(AVPacket& packet);
+
/// Input chunk reader, to be called by ffmpeg parser
int readPacket(boost::uint8_t* buf, int buf_size);
@@ -108,13 +204,13 @@
AVFormatContext *_formatCtx;
/// Index of the video stream in input
- int _videoIndex;
+ int _videoStreamIndex;
/// Video input stream
AVStream* _videoStream;
/// Index of the audio stream in input
- int _audioIndex;
+ int _audioStreamIndex;
// audio
AVStream* _audioStream;
Index: server/asobj/NetStreamFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.cpp,v
retrieving revision 1.141
retrieving revision 1.142
diff -u -b -r1.141 -r1.142
--- server/asobj/NetStreamFfmpeg.cpp 3 Jun 2008 16:21:38 -0000 1.141
+++ server/asobj/NetStreamFfmpeg.cpp 4 Jun 2008 14:06:57 -0000 1.142
@@ -725,6 +725,9 @@
{
assert ( m_parser.get() );
+ // nothing to do if we don't have a video decoder
+ if ( ! _videoDecoder.get() ) return;
+
#ifdef GNASH_DEBUG_DECODING
// bufferLength() would lock the mutex (which we already hold),
// so this is to avoid that.