/***************************************************************************** * * 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 * * $Id: softidct.c 543 2006-01-07 22:06:24Z picard $ * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #include "../common.h" #include "softidct.h" #ifndef MIPS64 #define MemCpy8 memcpy #define MemSet8 memset #else static void MemCpy8(void* dst,void* src,int len) { __asm( "addi $6,$6,-16;" "bltz $6,cpyskip16;" "cpyloop16:" "ldr $10,0($5);" "addi $6,$6,-16;" "ldr $11,8($5);" #ifdef MIPSVR41XX ".set noreorder;" "cache 13,0($4);" //cache without loading ".set reorder;" #endif "sdr $10,0($4);" "addi $5,$5,16;" "sdr $11,8($4);" "addi $4,$4,16;" "bgez $6,cpyloop16;" "cpyskip16:" "andi $6,$6,8;" "beq $6,$0,cpyskip8;" "ldr $10,0($5);" "sdr $10,0($4);" "cpyskip8:"); } static void MemSet8(void* dst,int v,int len) { __asm( "dsll $10,$5,56;" "dsrl $11,$10,8;" "or $10,$10,$11;" "dsrl $11,$10,16;" "or $10,$10,$11;" "dsrl $11,$10,32;" "or $10,$10,$11;" "addi $6,$6,-16;" "bltz $6,setskip16;" "setloop16:" #ifdef MIPSVR41XX ".set noreorder;" "cache 13,0($4);" //cache without loading ".set reorder;" #endif "sdr $10,0($4);" "addi $6,$6,-16;" "sdr $10,8($4);" "addi $4,$4,16;" "bgez $6,setloop16;" "setskip16:" "andi $6,$6,8;" "beq $6,$0,setskip8;" "sdr $10,0($4);" "setskip8:"); } #endif static void FillEdge(uint8_t *Ptr, int Width, int Height, int EdgeX, int EdgeY) { int n; uint8_t *p; int InnerWidth = Width - EdgeX*2; int InnerHeight = Height - EdgeY*2; // left and right p = Ptr + EdgeX + EdgeY * Width; for (n=0;nBufWidth, p->BufHeight, EDGE, EDGE); Ptr += p->YToU; FillEdge(Ptr, p->BufWidth>>p->UVX2, p->BufHeight>>p->UVY2, EDGE>>p->UVX2, EDGE>>p->UVY2); Ptr += p->YToU >> (p->UVX2+p->UVY2); FillEdge(Ptr, p->BufWidth>>p->UVX2, p->BufHeight>>p->UVY2, EDGE>>p->UVX2, EDGE>>p->UVY2); } #if defined(MIPS64_WIN32) static int TouchPages(softidct* p) { uint8_t* i; int Sum = 0; for (i=p->CodeBegin;iCodeEnd;i+=p->CodePage) Sum += *i; return Sum; } #endif static int Lock(softidct* p,int No,planes Planes,int* Brightness,video* Format) { if (Brightness) *Brightness = 0; if (Format) { *Format = p->Out.Format.Format.Video; Format->Pitch = p->BufWidth; Format->Width = p->BufWidth - 2*EDGE; Format->Height = p->BufHeight - 2*EDGE; } if (No<0 || No>=p->BufCount) { Planes[0] = NULL; Planes[1] = NULL; Planes[2] = NULL; return ERR_INVALID_PARAM; } Planes[0] = p->Buffer[No] + EDGE + EDGE*p->BufWidth; Planes[1] = p->Buffer[No] + p->YToU + (EDGE >> p->UVX2) + (EDGE >> p->UVY2)*(p->BufWidth >> p->UVX2); Planes[2] = (uint8_t*)Planes[1] + (p->YToU >> (p->UVX2+p->UVY2)); return ERR_NONE; } static void Unlock(softidct* p,int No) { } #if defined(CONFIG_IDCT_LOWRES) static const copyblock AllCopyBlock4x4[2][16] = //[Rounding][x][y] { { CopyBlock4x4_00, CopyBlock4x4_01, CopyBlock4x4_02, CopyBlock4x4_03, CopyBlock4x4_10, CopyBlock4x4_11, CopyBlock4x4_12, CopyBlock4x4_13, CopyBlock4x4_20, CopyBlock4x4_21, CopyBlock4x4_22, CopyBlock4x4_23, CopyBlock4x4_30, CopyBlock4x4_31, CopyBlock4x4_32, CopyBlock4x4_33 }, { CopyBlock4x4_00, CopyBlock4x4_01R, CopyBlock4x4_02R, CopyBlock4x4_03R, CopyBlock4x4_10R, CopyBlock4x4_11R, CopyBlock4x4_12R, CopyBlock4x4_13R, CopyBlock4x4_20R, CopyBlock4x4_21R, CopyBlock4x4_22R, CopyBlock4x4_23R, CopyBlock4x4_30R, CopyBlock4x4_31R, CopyBlock4x4_32R, CopyBlock4x4_33R }, }; #ifndef MIPS32 const addblock TableAddBlock4x4[16] = { AddBlock4x4_00,AddBlock4x4_01,AddBlock4x4_02,AddBlock4x4_03, AddBlock4x4_10,AddBlock4x4_11,AddBlock4x4_12,AddBlock4x4_13, AddBlock4x4_20,AddBlock4x4_21,AddBlock4x4_22,AddBlock4x4_23, AddBlock4x4_30,AddBlock4x4_31,AddBlock4x4_32,AddBlock4x4_33, }; #endif #endif static const copyblock AllCopyBlock[2][4] = //[Rounding][x][y] { { CopyBlock, CopyBlockHor, CopyBlockVer, CopyBlockHorVer }, { CopyBlock, CopyBlockHorRound, CopyBlockVerRound, CopyBlockHorVerRound } }; #ifdef MIPS64 static const copyblock AllCopyBlockM[2][4] = //[Rounding][x][y] { { CopyMBlock, CopyMBlockHor, CopyMBlockVer, CopyMBlockHorVer }, { CopyMBlock, CopyMBlockHorRound, CopyMBlockVerRound, CopyMBlockHorVerRound } }; #endif static int UpdateRounding(softidct* p) { #if defined(CONFIG_IDCT_LOWRES) if (p->Shift) p->CopyBlock4x4 = AllCopyBlock4x4[p->Rounding]; else #endif memcpy(p->CopyBlock,p->AllCopyBlock[p->Rounding],sizeof(copyblock)*4); #ifdef MIPS64 p->CopyMBlock = AllCopyBlockM[p->Rounding]; // no shift, instead 16x16 #endif return ERR_NONE; } static const idctprocess Process[3] = // pixelformat { (idctprocess)Process420, (idctprocess)Process422, (idctprocess)Process444, }; static const idctcopy Copy16x16[3] = // pixelformat { (idctcopy)Copy420, NULL, NULL, }; #ifdef CONFIG_IDCT_SWAP static const idctprocess ProcessSwap[3] = // pixelformat { (idctprocess)Process420Swap, (idctprocess)Process422Swap, (idctprocess)Process444Swap }; static const idctcopy Copy16x16Swap[3] = // pixelformat { (idctcopy)Copy420Swap, NULL, NULL, }; #endif #if defined(CONFIG_IDCT_LOWRES) static const idctprocess ProcessHalf[3] = // pixelformat { (idctprocess)Process420Half, (idctprocess)Process422Half, (idctprocess)Process444Half }; static const idctprocess ProcessQuarter[3] = // pixelformat { (idctprocess)Process420Quarter, (idctprocess)Process422Quarter, (idctprocess)Process444Quarter, }; static const idctcopy Copy16x16Half[3] = // pixelformat { (idctcopy)Copy420Half, NULL, NULL, }; #endif static bool_t AllocBuffer(softidct* p,int i,block* Block,uint8_t** Ptr) { #ifndef MIPS int Align = 32; int Offset = 0; #else int Align = 8192; int Offset = ((i>>1)+(i&1)*2)*2048; #endif if (!AllocBlock(p->BufSize+Align+Offset,Block,0,HEAP_ANYWR)) return 0; if (i>=2 && AvailMemory()<64*1024) { FreeBlock(Block); ShowOutOfMemory(); return 0; } *Ptr = (uint8_t*)(((uintptr_t)Block->Ptr + Align-1) & ~(Align-1)) + Offset; return 1; } static int SetBufferCount(softidct* p, int n, int Temp) { int i; n += Temp; if (n>p->MaxCount) return ERR_NOT_SUPPORTED; for (i=n;iBufCount;++i) { FreeBlock(&p->_Buffer[i]); p->Buffer[i] = NULL; p->BufAlloc[i] = 0; } if (p->BufCount > n) p->BufCount = n; for (i=p->BufCount;iBufSize) p->Buffer[i] = NULL; else if (!AllocBuffer(p,i,&p->_Buffer[i],&p->Buffer[i])) { p->MaxCount = p->BufCount; break; } p->BufAlloc[i] = p->BufSize; p->BufBorder[i] = 0; p->BufFrameNo[i] = -1; p->BufCount = i+1; } if (p->ShowNext >= p->BufCount) p->ShowNext = -1; if (p->ShowCurr >= p->BufCount) p->ShowCurr = -1; p->LastTemp = Temp && p->BufCount == n; if (p->BufCount != n) return ERR_OUT_OF_MEMORY; return ERR_NONE; } static int UpdateFormat(softidct* p) { if (p->Out.Format.Type == PACKET_VIDEO) { int AlignX,AlignY,Mode; int BlockSize; PlanarYUV(&p->Out.Format.Format.Video.Pixel,&p->UVX2,&p->UVY2,NULL); AlignX = (8 << p->UVX2) - 1; AlignY = (8 << p->UVY2) - 1; if (!p->BufferWidth || !p->BufferHeight) p->BufWidth = p->BufHeight = 0; else { p->BufWidth = (((p->BufferWidth+AlignX)&~AlignX) >> p->Shift)+2*EDGE; p->BufHeight = (((p->BufferHeight+AlignY)&~AlignY) >> p->Shift)+2*EDGE; } if (p->Out.Format.Format.Video.Direction & DIR_SWAPXY) SwapInt(&p->BufWidth,&p->BufHeight); p->YToU = p->BufHeight * p->BufWidth; p->BufSize = p->YToU + 2*(p->YToU >> (p->UVX2+p->UVY2)); p->BufWidthUV = p->BufWidth >> p->UVX2; p->Out.Format.Format.Video.Pitch = p->BufWidth; BlockSize = 8 >> p->Shift; if (p->Out.Format.Format.Video.Pixel.Flags & PF_YUV420) { Mode = 0; p->Tab[0] = 2*(BlockSize); //Y[0;0] -> Y[0;1] p->Tab[1] = 2*(BlockSize*p->BufWidth-BlockSize); //Y[0;1] -> Y[1;0] p->Tab[2] = 2*(BlockSize); //Y[1;0] -> Y[1;1] p->Tab[4] = 2*(p->YToU >> 2); //U->V p->Tab[5] = 2*(0); } else if (p->Out.Format.Format.Video.Pixel.Flags & PF_YUV422) { Mode = 1; p->Tab[0] = 2*(BlockSize); //Y[0;0] -> Y[0;1] p->Tab[2] = 2*(p->YToU >> 1); //U->V p->Tab[3] = 2*(0); } else if (p->Out.Format.Format.Video.Pixel.Flags & PF_YUV444) { Mode = 2; p->Tab[0] = 2*(p->YToU); //Y->U p->Tab[1] = 2*(p->YToU); //U->V p->Tab[2] = 2*(0); } else return ERR_NOT_SUPPORTED; if (Mode==0 && (p->Mode & IDCTMODE_QPEL)) { p->IDCT.MComp8x8 = p->QPELMComp8x8; p->IDCT.MComp16x16 = p->QPELMComp16x16; } else { p->IDCT.MComp8x8 = (idctmcomp) SoftMComp8x8; p->IDCT.MComp16x16 = (idctmcomp) SoftMComp16x16; } #if defined(CONFIG_IDCT_LOWRES) if (p->Shift == 1) { p->IDCT.Process = ProcessHalf[Mode]; p->IDCT.Copy16x16 = Copy16x16Half[Mode]; p->IDCT.Intra8x8 = (idctintra)Intra8x8Half; } else if (p->Shift == 2) { p->IDCT.Process = ProcessQuarter[Mode]; p->IDCT.Intra8x8 = (idctintra)Intra8x8Quarter; p->IDCT.Copy16x16 = NULL; } else #endif #ifdef CONFIG_IDCT_SWAP if (p->Out.Format.Format.Video.Direction & DIR_SWAPXY) { p->IDCT.Process = ProcessSwap[Mode]; p->IDCT.Copy16x16 = Copy16x16Swap[Mode]; p->IDCT.Intra8x8 = p->Intra8x8Swap; p->IDCT.MComp8x8 = (idctmcomp) SoftMComp8x8Swap; p->IDCT.MComp16x16 = (idctmcomp) SoftMComp16x16Swap; if (Mode == 0) { p->Tab[0] = 2*(8*p->BufWidth); //Y[0;0] -> Y[1;0] p->Tab[1] = 2*(8-8*p->BufWidth); //Y[1;0] -> Y[0;1] p->Tab[2] = 2*(8*p->BufWidth); //Y[0;1] -> Y[1;1] } } else #endif { p->IDCT.Process = Process[Mode]; p->IDCT.Copy16x16 = Copy16x16[Mode]; p->IDCT.Intra8x8 = p->Intra8x8; } #if defined(MIPS64) p->IDCT.Inter8x8 = Inter8x8Add; #endif } return ConnectionUpdate((node*)p,IDCT_OUTPUT,p->Out.Pin.Node,p->Out.Pin.No); } #ifdef CONFIG_IDCT_SWAP static int ChangeSwap(softidct* p) { if (p->BufCount > 0) { int No; planes TmpPlanes; video TmpFormat; int Brightness; video Format[2]; planes Planes[2]; TmpFormat = p->Out.Format.Format.Video; TmpFormat.Width = p->BufWidth - 2*EDGE; TmpFormat.Height = p->BufHeight - 2*EDGE; if (SurfaceAlloc(TmpPlanes,&TmpFormat) == ERR_NONE) { if (Lock(p,0,Planes[0],&Brightness,&Format[0])==ERR_NONE) { SurfaceCopy(&Format[0],&TmpFormat,Planes[0],TmpPlanes,NULL); Unlock(p,0); } for (No=1;NoBufCount;++No) if (Lock(p,No,Planes[0],&Brightness,&Format[0])==ERR_NONE) { SwapInt(&p->BufWidth,&p->BufHeight); if (Lock(p,0,Planes[1],&Brightness,&Format[1])==ERR_NONE) { block Tmp; SurfaceRotate(&Format[0],&Format[1],Planes[0],Planes[1],DIR_SWAPXY); Unlock(p,0); SwapPByte(&p->Buffer[No],&p->Buffer[0]); Tmp = p->_Buffer[0]; p->_Buffer[0] = p->_Buffer[No]; p->_Buffer[No] = Tmp; p->BufBorder[No] = 0; SwapInt(&p->BufAlloc[No],&p->BufAlloc[0]); } SwapInt(&p->BufWidth,&p->BufHeight); Unlock(p,No); } SwapInt(&p->BufWidth,&p->BufHeight); if (Lock(p,0,Planes[0],&Brightness,&Format[0])==ERR_NONE) { SurfaceRotate(&TmpFormat,&Format[0],TmpPlanes,Planes[0],DIR_SWAPXY); Unlock(p,0); p->BufBorder[0] = 0; } SwapInt(&p->BufWidth,&p->BufHeight); SurfaceFree(TmpPlanes); } } p->Out.Format.Format.Video.Direction ^= DIR_SWAPXY; SwapInt(&p->Out.Format.Format.Video.Width,&p->Out.Format.Format.Video.Height); SwapInt(&p->OutWidth,&p->OutHeight); return UpdateFormat(p); } #endif static int Send(softidct* p,tick_t RefTime,const flowstate* State); static int VerifyShift(softidct* p,int Shift) { // have to keep dword pitch alignment if (p->BufferWidth && Shift>0) { int AlignX = (8 << p->UVX2) - 1; int BufWidth = ((p->BufferWidth+AlignX)&~AlignX) >> (Shift+p->UVX2); if (BufWidth & 1) { Shift -= 2; } else if (BufWidth & 3) { --Shift; } if (Shift<0) Shift=0; } return Shift; } static int SetShift(softidct* p,int Shift,int Count) { #if !defined(CONFIG_IDCT_LOWRES) return ERR_NOT_SUPPORTED; #else if (Shift<0 || Shift>2) return ERR_NOT_SUPPORTED; #ifdef CONFIG_IDCT_SWAP if (Shift>0 && (p->Out.Format.Format.Video.Direction & DIR_SWAPXY)) ChangeSwap(p); #endif Shift = VerifyShift(p,Shift); if (p->Shift != Shift) { flowstate State; blitfx FX; planes Src[MAXIDCTBUF]; planes Dst; video SrcFormat; video DstFormat; uint8_t *TmpPtr = NULL; planes Tmp; block TmpBlock; int Diff = Shift - p->Shift; int i; if (AllocBlock(p->BufSize+16,&TmpBlock,0,HEAP_ANYWR)) { TmpPtr = (uint8_t*)ALIGN16((uintptr_t)TmpBlock.Ptr); Tmp[0] = TmpPtr + EDGE + EDGE*p->BufWidth; Tmp[1] = TmpPtr + p->YToU + (EDGE >> p->UVX2) + (EDGE >> p->UVY2)*(p->BufWidth >> p->UVX2); Tmp[2] = (uint8_t*)Tmp[1] + (p->YToU >> (p->UVX2+p->UVY2)); } for (i=0;iOut.Format.Format.Video.Width = p->OutWidth >> Shift; p->Out.Format.Format.Video.Height = p->OutHeight >> Shift; memset(&FX,0,sizeof(FX)); if (Diff>0) { FX.ScaleX = SCALE_ONE >> Diff; FX.ScaleY = SCALE_ONE >> Diff; } else { FX.ScaleX = SCALE_ONE << -Diff; FX.ScaleY = SCALE_ONE << -Diff; } p->Shift = Shift; UpdateRounding(p); UpdateFormat(p); for (i=0;iBufAlloc[i] < p->BufSize) { uint8_t* Ptr; block Block; if (!AllocBuffer(p,i,&Block,&Ptr)) // realloc buffer if neccessary) { if (TmpPtr) FreeBlock(&TmpBlock); SetShift(p,Shift - Diff,i); // restore (shrinking won't need more memory) return ERR_OUT_OF_MEMORY; } FreeBlock(&p->_Buffer[i]); p->Buffer[i] = Ptr; p->_Buffer[i] = Block; p->BufAlloc[i] = p->BufSize; } if (TmpPtr) { Lock(p,i,Dst,NULL,&DstFormat); SurfaceCopy(&SrcFormat,&DstFormat,Tmp,Dst,&FX); } p->BufBorder[i] = 0; } if (TmpPtr) FreeBlock(&TmpBlock); State.CurrTime = TIME_RESEND; State.DropLevel = 0; Send(p,TIME_UNKNOWN,&State); } return ERR_NONE; #endif } static int UpdateMode(softidct* p) { if (p->Mode & ~p->ModeSupported) return ERR_NOT_SUPPORTED; #ifdef CONFIG_IDCT_SWAP if (p->Mode && (p->Out.Format.Format.Video.Direction & DIR_SWAPXY)) ChangeSwap(p); #endif #if defined(CONFIG_IDCT_LOWRES) if (p->Mode && p->Shift) return SetShift(p,0,p->BufCount); #endif UpdateRounding(p); UpdateFormat(p); return ERR_NONE; } static int SetFormat(softidct* p, const video* Format) { SetBufferCount(p,0,0); PacketFormatClear(&p->Out.Format); if (Format) { size_t Area; if (!(Format->Pixel.Flags & (PF_YUV420|PF_YUV422|PF_YUV444))) return ERR_NOT_SUPPORTED; p->Out.Format.Type = PACKET_VIDEO; p->Out.Format.Format.Video = *Format; if (p->Out.Format.Format.Video.Direction & DIR_SWAPXY) SwapInt(&p->Out.Format.Format.Video.Width,&p->Out.Format.Format.Video.Height); p->Out.Format.Format.Video.Direction = 0; p->Out.Format.Format.Video.Pixel.Flags |= PF_16ALIGNED | PF_SAFEBORDER; p->MaxCount = MAXBUF; p->Rounding = 0; Area = p->Out.Format.Format.Video.Width * p->Out.Format.Format.Video.Height; if (Area >= 1024*1024 && AvailMemory() < Area*2) { video Desktop; size_t DesktopArea; QueryDesktop(&Desktop); DesktopArea = Desktop.Width * Desktop.Height; if (Area >= DesktopArea*4 && p->Shift<1) p->Shift = 1; if (Area >= DesktopArea*16 && p->Shift<2) p->Shift = 2; } p->Shift = VerifyShift(p,p->Shift); #if defined(MIPS64) if (p->Shift>0) return ERR_NOT_SUPPORTED; // fallback to mips32 #endif p->OutWidth = p->Out.Format.Format.Video.Width; p->OutHeight = p->Out.Format.Format.Video.Height; p->Out.Format.Format.Video.Width >>= p->Shift; p->Out.Format.Format.Video.Height >>= p->Shift; UpdateRounding(p); } #ifdef FREESCALE_MX1 if (p->MX1) { volatile int* Cmd = p->MX1-64; //0x22400 volatile int* GCCR = p->MX1-6972; //0x1B810 if (Format) { *GCCR |= 2; ThreadSleep(1); *Cmd = 0x284C+0x20; ThreadSleep(1); *Cmd = 0x284D; } else { *Cmd = 0x00; *GCCR &= ~2; } } #endif return UpdateFormat(p); } static int Set(softidct* p, int No, const void* Data, int Size) { flowstate State; int Result = ERR_INVALID_PARAM; switch (No) { case NODE_SETTINGSCHANGED: p->NeedLast = QueryAdvanced(ADVANCED_SLOW_VIDEO); break; case IDCT_SHOW: SETVALUE(p->ShowNext,int,ERR_NONE); if (p->ShowNext >= p->BufCount) p->ShowNext = -1; break; case FLOW_FLUSH: p->ShowCurr = -1; p->ShowNext = -1; return ERR_NONE; case IDCT_BACKUP: assert(Size == sizeof(idctbackup)); Result = IDCTRestore(&p->IDCT,(idctbackup*)Data); break; case IDCT_MODE: SETVALUECMP(p->Mode,int,UpdateMode(p),EqInt); break; case IDCT_BUFFERWIDTH: SETVALUE(p->BufferWidth,int,ERR_NONE); break; case IDCT_BUFFERHEIGHT: SETVALUE(p->BufferHeight,int,ERR_NONE); break; case IDCT_FORMAT: assert(Size == sizeof(video) || !Data); Result = SetFormat(p,(const video*)Data); break; case IDCT_OUTPUT|PIN_PROCESS: SETVALUE(p->Out.Process,packetprocess,ERR_NONE); break; #ifdef CONFIG_IDCT_SWAP case IDCT_OUTPUT|PIN_FORMAT: assert(Size == sizeof(packetformat) || !Data); if (Data && QueryAdvanced(ADVANCED_IDCTSWAP) && !p->Shift && !p->Mode && !(p->Out.Format.Format.Video.Pixel.Flags & PF_YUV422) && PacketFormatRotatedVideo(&p->Out.Format,(packetformat*)Data,DIR_SWAPXY)) Result = ChangeSwap(p); break; #endif case IDCT_OUTPUT: SETVALUE(p->Out.Pin,pin,ERR_NONE); break; case IDCT_ROUNDING: SETVALUE(p->Rounding,bool_t,UpdateRounding(p)); break; case IDCT_SHIFT: assert(Size == sizeof(int)); Result = SetShift(p,*(const int*)Data,p->BufCount); break; case IDCT_BUFFERCOUNT: assert(Size == sizeof(int)); Result = ERR_NONE; if (p->BufCount < *(const int*)Data) Result = SetBufferCount(p,*(const int*)Data,0); break; case FLOW_RESEND: State.CurrTime = TIME_RESEND; State.DropLevel = 0; Result = Send(p,TIME_UNKNOWN,&State); break; } if (No>=IDCT_FRAMENO && NoBufCount) SETVALUE(p->BufFrameNo[No-IDCT_FRAMENO],int,ERR_NONE); return Result; } static int Get(softidct* p, int No, void* Data, int Size) { int Result = ERR_INVALID_PARAM; switch (No) { case FLOW_BUFFERED: GETVALUE(1,bool_t); break; case IDCT_OUTPUT|PIN_PROCESS: GETVALUE(p->Out.Process,packetprocess); break; case IDCT_OUTPUT|PIN_FORMAT: GETVALUE(p->Out.Format,packetformat); break; case IDCT_OUTPUT: GETVALUE(p->Out.Pin,pin); break; case IDCT_FORMAT: GETVALUE(p->Out.Format.Format.Video,video); break; case IDCT_ROUNDING: GETVALUE(p->Rounding,bool_t); break; case IDCT_SHIFT: GETVALUE(p->Shift,int); break; case IDCT_MODE: GETVALUE(p->Mode,int); break; case IDCT_BUFFERCOUNT: GETVALUE(p->BufCount - p->LastTemp,int); break; case IDCT_BUFFERWIDTH: GETVALUE(p->BufferWidth,int); break; case IDCT_BUFFERHEIGHT: GETVALUE(p->BufferHeight,int); break; case IDCT_SHOW: GETVALUE(p->ShowNext,int); break; case IDCT_BACKUP: assert(Size == sizeof(idctbackup)); Result = IDCTBackup(&p->IDCT,(idctbackup*)Data); break; } if (No>=IDCT_FRAMENO && NoBufCount) GETVALUE(p->BufFrameNo[No-IDCT_FRAMENO],int); return Result; } static void Drop(softidct* p) { int i; for (i=0;iBufCount;++i) p->BufFrameNo[i] = -1; } static int Null(softidct* p,const flowstate* State,bool_t Empty) { packet* Packet = NULL; packet EmptyPacket; flowstate DropState; if (!State) { DropState.CurrTime = TIME_UNKNOWN; DropState.DropLevel = 1; State = &DropState; } if (Empty) { memset(&EmptyPacket,0,sizeof(EmptyPacket)); EmptyPacket.RefTime = TIME_UNKNOWN; Packet = &EmptyPacket; } return p->Out.Process(p->Out.Pin.Node,Packet,State); } static int Send(softidct* p,tick_t RefTime,const flowstate* State) { packet Packet; int Result = ERR_INVALID_DATA; if (State->DropLevel) return p->Out.Process(p->Out.Pin.Node,NULL,State); if (p->ShowNext < 0) return ERR_NEED_MORE_DATA; if (p->ShowCurr == p->ShowNext) p->ShowCurr = -1; if (Lock(p,p->ShowNext,*(planes*)&Packet.Data,NULL,NULL) == ERR_NONE) { Lock(p,p->ShowCurr,*(planes*)&Packet.LastData,NULL,NULL); Packet.RefTime = RefTime; Result = p->Out.Process(p->Out.Pin.Node,&Packet,State); Unlock(p,p->ShowCurr); Unlock(p,p->ShowNext); } if (Result != ERR_BUFFER_FULL) p->ShowCurr = p->ShowNext; return Result; } static int FrameStart(softidct* p,int FrameNo,int* OldFrameNo,int DstNo,int BackNo,int FwdNo,int ShowNo,bool_t Drop) { #if defined(MIPS64_WIN32) // win32 doesn't support 64bit natively. thread and process // changes won't save upper part of 64bit registers. // we have to disable interrupt and make sure all 1KB // code pages are in memory so no page loading is called // during code execution p->KMode = KernelMode(1); TouchPages(p); DisableInterrupts(); p->NextIRQ = 0; #endif if (!p->CopyBlock && (BackNo>=0 || FwdNo>=0)) return ERR_NOT_SUPPORTED; #ifdef ARM // ShowCurr will be the next "LastData" in output packet // we don't want to lose it's content if (p->NeedLast && p->ShowCurr == DstNo) { int SwapNo; for (SwapNo=0;SwapNoBufCount;++SwapNo) if (SwapNo != DstNo && SwapNo != BackNo && SwapNo != FwdNo && SwapNo != ShowNo) break; if (SwapNo < p->BufCount || SetBufferCount(p,p->BufCount,1)==ERR_NONE) { //DEBUG_MSG2("IDCT Swap %d,%d",SwapNo,DstNo); block Tmp; Tmp = p->_Buffer[SwapNo]; p->_Buffer[SwapNo] = p->_Buffer[DstNo]; p->_Buffer[DstNo] = Tmp; SwapPByte(&p->Buffer[SwapNo],&p->Buffer[DstNo]); SwapInt(&p->BufFrameNo[SwapNo],&p->BufFrameNo[DstNo]); SwapBool(&p->BufBorder[SwapNo],&p->BufBorder[DstNo]); SwapInt(&p->BufAlloc[SwapNo],&p->BufAlloc[DstNo]); p->ShowCurr = SwapNo; } } #endif p->ShowNext = ShowNo; if (OldFrameNo) *OldFrameNo = p->BufFrameNo[DstNo]; p->BufFrameNo[DstNo] = FrameNo; p->Dst = p->Buffer[DstNo]; p->Ref[0] = NULL; p->Ref[1] = NULL; p->RefMin[0] = NULL; p->RefMin[1] = NULL; p->RefMax[0] = NULL; p->RefMax[1] = NULL; if (BackNo>=0) { p->Ref[0] = p->Buffer[BackNo]; if (!p->BufBorder[BackNo]) { p->BufBorder[BackNo] = 1; FillEdgeYUV(p,p->Ref[0]); } p->RefMin[0] = p->Ref[0]; p->RefMax[0] = p->Ref[0] + p->BufSize - ((8+8*p->BufWidthUV)>>p->Shift); } if (FwdNo>=0) { p->Ref[1] = p->Buffer[FwdNo]; if (!p->BufBorder[FwdNo]) { p->BufBorder[FwdNo] = 1; FillEdgeYUV(p,p->Ref[1]); } p->RefMin[1] = p->Ref[1]; p->RefMax[1] = p->Ref[1] + p->BufSize - ((8+8*p->BufWidthUV)>>p->Shift); } p->BufBorder[DstNo] = 0; //invalidate border for dst #if !defined(MIPS64) #if defined(CONFIG_IDCT_LOWRES) if (p->Shift == 1) p->IDCT.Inter8x8 = p->Ref[1]!=NULL?(idctinter)Inter8x8BackFwdHalf:(idctinter)Inter8x8BackHalf; else #endif #ifdef CONFIG_IDCT_SWAP if (p->Out.Format.Format.Video.Direction & DIR_SWAPXY) p->IDCT.Inter8x8 = p->Inter8x8Swap[p->Ref[1]!=NULL]; else #endif p->IDCT.Inter8x8 = p->Inter8x8[p->Ref[1]!=NULL]; #endif p->inter8x8uv = p->IDCT.Inter8x8; // for qpel #ifdef FREESCALE_MX1 if (p->MX1) p->MX1Pop = MX1PopNone; #endif return ERR_NONE; } static void FrameEnd(softidct* p) { #ifdef MIPS64_WIN32 EnableInterrupts(); KernelMode(p->KMode); #endif #ifdef FREESCALE_MX1 if (p->MX1) p->MX1Pop(p); #endif } static int Create(softidct* p) { #if defined(MMX) if (!(QueryPlatform(PLATFORM_CAPS) & CAPS_X86_MMX)) return ERR_NOT_SUPPORTED; #endif #if defined(MIPS64) if (!QueryAdvanced(ADVANCED_VR41XX)) return ERR_NOT_SUPPORTED; #if defined(MIPSVR41XX) if (!(QueryPlatform(PLATFORM_CAPS) & CAPS_MIPS_VR4120)) return ERR_NOT_SUPPORTED; #endif #endif p->IDCT.Get = (nodeget)Get; p->IDCT.Set = (nodeset)Set; p->IDCT.Send = (idctsend)Send; p->IDCT.Null = (idctnull)Null; p->IDCT.Drop = (idctdrop)Drop; p->IDCT.Lock = (idctlock)Lock; p->IDCT.Unlock = (idctunlock)Unlock; p->IDCT.FrameStart = (idctframestart)FrameStart; p->IDCT.FrameEnd = (idctframeend)FrameEnd; #if !defined(MIPS64) && !defined(MIPS32) p->AddBlock[0] = AddBlock; p->AddBlock[1] = AddBlockHor; p->AddBlock[2] = AddBlockVer; p->AddBlock[3] = AddBlockHorVer; #endif memcpy(p->AllCopyBlock,AllCopyBlock,sizeof(AllCopyBlock)); p->Intra8x8 = (idctintra)Intra8x8; #ifndef MIPS64 p->Inter8x8[0] = (idctinter)Inter8x8Back; p->Inter8x8[1] = (idctinter)Inter8x8BackFwd; p->QPELInter = (idctinter)Inter8x8QPEL; p->QPELCopyBlockM = (copyblock)CopyBlockM; p->Inter8x8GMC = (idctinter)Inter8x8GMC; #endif #ifdef CONFIG_IDCT_SWAP p->Intra8x8Swap = (idctintra)Intra8x8Swap; #ifndef MIPS64 p->Inter8x8Swap[0] = (idctinter)Inter8x8BackSwap; p->Inter8x8Swap[1] = (idctinter)Inter8x8BackFwdSwap; #endif #endif #if defined(MIPS64_WIN32) CodeFindPages(*(void**)&p->IDCT.Enum,&p->CodeBegin,&p->CodeEnd,&p->CodePage); #endif #if defined(ARM) #if defined(FREESCALE_MX1) if (QueryPlatform(PLATFORM_MODEL)==MODEL_ZODIAC) { p->MX1 = (int*)0x80022500; p->Intra8x8 = (idctintra)MX1Intra8x8; p->Inter8x8[0] = (idctinter)MX1Inter8x8Back; p->Inter8x8[1] = (idctinter)MX1Inter8x8BackFwd; #ifdef CONFIG_IDCT_SWAP p->Intra8x8Swap = (idctintra)MX1Intra8x8Swap; p->Inter8x8Swap[0] = (idctinter)MX1Inter8x8BackSwap; p->Inter8x8Swap[1] = (idctinter)MX1Inter8x8BackFwdSwap; #endif } else #endif #if (!defined(TARGET_PALMOS) && !defined(TARGET_SYMBIAN)) || (__GNUC__>=4) || (__GNUC__==3 && __GNUC_MINOR__>=4) if (!QueryAdvanced(ADVANCED_NOWMMX) && (QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_WMMX)) { p->Intra8x8 = (idctintra)WMMXIntra8x8; p->Inter8x8[0] = (idctinter)WMMXInter8x8Back; p->Inter8x8[1] = (idctinter)WMMXInter8x8BackFwd; p->QPELInter = (idctinter)WMMXInter8x8QPEL; p->Inter8x8GMC = (idctinter)WMMXInter8x8GMC; p->QPELCopyBlockM = (copyblock)WMMXCopyBlockM; #ifdef CONFIG_IDCT_SWAP p->Intra8x8Swap = (idctintra)WMMXIntra8x8Swap; p->Inter8x8Swap[0] = (idctinter)WMMXInter8x8BackSwap; p->Inter8x8Swap[1] = (idctinter)WMMXInter8x8BackFwdSwap; #endif p->AllCopyBlock[0][0] = WMMXCopyBlock; p->AllCopyBlock[0][1] = WMMXCopyBlockHor; p->AllCopyBlock[0][2] = WMMXCopyBlockVer; p->AllCopyBlock[0][3] = WMMXCopyBlockHorVer; p->AllCopyBlock[1][0] = WMMXCopyBlock; p->AllCopyBlock[1][1] = WMMXCopyBlockHorRound; p->AllCopyBlock[1][2] = WMMXCopyBlockVerRound; p->AllCopyBlock[1][3] = WMMXCopyBlockHorVerRound; p->AddBlock[0] = WMMXAddBlock; p->AddBlock[1] = WMMXAddBlockHor; p->AddBlock[2] = WMMXAddBlockVer; p->AddBlock[3] = WMMXAddBlockHorVer; } else #endif // TARGET_PALMOS {} /* if (QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_5E) { if (QueryPlatform(PLATFORM_ICACHE) >= 32768) { p->AllCopyBlock[0][0] = FastCopyBlock; p->AllCopyBlock[0][1] = FastCopyBlockHor; p->AllCopyBlock[0][2] = FastCopyBlockVer; p->AllCopyBlock[0][3] = FastCopyBlockHorVer; p->AllCopyBlock[0][0] = FastCopyBlock; p->AllCopyBlock[1][1] = FastCopyBlockHorRound; p->AllCopyBlock[1][2] = FastCopyBlockVerRound; p->AllCopyBlock[1][3] = FastCopyBlockHorVerRound; p->AddBlock[0] = FastAddBlock; p->AddBlock[1] = FastAddBlockHor; p->AddBlock[2] = FastAddBlockVer; p->AddBlock[3] = FastAddBlockHorVer; } else { p->AllCopyBlock[0][0] = PreLoadCopyBlock; p->AllCopyBlock[0][1] = PreLoadCopyBlockHor; p->AllCopyBlock[0][2] = PreLoadCopyBlockVer; p->AllCopyBlock[0][3] = PreLoadCopyBlockHorVer; p->AllCopyBlock[0][0] = PreLoadCopyBlock; p->AllCopyBlock[1][1] = PreLoadCopyBlockHorRound; p->AllCopyBlock[1][2] = PreLoadCopyBlockVerRound; p->AllCopyBlock[1][3] = PreLoadCopyBlockHorVerRound; p->AddBlock[0] = PreLoadAddBlock; p->AddBlock[1] = PreLoadAddBlockHor; p->AddBlock[2] = PreLoadAddBlockVer; p->AddBlock[3] = PreLoadAddBlockHorVer; } } */ #endif //ARM p->Tmp = (uint8_t*)ALIGN16((uintptr_t)p->_Tmp); p->MaxCount = MAXBUF; p->BufCount = 0; p->LastTemp = 0; p->ShowCurr = -1; p->ShowNext = -1; return ERR_NONE; } static const nodedef SoftIDCT = { sizeof(softidct), #if defined(MPEG4_EXPORTS) MPEG4IDCT_ID, IDCT_CLASS, PRI_DEFAULT+20, #elif defined(MSMPEG4_EXPORTS) MSMPEG4IDCT_ID, IDCT_CLASS, PRI_DEFAULT+10, #else SOFTIDCT_ID, IDCT_CLASS, PRI_DEFAULT, #endif (nodecreate)Create, }; void SoftIDCT_Init() { NodeRegisterClass(&SoftIDCT); } void SoftIDCT_Done() { NodeUnRegisterClass(SoftIDCT.Class); }