Darwin-Streaming-Server/QTFileLib/QTTrack.cpp
Darren VanBuren 849723c9cf Add even more of the source
This should be about everything needed to build so far?
2017-03-07 17:14:16 -08:00

485 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();
}