Added compressed header support to movreader
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13149 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -8,6 +8,7 @@ Addon mov_reader : media plugins :
|
||||
false
|
||||
:
|
||||
libmovreader.a
|
||||
libz.a
|
||||
;
|
||||
|
||||
LinkSharedOSLibs mov_reader : be libmedia.so ;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "MOVAtom.h"
|
||||
|
||||
@@ -69,7 +69,7 @@ void AtomBase::ProcessMetaData()
|
||||
// - Calls ProcessMetaData on each child atom
|
||||
// (ensures stream is correct for child via offset)
|
||||
{
|
||||
setAtomOffset(theStream->Position());
|
||||
setAtomOffset(getStream()->Position());
|
||||
|
||||
OnProcessMetaData();
|
||||
|
||||
@@ -85,12 +85,19 @@ bool AtomBase::MoveToEnd()
|
||||
{
|
||||
off_t NewPosition = streamOffset + atomSize;
|
||||
|
||||
if (theStream->Position() != NewPosition) {
|
||||
return (theStream->Seek(NewPosition,0) > 0);
|
||||
if (getStream()->Position() != NewPosition) {
|
||||
return (getStream()->Seek(NewPosition,0) > 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64 AtomBase::getBytesRemaining()
|
||||
{
|
||||
off_t EndPosition = streamOffset + atomSize;
|
||||
|
||||
return (EndPosition - getStream()->Position());
|
||||
}
|
||||
|
||||
void AtomBase::DisplayAtoms()
|
||||
{
|
||||
uint32 aindent = 0;
|
||||
@@ -117,11 +124,22 @@ bool AtomBase::IsKnown()
|
||||
|
||||
void AtomBase::ReadArrayHeader(array_header *pHeader)
|
||||
{
|
||||
theStream->Read(pHeader,sizeof(array_header));
|
||||
getStream()->Read(pHeader,sizeof(array_header));
|
||||
|
||||
pHeader->NoEntries = B_BENDIAN_TO_HOST_INT32(pHeader->NoEntries);
|
||||
}
|
||||
|
||||
BPositionIO *AtomBase::OnGetStream()
|
||||
{
|
||||
// default implementation
|
||||
return theStream;
|
||||
}
|
||||
|
||||
BPositionIO *AtomBase::getStream()
|
||||
{
|
||||
return OnGetStream();
|
||||
}
|
||||
|
||||
AtomContainer::AtomContainer(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
TotalChildren = 0;
|
||||
@@ -145,18 +163,20 @@ void AtomContainer::DisplayAtoms(uint32 pindent)
|
||||
|
||||
void AtomContainer::ProcessMetaData()
|
||||
{
|
||||
setAtomOffset(theStream->Position());
|
||||
setAtomOffset(getStream()->Position());
|
||||
|
||||
OnProcessMetaData();
|
||||
|
||||
AtomBase *aChild;
|
||||
while (IsEndOfAtom() == false) {
|
||||
aChild = getAtom(theStream);
|
||||
aChild = getAtom(getStream());
|
||||
if (AddChild(aChild)) {
|
||||
aChild->ProcessMetaData();
|
||||
}
|
||||
}
|
||||
|
||||
OnChildProcessingComplete();
|
||||
|
||||
MoveToEnd();
|
||||
}
|
||||
|
||||
|
||||
@@ -87,8 +87,12 @@ public:
|
||||
virtual ~AtomBase();
|
||||
|
||||
virtual bool IsContainer() {return false;};
|
||||
|
||||
virtual BPositionIO *OnGetStream();
|
||||
BPositionIO *getStream();
|
||||
|
||||
bool IsExtended() {return false;};
|
||||
bool IsEndOfAtom() {return (theStream->Position() >= off_t(streamOffset + atomSize));};
|
||||
bool IsEndOfAtom() {return (getStream()->Position() >= off_t(streamOffset + atomSize));};
|
||||
|
||||
// Is this a known atom type
|
||||
bool IsKnown();
|
||||
@@ -98,6 +102,8 @@ public:
|
||||
uint64 getAtomSize() {return atomSize;};
|
||||
uint32 getAtomType() {return atomType;};
|
||||
|
||||
uint64 getBytesRemaining();
|
||||
|
||||
bool IsType(uint32 patomType) {return patomType == atomType;};
|
||||
|
||||
void setAtomOffset(off_t patomOffset) {atomOffset = patomOffset;};
|
||||
@@ -159,7 +165,7 @@ public:
|
||||
|
||||
// OnProcessMetaData() - Subclass override to read/set meta data
|
||||
virtual void OnProcessMetaData();
|
||||
|
||||
virtual void OnChildProcessingComplete() {};
|
||||
};
|
||||
|
||||
extern AtomBase *getAtom(BPositionIO *pStream);
|
||||
|
||||
@@ -180,10 +180,7 @@ AtomBase *aAtomBase;
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
|
||||
aAtomBase = dynamic_cast<TRAKAtom *>(aAtomBase)->GetChildAtom(uint32('stts'),0);
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
|
||||
|
||||
return aSTTSAtom->getSUMCounts();
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,10 +250,7 @@ uint32 MOVFileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
|
||||
}
|
||||
|
||||
// Add up all sample sizes in chunk
|
||||
// uint32 ChunkSize = 0;
|
||||
|
||||
while (aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk) == ChunkNo) {
|
||||
// ChunkSize += aTrakAtom->getSizeForSample(SampleNo);
|
||||
SampleNo++;
|
||||
}
|
||||
return SampleNo ;
|
||||
@@ -273,42 +267,55 @@ uint32 MOVFileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
|
||||
|
||||
uint64 MOVFileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
|
||||
{
|
||||
// BStopWatch *watch;
|
||||
|
||||
// Find Track
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
// Convert Frame to Track Time
|
||||
// uint32 FrameTime = aTrakAtom->getTimeForFrame(pFrameNo, getMovieTimeScale());
|
||||
// Get Sample for Frame
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
// Get Chunk For Sample and the offset for the frame within that chunk
|
||||
uint32 OffsetInChunk;
|
||||
if (stream_index == 0) {
|
||||
OffsetInChunk = 99;
|
||||
}
|
||||
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
|
||||
// Get Offset For Chunk
|
||||
// printf("Stream: %ld Frame %ld %ld <%ld/%ld> (",stream_index, pFrameNo, SampleNo, ChunkNo, OffsetInChunk);
|
||||
uint64 OffsetNo = aTrakAtom->getOffsetForChunk(ChunkNo);
|
||||
if (pFrameNo < aTrakAtom->FrameCount()) {
|
||||
// Convert Frame to Track Time
|
||||
// uint32 FrameTime = aTrakAtom->getTimeForFrame(pFrameNo, getMovieTimeScale());
|
||||
// Get Sample for Frame
|
||||
// watch = new BStopWatch("getSampleForFrame");
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
// delete watch;
|
||||
// Get Chunk For Sample and the offset for the frame within that chunk
|
||||
// watch = new BStopWatch("getChunkForSample");
|
||||
uint32 OffsetInChunk;
|
||||
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
|
||||
// delete watch;
|
||||
// Get Offset For Chunk
|
||||
// printf("Stream: %ld Frame %ld %ld <%ld/%ld> (",stream_index, pFrameNo, SampleNo, ChunkNo, OffsetInChunk);
|
||||
// watch = new BStopWatch("getOffsetForChunk");
|
||||
uint64 OffsetNo = aTrakAtom->getOffsetForChunk(ChunkNo);
|
||||
// delete watch;
|
||||
// printf("Frame %ld {%lld} <%ld/%ld> (",pFrameNo, OffsetNo, ChunkNo, OffsetInChunk);
|
||||
|
||||
// printf("Frame %ld {%lld} <%ld/%ld> (",pFrameNo, OffsetNo, ChunkNo, OffsetInChunk);
|
||||
|
||||
if (ChunkNo != 0) {
|
||||
uint32 SampleSize;
|
||||
// Adjust the Offset for the Offset in the chunk
|
||||
for (uint32 i=1;i<=OffsetInChunk;i++) {
|
||||
SampleSize = aTrakAtom->getSizeForSample(SampleNo-i);
|
||||
// printf(" %ld ",SampleSize);
|
||||
OffsetNo = OffsetNo + SampleSize;
|
||||
if (ChunkNo != 0) {
|
||||
uint32 SampleSize;
|
||||
// Adjust the Offset for the Offset in the chunk
|
||||
// watch = new BStopWatch("getSizeForSample");
|
||||
if (aTrakAtom->IsSingleSampleSize()) {
|
||||
SampleSize = aTrakAtom->getSizeForSample(SampleNo);
|
||||
OffsetNo = OffsetNo + (OffsetInChunk * SampleSize);
|
||||
} else {
|
||||
// This is bad news performance wise
|
||||
for (uint32 i=1;i<=OffsetInChunk;i++) {
|
||||
SampleSize = aTrakAtom->getSizeForSample(SampleNo-i);
|
||||
// printf(" %ld ",SampleSize);
|
||||
OffsetNo = OffsetNo + SampleSize;
|
||||
}
|
||||
}
|
||||
// printf(") %lld\n",OffsetNo);
|
||||
// delete watch;
|
||||
}
|
||||
// printf(") %lld\n",OffsetNo);
|
||||
}
|
||||
// printf("%ld:%ld:%ld:%lld\n",pFrameNo, SampleNo, ChunkNo, OffsetNo);
|
||||
// printf("\n");
|
||||
// printf("%ld:%ld:%ld:%lld\n",pFrameNo, SampleNo, ChunkNo, OffsetNo);
|
||||
// printf("\n");
|
||||
|
||||
return OffsetNo;
|
||||
return OffsetNo;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -466,13 +473,13 @@ const mov_stream_header *MOVFileReader::StreamFormat(uint32 stream_index)
|
||||
theStreamHeader.length = 0;
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
theStreamHeader.rate = 0;
|
||||
theStreamHeader.rate = uint32(1000000*VideoFormat(stream_index)->FrameRate);
|
||||
theStreamHeader.scale = 1000000;
|
||||
theStreamHeader.length = getVideoFrameCount();
|
||||
}
|
||||
|
||||
if (IsAudio(stream_index)) {
|
||||
theStreamHeader.rate = AudioFormat(stream_index)->SampleRate;
|
||||
theStreamHeader.rate = uint32(AudioFormat(stream_index)->SampleRate);
|
||||
theStreamHeader.scale = 1;
|
||||
theStreamHeader.length = getAudioFrameCount();
|
||||
theStreamHeader.sample_size = AudioFormat(stream_index)->SampleSize;
|
||||
@@ -488,31 +495,33 @@ uint32 MOVFileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo)
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
if (pFrameNo < aTrakAtom->FrameCount()) {
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
|
||||
if (IsAudio(stream_index)) {
|
||||
uint32 OffsetInChunk;
|
||||
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
|
||||
if (IsAudio(stream_index)) {
|
||||
uint32 OffsetInChunk;
|
||||
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
|
||||
|
||||
// Go back to first Sample in Chunk
|
||||
while (aTrakAtom->getChunkForSample(SampleNo-1, &OffsetInChunk) == ChunkNo) {
|
||||
SampleNo--;
|
||||
// Go back to first Sample in Chunk
|
||||
while (aTrakAtom->getChunkForSample(SampleNo-1, &OffsetInChunk) == ChunkNo) {
|
||||
SampleNo--;
|
||||
}
|
||||
|
||||
// Add up all sample sizes in chunk
|
||||
uint32 ChunkSize = 0;
|
||||
|
||||
while (aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk) == ChunkNo) {
|
||||
ChunkSize += aTrakAtom->getSizeForSample(SampleNo);
|
||||
SampleNo++;
|
||||
}
|
||||
return ChunkSize;
|
||||
}
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
return aTrakAtom->getSizeForSample(SampleNo);
|
||||
}
|
||||
|
||||
// Add up all sample sizes in chunk
|
||||
uint32 ChunkSize = 0;
|
||||
|
||||
while (aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk) == ChunkNo) {
|
||||
ChunkSize += aTrakAtom->getSizeForSample(SampleNo);
|
||||
SampleNo++;
|
||||
}
|
||||
return ChunkSize;
|
||||
}
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
return aTrakAtom->getSizeForSample(SampleNo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -536,9 +545,14 @@ bool MOVFileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t
|
||||
|
||||
*start = getOffsetForFrame(stream_index, pFrameNo);
|
||||
*size = getChunkSize(stream_index, pFrameNo);
|
||||
*keyframe = IsKeyFrame(stream_index, pFrameNo);
|
||||
|
||||
if ((*start > 0) && (*size > 0)) {
|
||||
*keyframe = IsKeyFrame(stream_index, pFrameNo);
|
||||
}
|
||||
|
||||
return !(IsEndOfFile(*start) || *start < 0);
|
||||
return ((*start > 0) && (*size > 0));
|
||||
|
||||
// return !(IsEndOfFile(*start) || *start < 0);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#include <SupportKit.h>
|
||||
#include <MediaFormats.h>
|
||||
|
||||
#include <libs/zlib/zlib.h>
|
||||
//#include <zlib.h>
|
||||
|
||||
#include "MOVParser.h"
|
||||
|
||||
//static
|
||||
@@ -159,6 +162,18 @@ AtomBase *getAtom(BPositionIO *pStream)
|
||||
return new FTYPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
if (aAtomType == uint32('cmov')) {
|
||||
return new CMOVAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
if (aAtomType == uint32('dcom')) {
|
||||
return new DCOMAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
if (aAtomType == uint32('cmvd')) {
|
||||
return new CMVDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
|
||||
}
|
||||
@@ -182,6 +197,171 @@ char *MOOVAtom::OnGetAtomName()
|
||||
return "Quicktime Movie";
|
||||
}
|
||||
|
||||
CMOVAtom::CMOVAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
theUncompressedStream = NULL;
|
||||
}
|
||||
|
||||
CMOVAtom::~CMOVAtom()
|
||||
{
|
||||
}
|
||||
|
||||
BPositionIO *CMOVAtom::OnGetStream()
|
||||
{
|
||||
// Use the decompressed stream instead of file stream
|
||||
if (theUncompressedStream) {
|
||||
return theUncompressedStream;
|
||||
}
|
||||
|
||||
return theStream;
|
||||
}
|
||||
|
||||
void CMOVAtom::OnProcessMetaData()
|
||||
{
|
||||
BMallocIO *theUncompressedData;
|
||||
uint8 *outBuffer;
|
||||
CMVDAtom *aCMVDAtom = NULL;
|
||||
uint32 compressionID = 0;
|
||||
uint64 descBytesLeft;
|
||||
uint32 Size;
|
||||
|
||||
descBytesLeft = getAtomSize();
|
||||
|
||||
// Check for Compression Type
|
||||
while (descBytesLeft > 0) {
|
||||
AtomBase *aAtomBase = getAtom(theStream);
|
||||
|
||||
aAtomBase->OnProcessMetaData();
|
||||
printf("%s [%Ld]\n",aAtomBase->getAtomName(),aAtomBase->getAtomSize());
|
||||
|
||||
if (aAtomBase->getAtomSize() > 0) {
|
||||
descBytesLeft = descBytesLeft - aAtomBase->getAtomSize();
|
||||
} else {
|
||||
printf("Invalid Atom found when reading Compressed Headers\n");
|
||||
descBytesLeft = 0;
|
||||
}
|
||||
|
||||
if (dynamic_cast<DCOMAtom *>(aAtomBase)) {
|
||||
// DCOM atom
|
||||
compressionID = dynamic_cast<DCOMAtom *>(aAtomBase)->getCompressionID();
|
||||
delete aAtomBase;
|
||||
} else {
|
||||
if (dynamic_cast<CMVDAtom *>(aAtomBase)) {
|
||||
// CMVD atom
|
||||
aCMVDAtom = dynamic_cast<CMVDAtom *>(aAtomBase);
|
||||
descBytesLeft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decompress data
|
||||
if (compressionID == 'zlib') {
|
||||
Size = aCMVDAtom->getUncompressedSize();
|
||||
|
||||
outBuffer = (uint8 *)(malloc(Size));
|
||||
|
||||
printf("Decompressing %ld bytes to %ld bytes\n",aCMVDAtom->getBufferSize(),Size);
|
||||
int result = uncompress(outBuffer, &Size, aCMVDAtom->getCompressedData(), aCMVDAtom->getBufferSize());
|
||||
|
||||
if (result != Z_OK) {
|
||||
printf("Failed to decompress headers uncompress returned ");
|
||||
switch (result) {
|
||||
case Z_MEM_ERROR:
|
||||
printf("Lack of Memory Error\n");
|
||||
break;
|
||||
case Z_BUF_ERROR:
|
||||
printf("Lack of Output buffer space Error\n");
|
||||
break;
|
||||
case Z_DATA_ERROR:
|
||||
printf("Input Data is corrupt or not a compressed set Error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy uncompressed data into BMAllocIO
|
||||
theUncompressedData = new BMallocIO();
|
||||
theUncompressedData->SetSize(Size);
|
||||
theUncompressedData->WriteAt(0L,outBuffer,Size);
|
||||
|
||||
free(outBuffer);
|
||||
delete aCMVDAtom;
|
||||
|
||||
// reset position on BMAllocIO
|
||||
theUncompressedData->Seek(SEEK_SET,0L);
|
||||
// Assign to Stream
|
||||
theUncompressedStream = theUncompressedData;
|
||||
|
||||
// All subsequent reads should use theUncompressedStream
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CMOVAtom::OnChildProcessingComplete()
|
||||
{
|
||||
// revert back to file stream once all children have finished
|
||||
if (theUncompressedStream) {
|
||||
delete theUncompressedStream;
|
||||
}
|
||||
theUncompressedStream = NULL;
|
||||
}
|
||||
|
||||
char *CMOVAtom::OnGetAtomName()
|
||||
{
|
||||
return "Compressed Quicktime Movie";
|
||||
}
|
||||
|
||||
DCOMAtom::DCOMAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
}
|
||||
|
||||
DCOMAtom::~DCOMAtom()
|
||||
{
|
||||
}
|
||||
|
||||
void DCOMAtom::OnProcessMetaData()
|
||||
{
|
||||
theStream->Read(&compressionID,sizeof(uint32));
|
||||
|
||||
compressionID = B_BENDIAN_TO_HOST_INT32(compressionID);
|
||||
}
|
||||
|
||||
char *DCOMAtom::OnGetAtomName()
|
||||
{
|
||||
return "Decompression Atom";
|
||||
}
|
||||
|
||||
CMVDAtom::CMVDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
Buffer = NULL;
|
||||
UncompressedSize = 0;
|
||||
BufferSize = 0;
|
||||
}
|
||||
|
||||
CMVDAtom::~CMVDAtom()
|
||||
{
|
||||
if (Buffer) {
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CMVDAtom::OnProcessMetaData()
|
||||
{
|
||||
theStream->Read(&UncompressedSize,sizeof(uint32));
|
||||
|
||||
UncompressedSize = B_BENDIAN_TO_HOST_INT32(UncompressedSize);
|
||||
|
||||
if (UncompressedSize > 0) {
|
||||
BufferSize = getBytesRemaining();
|
||||
Buffer = (uint8 *)(malloc(BufferSize));
|
||||
theStream->Read(Buffer,BufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
char *CMVDAtom::OnGetAtomName()
|
||||
{
|
||||
return "Compressed Movie Data";
|
||||
}
|
||||
|
||||
MVHDAtom::MVHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
}
|
||||
@@ -289,6 +469,7 @@ uint64 STTSAtom::getSUMDurations()
|
||||
|
||||
uint32 STTSAtom::getSampleForTime(uint32 pTime)
|
||||
{
|
||||
// TODO this is too slow. PreCalc SUMCounts when loading this.
|
||||
uint64 SUMDurations = 0;
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
@@ -303,23 +484,8 @@ uint32 STTSAtom::getSampleForTime(uint32 pTime)
|
||||
|
||||
uint32 STTSAtom::getSampleForFrame(uint32 pFrame)
|
||||
{
|
||||
// Hmm Sample is Frame really.
|
||||
|
||||
uint64 SUMCounts = 0;
|
||||
uint64 SUMDurations = 0;
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
for (uint32 j=0;j<theTimeToSampleArray[i]->Count;j++) {
|
||||
SUMCounts ++;
|
||||
SUMDurations += theTimeToSampleArray[i]->Duration;
|
||||
// printf("(i=%ld j=%ld) Duration %ld, Count %ld, Duration*Count %ld, SUM(Count) %lld, SUM(Duration*Count) %lld\n",i,j,theTimeToSampleArray[i]->Duration,theTimeToSampleArray[i]->Count,theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count,SUMCounts, SUMDurations);
|
||||
if (SUMCounts > pFrame) {
|
||||
return SUMCounts-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return theHeader.NoEntries;
|
||||
// Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs
|
||||
return pFrame;
|
||||
}
|
||||
|
||||
STSCAtom::STSCAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
@@ -361,12 +527,8 @@ SampleToChunk *aSampleToChunk;
|
||||
aSampleToChunk->TotalPrevFrames = 0;
|
||||
}
|
||||
|
||||
// printf("First Chunk/Samples Per Chunk/ID %ld/%ld/%ld (%ld)\n",aSampleToChunk->FirstChunk,aSampleToChunk->SamplesPerChunk,aSampleToChunk->SampleDescriptionID,aSampleToChunk->TotalPrevFrames);
|
||||
|
||||
theSampleToChunkArray[i] = aSampleToChunk;
|
||||
}
|
||||
|
||||
// printf("Sample To Chunk Array contains %ld Entries\n",theHeader.NoEntries);
|
||||
}
|
||||
|
||||
char *STSCAtom::OnGetAtomName()
|
||||
@@ -387,10 +549,6 @@ uint32 STSCAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk)
|
||||
|
||||
OffsetInChunk = (pSample - theSampleToChunkArray[i]->TotalPrevFrames) % theSampleToChunkArray[i]->SamplesPerChunk;
|
||||
|
||||
if (*pOffsetInChunk == 99) {
|
||||
// printf("%ld (%ld/%ld)\n",pSample, ChunkID, OffsetInChunk);
|
||||
}
|
||||
|
||||
*pOffsetInChunk = OffsetInChunk;
|
||||
return ChunkID;
|
||||
}
|
||||
@@ -502,6 +660,11 @@ uint32 STSZAtom::getSizeForSample(uint32 pSampleNo)
|
||||
return theSampleSizeArray[pSampleNo]->Size;
|
||||
}
|
||||
|
||||
bool STSZAtom::IsSingleSampleSize()
|
||||
{
|
||||
return (theHeader.SampleSize > 0);
|
||||
}
|
||||
|
||||
STCOAtom::STCOAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
theHeader.NoEntries = 0;
|
||||
@@ -536,8 +699,6 @@ ChunkToOffset *aChunkToOffset;
|
||||
|
||||
aChunkToOffset->Offset = OnGetChunkOffset();
|
||||
|
||||
// printf("%ld : %lld\n",i,aChunkToOffset->Offset);
|
||||
|
||||
theChunkToOffsetArray[i] = aChunkToOffset;
|
||||
}
|
||||
|
||||
@@ -551,14 +712,13 @@ char *STCOAtom::OnGetAtomName()
|
||||
|
||||
uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
|
||||
{
|
||||
// printf("?Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries);
|
||||
|
||||
// First chunk is first array entry
|
||||
if ((pChunkID > 0) && (pChunkID <= theHeader.NoEntries)) {
|
||||
return theChunkToOffsetArray[pChunkID - 1]->Offset;
|
||||
}
|
||||
|
||||
printf("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries);
|
||||
|
||||
// TODO Yes this will seg fault. But I get a very bad lock up if I don't :-(
|
||||
return theChunkToOffsetArray[pChunkID - 1]->Offset;
|
||||
// return theChunkToOffsetArray[0]->Offset;
|
||||
@@ -604,9 +764,6 @@ void STSDAtom::ReadSoundDescription()
|
||||
|
||||
descBytesLeft = aSoundDescriptionV1->basefields.Size - sizeof(SampleDescBase);
|
||||
|
||||
// Hmm this should be ok if each stsd describes only a single type
|
||||
DataFormat = aSoundDescriptionV1->basefields.DataFormat;
|
||||
|
||||
// Read in Audio Sample Data
|
||||
// We place into a V1 description even though it might be a V0 or earlier
|
||||
|
||||
|
||||
@@ -77,6 +77,49 @@ private:
|
||||
MVHDAtom *theMVHDAtom;
|
||||
};
|
||||
|
||||
// Atom class for reading the cmov atom
|
||||
class CMOVAtom : public AtomContainer {
|
||||
public:
|
||||
CMOVAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~CMOVAtom();
|
||||
|
||||
BPositionIO *OnGetStream();
|
||||
void OnProcessMetaData();
|
||||
void OnChildProcessingComplete();
|
||||
|
||||
char *OnGetAtomName();
|
||||
private:
|
||||
BMallocIO *theUncompressedStream;
|
||||
};
|
||||
|
||||
// Atom class for reading the dcom atom
|
||||
class DCOMAtom : public AtomBase {
|
||||
public:
|
||||
DCOMAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~DCOMAtom();
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
uint32 getCompressionID() {return compressionID;};
|
||||
private:
|
||||
uint32 compressionID;
|
||||
};
|
||||
|
||||
// Atom class for reading the cmvd atom
|
||||
class CMVDAtom : public AtomBase {
|
||||
public:
|
||||
CMVDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~CMVDAtom();
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
uint32 getUncompressedSize() {return UncompressedSize;};
|
||||
uint8 *getCompressedData() {return Buffer;};
|
||||
uint32 getBufferSize() {return BufferSize;};
|
||||
private:
|
||||
uint32 UncompressedSize;
|
||||
uint32 BufferSize;
|
||||
uint8 *Buffer;
|
||||
};
|
||||
|
||||
// Atom class for reading the ftyp atom
|
||||
class FTYPAtom : public AtomBase {
|
||||
public:
|
||||
@@ -190,7 +233,7 @@ public:
|
||||
char *OnGetAtomName();
|
||||
|
||||
uint32 getSizeForSample(uint32 pSampleNo);
|
||||
|
||||
bool IsSingleSampleSize();
|
||||
private:
|
||||
SampleSizeHeader theHeader;
|
||||
SampleSizeArray theSampleSizeArray;
|
||||
@@ -224,8 +267,6 @@ public:
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
|
||||
uint32 DataFormat;
|
||||
|
||||
VideoDescriptionV0 getAsVideo();
|
||||
SoundDescriptionV1 getAsAudio();
|
||||
|
||||
@@ -299,9 +340,10 @@ public:
|
||||
virtual ~TRAKAtom();
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
|
||||
void OnChildProcessingComplete();
|
||||
|
||||
bigtime_t Duration(uint32 TimeScale); // Return duration of track
|
||||
uint32 FrameCount();
|
||||
uint32 FrameCount() {return framecount;};
|
||||
bool IsVideo(); // Is this a video track
|
||||
bool IsAudio(); // Is this a audio track
|
||||
// GetAudioMetaData() // If this is a audio track get the audio meta data
|
||||
@@ -314,12 +356,15 @@ public:
|
||||
uint64 getOffsetForChunk(uint32 pChunk);
|
||||
uint32 getSizeForSample(uint32 pSample);
|
||||
bool IsSyncSample(uint32 pSampleNo);
|
||||
|
||||
bool IsSingleSampleSize();
|
||||
|
||||
TKHDAtom *getTKHDAtom();
|
||||
MDHDAtom *getMDHDAtom();
|
||||
private:
|
||||
TKHDAtom *theTKHDAtom;
|
||||
MDHDAtom *theMDHDAtom;
|
||||
|
||||
uint32 framecount;
|
||||
};
|
||||
|
||||
// Atom class for reading the media container atom
|
||||
@@ -399,7 +444,7 @@ public:
|
||||
uint32 getMediaComponentSubType();
|
||||
|
||||
private:
|
||||
hdlr theHeader;
|
||||
hdlr theHeader;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@ TRAKAtom::TRAKAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType,
|
||||
{
|
||||
theTKHDAtom = NULL;
|
||||
theMDHDAtom = NULL;
|
||||
framecount = 0;
|
||||
}
|
||||
|
||||
TRAKAtom::~TRAKAtom()
|
||||
@@ -79,6 +80,15 @@ bigtime_t TRAKAtom::Duration(uint32 TimeScale)
|
||||
return bigtime_t(getTKHDAtom()->getDuration() * 1000000) / TimeScale;
|
||||
}
|
||||
|
||||
void TRAKAtom::OnChildProcessingComplete()
|
||||
{
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(GetChildAtom(uint32('stts'),0));
|
||||
|
||||
if (aSTTSAtom) {
|
||||
framecount = aSTTSAtom->getSUMCounts();
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a video track
|
||||
bool TRAKAtom::IsVideo()
|
||||
{
|
||||
@@ -177,5 +187,16 @@ bool TRAKAtom::IsSyncSample(uint32 pSampleNo)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TRAKAtom::IsSingleSampleSize()
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('stsz'),0);
|
||||
|
||||
if (aAtomBase) {
|
||||
return (dynamic_cast<STSZAtom *>(aAtomBase))->IsSingleSampleSize();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetAudioMetaData() // If this is a audio track get the audio meta data
|
||||
// GetVideoMetaData() // If this is a video track get the video meta data
|
||||
|
||||
@@ -461,8 +461,6 @@ movReader::GetNextChunk(void *_cookie,
|
||||
if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe))
|
||||
return B_LAST_BUFFER_ERROR;
|
||||
|
||||
TRACE("stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
||||
|
||||
if (cookie->buffer_size < size) {
|
||||
delete [] cookie->buffer;
|
||||
cookie->buffer_size = (size + 15) & ~15;
|
||||
@@ -470,6 +468,7 @@ movReader::GetNextChunk(void *_cookie,
|
||||
}
|
||||
|
||||
if (cookie->audio) {
|
||||
TRACE("Audio stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
||||
mediaHeader->start_time = (cookie->byte_pos * 1000000LL * (int64)cookie->bytes_per_sec_scale) / cookie->bytes_per_sec_rate;
|
||||
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
|
||||
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||
@@ -484,6 +483,7 @@ movReader::GetNextChunk(void *_cookie,
|
||||
// cookie->frame_pos += theFileReader->getNoFramesInChunk(cookie->stream,cookie->frame_pos);
|
||||
// cookie->frame_pos += 2205;
|
||||
} else {
|
||||
TRACE("Video stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
||||
mediaHeader->start_time = (cookie->frame_pos * 1000000LL * (int64)cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
||||
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
|
||||
mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||
|
||||
Reference in New Issue
Block a user