Darwin-Streaming-Server/QTFileLib/QTAtom_stsc.cpp

620 lines
22 KiB
C++
Raw Permalink Normal View History

/*
*
* @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@
*
*/
//
// QTAtom_stsc:
// The 'stsc' QTAtom class.
// -------------------------------------
// Includes
//
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#ifndef __Win32__
#include <sys/types.h>
#include <netinet/in.h>
#endif
#include "QTFile.h"
#include "QTAtom.h"
#include "QTAtom_stsc.h"
#include "OSMemory.h"
// -------------------------------------
// Constants
//
const int stscPos_VersionFlags = 0;
const int stscPos_NumEntries = 4;
const int stscPos_SampleTable = 8;
// -------------------------------------
// Macros
//
#define DEBUG_PRINT(s) if(fDebug) qtss_printf s
#define DEEP_DEBUG_PRINT(s) if(fDeepDebug) qtss_printf s
// -------------------------------------
// Class state cookie
//
QTAtom_stsc_SampleTableControlBlock::QTAtom_stsc_SampleTableControlBlock(void)
{
Reset();
}
QTAtom_stsc_SampleTableControlBlock::~QTAtom_stsc_SampleTableControlBlock(void)
{
}
void QTAtom_stsc_SampleTableControlBlock::Reset(void)
{
fCurEntry = 0;
fCurSample = 1;
fLastFirstChunk = 1;
fLastSamplesPerChunk = 1;
fLastSampleDescription = 0;
fLastFirstChunk_GetChunkFirstLastSample = 1;
fLastSamplesPerChunk_GetChunkFirstLastSample = 1;
fLastTotalSamples_GetChunkFirstLastSample = 0;
fCurEntry_GetChunkFirstLastSample = 0;
chunkNumber_GetChunkFirstLastSample = 0;
firstSample_GetChunkFirstLastSample = 0;
lastSample_GetChunkFirstLastSample = 0;
fCurEntry_SampleToChunkInfo = 0;
fCurSample_SampleToChunkInfo = 1;
fLastFirstChunk_SampleToChunkInfo = 1;
fLastSamplesPerChunk_SampleToChunkInfo = 1;
fLastSampleDescription_SampleToChunkInfo = 0;
fFirstSampleNumber_SampleToChunkInfo = 0;
fFirstSamplesPerChunk_SampleToChunkInfo = 0;
fFirstChunkNumber_SampleToChunkInfo = 0;
fFirstSampleDescriptionIndex_SampleToChunkInfo = 0;
fFirstSampleOffsetInChunk_SampleToChunkInfo = 0;
fGetSampleInfo_SampleNumber = 0;
fGetSampleInfo_Length = 0;
fGetSampleInfo_SampleDescriptionIndex = 0;
fGetSampleInfo_Offset = 0;
fGetSampleInfo_LastChunk = 0;
fGetSampleInfo_LastChunkOffset = 0;
fGetSizeOfSamplesInChunk_chunkNumber = 0;
fGetSizeOfSamplesInChunk_firstSample = 0;
fGetSizeOfSamplesInChunk_lastSample = 0;
fGetSizeOfSamplesInChunk_size = 0;
}
// -------------------------------------
// Constructors and destructors
//
QTAtom_stsc::QTAtom_stsc(QTFile * File, QTFile::AtomTOCEntry * TOCEntry, Bool16 Debug, Bool16 DeepDebug)
: QTAtom(File, TOCEntry, Debug, DeepDebug),
fNumEntries(0), fSampleToChunkTable(NULL), fTableSize(0)
{
}
QTAtom_stsc::~QTAtom_stsc(void)
{
//
// Free our variables.
#if MMAP_TABLES
if( fSampleToChunkTable != NULL )
this->UnMap(fSampleToChunkTable, fTableSize);
#else
if( fSampleToChunkTable != NULL )
delete[] fSampleToChunkTable;
#endif
}
// -------------------------------------
// Initialization functions
//
Bool16 QTAtom_stsc::Initialize(void)
{
// Temporary vars
UInt32 tempInt32;
//
// Parse this atom's fields.
ReadInt32(stscPos_VersionFlags, &tempInt32);
fVersion = (UInt8)((tempInt32 >> 24) & 0x000000ff);
fFlags = tempInt32 & 0x00ffffff;
ReadInt32(stscPos_NumEntries, &fNumEntries);
//
// Validate the size of the sample table.
if( (UInt32)(fNumEntries * 12) != (fTOCEntry.AtomDataLength - 8) )
return false;
//
// Read in the sample-to-chunk table.
#if MMAP_TABLES
fTableSize = fNumEntries * 12;
fSampleToChunkTable = this->MemMap(stscPos_SampleTable, fTableSize);
if( fSampleToChunkTable == NULL )
return false;
#else
fSampleToChunkTable = NEW char[fNumEntries * 12];
if( fSampleToChunkTable == NULL )
return false;
ReadBytes(stscPos_SampleTable, fSampleToChunkTable, fNumEntries * 12);
#endif
//
// This atom has been successfully read in.
return true;
}
// -------------------------------------
// Accessors
//
Bool16 QTAtom_stsc::GetChunkFirstLastSample(UInt32 chunkNumber, UInt32 *firstSample, UInt32 *lastSample, QTAtom_stsc_SampleTableControlBlock *STCB)
{
// Temporary state var
QTAtom_stsc_SampleTableControlBlock *tempSTCB = NULL;
// General vars
UInt32 prevFirstChunk = 0, thisFirstChunk = 0;
UInt32 totalSamples = 0;
UInt32 numChunks = 0;
UInt32 numSamplesInChunks = 0;
UInt32 prevSamplesPerChunk = 0;
UInt32 samplesPerChunk = 0;
// qtss_printf("GetChunkFirstLastSample chunk = %d STCB->chunkNumber_GetChunkFirstLastSample= %d \n",chunkNumber,STCB->chunkNumber_GetChunkFirstLastSample);
if( STCB == NULL )
{
// qtss_printf(" QTAtom_stsc::GetChunkFirstLastSample (NULL == STCB) \n");
tempSTCB = NEW QTAtom_stsc_SampleTableControlBlock;
STCB = tempSTCB;
}
if ( (STCB->chunkNumber_GetChunkFirstLastSample == chunkNumber) && (STCB->lastSample_GetChunkFirstLastSample > 0) )
{
// qtss_printf("GetChunkFirstLastSample cache hit chunk = %d\n",chunkNumber);
if (firstSample) *firstSample = STCB->firstSample_GetChunkFirstLastSample;
if (lastSample) *lastSample = STCB->lastSample_GetChunkFirstLastSample;
goto GetChunkFirstLastSample_Done;
}
if (STCB->fCurEntry_GetChunkFirstLastSample > chunkNumber)
{
// qtss_printf(" QTAtom_stsc::GetChunkFirstLastSample missed Cache Loop \n");
STCB->fLastFirstChunk_GetChunkFirstLastSample = 1;
STCB->fLastSamplesPerChunk_GetChunkFirstLastSample = 1;
STCB->fLastTotalSamples_GetChunkFirstLastSample = 0;
STCB->fCurEntry_GetChunkFirstLastSample = 0;
STCB->chunkNumber_GetChunkFirstLastSample = 0;
STCB->firstSample_GetChunkFirstLastSample = 0;
STCB->lastSample_GetChunkFirstLastSample = 0;
}
if (STCB->fCurEntry_GetChunkFirstLastSample > 0)
{
// qtss_printf("GetChunkFirstLastSample cached loop chunk start = %d look for chunk = %"_S32BITARG_"\n",STCB->fLastFirstChunk_GetChunkFirstLastSample,chunkNumber);
samplesPerChunk = STCB->fLastSamplesPerChunk_GetChunkFirstLastSample;
totalSamples = STCB->fLastTotalSamples_GetChunkFirstLastSample;
thisFirstChunk = STCB->fLastFirstChunk_GetChunkFirstLastSample;
}
//
// Linearly search through the sample table until we find the chunk
// which contains the given sample.
if (fNumEntries == 1)
{
memcpy(&samplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry_GetChunkFirstLastSample * 12) + 4, 4);
samplesPerChunk = ntohl(samplesPerChunk);
prevSamplesPerChunk = ((chunkNumber -1 ) * samplesPerChunk);
totalSamples = chunkNumber * samplesPerChunk;
}
else
for( ; STCB->fCurEntry_GetChunkFirstLastSample < fNumEntries; STCB->fCurEntry_GetChunkFirstLastSample++ )
{
// Copy this entry's fields.
prevSamplesPerChunk = samplesPerChunk;
prevFirstChunk = thisFirstChunk;
memcpy(&thisFirstChunk, fSampleToChunkTable + (STCB->fCurEntry_GetChunkFirstLastSample * 12) + 0, 4);
thisFirstChunk = ntohl(thisFirstChunk);
memcpy(&samplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry_GetChunkFirstLastSample * 12) + 4, 4);
samplesPerChunk = ntohl(samplesPerChunk);
if (prevSamplesPerChunk == 0)
prevSamplesPerChunk = samplesPerChunk;
if ( chunkNumber < thisFirstChunk ) // found chunk in group
{
// qtss_printf("found chunk in group numEntries = %"_S32BITARG_" this chunk = %"_S32BITARG_" \n",fNumEntries, chunkNumber);
numSamplesInChunks = (chunkNumber - prevFirstChunk) * prevSamplesPerChunk;
totalSamples += numSamplesInChunks;
prevSamplesPerChunk = totalSamples - prevSamplesPerChunk;
break;
}
if ( chunkNumber == thisFirstChunk ) // found chunk
{
numSamplesInChunks = samplesPerChunk;
totalSamples += numSamplesInChunks;
prevSamplesPerChunk = totalSamples - samplesPerChunk;
break;
}
numChunks = chunkNumber - prevFirstChunk;
numSamplesInChunks = numChunks * samplesPerChunk;
totalSamples += numSamplesInChunks;
//
// We have yet to find the sample; update our CurSample counter
// and move on.
STCB->fLastFirstChunk_GetChunkFirstLastSample = thisFirstChunk;
STCB->fLastSamplesPerChunk_GetChunkFirstLastSample = samplesPerChunk;
STCB->fLastTotalSamples_GetChunkFirstLastSample = totalSamples;
}
if (firstSample) *firstSample = prevSamplesPerChunk + 1;
if (lastSample) *lastSample = totalSamples;
// qtss_printf("Get Chunk %"_S32BITARG_" First %"_S32BITARG_" Last %"_S32BITARG_" prevSamplesPerChunk %"_S32BITARG_" samplesPerChunk %"_S32BITARG_"\n",chunkNumber,*firstSample,*lastSample,prevSamplesPerChunk,samplesPerChunk);
STCB->chunkNumber_GetChunkFirstLastSample = chunkNumber;
STCB->firstSample_GetChunkFirstLastSample = prevSamplesPerChunk + 1;
STCB->lastSample_GetChunkFirstLastSample = totalSamples;
GetChunkFirstLastSample_Done:
delete tempSTCB;
return true;
}
UInt32 QTAtom_stsc::GetChunkFirstSample(UInt32 chunkNumber)
{
// Temporary state var
QTAtom_stsc_SampleTableControlBlock localSTCB;
QTAtom_stsc_SampleTableControlBlock *STCB = &localSTCB;
// General vars
UInt32 prevFirstChunk = 0, thisFirstChunk = 0, sampleDescription = 0;
UInt32 totalSamples = 1;
UInt32 numChunks = 0;
UInt32 numSamplesInChunks = 0;
UInt32 thisChunk = 0;
UInt32 prevSamplesPerChunk = 0;
UInt32 samplesPerChunk = 0;
//
// Linearly search through the sample table until we find the chunk
// which contains the given sample.
for( ; STCB->fCurEntry < fNumEntries; STCB->fCurEntry++ )
{
// Copy this entry's fields.
prevSamplesPerChunk = samplesPerChunk;
prevFirstChunk = thisFirstChunk;
memcpy(&thisFirstChunk, fSampleToChunkTable + (STCB->fCurEntry * 12) + 0, 4);
thisFirstChunk = ntohl(thisFirstChunk);
memcpy(&samplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry * 12) + 4, 4);
samplesPerChunk = ntohl(samplesPerChunk);
memcpy(&sampleDescription, fSampleToChunkTable + (STCB->fCurEntry * 12) + 8, 4);
sampleDescription = ntohl(sampleDescription);
thisChunk = thisFirstChunk;
numChunks = thisFirstChunk - prevFirstChunk;
if ( chunkNumber <= thisFirstChunk ) // found chunk in group
{
numChunks = chunkNumber - prevFirstChunk;
numSamplesInChunks = numChunks * prevSamplesPerChunk;
totalSamples += numSamplesInChunks;
break;
}
numChunks = thisFirstChunk - prevFirstChunk;
numSamplesInChunks = numChunks * prevSamplesPerChunk;
totalSamples += numSamplesInChunks;
//
// We have yet to find the sample; update our CurSample counter
// and move on.
STCB->fLastFirstChunk = thisFirstChunk;
STCB->fLastSampleDescription = sampleDescription;
STCB->fLastSamplesPerChunk = samplesPerChunk;
}
return totalSamples;
}
//UInt32 gstscCacheCount = 0;
//UInt32 gstscCallCount = 0;
Bool16 QTAtom_stsc::SampleToChunkInfo(UInt32 SampleNumber, UInt32 *samplesPerChunk, UInt32 *ChunkNumber, UInt32 *SampleDescriptionIndex, UInt32 *SampleOffsetInChunk, QTAtom_stsc_SampleTableControlBlock * STCB)
{
// Temporary state var
QTAtom_stsc_SampleTableControlBlock *tempSTCB = NULL;
// General vars
UInt32 NewCurSample;
UInt32 FirstChunk = 0, SamplesPerChunk = 0, SampleDescription = 0;
Bool16 missedCache = false;
if (STCB == NULL )
{
// qtss_printf(" QTAtom_stsc::SampleToChunkInfo (NULL == STCB) \n");
tempSTCB = NEW QTAtom_stsc_SampleTableControlBlock;
STCB = tempSTCB;
}
UInt32 aChunkNumber = 0;
UInt32 aSampleDescriptionIndex = 0;
UInt32 aSampleOffsetInChunk = 0;
UInt32 aSamplesPerChunk = 0;
/*
gstscCallCount ++;
if (gstscCallCount == 1000)
{
qtss_printf("QTAtom_stsc::SampleToChunkInfo #calls = %"_S32BITARG_", cache hits = %"_S32BITARG_" \n",gstscCallCount, gstscCacheCount);
gstscCacheCount = 0;
gstscCallCount = 0;
}
*/
//
// Use a temporary STCB if we weren't given one. We cannot use a default
// STCB as we would have no way to know when we are seeking around in the
// movie.
// qtss_printf("------ QTAtom_stsc::SampleToChunkInfo SampleNumber = %"_S32BITARG_"\n",SampleNumber);
if (STCB->fFirstSampleNumber_SampleToChunkInfo == SampleNumber)
{
// qtss_printf("------ QTAtom_stsc::SampleToChunkInfo cache hit SampleNumber = %"_S32BITARG_"\n",SampleNumber);
// gstscCacheCount ++;
aChunkNumber = STCB->fFirstChunkNumber_SampleToChunkInfo;
aSampleDescriptionIndex = STCB->fFirstSampleDescriptionIndex_SampleToChunkInfo;
aSamplesPerChunk = STCB->fFirstSamplesPerChunk_SampleToChunkInfo;
aSampleOffsetInChunk = STCB->fFirstSampleOffsetInChunk_SampleToChunkInfo;
if( ChunkNumber != NULL )
*ChunkNumber = aChunkNumber;
if( SampleDescriptionIndex != NULL )
*SampleDescriptionIndex = aSampleDescriptionIndex;
if( SampleOffsetInChunk != NULL )
*SampleOffsetInChunk = aSampleOffsetInChunk;
if (NULL != samplesPerChunk)
*samplesPerChunk = aSamplesPerChunk;
goto done;
}
// qtss_printf("QTAtom_stsc::SampleToChunkInfo missed cache SampleNumber = %"_S32BITARG_"\n",SampleNumber);
//
// Assume that this sample came out of the last chunk.
aChunkNumber = STCB->fLastFirstChunk_SampleToChunkInfo + ((SampleNumber - STCB->fCurSample_SampleToChunkInfo) / STCB->fLastSamplesPerChunk_SampleToChunkInfo) ;
aSampleDescriptionIndex = STCB->fLastSampleDescription_SampleToChunkInfo;
aSampleOffsetInChunk = SampleNumber - (STCB->fCurSample_SampleToChunkInfo + ((aChunkNumber - STCB->fLastFirstChunk_SampleToChunkInfo) * STCB->fLastSamplesPerChunk_SampleToChunkInfo));
aSamplesPerChunk = STCB->fLastSamplesPerChunk_SampleToChunkInfo;
if( ChunkNumber != NULL )
*ChunkNumber = aChunkNumber;
if( SampleDescriptionIndex != NULL )
*SampleDescriptionIndex = aSampleDescriptionIndex;
if( SampleOffsetInChunk != NULL )
*SampleOffsetInChunk = aSampleOffsetInChunk;
if (NULL != samplesPerChunk)
*samplesPerChunk = aSamplesPerChunk;
//
// Linear search through the sample table until we find the chunk
// which contains the given sample.
if (STCB->fCurSample_SampleToChunkInfo > SampleNumber) // we missed the cache start over
{
missedCache = true;
// qtss_printf("missed loop Cache!! STCB = %"_S32BITARG_" STCB->fCurSample_SampleToChunkInfo = %"_S32BITARG_" > SampleNumber = %"_S32BITARG_" \n",STCB, STCB->fCurSample_SampleToChunkInfo, SampleNumber);
STCB->fCurEntry_SampleToChunkInfo = 0;
STCB->fCurSample_SampleToChunkInfo = 1;
STCB->fLastFirstChunk_SampleToChunkInfo = 1;
STCB->fLastSamplesPerChunk_SampleToChunkInfo = 1;
STCB->fLastSampleDescription_SampleToChunkInfo = 0;
}
for(; STCB->fCurEntry_SampleToChunkInfo < fNumEntries; STCB->fCurEntry_SampleToChunkInfo++ ) {
//
// Copy this entry's fields.
memcpy(&FirstChunk, fSampleToChunkTable + (STCB->fCurEntry_SampleToChunkInfo * 12) + 0, 4);
FirstChunk = ntohl(FirstChunk);
memcpy(&SamplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry_SampleToChunkInfo * 12) + 4, 4);
SamplesPerChunk = ntohl(SamplesPerChunk);
memcpy(&SampleDescription, fSampleToChunkTable + (STCB->fCurEntry_SampleToChunkInfo * 12) + 8, 4);
SampleDescription = ntohl(SampleDescription);
//
// Check to see if the sample was actually in the last chunk and
// return if it was.
NewCurSample = STCB->fCurSample_SampleToChunkInfo + (FirstChunk - STCB->fLastFirstChunk_SampleToChunkInfo) * STCB->fLastSamplesPerChunk_SampleToChunkInfo ;
if( SampleNumber < NewCurSample )
{
if( ChunkNumber != NULL )
*ChunkNumber = aChunkNumber;
if( SampleDescriptionIndex != NULL )
*SampleDescriptionIndex = aSampleDescriptionIndex;
if( SampleOffsetInChunk != NULL )
*SampleOffsetInChunk = aSampleOffsetInChunk;
if (NULL != samplesPerChunk)
*samplesPerChunk = aSamplesPerChunk;
if (SampleNumber == 1 || missedCache)
{
// qtss_printf("QTAtom_stsc::SampleToChunkInfo (SampleNumber == %"_S32BITARG_") \n",SampleNumber);
STCB->fFirstChunkNumber_SampleToChunkInfo = aChunkNumber;
STCB->fFirstSampleDescriptionIndex_SampleToChunkInfo = aSampleDescriptionIndex;
STCB->fFirstSamplesPerChunk_SampleToChunkInfo = aSamplesPerChunk;
STCB->fFirstSampleOffsetInChunk_SampleToChunkInfo = aSampleOffsetInChunk;
STCB->fFirstSampleNumber_SampleToChunkInfo = SampleNumber;
}
// qtss_printf("GetSample Info in for loop returning offset %"_S32BITARG_" \n",aSampleOffsetInChunk);
goto done;
}
STCB->fCurSample_SampleToChunkInfo = NewCurSample;
//
// Assume that the sample will be in this chunk.
aChunkNumber = FirstChunk + ((SampleNumber - STCB->fCurSample_SampleToChunkInfo) / SamplesPerChunk) ;
aSampleDescriptionIndex = SampleDescription;
aSampleOffsetInChunk = SampleNumber - (STCB->fCurSample_SampleToChunkInfo + ((aChunkNumber - FirstChunk) * SamplesPerChunk));
aSamplesPerChunk = SamplesPerChunk;
//
// We have yet to find the sample; update our CurSample counter
// and move on.
STCB->fLastFirstChunk_SampleToChunkInfo = FirstChunk;
STCB->fLastSampleDescription_SampleToChunkInfo = SampleDescription;
STCB->fLastSamplesPerChunk_SampleToChunkInfo = SamplesPerChunk;
}
// qtss_printf("GetSample Info fall out of loop returning offset%"_S32BITARG_" \n",aSampleOffsetInChunk);
//
// Falling out of the loop means that the sample is in the last chunk of
// the table.
if( ChunkNumber != NULL )
*ChunkNumber = aChunkNumber;
if( SampleDescriptionIndex != NULL )
*SampleDescriptionIndex = aSampleDescriptionIndex;
if( SampleOffsetInChunk != NULL )
*SampleOffsetInChunk = aSampleOffsetInChunk;
if (NULL != samplesPerChunk)
*samplesPerChunk = aSamplesPerChunk;
if (SampleNumber == 1 || missedCache)
{
STCB->fFirstChunkNumber_SampleToChunkInfo = aChunkNumber;
STCB->fFirstSampleDescriptionIndex_SampleToChunkInfo = aSampleDescriptionIndex;
STCB->fFirstSamplesPerChunk_SampleToChunkInfo = aSamplesPerChunk;
STCB->fFirstSampleOffsetInChunk_SampleToChunkInfo = aSampleOffsetInChunk;
STCB->fFirstSampleNumber_SampleToChunkInfo = SampleNumber;
}
done:
delete tempSTCB;
return true;
}
// -------------------------------------
// Debugging functions
//
void QTAtom_stsc::DumpAtom(void)
{
DEBUG_PRINT(("QTAtom_stsc::DumpAtom - Dumping atom.\n"));
DEBUG_PRINT(("QTAtom_stsc::DumpAtom - ..Number of STC entries: %"_S32BITARG_"\n", fNumEntries));
}
void QTAtom_stsc::DumpTable(void)
{
// General vars
UInt32 FirstChunk = 0, SamplesPerChunk = 0, SampleDescription = 0;
//
// Print out a header.
qtss_printf("-- Sample-to-Chunk table -------------------------------------------------------\n");
qtss_printf("\n");
qtss_printf(" Sample Num FirstChunk Samples/Chunk Sample Description\n");
qtss_printf(" ---------- ---------- ------------- ------------------\n");
//
// Print the table.
for( UInt32 CurEntry = 0; CurEntry < fNumEntries; CurEntry++ ) {
//
// Copy this entry's fields.
memcpy(&FirstChunk, fSampleToChunkTable + (CurEntry * 12) + 0, 4);
FirstChunk = ntohl(FirstChunk);
memcpy(&SamplesPerChunk, fSampleToChunkTable + (CurEntry * 12) + 4, 4);
SamplesPerChunk = ntohl(SamplesPerChunk);
memcpy(&SampleDescription, fSampleToChunkTable + (CurEntry * 12) + 8, 4);
SampleDescription = ntohl(SampleDescription);
//
// Print out a listing.
qtss_printf(" %10"_U32BITARG_" : %10"_U32BITARG_" %10"_U32BITARG_" %10"_U32BITARG_"\n",
CurEntry+1, FirstChunk, SamplesPerChunk, SampleDescription);
}
}