gps/GPSResources/tcpmp/common/idct.c

624 lines
16 KiB
C
Raw Normal View History

2019-05-01 12:32:35 +00:00
/*****************************************************************************
*
* 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: idct.c 607 2006-01-22 20:58:29Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "common.h"
static const datatable Params[] =
{
{ IDCT_FORMAT, TYPE_BINARY, DF_HIDDEN, sizeof(video) },
{ IDCT_OUTPUT, TYPE_PACKET, DF_OUTPUT },
{ IDCT_ROUNDING, TYPE_BOOL, DF_HIDDEN },
{ IDCT_SHIFT, TYPE_INT, DF_HIDDEN },
{ IDCT_MODE, TYPE_INT, DF_HIDDEN },
{ IDCT_BUFFERCOUNT, TYPE_INT, DF_HIDDEN },
{ IDCT_BUFFERWIDTH, TYPE_INT, DF_HIDDEN },
{ IDCT_BUFFERHEIGHT,TYPE_INT, DF_HIDDEN },
DATATABLE_END(IDCT_CLASS)
};
static const datatable CodecParams[] =
{
{ CODECIDCT_INPUT, TYPE_PACKET, DF_INPUT },
{ CODECIDCT_IDCT, TYPE_NODE, DF_OUTPUT, IDCT_CLASS },
DATATABLE_END(CODECIDCT_CLASS)
};
int IDCTEnum(void* p, int* No, datadef* Param)
{
if (FlowEnum(p,No,Param)==ERR_NONE)
return ERR_NONE;
return NodeEnumTable(No,Param,Params);
}
static void DummyGMC(idct* p,const idct_gmc* gmc)
{
}
static void DummyInter8x8GMC(idct* p,void* Data,int Length)
{
p->Inter8x8(p,Data,Length);
}
static void DummyMCompGMC(idct* p,int x,int y)
{
static const int Zero[6] = {0,0,0,0,0,0};
p->MComp16x16(p,Zero,NULL);
}
static int IDCTCreate(idct* p)
{
p->Enum = IDCTEnum;
p->GMC = (idctgmc)DummyGMC;
p->Inter8x8GMC = (idctinter)DummyInter8x8GMC;
p->MCompGMC = (idctprocess)DummyMCompGMC;
return ERR_NONE;
}
static const nodedef IDCT =
{
sizeof(idct)|CF_ABSTRACT,
IDCT_CLASS,
FLOW_CLASS,
PRI_DEFAULT,
(nodecreate)IDCTCreate,
};
int IDCTBackup(idct* p,idctbackup* Backup)
{
int No;
planes Planes;
video Format;
memset(Backup,0,sizeof(idctbackup));
if (p->Get(p,IDCT_FORMAT,&Backup->Format,sizeof(video))!=ERR_NONE || !Backup->Format.Pixel.Flags ||
p->Get(p,IDCT_BUFFERWIDTH,&Backup->Width,sizeof(int))!=ERR_NONE ||
p->Get(p,IDCT_BUFFERHEIGHT,&Backup->Height,sizeof(int))!=ERR_NONE ||
p->Get(p,IDCT_BUFFERCOUNT,&Backup->Count,sizeof(int))!=ERR_NONE ||
p->Get(p,IDCT_SHOW,&Backup->Show,sizeof(int))!=ERR_NONE)
return ERR_INVALID_DATA;
p->Get(p,IDCT_SHIFT,&Backup->Shift,sizeof(int)); // optional
p->Get(p,IDCT_MODE,&Backup->Mode,sizeof(int));
for (No=0;No<Backup->Count;++No)
{
idctbufferbackup* Buffer = Backup->Buffer+No;
Buffer->FrameNo = -1;
p->Get(p,IDCT_FRAMENO+No,&Buffer->FrameNo,sizeof(int));
if (p->Lock(p,No,Planes,&Buffer->Brightness,&Format) == ERR_NONE)
{
Buffer->Format = Format;
DefaultPitch(&Buffer->Format);
if (SurfaceAlloc(Buffer->Buffer,&Buffer->Format) == ERR_NONE)
SurfaceCopy(&Format,&Buffer->Format,Planes,Buffer->Buffer,NULL);
p->Unlock(p,No);
}
}
p->Set(p,IDCT_FORMAT,NULL,0);
return ERR_NONE;
}
int IDCTRestore(idct* p,idctbackup* Backup)
{
int No;
if (p && Backup->Format.Pixel.Flags)
{
int Brightness;
planes Planes;
video Format;
blitfx FX;
memset(&FX,0,sizeof(FX));
FX.ScaleX = SCALE_ONE;
FX.ScaleY = SCALE_ONE;
p->Set(p,IDCT_MODE,&Backup->Mode,sizeof(int));
p->Set(p,IDCT_SHIFT,&Backup->Shift,sizeof(int));
p->Set(p,IDCT_BUFFERWIDTH,&Backup->Width,sizeof(int));
p->Set(p,IDCT_BUFFERHEIGHT,&Backup->Height,sizeof(int));
p->Set(p,IDCT_FORMAT,&Backup->Format,sizeof(video));
p->Set(p,IDCT_BUFFERCOUNT,&Backup->Count,sizeof(int));
for (No=0;No<Backup->Count;++No)
{
idctbufferbackup* Buffer = Backup->Buffer+No;
p->Set(p,IDCT_FRAMENO+No,&Buffer->FrameNo,sizeof(int));
if (Buffer->Buffer[0] && p->Lock(p,No,Planes,&Brightness,&Format) == ERR_NONE)
{
FX.Direction = CombineDir(Buffer->Format.Direction, 0, Format.Direction);
FX.Brightness = Brightness - Buffer->Brightness;
SurfaceCopy(&Buffer->Format,&Format,Buffer->Buffer,Planes,&FX);
p->Unlock(p,No);
}
}
p->Set(p,IDCT_SHOW,&Backup->Show,sizeof(int));
}
for (No=0;No<Backup->Count;++No)
SurfaceFree(Backup->Buffer[No].Buffer);
memset(Backup,0,sizeof(idctbackup));
return ERR_NONE;
}
//-----------------------------------------------------------------------------------------------
int CodecIDCTEnum(void* p, int* No, datadef* Param)
{
if (FlowEnum(p,No,Param)==ERR_NONE)
return ERR_NONE;
return NodeEnumTable(No,Param,CodecParams);
}
static int Discontinuity(codecidct* p)
{
p->RefTime = TIME_UNKNOWN;
p->Dropping = 1;
p->Show = -1;
if (p->IDCT.Ptr)
p->IDCT.Ptr->Drop(p->IDCT.Ptr);
if (p->Discontinuity)
p->Discontinuity(p);
return ERR_NONE;
}
static int Flush(codecidct* p)
{
Discontinuity(p);
p->RefUpdated = 0;
p->FrameEnd = 0;
p->Dropping = 0;
BufferClear(&p->Buffer);
if (p->Flush)
p->Flush(p);
return ERR_NONE;
}
static int UpdateCount(codecidct* p)
{
if (p->IDCT.Ptr)
{
p->IDCT.Ptr->Get(p->IDCT.Ptr,IDCT_BUFFERCOUNT,&p->IDCT.Count,sizeof(int));
if (p->UpdateCount)
p->UpdateCount(p);
if (p->IDCT.Width>0 && p->IDCT.Height>0 && p->IDCT.Count<p->MinCount)
{
p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_FORMAT,NULL,0);
return ERR_OUT_OF_MEMORY;
}
}
return ERR_NONE;
}
static bool_t Prepair(codecidct* p)
{
int Result;
idct* IDCT = p->IDCT.Ptr;
p->IDCT.Count = 0;
if (!IDCT || !p->IDCT.Format.Pixel.Flags)
return ERR_NONE;
Result = IDCT->Set(IDCT,IDCT_BUFFERWIDTH,&p->IDCT.Width,sizeof(int));
if (Result != ERR_NONE) return Result;
Result = IDCT->Set(IDCT,IDCT_BUFFERHEIGHT,&p->IDCT.Height,sizeof(int));
if (Result != ERR_NONE) return Result;
Result = IDCT->Set(IDCT,IDCT_FORMAT,&p->IDCT.Format,sizeof(video));
if (Result != ERR_NONE) return Result;
IDCT->Set(IDCT,IDCT_BUFFERCOUNT,&p->MinCount,sizeof(int));
if (p->DefCount > p->MinCount) // optional
{
DisableOutOfMemory();
IDCT->Set(IDCT,IDCT_BUFFERCOUNT,&p->DefCount,sizeof(int));
EnableOutOfMemory();
}
IDCT->Drop(IDCT);
return UpdateCount(p);
}
static int SetIDCT(codecidct* p, idct* Dst)
{
int Count;
blitfx FX;
planes SrcPlanes,DstPlanes;
int SrcBrightness,DstBrightness;
int SrcShift,DstShift;
int No;
int Result;
idct* Src = p->IDCT.Ptr;
if (Src == Dst)
return ERR_NONE;
if (!Src)
{
p->IDCT.Ptr = Dst;
Result= Prepair(p);
if (Result != ERR_NONE)
p->IDCT.Ptr = NULL;
return Result;
}
if (Dst)
{
assert(NodeIsClass(Dst->Class,IDCT_CLASS));
if (Src->Get(Src,IDCT_SHIFT,&SrcShift,sizeof(SrcShift))!=ERR_NONE)
SrcShift = 0;
Dst->Set(Dst,IDCT_SHIFT,&SrcShift,sizeof(SrcShift));
if (Dst->Get(Dst,IDCT_SHIFT,&DstShift,sizeof(DstShift))!=ERR_NONE)
DstShift = 0;
Result = Dst->Set(Dst,IDCT_MODE,&p->IDCT.Mode,sizeof(int));
if (Result != ERR_NONE) return Result;
Result = Dst->Set(Dst,IDCT_BUFFERWIDTH,&p->IDCT.Width,sizeof(int));
if (Result != ERR_NONE) return Result;
Result = Dst->Set(Dst,IDCT_BUFFERHEIGHT,&p->IDCT.Height,sizeof(int));
if (Result != ERR_NONE) return Result;
Result = Dst->Set(Dst,IDCT_FORMAT,&p->IDCT.Format,sizeof(video));
if (Result != ERR_NONE) return Result;
Result = Dst->Set(Dst,IDCT_BUFFERCOUNT,&p->MinCount,sizeof(int));
if (Result != ERR_NONE) return Result;
if (Src->Get(Src,IDCT_BUFFERCOUNT,&Count,sizeof(Count))==ERR_NONE && Count>p->MinCount)
Dst->Set(Dst,IDCT_BUFFERCOUNT,&Count,sizeof(Count)); // optional
memset(&FX,0,sizeof(FX));
FX.ScaleX = SCALE_ONE;
FX.ScaleY = SCALE_ONE;
No = SrcShift - DstShift;
if (No>0)
{
FX.ScaleX <<= No;
FX.ScaleY <<= No;
}
else if (No<0)
{
FX.ScaleX >>= No;
FX.ScaleY >>= No;
}
for (No=0;No<Count;++No)
{
video SrcFormat,DstFormat;
int FrameNo = -1;
Src->Get(Src,IDCT_FRAMENO+No,&FrameNo,sizeof(FrameNo));
Dst->Set(Dst,IDCT_FRAMENO+No,&FrameNo,sizeof(FrameNo));
if (Src->Lock(Src,No,SrcPlanes,&SrcBrightness,&SrcFormat) == ERR_NONE)
{
if (Dst->Lock(Dst,No,DstPlanes,&DstBrightness,&DstFormat) == ERR_NONE)
{
FX.Direction = CombineDir(SrcFormat.Direction, 0, DstFormat.Direction);
FX.Brightness = DstBrightness - SrcBrightness;
SurfaceCopy(&SrcFormat,&DstFormat,SrcPlanes,DstPlanes,&FX);
Dst->Unlock(Dst,No);
}
Src->Unlock(Src,No);
}
}
if (Src->Get(Src,IDCT_SHOW,&No,sizeof(No))==ERR_NONE)
Dst->Set(Dst,IDCT_SHOW,&No,sizeof(No));
}
Src->Set(Src,IDCT_FORMAT,NULL,0);
p->IDCT.Ptr = Dst;
UpdateCount(p); // can't and shouldn't fail here (src already cleared and dst pointer saved)
return ERR_NONE;
}
int CodecIDCTSetCount(codecidct* p, int Count)
{
if (!p->IDCT.Ptr)
return ERR_NONE;
p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_BUFFERCOUNT,&Count,sizeof(int));
return UpdateCount(p);
}
int CodecIDCTSetMode(codecidct* p, int Mode, bool_t Value)
{
if (Value)
p->IDCT.Mode |= Mode;
else
p->IDCT.Mode &= ~Mode;
if (p->IDCT.Ptr && p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_MODE,&p->IDCT.Mode,sizeof(int))!=ERR_NONE)
{
if (p->NotSupported.Node)
{
pin Pin;
Pin.No = CODECIDCT_IDCT;
Pin.Node = &p->Node;
if (p->NotSupported.Node->Set(p->NotSupported.Node,p->NotSupported.No,&Pin,sizeof(Pin)) == ERR_NONE)
return ERR_NOT_COMPATIBLE;
}
return ERR_NOT_SUPPORTED;
}
return ERR_NONE;
}
int CodecIDCTSetFormat(codecidct* p, int Flags, int Width, int Height, int IDCTWidth, int IDCTHeight, int Aspect)
{
int Result = ERR_NONE;
Flags |= p->In.Format.Format.Video.Pixel.Flags & PF_NOPREROTATE;
if (p->IDCT.Format.Pixel.Flags != Flags ||
p->IDCT.Format.Width != Width ||
p->IDCT.Format.Height != Height ||
p->IDCT.Format.Aspect != Aspect ||
p->IDCT.Width != IDCTWidth ||
p->IDCT.Height != IDCTHeight)
{
p->IDCT.Format.Pixel.Flags = Flags;
p->IDCT.Format.Width = Width;
p->IDCT.Format.Height = Height;
p->IDCT.Format.Aspect = Aspect;
p->IDCT.Width = IDCTWidth;
p->IDCT.Height = IDCTHeight;
p->In.Format.Format.Video.Width = Width;
p->In.Format.Format.Video.Height = Height;
if (p->UpdateSize)
Result = p->UpdateSize(p);
if (Result == ERR_NONE)
Result = Prepair(p);
}
return Result;
}
static int UpdateInput(codecidct* p)
{
int Result = ERR_NONE;
Flush(p);
if (!PacketFormatMatch(p->Node.Class, &p->In.Format))
PacketFormatClear(&p->In.Format);
memset(&p->IDCT.Format,0,sizeof(video));
if (p->UpdateInput)
Result = p->UpdateInput(p);
if (Result != ERR_NONE)
PacketFormatClear(&p->In.Format);
if (p->In.Format.Type != PACKET_VIDEO && p->IDCT.Ptr)
p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_FORMAT,NULL,0);
return Result;
}
static int Process(codecidct* p, const packet* Packet, const flowstate* State)
{
int Result;
idct* IDCT = p->IDCT.Ptr;
if (p->IDCT.Count<=0 && p->IDCT.Width>0 && p->IDCT.Height>0)
return ERR_INVALID_DATA;
p->State.CurrTime = State->CurrTime;
if (State->DropLevel > 1)
Discontinuity(p);
if (p->Show>=0) // pending frame?
{
Result = IDCT->Send(IDCT,p->RefTime,&p->State);
if (Result == ERR_BUFFER_FULL)
return Result;
p->Show = -1;
}
if (!Packet) // end of file or dropped
return IDCT->Null(IDCT,State,0);
if ((p->In.Format.Format.Video.Pixel.Flags & PF_FRAGMENTED) && p->FindNext)
{
bool_t Processed = 0;
//DEBUG_MSG2(DEBUG_CODEC,T("%d %d"),Packet->Length,Packet->RefTime);
for (;;)
{
if (!p->FindNext(p))
{
if (Processed)
{
Result = ERR_NEED_MORE_DATA;
break;
}
p->FrameEnd -= p->Buffer.ReadPos;
BufferPack(&p->Buffer,0);
BufferWrite(&p->Buffer,Packet->Data[0],Packet->Length,32768);
Processed = 1;
if (Packet->RefTime >= 0)
{
if (!p->RefUpdated)
{
p->RefTime = Packet->RefTime;
p->RefUpdated = 1;
// if (p->IDCT.Count >= 3 && p->FrameTime>0 && p->RefTime >= p->FrameTime)
// p->RefTime -= p->FrameTime;
}
}
else
p->RefUpdated = 0;
}
else
{
//static tick_t Last = 0;
//DEBUG_MSG2(DEBUG_CODEC,T("%d %d"),p->RefTime,p->RefTime-Last);
//Last = p->RefTime;
if (!p->FrameTime && !p->RefUpdated)
p->RefTime = State->CurrTime;
p->State.DropLevel = p->RefTime >= 0 && State->CurrTime >= 0 &&
p->RefTime < (State->CurrTime - p->DropTolerance);
if (State->DropLevel > 1)
{
p->IDCT.Ptr->Null(p->IDCT.Ptr,NULL,0);
Result = ERR_NONE;
}
else
Result = p->Frame(p,p->Buffer.Data+p->Buffer.ReadPos,p->FrameEnd-p->Buffer.ReadPos);
p->Buffer.ReadPos = p->FrameEnd;
if (p->RefTime >= 0)
p->RefTime += p->FrameTime;
p->RefUpdated = 0;
if (Result==ERR_NONE && p->Show>=0)
{
if (!Processed)
Result = ERR_BUFFER_FULL; // resend packet next time
break;
}
}
}
}
else
{
if (State->DropLevel > 1)
{
p->IDCT.Ptr->Null(p->IDCT.Ptr,NULL,0);
Result = ERR_NONE;
}
else
{
p->State.DropLevel = State->DropLevel;
p->RefTime = Packet->RefTime;
// if (p->IDCT.Count >= 3 && p->FrameTime>0 && p->RefTime >= p->FrameTime)
// p->RefTime -= p->FrameTime;
Result = p->Frame(p,Packet->Data[0],Packet->Length);
}
}
if (p->Show>=0 && IDCT->Send(IDCT,p->RefTime,&p->State) != ERR_BUFFER_FULL)
p->Show = -1;
return Result;
}
int CodecIDCTSet(codecidct* p, int No, const void* Data, int Size)
{
node* Advanced;
int Result = ERR_INVALID_PARAM;
switch (No)
{
case CODECIDCT_INPUT: SETVALUE(p->In.Pin,pin,ERR_NONE); break;
case CODECIDCT_INPUT|PIN_FORMAT: SETPACKETFORMAT(p->In.Format,packetformat,UpdateInput(p)); break;
case CODECIDCT_IDCT:
assert(Size==sizeof(idct*));
Result = SetIDCT(p,*(idct**)Data);
break;
case FLOW_NOT_SUPPORTED: SETVALUE(p->NotSupported,pin,ERR_NONE); break;
case FLOW_FLUSH: Result = Flush(p); break;
case NODE_SETTINGSCHANGED:
Advanced = Context()->Advanced;
if (Advanced)
Advanced->Get(Advanced,ADVANCED_DROPTOL,&p->DropTolerance,sizeof(tick_t));
break;
}
return Result;
}
int CodecIDCTGet(codecidct* p, int No, void* Data, int Size)
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case CODECIDCT_INPUT: GETVALUE(p->In.Pin,pin); break;
case CODECIDCT_INPUT|PIN_FORMAT: GETVALUE(p->In.Format,packetformat); break;
case CODECIDCT_INPUT|PIN_PROCESS: GETVALUE((packetprocess)Process,packetprocess); break;
case CODECIDCT_IDCT: GETVALUE(p->IDCT.Ptr,idct*); break;
}
return Result;
}
static int Create(codecidct* p)
{
p->Node.Enum = CodecIDCTEnum;
p->Node.Get = (nodeget)CodecIDCTGet;
p->Node.Set = (nodeset)CodecIDCTSet;
return ERR_NONE;
}
static void Delete(codecidct* p)
{
PacketFormatClear(&p->In.Format);
if (p->UpdateInput)
p->UpdateInput(p);
}
static const nodedef CodecIDCT =
{
sizeof(codecidct)|CF_ABSTRACT,
CODECIDCT_CLASS,
FLOW_CLASS,
PRI_DEFAULT,
(nodecreate)Create,
(nodedelete)Delete,
};
void IDCT_Init()
{
NodeRegisterClass(&IDCT);
NodeRegisterClass(&CodecIDCT);
}
void IDCT_Done()
{
NodeUnRegisterClass(CODECIDCT_CLASS);
NodeUnRegisterClass(IDCT_CLASS);
}