📄 umc_avs_dec_fussion_core_load_source.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) 2007 Intel Corporation. All Rights Reserved.
//
//
*/
#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER)
#include "umc_avs_dec_fussion_core.h"
#include "umc_avs_dec_byte_stream.h"
#include "umc_avs_dec_bit_stream.h"
#include "umc_automatic_mutex.h"
namespace UMC
{
static
bool FindStartCode(Ipp8u *(&pbSrc), size_t &srcSize)
{
Ipp8u *pbSrcEnd;
// calculate the end of sample
pbSrcEnd = pbSrc + srcSize - 4;
do
{
// we can skip 3 bytes when
// the next but one byte is greater than 1
if (1 < pbSrc[2])
{
pbSrc += 3;
}
// we can skip 2 bytes when
// the next byte byte is not 0
else if (0 < pbSrc[1])
{
pbSrc += 2;
}
// in other case we have to analyze stream byte by byte
else
{
// we found a start code
if (1 == pbSrc[2])
{
if (0 == pbSrc[0])
{
// update the remain bytes
srcSize = pbSrcEnd - pbSrc + 4;
return true;
}
pbSrc += 2;
}
pbSrc += 1;
}
} while (pbSrc <= pbSrcEnd);
// skip last bytes
pbSrc = pbSrcEnd + 4;
srcSize = 0;
return false;
} // bool FindStartCode(Ipp8u *(&pbSrc), size_t &srcSize)
Status AVSFussionCore::LoadSource(MediaData *pSrc)
{
Ipp8u *pbSrc;
size_t srcSize;
Status umcRes = UMC_OK;
bool bRes;
// check end of stream
if (NULL == pSrc)
{
FinalizePicture();
return UMC_OK;
}
pbSrc = (Ipp8u *) pSrc->GetDataPointer();
srcSize = pSrc->GetDataSize();
// one by one NAL unit load source into the core
bRes = FindStartCode(pbSrc, srcSize);
while (bRes)
{
size_t iNALUnitSize, nextSize;
Ipp8u *pbSrcNext;
// figure out the unit's size
iNALUnitSize = srcSize;
pbSrcNext = pbSrc + 4;
nextSize = srcSize - 4;
bRes = FindStartCode(pbSrcNext, nextSize);
if (bRes)
iNALUnitSize = pbSrcNext - pbSrc;
// load NAL unit into the core
umcRes = LoadNALUnit(pbSrc, iNALUnitSize);
switch (umcRes)
{
// everything is fine, the NAL unit goes well.
// collected data is not enough for decoding.
case UMC_ERR_NOT_ENOUGH_DATA:
// advance to the next start code
pbSrc = pbSrcNext;
srcSize = nextSize;
umcRes = UMC_OK;
break;
// the frame has just been completed.
// repeat the latest NAL unit.
case UMC_ERR_NOT_ENOUGH_BUFFER:
umcRes = UMC_OK;
break;
// well, we collected whole bunch of frames.
// let us decode something.
case UMC_OK:
bRes = false;
break;
// some errors.
// stop and exit.
default:
bRes = false;
break;
}
}
// update media source
pSrc->MoveDataPointer((Ipp32s) (pbSrc - (Ipp8u *) pSrc->GetDataPointer()));
// check error(s)
if (UMC_OK != umcRes)
return umcRes;
if (0 == srcSize)
return UMC_ERR_NOT_ENOUGH_DATA;
return UMC_OK;
} // Status AVSFussionCore::LoadSource(MediaData *pSrc)
Status AVSFussionCore::LoadNALUnit(Ipp8u *pbSrc, size_t srcSize)
{
AVSFrame *pFrame = AllocateFrame();
// check state
if (NULL == pFrame)
{
// everything is fine, we collected enough data for decoding
if (m_iNumFrames == AVS_DEF_NUMBER_OF_FRAMES + m_iNumberOfThreads)
return UMC_OK;
else
return UMC_ERR_ALLOC;
}
// handle data type
switch (pbSrc[3])
{
// these are valuable information
// it is possible,that it is from the next frame
case VIDEO_SEQUENCE_START_CODE:
if (UMC_OK == FinalizePicture())
return UMC_ERR_NOT_ENOUGH_BUFFER;
ParseSequenceHeader(pbSrc, srcSize);
break;
case I_PICTURE_START_CODE:
case BP_PICTURE_START_CODE:
if (UMC_OK == FinalizePicture())
return UMC_ERR_NOT_ENOUGH_BUFFER;
ParsePictureHeader(pbSrc, srcSize);
break;
case VIDEO_SEQUENCE_END_CODE:
case USER_DATA_START_CODE:
case EXTENSION_START_CODE:
case VIDEO_EDIT_CODE:
FinalizePicture();
break;
// add video data to the frame
default:
if ((0 <= pbSrc[3]) &&
(LAST_SLICE_START_CODE >= pbSrc[3]))
{
Status umcRes;
umcRes = AddSliceToPicture(pbSrc, srcSize);
if (UMC_ERR_NOT_ENOUGH_BUFFER == umcRes)
FinalizePicture();
if (UMC_OK != umcRes)
return umcRes;
}
break;
};
// we need more source data
return UMC_ERR_NOT_ENOUGH_DATA;
} // Status AVSFussionCore::LoadNALUnit(Ipp8u *pbSrc, size_t srcSize)
void AVSFussionCore::ParseSequenceHeader(Ipp8u *pbSrc, size_t srcSize)
{
Status umcRes;
umcRes = DecodeAVSSequenceHeader(&m_seqHeader, pbSrc, srcSize);
} // void AVSFussionCore::ParseSequenceHeader(Ipp8u *pbSrc, size_t srcSize)
class AVSDwordWriter
{
public:
AVSDwordWriter(Ipp32u *pDst)
{
m_pBegin = pDst;
m_pDst = pDst;
m_nBits = 0;
m_numFreeBits = 32;
}
void PutBits(Ipp32u bits, Ipp32s numBits)
{
// the bits register is overflow - need save data to the memory
if (m_numFreeBits <= numBits)
{
// fill empty bit positions
m_nBits = (m_nBits << m_numFreeBits) |
(bits >> (numBits - m_numFreeBits));
*m_pDst = m_nBits;
m_pDst += 1;
// copy remain bits
m_nBits = bits;
m_numFreeBits = (32 - (numBits - m_numFreeBits));
}
// there is enough room to save bits
else
{
m_nBits = (m_nBits << numBits) | bits;
m_numFreeBits -= numBits;
}
}
size_t FlushStream(void)
{
if (32 != m_numFreeBits)
PutBits(0, m_numFreeBits);
return (m_pDst - m_pBegin);
}
protected:
Ipp32u *m_pBegin; // (Ipp32u *) pointer to beginning of writing
Ipp32u *m_pDst; // (Ipp32u *) the current writing position
Ipp32u m_nBits; // (Ipp32u) cached bits
Ipp32s m_numFreeBits; // (Ipp32s) number of free bits in the cache
};
size_t SwapAndRemovePreventionBits(Ipp32u *pDst, Ipp8u *pbSrc, size_t srcSize)
{
AVSDwordWriter dst(pDst);
Ipp8u *pbSrcEnd = pbSrc + srcSize;
// Copy source removing prevention bits
dst.PutBits(pbSrc[0], 8);
dst.PutBits(pbSrc[1], 8);
pbSrc += 2;
while (pbSrcEnd > pbSrc)
{
// we found the first prevention pattern
if ((2 == pbSrc[0]) &&
(0 == pbSrc[-1]) &
(0 == pbSrc[-2]))
{
// put zero bits into the destination stream
dst.PutBits(0, 6);
}
else
{
// put byte into the destination stream
dst.PutBits(pbSrc[0], 8);
}
pbSrc += 1;
}
// finalize the stream
return dst.FlushStream();
} // size_t SwapAndRemovePreventionBits(Ipp32u *pDst, Ipp8u *pbSrc, Ipp32s srcSize)
void AVSFussionCore::ParsePictureHeader(Ipp8u *pbSrc, size_t srcSize)
{
AVS_PICTURE_HEADER picHeader;
AVS_BIT_STREAM_CONTEXT ctx;
Ipp32u data[64], *pSrcEnd;
size_t iDwords;
// check error(s)
if (VIDEO_SEQUENCE_START_CODE != m_seqHeader.video_sequence_start_code)
return;
// prepare source data
iDwords = SwapAndRemovePreventionBits(data, pbSrc, srcSize);
pSrcEnd = data + iDwords;
// initialize decoding context
ctx.src = data;
ctx.offset = 31;
// decode picture header
DecodePicHeader(&ctx, &m_seqHeader, &picHeader);
// check error(s)
if ((pSrcEnd > ctx.src) ||
(31 == ctx.offset))
{
m_picHeader = picHeader;
}
} // void AVSFussionCore::ParsePictureHeader(Ipp8u *pbSrc, size_t srcSize)
Status AVSFussionCore::AddSliceToPicture(Ipp8u *pbSrc, size_t srcSize)
{
AVSListElement<AVSFrame> *pFrame = m_FreeFrames.GetHead();
AVSListElement<AVSMemory> *pMemory;
AVSListElement<AVSSlice> *pSlice;
size_t iDwords;
// check error(s)
// there is no header. Just skip this NAL unit.
if (VIDEO_SEQUENCE_START_CODE != m_seqHeader.video_sequence_start_code)
return UMC_OK;
if ((I_PICTURE_START_CODE != m_picHeader.picture_start_code) &&
(BP_PICTURE_START_CODE != m_picHeader.picture_start_code))
return UMC_OK;
if (m_iPrevSliceStartCode > pbSrc[3])
return UMC_ERR_NOT_ENOUGH_BUFFER;
// allocate a memory piece for the slice
pMemory = AllocateMemoryPiece(align_value<size_t> (srcSize, 4));
if (NULL == pMemory)
{
return UMC_ERR_ALLOC;
}
// allocate the slice
pSlice = AllocateSlice();
if (NULL == pSlice)
{
m_FreeMemory.AddToTail(*pMemory);
return UMC_ERR_ALLOC;
}
// swap source
iDwords = SwapAndRemovePreventionBits(pMemory->GetBuffer(), pbSrc, srcSize);
pMemory->SetDataSize(iDwords);
// add these both to the frame
pFrame->m_Slices.AddToTail(*pSlice);
pFrame->m_MemoryPieces.AddToTail(*pMemory);
m_iPrevSliceStartCode = pbSrc[3];
return UMC_OK;
} // Status AVSFussionCore::AddSliceToPicture(Ipp8u *pbSrc, size_t srcSize)
Status AVSFussionCore::FinalizePicture(void)
{
AVSListElement<AVSFrame> *pToAdd = m_FreeFrames.GetHead();
// we met something that make us finish the frame.
// of course we must have something to decode.
if ((pToAdd) &&
(pToAdd->m_Slices.GetHead()))
{
Status umcRes;
// now we need to initialize the collected frame
umcRes = InitializeFrame(pToAdd);
if (UMC_OK != umcRes)
{
PurgeFrame(pToAdd);
return UMC_ERR_NOT_ENOUGH_DATA;
}
// then move it into the being decoded frame list
{
AutomaticMutex guard(m_guard.ExtractHandle());
// remove the frame from the free frame list
m_Frames.AddToTail(*m_FreeFrames.ExtractHead());
}
// reset the previous slice's number
m_iPrevSliceStartCode = 0;
return UMC_OK;
}
// the frame was incomplete
return UMC_ERR_NOT_ENOUGH_DATA;
} // bool AVSFussionCore::FinalizePicture(bool bForce)
} // namespace UMC
#endif // #if defined(UMC_ENABLE_AVS_VIDEO_DECODER)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -