📄 umc_avi_splitter.cpp
字号:
// ascend from avi_ or avix
m_AviChunkReader.Ascend();
// look for AVIX list type at next loop
bExtension = true;
}
}
else
{
for (i = 0; i < m_AviHdr.uiStreams; i++)
{
if (AVI_FOURCC_auds == m_pTrack[i].m_StreamHeader.fccType ||
AVI_FOURCC_vids == m_pTrack[i].m_StreamHeader.fccType ||
AVI_FOURCC_iavs == m_pTrack[i].m_StreamHeader.fccType ||
AVI_FOURCC_ivas == m_pTrack[i].m_StreamHeader.fccType)
InitIndexUsingNewAVIIndex(i, m_pTrack[i].m_pIndex, m_pTrack[i].m_uiIndexSize);
}
}
return UMC_OK;
}
Status AVISplitter::InitIndexUsingOldAVIIndex(Ipp8u *pIndexBuffer, Ipp32s nIndexSize,
Ipp64u nMoviChunkStartAddr, Ipp64u /*nMoviChunkEndAddr*/)
{
const Ipp32s BYTES_PER_ENTRY = 16;
Ipp32s nTotalEntry = nIndexSize/BYTES_PER_ENTRY;
Ipp32s i;
// members of avi index entry
Ipp32u nChunkID = 0;
Ipp32u nFlag = 0;
Ipp32u nOffset = 0;
Ipp32u nLength = 0;
// do a quick check if the content contains VBR audio
if (!m_bCheckVBRAudio)
{
m_bCheckVBRAudio = true;
bool bAudioPresent = false;
for (i = 0; i < (Ipp32s)m_AviHdr.uiStreams && !bAudioPresent; i++)
if (AVI_FOURCC_auds == m_pTrack[i].m_StreamHeader.fccType)
bAudioPresent = true;
if (bAudioPresent)
{
Ipp8u *pTemp = pIndexBuffer;
Ipp32s iAudioSampleChecked = 0;
// check up to 100 audio samples in the first fragment to determine VBR or CBR audio
const Ipp32s MAX_AUDIO_SAMPLE_TO_CHECK = 100;
for (i = 0; i < nTotalEntry; i++)
{
nChunkID = *(Ipp32u*)pTemp;
Ipp32u uiTrackNum = GetTrackId(nChunkID);
// 16 bytes per entry
nLength = *(Ipp32u*)(pTemp + 12);
pTemp += BYTES_PER_ENTRY;
if (uiTrackNum > m_AviHdr.uiStreams || !IsAudio(nChunkID))
continue;
if (nLength < ((WaveFormatEx *)m_pTrack[uiTrackNum].m_pStreamFormat)->nBlockAlign)
{
m_bIsVBRAudio = true;
break;
}
iAudioSampleChecked++;
if (iAudioSampleChecked > MAX_AUDIO_SAMPLE_TO_CHECK)
{
// Limit reached, stop checking. Assuming it is CBR audio.
break;
}
}
}
}
Ipp32u uiTrackNum = 0;
Ipp64f *pTimeStamp = new Ipp64f[m_AviHdr.uiStreams];
bool bIsVideoTrack = true;
bool bAbsoluteOffset = true;
Ipp32u *pSize = new Ipp32u[m_AviHdr.uiStreams];
TrackIndex *pTrackIndex;
IndexFragment *pFrag = new IndexFragment[m_AviHdr.uiStreams];
IndexEntry *pEntry;
Ipp32u *pCounter = new Ipp32u[m_AviHdr.uiStreams];
bool *pIsFirstFrame = new bool[m_AviHdr.uiStreams];
for (i = 0; i < (Ipp32s)m_AviHdr.uiStreams; i++)
{
pTimeStamp[i] = 0.0;
pSize[i] = 0;
pCounter[i] = 0;
pIsFirstFrame[i] = true;
}
for (i = 0; i < nTotalEntry; i++)
{
nChunkID = *(Ipp32u *)pIndexBuffer;
pIndexBuffer += 4;
uiTrackNum = GetTrackId(nChunkID);
if (uiTrackNum >= m_AviHdr.uiStreams)
{
pIndexBuffer += 12;
continue;
}
// initialize these variables based on track index
bIsVideoTrack = !IsAudio(nChunkID);
pTrackIndex = &m_pTrackIndex[uiTrackNum];
nFlag = *(Ipp32u *)pIndexBuffer;
pIndexBuffer += 4;
// offset includes 8 bytes of chunk header
nOffset = *(Ipp32u *)pIndexBuffer;
pIndexBuffer += 4;
// length does not include 8 bytes of chunk header
nLength = *(Ipp32u *)pIndexBuffer;
pIndexBuffer += 4;
if (i == 0)
{
bAbsoluteOffset = nOffset > nMoviChunkStartAddr;
}
if ((Ipp32s)pCounter[uiTrackNum] >= pFrag[uiTrackNum].iNOfEntries)
{ // fragment is full
if (pFrag[uiTrackNum].iNOfEntries > 0 && pFrag[uiTrackNum].pEntryArray)
pTrackIndex->Add(pFrag[uiTrackNum]);
// estimated total samples, will be adjusted at the end
pFrag[uiTrackNum].iNOfEntries = (nTotalEntry - i) / m_AviHdr.uiStreams + 1;
if (pFrag[uiTrackNum].iNOfEntries < 100)
pFrag[uiTrackNum].iNOfEntries = 100;
pCounter[uiTrackNum] = 0;
pFrag[uiTrackNum].pEntryArray = new IndexEntry[pFrag[uiTrackNum].iNOfEntries];
if (NULL == pFrag[uiTrackNum].pEntryArray)
return UMC_ERR_ALLOC;
}
pTimeStamp[uiTrackNum] += GetSampleDuration(bIsVideoTrack, m_bIsVBRAudio,
(Ipp64f)(m_pTrack[uiTrackNum].m_StreamHeader.uiScale) / m_pTrack[uiTrackNum].m_StreamHeader.uiRate,
((WaveFormatEx *)m_pTrack[uiTrackNum].m_pStreamFormat)->nBlockAlign,
nLength);
pEntry = &pFrag[uiTrackNum].pEntryArray[pCounter[uiTrackNum]];
pEntry->uiSize = pSize[uiTrackNum] = nLength;
if (nLength > m_pTrack[uiTrackNum].m_uiMaxSampleSize)
m_pTrack[uiTrackNum].m_uiMaxSampleSize = nLength;
pEntry->dDts = -1.0;
if (pIsFirstFrame[uiTrackNum])
{
// Start time, usually it is zero, but it can specify a delay time for
// a stream that does not start concurrently with the file.
pIsFirstFrame[uiTrackNum] = false;
pEntry->dPts = m_pTrack[uiTrackNum].m_StreamHeader.uiStart *
(Ipp64f)(m_pTrack[uiTrackNum].m_StreamHeader.uiScale) /
m_pTrack[uiTrackNum].m_StreamHeader.uiRate;
}
else
{
pEntry->dPts = pTimeStamp[uiTrackNum];
}
// check index flag
if (nFlag & AVIIF_KEYFRAME)
pEntry->uiFlags = I_PICTURE;
if ((nFlag & AVIIF_FIRSTPART) || (nFlag & AVIIF_LASTPART))
{
vm_debug_trace(VM_DEBUG_ERROR, __VM_STRING("WARNING: AVI index has FIRSTPART or LASTPART flag set!\n"));
}
if (nFlag & AVIIF_NO_TIME)
{
vm_debug_trace(VM_DEBUG_ERROR, __VM_STRING("WARNING: AVI index has NO_TIME flag set!\n"));
}
pEntry->stPosition = nOffset + 8; // 8 bytes of chunk header
if (!bAbsoluteOffset)
pEntry->stPosition += (size_t)nMoviChunkStartAddr;
pCounter[uiTrackNum]++;
}
for (i = 0; i < (Ipp32s)m_AviHdr.uiStreams; i++)
{
if (pCounter[i] > 0)
{
pFrag[i].iNOfEntries = pCounter[i];
m_pTrackIndex[i].Add(pFrag[i]);
}
}
delete[] pTimeStamp;
delete[] pSize;
delete[] pCounter;
delete[] pFrag;
delete[] pIsFirstFrame;
return UMC_OK;
}
Status AVISplitter::InitIndexUsingNewAVIIndex(Ipp32u nTrackNum, Ipp8u *pIndexBuffer, Ipp32s nIndexSize)
{
Status umcRes = UMC_OK;
Ipp8u *buf = pIndexBuffer;
Ipp16u wLongsPerEntry = *(Ipp16u *)buf;
wLongsPerEntry = BIG_ENDIAN_SWAP16(wLongsPerEntry);
buf += 2;
buf += 1; // skip bIndexSubType
Ipp8u bIndexType = *(Ipp8u *)buf;
buf += 1;
Ipp32u nEntriesInUse = *(Ipp32u *)buf;
nEntriesInUse = BIG_ENDIAN_SWAP32(nEntriesInUse);
buf += 4;
buf += 4; // skip dwChunkId
Ipp64u qwBaseOffset = 0;
if (bIndexType == AVI_INDEX_OF_CHUNKS || bIndexType == AVI_INDEX_OF_SUB_2FIELD)
{
// low half of qwBaseOffset
((Ipp32u *)&qwBaseOffset)[0] = *(Ipp32u *)buf;
buf += 4;
// high half of qwBaseOffset
((Ipp32u *)&qwBaseOffset)[1] = *(Ipp32u *)buf;
qwBaseOffset = BIG_ENDIAN_SWAP64(qwBaseOffset);
buf += 4;
buf += 4; // reserved
if (wLongsPerEntry == 0)
wLongsPerEntry = (bIndexType == AVI_INDEX_OF_CHUNKS) ? 2 : 3;
}
else if (bIndexType == AVI_INDEX_OF_INDEXES)
{
buf += 12; // reserved (3 Ipp32u)
if (wLongsPerEntry == 0)
wLongsPerEntry = 4;
}
if (wLongsPerEntry == 0)
return UMC_ERR_FAILED;
nIndexSize -= (buf - pIndexBuffer);
nEntriesInUse = IPP_MIN(nEntriesInUse, Ipp32u(nIndexSize / (wLongsPerEntry * 4)));
// super index
if (bIndexType == AVI_INDEX_OF_INDEXES)
{
Ipp32u i;
for (i = 0; i < nEntriesInUse; i++)
{
Ipp64u qwOffset = *(Ipp64u *)buf;
qwOffset = BIG_ENDIAN_SWAP64(qwOffset);
buf += 8;
// size of index chunk at this offset
Ipp32u dwSize = *(Ipp32u *)buf;
dwSize = BIG_ENDIAN_SWAP32(dwSize);
buf += 4;
buf += 4; // ignore dwDuration
Ipp8u *pIndexBuffer = ippsMalloc_8u(dwSize);
if (pIndexBuffer == NULL)
return UMC_ERR_ALLOC;
Status umcRes = m_AviChunkReader.GetData(qwOffset, pIndexBuffer, dwSize);
if (umcRes == UMC_OK)
{
// skip standard chunk header - 8 bytes
umcRes = InitIndexUsingNewAVIIndex(nTrackNum, pIndexBuffer + 8, dwSize - 8);
}
ippsFree(pIndexBuffer);
}
}
else
{
// standard index
umcRes = InitIndexUsingStandardIndex(nTrackNum, buf, nEntriesInUse, qwBaseOffset, wLongsPerEntry);
}
return umcRes;
}
Status AVISplitter::InitIndexUsingStandardIndex(
Ipp32u nTrackNum,
Ipp8u *pIndexBuffer,
Ipp32u nEntriesInUse,
Ipp64u qwBaseOffset,
Ipp16u wLongsPerEntry)
{
// AVI standard index chunk or AVI field index chunk
TrackIndex *pIndex = &m_pTrackIndex[nTrackNum];
IndexFragment frag;
IndexEntry entry;
Ipp32u i;
frag.iNOfEntries = nEntriesInUse;
frag.pEntryArray = new IndexEntry[nEntriesInUse];
if (NULL == frag.pEntryArray)
return UMC_ERR_ALLOC;
memset(frag.pEntryArray, 0, nEntriesInUse * sizeof(IndexEntry));
bool bIsAudioTrack = (AVI_FOURCC_auds == m_pTrack[nTrackNum].m_StreamHeader.fccType);
Ipp32s nBlockAlign = !bIsAudioTrack ? 0 : ((WaveFormatEx *)m_pTrack[nTrackNum].m_pStreamFormat)->nBlockAlign;
Ipp64f dFrameDuration = (Ipp64f)(m_pTrack[nTrackNum].m_StreamHeader.uiScale) / m_pTrack[nTrackNum].m_StreamHeader.uiRate;
// if we have already checked VBR or CBR audio in the first standard index,
// don't bother to do another check.
if (bIsAudioTrack && !m_bCheckVBRAudio)
{
m_bCheckVBRAudio = true;
Ipp8u *pTemp = pIndexBuffer;
Ipp32u dwSize = 0;
for (i = 0; i < nEntriesInUse; i++)
{
dwSize = (*(Ipp32u*)(pTemp + 4));
dwSize = BIG_ENDIAN_SWAP32(dwSize);
dwSize &= 0x7FFFFFFF;
// move buffer to next entry
pTemp += wLongsPerEntry * 4;
if ((Ipp32s)dwSize < nBlockAlign)
{
// VBR if sample size is less than block aglin.
// same other applications check if nBlockAlign is 1152 or 576.
m_bIsVBRAudio = true;
break;
}
}
}
Ipp32u dwOffset = 0;
Ipp32u dwSize = 0;
Ipp64f dTimeStamp = 0;
if (UMC_OK == pIndex->Last(entry))
{
dTimeStamp = entry.GetTimeStamp();
dTimeStamp += GetSampleDuration(!bIsAudioTrack, m_bIsVBRAudio, dFrameDuration, nBlockAlign, entry.uiSize);
}
for (i = 0; i < nEntriesInUse; i++)
{
dwOffset = *(Ipp32u *)pIndexBuffer;
dwOffset = BIG_ENDIAN_SWAP32(dwOffset);
dwSize = *(Ipp32u *)(pIndexBuffer + 4);
dwSize = BIG_ENDIAN_SWAP32(dwSize);
// move to next index entry
pIndexBuffer += wLongsPerEntry * 4;
frag.pEntryArray[i].stPosition = (size_t)(qwBaseOffset + dwOffset);
// bit 31 is Key frame flag
frag.pEntryArray[i].uiSize = dwSize & 0x7FFFFFFF;
if (frag.pEntryArray[i].uiSize > m_pTrack[nTrackNum].m_uiMaxSampleSize)
m_pTrack[nTrackNum].m_uiMaxSampleSize = frag.pEntryArray[i].uiSize;
// bit 31 is set if this is NOT a key frame
if (((dwSize & 0x8FFFFFFF) >> 31) == 0)
frag.pEntryArray[i].uiFlags = I_PICTURE;
// first sample overall
frag.pEntryArray[i].dDts = -1.0;
if (i == 0 && UMC_OK != pIndex->First(entry))
{
// Start time, usually it is zero, but it can specify a delay time for
// a stream that does not start concurrently with the file.
frag.pEntryArray[i].dPts = m_pTrack[nTrackNum].m_StreamHeader.uiStart * dFrameDuration;
}
else
{
frag.pEntryArray[i].dPts = dTimeStamp;
}
dTimeStamp += GetSampleDuration(!bIsAudioTrack, m_bIsVBRAudio, dFrameDuration, nBlockAlign, frag.pEntryArray[i].uiSize);
}
return pIndex->Add(frag);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -