gps/GPSResources/tcpmp/common/softidct/softidct.c

1217 lines
30 KiB
C
Executable File

/*****************************************************************************
*
* 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;n<InnerHeight;++n)
{
MemSet8(p-EdgeX, p[0], EdgeX);
MemSet8(p+InnerWidth,p[InnerWidth-1], EdgeX);
p += Width;
}
// top
p = Ptr;
for (n=0;n<EdgeY;++n)
{
MemCpy8(p, Ptr+EdgeY * Width, Width);
p += Width;
}
// bottom
p = Ptr + (Height-EdgeY)*Width;
for (n=0;n<EdgeY;++n)
{
MemCpy8(p, Ptr+(Height-EdgeY-1)*Width, Width);
p += Width;
}
}
static void FillEdgeYUV(softidct* p,uint8_t *Ptr)
{
FillEdge(Ptr, p->BufWidth, 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;i<p->CodeEnd;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;i<p->BufCount;++i)
{
FreeBlock(&p->_Buffer[i]);
p->Buffer[i] = NULL;
p->BufAlloc[i] = 0;
}
if (p->BufCount > n)
p->BufCount = n;
for (i=p->BufCount;i<n;++i)
{
if (!p->BufSize)
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;No<p->BufCount;++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;i<Count;++i)
Lock(p,i,Src[i],NULL,&SrcFormat);
p->Out.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;i<Count;++i)
{
if (TmpPtr)
SurfaceCopy(&SrcFormat,&SrcFormat,Src[i],Tmp,NULL);
if (p->BufAlloc[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 && No<IDCT_FRAMENO+p->BufCount)
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 && No<IDCT_FRAMENO+p->BufCount)
GETVALUE(p->BufFrameNo[No-IDCT_FRAMENO],int);
return Result;
}
static void Drop(softidct* p)
{
int i;
for (i=0;i<p->BufCount;++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;SwapNo<p->BufCount;++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);
}