📄 maimpeg2dec.c
字号:
/* <LIC_AMD_STD> * Copyright (c) 2005 Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * The full GNU General Public License is included in this distribution in the * file called COPYING * </LIC_AMD_STD> *//* <CTL_AMD_STD> * </CTL_AMD_STD> *//* <DOC_AMD_STD> @doc MAI @module maimpeg2dec.c - Media Accelerator Interface, MPEG2 video decoder MAI video wrapper file. Contains wrapper interface for MPEG2 video decoder to MAI * </DOC_AMD_STD> */#include "mai_osal.h"#if defined(MAI_OS_WINDOWS)typedef unsigned short uint16_t;typedef signed short int16_t;typedef unsigned char uint8_t;typedef signed char int8_t;typedef signed __int64 int64_t;typedef unsigned __int64 uint64_t;typedef unsigned int uint32_t;typedef signed int int32_t;#else#include <inttypes.h>#endif#include <memory.h> /* for memset */#include "mai_component.h"#include "mai_param.h" /* for Get/SetParam */#include "mpeg2.h" /* libmpeg2 public header for APIs */#include "mai_compbase.h"#ifdef MAE_HW#include "mae_interface.h"#endifextern void setup_mae_driver(void *pvParamVideoAccel);/* enable display (non-MAE) */#if !defined(NO_DISPLAY)#if defined(MAI_OS_WINXP)#define VREND_SUPPORT#elif defined(MAI_OS_LINUX) && !defined(MAE_HW)#define VREND_SUPPORT#ifdef MAI_OS_WINCE#undef VREND_SUPPORT#endif /* MAI_OS_WINCE */#endif#endif/* send PTS to decoder on GOP boundary only *//* #define SETPTS_ON_GOP_ONLY */#ifdef VREND_SUPPORT#include "util_render.h"#endif#ifdef TRACE_BUILD#define ERRORPRINTF(_args_) MAIOSDebugPrint _args_#define APIPRINTF(_args_) MAIOSDebugPrint _args_#define DPRINTF(_args_) /* MAIOSDebugPrint _args_ */#define DPRINTF2(_args_) /* MAIOSDebugPrint _args_ */#define SYNCPRINTF(_args_) MAIOSDebugPrint _args_#else#define ERRORPRINTF(_args_) /* MAIOSDebugPrint _args_ */#define APIPRINTF(_args_) /* MAIOSDebugPrint _args_ */#define DPRINTF(_args_) /* MAIOSDebugPrint _args_ */#define DPRINTF2(_args_) /* MAIOSDebugPrint _args_ */#define SYNCPRINTF(_args_) /* MAIOSDebugPrint _args_ */#endif#if !defined(MAI_OS_LINUX)#define SYNC_SKIPPING_SUPPORT /* enable frame skipping if sync is falling behind */#endif#ifdef MAI_OS_WINCE//WinCE we use a single buffer so having we don't need to alloc so many#define DEFAULT_INBUFSIZE 32*1024#define DEFAULT_INBUFCOUNT 32#else#define DEFAULT_INBUFSIZE 16*1024#define DEFAULT_INBUFCOUNT 128#endif#define OUTPUT_MODE_NONE 0 /* output not sent anywhere */#define OUTPUT_MODE_VREND 1 /* output sent directly to video output */#define OUTPUT_MODE_OUTPUTPIN 2 /* output sent to output pin *//* Our component's private processor variables are stored here */typedef struct ProcessorInfo_s { mpeg2dec_t *m_pDecoder; unsigned int m_eOutputMode; unsigned int m_uiFrameCount; unsigned int m_uiOutputFrameCount; unsigned int m_uiErrorCount; MAIOSCritSec_t m_hCSDecode; unsigned long m_uiDisplayOnOff; unsigned int m_bVideoOpen; unsigned char *m_pVideoBuffer[3]; m_bool m_bFirstInput; MAITimeStamp_t m_tDecodePTS; /* PTS of last frame decoded */ MAITimeStamp_t m_tInputPTS; /* PTS of last packet on input */ MAICompBuffer_t *m_pOutBufferInfo; MAISpeed_e m_CurrentSpeed; MAISpeed_e m_NextSpeed; unsigned int m_uiCurrentDecodeMode; unsigned int m_uiNextDecodeMode; unsigned int m_uiFramesOutInMode; /* how many frames output since mode changed */ unsigned int m_uiSyncSkippingThreshold; /* threshold in millisecs to start skipping frames */ unsigned int m_uiSyncSkippingThresholdI; /* threshold in millisecs to start skipping to I-frames */ m_bool m_bCheckSync; unsigned int m_uiFramesSinceCheckSync;} ProcessorInfo_t;/* Function prototypes*/static void update_speed(ProcessorInfo_t *pPInfo, int bForceUpdate);#if 0/* obsolete - kept here to verify that compbase covers all information reported */static void _InBufferPoolStateCB(MAICompBufferPool_t hBufferPool, MAIBufState_e ePoolState, void *pUserData){ MAICompHandle_t hThisComp = (MAICompHandle_t)pUserData; /* This reports to us if BufferPool becomes: MAI_BUFSTATE_FILLED or MAI_BUFSTATE_EMPTY */ DPRINTF((M_TEXT("MPV2: _InBufferPoolStateCB() ePoolState=%d\n"), ePoolState)); if (g_pfProgressCB && (g_uiProgressSelectFlags & MAI_PROGRESS_BUFFER)!=0) { MAIProgressBuffer_t ProgressInfo; unsigned int uiMaxBufs; unsigned int uiMaxBufSize; unsigned int uiBufsFilled; unsigned int uiDataFilled; MAICompBufferPoolGetStatus(hBufferPool, &uiMaxBufs, &uiMaxBufSize, &uiBufsFilled, &uiDataFilled); /* setup progress info fields */ memset(&ProgressInfo, 0, sizeof(MAIProgressBuffer_t)); ProgressInfo.uiFlags=MAI_PROGRESSFLAG_TIMESTAMP; ProgressInfo.hComp=hThisComp; ProgressInfo.tCurrentTime = g_tLastPTS; ProgressInfo.eBufferUnitType=MAI_UNIT_BYTES; ProgressInfo.uiBufferAvail=(uiMaxBufs-uiBufsFilled)*uiMaxBufSize; ProgressInfo.uiBufferUsed=uiDataFilled; ProgressInfo.uiTotalBufferCount=uiMaxBufs; ProgressInfo.uiUsedBufferCount=uiBufsFilled; /* make progress call */ g_pfProgressCB(hThisComp, MAI_PROGRESS_BUFFER, &ProgressInfo, sizeof(ProgressInfo)); DPRINTF((M_TEXT("MPV2: _InBufferPoolStateCB() g_pfProgressCB done\n"))); }}#endif#define SETSKIPMODE(_pinfo, _skipframes) mpeg2_setskipmode(_pinfo->m_pDecoder, _skipframes)#define GETSKIPMODE(_pinfo) mpeg2_getskipmode(_pinfo->m_pDecoder)#define SETDECODEMODE(_pinfo, _mode, _speed) mpeg2_setmode(_pinfo->m_pDecoder, (mpeg2_decode_mode_t)_mode, _speed)#define GETDECODEMODE(_pinfo) mpeg2_getmode(_pinfo->m_pDecoder)static void update_speed(ProcessorInfo_t *pPInfo, int bForceUpdate){ unsigned int uiNewPlayRate=pPInfo->m_NextSpeed&MAI_SPEED_RATEMASK; if ((pPInfo->m_NextSpeed!=MAI_SPEED_UNSPECIFIED && pPInfo->m_CurrentSpeed!=pPInfo->m_NextSpeed) || pPInfo->m_uiCurrentDecodeMode!=pPInfo->m_uiNextDecodeMode) bForceUpdate=1; if (bForceUpdate && pPInfo->m_pDecoder) { MAISpeed_e NextSpeed=(pPInfo->m_NextSpeed==MAI_SPEED_UNSPECIFIED)?pPInfo->m_CurrentSpeed:pPInfo->m_NextSpeed; APIPRINTF((M_TEXT("MPV2: update_speed() NextSpeed=0x%X NextMode=%d\n"), pPInfo->m_NextSpeed, pPInfo->m_uiNextDecodeMode)); if (NextSpeed!=MAI_SPEED_UNSPECIFIED && pPInfo->m_CurrentSpeed!=pPInfo->m_NextSpeed && pPInfo->m_uiCurrentDecodeMode==pPInfo->m_uiNextDecodeMode) { /* Speed is changing, and there has been no request to change decode mode, */ /* so just translate the new speed to the decode mode */ APIPRINTF((M_TEXT("MPV2: update_speed() 0x%X->0x%X\n"), pPInfo->m_CurrentSpeed, pPInfo->m_NextSpeed)); if ((NextSpeed&MAI_SPEED_REVERSEFLAG)!=0) pPInfo->m_uiNextDecodeMode=DECODE_I_ONLY; else if (uiNewPlayRate>MAI_SPEED_4X) pPInfo->m_uiNextDecodeMode=DECODE_I_ONLY; else if (uiNewPlayRate>=MAI_SPEED_2X) pPInfo->m_uiNextDecodeMode=DECODE_IP_ONLY; else pPInfo->m_uiNextDecodeMode=DECODE_NORMAL; } /* set mode in decoder */ APIPRINTF((M_TEXT("MPV2: update_speed() mpeg2_setmode(mode=%d, speed=0x%X)\n"), pPInfo->m_uiNextDecodeMode, pPInfo->m_NextSpeed)); if (pPInfo->m_NextSpeed!=pPInfo->m_CurrentSpeed) { APIPRINTF((M_TEXT("MPV2: update_speed() mpeg2_setmode(mode=%d, speed=0x%X) playback direction change\n"), pPInfo->m_uiNextDecodeMode, pPInfo->m_NextSpeed)); mpeg2_setdiscontinuity(pPInfo->m_pDecoder, 1); } SETDECODEMODE(pPInfo, pPInfo->m_uiNextDecodeMode, NextSpeed); pPInfo->m_uiCurrentDecodeMode=pPInfo->m_uiNextDecodeMode; /* remember mode */ pPInfo->m_CurrentSpeed=NextSpeed; }}#ifdef SYNC_SKIPPING_SUPPORTstatic void check_sync(ProcessorInfo_t *pPInfo, MAIParamClock_t *pClock){ mpeg_time_t tCurrent=0; SYNCPRINTF((M_TEXT("MPV2:check_sync() CurrentSpeed=0x%08X\n"), pPInfo->m_CurrentSpeed)); pPInfo->m_bCheckSync=M_TRUE; pPInfo->m_uiFramesSinceCheckSync=0; /* track how frequently check_sync is called */ mpeg2_gettimestamp (pPInfo->m_pDecoder, &tCurrent); if ((pClock->uiFlags&MAI_CLOCK_FLAG_SYNCTHRESHOLD)!=0) { pPInfo->m_uiSyncSkippingThreshold=pClock->uiParam1; pPInfo->m_uiSyncSkippingThresholdI=pClock->uiParam1*6; /* check for resonable I frame skipping thresholds */ if (pPInfo->m_uiSyncSkippingThresholdI>800) pPInfo->m_uiSyncSkippingThresholdI=800; else if (pPInfo->m_uiSyncSkippingThresholdI<150) pPInfo->m_uiSyncSkippingThresholdI=150; } if (pPInfo->m_CurrentSpeed==MAI_SPEED_NORMAL) { if ((pClock->uiFlags&MAI_CLOCK_FLAG_CURRENTTIME)!=0) { int iTimeDiff=(int)(MAITIME_LO32(pClock->tCurrentTime)-MAITIME_LO32(tCurrent)); SYNCPRINTF((M_TEXT("MPV2:check_sync() DecodePTS=%d TimeDiff=%d Threshold=%d PlayDecodeMode=%d FInMode=%d\n"), MAITIME_LO32(tCurrent), iTimeDiff, pPInfo->m_uiSyncSkippingThreshold, pPInfo->m_uiCurrentDecodeMode, pPInfo->m_uiFramesOutInMode)); if (pPInfo->m_uiFramesOutInMode>=1) /* have we decoded some frames in the current decode mode? */ { int iSkipMoreOrLess=0; /* <0==less skipping, 0==leave mode, >0==more skipping */ unsigned int eCurrentMode=GETDECODEMODE(pPInfo); unsigned int uiSkipMode = 1; if (eCurrentMode == DECODE_I_ONLY) uiSkipMode = GETSKIPMODE(pPInfo); /* determine if we should increase or decrease skipping based on thresholds */ if (iTimeDiff>(int)pPInfo->m_uiSyncSkippingThreshold) { /* video is falling behind - we'll gracefully adjust skipping mode as needed */ if (eCurrentMode == DECODE_NORMAL) iSkipMoreOrLess=1; else if (iTimeDiff>(int)pPInfo->m_uiSyncSkippingThresholdI) { if (eCurrentMode == DECODE_IP_ONLY) { /* increase skipping from IP mode only */ if (pPInfo->m_uiFramesOutInMode>15) /* help smooth transitions, we've processed several frames in this mode */ iSkipMoreOrLess=1; } /* I_ONLY */ else if (tCurrent>0 /* ensure we don't skip too much at preroll (negative timestamps) */ && uiSkipMode<=4) /* limit highest practical skipping to every 8 frames */ { if (pPInfo->m_uiFramesOutInMode>30) /* help smooth transitions, we've processed several frames in this mode */ iSkipMoreOrLess=1; } } else if (eCurrentMode == DECODE_I_ONLY) iSkipMoreOrLess=-1; /* reduce I-frame skipping */ } else if (iTimeDiff<0) /* video is catching up */ { if (eCurrentMode != DECODE_NORMAL) { if (iTimeDiff<-200) iSkipMoreOrLess=-2; /* reduce skipping faster */ else if (eCurrentMode == DECODE_I_ONLY) iSkipMoreOrLess=-1; /* reduce skipping one mode */ } } if (iSkipMoreOrLess) /* we need to increase or decrease skipping mode */ { SYNCPRINTF((M_TEXT("MPV2:check_sync() MoreLess=%d CurrentMode=%d Diff=%d Thresh=%d FInMode=%d Skip=%d\n"), iSkipMoreOrLess, eCurrentMode, iTimeDiff, pPInfo->m_uiSyncSkippingThreshold, pPInfo->m_uiFramesOutInMode, uiSkipMode)); if (iSkipMoreOrLess>0) { /* bump up the skipping mode to maintain sync */ if (eCurrentMode == DECODE_NORMAL) { SYNCPRINTF((M_TEXT("MPV2:check_sync() IP-frames\n"))); SETDECODEMODE(pPInfo, DECODE_IP_ONLY, pPInfo->m_CurrentSpeed); pPInfo->m_uiFramesOutInMode=0; } else if (eCurrentMode == DECODE_IP_ONLY) { SYNCPRINTF((M_TEXT("MPV2:check_sync() I-Frames skipmode 1\n"))); SETDECODEMODE(pPInfo, DECODE_I_ONLY, pPInfo->m_CurrentSpeed); SETSKIPMODE(pPInfo, 1); pPInfo->m_uiFramesOutInMode=0; } else if (eCurrentMode == DECODE_I_ONLY) { /* already in I Frame only decode mode, bump up I-frame skipping */ unsigned int uiNewSkipMode=uiSkipMode+1; SYNCPRINTF((M_TEXT("MPV2:check_sync() I-Frames: increase skipping %d->%d\n"), uiSkipMode, uiNewSkipMode)); SETSKIPMODE(pPInfo, uiNewSkipMode); pPInfo->m_uiFramesOutInMode=0; } } else if (iSkipMoreOrLess<0) /* reduce skipping */ { /* bump down the skipping mode (we're catching up) */ if (eCurrentMode == DECODE_I_ONLY && ((int)uiSkipMode + iSkipMoreOrLess)>0) { /* I-Frame only skipping mode */ unsigned int uiNewSkipMode=uiSkipMode; if (iSkipMoreOrLess==-1) /* step down I-frame only skipping */ uiNewSkipMode=uiSkipMode-1; else if (iSkipMoreOrLess<-1) /* step down quicker */ uiNewSkipMode=uiSkipMode/2; if (uiNewSkipMode==0) uiNewSkipMode=1; SYNCPRINTF((M_TEXT("MPV2:check_sync() I-Frames: reduce skipping %d->%d\n"), uiSkipMode, uiNewSkipMode)); SETSKIPMODE(pPInfo, uiNewSkipMode); } else if (eCurrentMode == DECODE_I_ONLY && iSkipMoreOrLess==-1) { /* go from I mode to IP mode */ SYNCPRINTF((M_TEXT("MPV2:check_sync() IP-frames\n"))); SETSKIPMODE(pPInfo, 1); SETDECODEMODE(pPInfo, DECODE_IP_ONLY, pPInfo->m_CurrentSpeed); } else { /* go back to normal mode */ SYNCPRINTF((M_TEXT("MPV2:check_sync() Play NORMAL\n"))); SETDECODEMODE(pPInfo, DECODE_NORMAL, pPInfo->m_CurrentSpeed); } pPInfo->m_uiFramesOutInMode=0; } } /* if (iSkipMoreOrLess) */ } } }}#endif /* SYNC_SKIPPING_SUPPORT */MAIStatus_e _newformat(MAICompHandle_t hComp){ ProcessorInfo_t *pPInfo=(ProcessorInfo_t *)HCOMP_TO_USERINFO(hComp); MAIStatus_e eStatus = MAI_STATUS_OK; int szY, szUV; const mpeg2_info_t *pInfo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -