Browse Source
Type restructuring for C++98 and build configuration updates. This version compiles successfully, but without webm libraries yet linked in.rarified/movieplayer
rarified
4 years ago
20 changed files with 10589 additions and 175 deletions
@ -0,0 +1,452 @@ |
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools |
||||||
|
Copyright (C) 2011 Cyan Worlds, 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7 |
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or |
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||||
|
(or a modified version of those libraries), |
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||||
|
licensors of this Program grant you additional |
||||||
|
permission to convey the resulting work. Corresponding Source for a |
||||||
|
non-source form of such a combination shall include the source code for |
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||||
|
work. |
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||||
|
or by snail mail at: |
||||||
|
Cyan Worlds, Inc. |
||||||
|
14617 N Newport Hwy |
||||||
|
Mead, WA 99021 |
||||||
|
|
||||||
|
*==LICENSE==*/ |
||||||
|
|
||||||
|
#include "plMoviePlayer.h" |
||||||
|
|
||||||
|
#include "hsConfig.h" |
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
# define VPX_CODEC_DISABLE_COMPAT 1 |
||||||
|
# include <vpx/vpx_decoder.h> |
||||||
|
# include <vpx/vp8dx.h> |
||||||
|
# define iface (vpx_codec_vp9_dx()) |
||||||
|
# include <opus.h> |
||||||
|
|
||||||
|
# define WEBM_CODECID_VP9 "V_VP9" |
||||||
|
# define WEBM_CODECID_OPUS "A_OPUS" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "hsResMgr.h" |
||||||
|
#include "hsTimer.h" |
||||||
|
#include "../plAudio/plWin32VideoSound.h" |
||||||
|
#include "../plGImage/plMipmap.h" |
||||||
|
#include "../pnKeyedObject/plUoid.h" |
||||||
|
#include "../plPipeline/hsGDeviceRef.h" |
||||||
|
#include "../plPipeline/plPlates.h" |
||||||
|
#include "../plResMgr/plLocalization.h" |
||||||
|
#include "../plStatusLog/plStatusLog.h" |
||||||
|
#include "../plFile/plFileUtils.h" |
||||||
|
|
||||||
|
#include "plPlanarImage.h" |
||||||
|
#include "webm/mkvreader.hpp" |
||||||
|
#include "webm/mkvparser.hpp" |
||||||
|
|
||||||
|
#define SAFE_OP(x, err) \ |
||||||
|
{ \
|
||||||
|
Int64 ret = 0; \
|
||||||
|
ret = x; \
|
||||||
|
if (ret < 0) { \
|
||||||
|
hsAssert(false, "failed to " err); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
} |
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class VPX |
||||||
|
{ |
||||||
|
VPX() { } |
||||||
|
|
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
public: |
||||||
|
vpx_codec_ctx_t codec; |
||||||
|
|
||||||
|
~VPX() |
||||||
|
{ |
||||||
|
if (vpx_codec_destroy(&codec)) |
||||||
|
hsAssert(false, vpx_codec_error_detail(&codec)); |
||||||
|
} |
||||||
|
|
||||||
|
static VPX* Create() |
||||||
|
{ |
||||||
|
VPX* instance = new VPX; |
||||||
|
if (vpx_codec_dec_init(&instance->codec, iface, nullptr, 0)) { |
||||||
|
hsAssert(false, vpx_codec_error_detail(&instance->codec)); |
||||||
|
delete instance; |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
return instance; |
||||||
|
} |
||||||
|
|
||||||
|
vpx_image_t* Decode(UInt8* buf, UInt32 size) |
||||||
|
{ |
||||||
|
if (vpx_codec_decode(&codec, buf, size, nullptr, 0) != VPX_CODEC_OK) { |
||||||
|
const char* detail = vpx_codec_error_detail(&codec); |
||||||
|
hsAssert(false, detail ? detail : "unspecified decode error"); |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
vpx_codec_iter_t iter = nullptr; |
||||||
|
// ASSUMPTION: only one image per frame
|
||||||
|
// if this proves false, move decoder function into IProcessVideoFrame
|
||||||
|
return vpx_codec_get_frame(&codec, &iter); |
||||||
|
} |
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class TrackMgr |
||||||
|
{ |
||||||
|
protected: |
||||||
|
const mkvparser::Track* fTrack; |
||||||
|
const mkvparser::BlockEntry* fCurrentBlock; |
||||||
|
Int32 fStatus; |
||||||
|
|
||||||
|
public: |
||||||
|
TrackMgr(const mkvparser::Track* track) : fTrack(track), fCurrentBlock(nullptr), fStatus(0) { } |
||||||
|
|
||||||
|
const mkvparser::Track* GetTrack() { return fTrack; } |
||||||
|
|
||||||
|
bool GetFrames(mkvparser::MkvReader* reader, Int64 movieTimeNs, std::vector<blkbuf_t>& frames) |
||||||
|
{ |
||||||
|
// If we have no block yet, grab the first one
|
||||||
|
if (!fCurrentBlock) |
||||||
|
fStatus = fTrack->GetFirst(fCurrentBlock); |
||||||
|
|
||||||
|
// Continue through the blocks until our current movie time
|
||||||
|
while (fCurrentBlock && fStatus == 0) { |
||||||
|
const mkvparser::Block* block = fCurrentBlock->GetBlock(); |
||||||
|
Int64 time = block->GetTime(fCurrentBlock->GetCluster()) - fTrack->GetCodecDelay(); |
||||||
|
if (time <= movieTimeNs) { |
||||||
|
// We want to play this block, add it to the frames buffer
|
||||||
|
frames.reserve(frames.size() + block->GetFrameCount()); |
||||||
|
for (Int32 i = 0; i < block->GetFrameCount(); i++) { |
||||||
|
const mkvparser::Block::Frame data = block->GetFrame(i); |
||||||
|
UInt8* buf = new UInt8[data.len]; |
||||||
|
data.Read(reader, buf); |
||||||
|
frames.push_back(std::make_pair(std::auto_ptr<UInt8>(buf), static_cast<Int32>(data.len))); |
||||||
|
} |
||||||
|
fStatus = fTrack->GetNext(fCurrentBlock, fCurrentBlock); |
||||||
|
} else { |
||||||
|
// We've got all frames that have to play... come back for more later!
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; // No more blocks... We're done!
|
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
plMoviePlayer::plMoviePlayer() |
||||||
|
: fPlate(nullptr), |
||||||
|
fTexture(nullptr), |
||||||
|
fReader(nullptr), |
||||||
|
fMovieTime(0), |
||||||
|
fLastFrameTime(0), |
||||||
|
fPosition(hsPoint2()), |
||||||
|
fPlaying(false), |
||||||
|
fPaused(false), |
||||||
|
fMoviePath(nullptr) |
||||||
|
{ |
||||||
|
fScale.Set(1.0f, 1.0f); |
||||||
|
} |
||||||
|
|
||||||
|
plMoviePlayer::~plMoviePlayer() |
||||||
|
{ |
||||||
|
if (fPlate) |
||||||
|
// The plPlate owns the Mipmap Texture, so it destroys it for us
|
||||||
|
plPlateManager::Instance().DestroyPlate(fPlate); |
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
if (fReader) { |
||||||
|
fReader->Close(); |
||||||
|
delete fReader; |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::IOpenMovie() |
||||||
|
{ |
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
if (!plFileUtils::FileExists(fMoviePath)) { |
||||||
|
plStatusLog::AddLineS("movie.log", "%s: Tried to play a movie that doesn't exist.", fMoviePath); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// open the movie with libwebm
|
||||||
|
fReader = new mkvparser::MkvReader; |
||||||
|
SAFE_OP(fReader->Open(fMoviePath), "open movie"); |
||||||
|
|
||||||
|
// opens the segment
|
||||||
|
// it contains everything you ever want to know about the movie
|
||||||
|
long long pos = 0; |
||||||
|
mkvparser::EBMLHeader ebmlHeader; |
||||||
|
SAFE_OP(ebmlHeader.Parse(fReader, pos), "read mkv header"); |
||||||
|
mkvparser::Segment* seg; |
||||||
|
SAFE_OP(mkvparser::Segment::CreateInstance(fReader, pos, seg), "get segment info"); |
||||||
|
SAFE_OP(seg->Load(), "load segment from webm"); |
||||||
|
fSegment.reset(seg); |
||||||
|
|
||||||
|
// Use first tracks unless another one matches the current game language
|
||||||
|
const mkvparser::Tracks* tracks = fSegment->GetTracks(); |
||||||
|
for (UInt32 i = 0; i < tracks->GetTracksCount(); ++i) { |
||||||
|
const mkvparser::Track* track = tracks->GetTrackByIndex(i); |
||||||
|
if (!track) |
||||||
|
continue; |
||||||
|
|
||||||
|
switch (track->GetType()) { |
||||||
|
case mkvparser::Track::kAudio: |
||||||
|
if (!fAudioTrack.get() || ICheckLanguage(track)) |
||||||
|
fAudioTrack.reset(new TrackMgr(track)); |
||||||
|
break; |
||||||
|
case mkvparser::Track::kVideo: |
||||||
|
if (!fVideoTrack.get() || ICheckLanguage(track)) |
||||||
|
fVideoTrack.reset(new TrackMgr(track)); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
#else |
||||||
|
return false; |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::ILoadAudio() |
||||||
|
{ |
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
// Fetch audio track information
|
||||||
|
if (!fAudioTrack.get()) |
||||||
|
return false; |
||||||
|
const mkvparser::AudioTrack* audio = static_cast<const mkvparser::AudioTrack*>(fAudioTrack->GetTrack()); |
||||||
|
plWAVHeader header; |
||||||
|
header.fFormatTag = plWAVHeader::kPCMFormatTag; |
||||||
|
header.fNumChannels = audio->GetChannels(); |
||||||
|
header.fBitsPerSample = audio->GetBitDepth() == 8 ? 8 : 16; |
||||||
|
header.fNumSamplesPerSec = 48000; // OPUS specs say we shall always decode at 48kHz
|
||||||
|
header.fBlockAlign = header.fNumChannels * header.fBitsPerSample / 8; |
||||||
|
header.fAvgBytesPerSec = header.fNumSamplesPerSec * header.fBlockAlign; |
||||||
|
fAudioSound.reset(new plWin32VideoSound(header)); |
||||||
|
|
||||||
|
// Initialize Opus
|
||||||
|
if (strncmp(audio->GetCodecId(), WEBM_CODECID_OPUS, arrsize(WEBM_CODECID_OPUS)) != 0) { |
||||||
|
plStatusLog::AddLineS("movie.log", "%s: Not an Opus audio track!", fMoviePath); |
||||||
|
return false; |
||||||
|
} |
||||||
|
int error; |
||||||
|
OpusDecoder* opus = opus_decoder_create(48000, audio->GetChannels(), &error); |
||||||
|
if (error != OPUS_OK) |
||||||
|
hsAssert(false, "Error occured initalizing opus"); |
||||||
|
|
||||||
|
// Decode audio track
|
||||||
|
std::vector<blkbuf_t> frames; |
||||||
|
fAudioTrack->GetFrames(fReader, fSegment->GetDuration(), frames); |
||||||
|
static const int maxFrameSize = 5760; // for max packet duration at 48kHz
|
||||||
|
std::vector<Int16> decoded; |
||||||
|
decoded.reserve(frames.size() * audio->GetChannels() * maxFrameSize); |
||||||
|
|
||||||
|
Int16* frameData = new Int16[maxFrameSize * audio->GetChannels()]; |
||||||
|
for (std::vector<blkbuf_t>::iterator& frame = frames.begin(); frame != frames.end(); frame++) { |
||||||
|
const std::auto_ptr<UInt8>& buf = frame->first; |
||||||
|
Int32 size = frame->second; |
||||||
|
|
||||||
|
int samples = opus_decode(opus, buf.get(), size, frameData, maxFrameSize, 0); |
||||||
|
if (samples < 0) |
||||||
|
hsAssert(false, "opus error"); |
||||||
|
for (size_t i = 0; i < samples * audio->GetChannels(); i++) |
||||||
|
decoded.push_back(frameData[i]); |
||||||
|
} |
||||||
|
delete[] frameData; |
||||||
|
|
||||||
|
fAudioSound->FillSoundBuffer(reinterpret_cast<UInt8*>(decoded.data()), decoded.size() * sizeof(Int16)); |
||||||
|
opus_decoder_destroy(opus); |
||||||
|
return true; |
||||||
|
#else |
||||||
|
return false; |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::ICheckLanguage(const mkvparser::Track* track) |
||||||
|
{ |
||||||
|
std::set<std::string> codes = plLocalization::GetLanguageCodes(plLocalization::GetLanguage()); |
||||||
|
if (codes.find(track->GetLanguage()) != codes.end()) |
||||||
|
return true; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void plMoviePlayer::IProcessVideoFrame(const std::vector<blkbuf_t>& frames) |
||||||
|
{ |
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
vpx_image_t* img = nullptr; |
||||||
|
|
||||||
|
// We have to decode all the frames, but we only want to display the most recent one to the user.
|
||||||
|
for (std::vector<blkbuf_t>::const_iterator frame = frames.begin(); frame != frames.end(); frame++) { |
||||||
|
const std::auto_ptr<UInt8>& buf = frame->first; |
||||||
|
UInt32 size = static_cast<UInt32>(frame->second); |
||||||
|
img = fVpx->Decode(buf.get(), size); |
||||||
|
} |
||||||
|
|
||||||
|
if (img) { |
||||||
|
// According to VideoLAN[1], I420 is the most common image format in videos. I am inclined to believe this as our
|
||||||
|
// attemps to convert the common Uru videos use I420 image data. So, as a shortcut, we will only implement that format.
|
||||||
|
// If for some reason we need other formats, please, be my guest!
|
||||||
|
// [1] = http://wiki.videolan.org/YUV#YUV_4:2:0_.28I420.2FJ420.2FYV12.29
|
||||||
|
switch (img->fmt) { |
||||||
|
case VPX_IMG_FMT_I420: |
||||||
|
plPlanarImage::Yuv420ToRgba(img->d_w, img->d_h, reinterpret_cast<const Int32*>(img->stride), img->planes, reinterpret_cast<UInt8*>(fTexture->GetImage())); |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
hsAssert(false, "image format"); |
||||||
|
} |
||||||
|
|
||||||
|
// Flush new data to the device
|
||||||
|
if (fTexture->GetDeviceRef()) |
||||||
|
fTexture->GetDeviceRef()->SetDirty(true); |
||||||
|
fPlate->SetVisible(true); |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::Start() |
||||||
|
{ |
||||||
|
if (fPlaying) |
||||||
|
return false; |
||||||
|
|
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
if (!IOpenMovie()) |
||||||
|
return false; |
||||||
|
hsAssert(fVideoTrack, "nil video track -- expect bad things to happen!"); |
||||||
|
|
||||||
|
// Initialize VPX
|
||||||
|
const mkvparser::VideoTrack* video = static_cast<const mkvparser::VideoTrack*>(fVideoTrack->GetTrack()); |
||||||
|
if (strncmp(video->GetCodecId(), WEBM_CODECID_VP9, arrsize(WEBM_CODECID_VP9)) != 0) { |
||||||
|
plStatusLog::AddLineS("movie.log", "%s: Not a VP9 video track!", fMoviePath); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (VPX* vpx = VPX::Create()) |
||||||
|
fVpx.reset(vpx); |
||||||
|
else |
||||||
|
return false; |
||||||
|
|
||||||
|
// Decode the audio track and load it into a sound buffer
|
||||||
|
if (!ILoadAudio()) |
||||||
|
return false; |
||||||
|
|
||||||
|
fLastFrameTime = static_cast<Int64>(hsTimer::GetMilliSeconds()); |
||||||
|
fAudioSound->Play(); |
||||||
|
fPlaying = true; |
||||||
|
|
||||||
|
return true; |
||||||
|
#else |
||||||
|
return false; |
||||||
|
#endif // MOVIE_AVAILABLE
|
||||||
|
} |
||||||
|
|
||||||
|
void plMoviePlayer::IInitPlate(UInt32 width, UInt32 height) |
||||||
|
{ |
||||||
|
// Need to figure out scaling based on pipe size.
|
||||||
|
plPlateManager& plateMgr = plPlateManager::Instance(); |
||||||
|
float plateWidth = width * fScale.fX; |
||||||
|
float plateHeight = height * fScale.fY; |
||||||
|
if (plateWidth > plateMgr.GetPipeWidth() || plateHeight > plateMgr.GetPipeHeight()) { |
||||||
|
float scale = std::min(plateMgr.GetPipeWidth() / plateWidth, plateMgr.GetPipeHeight() / plateHeight); |
||||||
|
plateWidth *= scale; |
||||||
|
plateHeight *= scale; |
||||||
|
} |
||||||
|
plateMgr.CreatePlate(&fPlate, fPosition.fX, fPosition.fY, 0, 0); |
||||||
|
plateMgr.SetPlatePixelSize(fPlate, plateWidth, plateHeight); |
||||||
|
fTexture = fPlate->CreateMaterial(width, height, false); |
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::NextFrame() |
||||||
|
{ |
||||||
|
if (!fPlaying) |
||||||
|
return false; |
||||||
|
|
||||||
|
Int64 frameTime = static_cast<Int64>(hsTimer::GetMilliSeconds()); |
||||||
|
Int64 frameTimeDelta = frameTime - fLastFrameTime; |
||||||
|
fLastFrameTime = frameTime; |
||||||
|
|
||||||
|
if (fPaused) |
||||||
|
return true; |
||||||
|
|
||||||
|
#ifdef PLASMA_USE_WEBM |
||||||
|
// Get our current timecode
|
||||||
|
fMovieTime += frameTimeDelta; |
||||||
|
|
||||||
|
std::vector<blkbuf_t> video; |
||||||
|
if (fVideoTrack.get() != nullptr || !fVideoTrack->GetFrames(fReader, fMovieTime * 1000000, video)) { |
||||||
|
Stop(); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// If the pipeline's device was invalidated, the plate will be invalid. Recreate now.
|
||||||
|
if (!fPlate) { |
||||||
|
const mkvparser::VideoTrack* vt = static_cast<const mkvparser::VideoTrack*>(fVideoTrack->GetTrack()); |
||||||
|
IInitPlate(static_cast<UInt32>(vt->GetWidth()), static_cast<UInt32>(vt->GetHeight())); |
||||||
|
hsAssert(fPlate, "failed to init plMoviePlayer plate -- bad things will happen!"); |
||||||
|
} |
||||||
|
|
||||||
|
// Show our mess
|
||||||
|
IProcessVideoFrame(video); |
||||||
|
fAudioSound->RefreshVolume(); |
||||||
|
|
||||||
|
return true; |
||||||
|
#else |
||||||
|
return false; |
||||||
|
#endif // MOVIE_AVAILABLE
|
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::Pause(bool on) |
||||||
|
{ |
||||||
|
if (!fPlaying) |
||||||
|
return false; |
||||||
|
|
||||||
|
fAudioSound->Pause(on); |
||||||
|
fPaused = on; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool plMoviePlayer::Stop() |
||||||
|
{ |
||||||
|
fPlaying = false; |
||||||
|
if (fAudioSound.get() != nullptr) |
||||||
|
fAudioSound->Stop(); |
||||||
|
if (fPlate) |
||||||
|
fPlate->SetVisible(false); |
||||||
|
|
||||||
|
for (std::vector<plMessage*>::iterator cb = fCallbacks.begin(); cb != fCallbacks.end(); cb++) |
||||||
|
(*cb)->Send(); |
||||||
|
fCallbacks.clear(); |
||||||
|
return true; |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools |
||||||
|
Copyright (C) 2011 Cyan Worlds, 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7 |
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or |
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||||
|
(or a modified version of those libraries), |
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||||
|
licensors of this Program grant you additional |
||||||
|
permission to convey the resulting work. Corresponding Source for a |
||||||
|
non-source form of such a combination shall include the source code for |
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||||
|
work. |
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||||
|
or by snail mail at: |
||||||
|
Cyan Worlds, Inc. |
||||||
|
14617 N Newport Hwy |
||||||
|
Mead, WA 99021 |
||||||
|
|
||||||
|
*==LICENSE==*/ |
||||||
|
|
||||||
|
#ifndef _plMoviePlayer_inc |
||||||
|
#define _plMoviePlayer_inc |
||||||
|
|
||||||
|
#include "HeadSpin.h" |
||||||
|
#include "hsPoint2.h" |
||||||
|
#include "hsColorRGBA.h" |
||||||
|
#include "../plMessage/plMovieMsg.h" |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <vector> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
namespace mkvparser |
||||||
|
{ |
||||||
|
class BlockEntry; |
||||||
|
class MkvReader; |
||||||
|
class Segment; |
||||||
|
class Track; |
||||||
|
} |
||||||
|
|
||||||
|
typedef std::pair<std::auto_ptr<UInt8>, UInt32> blkbuf_t; |
||||||
|
|
||||||
|
class plMoviePlayer |
||||||
|
{ |
||||||
|
protected: |
||||||
|
class plPlate* fPlate; |
||||||
|
class plMipmap* fTexture; |
||||||
|
|
||||||
|
mkvparser::MkvReader* fReader; |
||||||
|
std::auto_ptr<mkvparser::Segment> fSegment; |
||||||
|
std::auto_ptr<class TrackMgr> fAudioTrack, fVideoTrack; // TODO: vector of tracks?
|
||||||
|
std::auto_ptr<class plWin32VideoSound> fAudioSound; |
||||||
|
std::auto_ptr<class VPX> fVpx; |
||||||
|
|
||||||
|
UInt64 fMovieTime, fLastFrameTime; // in ms
|
||||||
|
hsPoint2 fPosition, fScale; |
||||||
|
const char *fMoviePath; |
||||||
|
|
||||||
|
bool fPlaying; |
||||||
|
bool fPaused; |
||||||
|
|
||||||
|
void IInitPlate(UInt32 width, UInt32 height); |
||||||
|
|
||||||
|
bool IOpenMovie(); |
||||||
|
bool ILoadAudio(); |
||||||
|
bool ICheckLanguage(const mkvparser::Track* track); |
||||||
|
void IProcessVideoFrame(const std::vector<blkbuf_t>& frames); |
||||||
|
|
||||||
|
public: |
||||||
|
plMoviePlayer(); |
||||||
|
~plMoviePlayer(); |
||||||
|
|
||||||
|
bool Start(); |
||||||
|
bool Pause(bool on); |
||||||
|
bool Stop(); |
||||||
|
bool NextFrame(); |
||||||
|
|
||||||
|
void AddCallback(plMessage* msg) { hsRefCnt_SafeRef(msg); fCallbacks.push_back(msg); } |
||||||
|
UInt32 GetNumCallbacks() const { return 0; } |
||||||
|
plMessage* GetCallback(int i) const { return nullptr; } |
||||||
|
|
||||||
|
const char *GetFileName() const { return fMoviePath; } |
||||||
|
void SetFileName(const char* filename) { fMoviePath = filename; } |
||||||
|
|
||||||
|
void SetColor(const hsColorRGBA& c) { } |
||||||
|
const hsColorRGBA GetColor() const { return hsColorRGBA(); } |
||||||
|
|
||||||
|
/** The volume is handled by the options menu slider, as of now. */ |
||||||
|
void SetVolume(float v) { } |
||||||
|
|
||||||
|
hsPoint2 GetPosition() const { return fPosition; } |
||||||
|
void SetPosition(const hsPoint2& pos) { fPosition = pos; } |
||||||
|
void SetPosition(float x, float y) { fPosition.Set(x, y); } |
||||||
|
|
||||||
|
hsPoint2 GetScale() const { return fScale; } |
||||||
|
void SetScale(const hsPoint2& scale) { fScale = scale; } |
||||||
|
void SetScale(float x, float y) { fScale.Set(x, y); } |
||||||
|
|
||||||
|
void SetFadeFromTime(float secs) { } |
||||||
|
void SetFadeFromColor(hsColorRGBA c) { } |
||||||
|
|
||||||
|
void SetFadeToTime(float secs) { } |
||||||
|
void SetFadeToColor(hsColorRGBA c) { } |
||||||
|
|
||||||
|
private: |
||||||
|
std::vector<plMessage*> fCallbacks; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // _plMoviePlayer_inc
|
@ -0,0 +1,97 @@ |
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools |
||||||
|
Copyright (C) 2011 Cyan Worlds, 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7 |
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or |
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||||
|
(or a modified version of those libraries), |
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||||
|
licensors of this Program grant you additional |
||||||
|
permission to convey the resulting work. Corresponding Source for a |
||||||
|
non-source form of such a combination shall include the source code for |
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||||
|
work. |
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||||
|
or by snail mail at: |
||||||
|
Cyan Worlds, Inc. |
||||||
|
14617 N Newport Hwy |
||||||
|
Mead, WA 99021 |
||||||
|
|
||||||
|
*==LICENSE==*/ |
||||||
|
|
||||||
|
#include "plPlanarImage.h" |
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static UInt8 Clip(UInt32 val) { |
||||||
|
if (val < 0) { |
||||||
|
return 0; |
||||||
|
} else if (val > 255) { |
||||||
|
return 255; |
||||||
|
} |
||||||
|
return static_cast<UInt8>(val); |
||||||
|
} |
||||||
|
|
||||||
|
#define YG 74 /* static_cast<int8>(1.164 * 64 + 0.5) */ |
||||||
|
|
||||||
|
#define UB 127 /* min(63,static_cast<int8>(2.018 * 64)) */ |
||||||
|
#define UG -25 /* static_cast<int8>(-0.391 * 64 - 0.5) */ |
||||||
|
#define UR 0 |
||||||
|
|
||||||
|
#define VB 0 |
||||||
|
#define VG -52 /* static_cast<int8>(-0.813 * 64 - 0.5) */ |
||||||
|
#define VR 102 /* static_cast<int8>(1.596 * 64 + 0.5) */ |
||||||
|
|
||||||
|
// Bias
|
||||||
|
#define BB UB * 128 + VB * 128 |
||||||
|
#define BG UG * 128 + VG * 128 |
||||||
|
#define BR UR * 128 + VR * 128 |
||||||
|
|
||||||
|
void plPlanarImage::Yuv420ToRgba(UInt32 w, UInt32 h, const Int32* stride, UInt8** planes, UInt8* const dest) |
||||||
|
{ |
||||||
|
const UInt8* y_src = planes[0]; |
||||||
|
const UInt8* u_src = planes[1]; |
||||||
|
const UInt8* v_src = planes[2]; |
||||||
|
|
||||||
|
for (UInt32 i = 0; i < h; ++i) |
||||||
|
{ |
||||||
|
for (UInt32 j = 0; j < w; ++j) |
||||||
|
{ |
||||||
|
size_t y_idx = stride[0] * i + j; |
||||||
|
size_t u_idx = stride[1] * (i/2) + (j/2); |
||||||
|
size_t v_idx = stride[2] * (i/2) + (j/2); |
||||||
|
size_t dest_idx = w * i + j; |
||||||
|
|
||||||
|
UInt32 y = static_cast<UInt32>(y_src[y_idx]); |
||||||
|
UInt32 u = static_cast<UInt32>(u_src[u_idx]); |
||||||
|
UInt32 v = static_cast<UInt32>(v_src[v_idx]); |
||||||
|
UInt32 y1 = (y - 16) * YG; |
||||||
|
|
||||||
|
dest[dest_idx*4+0] = Clip(((u * UB + v * VB) - (BB) + y1) >> 6); |
||||||
|
dest[dest_idx*4+1] = Clip(((u * UG + v * VG) - (BG) + y1) >> 6); |
||||||
|
dest[dest_idx*4+2] = Clip(((u * UR + v * VR) - (BR) + y1) >> 6); |
||||||
|
dest[dest_idx*4+3] = 0xff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools |
||||||
|
Copyright (C) 2011 Cyan Worlds, 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7 |
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or |
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||||
|
(or a modified version of those libraries), |
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||||
|
licensors of this Program grant you additional |
||||||
|
permission to convey the resulting work. Corresponding Source for a |
||||||
|
non-source form of such a combination shall include the source code for |
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||||
|
work. |
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||||
|
or by snail mail at: |
||||||
|
Cyan Worlds, Inc. |
||||||
|
14617 N Newport Hwy |
||||||
|
Mead, WA 99021 |
||||||
|
|
||||||
|
*==LICENSE==*/ |
||||||
|
|
||||||
|
#ifndef _plPlanarImage_inc |
||||||
|
#define _plPlanarImage_inc |
||||||
|
|
||||||
|
#include "HeadSpin.h" |
||||||
|
|
||||||
|
namespace plPlanarImage |
||||||
|
{ |
||||||
|
void Yuv420ToRgba(UInt32 w, UInt32 h, const Int32* stride, UInt8** planes, UInt8* const dest); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // _plPlanarImage_inc
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,945 @@ |
|||||||
|
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the LICENSE file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
|
#ifndef MKVPARSER_HPP |
||||||
|
#define MKVPARSER_HPP |
||||||
|
|
||||||
|
#include <cstdlib> |
||||||
|
#include <cstdio> |
||||||
|
#include <cstddef> |
||||||
|
|
||||||
|
namespace mkvparser { |
||||||
|
|
||||||
|
const int E_FILE_FORMAT_INVALID = -2; |
||||||
|
const int E_BUFFER_NOT_FULL = -3; |
||||||
|
|
||||||
|
class IMkvReader { |
||||||
|
public: |
||||||
|
virtual int Read(long long pos, long len, unsigned char* buf) = 0; |
||||||
|
virtual int Length(long long* total, long long* available) = 0; |
||||||
|
|
||||||
|
protected: |
||||||
|
virtual ~IMkvReader(); |
||||||
|
}; |
||||||
|
|
||||||
|
long long GetUIntLength(IMkvReader*, long long, long&); |
||||||
|
long long ReadUInt(IMkvReader*, long long, long&); |
||||||
|
long long UnserializeUInt(IMkvReader*, long long pos, long long size); |
||||||
|
|
||||||
|
long UnserializeFloat(IMkvReader*, long long pos, long long size, double&); |
||||||
|
long UnserializeInt(IMkvReader*, long long pos, long len, long long& result); |
||||||
|
|
||||||
|
long UnserializeString(IMkvReader*, long long pos, long long size, char*& str); |
||||||
|
|
||||||
|
long ParseElementHeader(IMkvReader* pReader, |
||||||
|
long long& pos, // consume id and size fields
|
||||||
|
long long stop, // if you know size of element's parent
|
||||||
|
long long& id, long long& size); |
||||||
|
|
||||||
|
bool Match(IMkvReader*, long long&, unsigned long, long long&); |
||||||
|
bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&); |
||||||
|
|
||||||
|
void GetVersion(int& major, int& minor, int& build, int& revision); |
||||||
|
|
||||||
|
struct EBMLHeader { |
||||||
|
EBMLHeader(); |
||||||
|
~EBMLHeader(); |
||||||
|
long long m_version; |
||||||
|
long long m_readVersion; |
||||||
|
long long m_maxIdLength; |
||||||
|
long long m_maxSizeLength; |
||||||
|
char* m_docType; |
||||||
|
long long m_docTypeVersion; |
||||||
|
long long m_docTypeReadVersion; |
||||||
|
|
||||||
|
long long Parse(IMkvReader*, long long&); |
||||||
|
void Init(); |
||||||
|
}; |
||||||
|
|
||||||
|
class Segment; |
||||||
|
class Track; |
||||||
|
class Cluster; |
||||||
|
|
||||||
|
class Block { |
||||||
|
Block(const Block&); |
||||||
|
Block& operator=(const Block&); |
||||||
|
|
||||||
|
public: |
||||||
|
const long long m_start; |
||||||
|
const long long m_size; |
||||||
|
|
||||||
|
Block(long long start, long long size, long long discard_padding); |
||||||
|
~Block(); |
||||||
|
|
||||||
|
long Parse(const Cluster*); |
||||||
|
|
||||||
|
long long GetTrackNumber() const; |
||||||
|
long long GetTimeCode(const Cluster*) const; // absolute, but not scaled
|
||||||
|
long long GetTime(const Cluster*) const; // absolute, and scaled (ns)
|
||||||
|
bool IsKey() const; |
||||||
|
void SetKey(bool); |
||||||
|
bool IsInvisible() const; |
||||||
|
|
||||||
|
enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml }; |
||||||
|
Lacing GetLacing() const; |
||||||
|
|
||||||
|
int GetFrameCount() const; // to index frames: [0, count)
|
||||||
|
|
||||||
|
struct Frame { |
||||||
|
long long pos; // absolute offset
|
||||||
|
long len; |
||||||
|
|
||||||
|
long Read(IMkvReader*, unsigned char*) const; |
||||||
|
}; |
||||||
|
|
||||||
|
const Frame& GetFrame(int frame_index) const; |
||||||
|
|
||||||
|
long long GetDiscardPadding() const; |
||||||
|
|
||||||
|
private: |
||||||
|
long long m_track; // Track::Number()
|
||||||
|
short m_timecode; // relative to cluster
|
||||||
|
unsigned char m_flags; |
||||||
|
|
||||||
|
Frame* m_frames; |
||||||
|
int m_frame_count; |
||||||
|
|
||||||
|
protected: |
||||||
|
const long long m_discard_padding; |
||||||
|
}; |
||||||
|
|
||||||
|
class BlockEntry { |
||||||
|
BlockEntry(const BlockEntry&); |
||||||
|
BlockEntry& operator=(const BlockEntry&); |
||||||
|
|
||||||
|
protected: |
||||||
|
BlockEntry(Cluster*, long index); |
||||||
|
|
||||||
|
public: |
||||||
|
virtual ~BlockEntry(); |
||||||
|
|
||||||
|
bool EOS() const; |
||||||
|
const Cluster* GetCluster() const; |
||||||
|
long GetIndex() const; |
||||||
|
virtual const Block* GetBlock() const = 0; |
||||||
|
|
||||||
|
enum Kind { kBlockEOS, kBlockSimple, kBlockGroup }; |
||||||
|
virtual Kind GetKind() const = 0; |
||||||
|
|
||||||
|
protected: |
||||||
|
Cluster* const m_pCluster; |
||||||
|
const long m_index; |
||||||
|
}; |
||||||
|
|
||||||
|
class SimpleBlock : public BlockEntry { |
||||||
|
SimpleBlock(const SimpleBlock&); |
||||||
|
SimpleBlock& operator=(const SimpleBlock&); |
||||||
|
|
||||||
|
public: |
||||||
|
SimpleBlock(Cluster*, long index, long long start, long long size); |
||||||
|
long Parse(); |
||||||
|
|
||||||
|
Kind GetKind() const; |
||||||
|
const Block* GetBlock() const; |
||||||
|
|
||||||
|
protected: |
||||||
|
Block m_block; |
||||||
|
}; |
||||||
|
|
||||||
|
class BlockGroup : public BlockEntry { |
||||||
|
BlockGroup(const BlockGroup&); |
||||||
|
BlockGroup& operator=(const BlockGroup&); |
||||||
|
|
||||||
|
public: |
||||||
|
BlockGroup(Cluster*, long index, |
||||||
|
long long block_start, // absolute pos of block's payload
|
||||||
|
long long block_size, // size of block's payload
|
||||||
|
long long prev, long long next, long long duration, |
||||||
|
long long discard_padding); |
||||||
|
|
||||||
|
long Parse(); |
||||||
|
|
||||||
|
Kind GetKind() const; |
||||||
|
const Block* GetBlock() const; |
||||||
|
|
||||||
|
long long GetPrevTimeCode() const; // relative to block's time
|
||||||
|
long long GetNextTimeCode() const; // as above
|
||||||
|
long long GetDurationTimeCode() const; |
||||||
|
|
||||||
|
private: |
||||||
|
Block m_block; |
||||||
|
const long long m_prev; |
||||||
|
const long long m_next; |
||||||
|
const long long m_duration; |
||||||
|
}; |
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// ContentEncoding element
|
||||||
|
// Elements used to describe if the track data has been encrypted or
|
||||||
|
// compressed with zlib or header stripping.
|
||||||
|
class ContentEncoding { |
||||||
|
public: |
||||||
|
enum { kCTR = 1 }; |
||||||
|
|
||||||
|
ContentEncoding(); |
||||||
|
~ContentEncoding(); |
||||||
|
|
||||||
|
// ContentCompression element names
|
||||||
|
struct ContentCompression { |
||||||
|
ContentCompression(); |
||||||
|
~ContentCompression(); |
||||||
|
|
||||||
|
unsigned long long algo; |
||||||
|
unsigned char* settings; |
||||||
|
long long settings_len; |
||||||
|
}; |
||||||
|
|
||||||
|
// ContentEncAESSettings element names
|
||||||
|
struct ContentEncAESSettings { |
||||||
|
ContentEncAESSettings() : cipher_mode(kCTR) {} |
||||||
|
~ContentEncAESSettings() {} |
||||||
|
|
||||||
|
unsigned long long cipher_mode; |
||||||
|
}; |
||||||
|
|
||||||
|
// ContentEncryption element names
|
||||||
|
struct ContentEncryption { |
||||||
|
ContentEncryption(); |
||||||
|
~ContentEncryption(); |
||||||
|
|
||||||
|
unsigned long long algo; |
||||||
|
unsigned char* key_id; |
||||||
|
long long key_id_len; |
||||||
|
unsigned char* signature; |
||||||
|
long long signature_len; |
||||||
|
unsigned char* sig_key_id; |
||||||
|
long long sig_key_id_len; |
||||||
|
unsigned long long sig_algo; |
||||||
|
unsigned long long sig_hash_algo; |
||||||
|
|
||||||
|
ContentEncAESSettings aes_settings; |
||||||
|
}; |
||||||
|
|
||||||
|
// Returns ContentCompression represented by |idx|. Returns NULL if |idx|
|
||||||
|
// is out of bounds.
|
||||||
|
const ContentCompression* GetCompressionByIndex(unsigned long idx) const; |
||||||
|
|
||||||
|
// Returns number of ContentCompression elements in this ContentEncoding
|
||||||
|
// element.
|
||||||
|
unsigned long GetCompressionCount() const; |
||||||
|
|
||||||
|
// Parses the ContentCompression element from |pReader|. |start| is the
|
||||||
|
// starting offset of the ContentCompression payload. |size| is the size in
|
||||||
|
// bytes of the ContentCompression payload. |compression| is where the parsed
|
||||||
|
// values will be stored.
|
||||||
|
long ParseCompressionEntry(long long start, long long size, |
||||||
|
IMkvReader* pReader, |
||||||
|
ContentCompression* compression); |
||||||
|
|
||||||
|
// Returns ContentEncryption represented by |idx|. Returns NULL if |idx|
|
||||||
|
// is out of bounds.
|
||||||
|
const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const; |
||||||
|
|
||||||
|
// Returns number of ContentEncryption elements in this ContentEncoding
|
||||||
|
// element.
|
||||||
|
unsigned long GetEncryptionCount() const; |
||||||
|
|
||||||
|
// Parses the ContentEncAESSettings element from |pReader|. |start| is the
|
||||||
|
// starting offset of the ContentEncAESSettings payload. |size| is the
|
||||||
|
// size in bytes of the ContentEncAESSettings payload. |encryption| is
|
||||||
|
// where the parsed values will be stored.
|
||||||
|
long ParseContentEncAESSettingsEntry(long long start, long long size, |
||||||
|
IMkvReader* pReader, |
||||||
|
ContentEncAESSettings* aes); |
||||||
|
|
||||||
|
// Parses the ContentEncoding element from |pReader|. |start| is the
|
||||||
|
// starting offset of the ContentEncoding payload. |size| is the size in
|
||||||
|
// bytes of the ContentEncoding payload. Returns true on success.
|
||||||
|
long ParseContentEncodingEntry(long long start, long long size, |
||||||
|
IMkvReader* pReader); |
||||||
|
|
||||||
|
// Parses the ContentEncryption element from |pReader|. |start| is the
|
||||||
|
// starting offset of the ContentEncryption payload. |size| is the size in
|
||||||
|
// bytes of the ContentEncryption payload. |encryption| is where the parsed
|
||||||
|
// values will be stored.
|
||||||
|
long ParseEncryptionEntry(long long start, long long size, |
||||||
|
IMkvReader* pReader, ContentEncryption* encryption); |
||||||
|
|
||||||
|
unsigned long long encoding_order() const { return encoding_order_; } |
||||||
|
unsigned long long encoding_scope() const { return encoding_scope_; } |
||||||
|
unsigned long long encoding_type() const { return encoding_type_; } |
||||||
|
|
||||||
|
private: |
||||||
|
// Member variables for list of ContentCompression elements.
|
||||||
|
ContentCompression** compression_entries_; |
||||||
|
ContentCompression** compression_entries_end_; |
||||||
|
|
||||||
|
// Member variables for list of ContentEncryption elements.
|
||||||
|
ContentEncryption** encryption_entries_; |
||||||
|
ContentEncryption** encryption_entries_end_; |
||||||
|
|
||||||
|
// ContentEncoding element names
|
||||||
|
unsigned long long encoding_order_; |
||||||
|
unsigned long long encoding_scope_; |
||||||
|
unsigned long long encoding_type_; |
||||||
|
|
||||||
|
// LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
|
||||||
|
ContentEncoding(const ContentEncoding&); |
||||||
|
ContentEncoding& operator=(const ContentEncoding&); |
||||||
|
}; |
||||||
|
|
||||||
|
class Track { |
||||||
|
Track(const Track&); |
||||||
|
Track& operator=(const Track&); |
||||||
|
|
||||||
|
public: |
||||||
|
class Info; |
||||||
|
static long Create(Segment*, const Info&, long long element_start, |
||||||
|
long long element_size, Track*&); |
||||||
|
|
||||||
|
enum Type { kVideo = 1, kAudio = 2, kSubtitle = 0x11, kMetadata = 0x21 }; |
||||||
|
|
||||||
|
Segment* const m_pSegment; |
||||||
|
const long long m_element_start; |
||||||
|
const long long m_element_size; |
||||||
|
virtual ~Track(); |
||||||
|
|
||||||
|
long GetType() const; |
||||||
|
long GetNumber() const; |
||||||
|
unsigned long long GetUid() const; |
||||||
|
const char* GetNameAsUTF8() const; |
||||||
|
const char* GetLanguage() const; |
||||||
|
const char* GetCodecNameAsUTF8() const; |
||||||
|
const char* GetCodecId() const; |
||||||
|
const unsigned char* GetCodecPrivate(size_t&) const; |
||||||
|
bool GetLacing() const; |
||||||
|
unsigned long long GetDefaultDuration() const; |
||||||
|
unsigned long long GetCodecDelay() const; |
||||||
|
unsigned long long GetSeekPreRoll() const; |
||||||
|
|
||||||
|
const BlockEntry* GetEOS() const; |
||||||
|
|
||||||
|
struct Settings { |
||||||
|
long long start; |
||||||
|
long long size; |
||||||
|
}; |
||||||
|
|
||||||
|
class Info { |
||||||
|
public: |
||||||
|
Info(); |
||||||
|
~Info(); |
||||||
|
int Copy(Info&) const; |
||||||
|
void Clear(); |
||||||
|
long type; |
||||||
|
long number; |
||||||
|
unsigned long long uid; |
||||||
|
unsigned long long defaultDuration; |
||||||
|
unsigned long long codecDelay; |
||||||
|
unsigned long long seekPreRoll; |
||||||
|
char* nameAsUTF8; |
||||||
|
char* language; |
||||||
|
char* codecId; |
||||||
|
char* codecNameAsUTF8; |
||||||
|
unsigned char* codecPrivate; |
||||||
|
size_t codecPrivateSize; |
||||||
|
bool lacing; |
||||||
|
Settings settings; |
||||||
|
|
||||||
|
private: |
||||||
|
Info(const Info&); |
||||||
|
Info& operator=(const Info&); |
||||||
|
int CopyStr(char* Info::*str, Info&) const; |
||||||
|
}; |
||||||
|
|
||||||
|
long GetFirst(const BlockEntry*&) const; |
||||||
|
long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; |
||||||
|
virtual bool VetEntry(const BlockEntry*) const; |
||||||
|
virtual long Seek(long long time_ns, const BlockEntry*&) const; |
||||||
|
|
||||||
|
const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const; |
||||||
|
unsigned long GetContentEncodingCount() const; |
||||||
|
|
||||||
|
long ParseContentEncodingsEntry(long long start, long long size); |
||||||
|
|
||||||
|
protected: |
||||||
|
Track(Segment*, long long element_start, long long element_size); |
||||||
|
|
||||||
|
Info m_info; |
||||||
|
|
||||||
|
class EOSBlock : public BlockEntry { |
||||||
|
public: |
||||||
|
EOSBlock(); |
||||||
|
|
||||||
|
Kind GetKind() const; |
||||||
|
const Block* GetBlock() const; |
||||||
|
}; |
||||||
|
|
||||||
|
EOSBlock m_eos; |
||||||
|
|
||||||
|
private: |
||||||
|
ContentEncoding** content_encoding_entries_; |
||||||
|
ContentEncoding** content_encoding_entries_end_; |
||||||
|
}; |
||||||
|
|
||||||
|
class VideoTrack : public Track { |
||||||
|
VideoTrack(const VideoTrack&); |
||||||
|
VideoTrack& operator=(const VideoTrack&); |
||||||
|
|
||||||
|
VideoTrack(Segment*, long long element_start, long long element_size); |
||||||
|
|
||||||
|
public: |
||||||
|
static long Parse(Segment*, const Info&, long long element_start, |
||||||
|
long long element_size, VideoTrack*&); |
||||||
|
|
||||||
|
long long GetWidth() const; |
||||||
|
long long GetHeight() const; |
||||||
|
double GetFrameRate() const; |
||||||
|
|
||||||
|
bool VetEntry(const BlockEntry*) const; |
||||||
|
long Seek(long long time_ns, const BlockEntry*&) const; |
||||||
|
|
||||||
|
private: |
||||||
|
long long m_width; |
||||||
|
long long m_height; |
||||||
|
double m_rate; |
||||||
|
}; |
||||||
|
|
||||||
|
class AudioTrack : public Track { |
||||||
|
AudioTrack(const AudioTrack&); |
||||||
|
AudioTrack& operator=(const AudioTrack&); |
||||||
|
|
||||||
|
AudioTrack(Segment*, long long element_start, long long element_size); |
||||||
|
|
||||||
|
public: |
||||||
|
static long Parse(Segment*, const Info&, long long element_start, |
||||||
|
long long element_size, AudioTrack*&); |
||||||
|
|
||||||
|
double GetSamplingRate() const; |
||||||
|
long long GetChannels() const; |
||||||
|
long long GetBitDepth() const; |
||||||
|
|
||||||
|
private: |
||||||
|
double m_rate; |
||||||
|
long long m_channels; |
||||||
|
long long m_bitDepth; |
||||||
|
}; |
||||||
|
|
||||||
|
class Tracks { |
||||||
|
Tracks(const Tracks&); |
||||||
|
Tracks& operator=(const Tracks&); |
||||||
|
|
||||||
|
public: |
||||||
|
Segment* const m_pSegment; |
||||||
|
const long long m_start; |
||||||
|
const long long m_size; |
||||||
|
const long long m_element_start; |
||||||
|
const long long m_element_size; |
||||||
|
|
||||||
|
Tracks(Segment*, long long start, long long size, long long element_start, |
||||||
|
long long element_size); |
||||||
|
|
||||||
|
~Tracks(); |
||||||
|
|
||||||
|
long Parse(); |
||||||
|
|
||||||
|
unsigned long GetTracksCount() const; |
||||||
|
|
||||||
|
const Track* GetTrackByNumber(long tn) const; |
||||||
|
const Track* GetTrackByIndex(unsigned long idx) const; |
||||||
|
|
||||||
|
private: |
||||||
|
Track** m_trackEntries; |
||||||
|
Track** m_trackEntriesEnd; |
||||||
|
|
||||||
|
long ParseTrackEntry(long long payload_start, long long payload_size, |
||||||
|
long long element_start, long long element_size, |
||||||
|
Track*&) const; |
||||||
|
}; |
||||||
|
|
||||||
|
class Chapters { |
||||||
|
Chapters(const Chapters&); |
||||||
|
Chapters& operator=(const Chapters&); |
||||||
|
|
||||||
|
public: |
||||||
|
Segment* const m_pSegment; |
||||||
|
const long long m_start; |
||||||
|
const long long m_size; |
||||||
|
const long long m_element_start; |
||||||
|
const long long m_element_size; |
||||||
|
|
||||||
|
Chapters(Segment*, long long payload_start, long long payload_size, |
||||||
|
long long element_start, long long element_size); |
||||||
|
|
||||||
|
~Chapters(); |
||||||
|
|
||||||
|
long Parse(); |
||||||
|
|
||||||
|
class Atom; |
||||||
|
class Edition; |
||||||
|
|
||||||
|
class Display { |
||||||
|
friend class Atom; |
||||||
|
Display(); |
||||||
|
Display(const Display&); |
||||||
|
~Display(); |
||||||
|
Display& operator=(const Display&); |
||||||
|
|
||||||
|
public: |
||||||
|
const char* GetString() const; |
||||||
|
const char* GetLanguage() const; |
||||||
|
const char* GetCountry() const; |
||||||
|
|
||||||
|
private: |
||||||
|
void Init(); |
||||||
|
void ShallowCopy(Display&) const; |
||||||
|
void Clear(); |
||||||
|
long Parse(IMkvReader*, long long pos, long long size); |
||||||
|
|
||||||
|
char* m_string; |
||||||
|
char* m_language; |
||||||
|
char* m_country; |
||||||
|
}; |
||||||
|
|
||||||
|
class Atom { |
||||||
|
friend class Edition; |
||||||
|
Atom(); |
||||||
|
Atom(const Atom&); |
||||||
|
~Atom(); |
||||||
|
Atom& operator=(const Atom&); |
||||||
|
|
||||||
|
public: |
||||||
|
unsigned long long GetUID() const; |
||||||
|
const char* GetStringUID() const; |
||||||
|
|
||||||
|
long long GetStartTimecode() const; |
||||||
|
long long GetStopTimecode() const; |
||||||
|
|
||||||
|
long long GetStartTime(const Chapters*) const; |
||||||
|
long long GetStopTime(const Chapters*) const; |
||||||
|
|
||||||
|
int GetDisplayCount() const; |
||||||
|
const Display* GetDisplay(int index) const; |
||||||
|
|
||||||
|
private: |
||||||
|
void Init(); |
||||||
|
void ShallowCopy(Atom&) const; |
||||||
|
void Clear(); |
||||||
|
long Parse(IMkvReader*, long long pos, long long size); |
||||||
|
static long long GetTime(const Chapters*, long long timecode); |
||||||
|
|
||||||
|
long ParseDisplay(IMkvReader*, long long pos, long long size); |
||||||
|
bool ExpandDisplaysArray(); |
||||||
|
|
||||||
|
char* m_string_uid; |
||||||
|
unsigned long long m_uid; |
||||||
|
long long m_start_timecode; |
||||||
|
long long m_stop_timecode; |
||||||
|
|
||||||
|
Display* m_displays; |
||||||
|
int m_displays_size; |
||||||
|
int m_displays_count; |
||||||
|
}; |
||||||
|
|
||||||
|
class Edition { |
||||||
|
friend class Chapters; |
||||||
|
Edition(); |
||||||
|
Edition(const Edition&); |
||||||
|
~Edition(); |
||||||
|
Edition& operator=(const Edition&); |
||||||
|
|
||||||
|
public: |
||||||
|
int GetAtomCount() const; |
||||||
|
const Atom* GetAtom(int index) const; |
||||||
|
|
||||||
|
private: |
||||||
|
void Init(); |
||||||
|
void ShallowCopy(Edition&) const; |
||||||
|
void Clear(); |
||||||
|
long Parse(IMkvReader*, long long pos, long long size); |
||||||
|
|
||||||
|
long ParseAtom(IMkvReader*, long long pos, long long size); |
||||||
|
bool ExpandAtomsArray(); |
||||||
|
|
||||||
|
Atom* m_atoms; |
||||||
|
int m_atoms_size; |
||||||
|
int m_atoms_count; |
||||||
|
}; |
||||||
|
|
||||||
|
int GetEditionCount() const; |
||||||
|
const Edition* GetEdition(int index) const; |
||||||
|
|
||||||
|
private: |
||||||
|
long ParseEdition(long long pos, long long size); |
||||||
|
bool ExpandEditionsArray(); |
||||||
|
|
||||||
|
Edition* m_editions; |
||||||
|
int m_editions_size; |
||||||
|
int m_editions_count; |
||||||
|
}; |
||||||
|
|
||||||
|
class SegmentInfo { |
||||||
|
SegmentInfo(const SegmentInfo&); |
||||||
|
SegmentInfo& operator=(const SegmentInfo&); |
||||||
|
|
||||||
|
public: |
||||||
|
Segment* const m_pSegment; |
||||||
|
const long long m_start; |
||||||
|
const long long m_size; |
||||||
|
const long long m_element_start; |
||||||
|
const long long m_element_size; |
||||||
|
|
||||||
|
SegmentInfo(Segment*, long long start, long long size, |
||||||
|
long long element_start, long long element_size); |
||||||
|
|
||||||
|
~SegmentInfo(); |
||||||
|
|
||||||
|
long Parse(); |
||||||
|
|
||||||
|
long long GetTimeCodeScale() const; |
||||||
|
long long GetDuration() const; // scaled
|
||||||
|
const char* GetMuxingAppAsUTF8() const; |
||||||
|
const char* GetWritingAppAsUTF8() const; |
||||||
|
const char* GetTitleAsUTF8() const; |
||||||
|
|
||||||
|
private: |
||||||
|
long long m_timecodeScale; |
||||||
|
double m_duration; |
||||||
|
char* m_pMuxingAppAsUTF8; |
||||||
|
char* m_pWritingAppAsUTF8; |
||||||
|
char* m_pTitleAsUTF8; |
||||||
|
}; |
||||||
|
|
||||||
|
class SeekHead { |
||||||
|
SeekHead(const SeekHead&); |
||||||
|
SeekHead& operator=(const SeekHead&); |
||||||
|
|
||||||
|
public: |
||||||
|
Segment* const m_pSegment; |
||||||
|
const long long m_start; |
||||||
|
const long long m_size; |
||||||
|
const long long m_element_start; |
||||||
|
const long long m_element_size; |
||||||
|
|
||||||
|
SeekHead(Segment*, long long start, long long size, long long element_start, |
||||||
|
long long element_size); |
||||||
|
|
||||||
|
~SeekHead(); |
||||||
|
|
||||||
|
long Parse(); |
||||||
|
|
||||||
|
struct Entry { |
||||||
|
// the SeekHead entry payload
|
||||||
|
long long id; |
||||||
|
long long pos; |
||||||
|
|
||||||
|
// absolute pos of SeekEntry ID
|
||||||
|
long long element_start; |
||||||
|
|
||||||
|
// SeekEntry ID size + size size + payload
|
||||||
|
long long element_size; |
||||||
|
}; |
||||||
|
|
||||||
|
int GetCount() const; |
||||||
|
const Entry* GetEntry(int idx) const; |
||||||
|
|
||||||
|
struct VoidElement { |
||||||
|
// absolute pos of Void ID
|
||||||
|
long long element_start; |
||||||
|
|
||||||
|
// ID size + size size + payload size
|
||||||
|
long long element_size; |
||||||
|
}; |
||||||
|
|
||||||
|
int GetVoidElementCount() const; |
||||||
|
const VoidElement* GetVoidElement(int idx) const; |
||||||
|
|
||||||
|
private: |
||||||
|
Entry* m_entries; |
||||||
|
int m_entry_count; |
||||||
|
|
||||||
|
VoidElement* m_void_elements; |
||||||
|
int m_void_element_count; |
||||||
|
|
||||||
|
static bool ParseEntry(IMkvReader*, |
||||||
|
long long pos, // payload
|
||||||
|
long long size, Entry*); |
||||||
|
}; |
||||||
|
|
||||||
|
class Cues; |
||||||
|
class CuePoint { |
||||||
|
friend class Cues; |
||||||
|
|
||||||
|
CuePoint(long, long long); |
||||||
|
~CuePoint(); |
||||||
|
|
||||||
|
CuePoint(const CuePoint&); |
||||||
|
CuePoint& operator=(const CuePoint&); |
||||||
|
|
||||||
|
public: |
||||||
|
long long m_element_start; |
||||||
|
long long m_element_size; |
||||||
|
|
||||||
|
void Load(IMkvReader*); |
||||||
|
|
||||||
|
long long GetTimeCode() const; // absolute but unscaled
|
||||||
|
long long GetTime(const Segment*) const; // absolute and scaled (ns units)
|
||||||
|
|
||||||
|
struct TrackPosition { |
||||||
|
long long m_track; |
||||||
|
long long m_pos; // of cluster
|
||||||
|
long long m_block; |
||||||
|
// codec_state //defaults to 0
|
||||||
|
// reference = clusters containing req'd referenced blocks
|
||||||
|
// reftime = timecode of the referenced block
|
||||||
|
|
||||||
|
void Parse(IMkvReader*, long long, long long); |
||||||
|
}; |
||||||
|
|
||||||
|
const TrackPosition* Find(const Track*) const; |
||||||
|
|
||||||
|
private: |
||||||
|
const long m_index; |
||||||
|
long long m_timecode; |
||||||
|
TrackPosition* m_track_positions; |
||||||
|
size_t m_track_positions_count; |
||||||
|
}; |
||||||
|
|
||||||
|
class Cues { |
||||||
|
friend class Segment; |
||||||
|
|
||||||
|
Cues(Segment*, long long start, long long size, long long element_start, |
||||||
|
long long element_size); |
||||||
|
~Cues(); |
||||||
|
|
||||||
|
Cues(const Cues&); |
||||||
|
Cues& operator=(const Cues&); |
||||||
|
|
||||||
|
public: |
||||||
|
Segment* const m_pSegment; |
||||||
|
const long long m_start; |
||||||
|
const long long m_size; |
||||||
|
const long long m_element_start; |
||||||
|
const long long m_element_size; |
||||||
|
|
||||||
|
bool Find( // lower bound of time_ns
|
||||||
|
long long time_ns, const Track*, const CuePoint*&, |
||||||
|
const CuePoint::TrackPosition*&) const; |
||||||
|
|
||||||
|
#if 0 |
||||||
|
bool FindNext( //upper_bound of time_ns
|
||||||
|
long long time_ns, |
||||||
|
const Track*, |
||||||
|
const CuePoint*&, |
||||||
|
const CuePoint::TrackPosition*&) const; |
||||||
|
#endif |
||||||
|
|
||||||
|
const CuePoint* GetFirst() const; |
||||||
|
const CuePoint* GetLast() const; |
||||||
|
const CuePoint* GetNext(const CuePoint*) const; |
||||||
|
|
||||||
|
const BlockEntry* GetBlock(const CuePoint*, |
||||||
|
const CuePoint::TrackPosition*) const; |
||||||
|
|
||||||
|
bool LoadCuePoint() const; |
||||||
|
long GetCount() const; // loaded only
|
||||||
|
// long GetTotal() const; //loaded + preloaded
|
||||||
|
bool DoneParsing() const; |
||||||
|
|
||||||
|
private: |
||||||
|
void Init() const; |
||||||
|
void PreloadCuePoint(long&, long long) const; |
||||||
|
|
||||||
|
mutable CuePoint** m_cue_points; |
||||||
|
mutable long m_count; |
||||||
|
mutable long m_preload_count; |
||||||
|
mutable long long m_pos; |
||||||
|
}; |
||||||
|
|
||||||
|
class Cluster { |
||||||
|
friend class Segment; |
||||||
|
|
||||||
|
Cluster(const Cluster&); |
||||||
|
Cluster& operator=(const Cluster&); |
||||||
|
|
||||||
|
public: |
||||||
|
Segment* const m_pSegment; |
||||||
|
|
||||||
|
public: |
||||||
|
static Cluster* Create(Segment*, |
||||||
|
long index, // index in segment
|
||||||
|
long long off); // offset relative to segment
|
||||||
|
// long long element_size);
|
||||||
|
|
||||||
|
Cluster(); // EndOfStream
|
||||||
|
~Cluster(); |
||||||
|
|
||||||
|
bool EOS() const; |
||||||
|
|
||||||
|
long long GetTimeCode() const; // absolute, but not scaled
|
||||||
|
long long GetTime() const; // absolute, and scaled (nanosecond units)
|
||||||
|
long long GetFirstTime() const; // time (ns) of first (earliest) block
|
||||||
|
long long GetLastTime() const; // time (ns) of last (latest) block
|
||||||
|
|
||||||
|
long GetFirst(const BlockEntry*&) const; |
||||||
|
long GetLast(const BlockEntry*&) const; |
||||||
|
long GetNext(const BlockEntry* curr, const BlockEntry*& next) const; |
||||||
|
|
||||||
|
const BlockEntry* GetEntry(const Track*, long long ns = -1) const; |
||||||
|
const BlockEntry* GetEntry(const CuePoint&, |
||||||
|
const CuePoint::TrackPosition&) const; |
||||||
|
// const BlockEntry* GetMaxKey(const VideoTrack*) const;
|
||||||
|
|
||||||
|
// static bool HasBlockEntries(const Segment*, long long);
|
||||||
|
|
||||||
|
static long HasBlockEntries(const Segment*, long long idoff, long long& pos, |
||||||
|
long& size); |
||||||
|
|
||||||
|
long GetEntryCount() const; |
||||||
|
|
||||||
|
long Load(long long& pos, long& size) const; |
||||||
|
|
||||||
|
long Parse(long long& pos, long& size) const; |
||||||
|
long GetEntry(long index, const mkvparser::BlockEntry*&) const; |
||||||
|
|
||||||
|
protected: |
||||||
|
Cluster(Segment*, long index, long long element_start); |
||||||
|
// long long element_size);
|
||||||
|
|
||||||
|
public: |
||||||
|
const long long m_element_start; |
||||||
|
long long GetPosition() const; // offset relative to segment
|
||||||
|
|
||||||
|
long GetIndex() const; |
||||||
|
long long GetElementSize() const; |
||||||
|
// long long GetPayloadSize() const;
|
||||||
|
|
||||||
|
// long long Unparsed() const;
|
||||||
|
|
||||||
|
private: |
||||||
|
long m_index; |
||||||
|
mutable long long m_pos; |
||||||
|
// mutable long long m_size;
|
||||||
|
mutable long long m_element_size; |
||||||
|
mutable long long m_timecode; |
||||||
|
mutable BlockEntry** m_entries; |
||||||
|
mutable long m_entries_size; |
||||||
|
mutable long m_entries_count; |
||||||
|
|
||||||
|
long ParseSimpleBlock(long long, long long&, long&); |
||||||
|
long ParseBlockGroup(long long, long long&, long&); |
||||||
|
|
||||||
|
long CreateBlock(long long id, long long pos, long long size, |
||||||
|
long long discard_padding); |
||||||
|
long CreateBlockGroup(long long start_offset, long long size, |
||||||
|
long long discard_padding); |
||||||
|
long CreateSimpleBlock(long long, long long); |
||||||
|
}; |
||||||
|
|
||||||
|
class Segment { |
||||||
|
friend class Cues; |
||||||
|
friend class Track; |
||||||
|
friend class VideoTrack; |
||||||
|
|
||||||
|
Segment(const Segment&); |
||||||
|
Segment& operator=(const Segment&); |
||||||
|
|
||||||
|
private: |
||||||
|
Segment(IMkvReader*, long long elem_start, |
||||||
|
// long long elem_size,
|
||||||
|
long long pos, long long size); |
||||||
|
|
||||||
|
public: |
||||||
|
IMkvReader* const m_pReader; |
||||||
|
const long long m_element_start; |
||||||
|
// const long long m_element_size;
|
||||||
|
const long long m_start; // posn of segment payload
|
||||||
|
const long long m_size; // size of segment payload
|
||||||
|
Cluster m_eos; // TODO: make private?
|
||||||
|
|
||||||
|
static long long CreateInstance(IMkvReader*, long long, Segment*&); |
||||||
|
~Segment(); |
||||||
|
|
||||||
|
long Load(); // loads headers and all clusters
|
||||||
|
|
||||||
|
// for incremental loading
|
||||||
|
// long long Unparsed() const;
|
||||||
|
bool DoneParsing() const; |
||||||
|
long long ParseHeaders(); // stops when first cluster is found
|
||||||
|
// long FindNextCluster(long long& pos, long& size) const;
|
||||||
|
long LoadCluster(long long& pos, long& size); // load one cluster
|
||||||
|
long LoadCluster(); |
||||||
|
|
||||||
|
long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos, |
||||||
|
long& size); |
||||||
|
|
||||||
|
#if 0 |
||||||
|
//This pair parses one cluster, but only changes the state of the
|
||||||
|
//segment object when the cluster is actually added to the index.
|
||||||
|
long ParseCluster(long long& cluster_pos, long long& new_pos) const; |
||||||
|
bool AddCluster(long long cluster_pos, long long new_pos); |
||||||
|
#endif |
||||||
|
|
||||||
|
const SeekHead* GetSeekHead() const; |
||||||
|
const Tracks* GetTracks() const; |
||||||
|
const SegmentInfo* GetInfo() const; |
||||||
|
const Cues* GetCues() const; |
||||||
|
const Chapters* GetChapters() const; |
||||||
|
|
||||||
|
long long GetDuration() const; |
||||||
|
|
||||||
|
unsigned long GetCount() const; |
||||||
|
const Cluster* GetFirst() const; |
||||||
|
const Cluster* GetLast() const; |
||||||
|
const Cluster* GetNext(const Cluster*); |
||||||
|
|
||||||
|
const Cluster* FindCluster(long long time_nanoseconds) const; |
||||||
|
// const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
|
||||||
|
|
||||||
|
const Cluster* FindOrPreloadCluster(long long pos); |
||||||
|
|
||||||
|
long ParseCues(long long cues_off, // offset relative to start of segment
|
||||||
|
long long& parse_pos, long& parse_len); |
||||||
|
|
||||||
|
private: |
||||||
|
long long m_pos; // absolute file posn; what has been consumed so far
|
||||||
|
Cluster* m_pUnknownSize; |
||||||
|
|
||||||
|
SeekHead* m_pSeekHead; |
||||||
|
SegmentInfo* m_pInfo; |
||||||
|
Tracks* m_pTracks; |
||||||
|
Cues* m_pCues; |
||||||
|
Chapters* m_pChapters; |
||||||
|
Cluster** m_clusters; |
||||||
|
long m_clusterCount; // number of entries for which m_index >= 0
|
||||||
|
long m_clusterPreloadCount; // number of entries for which m_index < 0
|
||||||
|
long m_clusterSize; // array size
|
||||||
|
|
||||||
|
long DoLoadCluster(long long&, long&); |
||||||
|
long DoLoadClusterUnknownSize(long long&, long&); |
||||||
|
long DoParseNext(const Cluster*&, long long&, long&); |
||||||
|
|
||||||
|
void AppendCluster(Cluster*); |
||||||
|
void PreloadCluster(Cluster*, ptrdiff_t); |
||||||
|
|
||||||
|
// void ParseSeekHead(long long pos, long long size);
|
||||||
|
// void ParseSeekEntry(long long pos, long long size);
|
||||||
|
// void ParseCues(long long);
|
||||||
|
|
||||||
|
const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&); |
||||||
|
}; |
||||||
|
|
||||||
|
} // end namespace mkvparser
|
||||||
|
|
||||||
|
inline long mkvparser::Segment::LoadCluster() { |
||||||
|
long long pos; |
||||||
|
long size; |
||||||
|
|
||||||
|
return LoadCluster(pos, size); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // MKVPARSER_HPP
|
@ -0,0 +1,132 @@ |
|||||||
|
// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the LICENSE file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
|
#include "mkvreader.hpp" |
||||||
|
|
||||||
|
#include <cassert> |
||||||
|
|
||||||
|
namespace mkvparser { |
||||||
|
|
||||||
|
MkvReader::MkvReader() : m_file(NULL), reader_owns_file_(true) {} |
||||||
|
|
||||||
|
MkvReader::MkvReader(FILE* fp) : m_file(fp), reader_owns_file_(false) { |
||||||
|
GetFileSize(); |
||||||
|
} |
||||||
|
|
||||||
|
MkvReader::~MkvReader() { |
||||||
|
if (reader_owns_file_) |
||||||
|
Close(); |
||||||
|
m_file = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
int MkvReader::Open(const char* fileName) { |
||||||
|
if (fileName == NULL) |
||||||
|
return -1; |
||||||
|
|
||||||
|
if (m_file) |
||||||
|
return -1; |
||||||
|
|
||||||
|
#ifdef _MSC_VER |
||||||
|
const errno_t e = fopen_s(&m_file, fileName, "rb"); |
||||||
|
|
||||||
|
if (e) |
||||||
|
return -1; // error
|
||||||
|
#else |
||||||
|
m_file = fopen(fileName, "rb"); |
||||||
|
|
||||||
|
if (m_file == NULL) |
||||||
|
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 |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void MkvReader::Close() { |
||||||
|
if (m_file != NULL) { |
||||||
|
fclose(m_file); |
||||||
|
m_file = NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int MkvReader::Length(long long* total, long long* available) { |
||||||
|
if (m_file == NULL) |
||||||
|
return -1; |
||||||
|
|
||||||
|
if (total) |
||||||
|
*total = m_length; |
||||||
|
|
||||||
|
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 _MSC_VER |
||||||
|
const int status = _fseeki64(m_file, offset, SEEK_SET); |
||||||
|
|
||||||
|
if (status) |
||||||
|
return -1; // error
|
||||||
|
#else |
||||||
|
fseek(m_file, offset, SEEK_SET); |
||||||
|
#endif |
||||||
|
|
||||||
|
const size_t size = fread(buffer, 1, len, m_file); |
||||||
|
|
||||||
|
if (size < size_t(len)) |
||||||
|
return -1; // error
|
||||||
|
|
||||||
|
return 0; // success
|
||||||
|
} |
||||||
|
|
||||||
|
} // end namespace mkvparser
|
@ -0,0 +1,45 @@ |
|||||||
|
// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the LICENSE file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
|
#ifndef MKVREADER_HPP |
||||||
|
#define MKVREADER_HPP |
||||||
|
|
||||||
|
#include "mkvparser.hpp" |
||||||
|
#include <cstdio> |
||||||
|
|
||||||
|
namespace mkvparser { |
||||||
|
|
||||||
|
class MkvReader : public IMkvReader { |
||||||
|
public: |
||||||
|
MkvReader(); |
||||||
|
explicit MkvReader(FILE* fp); |
||||||
|
virtual ~MkvReader(); |
||||||
|
|
||||||
|
int Open(const char*); |
||||||
|
void Close(); |
||||||
|
|
||||||
|
virtual int Read(long long position, long length, unsigned char* buffer); |
||||||
|
virtual int Length(long long* total, long long* available); |
||||||
|
|
||||||
|
private: |
||||||
|
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
|
||||||
|
|
||||||
|
#endif // MKVREADER_HPP
|
@ -0,0 +1,122 @@ |
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools |
||||||
|
Copyright (C) 2011 Cyan Worlds, 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7 |
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or |
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||||
|
(or a modified version of those libraries), |
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||||
|
licensors of this Program grant you additional |
||||||
|
permission to convey the resulting work. Corresponding Source for a |
||||||
|
non-source form of such a combination shall include the source code for |
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||||
|
work. |
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||||
|
or by snail mail at: |
||||||
|
Cyan Worlds, Inc. |
||||||
|
14617 N Newport Hwy |
||||||
|
Mead, WA 99021 |
||||||
|
|
||||||
|
*==LICENSE==*/ |
||||||
|
|
||||||
|
#include "plWin32VideoSound.h" |
||||||
|
|
||||||
|
#include "hsResMgr.h" |
||||||
|
#include "plDSoundBuffer.h" |
||||||
|
|
||||||
|
static int uniqueID = 0; |
||||||
|
plWin32VideoSound::plWin32VideoSound(const plWAVHeader& header) : plWin32Sound() |
||||||
|
{ |
||||||
|
fCurrVolume = 1.0f; |
||||||
|
fDesiredVol = 1.0f; |
||||||
|
fSoftVolume = 1.0f; |
||||||
|
fType = kGUISound; |
||||||
|
|
||||||
|
fWAVHeader = header; |
||||||
|
fDSoundBuffer = new plDSoundBuffer(0, fWAVHeader, false, false); |
||||||
|
|
||||||
|
uniqueID++; |
||||||
|
|
||||||
|
char keyName[32]; |
||||||
|
StrPrintf(keyName, arrsize(keyName), "VoiceSound_%d", uniqueID); |
||||||
|
|
||||||
|
hsgResMgr::ResMgr()->NewKey(keyName, this, plLocation::kGlobalFixedLoc); |
||||||
|
} |
||||||
|
|
||||||
|
plWin32VideoSound::~plWin32VideoSound() |
||||||
|
{ |
||||||
|
if (fDSoundBuffer) |
||||||
|
delete fDSoundBuffer; |
||||||
|
} |
||||||
|
|
||||||
|
void plWin32VideoSound::Play() |
||||||
|
{ |
||||||
|
IActuallyPlay(); |
||||||
|
} |
||||||
|
|
||||||
|
void plWin32VideoSound::Pause(bool on) |
||||||
|
{ |
||||||
|
if (on) |
||||||
|
fDSoundBuffer->Pause(); |
||||||
|
else if (!fReallyPlaying) |
||||||
|
fDSoundBuffer->Play(); |
||||||
|
fReallyPlaying = !on; |
||||||
|
} |
||||||
|
|
||||||
|
void plWin32VideoSound::FillSoundBuffer(void* buffer, size_t size) |
||||||
|
{ |
||||||
|
fDSoundBuffer->FillBuffer(buffer, size, &fWAVHeader); |
||||||
|
fDSoundBuffer->SetScalarVolume(1.0f); |
||||||
|
} |
||||||
|
|
||||||
|
void plWin32VideoSound::IDerivedActuallyPlay() |
||||||
|
{ |
||||||
|
if (!fReallyPlaying) { |
||||||
|
fDSoundBuffer->Play(); |
||||||
|
fReallyPlaying = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
hsBool plWin32VideoSound::LoadSound(hsBool is3D) |
||||||
|
{ |
||||||
|
hsAssert(false, "unimplemented cause unnecessary for this class"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void plWin32VideoSound::SetStartPos(unsigned bytes) |
||||||
|
{ |
||||||
|
//do nothing
|
||||||
|
hsAssert(false, "unimplemented cause unnecessary for this class"); |
||||||
|
} |
||||||
|
|
||||||
|
float plWin32VideoSound::GetActualTimeSec() |
||||||
|
{ |
||||||
|
hsAssert(false, "unimplemented cause unnecessary for this class"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
void plWin32VideoSound::ISetActualTime(double t) |
||||||
|
{ |
||||||
|
hsAssert(false, "unimplemented cause unnecessary for this class"); |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools |
||||||
|
Copyright (C) 2011 Cyan Worlds, 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7 |
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or |
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
||||||
|
(or a modified version of those libraries), |
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
||||||
|
licensors of this Program grant you additional |
||||||
|
permission to convey the resulting work. Corresponding Source for a |
||||||
|
non-source form of such a combination shall include the source code for |
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
||||||
|
work. |
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
||||||
|
or by snail mail at: |
||||||
|
Cyan Worlds, Inc. |
||||||
|
14617 N Newport Hwy |
||||||
|
Mead, WA 99021 |
||||||
|
|
||||||
|
*==LICENSE==*/ |
||||||
|
|
||||||
|
#ifndef plWin32VideoSound_h |
||||||
|
#define plWin32VideoSound_h |
||||||
|
|
||||||
|
#include "plWin32Sound.h" |
||||||
|
|
||||||
|
class plWin32VideoSound : public plWin32Sound |
||||||
|
{ |
||||||
|
public: |
||||||
|
plWin32VideoSound(const plWAVHeader& header); |
||||||
|
virtual ~plWin32VideoSound(); |
||||||
|
|
||||||
|
virtual void Play(); |
||||||
|
virtual void Pause(bool on); |
||||||
|
void FillSoundBuffer(void* buffer, size_t size); |
||||||
|
|
||||||
|
protected: |
||||||
|
void IDerivedActuallyPlay(); |
||||||
|
hsBool LoadSound(hsBool is3D); |
||||||
|
void SetStartPos(unsigned bytes); |
||||||
|
float GetActualTimeSec(); |
||||||
|
void ISetActualTime(double t); |
||||||
|
|
||||||
|
plWAVHeader fWAVHeader; |
||||||
|
}; |
||||||
|
#endif |
Loading…
Reference in new issue