[asterisk-scf-commits] asterisk-scf/integration/file_media_service.git branch "initial_development" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Wed Oct 12 09:52:51 CDT 2011
branch "initial_development" has been updated
via 883f26046f8ebe1d4337581de99a07e32d86d3e9 (commit)
from 12ee5808908be376f29b5246c71106e5d0704f67 (commit)
Summary of changes:
src/MatroskaCodec.cpp | 30 -
src/MatroskaCodec.h | 83 ---
src/MatroskaUtils.cpp | 1541 -------------------------------------------------
src/MatroskaUtils.h | 275 ---------
4 files changed, 0 insertions(+), 1929 deletions(-)
delete mode 100755 src/MatroskaCodec.cpp
delete mode 100755 src/MatroskaCodec.h
delete mode 100755 src/MatroskaUtils.cpp
delete mode 100755 src/MatroskaUtils.h
- Log -----------------------------------------------------------------
commit 883f26046f8ebe1d4337581de99a07e32d86d3e9
Author: Brent Eagles <beagles at digium.com>
Date: Wed Oct 12 12:22:17 2011 -0230
Remove files that use the LGPL libmatroska.
diff --git a/src/MatroskaCodec.cpp b/src/MatroskaCodec.cpp
deleted file mode 100755
index 62da989..0000000
--- a/src/MatroskaCodec.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 2011, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk SCF project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE.txt file
- * at the top of the source tree.
- */
-
-#include "MatroskaCodec.h"
-
-using namespace AsteriskSCF::FileMediaService::Implementation;
-
-
-CodecPtr MatroskaCodecTranslator::create(const AsteriskSCF::Media::V1::FormatPtr&)
-{
- return CodecPtr();
-}
-
-AsteriskSCF::Media::V1::FormatPtr create(const CodecPtr&)
-{
- return AsteriskSCF::Media::V1::FormatPtr();
-}
diff --git a/src/MatroskaCodec.h b/src/MatroskaCodec.h
deleted file mode 100755
index 5433be0..0000000
--- a/src/MatroskaCodec.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 2011, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk SCF project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE.txt file
- * at the top of the source tree.
- */
-
-#include <AsteriskSCF/Media/MediaIf.h>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-#include <string>
-
-namespace AsteriskSCF
-{
-namespace FileMediaService
-{
-namespace Implementation
-{
-
-/**
- * Base class for mapping codec information into matroska codec encodings.
- * TODO: Matching implementation and factories for each codec of import/or translations
- * to AsteriskSCF Media Format classes.
- */
-class Codec
-{
-public:
- virtual ~Codec() {}
-
- virtual std::vector<unsigned char> privateBytes() const = 0;
- virtual std::string id() const = 0;
-};
-typedef boost::shared_ptr<Codec> CodecPtr;
-
-/**
- * Specialization for audio codecs.
- */
-class AudioCodec : public Codec
-{
-public:
- virtual unsigned int channels() = 0;
- virtual double sampleRate() = 0;
- virtual unsigned int bitDepth() = 0;
- virtual double outputSampleRate() = 0;
-};
-typedef boost::shared_ptr<AudioCodec> AudioCodecPtr;
-
-/**
- * Specialization for video codecs.
- */
-class VideoCodec : public Codec
-{
-public:
- virtual unsigned int width() = 0;
- virtual unsigned int height() = 0;
- virtual unsigned int displayWidth() = 0;
- virtual unsigned int displayHeight() = 0;
-};
-typedef boost::shared_ptr<VideoCodec> VideoCodecPtr;
-
-/**
- * Facility for converting AsteriskSCF format objects to Matroska utility codecs and
- * vice-versa.
- */
-class MatroskaCodecTranslator
-{
-public:
- static CodecPtr create(const AsteriskSCF::Media::V1::FormatPtr& format);
- static AsteriskSCF::Media::V1::FormatPtr create(const CodecPtr& codec);
-};
-
-} /* End of namespace implementation */
-} /* End of namespace FileMediaService */
-} /* End of namespace AsteriskSCF */
diff --git a/src/MatroskaUtils.cpp b/src/MatroskaUtils.cpp
deleted file mode 100755
index 9f2a51c..0000000
--- a/src/MatroskaUtils.cpp
+++ /dev/null
@@ -1,1541 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 2011, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk SCF project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE.txt file
- * at the top of the source tree.
- */
-
-//
-// boost does something here that VC++ complains loudly and annoyingly about.
-// Unfortunately GCC complains about the pragma and warnings-as-errors busts
-// compilation.
-//
-#ifdef WIN32
-#pragma warning(disable: 4996)
-#endif
-
-#include "MatroskaUtils.h"
-
-#include <ebml/EbmlHead.h>
-#include <ebml/EbmlSubHead.h>
-#include <ebml/EbmlUInteger.h>
-#include <ebml/EbmlVoid.h>
-#include <ebml/EbmlUnicodeString.h>
-
-#include <matroska/KaxSeekHead.h>
-#include <matroska/KaxTracks.h>
-#include <matroska/KaxCluster.h>
-#include <matroska/KaxBlock.h>
-#include <matroska/KaxCues.h>
-#include <matroska/KaxSegment.h>
-#include <matroska/KaxVersion.h>
-#include <matroska/KaxTrackAudio.h>
-#include <matroska/KaxTrackVideo.h>
-
-#include <sstream>
-#include <map>
-#include <iostream>
-#include <list>
-
-#include <time.h>
-
-#include <boost/uuid/uuid.hpp>
-#include <boost/uuid/uuid_generators.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/thread/locks.hpp>
-#include <boost/thread/shared_mutex.hpp>
-
-//
-// TODO: TimeCode or Timecode.. pick one.
-//
-
-using namespace libebml;
-using namespace libmatroska;
-using namespace std;
-
-namespace AsteriskSCF
-{
-namespace FileMediaService
-{
-namespace Implementation
-{
-
-//
-// A little range checking casting function I cooked up. It
-// isn't used consistently because I decided to write it part
-// way through and didn't retro fit.
-//
-inline unsigned char trackNo(unsigned long value)
-{
- assert(value < 256);
- if (value > 255)
- {
- throw InvalidTrackNumber();
- }
- return static_cast<unsigned char>(value);
-}
-
-int AudioTrackType::getType() const
-{
- return track_audio;
-}
-
-int VideoTrackType::getType() const
-{
- return track_video;
-}
-
-void Header::writeTo(const OpaqueContainerDataPtr& data)
-{
- EbmlHead header;
- EDocType& docType = GetChild<EDocType>(header);
- EbmlString* stringField = dynamic_cast<EbmlString*>(&docType);
- assert(stringField);
- *stringField = "matroska";
- EDocTypeVersion& docTypeVer = GetChild<EDocTypeVersion>(header);
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&docTypeVer);
- assert(uintField);
- *uintField = 1;
- EDocTypeReadVersion& docTypeReadVer = GetChild<EDocTypeReadVersion>(header);
- uintField = dynamic_cast<EbmlUInteger*>(&docTypeReadVer);
- assert(uintField);
- *uintField = 1;
-
- //
- // DO NOT allow default arg or pass false as the second argument! Many
- // code examples do, but it will end in tears! The matroska lib will
- // not write "default" values if you do and to it, and value that is
- // set but is the same as it might have as a default is the same
- // thing as you not setting it.
- //
- header.Render(*data->getIO(), true);
-}
-
-namespace Internal
-{
-
-typedef boost::shared_ptr<KaxSegment> KaxSegmentPtr;
-
-
-class ContainerWriterImpl;
-typedef boost::shared_ptr<ContainerWriterImpl> ContainerWriterImplPtr;
-
-//
-// Internal wrapper around KaxCluster. Do NOT delete mCluster, you don't
-// own it! Cluster for the moment is about writing only.. the name should
-// probably be changed.
-//
-// Note: the matroska website says that blocks that are part of a cluster
-// have timecodes relative to the parent cluster. This seems not to be
-// the case... mkvtoolnix does not generate them this way and matroska lib
-// freaks out if you try that.
-//
-class Cluster
-{
-public:
- Cluster(KaxCluster* cluster, const ContainerWriterImplPtr& segment,
- uint64 initialTimeCode, uint64 lastTimeCode);
- uint64 startTimeCode() const;
- void render(IOCallback* io, KaxCues* cues);
- KaxCluster* kax();
- uint64 increaseSize(uint64 addThisMuch);
- uint64 size() const;
-
-private:
- KaxCluster* mCluster;
- ContainerWriterImplPtr mContainer;
- const uint64 mTimeCode;
- uint64 mSize;
-};
-typedef boost::shared_ptr<Cluster> ClusterPtr;
-
-//
-// Implementation of the A::M::I::TrackWriter. Like many things, deleting the wrapped
-// KaxEntry will probably end in tears. If there is a proper time to kill it,
-// it is not clear yet. It is probably simply a pointer to an internal structure
-// of KaxSegment so let's not worry about it for now.
-//
-class Writer : public TrackWriter, public boost::enable_shared_from_this<Writer>
-{
-public:
- Writer(const ContainerWriterImplPtr& containerWriter, KaxTrackEntry* t, unsigned char number);
- void setCodecAndType(const CodecPtr& codec, const TrackTypePtr& trackType);
- void addTag(const string& name, const string& value);
- void write(uint64 timeCode, uint32 duration, const unsigned char* data, size_t len);
-
- uint64 getSize();
- TagSeq getTags();
- void finished();
- uint64 getID();
-
-private:
- ContainerWriterImplPtr mContainer;
- KaxTrackEntry* mTrack;
- CodecPtr mCodec;
- TrackTypePtr mTrackType;
- KaxBlockGroup* mGroup;
- TagSeq mTags;
- uint64 mLastTimeCode;
- uint32 mDuration;
- uint64 mByteCount;
- uint64 mTotalTime;
-};
-typedef boost::shared_ptr<Writer> WriterPtr;
-
-class ContainerReaderImpl;
-typedef boost::shared_ptr<ContainerReaderImpl> ContainerReaderImplPtr;
-
-/**
- * I'm going to implement this stuff in line so it is a little more clear what is going
- * on. I *will* document it, but for the moment this is more for me so I don't forget
- * what I'm at.
- */
-class BlockAccessTracker
-{
-public:
- BlockAccessTracker(KaxBlockGroup* block) :
- mBlock(block)
- {
- }
-
- ~BlockAccessTracker()
- {
- mBlock->ReleaseFrames();
- }
-
- KaxBlockGroup* blockGroup()
- {
- return mBlock;
- }
-
-private:
- KaxBlockGroup* mBlock;
-};
-
-typedef boost::shared_ptr<BlockAccessTracker> BlockAccessTrackerPtr;
-typedef vector<BlockAccessTrackerPtr> BlockAccessTrackers;
-
-class TrackingDataBuf
-{
-public:
- TrackingDataBuf(const BlockAccessTrackers& trackers);
-
- size_t fillFrames(FrameSeq& frames, size_t frameCount);
- void getAllFrames(FrameSeq& frames);
-
- //
- // Shouldn't be used by anybody.. more for testing than anything
- //
- BlockAccessTrackers getTrackers() { return mTrackers; }
-
-private:
- BlockAccessTrackers mTrackers;
- BlockAccessTrackers::iterator mCurrentTracker;
- size_t mCurrentFrame;
-};
-typedef boost::shared_ptr<TrackingDataBuf> TrackingDataBufPtr;
-
-typedef vector<KaxCluster*> KaxClusterSeq;
-typedef vector<KaxBlockGroup*> KaxBlockGroupSeq;
-
-class TrackData
-{
-public:
- TrackData(const KaxSegmentPtr& segment, const OpaqueContainerDataPtr& data);
-
- void addBlock(KaxBlockGroup* block);
-
- uint64 getStartTimeCode();
- uint64 getLastTimeCode();
- uint64 getDuration();
-
- TrackingDataBufPtr getFromUntil(uint64 startTime, uint64 endTime);
-
- TrackingDataBufPtr getBlocks(size_t pos, size_t count);
-
-private:
- KaxSegmentPtr mSegment;
- BlockAccessTrackers mBlocks;
- OpaqueContainerDataPtr mDataFile;
-
- boost::shared_mutex mLock;
- typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
- typedef boost::shared_lock<boost::shared_mutex> SharedLock;
-};
-
-typedef boost::shared_ptr<TrackData> TrackDataPtr;
-
-//
-// Track number to track data mapping!
-//
-typedef map<unsigned char, TrackDataPtr> TrackDataMap;
-
-//
-// A given container has only one pool and every container view gets
-// their data from here.
-//
-class TrackDataPool
-{
-public:
- TrackDataPool(const KaxSegmentPtr& container, const OpaqueContainerDataPtr& dataFile);
- TrackDataPtr getTrackData(unsigned char trackNumber);
-private:
- KaxSegmentPtr mSegment;
- TrackDataMap mDataMap;
- OpaqueContainerDataPtr mDataFile;
- boost::shared_mutex mLock;
- typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
- typedef boost::shared_lock<boost::shared_mutex> SharedLock;
-};
-typedef boost::shared_ptr<TrackDataPool> TrackDataPoolPtr;
-
-//
-// Implementation of the TrackReader
-//
-class Reader : public TrackReader , public boost::enable_shared_from_this<Reader>
-{
-public:
- Reader(const ContainerReaderImplPtr& containerReader, KaxTrackEntry* t, unsigned char number,
- const TrackDataPtr& data);
-
- uint64 getSize();
- TagSeq getTags();
- uint64 getID();
-
- void reset();
-
- void getFrames(FrameSeq& frames, size_t requestedNumberOfFrames);
-
- void getFrames(FrameSeq& frames, uint64 fromTime, uint64 untilTime);
-
- uint64 getStartTimecode();
-
- CodecPtr getCodec();
-
- TrackTypePtr getType();
-
-private:
- ContainerReaderImplPtr mContainer;
- TrackDataPtr mTrackData;
- KaxTrackEntry* mTrack;
- TrackingDataBufPtr mCurrentData;
- const unsigned char mTrackNumber;
- size_t mBlockIndex;
-};
-typedef boost::shared_ptr<Reader> ReaderPtr;
-
-//
-// Base class for both the reader and writers of KSegments.
-//
-class ContainerImplBase
-{
-public:
- ContainerImplBase(const KaxSegmentPtr& segment);
-
- KaxSegment& kax();
-
- uint64 globalTimeScale() const;
-
-protected:
- KaxSegmentPtr mSegment;
- KaxSeekHead* mSeekHead;
- EbmlVoid* mIndexSpace;
- KaxTracks* mTracks;
- KaxSeekHead* mLeftOverSeek;
- KaxCues* mCues;
-
- OpaqueContainerDataPtr mContainer;
-
- ClusterPtr mActiveCluster;
-
- //
- // Should be configurable for new files. Existing files will have this set on them. If
- // they do, we will probably want to normalize to something consistent for the service.
- //
- uint64 mTimeCodeScale;
- uint64 mMaxTimePerCluster;
- uint64 mPrevTime;
- uint16 mPrevTrack;
- uint64 mLastTime;
-
- typedef map<uint64, TagSeq> TrackTags;
- TrackTags mTrackTags;
-
- uint64 mClusterCount;
-
- void initialize();
-};
-
-//
-// Wrapper around the "segment" for writing, where everything happens.
-//
-class ContainerWriterImpl : public ContainerWriter, public ContainerImplBase,
- public boost::enable_shared_from_this<ContainerWriterImpl>
-{
-public:
- //
- // The default constructor is creating a new segment.
- //
- ContainerWriterImpl();
-
-
- void addTo(const OpaqueContainerDataPtr& data);
-
- size_t getTrackCount();
- TrackWriterPtr getTrack(unsigned char track);
-
- void close();
-
- //
- // Internal implementation details.
- //
-
- ClusterPtr getCluster(uint64 currentTimeCode);
- uint64 addTime(uint64 moreTime);
-
- void commit(const WriterPtr& track);
-
-private:
- ClusterPtr mActiveCluster;
-};
-
-//
-// Wrapper around the "segment" for reading, where everything happens... well, reading stuff that is...
-// the writing stuff is.. well you know.
-//
-class ContainerReaderImpl : public ContainerImplBase, public ContainerReader,
- public boost::enable_shared_from_this<ContainerReaderImpl>
-{
-public:
- ContainerReaderImpl(const KaxSegmentPtr& segment, const OpaqueContainerDataPtr& dataFile);
- size_t getTrackCount();
- //
- // I know it is kind of weird that matroska defines a track number as single byte value
- // but the matroska lib defines track collection to be of possible size size_t. <shrug>
- //
- TrackReaderPtr getTrack(unsigned char trackNumber);
- TrackReaderSeq getTracks();
- void close();
-
-private:
- OpaqueContainerDataPtr mDataFile;
- TrackDataPoolPtr mTrackPool;
-
- TrackDataPtr getTrackData(unsigned char trackNumber);
-};
-
-//
-// IMPL
-//
-////////////////////////////////////////////////////////////////////////////////////////////
-// TrackingDataBuf implementation.
-//
-TrackingDataBuf::TrackingDataBuf(const BlockAccessTrackers& trackers) :
- mTrackers(trackers),
- mCurrentTracker(mTrackers.begin()),
- mCurrentFrame(0)
-{
-}
-
-class DataToFrameAdapter : public Frame
-{
-public:
- DataToFrameAdapter(const DataBuffer& buf)
- {
- copy(buf.Buffer(), buf.Buffer()+buf.Size(), mData.begin());
- }
-};
-
-size_t TrackingDataBuf::fillFrames(FrameSeq& frames, size_t frameCount)
-{
- size_t framesFilled = 0;
- //
- // We descend through the structures and iterate through the collections
- // until we successfully retrieve up to count bytes. We keep track of where
- // we were when this accomplished so the next read will start where we left
- // off.
- //
- // NOTE: this should be *heavily* unit tested.
- //
- for(; mCurrentTracker != mTrackers.end() && frameCount > 0 ; ++mCurrentTracker)
- {
- KaxInternalBlock& current = (KaxInternalBlock&)(*(*mCurrentTracker)->blockGroup());
-
- for (; mCurrentFrame < current.NumberFrames() && frameCount > 0; ++mCurrentFrame, ++framesFilled)
- {
- DataBuffer& buf = current.GetBuffer(static_cast<unsigned int>(mCurrentFrame));
- frames.push_back(FramePtr(new DataToFrameAdapter(buf)));
- --frameCount;
- }
- }
- return framesFilled;
-}
-
-void TrackingDataBuf::getAllFrames(FrameSeq& frames)
-{
- for (BlockAccessTrackers::iterator iter = mTrackers.begin(); iter != mTrackers.end(); ++iter)
- {
- KaxInternalBlock& current = (KaxInternalBlock&)(*(*mCurrentTracker)->blockGroup());
-
- for (unsigned long currentBuf = 0; currentBuf < current.NumberFrames(); ++currentBuf)
- {
- DataBuffer& buf = current.GetBuffer(static_cast<unsigned int>(currentBuf));
- frames.push_back(FramePtr(new DataToFrameAdapter(buf)));
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// TrackData implementation.
-//
-TrackData::TrackData(const KaxSegmentPtr& segment, const OpaqueContainerDataPtr& dataFile) :
- mSegment(segment),
- mDataFile(dataFile)
-{
-}
-
-void TrackData::addBlock(KaxBlockGroup* block)
-{
- if (mBlocks.size() == 0)
- {
- mBlocks.push_back(BlockAccessTrackerPtr(new BlockAccessTracker(block)));
- return;
- }
-
- if (block->GlobalTimecode() < mBlocks.front()->blockGroup()->GlobalTimecode())
- {
- mBlocks.insert(mBlocks.begin(), BlockAccessTrackerPtr(new BlockAccessTracker(block)));
- }
- else if (block->GlobalTimecode() > mBlocks.back()->blockGroup()->GlobalTimecode())
- {
- mBlocks.push_back(BlockAccessTrackerPtr(new BlockAccessTracker(block)));
- }
- else
- {
- for (BlockAccessTrackers::iterator i = mBlocks.end() -1; i != mBlocks.begin(); --i)
- {
- if (block->GlobalTimecode() > (*i)->blockGroup()->GlobalTimecode())
- {
- //
- // This is actually safe because the "tack on" the last block case is handled.
- //
- ++i;
- mBlocks.insert(i, BlockAccessTrackerPtr(new BlockAccessTracker(block)));
- break;
- }
- }
- }
-}
-
-uint64 TrackData::getStartTimeCode()
-{
- if (mBlocks.size() == 0)
- {
- return 0;
- }
-
- return mBlocks.front()->blockGroup()->GlobalTimecode();
-}
-
-uint64 TrackData::getLastTimeCode()
-{
- if (mBlocks.size() == 0)
- {
- return 0;
- }
- return mBlocks.back()->blockGroup()->GlobalTimecode();
-}
-
-uint64 TrackData::getDuration()
-{
- if (mBlocks.size() == 0)
- {
- return 0;
- }
- uint64 lastBlockDuration = 0;
- if (!mBlocks.back()->blockGroup()->GetBlockDuration(lastBlockDuration))
- {
- //
- // Probably want to log somethin' here. We don't have a proper duration on this last block.
- //
- }
- return mBlocks.back()->blockGroup()->GlobalTimecode() - mBlocks.front()->blockGroup()->GlobalTimecode()
- + lastBlockDuration;
-}
-
-TrackingDataBufPtr TrackData::getFromUntil(uint64 startTime, uint64 endTime)
-{
- SharedLock lock(mLock);
- BlockAccessTrackers subset;
- for (BlockAccessTrackers::const_iterator i = mBlocks.begin(); i != mBlocks.end(); ++i)
- {
- uint64 timecode = (*i)->blockGroup()->GlobalTimecode();
- if (timecode >= startTime && timecode < endTime)
- {
- if (!(*i)->blockGroup()->ValueIsSet())
- {
- IOCallback* io = mDataFile->getIO();
- if (io)
- {
- (*i)->blockGroup()->ReadData(*(mDataFile->getIO()), SCOPE_ALL_DATA);
- }
- }
- subset.push_back(*i);
- }
- }
- return TrackingDataBufPtr(new TrackingDataBuf(subset));
-}
-
-TrackingDataBufPtr TrackData::getBlocks(size_t pos, size_t count)
-{
- SharedLock lock(mLock);
- if (pos > mBlocks.size())
- {
- return TrackingDataBufPtr();
- }
- BlockAccessTrackers subset;
- subset.reserve(count);
-
- for (size_t i = pos; (i < mBlocks.size()) && (i < (pos + count)); ++i)
- {
- if (!mBlocks[i]->blockGroup()->ValueIsSet())
- {
- IOCallback* io = mDataFile->getIO();
- if (io)
- {
- mBlocks[i]->blockGroup()->ReadData(*mDataFile->getIO(), SCOPE_ALL_DATA);
- }
- }
-
- subset.push_back(mBlocks[i]);
- }
- return TrackingDataBufPtr(new TrackingDataBuf(subset));
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// TrackDataPool implementation.
-//
-TrackDataPool::TrackDataPool(const KaxSegmentPtr& segment, const OpaqueContainerDataPtr& dataFile) :
- mSegment(segment),
- mDataFile(dataFile)
-{
- KaxTracks& tracks = GetChild<KaxTracks>(*mSegment);
-
- for (size_t i = 0; i < tracks.ListSize(); ++i)
- {
- KaxTrackEntry* t = static_cast<KaxTrackEntry*>(tracks[static_cast<unsigned int>(i)]);
- unsigned char trackNumber = (uint8)(t->TrackNumber());
- mDataMap[trackNumber] = TrackDataPtr(new TrackData(segment, mDataFile));
- }
- KaxClusterSeq allClusters;
- for (EBML_MASTER_ITERATOR clusterIter = mSegment->begin(); clusterIter != mSegment->end(); ++clusterIter)
- {
- if (EbmlId(**clusterIter) == EBML_ID(KaxCluster))
- {
- KaxCluster* cluster = static_cast<KaxCluster*>(*clusterIter);
- allClusters.push_back(cluster);
-
- for (EBML_MASTER_ITERATOR blockGroupIter = cluster->begin(); blockGroupIter != cluster->end();
- ++blockGroupIter)
- {
- if (EbmlId(**blockGroupIter) == EBML_ID(KaxBlockGroup))
- {
- KaxBlockGroup* blockGroup = static_cast<KaxBlockGroup*>(*blockGroupIter);
- TrackDataMap::iterator mapEntry = mDataMap.find(trackNo(blockGroup->TrackNumber()));
- if (mapEntry == mDataMap.end())
- {
- //
- // This actually indicates that something is probably wrong with the source
- // matroska file.
- //
- mDataMap[trackNo(blockGroup->TrackNumber())] = TrackDataPtr(new TrackData(segment, mDataFile));
- }
- mDataMap[trackNo(blockGroup->TrackNumber())]->addBlock(blockGroup);
- }
- }
- }
- }
-}
-
-TrackDataPtr TrackDataPool::getTrackData(unsigned char trackNumber)
-{
- SharedLock lock(mLock);
- TrackDataMap::iterator mapEntry = mDataMap.find(trackNumber);
- if (mapEntry == mDataMap.end())
- {
- throw InvalidTrackNumber();
- }
- return mapEntry->second;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// Cluster implementation.
-//
-Cluster::Cluster(KaxCluster* cluster, const ContainerWriterImplPtr& container,
- uint64 initialTimeCode, uint64 lastTimeCode) :
- mCluster(cluster),
- mContainer(container),
- mTimeCode(initialTimeCode),
- mSize(0)
-{
- mCluster->SetParent(mContainer->kax());
- mCluster->SetGlobalTimecodeScale(mContainer->globalTimeScale());
- mCluster->SetPreviousTimecode(lastTimeCode * mContainer->globalTimeScale(), mContainer->globalTimeScale());
- mCluster->InitTimecode(initialTimeCode, mContainer->globalTimeScale());
- mCluster->EnableChecksum();
- KaxClusterTimecode& tc = GetChild<KaxClusterTimecode>(*mCluster);
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&tc);
- assert(uintField);
- *uintField = initialTimeCode;
-}
-
-uint64 Cluster::startTimeCode() const
-{
- return mTimeCode;
-}
-
-void Cluster::render(IOCallback* io, KaxCues* cues)
-{
- mCluster->Render(*io, *cues);
- mCluster->ReleaseFrames();
-}
-
-KaxCluster* Cluster::kax()
-{
- return mCluster;
-}
-
-uint64 Cluster::increaseSize(uint64 addThisMuch)
-{
- mSize += addThisMuch;
- return mSize;
-}
-
-uint64 Cluster::size() const
-{
- return mSize;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// Writer implementation.
-//
-Writer::Writer(const ContainerWriterImplPtr& container, KaxTrackEntry* t, unsigned char number) :
- TrackWriter(number),
- mContainer(container),
- mTrack(t),
- mGroup(0),
- mLastTimeCode(0),
- mDuration(0),
- mByteCount(0),
- mTotalTime(0)
-{
-}
-
-void Writer::setCodecAndType(const CodecPtr& codec, const TrackTypePtr& trackType)
-{
- //
- // Generic codec info to matroska stuff translation
- //
- mCodec = codec;
- mTrackType = trackType;
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxTrackType>(*mTrack));
- assert(uintField);
- *uintField = trackType->getType();
- EbmlString* stringField = dynamic_cast<EbmlString*>(&GetChild<KaxCodecID>(*mTrack));
- assert(stringField);
- *stringField = codec->id();
- if (codec->privateBytes().size() != 0)
- {
- KaxCodecPrivate& privateData = GetChild<KaxCodecPrivate>(*mTrack);
- vector<unsigned char> codecsData = codec->privateBytes();
- privateData.CopyBuffer(static_cast<unsigned char*>(&codecsData[0]), static_cast<uint32>(codecsData.size()));
- }
-
- if (mTrackType->getType() == track_audio)
- {
- KaxTrackAudio& audio = GetChild<KaxTrackAudio>(*mTrack);
- AudioCodecPtr audioCodec = boost::dynamic_pointer_cast<AudioCodec>(codec);
- assert(audioCodec);
- if (audioCodec->channels() != 0)
- {
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxAudioChannels>(audio));
- assert(uintField);
- *uintField = audioCodec->channels();
- }
-
- if (audioCodec->sampleRate() != 0)
- {
- KaxAudioSamplingFreq& freq = GetChild<KaxAudioSamplingFreq>(audio);
- EbmlFloat* floatField = dynamic_cast<EbmlFloat*>(&freq);
- assert(floatField);
- *floatField = audioCodec->sampleRate();
- freq.ValidateSize();
- }
-
- if (audioCodec->outputSampleRate() > 0.0)
- {
- KaxAudioOutputSamplingFreq& freq = GetChild<KaxAudioOutputSamplingFreq>(audio);
- EbmlFloat* floatField = dynamic_cast<EbmlFloat*>(&freq);
- assert(floatField);
- *floatField = audioCodec->sampleRate();
- freq.ValidateSize();
- }
-
- if (audioCodec->bitDepth() != 0)
- {
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxAudioBitDepth>(audio));
- assert(uintField);
- *uintField = audioCodec->bitDepth();
- }
- }
- else
- {
- VideoCodecPtr videoCodec = boost::dynamic_pointer_cast<VideoCodec>(codec);
- assert(videoCodec);
-
- KaxTrackVideo& video = GetChild<KaxTrackVideo>(*mTrack);
- unsigned int defaultDisplayWidth = 0;
- if (videoCodec->width() != 0)
- {
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxVideoPixelWidth>(video));
- assert(uintField);
- *uintField = videoCodec->width();
- defaultDisplayWidth = videoCodec->width();
- }
- if (videoCodec->displayWidth() != 0)
- {
- defaultDisplayWidth = videoCodec->displayWidth();
- }
-
- unsigned int defaultDisplayHeight = 0;
- if (videoCodec->height() != 0)
- {
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxVideoPixelHeight>(video));
- assert(uintField);
- *uintField = videoCodec->height();
- defaultDisplayHeight = videoCodec->height();
- }
- if (videoCodec->displayHeight() != 0)
- {
- defaultDisplayHeight = videoCodec->displayHeight();
- }
-
- if (defaultDisplayWidth != 0)
- {
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxVideoDisplayWidth>(video));
- assert(uintField);
- *uintField = defaultDisplayWidth;
- }
-
- if (defaultDisplayHeight != 0)
- {
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxVideoDisplayHeight>(video));
- assert(uintField);
- *uintField = defaultDisplayHeight;
- }
- }
-}
-
-void Writer::addTag(const string& name, const string& value)
-{
- mTags.push_back(Tag(name, value));
-}
-
-void Writer::write(uint64 timeCode, uint32 duration, const unsigned char* data, size_t len)
-{
- ClusterPtr cluster = mContainer->getCluster(timeCode);
- //
- // Lazy initializtion of the current block group.
- //
- if (!mGroup)
- {
- mGroup = &cluster->kax()->GetNewBlock();
- mGroup->SetParent(*cluster->kax());
- mGroup->SetParentTrack(*mTrack);
- }
- else if (mGroup->GetParentCluster() != cluster->kax())
- {
- //
- // The cluster may have changed on us if we exceeded the limits. If we did, we need to
- // get a new block agroup and set it up.
- //
- mGroup = &cluster->kax()->GetNewBlock();
- mGroup->SetParent(*cluster->kax());
- mGroup->SetParentTrack(*mTrack);
- }
- //
- // Keep track. While we do need the info for matroska, it is pretty handy for debugging
- // anyway.
- //
- mByteCount += len;
- mTotalTime += duration;
-
- //
- // Add the data to the actual block.
- //
- KaxBlock& block = GetChild<KaxBlock>(*mGroup);
- block.SetParent(*cluster->kax());
-
- //
- // We need to allocate heap and copy the data to it, the block seems to take ownership.
- //
- binary* copiedData = new binary[len];
- memcpy(copiedData, data, len);
- DataBuffer* buf = new DataBuffer(copiedData, static_cast<uint32>(len));
-
- //
- // The AddFrame call may return "false" indicating it does not want to have any more frames added
- // to it. In which case we create a new blockgroup on the next go'round.
- //
- bool blockWantsMore = block.AddFrame(*mTrack, mLastTimeCode * mContainer->globalTimeScale(), *buf);
- cluster->increaseSize(buf->Size());
- mDuration += duration;
-
- //
- // While a nuisance, we want to set the duration each time we change it
- //
- mGroup->SetBlockDuration(mDuration * mContainer->globalTimeScale());
-
- //
- // If we are creating a new group, we probably want to finish this one up with some tidying.
- // Notice how the method name "SetBlockDuration" is on an instance of block group and how the
- // call to create the new blockgroup is GetNewBlock()? I noticed.... don't be confused, sometimes
- // it is best just to go with it.
- //
- if (!blockWantsMore)
- {
- mGroup = 0;
- mLastTimeCode = mDuration + mLastTimeCode;
- mDuration = 0;
- }
-
- //
- // We are not doing references at this time so nothing to do there.
- // TODO: Supposedly there is something we should be doing with the cues if
- // this is a video track.
- //
- if ((uint8)(GetChild<KaxTrackType>(*mTrack)) == track_video)
- {
- //
- // TODO: update cues. In addition to the other interesting bits, some of the code
- // examples I looked at use a non-existent method. I checked.. it has been deprecated.
- // I guess deprecated means "removed for good, too bad". Who knew?
- //
- }
-}
-
-uint64 Writer::getSize()
-{
- return mByteCount;
-}
-
-TagSeq Writer::getTags()
-{
- return mTags;
-}
-
-void Writer::finished()
-{
- if (!mTrackType || !mCodec)
- {
- throw IncompleteException();
- }
- mContainer->addTime(mTotalTime);
- mContainer->commit(shared_from_this());
-}
-
-uint64 Writer::getID()
-{
- return static_cast<uint64>(GetChild<KaxTrackUID>(*mTrack));
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// Reader implementation
-//
-Reader::Reader(const ContainerReaderImplPtr& containerReader, KaxTrackEntry* t, unsigned char number,
- const TrackDataPtr& data) :
- TrackReader(number),
- mContainer(containerReader),
- mTrackData(data),
- mTrack(t),
- mTrackNumber(number),
- mBlockIndex(0)
-{
- mCurrentData = mTrackData->getBlocks(mBlockIndex++, 1);
-}
-
-uint64 Reader::getSize()
-{
- return 0; // XXX it is not clear whether this is meanignful.
-}
-
-TagSeq Reader::getTags()
-{
- return TagSeq(); // XXX
-}
-
-uint64 Reader::getID()
-{
- return static_cast<uint64>(GetChild<KaxTrackUID>(*mTrack));
-}
-
-void Reader::reset()
-{
- mBlockIndex = 0;
- mCurrentData = mTrackData->getBlocks(mBlockIndex, 1);
-}
-
-void Reader::getFrames(FrameSeq& frames, size_t requestedNumberOfFrames)
-{
- if (!mCurrentData)
- {
- //
- // We are out of data.
- //
- return;
- }
-
- for (size_t framesRead = mCurrentData->fillFrames(frames, requestedNumberOfFrames);
- framesRead < requestedNumberOfFrames; )
- {
- //
- // The current data set is exhausted.. let's go get some more blocks.
- //
- mCurrentData = mTrackData->getBlocks(mBlockIndex++, 1);
- if (!mCurrentData)
- {
- //
- // That's it folks.. no more data.
- //
- return;
- }
- framesRead += mCurrentData->fillFrames(frames, requestedNumberOfFrames - framesRead);
- }
-}
-
-void Reader::getFrames(FrameSeq& frames, uint64 fromTime, uint64 untilTime)
-{
- TrackingDataBufPtr data = mTrackData->getFromUntil(fromTime * mTrack->GlobalTimecodeScale(),
- untilTime * mTrack->GlobalTimecodeScale());
- data->getAllFrames(frames);
-}
-
-uint64 Reader::getStartTimecode()
-{
- return mTrackData->getStartTimeCode();
-}
-
-CodecPtr Reader::getCodec()
-{
- //
- // XXX translate track codec info to our codec objectsj
- //
- return CodecPtr();
-}
-
-TrackTypePtr Reader::getType()
-{
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxTrackType>(*mTrack));
- assert(uintField);
- if ((uint16)(*uintField) == track_audio)
- {
- return TrackTypePtr(new AudioTrackType);
- }
- else if ((uint16)(*uintField) == track_video)
- {
- return TrackTypePtr(new VideoTrackType);
- }
- return TrackTypePtr();
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// ContainerImplBase implementation.
-//
-ContainerImplBase::ContainerImplBase(const KaxSegmentPtr& segment) :
- mSegment(segment)
-{
- if (mSegment->ValueIsSet())
- {
- KaxInfo& info = GetChild<KaxInfo>(*mSegment);
- KaxTimecodeScale& scale = GetChild<KaxTimecodeScale>(info);
- mTimeCodeScale = (uint64)scale;
- }
- else
- {
- mTimeCodeScale = 1000000; // Means our times are all in milliseconds... TODO: define a constant.
- }
-}
-
-KaxSegment& ContainerImplBase::kax()
-{
- //
- // Ok.. it grieves me to return a reference here, but I don't want to refactor anymore right now.
- //
- return *mSegment;
-}
-
-uint64 ContainerImplBase::globalTimeScale() const
-{
- return mTimeCodeScale;
-}
-
-void ContainerImplBase::initialize()
-{
- mMaxTimePerCluster = 1000; // How many milliseconds per cluster.
- mPrevTime = 0xFFFFFFFFFFFFFFFF; // Dummy value to make sure we start off right.
- mPrevTrack = 0xFFFF; // This isn't really used much as we haven't start setting up references.
- mLastTime = 0; // The rest is general initialization.
-
- //
- // initialize helper members into the segment.
- //
- mSeekHead = &GetChild<KaxSeekHead>(*mSegment);
- mIndexSpace = &GetChild<EbmlVoid>(*mSegment);
- mTracks = &GetChild<KaxTracks>(*mSegment);
- mLeftOverSeek = &GetChild<KaxSeekHead>(*mSegment);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// ContainerWriterImpl implementation.
-//
-ContainerWriterImpl::ContainerWriterImpl() :
- ContainerImplBase(KaxSegmentPtr(new KaxSegment))
-{
- initialize();
-}
-
-void ContainerWriterImpl::addTo(const OpaqueContainerDataPtr& data)
-{
- mContainer = data;
-
- //
- // Write the "head" of the segment.. I guess. The number 5 means set everything for
- // a file that might hold a huge bunch of data.. it is a size classification.. .maybe?
- //
- mSegment->WriteHead(*(data->getIO()), 5);
-
- //
- // Make space for seek head. This could be rightsized... the number I picked was arbitrary.
- // A lot of code examples used 1000 bytes, so maybe this is too big?
- //
- mIndexSpace->SetSize(2 * 1024);
- mIndexSpace->Render(*(data->getIO()));
-
- //
- // The info part of the segment talks about what who is doing what... presumably
- // so an app that reads this file and chokes and dies because we did something
- // wrong knows who to blame.
- //
- KaxInfo& info = GetChild<KaxInfo>(*mSegment);
- KaxWritingApp& writingApp = GetChild<KaxWritingApp>(info);
- EbmlUnicodeString* unicodeField = dynamic_cast<EbmlUnicodeString*>(&writingApp);
- assert(unicodeField);
- *unicodeField = L"Asterisk SCF";
- stringstream os;
- os << "Asterisk SCF Matroska Container Library with libmatroska " << KaxCodeVersion << " and libebml " << EbmlCodeVersion;
- UTFstring muxerName;
- muxerName.SetUTF8(os.str());
- KaxMuxingApp& muxer = GetChild<KaxMuxingApp>(info);
- unicodeField = dynamic_cast<EbmlUnicodeString*>(&muxer);
- assert(unicodeField);
- *unicodeField = muxerName;
- KaxDateUTC& date = GetChild<KaxDateUTC>(info);
- date.SetEpochDate(static_cast<int32>(time(0)));
- KaxTimecodeScale& scale = GetChild<KaxTimecodeScale>(info);
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&scale);
- assert(uintField);
- *uintField = mTimeCodeScale;
- KaxDuration& duration = GetChild<KaxDuration>(info);
- EbmlFloat* floatField = dynamic_cast<EbmlFloat*>(&duration);
- assert(floatField);
- *floatField = 10000; // We set a dummy value for this right now.
- KaxSegmentUID& uuid = GetChild<KaxSegmentUID>(info);
- boost::uuids::uuid idValue = boost::uuids::random_generator()();
- binary* buf = new binary[idValue.static_size()];
- for (boost::uuids::uuid::const_iterator i = idValue.begin(); i != idValue.end(); ++i)
- {
- *buf = *i;
- }
- uuid.SetBuffer(buf, static_cast<uint32>(idValue.static_size()));
- info.Render(*(data->getIO()));
-
- mSeekHead->IndexThis(info, *mSegment);
- mCues = &GetChild<KaxCues>(*mSegment);
- mCues->SetGlobalTimecodeScale(mTimeCodeScale);
- //
- // We are writing the tracks here initially.. but we haven't added tracks yet. I don't
- // know either.. except VLC hates me if I don't do this.
- //
- mTracks->Render(*(data->getIO()));
-
- //
- // The problem is of course.. we don't know how many tracks are really going to be in
- // here yet, so I write some more blank space. 1k might be too small here. If the track
- // count is big enough, when we come back and write the real track info, we might
- // clobber the first cluster.... things that make you go "hmmmm".
- //
- EbmlVoid moreSpace;
- moreSpace.SetSize(1024);
- moreSpace.Render(*(data->getIO()));
- //
- // Ok.. so I think that is it for setup .. whew!
- //
-}
-
-size_t ContainerWriterImpl::getTrackCount()
-{
- if (mTracks)
- {
- return mTracks->ListSize();
- }
- return 0;
-}
-
-TrackWriterPtr ContainerWriterImpl::getTrack(unsigned char track)
-{
- if (track == 0)
- {
- throw InvalidTrackNumber("Track list index starts at 1.");
- }
- KaxTrackEntry* t = 0;
- if (mTracks->ListSize() < track)
- {
-
- //
- // We need to create a new track!
- //
- if (mTracks->ListSize() == 0)
- {
- t = &GetChild<KaxTrackEntry>(*mTracks);
- }
- else
- {
- t = &GetNextChild<KaxTrackEntry>(*mTracks,
- static_cast<KaxTrackEntry&>(*(*mTracks)[static_cast<unsigned int>(mTracks->ListSize()-1)]));
- }
-
- //
- // Initialize me! Mostly just generic stuff.
- //
- assert(t);
- KaxTrackNumber& trackNumber = GetChild<KaxTrackNumber>(*t);
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&trackNumber);
- assert(uintField);
- *uintField = track;
- KaxTrackUID& trackId = GetChild<KaxTrackUID>(*t);
- uintField = dynamic_cast<EbmlUInteger*>(&trackId);
- assert(uintField);
- *uintField = rand();
- KaxTrackLanguage& lang = GetChild<KaxTrackLanguage>(*t);
- EbmlString* stringField = dynamic_cast<EbmlString*>(&lang);
- assert(stringField);
- *stringField = "eng";
- t->SetGlobalTimecodeScale(mTimeCodeScale);
- uintField = dynamic_cast<EbmlUInteger*>(&GetChild<KaxTrackFlagLacing>(*t));
- assert(uintField);
- *uintField = true;
- }
- else
- {
- t = dynamic_cast<KaxTrackEntry*>((*mTracks)[track-1]);
- assert(t);
- }
- return TrackWriterPtr(new Writer(shared_from_this(), t, track));
-}
-
-void ContainerWriterImpl::close()
-{
- //
- // Done are we? Make sure we write the last cluster out.
- //
- if (mActiveCluster)
- {
- mActiveCluster->render(mContainer->getIO(), mCues);
- mActiveCluster.reset();
- }
-
- //
- // Now.. we are writing at the end of the file. Cues can go here.. that's okay.
- //
- if (mCues && mCues->ElementSize() != 0)
- {
- mCues->Render(*mContainer->getIO());
- if (mSeekHead)
- {
- mSeekHead->IndexThis(*mCues, *mSegment);
- }
- }
-
- //
- // Info was back near the front remember? Remember to seek back before rendering.. oh and remember
- // where we are before we move or we will be very unhappy.
- //
- KaxInfo& info = GetChild<KaxInfo>(*mSegment);
- KaxDuration& duration = GetChild<KaxDuration>(info);
- EbmlFloat* floatField = dynamic_cast<EbmlFloat*>(&duration);
- assert(floatField);
- *floatField = static_cast<double>(mLastTime);
- info.UpdateSize();
- uint64 bookmark = mContainer->getIO()->getFilePointer();
- mContainer->getIO()->setFilePointer(info.GetElementPosition());
- info.Render(*mContainer->getIO());
-
- //
- // As I recall the tracks were right after info, so we can write them now too..
- //
- mTracks->Render(*mContainer->getIO());
- mSeekHead->IndexThis(*mTracks, *mSegment);
-
- //
- // Didn't forget to add the index entry? Good for you. Now where were we...?
- //
- mContainer->getIO()->setFilePointer(bookmark);
-
- //
- // Now is a good time to write the tags.. they are related to tracks, but they go in there
- // own space.
- //
- KaxTags& tags = GetChild<KaxTags>(*mSegment);
- KaxTag* lastTag = 0;
- for (TrackTags::iterator i = mTrackTags.begin(); i != mTrackTags.end(); ++i)
- {
- KaxTag* current = 0;
- if (lastTag)
- {
- current = &GetNextChild<KaxTag>(tags, *lastTag);
- }
- else
- {
- current = &GetChild<KaxTag>(tags);
- }
- lastTag = current;
-
- KaxTagTargets& targets = GetChild<KaxTagTargets>(*current);
- KaxTagTrackUID& trackUID = GetChild<KaxTagTrackUID>(targets);
- EbmlUInteger* uintField = dynamic_cast<EbmlUInteger*>(&trackUID);
- assert(uintField);
- *uintField = i->first;
- KaxTagSimple* tagEntry = 0;
- for (TagSeq::const_iterator t = i->second.begin(); t != i->second.end(); ++t)
- {
- KaxTagSimple* currentEntry = 0;
- if (tagEntry)
- {
- currentEntry = &GetNextChild<KaxTagSimple>(*current, *tagEntry);
- }
- else
- {
- currentEntry = &GetChild<KaxTagSimple>(*current);
- }
- tagEntry = currentEntry;
- EbmlUnicodeString* unicodeField = dynamic_cast<EbmlUnicodeString*>(&GetChild<KaxTagName>(*currentEntry));
- assert(unicodeField);
- UTFstring utf;
- utf.SetUTF8(t->name);
- *unicodeField = utf;
-
- unicodeField = dynamic_cast<EbmlUnicodeString*>(&GetChild<KaxTagString>(*currentEntry));
- assert(unicodeField);
- utf.SetUTF8(t->value);
- *unicodeField = utf;
- }
- }
-
- //
- // But don't forget to write!
- //
- tags.Render(*mContainer->getIO());
-
- if (mSeekHead)
- {
- mSeekHead->IndexThis(tags, *mSegment);
- }
-
- if (mIndexSpace)
- {
- //
- // Now we have real index info, so lets go back and fix that. Umm.. did that re-render? I
- // studies say yes. Why can't everything work that way?
- //
- mIndexSpace->ReplaceWith(*mSeekHead, *mContainer->getIO());
- }
-
- //
- // Let's find out where whether we need to something with our size and rewrite that "head" bit.
- //
- mContainer->getIO()->setFilePointer(0, seek_end);
- uint64 newSize = mContainer->getIO()->getFilePointer() - mSegment->GetElementPosition() - mSegment->HeadSize();
- mContainer->getIO()->setFilePointer(mSegment->GetElementPosition());
- if (mSegment->ForceSize(newSize))
- {
- mSegment->OverwriteHead(*mContainer->getIO());
- }
-}
-
-//
-// Internal implementation details.
-//
-ClusterPtr ContainerWriterImpl::getCluster(uint64 currentTimeCode)
-{
- uint64 oldTimeCode = 0;
- if (mActiveCluster)
- {
- if ((currentTimeCode - mActiveCluster->startTimeCode()) < mMaxTimePerCluster)
- {
- return mActiveCluster;
- }
- mActiveCluster->render(mContainer->getIO(), mCues);
- oldTimeCode = mActiveCluster->startTimeCode();
- }
- ++mClusterCount;
- mActiveCluster.reset(new Cluster(new KaxCluster, shared_from_this(), currentTimeCode, oldTimeCode));
- return mActiveCluster;
-}
-
-uint64 ContainerWriterImpl::addTime(uint64 moreTime)
-{
- mLastTime += moreTime;
- return mLastTime;
-}
-
-void ContainerWriterImpl::commit(const WriterPtr& track)
-{
- mTrackTags[track->getID()] = track->getTags();
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// ContainerReaderImpl implementation.
-//
-ContainerReaderImpl::ContainerReaderImpl(const KaxSegmentPtr& segment,
- const OpaqueContainerDataPtr& dataFile) :
- ContainerImplBase(segment),
- mDataFile(dataFile),
- mTrackPool(new TrackDataPool(segment, dataFile))
-{
- initialize();
-}
-
-//
-// TODO: move method to base class.
-// Yeah, I know there is some code duplication. I had originally separated these because I suspected
-// that they would be different. I think they could probably be safely merged.
-//
-size_t ContainerReaderImpl::getTrackCount()
-{
- return mTracks->ListSize();
-}
-
-TrackReaderPtr ContainerReaderImpl::getTrack(unsigned char trackNumber)
-{
- if (trackNumber == 0)
- {
- throw InvalidTrackNumber("track numbers start at 1.");
- }
-
- if (trackNumber > mTracks->ListSize())
- {
- throw InvalidTrackNumber();
- }
- KaxTrackEntry* t = dynamic_cast<KaxTrackEntry*>((*mTracks)[trackNumber-1]);
- if (!t->ValueIsSet())
- {
- t->ReadData(*mContainer->getIO(), SCOPE_ALL_DATA);
- }
- return TrackReaderPtr(new Reader(shared_from_this(), t, trackNumber,
- mTrackPool->getTrackData(trackNumber)));
-}
-
-TrackReaderSeq ContainerReaderImpl::getTracks()
-{
- //
- // A little note on getTracks(): I could cache the track entries once they've been created,
- // but I expect a container file to be open by multiple threads. The Reader should be
- // unique to the thread, but I think the read clusters ought to pool and be shared.
- //
- TrackReaderSeq result;
- for (uint32 i = 0; i < mTracks->ListSize(); ++i)
- {
- uint32 trackNumber = i + 1;
- KaxTrackEntry* t = dynamic_cast<KaxTrackEntry*>((*mTracks)[i]);
- if (!t->ValueIsSet())
- {
- t->ReadData(*mContainer->getIO(), SCOPE_ALL_DATA);
- }
- result.push_back(TrackReaderPtr(new Reader(shared_from_this(), t, trackNo(trackNumber),
- mTrackPool->getTrackData(trackNo(trackNumber)))));
- }
- return result;
-}
-
-void ContainerReaderImpl::close()
-{
- //
- // Not sold that I want this method... I was kind of thinking that this would really
- // be reference count based.
- //
-}
-
-} /* End of namespace internal. */
-
-using namespace ::AsteriskSCF::FileMediaService::Implementation::Internal;
-
-ContainerWriterPtr ContainerWriter::create()
-{
- return ContainerWriterPtr(new ContainerWriterImpl);
-}
-
-ContainerReaderPtr ContainerReader::read(const OpaqueContainerDataPtr& data)
-{
- //
- // Here is kind of the dilemna.. do we seek to where we expect things to be or not?
- // Tell you what, let someone else decide! There is a second method that finds the right
- // place in the file!
- //
- KaxSegmentPtr seg(new KaxSegment);
- seg->ReadData(*data->getIO(), SCOPE_ALL_DATA);
- return ContainerReaderPtr(new ContainerReaderImpl(seg, data));
-}
-
-ContainerReaderPtr ContainerReader::locateAndRead(const OpaqueContainerDataPtr& data)
-{
- //
- // Find the right place.. well that is all well and good, but I'm not sure that we
- // can be sure how big EbmlHeader is going to be. So we will brute force it and
- // read the EbmlHead anyways. The chances of someone else having read that info first is
- // slim anyways.
- //
-
- //
- // Make sure we go to the start of the file... in at least one version of the
- // matroska library, all the read does is seek to EbmlHeader().GetSize() from current.
- // If we are not at the start of the file.. kaboom. Full of sighs.
- //
- data->getIO()->setFilePointer(0);
- EbmlHead header;
-
- //
- // The "true" is for "read fully"... which is garbage as it looks like some versions
- // of libmatroska do not actually read anything at all for this call, but oh well.
- //
- header.ReadData(*data->getIO(), SCOPE_ALL_DATA);
-
- //
- // Ok, so now we are presumably at where the segment starts. We'll delegate to the
- // non-seeky version for the actual creation.
- //
- return ContainerReader::read(data);
-}
-
-} /* End of namespace Implementation */
-} /* End of namespace FileMediaService */
-} /* End of namespace AsteriskSCF */
-
diff --git a/src/MatroskaUtils.h b/src/MatroskaUtils.h
deleted file mode 100755
index 222fd44..0000000
--- a/src/MatroskaUtils.h
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 2011, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk SCF project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE.txt file
- * at the top of the source tree.
- */
-
-#include "OpaqueContainerData.h"
-
-#include <ebml/EbmlTypes.h>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-#include <string>
-#include <stdexcept>
-
-#include "MatroskaCodec.h"
-
-namespace AsteriskSCF
-{
-namespace FileMediaService
-{
-namespace Implementation
-{
-
-/**
- * File header that must be added to every matroska file being created before the "Segment" is added to it.
- */
-class Header
-{
-public:
- void writeTo(const OpaqueContainerDataPtr& data);
-};
-
-/**
- * Simple track types.
- */
-class TrackType
-{
-public:
- virtual ~TrackType() {}
- virtual int getType() const = 0;
-};
-typedef boost::shared_ptr<TrackType> TrackTypePtr;
-
-class AudioTrackType : public TrackType
-{
-public:
- int getType() const;
-};
-
-class VideoTrackType : public TrackType
-{
-public:
- int getType() const;
-};
-
-/**
- * Matroska supports track tagging which is pretty awesome because we
- * can add app-support data.
- */
-struct Tag
-{
- std::string name;
- std::string value;
-
- Tag(const std::string& n, const std::string& v) :
- name(n), value(v) {}
-};
-typedef std::vector<Tag> TagSeq;
-
-class TrackBase
-{
-public:
- virtual ~TrackBase() {}
-
- unsigned char trackNumber()
- {
- return mTrackNumber;
- }
-
- virtual uint64 getSize() = 0;
- virtual TagSeq getTags() = 0;
- virtual uint64 getID() = 0;
-
-protected:
- unsigned char mTrackNumber;
-
- TrackBase(unsigned char trackNo) :
- mTrackNumber(trackNo)
- {
- }
-};
-
-/**
- * Encapsulation of tracks for writing. Virtual because I'm trying to keep matroska-specific stuff
- * out of the headers.
- */
-class TrackWriter : public TrackBase
-{
-public:
-
- class IncompleteException : public std::logic_error
- {
- public:
- IncompleteException() :
- std::logic_error("IncompleteException")
- {
- }
- };
-
- virtual ~TrackWriter() {}
-
- //
- // Move to a track writer class.
- //
- virtual void setCodecAndType(const CodecPtr& codec, const TrackTypePtr& trackType) = 0;
- virtual void addTag(const std::string& name, const std::string& value) = 0;
- virtual void write(uint64 timeCode, uint32 duration, const unsigned char* data, size_t len) = 0;
- virtual void finished() = 0;
-
-protected:
- TrackWriter(unsigned char trackNum) :
- TrackBase(trackNum) {}
-};
-typedef boost::shared_ptr<TrackWriter> TrackWriterPtr;
-
-class Frame
-{
-public:
- std::vector<unsigned char>& data() const;
-
-protected:
- std::vector<unsigned char> mData;
-};
-typedef boost::shared_ptr<Frame> FramePtr;
-typedef std::vector<FramePtr> FrameSeq;
-
-/**
- * Encapsulation of tracks for reading.
- */
-class TrackReader : public TrackBase
-{
-public:
- /**
- * Start at the beginning.
- */
- virtual void reset() = 0;
-
- virtual void getFrames(FrameSeq& frames, size_t requestedNumberOfFrames) = 0;
-
- virtual void getFrames(FrameSeq& frames, uint64 fromTime, uint64 untilTime) = 0;
-
- virtual uint64 getStartTimecode() = 0;
-
- virtual CodecPtr getCodec() = 0;
-
- virtual TrackTypePtr getType() = 0;
-
- /**
- * Note the absence of a close method. This is because a track reader only provides
- * a view on data that is read or in the process of being read. The resources
- * allocated to this process belong to the library itself. A close() method
- * is really not necessary. When the library realizes that the container and
- * it's associated readers are no longer in use, it will free up any cached
- * resources and close "stuff".
- */
-
-protected:
- TrackReader(unsigned char trackNum) :
- TrackBase(trackNum)
- {
- }
-};
-typedef boost::shared_ptr<TrackReader> TrackReaderPtr;
-typedef std::vector<TrackReaderPtr> TrackReaderSeq;
-
-class InvalidTrackNumber : public std::out_of_range
-{
-public:
- InvalidTrackNumber(const std::string& hint) :
- std::out_of_range(std::string("Track number does not exist: ") + hint)
- {
- }
-
- InvalidTrackNumber() :
- std::out_of_range("Track number does not exists")
- {
- }
-};
-
-class ContainerWriter;
-typedef boost::shared_ptr<ContainerWriter> ContainerWriterPtr;
-
-/**
- * Regarding the matroska specific stuff... I forgot myself and used Matroska specific terminology
- * if not types... I should rename this to be something more generic.
- */
-class ContainerWriter
-{
- //
- // Hidden and unimplemented.
- //
- ContainerWriter(const ContainerWriter&);
- void operator=(const ContainerWriter&);
-
-public:
-
- virtual ~ContainerWriter() {}
- virtual void addTo(const OpaqueContainerDataPtr& data) = 0;
-
- virtual size_t getTrackCount() = 0;
- virtual TrackWriterPtr getTrack(unsigned char trackNumber) = 0;
-
-
- virtual void close() = 0;
-
- /**
- * Create a Segment instance for writing a new container file.
- */
- static ContainerWriterPtr create();
-
-protected:
- ContainerWriter() {}
-};
-
-class ContainerReader;
-typedef boost::shared_ptr<ContainerReader> ContainerReaderPtr;
-
-class ContainerReader
-{
- //
- // Hidden and unimplemented.
- //
- ContainerReader(const ContainerReader&);
- void operator=(const ContainerReader&);
-
-public:
- virtual ~ContainerReader() {}
-
- virtual size_t getTrackCount() = 0;
- virtual TrackReaderPtr getTrack(unsigned char trackNumber) =0;
- virtual TrackReaderSeq getTracks() = 0;
-
- virtual void close() = 0;
-
- /**
- * Attempt to read a segment from the container data at the current location.
- */
- static ContainerReaderPtr read(const OpaqueContainerDataPtr& data);
-
- /**
- * Seek to the expected location for the Matroska segment in the specified file
- * and create a segement from the data there. We don't set the file pointer back
- * to where it was.. so if it is necessary to go back there, you will have
- * to track it yourself. Sorry.
- */
- static ContainerReaderPtr locateAndRead(const OpaqueContainerDataPtr& data);
-
-protected:
- ContainerReader() {}
-
-};
-
-} /* End of namespace Implementation */
-} /* End of namespace FileMediaService */
-} /* End of namepsace AsteriskSCF */
-----------------------------------------------------------------------
--
asterisk-scf/integration/file_media_service.git
More information about the asterisk-scf-commits
mailing list