mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 19:29:09 +00:00
Rewrite TrackMgr
Also: Do not start the video again if it is already playing. Update files from libwebm
This commit is contained in:
@ -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)
|
||||||
{
|
|
||||||
#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
|
|
||||||
IProcessVideoFrame(video);
|
|
||||||
IProcessAudioFrame(audio);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false;
|
return false;
|
||||||
#endif // VIDEO_AVAILABLE
|
|
||||||
|
#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(fReader, movieTime, audio))
|
||||||
|
tracksWithData++;
|
||||||
}
|
}
|
||||||
|
if (fVideoTrack)
|
||||||
|
{
|
||||||
|
if (fVideoTrack->GetFrames(fReader, movieTime, video))
|
||||||
|
tracksWithData++;
|
||||||
|
}
|
||||||
|
if (!tracksWithData)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show our mess
|
||||||
|
IProcessVideoFrame(video);
|
||||||
|
IProcessAudioFrame(audio);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
#endif // VIDEO_AVAILABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
bool plMoviePlayer::Stop()
|
bool plMoviePlayer::Stop()
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||||
|
return !GetFileSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MkvReader::GetFileSize() {
|
||||||
|
if (m_file == NULL)
|
||||||
|
return false;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
int status = _fseeki64(m_file, 0L, SEEK_END);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return false; // error
|
||||||
|
|
||||||
|
m_length = _ftelli64(m_file);
|
||||||
|
#else
|
||||||
|
fseek(m_file, 0L, SEEK_END);
|
||||||
|
m_length = ftell(m_file);
|
||||||
|
#endif
|
||||||
|
assert(m_length >= 0);
|
||||||
|
|
||||||
|
if (m_length < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
status = _fseeki64(m_file, 0L, SEEK_SET);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return false; // error
|
||||||
|
#else
|
||||||
|
fseek(m_file, 0L, SEEK_SET);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WIN32
|
return true;
|
||||||
int status = _fseeki64(m_file, 0L, SEEK_END);
|
}
|
||||||
|
|
||||||
if (status)
|
void MkvReader::Close() {
|
||||||
return -1; //error
|
if (m_file != NULL) {
|
||||||
|
fclose(m_file);
|
||||||
|
m_file = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_length = _ftelli64(m_file);
|
int MkvReader::Length(long long* total, long long* available) {
|
||||||
#else
|
if (m_file == NULL)
|
||||||
fseek(m_file, 0L, SEEK_END);
|
return -1;
|
||||||
m_length = ftell(m_file);
|
|
||||||
#endif
|
|
||||||
assert(m_length >= 0);
|
|
||||||
|
|
||||||
#ifdef WIN32
|
if (total)
|
||||||
status = _fseeki64(m_file, 0L, SEEK_SET);
|
*total = m_length;
|
||||||
|
|
||||||
if (status)
|
if (available)
|
||||||
return -1; //error
|
*available = m_length;
|
||||||
#else
|
|
||||||
fseek(m_file, 0L, SEEK_SET);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
|
||||||
|
if (m_file == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
void MkvReader::Close()
|
if (offset >= m_length)
|
||||||
{
|
return -1;
|
||||||
if (m_file != NULL)
|
|
||||||
{
|
|
||||||
fclose(m_file);
|
|
||||||
m_file = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int MkvReader::Length(long long* total, long long* available)
|
#ifdef _MSC_VER
|
||||||
{
|
const int status = _fseeki64(m_file, offset, SEEK_SET);
|
||||||
if (m_file == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (total)
|
if (status)
|
||||||
*total = m_length;
|
return -1; // error
|
||||||
|
|
||||||
if (available)
|
|
||||||
*available = m_length;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MkvReader::Read(long long offset, long len, unsigned char* buffer)
|
|
||||||
{
|
|
||||||
if (m_file == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (offset < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (offset >= m_length)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
const int status = _fseeki64(m_file, offset, SEEK_SET);
|
|
||||||
|
|
||||||
if (status)
|
|
||||||
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
|
||||||
|
@ -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(const MkvReader&);
|
MkvReader();
|
||||||
MkvReader& operator=(const MkvReader&);
|
explicit MkvReader(FILE* fp);
|
||||||
public:
|
virtual ~MkvReader();
|
||||||
MkvReader();
|
|
||||||
virtual ~MkvReader();
|
|
||||||
|
|
||||||
int Open(const char*);
|
int Open(const char*);
|
||||||
void Close();
|
void Close();
|
||||||
bool IsOpen() const;
|
|
||||||
|
|
||||||
virtual int Read(long long position, long length, unsigned char* buffer);
|
virtual int Read(long long position, long length, unsigned char* buffer);
|
||||||
virtual int Length(long long* total, long long* available);
|
virtual int Length(long long* total, long long* available);
|
||||||
private:
|
|
||||||
long long m_length;
|
private:
|
||||||
FILE* m_file;
|
MkvReader(const MkvReader&);
|
||||||
|
MkvReader& operator=(const MkvReader&);
|
||||||
|
|
||||||
|
// Determines the size of the file. This is called either by the constructor
|
||||||
|
// 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
|
||||||
|
Reference in New Issue
Block a user