/*****************************************************************
|
| AP4 - Fragment Sample Table
|
| Copyright 2014-2016 Aleksoid1978
|
****************************************************************/
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include "Ap4.h"
#include "Ap4FragmentSampleTable.h"
/*----------------------------------------------------------------------
| constants
+---------------------------------------------------------------------*/
const AP4_UI32 AP4_FRAG_FLAG_SAMPLE_IS_DIFFERENCE = 0x00010000;
const AP4_UI32 AP4_FRAG_FLAG_SAMPLE_FLAG_DEPENDS_YES = 0x01000000;
/*----------------------------------------------------------------------
| AP4_FragmentSampleTable::AP4_FragmentSampleTable
+---------------------------------------------------------------------*/
AP4_FragmentSampleTable::AP4_FragmentSampleTable() :
m_Duration(0)
{
}
/*----------------------------------------------------------------------
| AP4_FragmentSampleTable::GetSample
+---------------------------------------------------------------------*/
AP4_Result
AP4_FragmentSampleTable::GetSample(AP4_Ordinal index, AP4_Sample& sample)
{
if (index >= m_FragmentSamples.ItemCount()) return AP4_ERROR_OUT_OF_RANGE;
// copy the sample
sample = m_FragmentSamples[index];
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_FragmentSampleTable::AddTrun
+---------------------------------------------------------------------*/
AP4_Result
AP4_FragmentSampleTable::AddTrun(AP4_TrunAtom* trun, AP4_TfhdAtom* tfhd, AP4_TrexAtom* trex, AP4_ByteStream& stream, AP4_UI64& dts_origin, AP4_Offset moof_offset, AP4_Offset& mdat_payload_offset)
{
if (trun) {
AP4_Flags tfhd_flags = tfhd->GetFlags();
AP4_Flags trun_flags = trun->GetFlags();
// update the number of samples
AP4_Cardinal start = m_FragmentSamples.ItemCount();
m_FragmentSamples.SetItemCount(start + trun->GetEntries().ItemCount());
// base data offset
AP4_Offset data_offset = 0;
if (tfhd_flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
data_offset = tfhd->GetBaseDataOffset();
} else {
data_offset = moof_offset;
}
if (trun_flags & AP4_TRUN_FLAG_DATA_OFFSET_PRESENT) {
data_offset += trun->GetDataOffset();
}
// MS hack
if (data_offset == moof_offset) {
data_offset = mdat_payload_offset;
} else {
mdat_payload_offset = data_offset;
}
// sample description index
AP4_UI32 sample_description_index = 0;
if (tfhd_flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) {
sample_description_index = tfhd->GetSampleDescriptionIndex();
} else if (trex) {
sample_description_index = trex->GetDefaultSampleDescriptionIndex();
}
// default sample size
AP4_UI32 default_sample_size = 0;
if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
default_sample_size = tfhd->GetDefaultSampleSize();
} else if (trex) {
default_sample_size = trex->GetDefaultSampleSize();
}
// default sample duration
AP4_UI32 default_sample_duration = 0;
if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) {
default_sample_duration = tfhd->GetDefaultSampleDuration();
} else if (trex) {
default_sample_duration = trex->GetDefaultSampleDuration();
}
// default sample flags
AP4_UI32 default_sample_flags = 0;
if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) {
default_sample_flags = tfhd->GetDefaultSampleFlags();
} else if (trex) {
default_sample_flags = trex->GetDefaultSampleFlags();
}
bool found_keyframe = false;
// parse all trun entries to setup the samples
AP4_UI64 dts = dts_origin ? dts_origin : m_Duration;
for (AP4_Cardinal i = 0; i < trun->GetEntries().ItemCount(); i++) {
const AP4_TrunAtom::Entry& entry = trun->GetEntries()[i];
AP4_Sample& sample = m_FragmentSamples[start + i];
// sample size
if (trun_flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
sample.SetSize(entry.sample_size);
} else {
sample.SetSize(default_sample_size);
}
mdat_payload_offset += sample.GetSize(); // update the payload offset
// sample duration
if (trun_flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
sample.SetDuration(entry.sample_duration);
} else {
sample.SetDuration(default_sample_duration);
}
// sample flags
AP4_UI32 sample_flags = default_sample_flags;
if (i == 0 && (trun_flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT)) {
sample_flags = trun->GetFirstSampleFlags();
} else if (trun_flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
sample_flags = entry.sample_flags;
}
if (!found_keyframe && !(sample_flags & (AP4_FRAG_FLAG_SAMPLE_IS_DIFFERENCE | AP4_FRAG_FLAG_SAMPLE_FLAG_DEPENDS_YES))) {
found_keyframe = true;
sample.SetSync(true);
} else {
sample.SetSync(false);
}
// sample description index
if (sample_description_index >= 1) {
sample.SetDescriptionIndex(sample_description_index - 1);
}
// data stream
sample.SetDataStream(stream);
// data offset
sample.SetOffset(data_offset);
data_offset += sample.GetSize();
// dts and cts
sample.SetDts(dts);
AP4_SI32 offset = 0;
if (trun_flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
offset = entry.sample_composition_time_offset;
}
sample.SetCts(dts + offset);
// update the counters
dts += sample.GetDuration();
m_Duration += sample.GetDuration();
}
// update the dts
dts_origin = dts;
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_FragmentSampleTable::GetSampleIndexForTimeStamp
+---------------------------------------------------------------------*/
AP4_Result
AP4_FragmentSampleTable::GetSampleIndexForTimeStamp(AP4_SI64 ts, AP4_Ordinal& index)
{
for (AP4_Ordinal i = 0; i < m_FragmentSamples.ItemCount(); i++) {
if (m_FragmentSamples[i].GetCts() > ts) {
index = i == 0 ? i : i - 1;
return AP4_SUCCESS;
}
}
return AP4_FAILURE;
}
/*----------------------------------------------------------------------
| AP4_FragmentSampleTable::Clear
+---------------------------------------------------------------------*/
void
AP4_FragmentSampleTable::Clear()
{
m_FragmentSamples.Clear(true);
m_Duration = 0;
}
↑ V1051 Consider checking for misprints. It's possible that the 'sample_flags' should be checked here.