📄 umc_mp4_spl.cpp
字号:
/*//////////////////////////////////////////////////////////////////////////////
//
// INTEL CORPORATION PROPRIETARY INFORMATION
// This software is supplied under the terms of a license agreement or
// nondisclosure agreement with Intel Corporation and may not be copied
// or disclosed except in accordance with the terms of that agreement.
// Copyright(c) 2004-2007 Intel Corporation. All Rights Reserved.
//
*/
#include <ipps.h>
#include "ippdefs.h"
#include "vm_thread.h"
#include "vm_types.h"
#include "vm_time.h"
#include "umc_media_data.h"
#include "umc_cyclic_buffer.h"
#include "mp4cmn_config.h"
#include "bstream.h"
#include "umc_mp4_spl.h"
#include "umc_automatic_mutex.h"
#include "umc_structures.h"
namespace UMC
{
Splitter *CreateMPEG4Splitter() { return (new MP4Splitter()); }
MP4Splitter::MP4Splitter():
SplitterBase(),
m_nFragPosEnd(0),
m_pLastPTS(NULL)
{
}
MP4Splitter::~MP4Splitter()
{
Close();
}
Status MP4Splitter::CheckInit()
{
// already initialized
if ((m_pReader == NULL) ||
(!m_ReaderMutex.IsInited()) ||
(m_pTrackIndex == NULL) ||
(m_ppMediaBuffer == NULL) ||
(m_ppLockedFrame == NULL) ||
(m_pInfo == NULL))
return UMC_ERR_NOT_INITIALIZED;
return UMC_OK;
}
Status MP4Splitter::Clear_track(T_trak_data* pTrak)
{
Ipp32u j = 0;
if (pTrak) {
for (j = 0; j < pTrak->mdia.minf.stbl.stsd.total_entries; j++) {
if (!pTrak->mdia.minf.stbl.stsd.table[j].esds.flags) {
if (pTrak->mdia.minf.stbl.stsd.table[j].esds.decoderConfigLen) {
ippsFree(pTrak->mdia.minf.stbl.stsd.table[j].esds.decoderConfig);
pTrak->mdia.minf.stbl.stsd.table[j].esds.decoderConfig = NULL;
}
}
if (pTrak->mdia.minf.stbl.stsd.table[j].avcC.decoderConfigLen) {
ippsFree(pTrak->mdia.minf.stbl.stsd.table[j].avcC.decoderConfig);
pTrak->mdia.minf.stbl.stsd.table[j].avcC.decoderConfig = NULL;
}
if (pTrak->mdia.minf.stbl.stsd.table[j].damr.decoderConfigLen) {
ippsFree(pTrak->mdia.minf.stbl.stsd.table[j].damr.decoderConfig);
pTrak->mdia.minf.stbl.stsd.table[j].damr.decoderConfig = NULL;
}
}
if (!(pTrak->mdia.minf.stbl.stsz.flags)) {
if (!pTrak->mdia.minf.stbl.stsz.sample_size) {
if (pTrak->mdia.minf.stbl.stsz.table)
ippsFree(pTrak->mdia.minf.stbl.stsz.table);
pTrak->mdia.minf.stbl.stsz.table = NULL;
}
}
if(!(pTrak->mdia.minf.stbl.stsc.flags)) {
if (pTrak->mdia.minf.stbl.stsc.table)
ippsFree(pTrak->mdia.minf.stbl.stsc.table);
pTrak->mdia.minf.stbl.stsc.table = NULL;
}
if (pTrak->mdia.minf.stbl.ctts.table)
ippsFree(pTrak->mdia.minf.stbl.ctts.table);
pTrak->mdia.minf.stbl.ctts.table = NULL;
if (pTrak->mdia.minf.stbl.co64.table)
ippsFree(pTrak->mdia.minf.stbl.co64.table);
pTrak->mdia.minf.stbl.co64.table = NULL;
if(!(pTrak->mdia.minf.stbl.stco.flags)) {
if (pTrak->mdia.minf.stbl.stco.table)
ippsFree(pTrak->mdia.minf.stbl.stco.table);
pTrak->mdia.minf.stbl.stco.table = NULL;
}
if(!(pTrak->mdia.minf.stbl.stts.flags)) {
if (pTrak->mdia.minf.stbl.stts.table)
ippsFree(pTrak->mdia.minf.stbl.stts.table);
pTrak->mdia.minf.stbl.stts.table = NULL;
}
if(!(pTrak->mdia.minf.stbl.stss.flags)) {
if (pTrak->mdia.minf.stbl.stss.table)
ippsFree(pTrak->mdia.minf.stbl.stss.table);
pTrak->mdia.minf.stbl.stss.table = NULL;
}
if(!(pTrak->mdia.minf.stbl.stsd.flags)) {
if (pTrak->mdia.minf.stbl.stsd.table)
ippsFree(pTrak->mdia.minf.stbl.stsd.table);
pTrak->mdia.minf.stbl.stsd.table = NULL;
}
if (!(pTrak->mdia.minf.dinf.dref.flags)) {
for (j = 0; j < pTrak->mdia.minf.dinf.dref.total_entries; j++) {
if (pTrak->mdia.minf.dinf.dref.table[j].data_reference)
ippsFree(pTrak->mdia.minf.dinf.dref.table[j].data_reference);
pTrak->mdia.minf.dinf.dref.table[j].data_reference = NULL;
}
if (pTrak->mdia.minf.dinf.dref.table) {
ippsFree(pTrak->mdia.minf.dinf.dref.table);
}
pTrak->mdia.minf.dinf.dref.table = NULL;
}
ippsFree(pTrak);
}
return UMC_OK;
}
void MP4Splitter::FillSampleSizeAndType(T_trak_data *trak,
IndexFragment &frag)
{
Ipp32u i;
T_stsz_data stsz = trak->mdia.minf.stbl.stsz;
T_stss_data stss = trak->mdia.minf.stbl.stss;
for (i = 0; i < (Ipp32u)frag.iNOfEntries; i++) {
if (stsz.sample_size == 0) {
frag.pEntryArray[i].uiSize = trak->mdia.minf.stbl.stsz.table[i].size;
} else {
frag.pEntryArray[i].uiSize = stsz.sample_size;
}
if (stss.table == NULL) {
frag.pEntryArray[i].uiFlags = I_PICTURE;
}
}
if (stss.table) {
for (i = 0; i < stss.total_entries; i++) {
frag.pEntryArray[stss.table[i].sample_number - 1].uiFlags = I_PICTURE;
}
}
}
void MP4Splitter::FillSamplePos(T_trak_data *trak,
IndexFragment &frag)
{
Ipp32u i;
// chunk offset box (32 bit version)
T_stco_data& stco = trak->mdia.minf.stbl.stco;
// chunk offset box (64 bit version)
T_co64_data& co64 = trak->mdia.minf.stbl.co64;
// sample to chunk box
T_stsc_data& stsc = trak->mdia.minf.stbl.stsc;
Ipp64u nSampleOffset = 0;
Ipp32u stco_i = 1;
Ipp32u stsc_i = 0;
Ipp32u samp_i = 0;
while (samp_i < (Ipp32u)frag.iNOfEntries) {
if (stco.total_entries) {
if (stco_i > stco.total_entries)
break;
nSampleOffset = stco.table[stco_i - 1].offset;
} else {
if (stco_i > co64.total_entries)
break;
nSampleOffset = co64.table[stco_i - 1].offset;
}
/* skipping invalid entries */
while (stsc_i < stsc.total_entries - 1) {
if (stsc.table[stsc_i + 1].chunk - stsc.table[stsc_i].chunk <= 0) {
stsc_i++;
} else {
break;
}
}
for (i = 0; i < stsc.table[stsc_i].samples; i++) {
frag.pEntryArray[samp_i].stPosition = (size_t)nSampleOffset;
nSampleOffset += frag.pEntryArray[samp_i].uiSize;
samp_i++;
if (samp_i >= (Ipp32u)frag.iNOfEntries)
break;
}
stco_i++;
if (stsc_i < stsc.total_entries - 1 &&
stco_i == stsc.table[stsc_i + 1].chunk) {
stsc_i++;
}
}
}
void MP4Splitter::FillSampleTimeStamp(T_trak_data *trak,
IndexFragment &frag)
{
// decoding time to sample box
T_stts_data& stts = trak->mdia.minf.stbl.stts;
// composition time to sample box
T_ctts_data& ctts = trak->mdia.minf.stbl.ctts;
Ipp32s nTimeScale = trak->mdia.mdhd.time_scale;
if (nTimeScale == 0) {
frag.iNOfEntries = 0;
return;
}
Ipp32u i;
Ipp32u stts_i;
Ipp32u samp_i = 0;
Ipp32u ctts_i = 0;
Ipp32u nTimeStamp = 0;
for (stts_i = 0; stts_i < stts.total_entries; stts_i++) {
for (i = 0; i < stts.table[stts_i].sample_count; i++) {
if (ctts.total_entries == 0) { // composition time stamp not present
frag.pEntryArray[samp_i].dPts = (Ipp64f)nTimeStamp / nTimeScale;
frag.pEntryArray[samp_i].dDts = -1.0;
} else {
frag.pEntryArray[samp_i].dPts =
frag.pEntryArray[samp_i].dDts = (Ipp64f)nTimeStamp;
}
nTimeStamp += stts.table[stts_i].sample_duration;
samp_i++;
if (samp_i >= (Ipp32u)frag.iNOfEntries)
break;
}
}
if (ctts.total_entries == 0) {
if (samp_i < (Ipp32u)frag.iNOfEntries) {
frag.iNOfEntries = samp_i;
}
return;
}
samp_i = 0;
for (ctts_i = 0; ctts_i < ctts.total_entries; ctts_i++) {
for (i = 0; i < ctts.table[ctts_i].sample_count; i++) {
frag.pEntryArray[samp_i].dPts += ctts.table[ctts_i].sample_offset;
frag.pEntryArray[samp_i].dPts /= nTimeScale;
frag.pEntryArray[samp_i].dDts /= nTimeScale;
samp_i++;
if (samp_i >= (Ipp32u)frag.iNOfEntries)
return;
}
}
if (samp_i < (Ipp32u)frag.iNOfEntries)
frag.iNOfEntries = samp_i;
}
Status MP4Splitter::AddMoovToIndex(Ipp32u iES)
{
IndexFragment frag;
T_trak_data *trak = m_headerMPEG4.moov.trak[iES];
Ipp32u nEntries = trak->mdia.minf.stbl.stsz.total_entries;
frag.iNOfEntries = nEntries;
if (frag.iNOfEntries <= 0)
return UMC_OK;
frag.pEntryArray = new IndexEntry[nEntries];
if (NULL == frag.pEntryArray)
return UMC_ERR_ALLOC;
FillSampleSizeAndType(trak, frag);
FillSamplePos(trak, frag);
FillSampleTimeStamp(trak, frag);
m_pLastPTS[iES] = frag.pEntryArray[frag.iNOfEntries-1].GetTimeStamp();
return m_pTrackIndex[iES].Add(frag);
}
Status MP4Splitter::AddMoofRunToIndex(Ipp32u iES, T_trex_data *pTrex, T_traf *pTraf,
T_trun *pTrun, Ipp64u &nBaseOffset)
{
IndexFragment frag;
Ipp32u i;
Ipp64f rTimeScale = m_headerMPEG4.moov.trak[iES]->mdia.mdhd.time_scale;
if (rTimeScale <= 0)
return UMC_ERR_FAILED;
frag.iNOfEntries = pTrun->sample_count;
frag.pEntryArray = new IndexEntry[pTrun->sample_count];
if (NULL == frag.pEntryArray)
return UMC_ERR_ALLOC;
for (i = 0; i < pTrun->sample_count; i++) {
if (m_bFlagStop)
return UMC_OK;
// sample size present in trun
if (pTrun->flags & SAMPLE_SIZE_PRESENT) {
frag.pEntryArray[i].uiSize = pTrun->table_trun[i].sample_size;
}
// sample size present in track fragment header box (tfhd)
else if (pTraf->tfhd.flags & DEFAULT_SAMPLE_SIZE_PRESENT) {
frag.pEntryArray[i].uiSize = pTraf->tfhd.default_sample_size;
} else {
// default sample size in Track Extends box
frag.pEntryArray[i].uiSize = pTrex->default_sample_size;
}
frag.pEntryArray[i].stPosition = (size_t)nBaseOffset;
// update base offset for next sample
nBaseOffset = frag.pEntryArray[i].stPosition + frag.pEntryArray[i].uiSize;
Ipp32u duration = 0;
// sample duration present in Track Fragment Run box
if (pTrun->flags & SAMPLE_DURATION_PRESENT) {
duration = pTrun->table_trun[i].sample_duration;
}
// sample duration present in Track Fragment Header box
else if (pTraf->tfhd.flags & DEFAULT_SAMPLE_DURATION_PRESENT) {
duration = pTraf->tfhd.default_sample_duration;
} else {
duration = pTrex->default_sample_duration;
}
// sample-composition-time-offset-present
if (pTrun->flags & SAMPLE_COMPOSITION_TIME_OFFSETS_PRESENT) {
duration += pTrun->table_trun[i].sample_composition_time_offset;
}
if (rTimeScale) {
frag.pEntryArray[i].dPts = duration/rTimeScale;
}
frag.pEntryArray[i].dPts += m_pLastPTS[iES];
m_pLastPTS[iES] = frag.pEntryArray[i].GetTimeStamp();
}
return m_pTrackIndex[iES].Add(frag);
}
Ipp32u MP4Splitter::InitMoofThreadCallback(void* pParam)
{
VM_ASSERT(NULL != pParam);
UMC::MP4Splitter* pThis = (MP4Splitter*)pParam;
pThis->InitMoof();
return 0;
}
Status MP4Splitter::MapTrafIDToTrackID (Ipp32u trafID, Ipp32u &nTrack)
{
Ipp32u i;
for (i = 0; i < m_pInfo->m_nOfTracks; i++) {
if (m_pInfo->m_ppTrackInfo[i]->m_PID == trafID) {
nTrack = i;
return UMC_OK;
}
}
return UMC_ERR_FAILED;
}
/* reads the next fragment and adds it to the index */
Status MP4Splitter::InitMoof()
{
Ipp32u iES, jES;
Status umcRes = CheckInit();
if (umcRes != UMC_OK)
return umcRes;
while (!m_bFlagStop) {
umcRes = SelectNextFragment();
UMC_CHECK_STATUS(umcRes)
Ipp64u nBaseOffset = 0;
for (iES = 0; iES < m_headerMPEG4.moof.total_tracks; iES++) {
// track fragment
T_traf* pTraf = m_headerMPEG4.moof.traf[iES];
if (pTraf == NULL)
continue;
// track extend box
T_trex_data* pTrex = NULL;
// finding a corresponding trex box based on track ID
for (jES = 0; jES < m_headerMPEG4.moov.mvex.total_tracks; jES++) {
if (m_headerMPEG4.moov.mvex.trex[jES] == NULL)
continue;
if (pTraf->tfhd.track_ID == m_headerMPEG4.moov.mvex.trex[jES]->track_ID) {
pTrex = m_headerMPEG4.moov.mvex.trex[jES];
break;
}
}
if (pTrex == NULL)
continue;
if (pTraf->tfhd.flags & BASE_DATA_OFFSET_PRESENT) {
// base data offset present
nBaseOffset = pTraf->tfhd.base_data_offset;
}
if ((iES == 0) && (nBaseOffset == 0)) {
// first byte after enclosing moof box;
nBaseOffset = m_headerMPEG4.moof.end;
// offset by 8 bytes (compact mdat box) or 16 bytes (large size)
if (m_headerMPEG4.data.is_large_size) {
nBaseOffset += 16;
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -