Browse Source

Rewrite TrackMgr

Also:
Do not start the video again if it is already playing.
Update files from libwebm
Florian Meißner 10 years ago
parent
commit
2d990ae3e8
  1. 163
      Sources/Plasma/FeatureLib/pfMoviePlayer/plMoviePlayer.cpp
  2. 10427
      Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.cpp
  3. 1569
      Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.hpp
  4. 148
      Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.cpp
  5. 50
      Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.hpp

163
Sources/Plasma/FeatureLib/pfMoviePlayer/plMoviePlayer.cpp

@ -120,81 +120,48 @@ public:
class TrackMgr class TrackMgr
{ {
const mkvparser::BlockEntry* blk_entry; protected:
bool valid; const mkvparser::Track* fTrack;
const mkvparser::BlockEntry* fCurrentBlock;
bool PeekNextBlockEntry(const std::unique_ptr<mkvparser::Segment>& segment) int32_t fStatus;
{
// Assume that if blk_entry == nullptr, we need to start from the beginning
// Load the current cluster
const mkvparser::Cluster* cluster;
if (blk_entry)
cluster = blk_entry->GetCluster();
else
cluster = segment->GetFirst();
// As long as we have clusters, they contain blocks that we have to process
while (cluster && !cluster->EOS()) {
// If we have no block yet, get the first one, otherwise the next one
if (!blk_entry)
{
SAFE_OP(cluster->GetFirst(blk_entry), "get first block");
}
else
{
SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block");
}
// Are there any blocks left?
while (blk_entry && !blk_entry->EOS()) {
// Is this the next block we want for our track? Awesome, we're done!
if (blk_entry->GetBlock()->GetTrackNumber() == number)
return true;
SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block");
}
// No blocks left, go to next cluster
blk_entry = nullptr;
cluster = segment->GetNext(cluster);
}
// That's it, nothing left...
return false;
}
public: public:
int32_t number; TrackMgr(const mkvparser::Track* track) : fTrack(track), fCurrentBlock(nullptr), fStatus(0) { }
TrackMgr(int32_t num) : blk_entry(nullptr), valid(true), number(num) { } const mkvparser::Track* GetTrack() { return fTrack; }
bool GetFrames(plMoviePlayer* p, int64_t movieTime, std::vector<blkbuf_t>& frames) bool GetFrames(mkvparser::MkvReader* reader, int64_t movieTime, std::vector<blkbuf_t>& frames)
{ {
if (!valid) // If we have no block yet, grab the first one
return false; if (!fCurrentBlock)
fStatus = fTrack->GetFirst(fCurrentBlock);
const mkvparser::BlockEntry* prev = blk_entry; // Continue through the blocks until our current movie time
while (valid = PeekNextBlockEntry(p->fSegment)) while (fCurrentBlock && fStatus == 0)
{ {
const mkvparser::Block* blk = blk_entry->GetBlock(); const mkvparser::Block* block = fCurrentBlock->GetBlock();
if (blk->GetTime(blk_entry->GetCluster()) <= movieTime) int64_t time = block->GetTime(fCurrentBlock->GetCluster()) - fTrack->GetCodecDelay();
if (time <= movieTime * 1000000) // Block time is nano seconds
{ {
frames.reserve(frames.size() + blk->GetFrameCount()); // We want to play this block, add it to the frames buffer
for (int32_t i = 0; i < blk->GetFrameCount(); ++i) frames.reserve(frames.size() + block->GetFrameCount());
for (int32_t i = 0; i < block->GetFrameCount(); i++)
{ {
const mkvparser::Block::Frame data = blk->GetFrame(i); const mkvparser::Block::Frame data = block->GetFrame(i);
uint8_t* buf = new uint8_t[data.len]; uint8_t* buf = new uint8_t[data.len];
data.Read(p->fReader, buf); data.Read(reader, buf);
frames.push_back(std::make_tuple(std::unique_ptr<uint8_t>(buf), static_cast<int32_t>(data.len))); frames.push_back(std::make_tuple(std::unique_ptr<uint8_t>(buf), static_cast<int32_t>(data.len)));
} }
fStatus = fTrack->GetNext(fCurrentBlock, fCurrentBlock);
} }
else else
{ {
blk_entry = prev; // We've got all frames that have to play... come back for more later!
return true; return true;
} }
prev = blk_entry;
} }
return true;
return false; // No more blocks... We're done!
} }
}; };
@ -270,13 +237,13 @@ bool plMoviePlayer::IOpenMovie()
case mkvparser::Track::kAudio: case mkvparser::Track::kAudio:
{ {
if (!fAudioTrack) if (!fAudioTrack)
fAudioTrack.reset(new TrackMgr(track->GetNumber())); fAudioTrack.reset(new TrackMgr(track));
break; break;
} }
case mkvparser::Track::kVideo: case mkvparser::Track::kVideo:
{ {
if (!fVideoTrack) if (!fVideoTrack)
fVideoTrack.reset(new TrackMgr(track->GetNumber())); fVideoTrack.reset(new TrackMgr(track));
break; break;
} }
} }
@ -325,7 +292,7 @@ void plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames)
void plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames) void plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames)
{ {
#ifdef VIDEO_AVAILABLE #ifdef VIDEO_AVAILABLE
const unsigned char* data = nullptr; const uint8_t* data = nullptr;
int32_t size = 0; int32_t size = 0;
for (auto it = frames.begin(); it != frames.end(); ++it) for (auto it = frames.begin(); it != frames.end(); ++it)
{ {
@ -334,7 +301,7 @@ void plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames)
size = std::get<1>(*it); size = std::get<1>(*it);
static const int frameSize = 5760; //max packet duration at 48kHz static const int frameSize = 5760; //max packet duration at 48kHz
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fSegment->GetTracks()->GetTrackByNumber(fAudioTrack->number)); const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fAudioTrack->GetTrack());
int16_t* pcm = new int16_t[frameSize * audio->GetChannels() * sizeof(int16_t)]; int16_t* pcm = new int16_t[frameSize * audio->GetChannels() * sizeof(int16_t)];
int samples = opus_decode(fOpusDecoder, data, size, pcm, frameSize, 0); int samples = opus_decode(fOpusDecoder, data, size, pcm, frameSize, 0);
if (samples < 0) if (samples < 0)
@ -346,6 +313,9 @@ void plMoviePlayer::IProcessAudioFrame(const std::vector<blkbuf_t>& frames)
bool plMoviePlayer::Start() bool plMoviePlayer::Start()
{ {
if (fPlaying)
return false;
#ifdef VIDEO_AVAILABLE #ifdef VIDEO_AVAILABLE
if (!IOpenMovie()) if (!IOpenMovie())
return false; return false;
@ -359,7 +329,7 @@ bool plMoviePlayer::Start()
// Need to figure out scaling based on pipe size. // Need to figure out scaling based on pipe size.
plPlateManager& plateMgr = plPlateManager::Instance(); plPlateManager& plateMgr = plPlateManager::Instance();
const mkvparser::VideoTrack* video = static_cast<const mkvparser::VideoTrack*>(fSegment->GetTracks()->GetTrackByNumber(fVideoTrack->number)); const mkvparser::VideoTrack* video = static_cast<const mkvparser::VideoTrack*>(fVideoTrack->GetTrack());
float width = (static_cast<float>(video->GetWidth()) / static_cast<float>(plateMgr.GetPipeWidth())) * fScale.fX; float width = (static_cast<float>(video->GetWidth()) / static_cast<float>(plateMgr.GetPipeWidth())) * fScale.fX;
float height = (static_cast<float>(video->GetHeight()) / static_cast<float>(plateMgr.GetPipeHeight())) * fScale.fY; float height = (static_cast<float>(video->GetHeight()) / static_cast<float>(plateMgr.GetPipeHeight())) * fScale.fY;
@ -368,7 +338,7 @@ bool plMoviePlayer::Start()
fTexture = fPlate->CreateMaterial(static_cast<uint32_t>(video->GetWidth()), static_cast<uint32_t>(video->GetHeight()), nullptr); fTexture = fPlate->CreateMaterial(static_cast<uint32_t>(video->GetWidth()), static_cast<uint32_t>(video->GetHeight()), nullptr);
//initialize opus //initialize opus
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fSegment->GetTracks()->GetTrackByNumber(fAudioTrack->number)); const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fAudioTrack->GetTrack());
plWAVHeader header; plWAVHeader header;
header.fFormatTag = plWAVHeader::kPCMFormatTag; header.fFormatTag = plWAVHeader::kPCMFormatTag;
header.fNumChannels = audio->GetChannels(); header.fNumChannels = audio->GetChannels();
@ -392,45 +362,44 @@ bool plMoviePlayer::Start()
bool plMoviePlayer::NextFrame() bool plMoviePlayer::NextFrame()
{ {
if (fPlaying) if (!fPlaying)
{ return false;
#ifdef VIDEO_AVAILABLE
// Get our current timecode
int64_t movieTime = 0;
if (fStartTime == 0)
fStartTime = static_cast<int64_t>(hsTimer::GetMilliSeconds());
else
movieTime = GetMovieTime();
std::vector<blkbuf_t> audio;
std::vector<blkbuf_t> video;
uint8_t tracksWithData = 0;
if (fAudioTrack)
{
if (fAudioTrack->GetFrames(this, movieTime, audio))
tracksWithData++;
}
if (fVideoTrack)
{
if (fVideoTrack->GetFrames(this, movieTime, video))
tracksWithData++;
}
if (!tracksWithData)
{
Stop();
return false;
}
// Show our mess #ifdef VIDEO_AVAILABLE
IProcessVideoFrame(video); // Get our current timecode
IProcessAudioFrame(audio); int64_t movieTime = 0;
if (fStartTime == 0)
fStartTime = static_cast<int64_t>(hsTimer::GetMilliSeconds());
else
movieTime = GetMovieTime();
return true; std::vector<blkbuf_t> audio;
#else std::vector<blkbuf_t> video;
uint8_t tracksWithData = 0;
if (fAudioTrack)
{
if (fAudioTrack->GetFrames(fReader, movieTime, audio))
tracksWithData++;
}
if (fVideoTrack)
{
if (fVideoTrack->GetFrames(fReader, movieTime, video))
tracksWithData++;
}
if (!tracksWithData)
{
Stop();
return false; return false;
#endif // VIDEO_AVAILABLE
} }
// Show our mess
IProcessVideoFrame(video);
IProcessAudioFrame(audio);
return true;
#else
return false; return false;
#endif // VIDEO_AVAILABLE
} }
bool plMoviePlayer::Stop() bool plMoviePlayer::Stop()

10427
Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.cpp

File diff suppressed because it is too large Load Diff

1569
Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.hpp

File diff suppressed because it is too large Load Diff

148
Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.cpp

@ -10,119 +10,123 @@
#include <cassert> #include <cassert>
namespace mkvparser namespace mkvparser {
{
MkvReader::MkvReader() : MkvReader::MkvReader() : m_file(NULL), reader_owns_file_(true) {}
m_file(NULL)
{ MkvReader::MkvReader(FILE* fp) : m_file(fp), reader_owns_file_(false) {
GetFileSize();
} }
MkvReader::~MkvReader() MkvReader::~MkvReader() {
{ if (reader_owns_file_)
Close(); Close();
m_file = NULL;
} }
int MkvReader::Open(const char* fileName) int MkvReader::Open(const char* fileName) {
{ if (fileName == NULL)
if (fileName == NULL) return -1;
return -1;
if (m_file) if (m_file)
return -1; return -1;
#ifdef WIN32 #ifdef _MSC_VER
const errno_t e = fopen_s(&m_file, fileName, "rb"); const errno_t e = fopen_s(&m_file, fileName, "rb");
if (e) if (e)
return -1; //error return -1; // error
#else #else
m_file = fopen(fileName, "rb"); m_file = fopen(fileName, "rb");
if (m_file == NULL) if (m_file == NULL)
return -1; return -1;
#endif #endif
return !GetFileSize();
}
#ifdef WIN32 bool MkvReader::GetFileSize() {
int status = _fseeki64(m_file, 0L, SEEK_END); if (m_file == NULL)
return false;
#ifdef _MSC_VER
int status = _fseeki64(m_file, 0L, SEEK_END);
if (status) if (status)
return -1; //error return false; // error
m_length = _ftelli64(m_file); m_length = _ftelli64(m_file);
#else #else
fseek(m_file, 0L, SEEK_END); fseek(m_file, 0L, SEEK_END);
m_length = ftell(m_file); m_length = ftell(m_file);
#endif #endif
assert(m_length >= 0); assert(m_length >= 0);
if (m_length < 0)
return false;
#ifdef WIN32 #ifdef _MSC_VER
status = _fseeki64(m_file, 0L, SEEK_SET); status = _fseeki64(m_file, 0L, SEEK_SET);
if (status) if (status)
return -1; //error return false; // error
#else #else
fseek(m_file, 0L, SEEK_SET); fseek(m_file, 0L, SEEK_SET);
#endif #endif
return 0; return true;
} }
void MkvReader::Close() void MkvReader::Close() {
{ if (m_file != NULL) {
if (m_file != NULL) fclose(m_file);
{ m_file = NULL;
fclose(m_file); }
m_file = NULL;
}
} }
int MkvReader::Length(long long* total, long long* available) int MkvReader::Length(long long* total, long long* available) {
{ if (m_file == NULL)
if (m_file == NULL) return -1;
return -1;
if (total) if (total)
*total = m_length; *total = m_length;
if (available) if (available)
*available = m_length; *available = m_length;
return 0; return 0;
} }
int MkvReader::Read(long long offset, long len, unsigned char* buffer) int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
{ if (m_file == NULL)
if (m_file == NULL) return -1;
return -1;
if (offset < 0) if (offset < 0)
return -1; return -1;
if (len < 0) if (len < 0)
return -1; return -1;
if (len == 0) if (len == 0)
return 0; return 0;
if (offset >= m_length) if (offset >= m_length)
return -1; return -1;
#ifdef WIN32 #ifdef _MSC_VER
const int status = _fseeki64(m_file, offset, SEEK_SET); const int status = _fseeki64(m_file, offset, SEEK_SET);
if (status) if (status)
return -1; //error return -1; // error
#else #else
fseek(m_file, offset, SEEK_SET); fseek(m_file, offset, SEEK_SET);
#endif #endif
const size_t size = fread(buffer, 1, len, m_file); const size_t size = fread(buffer, 1, len, m_file);
if (size < size_t(len)) if (size < size_t(len))
return -1; //error return -1; // error
return 0; //success return 0; // success
} }
} //end namespace mkvparser } // end namespace mkvparser

