486 lines
15 KiB
C++
486 lines
15 KiB
C++
|
/*
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_START@
|
||
|
*
|
||
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||
|
*
|
||
|
* This file contains Original Code and/or Modifications of Original Code
|
||
|
* as defined in and that are subject to the Apple Public Source License
|
||
|
* Version 2.0 (the 'License'). You may not use this file except in
|
||
|
* compliance with the License. Please obtain a copy of the License at
|
||
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||
|
* file.
|
||
|
*
|
||
|
* The Original Code and all software distributed under the License are
|
||
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||
|
* Please see the License for the specific language governing rights and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_END@
|
||
|
*
|
||
|
*/
|
||
|
//
|
||
|
// QTTrack:
|
||
|
// The central point of control for a track in a QTFile.
|
||
|
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Includes
|
||
|
//
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "SafeStdLib.h"
|
||
|
#include <string.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
#include "QTFile.h"
|
||
|
|
||
|
#include "QTAtom.h"
|
||
|
#include "QTAtom_dref.h"
|
||
|
#include "QTAtom_elst.h"
|
||
|
#include "QTAtom_mdhd.h"
|
||
|
#include "QTAtom_tkhd.h"
|
||
|
#include "QTAtom_stco.h"
|
||
|
#include "QTAtom_stsc.h"
|
||
|
#include "QTAtom_stsd.h"
|
||
|
#include "QTAtom_stss.h"
|
||
|
#include "QTAtom_stsz.h"
|
||
|
#include "QTAtom_stts.h"
|
||
|
|
||
|
#include "QTTrack.h"
|
||
|
|
||
|
#include "OSMemory.h"
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Macros
|
||
|
//
|
||
|
#define DEBUG_PRINT(s) if(fDebug) qtss_printf s
|
||
|
#define DEEP_DEBUG_PRINT(s) if(fDeepDebug) qtss_printf s
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Constructors and destructors
|
||
|
//
|
||
|
QTTrack::QTTrack(QTFile * File, QTFile::AtomTOCEntry * Atom, Bool16 Debug, Bool16 DeepDebug)
|
||
|
: fDebug(Debug), fDeepDebug(DeepDebug),
|
||
|
fFile(File),
|
||
|
fIsInitialized(false),
|
||
|
fTrackHeaderAtom(NULL),
|
||
|
fTrackName(NULL),
|
||
|
fMediaHeaderAtom(NULL),
|
||
|
fEditListAtom(NULL), fDataReferenceAtom(NULL),
|
||
|
fTimeToSampleAtom(NULL),fCompTimeToSampleAtom(NULL), fSampleToChunkAtom(NULL), fSampleDescriptionAtom(NULL),
|
||
|
fChunkOffsetAtom(NULL), fSampleSizeAtom(NULL), fSyncSampleAtom(NULL),
|
||
|
fFirstEditMediaTime(0)
|
||
|
{
|
||
|
// Temporary vars
|
||
|
QTFile::AtomTOCEntry *tempTOCEntry;
|
||
|
|
||
|
//
|
||
|
// Make a copy of the TOC entry.
|
||
|
memcpy(&fTOCEntry, Atom, sizeof(QTFile::AtomTOCEntry));
|
||
|
|
||
|
//
|
||
|
// Load in the track header atom for this track.
|
||
|
if( !fFile->FindTOCEntry(":tkhd", &tempTOCEntry, &fTOCEntry) )
|
||
|
return;
|
||
|
|
||
|
fTrackHeaderAtom = NEW QTAtom_tkhd(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fTrackHeaderAtom == NULL )
|
||
|
return;
|
||
|
if( !fTrackHeaderAtom->Initialize() ) {
|
||
|
delete fTrackHeaderAtom;
|
||
|
fTrackHeaderAtom = NULL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
QTTrack::~QTTrack(void)
|
||
|
{
|
||
|
//
|
||
|
// Free our variables
|
||
|
if( fTrackHeaderAtom != NULL )
|
||
|
delete fTrackHeaderAtom;
|
||
|
if( fTrackName != NULL )
|
||
|
delete[] fTrackName;
|
||
|
|
||
|
if( fMediaHeaderAtom != NULL )
|
||
|
delete fMediaHeaderAtom;
|
||
|
|
||
|
if( fEditListAtom != NULL )
|
||
|
delete fEditListAtom;
|
||
|
if( fDataReferenceAtom != NULL )
|
||
|
delete fDataReferenceAtom;
|
||
|
|
||
|
if( fTimeToSampleAtom != NULL )
|
||
|
delete fTimeToSampleAtom;
|
||
|
if( fSampleToChunkAtom != NULL )
|
||
|
delete fSampleToChunkAtom;
|
||
|
if( fSampleDescriptionAtom != NULL )
|
||
|
delete fSampleDescriptionAtom;
|
||
|
if( fChunkOffsetAtom != NULL )
|
||
|
delete fChunkOffsetAtom;
|
||
|
if( fSampleSizeAtom != NULL )
|
||
|
delete fSampleSizeAtom;
|
||
|
if( fSyncSampleAtom != NULL )
|
||
|
delete fSyncSampleAtom;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Initialization functions
|
||
|
//
|
||
|
QTTrack::ErrorCode QTTrack::Initialize(void)
|
||
|
{
|
||
|
// Temporary vars
|
||
|
QTFile::AtomTOCEntry *tempTOCEntry;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Don't initialize more than once.
|
||
|
if( IsInitialized() )
|
||
|
return errNoError;
|
||
|
|
||
|
//
|
||
|
// Make sure that we were able to read in our track header atom.
|
||
|
if( fTrackHeaderAtom == NULL )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
//
|
||
|
// See if this track has a name and load it in.
|
||
|
if( fFile->FindTOCEntry(":udta:name", &tempTOCEntry, &fTOCEntry) ) {
|
||
|
fTrackName = NEW char[ (SInt32) (tempTOCEntry->AtomDataLength + 1) ];
|
||
|
if( fTrackName != NULL )
|
||
|
fFile->Read(tempTOCEntry->AtomDataPos, fTrackName, (UInt32) tempTOCEntry->AtomDataLength);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Load in the media header atom for this track.
|
||
|
if( !fFile->FindTOCEntry(":mdia:mdhd", &tempTOCEntry, &fTOCEntry) )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fMediaHeaderAtom = NEW QTAtom_mdhd(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fMediaHeaderAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fMediaHeaderAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Load in the edit list atom for this track.
|
||
|
DEEP_DEBUG_PRINT(("Searching track #%"_U32BITARG_" 'elst' atom.\n", GetTrackID()));
|
||
|
if( fFile->FindTOCEntry(":edts:elst", &tempTOCEntry, &fTOCEntry) ) {
|
||
|
fEditListAtom = NEW QTAtom_elst(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fEditListAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fEditListAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
//
|
||
|
// Compute the first edit's media time.
|
||
|
fFirstEditMediaTime = (UInt32)(( ( (Float64) (SInt64) GetFirstEditMovieTime())/ fFile->GetTimeScale()) * GetTimeScale());
|
||
|
} else {
|
||
|
fEditListAtom = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Load in the data reference atom for this track.
|
||
|
if( !fFile->FindTOCEntry(":mdia:minf:dinf:dref", &tempTOCEntry, &fTOCEntry) )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fDataReferenceAtom = NEW QTAtom_dref(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fDataReferenceAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fDataReferenceAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Load in the sample table atoms.
|
||
|
if( !fFile->FindTOCEntry(":mdia:minf:stbl:stts", &tempTOCEntry, &fTOCEntry) )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fTimeToSampleAtom = NEW QTAtom_stts(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fTimeToSampleAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fTimeToSampleAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
if( fFile->FindTOCEntry(":mdia:minf:stbl:ctts", &tempTOCEntry, &fTOCEntry) )
|
||
|
{
|
||
|
fCompTimeToSampleAtom = NEW QTAtom_ctts(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fCompTimeToSampleAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fCompTimeToSampleAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
}
|
||
|
|
||
|
if( !fFile->FindTOCEntry(":mdia:minf:stbl:stsc", &tempTOCEntry, &fTOCEntry) )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fSampleToChunkAtom = NEW QTAtom_stsc(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fSampleToChunkAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fSampleToChunkAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
|
||
|
if( !fFile->FindTOCEntry(":mdia:minf:stbl:stsd", &tempTOCEntry, &fTOCEntry) )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fSampleDescriptionAtom = NEW QTAtom_stsd(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fSampleDescriptionAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fSampleDescriptionAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
|
||
|
UInt16 offSetSize = 0;
|
||
|
Bool16 coFound = false;
|
||
|
|
||
|
if( fFile->FindTOCEntry(":mdia:minf:stbl:stco", &tempTOCEntry, &fTOCEntry) )
|
||
|
{
|
||
|
coFound = true;
|
||
|
offSetSize = 4;
|
||
|
} else if( fFile->FindTOCEntry(":mdia:minf:stbl:co64", &tempTOCEntry, &fTOCEntry) )
|
||
|
{
|
||
|
coFound = true;
|
||
|
offSetSize = 8;
|
||
|
}
|
||
|
|
||
|
if (!coFound)
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fChunkOffsetAtom = NEW QTAtom_stco(fFile, tempTOCEntry, offSetSize, fDebug, fDeepDebug);
|
||
|
if( fChunkOffsetAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fChunkOffsetAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
|
||
|
if( !fFile->FindTOCEntry(":mdia:minf:stbl:stsz", &tempTOCEntry, &fTOCEntry) )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
fSampleSizeAtom = NEW QTAtom_stsz(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fSampleSizeAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fSampleSizeAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
|
||
|
if( fFile->FindTOCEntry(":mdia:minf:stbl:stss", &tempTOCEntry, &fTOCEntry) ) {
|
||
|
fSyncSampleAtom = NEW QTAtom_stss(fFile, tempTOCEntry, fDebug, fDeepDebug);
|
||
|
if( fSyncSampleAtom == NULL )
|
||
|
return errInternalError;
|
||
|
if( !fSyncSampleAtom->Initialize() )
|
||
|
return errInvalidQuickTimeFile;
|
||
|
} else {
|
||
|
fSyncSampleAtom = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// This track has been successfully initialiazed.
|
||
|
fIsInitialized = true;
|
||
|
return errNoError;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Sample functions
|
||
|
//
|
||
|
Bool16 QTTrack::GetSampleInfo(UInt32 SampleNumber, UInt32 * const Length, UInt64 * const Offset, UInt32 * const SampleDescriptionIndex, QTAtom_stsc_SampleTableControlBlock * STCB)
|
||
|
{
|
||
|
|
||
|
Assert(STCB != NULL);
|
||
|
|
||
|
// qtss_printf("GetSampleInfo QTTrack SampleNumber = %"_S32BITARG_" \n", SampleNumber);
|
||
|
|
||
|
if (STCB->fGetSampleInfo_SampleNumber == SampleNumber && STCB->fGetSampleInfo_Length > 0)
|
||
|
{
|
||
|
// qtss_printf("----- GetSampleInfo Cache Hit QTTrack SampleNumber = %"_S32BITARG_" \n", SampleNumber);
|
||
|
|
||
|
if (Length) *Length = STCB->fGetSampleInfo_Length;
|
||
|
if (Offset) *Offset = STCB->fGetSampleInfo_Offset;
|
||
|
if (SampleDescriptionIndex) *SampleDescriptionIndex = STCB->fGetSampleInfo_SampleDescriptionIndex;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Temporary vars
|
||
|
UInt32 sampleLength = 0;
|
||
|
UInt32 sampleDescriptionIndex = 0;
|
||
|
// General vars
|
||
|
UInt32 ChunkNumber, SampleOffsetInChunk;
|
||
|
UInt64 sampleFileStartOffset = 0;
|
||
|
UInt64 ChunkOffset = 0;
|
||
|
|
||
|
|
||
|
// Locate this sample, compute its offset, and get its size.
|
||
|
if( !SampleNumberToChunkNumber(SampleNumber, &ChunkNumber, &sampleDescriptionIndex, &SampleOffsetInChunk, STCB) )
|
||
|
return false;
|
||
|
|
||
|
|
||
|
if( !fSampleSizeAtom->SampleSize(SampleNumber, &sampleLength) )
|
||
|
return false;
|
||
|
|
||
|
if (ChunkNumber == STCB->fGetSampleInfo_LastChunk && (SampleNumber == (STCB->fGetSampleInfo_SampleNumber+1) ) )
|
||
|
{
|
||
|
|
||
|
sampleFileStartOffset = STCB->fGetSampleInfo_Offset;
|
||
|
sampleFileStartOffset += STCB->fGetSampleInfo_Length;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( !fChunkOffsetAtom->ChunkOffset(ChunkNumber, &ChunkOffset) )
|
||
|
return false;
|
||
|
|
||
|
// Walk through all of the samples previous to this one, adding up
|
||
|
// their lengths to figure out what the offset from the start of
|
||
|
// the chunk to this sample is.
|
||
|
|
||
|
|
||
|
UInt32 tempSampleLength = fSampleSizeAtom->GetCommonSampleSize();
|
||
|
sampleFileStartOffset = ChunkOffset;
|
||
|
|
||
|
if (tempSampleLength > 0) // samples are the same size so just multiply to get size
|
||
|
{ sampleFileStartOffset += ( tempSampleLength * SampleOffsetInChunk );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( UInt32 CurSample = (SampleNumber - SampleOffsetInChunk);CurSample < SampleNumber; CurSample++)
|
||
|
{
|
||
|
// Get the length of this sample and add it to our offset.
|
||
|
if( !fSampleSizeAtom->SampleSize(CurSample, &tempSampleLength) )
|
||
|
return false;
|
||
|
sampleFileStartOffset += tempSampleLength;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
STCB->fGetSampleInfo_LastChunk = ChunkNumber;
|
||
|
STCB->fGetSampleInfo_LastChunkOffset = (UInt32) ChunkOffset;
|
||
|
STCB->fGetSampleInfo_SampleDescriptionIndex = sampleDescriptionIndex;
|
||
|
}
|
||
|
|
||
|
STCB->fGetSampleInfo_SampleNumber = SampleNumber;
|
||
|
STCB->fGetSampleInfo_Length = sampleLength;
|
||
|
STCB->fGetSampleInfo_Offset = sampleFileStartOffset;
|
||
|
|
||
|
if (Length != NULL) *Length = sampleLength;
|
||
|
if (Offset != NULL) *Offset = sampleFileStartOffset;
|
||
|
if (SampleDescriptionIndex != NULL) *SampleDescriptionIndex = sampleDescriptionIndex;
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// The sample was successfully located.
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
Bool16 QTTrack::GetSizeOfSamplesInChunk(UInt32 chunkNumber, UInt32 * const sizePtr, UInt32 * const firstSampleNumPtr, UInt32 * const lastSampleNumPtr, QTAtom_stsc_SampleTableControlBlock * stcbPtr)
|
||
|
{
|
||
|
UInt32 firstSample = 0;
|
||
|
UInt32 lastSample = 0;
|
||
|
UInt32 size = 0;
|
||
|
|
||
|
if (stcbPtr && stcbPtr->fGetSizeOfSamplesInChunk_chunkNumber == chunkNumber)
|
||
|
{
|
||
|
// qtss_printf("QTTrack::GetSizeOfSamplesInChunk cache hit %"_S32BITARG_" \n", chunkNumber);
|
||
|
if (firstSampleNumPtr != NULL) *firstSampleNumPtr = stcbPtr->fGetSizeOfSamplesInChunk_firstSample;
|
||
|
if (lastSampleNumPtr != NULL) *lastSampleNumPtr = stcbPtr->fGetSizeOfSamplesInChunk_lastSample;
|
||
|
if (sizePtr != NULL) *sizePtr = stcbPtr->fGetSizeOfSamplesInChunk_size;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Bool16 result = GetChunkFirstLastSample(chunkNumber, &firstSample, &lastSample, stcbPtr);
|
||
|
|
||
|
if (result && (sizePtr != NULL) )
|
||
|
{
|
||
|
result = SampleRangeSize(firstSample, lastSample, &size);
|
||
|
}
|
||
|
|
||
|
if (firstSampleNumPtr != NULL) *firstSampleNumPtr = firstSample;
|
||
|
if (lastSampleNumPtr != NULL) *lastSampleNumPtr = lastSample;
|
||
|
if (sizePtr != NULL) *sizePtr = size;
|
||
|
|
||
|
if (stcbPtr && result)
|
||
|
{
|
||
|
stcbPtr->fGetSizeOfSamplesInChunk_chunkNumber = chunkNumber;
|
||
|
stcbPtr->fGetSizeOfSamplesInChunk_firstSample = firstSample;
|
||
|
stcbPtr->fGetSizeOfSamplesInChunk_lastSample = lastSample;
|
||
|
stcbPtr->fGetSizeOfSamplesInChunk_size = size;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
Bool16 QTTrack::GetSample(UInt32 SampleNumber, char * Buffer, UInt32 * Length, QTFile_FileControlBlock * FCB, QTAtom_stsc_SampleTableControlBlock * STCB)
|
||
|
{
|
||
|
// General vars
|
||
|
UInt32 SampleDescriptionIndex;
|
||
|
UInt64 SampleOffset;
|
||
|
|
||
|
//
|
||
|
// Get the location and size of this sample.
|
||
|
if( !this->GetSampleInfo(SampleNumber, Length, &SampleOffset, &SampleDescriptionIndex, STCB) )
|
||
|
return false;
|
||
|
|
||
|
//
|
||
|
// Read in the sample
|
||
|
if( !fDataReferenceAtom->Read(SampleDescriptionIndex, SampleOffset, Buffer, *Length, FCB) )
|
||
|
return false;
|
||
|
|
||
|
//
|
||
|
// The sample was successfully read in.
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Debugging functions
|
||
|
//
|
||
|
void QTTrack::DumpTrack(void)
|
||
|
{
|
||
|
//
|
||
|
// Dump this track's information.
|
||
|
DEBUG_PRINT(("QTTrack::DumpTrack - Dumping track.\n"));
|
||
|
DEBUG_PRINT(("QTTrack::DumpTrack - ..Track name: \"%s\".\n", fTrackName ? fTrackName : "<untitled>"));
|
||
|
|
||
|
//
|
||
|
// Dump the sub-atoms of this track.
|
||
|
if( fTrackHeaderAtom != NULL )
|
||
|
fTrackHeaderAtom->DumpAtom();
|
||
|
|
||
|
if( fMediaHeaderAtom != NULL )
|
||
|
fMediaHeaderAtom->DumpAtom();
|
||
|
|
||
|
if( fDataReferenceAtom != NULL )
|
||
|
fDataReferenceAtom->DumpAtom();
|
||
|
|
||
|
if( fCompTimeToSampleAtom != NULL)
|
||
|
fCompTimeToSampleAtom->DumpAtom();
|
||
|
if( fTimeToSampleAtom != NULL )
|
||
|
fTimeToSampleAtom->DumpAtom();
|
||
|
if( fSampleToChunkAtom != NULL )
|
||
|
fSampleToChunkAtom->DumpAtom();
|
||
|
if( fSampleDescriptionAtom != NULL )
|
||
|
fSampleDescriptionAtom->DumpAtom();
|
||
|
if( fChunkOffsetAtom != NULL )
|
||
|
fChunkOffsetAtom->DumpAtom();
|
||
|
if( fSampleSizeAtom != NULL )
|
||
|
fSampleSizeAtom->DumpAtom();
|
||
|
}
|