/***************************************************************************** * * 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;NoCount;++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;NoCount;++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;NoCount;++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.CountMinCount) { 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;NoGet(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); }