322 lines
11 KiB
C++
322 lines
11 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@
|
|
*
|
|
*/
|
|
|
|
//
|
|
// QTFile:
|
|
// The central point of control for a file in the QuickTime File Format.
|
|
|
|
|
|
// -------------------------------------
|
|
// Includes
|
|
//
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "SafeStdLib.h"
|
|
#include <string.h>
|
|
|
|
#include "OSMutex.h"
|
|
#include "OSMemory.h"
|
|
|
|
#include "QTFile.h"
|
|
|
|
#include "QTAtom.h"
|
|
#include "QTAtom_mvhd.h"
|
|
#include "QTAtom_tkhd.h"
|
|
|
|
#include "QTTrack.h"
|
|
#include "QTHintTrack.h"
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Macros
|
|
//
|
|
//#define DEBUG_PRINT(s) if(fDebug) qtss_printf s
|
|
//#define DEEP_DEBUG_PRINT(s) if(fDeepDebug) qtss_printf s
|
|
|
|
|
|
// -------------------------------------
|
|
// Class state cookie
|
|
//
|
|
|
|
QTFile_FileControlBlock::QTFile_FileControlBlock(void)
|
|
: fDataFD(NULL), fDataBufferPool(NULL),
|
|
fDataBufferSize(0), fDataBufferPosStart(0), fDataBufferPosEnd(0),
|
|
fCurrentDataBuffer(NULL), fPreviousDataBuffer(NULL),
|
|
fCurrentDataBufferLength(0), fPreviousDataBufferLength(0),
|
|
fNumBlocksPerBuff(1),fNumBuffs(1),
|
|
fCacheEnabled(false)
|
|
|
|
{
|
|
}
|
|
|
|
QTFile_FileControlBlock::~QTFile_FileControlBlock(void)
|
|
{
|
|
if( fDataBufferPool != NULL )
|
|
delete[] fDataBufferPool;
|
|
#if DSS_USE_API_CALLBACKS
|
|
(void)QTSS_CloseFileObject(fDataFD);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void QTFile_FileControlBlock::Set( char * DataPath)
|
|
{
|
|
#if DSS_USE_API_CALLBACKS
|
|
(void)QTSS_OpenFileObject(DataPath, qtssOpenFileReadAhead, &fDataFD);
|
|
#else
|
|
fDataFD.Set(DataPath);
|
|
#endif
|
|
|
|
}
|
|
|
|
Bool16 QTFile_FileControlBlock::ReadInternal(FILE_SOURCE *dataFD, UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32 *inReadLenPtr)
|
|
{
|
|
UInt32 readLen = 0;
|
|
if (NULL != inReadLenPtr)
|
|
*inReadLenPtr = 0;
|
|
|
|
#if DSS_USE_API_CALLBACKS
|
|
QTSS_Error theErr = QTSS_Seek(*dataFD, inPosition);
|
|
if (theErr == QTSS_NoErr)
|
|
theErr = QTSS_Read(*dataFD, inBuffer, inLength, &readLen);
|
|
if (theErr != QTSS_NoErr)
|
|
return false;
|
|
#else
|
|
if( dataFD->Read(inPosition, inBuffer, inLength, &readLen) != OS_NoErr )
|
|
return false;
|
|
#endif
|
|
if (NULL != inReadLenPtr)
|
|
*inReadLenPtr = readLen;
|
|
|
|
if(inReadLenPtr == NULL && readLen != inLength) //external reads expect false if it fails to read all the requested data.
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
Bool16 QTFile_FileControlBlock::Read(FILE_SOURCE *dflt, UInt64 inPosition, void* inBuffer, UInt32 inLength)
|
|
{
|
|
// Temporary vars
|
|
UInt32 rcSize;
|
|
|
|
// General vars
|
|
FILE_SOURCE *dataFD;
|
|
|
|
// success or failure
|
|
Bool16 result = false;
|
|
|
|
// Get the file descriptor. If the FCB is NULL, or the descriptor in
|
|
// the FCB is -1, then we need to use the class' descriptor.
|
|
if (this->IsValid())
|
|
dataFD = &fDataFD;
|
|
else
|
|
dataFD = dflt;
|
|
|
|
if (
|
|
( !fCacheEnabled) || // file control block caching disabled
|
|
( inLength > fDataBufferSize ) || // too big for this cache
|
|
( inPosition < fDataBufferPosStart) // backing up
|
|
)
|
|
{
|
|
//if ( !fCacheEnabled) qtss_printf("QTFile_FileControlBlock::Read cache not enabled\n");
|
|
//if ( inLength > fDataBufferSize) qtss_printf("QTFile_FileControlBlock::Read read too big for cache len=%"_U32BITARG_" max%"_U32BITARG_"\n",inLength,fDataBufferSize);
|
|
//if ( inPosition < fDataBufferPosStart) qtss_printf("QTFile_FileControlBlock::Read backing up skipping cache missed by =%"_U32BITARG_" bytes\n", fDataBufferPosStart - inPosition);
|
|
result = this->ReadInternal(dataFD, inPosition, inBuffer, inLength);
|
|
goto done;
|
|
}
|
|
|
|
|
|
// Is the requested block of data in our data buffer? If not, read in the
|
|
// section of the file where this piece of data is.
|
|
if( (inPosition < fDataBufferPosStart) || ((inPosition + inLength) > fDataBufferPosEnd) )
|
|
{
|
|
// If this is a forward-moving, contiguous read, then we can keep the
|
|
// current buffer around.
|
|
|
|
if ( (fCurrentDataBufferLength != 0)
|
|
&& ((fDataBufferPosEnd - fCurrentDataBufferLength) <= inPosition)
|
|
&& ((fDataBufferPosEnd + fDataBufferSize) >= (inPosition + inLength))
|
|
)
|
|
{
|
|
// Temporary vars
|
|
char *TempDataBuffer;
|
|
|
|
//qtss_printf("QTFile_FileControlBlock::Read forward read inPosition=%"_64BITARG_"u fPreviousDataBuffer=%"_64BITARG_"u start=%"_64BITARG_"u\n",inPosition,fDataBufferPosStart,fDataBufferPosEnd);
|
|
|
|
// First, demote the current buffer.
|
|
fDataBufferPosStart += fPreviousDataBufferLength;
|
|
TempDataBuffer = fPreviousDataBuffer;
|
|
|
|
fPreviousDataBuffer = fCurrentDataBuffer;
|
|
fPreviousDataBufferLength = fCurrentDataBufferLength;
|
|
|
|
fCurrentDataBuffer = TempDataBuffer;
|
|
fCurrentDataBufferLength = 0;
|
|
|
|
//
|
|
// Then, fill the now-current buffer with data.
|
|
if (!this->ReadInternal(dataFD, fDataBufferPosEnd, fCurrentDataBuffer, fDataBufferSize, &rcSize) )
|
|
goto done;
|
|
|
|
//Assert(rcSize == fDataBufferSize);
|
|
fCurrentDataBufferLength = (UInt32)rcSize;
|
|
fDataBufferPosEnd += fCurrentDataBufferLength;
|
|
}
|
|
else
|
|
{
|
|
//qtss_printf("QTFile_FileControlBlock::Read not a contiguous forward read inPosition=%"_64BITARG_"u fPreviousDataBuffer=%"_64BITARG_"u missed=%"_64BITARG_"d\n ",inPosition,fDataBufferPosStart,(fDataBufferPosStart > inPosition) ? fDataBufferPosStart-inPosition: inPosition - fDataBufferPosStart);
|
|
|
|
// We need to play with our current and previous data buffers in
|
|
// order to skip around while reading.
|
|
fCurrentDataBuffer = fDataBufferPool;
|
|
fCurrentDataBufferLength = 0;
|
|
|
|
fPreviousDataBuffer = (char *)fDataBufferPool + fDataBufferSize;
|
|
fPreviousDataBufferLength = 0;
|
|
|
|
fDataBufferPosStart = inPosition;
|
|
|
|
if (! this->ReadInternal(dataFD, fDataBufferPosStart, fCurrentDataBuffer, fDataBufferSize, &rcSize) )
|
|
goto done;
|
|
|
|
//Assert(rcSize == fDataBufferSize);
|
|
fCurrentDataBufferLength = (UInt32)rcSize;
|
|
fDataBufferPosEnd = fDataBufferPosStart + fCurrentDataBufferLength;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the data out of our buffer(s).
|
|
{
|
|
// General vars
|
|
UInt64 ReadLength = inLength;
|
|
UInt64 ReadOffset = inPosition - fDataBufferPosStart;
|
|
|
|
//
|
|
// Figure out if doing a continuous copy would cause us to cross a
|
|
// buffer boundary.
|
|
if ( (inPosition < (fDataBufferPosStart + fPreviousDataBufferLength))
|
|
&& ((ReadOffset + ReadLength) > fPreviousDataBufferLength )
|
|
)
|
|
{
|
|
// Temporary vars
|
|
char *pBuffer = (char *)inBuffer;
|
|
|
|
//
|
|
// Read the first part of the block.
|
|
ReadLength = fDataBufferSize - ReadOffset;
|
|
if (ReadLength <= (fPreviousDataBufferLength - ReadOffset) )
|
|
::memcpy(pBuffer, fPreviousDataBuffer + ReadOffset, (UInt32) ReadLength);
|
|
else
|
|
goto done;
|
|
|
|
pBuffer += ReadLength;
|
|
|
|
//
|
|
// Read the last part of the block.
|
|
ReadLength = inLength - ReadLength;
|
|
if (ReadLength <= fCurrentDataBufferLength )
|
|
{ ::memcpy(pBuffer, fCurrentDataBuffer, (UInt32) ReadLength);
|
|
result = true;
|
|
}
|
|
//
|
|
// Or maybe this is a continuous copy out of the old buffer.
|
|
}
|
|
else if ( inPosition < (fDataBufferPosEnd - fCurrentDataBufferLength) )
|
|
{
|
|
if (ReadLength <= (fPreviousDataBufferLength - ReadOffset) )
|
|
{ ::memcpy(inBuffer, fPreviousDataBuffer + ReadOffset, (UInt32)ReadLength);
|
|
|
|
result = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReadOffset -= fPreviousDataBufferLength;
|
|
if (ReadLength <= (fCurrentDataBufferLength - ReadOffset) )
|
|
{ ::memcpy(inBuffer, fCurrentDataBuffer + ReadOffset, (UInt32) ReadLength);
|
|
result = true;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
done:
|
|
// We're done.
|
|
return result;
|
|
}
|
|
|
|
|
|
void QTFile_FileControlBlock::AdjustDataBufferBitRate(UInt32 inUnitSizeInK, UInt32 inFileBitRate, UInt32 inNumBuffSizeUnits, UInt32 inMaxBitRateBuffSizeInBlocks)
|
|
{
|
|
if (!fCacheEnabled)
|
|
return;
|
|
|
|
// General vars
|
|
UInt32 newDataBufferSizeInUnits = inNumBuffSizeUnits;
|
|
UInt32 newDataBufferSize = 0;
|
|
UInt32 newUnitSizeBytes = 0;
|
|
|
|
if (inUnitSizeInK < 1)
|
|
inUnitSizeInK = 32;
|
|
|
|
newUnitSizeBytes = inUnitSizeInK * 1024;
|
|
|
|
if (inMaxBitRateBuffSizeInBlocks < 1)
|
|
inMaxBitRateBuffSizeInBlocks = kMaxDefaultBlocks;
|
|
|
|
if (inFileBitRate == 0) // set the maximum
|
|
inFileBitRate = inMaxBitRateBuffSizeInBlocks * newUnitSizeBytes;
|
|
|
|
if (inNumBuffSizeUnits < 1) // calculate if not set to a given number
|
|
{
|
|
newDataBufferSizeInUnits = (inFileBitRate + newUnitSizeBytes) / newUnitSizeBytes; // 32k bytes of buffer for every 32k bits in rate
|
|
if( newDataBufferSizeInUnits > inMaxBitRateBuffSizeInBlocks ) // Limit the buffer size value to a reasonable maximum. should be pref
|
|
newDataBufferSizeInUnits = inMaxBitRateBuffSizeInBlocks;
|
|
}
|
|
|
|
newDataBufferSize = newDataBufferSizeInUnits * kBlockByteSize;
|
|
|
|
//qtss_printf("QTFile_FileControlBlock::AdjustDataBuffer private buffers NewDataBufferSizeInUnits =%"_U32BITARG_" NewDataBufferSize = %"_U32BITARG_"\n",newDataBufferSizeInUnits,newDataBufferSize);
|
|
|
|
// Free the old buffer.
|
|
delete[] fDataBufferPool;
|
|
fDataBufferSize = newDataBufferSize;
|
|
fDataBufferPool = NEW char[2 * newDataBufferSize]; // 2 contiguous buffers
|
|
fCurrentDataBuffer = fDataBufferPool;
|
|
fPreviousDataBuffer = (char *)fDataBufferPool + newDataBufferSize;
|
|
|
|
fDataBufferPosStart = 0;
|
|
fDataBufferPosEnd = 0;
|
|
fCurrentDataBufferLength = 0;
|
|
fPreviousDataBuffer = 0;
|
|
|
|
}
|