50
Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.hpp

@ -12,28 +12,34 @@
#include "mkvparser.hpp" #include "mkvparser.hpp"
#include <cstdio> #include <cstdio>
namespace mkvparser namespace mkvparser {
{
class MkvReader : public IMkvReader {
class MkvReader : public IMkvReader public:
{ MkvReader();
MkvReader(const MkvReader&); explicit MkvReader(FILE* fp);
MkvReader& operator=(const MkvReader&); virtual ~MkvReader();
public:
MkvReader(); int Open(const char*);
virtual ~MkvReader(); void Close();
int Open(const char*); virtual int Read(long long position, long length, unsigned char* buffer);
void Close(); virtual int Length(long long* total, long long* available);
bool IsOpen() const;
private:
virtual int Read(long long position, long length, unsigned char* buffer); MkvReader(const MkvReader&);
virtual int Length(long long* total, long long* available); MkvReader& operator=(const MkvReader&);
private:
long long m_length; // Determines the size of the file. This is called either by the constructor
FILE* m_file; // or by the Open function depending on file ownership. Returns true on
// success.
bool GetFileSize();
long long m_length;
FILE* m_file;
bool reader_owns_file_;
}; };
} //end namespace mkvparser } // end namespace mkvparser
#endif //MKVREADER_HPP #endif // MKVREADER_HPP

Loading…
Cancel
Save