📄 umc_mpeg2_dec.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) 2003-2007 Intel Corporation. All Rights Reserved.
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_MPEG2_VIDEO_DECODER)
#include "vm_sys_info.h"
#include "vm_time.h"
#include "umc_video_data.h"
#include "umc_video_processing.h"
#include "umc_memory_allocator.h"
#include "umc_mpeg2_dec_base.h"
#include "umc_mpeg2_dec.h"
#include "umc_mpeg2_dec_tbl.h"
using namespace UMC;
#define ALIGN_VALUE 16
namespace UMC
{
VideoDecoder *CreateMPEG2Decoder() { return new MPEG2VideoDecoder(); }
}
static IppStatus mp2_HuffmanTableInitAlloc(Ipp32s *tbl, Ipp32s bits_table0, mp2_VLCTable *vlc)
{
Ipp32s *ptbl;
Ipp16s bad_value = 0;
Ipp32s max_bits;
Ipp32s num_tbl;
Ipp32s i, j, k, m, n;
Ipp32s bits, code, value;
Ipp32s bits0, bits1;
Ipp32s min_value, max_value, spec_value;
Ipp32s min_code0, min_code1;
Ipp32s max_code0, max_code1;
Ipp32s prefix_code1 = -1;
Ipp32s bits_table1 = 0;
Ipp32s *buffer = NULL;
Ipp32s *codes;
Ipp32s *cbits;
Ipp32s *values;
Ipp16s *table0 = NULL;
Ipp16s *table1 = NULL;
/* get number of entries (n) */
max_bits = *tbl++;
num_tbl = *tbl++;
for (i = 0; i < num_tbl; i++) {
*tbl++;
}
n = 0;
ptbl = tbl;
for (bits = 1; bits <= max_bits; bits++) {
m = *ptbl;
if (m < 0) break;
n += m;
ptbl += 2*m + 1;
}
/* alloc internal table */
buffer = new Ipp32s[3*n];
if (!buffer) return ippStsErr;
codes = buffer;
cbits = buffer + n;
values = buffer + 2*n;
/* read VLC to internal table */
min_value = 0x7fffffff;
max_value = 0;
spec_value = 0;
ptbl = tbl;
k = 0;
for (bits = 1; bits <= max_bits; bits++) {
if (*ptbl < 0) break;
m = *ptbl++;
for (i = 0; i < m; i++) {
code = *ptbl++;
value = *ptbl++;
code &= ((1 << bits) - 1);
if (value < min_value) min_value = value;
if (value > max_value) {
if (!spec_value && value >= 0xffff) {
spec_value = value;
} else {
max_value = value;
}
}
codes[k] = code << (30 - bits);
cbits[k] = bits;
values[k] = value;
k++;
}
}
if (!bits_table0) {
bits_table0 = max_bits;
bits_table1 = 0;
vlc->threshold_table0 = 0;
}
bits0 = bits_table0;
//for (bits0 = 1; bits0 < max_bits; bits0++)
if (bits0 > 0 && bits0 < max_bits) {
min_code0 = min_code1 = 0x7fffffff;
max_code0 = max_code1 = 0;
for (i = 0; i < n; i++) {
code = codes[i];
bits = cbits[i];
if (bits <= bits0) {
if (code > max_code0) max_code0 = code;
if (code < min_code0) min_code0 = code;
} else {
if (code > max_code1) max_code1 = code;
if (code < min_code1) min_code1 = code;
}
}
if ((max_code0 < min_code1) || (max_code1 < min_code0)) {
for (j = 0; j < 29; j++) {
if ((min_code1 ^ max_code1) & (1 << (29 - j))) break;
}
bits1 = max_bits - j;
if (bits0 == bits_table0) {
bits_table1 = bits1;
prefix_code1 = min_code1 >> (30 - bits0);
vlc->threshold_table0 = min_code0 >> (30 - max_bits);
}
}
}
if (bits_table0 > 0 && bits_table0 < max_bits && !bits_table1) {
if (buffer) delete[] buffer;
return ippStsErr;
}
bad_value = (bad_value << 8) | VLC_BAD;
table0 = ippsMalloc_16s(1 << bits_table0);
ippsSet_16s(bad_value, table0, 1 << bits_table0);
if (bits_table1) {
table1 = ippsMalloc_16s(1 << bits_table1);
ippsSet_16s(bad_value, table1, 1 << bits_table1);
}
for (i = 0; i < n; i++) {
code = codes[i];
bits = cbits[i];
value = values[i];
if (bits <= bits_table0) {
code = code >> (30 - bits_table0);
for (j = 0; j < (1 << (bits_table0 - bits)); j++) {
table0[code + j] = (Ipp16s)((value << 8) | bits);
}
} else {
code = code >> (30 - max_bits);
code = code & ((1 << bits_table1) - 1);
for (j = 0; j < (1 << (max_bits - bits)); j++) {
table1[code + j] = (Ipp16s)((value << 8) | bits);
}
}
}
if (bits_table1) { // fill VLC_NEXTTABLE
if (prefix_code1 == -1) {
if (buffer) delete[] buffer;
return ippStsErr;
}
bad_value = (bad_value &~ 255) | VLC_NEXTTABLE;
for (j = 0; j < (1 << ((bits_table0 - (max_bits - bits_table1)))); j++) {
table0[prefix_code1 + j] = bad_value;
}
}
vlc->max_bits = max_bits;
vlc->bits_table0 = bits_table0;
vlc->bits_table1 = bits_table1;
vlc->table0 = table0;
vlc->table1 = table1;
if (buffer) delete[] buffer;
return ippStsNoErr;
}
static void mp2_HuffmanTableFree(mp2_VLCTable *vlc) {
if (vlc->table0) {
ippsFree(vlc->table0);
vlc->table0 = NULL;
}
if (vlc->table1) {
ippsFree(vlc->table1);
vlc->table1 = NULL;
}
}
bool MPEG2VideoDecoderBase::InitTables()
{
if (ippStsNoErr != mp2_HuffmanTableInitAlloc(MBAdressing, 5, &vlcMBAdressing))
return false;
if (ippStsNoErr != mp2_HuffmanTableInitAlloc(IMBType, 0, &vlcMBType[0]))
return false;
if (ippStsNoErr != mp2_HuffmanTableInitAlloc(PMBType, 0, &vlcMBType[1]))
return false;
if (ippStsNoErr != mp2_HuffmanTableInitAlloc(BMBType, 0, &vlcMBType[2]))
return false;
if (ippStsNoErr != mp2_HuffmanTableInitAlloc(MBPattern, 5, &vlcMBPattern))
return false;
if (ippStsNoErr != mp2_HuffmanTableInitAlloc(MotionVector, 5, &vlcMotionVector))
return false;
return true;
}
bool MPEG2VideoDecoderBase::DeleteTables()
{
// release tools
if(Video)
{
ippsFree(Video[0]);
Video[0] = NULL;
ippsFree(Video);
Video = NULL;
}
if(frame_buffer.ptr_context_data)
{
//ippsFree(frame_buffer.ptr_context_data);
m_pMemoryAllocator->Free(frame_buffer.mid_context_data);
frame_buffer.ptr_context_data = NULL;
}
if ( m_bOwnAllocator && m_pMemoryAllocator !=0 ) {
delete m_pMemoryAllocator;
m_bOwnAllocator = false;
m_pMemoryAllocator = 0;
}
// release tables
mp2_HuffmanTableFree(&vlcMBAdressing);
mp2_HuffmanTableFree(&vlcMBType[0]);
mp2_HuffmanTableFree(&vlcMBType[1]);
mp2_HuffmanTableFree(&vlcMBType[2]);
mp2_HuffmanTableFree(&vlcMBPattern);
mp2_HuffmanTableFree(&vlcMotionVector);
return UMC_OK;
}
Ipp32u VM_THREAD_CALLCONVENTION MPEG2VideoDecoderBase::ThreadWorkingRoutine(void *lpv)
{
THREAD_ID * lpThreadId;
MPEG2VideoDecoderBase * lpOwner;
// check error(s)
if (NULL == lpv)
return 0xbaadf00d;
lpThreadId = reinterpret_cast<THREAD_ID *> (lpv);
lpOwner = reinterpret_cast<MPEG2VideoDecoderBase *> (lpThreadId->m_lpOwner);
// wait for start
vm_event_wait(lpOwner->m_lpStartEvent + lpThreadId->m_nNumber);
while (VM_TIMEOUT == vm_event_timed_wait(&(lpOwner->m_lpQuit[lpThreadId->m_nNumber]), 0))
{
lpOwner->DecodeSlices(lpThreadId->m_nNumber);
// set finish
vm_event_signal(lpOwner->m_lpStopEvent + lpThreadId->m_nNumber);
//vm_time_sleep(0);
// wait for start
vm_event_wait(lpOwner->m_lpStartEvent + lpThreadId->m_nNumber);
}
return lpThreadId->m_nNumber;
}
Status MPEG2VideoDecoderBase::ThreadingSetup(Ipp32s maxThreads)
{
Ipp32s i;
Ipp32s aligned_size;
if(maxThreads == 0)
m_nNumberOfThreads = vm_sys_info_get_cpu_num();
else
m_nNumberOfThreads = maxThreads;
if (0 >= m_nNumberOfThreads)
m_nNumberOfThreads = 1;
else if (8 < m_nNumberOfThreads)
m_nNumberOfThreads = 8;
Video = (IppVideoContext**)ippsMalloc_8u(m_nNumberOfThreads*sizeof(IppVideoContext*));
if(!Video) return UMC_ERR_ALLOC;
aligned_size = (Ipp32s)((sizeof(IppVideoContext) + 15) &~ 15);
Video[0] = (IppVideoContext*)ippsMalloc_8u(m_nNumberOfThreads*aligned_size);
if(!Video[0]) return UMC_ERR_ALLOC;
memset(Video[0], 0, m_nNumberOfThreads*aligned_size);
for(i = 0; i < m_nNumberOfThreads; i++)
{
if (i)
Video[i] = (IppVideoContext*)((Ipp8u *)Video[0] + i*aligned_size);
// Intra&inter spec
memset(&Video[i]->decodeIntraSpec, 0, sizeof(IppiDecodeIntraSpec_MPEG2));
memset(&Video[i]->decodeInterSpec, 0, sizeof(IppiDecodeInterSpec_MPEG2));
ippiDecodeInterInit_MPEG2(NULL, IPPVC_MPEG1_STREAM, &Video[i]->decodeInterSpec);
Video[i]->decodeInterSpecChroma = Video[i]->decodeInterSpec;
Video[i]->decodeInterSpec.idxLastNonZero = 63;
Video[i]->decodeIntraSpec.intraVLCFormat = PictureHeader.intra_vlc_format;
Video[i]->decodeIntraSpec.intraShiftDC = PictureHeader.curr_intra_dc_multi;
}
// create threading tools
if (1 < m_nNumberOfThreads)
{
// create exit event(s)
m_lpQuit = new vm_event[m_nNumberOfThreads];
if (NULL == m_lpQuit)
return UMC_ERR_ALLOC;
for (i = 1; i < m_nNumberOfThreads; i++)
{
vm_event_set_invalid(m_lpQuit + i);
if (VM_OK != vm_event_init(m_lpQuit + i, 0, 0))
return UMC_ERR_INIT;
}
// create start event(s)
m_lpStartEvent = new vm_event[m_nNumberOfThreads];
if (NULL == m_lpStartEvent)
return UMC_ERR_ALLOC;
for (i = 1; i < m_nNumberOfThreads; i++)
{
vm_event_set_invalid(m_lpStartEvent + i);
if (VM_OK != vm_event_init(m_lpStartEvent + i, 0, 0))
return UMC_ERR_INIT;
}
// create stop event(s)
m_lpStopEvent = new vm_event[m_nNumberOfThreads];
if (NULL == m_lpStopEvent)
return UMC_ERR_ALLOC;
for (i = 1;i < m_nNumberOfThreads;i += 1)
{
vm_event_set_invalid(m_lpStopEvent + i);
if (VM_OK != vm_event_init(m_lpStopEvent + i, 0, 0))
return UMC_ERR_INIT;
}
// allocate thread ID(s)
m_lpThreadsID = new THREAD_ID[m_nNumberOfThreads];
if (NULL == m_lpThreadsID)
return UMC_ERR_ALLOC;
// starting thread(s)
m_lpThreads = new vm_thread[m_nNumberOfThreads];
if (NULL == m_lpThreads)
return UMC_ERR_ALLOC;
for (i = 1;i < m_nNumberOfThreads;i += 1)
{
vm_thread_set_invalid(m_lpThreads + i);
m_lpThreadsID[i].m_nNumber = i;
m_lpThreadsID[i].m_lpOwner = this;
if (0 == vm_thread_create(m_lpThreads + i, ThreadWorkingRoutine, m_lpThreadsID + i))
return UMC_ERR_INIT;
}
}
m_nNumberOfAllocatedThreads = m_nNumberOfThreads;
return UMC_OK;
}
Status MPEG2VideoDecoderBase::Init(BaseCodecParams *pInit)
{
MediaData *data;
Status ret;
VideoDecoderParams *init = DynamicCast<VideoDecoderParams, BaseCodecParams>(pInit);
if(!init)
return UMC_ERR_INIT;
data = init->m_pData;
if (data != 0 && data->GetDataSize() == 0)
data = 0;
// checks or create memory allocator;
ret = BaseCodec::Init(pInit);
if(ret != UMC_OK)
return ret;
if((init->lFlags & FLAG_VDEC_4BYTE_ACCESS) != 0)
return UMC_ERR_UNSUPPORTED;
Reset();
m_ClipInfo = init->info;
m_lFlags = init->lFlags;
m_PostProcessing = init->pPostProcessing;
// creates thread's structures (Video[])
if(UMC_OK != ThreadingSetup(init->numThreads))
return UMC_ERR_ALLOC;
if (data != 0) {
PrepareBuffer(data);
// get sequence header start code
// search while not found or EOD
if(UMC_OK != FindSequenceHeader(Video[0]))
return (UMC_ERR_SYNC);
if(UMC_OK != DecodeSequenceHeader(Video[0]))
return (UMC_ERR_INVALID_STREAM);
FlushBuffer(data, false);
} else { // get stream parameters from sVideoInfo
if(UMC_OK != DecodeSequenceHeader( 0 ))
return (UMC_ERR_INVALID_PARAMS);
}
m_ccCurrData.SetBufferPointer(NULL, 0);
m_pCCData = new SampleBuffer;
if(m_pCCData)
{
Status res = UMC_OK;
MediaBufferParams initPar;
initPar.m_prefInputBufferSize = initPar.m_prefOutputBufferSize = 1024;
initPar.m_numberOfFrames = 20;
initPar.m_pMemoryAllocator = m_pMemoryAllocator;
res = m_pCCData->Init(&initPar);
if(res != UMC_OK)
{
m_pCCData->Close();
delete m_pCCData;
m_pCCData = NULL;
}
}
if (false == InitTables())
return UMC_ERR_INIT;
sequenceHeader.frame_count = 0;
sequenceHeader.stream_time = 0;
sequenceHeader.is_skipped_b = 0;
sequenceHeader.num_of_skipped = 0;
sequenceHeader.bdied = 0;
frame_buffer.prev_index = 0;
frame_buffer.curr_index = 0;
frame_buffer.next_index = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -