idct.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:16k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*****************************************************************************
  2.  *
  3.  * This program is free software ; you can redistribute it and/or modify
  4.  * it under the terms of the GNU General Public License as published by
  5.  * the Free Software Foundation; either version 2 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  16.  *
  17.  * $Id: idct.c 607 2006-01-22 20:58:29Z picard $
  18.  *
  19.  * The Core Pocket Media Player
  20.  * Copyright (c) 2004-2005 Gabor Kovacs
  21.  *
  22.  ****************************************************************************/
  23. #include "common.h"
  24. static const datatable Params[] = 
  25. {
  26. { IDCT_FORMAT, TYPE_BINARY, DF_HIDDEN, sizeof(video) },
  27. { IDCT_OUTPUT, TYPE_PACKET, DF_OUTPUT },
  28. { IDCT_ROUNDING, TYPE_BOOL, DF_HIDDEN },
  29. { IDCT_SHIFT, TYPE_INT, DF_HIDDEN },
  30. { IDCT_MODE, TYPE_INT, DF_HIDDEN },
  31. { IDCT_BUFFERCOUNT, TYPE_INT, DF_HIDDEN },
  32. { IDCT_BUFFERWIDTH, TYPE_INT, DF_HIDDEN },
  33. { IDCT_BUFFERHEIGHT,TYPE_INT, DF_HIDDEN },
  34. DATATABLE_END(IDCT_CLASS)
  35. };
  36. static const datatable CodecParams[] = 
  37. {
  38. { CODECIDCT_INPUT, TYPE_PACKET, DF_INPUT },
  39. { CODECIDCT_IDCT, TYPE_NODE, DF_OUTPUT, IDCT_CLASS },
  40. DATATABLE_END(CODECIDCT_CLASS)
  41. };
  42. int IDCTEnum(void* p, int* No, datadef* Param)
  43. {
  44. if (FlowEnum(p,No,Param)==ERR_NONE)
  45. return ERR_NONE;
  46. return NodeEnumTable(No,Param,Params);
  47. }
  48. static void DummyGMC(idct* p,const idct_gmc* gmc)
  49. {
  50. }
  51. static void DummyInter8x8GMC(idct* p,void* Data,int Length)
  52. {
  53. p->Inter8x8(p,Data,Length);
  54. }
  55. static void DummyMCompGMC(idct* p,int x,int y)
  56. {
  57. static const int Zero[6] = {0,0,0,0,0,0};
  58. p->MComp16x16(p,Zero,NULL);
  59. }
  60. static int IDCTCreate(idct* p)
  61. {
  62. p->Enum = IDCTEnum;
  63. p->GMC = (idctgmc)DummyGMC;
  64. p->Inter8x8GMC = (idctinter)DummyInter8x8GMC;
  65. p->MCompGMC = (idctprocess)DummyMCompGMC;
  66. return ERR_NONE;
  67. }
  68. static const nodedef IDCT =
  69. {
  70. sizeof(idct)|CF_ABSTRACT,
  71. IDCT_CLASS,
  72. FLOW_CLASS,
  73. PRI_DEFAULT,
  74. (nodecreate)IDCTCreate,
  75. };
  76. int IDCTBackup(idct* p,idctbackup* Backup)
  77. {
  78. int No;
  79. planes Planes;
  80. video Format;
  81. memset(Backup,0,sizeof(idctbackup));
  82. if (p->Get(p,IDCT_FORMAT,&Backup->Format,sizeof(video))!=ERR_NONE || !Backup->Format.Pixel.Flags ||
  83. p->Get(p,IDCT_BUFFERWIDTH,&Backup->Width,sizeof(int))!=ERR_NONE ||
  84. p->Get(p,IDCT_BUFFERHEIGHT,&Backup->Height,sizeof(int))!=ERR_NONE ||
  85. p->Get(p,IDCT_BUFFERCOUNT,&Backup->Count,sizeof(int))!=ERR_NONE ||
  86. p->Get(p,IDCT_SHOW,&Backup->Show,sizeof(int))!=ERR_NONE)
  87. return ERR_INVALID_DATA;
  88. p->Get(p,IDCT_SHIFT,&Backup->Shift,sizeof(int)); // optional
  89. p->Get(p,IDCT_MODE,&Backup->Mode,sizeof(int));
  90. for (No=0;No<Backup->Count;++No)
  91. {
  92. idctbufferbackup* Buffer = Backup->Buffer+No;
  93. Buffer->FrameNo = -1;
  94. p->Get(p,IDCT_FRAMENO+No,&Buffer->FrameNo,sizeof(int));
  95. if (p->Lock(p,No,Planes,&Buffer->Brightness,&Format) == ERR_NONE)
  96. {
  97. Buffer->Format = Format;
  98. DefaultPitch(&Buffer->Format);
  99. if (SurfaceAlloc(Buffer->Buffer,&Buffer->Format) == ERR_NONE)
  100. SurfaceCopy(&Format,&Buffer->Format,Planes,Buffer->Buffer,NULL);
  101. p->Unlock(p,No);
  102. }
  103. }
  104. p->Set(p,IDCT_FORMAT,NULL,0);
  105. return ERR_NONE;
  106. }
  107. int IDCTRestore(idct* p,idctbackup* Backup)
  108. {
  109. int No;
  110. if (p && Backup->Format.Pixel.Flags)
  111. {
  112. int Brightness;
  113. planes Planes;
  114. video Format;
  115. blitfx FX;
  116. memset(&FX,0,sizeof(FX));
  117. FX.ScaleX = SCALE_ONE;
  118. FX.ScaleY = SCALE_ONE;
  119. p->Set(p,IDCT_MODE,&Backup->Mode,sizeof(int));
  120. p->Set(p,IDCT_SHIFT,&Backup->Shift,sizeof(int));
  121. p->Set(p,IDCT_BUFFERWIDTH,&Backup->Width,sizeof(int));
  122. p->Set(p,IDCT_BUFFERHEIGHT,&Backup->Height,sizeof(int));
  123. p->Set(p,IDCT_FORMAT,&Backup->Format,sizeof(video));
  124. p->Set(p,IDCT_BUFFERCOUNT,&Backup->Count,sizeof(int));
  125. for (No=0;No<Backup->Count;++No)
  126. {
  127. idctbufferbackup* Buffer = Backup->Buffer+No;
  128. p->Set(p,IDCT_FRAMENO+No,&Buffer->FrameNo,sizeof(int));
  129. if (Buffer->Buffer[0] && p->Lock(p,No,Planes,&Brightness,&Format) == ERR_NONE)
  130. {
  131. FX.Direction = CombineDir(Buffer->Format.Direction, 0, Format.Direction);
  132. FX.Brightness = Brightness - Buffer->Brightness;
  133. SurfaceCopy(&Buffer->Format,&Format,Buffer->Buffer,Planes,&FX);
  134. p->Unlock(p,No);
  135. }
  136. }
  137. p->Set(p,IDCT_SHOW,&Backup->Show,sizeof(int));
  138. }
  139. for (No=0;No<Backup->Count;++No)
  140. SurfaceFree(Backup->Buffer[No].Buffer);
  141. memset(Backup,0,sizeof(idctbackup));
  142. return ERR_NONE;
  143. }
  144. //-----------------------------------------------------------------------------------------------
  145. int CodecIDCTEnum(void* p, int* No, datadef* Param)
  146. {
  147. if (FlowEnum(p,No,Param)==ERR_NONE)
  148. return ERR_NONE;
  149. return NodeEnumTable(No,Param,CodecParams);
  150. }
  151. static int Discontinuity(codecidct* p)
  152. {
  153. p->RefTime = TIME_UNKNOWN;
  154. p->Dropping = 1;
  155. p->Show = -1;
  156. if (p->IDCT.Ptr)
  157. p->IDCT.Ptr->Drop(p->IDCT.Ptr);
  158. if (p->Discontinuity)
  159. p->Discontinuity(p);
  160. return ERR_NONE;
  161. }
  162. static int Flush(codecidct* p)
  163. {
  164. Discontinuity(p);
  165. p->RefUpdated = 0;
  166. p->FrameEnd = 0;
  167. p->Dropping = 0;
  168. BufferClear(&p->Buffer);
  169. if (p->Flush)
  170. p->Flush(p);
  171. return ERR_NONE;
  172. }
  173. static int UpdateCount(codecidct* p)
  174. {
  175. if (p->IDCT.Ptr)
  176. {
  177. p->IDCT.Ptr->Get(p->IDCT.Ptr,IDCT_BUFFERCOUNT,&p->IDCT.Count,sizeof(int));
  178. if (p->UpdateCount)
  179. p->UpdateCount(p);
  180. if (p->IDCT.Width>0 && p->IDCT.Height>0 && p->IDCT.Count<p->MinCount)
  181. {
  182. p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_FORMAT,NULL,0);
  183. return ERR_OUT_OF_MEMORY;
  184. }
  185. }
  186. return ERR_NONE;
  187. }
  188. static bool_t Prepair(codecidct* p)
  189. {
  190. int Result;
  191. idct* IDCT = p->IDCT.Ptr;
  192. p->IDCT.Count = 0;
  193. if (!IDCT || !p->IDCT.Format.Pixel.Flags)
  194. return ERR_NONE;
  195. Result = IDCT->Set(IDCT,IDCT_BUFFERWIDTH,&p->IDCT.Width,sizeof(int));
  196. if (Result != ERR_NONE) return Result;
  197. Result = IDCT->Set(IDCT,IDCT_BUFFERHEIGHT,&p->IDCT.Height,sizeof(int));
  198. if (Result != ERR_NONE) return Result;
  199. Result = IDCT->Set(IDCT,IDCT_FORMAT,&p->IDCT.Format,sizeof(video));
  200. if (Result != ERR_NONE) return Result;
  201. IDCT->Set(IDCT,IDCT_BUFFERCOUNT,&p->MinCount,sizeof(int));
  202. if (p->DefCount > p->MinCount) // optional
  203. {
  204. DisableOutOfMemory();
  205. IDCT->Set(IDCT,IDCT_BUFFERCOUNT,&p->DefCount,sizeof(int));
  206. EnableOutOfMemory();
  207. }
  208. IDCT->Drop(IDCT);
  209. return UpdateCount(p);
  210. }
  211. static int SetIDCT(codecidct* p, idct* Dst)
  212. {
  213. int Count;
  214. blitfx FX;
  215. planes SrcPlanes,DstPlanes;
  216. int SrcBrightness,DstBrightness;
  217. int SrcShift,DstShift;
  218. int No;
  219. int Result;
  220. idct* Src = p->IDCT.Ptr;
  221. if (Src == Dst)
  222. return ERR_NONE;
  223. if (!Src)
  224. {
  225. p->IDCT.Ptr = Dst;
  226. Result= Prepair(p);
  227. if (Result != ERR_NONE)
  228. p->IDCT.Ptr = NULL;
  229. return Result;
  230. }
  231. if (Dst)
  232. {
  233. assert(NodeIsClass(Dst->Class,IDCT_CLASS));
  234. if (Src->Get(Src,IDCT_SHIFT,&SrcShift,sizeof(SrcShift))!=ERR_NONE)
  235. SrcShift = 0;
  236. Dst->Set(Dst,IDCT_SHIFT,&SrcShift,sizeof(SrcShift));
  237. if (Dst->Get(Dst,IDCT_SHIFT,&DstShift,sizeof(DstShift))!=ERR_NONE)
  238. DstShift = 0;
  239. Result = Dst->Set(Dst,IDCT_MODE,&p->IDCT.Mode,sizeof(int));
  240. if (Result != ERR_NONE) return Result;
  241. Result = Dst->Set(Dst,IDCT_BUFFERWIDTH,&p->IDCT.Width,sizeof(int));
  242. if (Result != ERR_NONE) return Result;
  243. Result = Dst->Set(Dst,IDCT_BUFFERHEIGHT,&p->IDCT.Height,sizeof(int));
  244. if (Result != ERR_NONE) return Result;
  245. Result = Dst->Set(Dst,IDCT_FORMAT,&p->IDCT.Format,sizeof(video));
  246. if (Result != ERR_NONE) return Result;
  247. Result = Dst->Set(Dst,IDCT_BUFFERCOUNT,&p->MinCount,sizeof(int));
  248. if (Result != ERR_NONE) return Result;
  249. if (Src->Get(Src,IDCT_BUFFERCOUNT,&Count,sizeof(Count))==ERR_NONE && Count>p->MinCount)
  250. Dst->Set(Dst,IDCT_BUFFERCOUNT,&Count,sizeof(Count)); // optional
  251. memset(&FX,0,sizeof(FX));
  252. FX.ScaleX = SCALE_ONE;
  253. FX.ScaleY = SCALE_ONE;
  254. No = SrcShift - DstShift;
  255. if (No>0)
  256. {
  257. FX.ScaleX <<= No;
  258. FX.ScaleY <<= No;
  259. }
  260. else if (No<0)
  261. {
  262. FX.ScaleX >>= No;
  263. FX.ScaleY >>= No;
  264. }
  265. for (No=0;No<Count;++No)
  266. {
  267. video SrcFormat,DstFormat;
  268. int FrameNo = -1;
  269. Src->Get(Src,IDCT_FRAMENO+No,&FrameNo,sizeof(FrameNo));
  270. Dst->Set(Dst,IDCT_FRAMENO+No,&FrameNo,sizeof(FrameNo));
  271. if (Src->Lock(Src,No,SrcPlanes,&SrcBrightness,&SrcFormat) == ERR_NONE)
  272. {
  273. if (Dst->Lock(Dst,No,DstPlanes,&DstBrightness,&DstFormat) == ERR_NONE)
  274. {
  275. FX.Direction = CombineDir(SrcFormat.Direction, 0, DstFormat.Direction);
  276. FX.Brightness = DstBrightness - SrcBrightness;
  277. SurfaceCopy(&SrcFormat,&DstFormat,SrcPlanes,DstPlanes,&FX);
  278. Dst->Unlock(Dst,No);
  279. }
  280. Src->Unlock(Src,No);
  281. }
  282. }
  283. if (Src->Get(Src,IDCT_SHOW,&No,sizeof(No))==ERR_NONE)
  284. Dst->Set(Dst,IDCT_SHOW,&No,sizeof(No));
  285. }
  286. Src->Set(Src,IDCT_FORMAT,NULL,0);
  287. p->IDCT.Ptr = Dst;
  288. UpdateCount(p); // can't and shouldn't fail here (src already cleared and dst pointer saved)
  289. return ERR_NONE;
  290. }
  291. int CodecIDCTSetCount(codecidct* p, int Count)
  292. {
  293. if (!p->IDCT.Ptr)
  294. return ERR_NONE;
  295. p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_BUFFERCOUNT,&Count,sizeof(int));
  296. return UpdateCount(p);
  297. }
  298. int CodecIDCTSetMode(codecidct* p, int Mode, bool_t Value)
  299. {
  300. if (Value)
  301. p->IDCT.Mode |= Mode;
  302. else
  303. p->IDCT.Mode &= ~Mode;
  304. if (p->IDCT.Ptr && p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_MODE,&p->IDCT.Mode,sizeof(int))!=ERR_NONE)
  305. {
  306. if (p->NotSupported.Node)
  307. {
  308. pin Pin;
  309. Pin.No = CODECIDCT_IDCT;
  310. Pin.Node = &p->Node;
  311. if (p->NotSupported.Node->Set(p->NotSupported.Node,p->NotSupported.No,&Pin,sizeof(Pin)) == ERR_NONE)
  312. return ERR_NOT_COMPATIBLE;
  313. }
  314. return ERR_NOT_SUPPORTED;
  315. }
  316. return ERR_NONE;
  317. }
  318. int CodecIDCTSetFormat(codecidct* p, int Flags, int Width, int Height, int IDCTWidth, int IDCTHeight, int Aspect)
  319. {
  320. int Result = ERR_NONE;
  321. Flags |= p->In.Format.Format.Video.Pixel.Flags & PF_NOPREROTATE;
  322. if (p->IDCT.Format.Pixel.Flags != Flags ||
  323. p->IDCT.Format.Width != Width || 
  324. p->IDCT.Format.Height != Height ||
  325. p->IDCT.Format.Aspect != Aspect ||
  326. p->IDCT.Width != IDCTWidth ||
  327. p->IDCT.Height != IDCTHeight)
  328. {
  329. p->IDCT.Format.Pixel.Flags = Flags;
  330. p->IDCT.Format.Width = Width;
  331. p->IDCT.Format.Height = Height;
  332. p->IDCT.Format.Aspect = Aspect;
  333. p->IDCT.Width = IDCTWidth;
  334. p->IDCT.Height = IDCTHeight;
  335. p->In.Format.Format.Video.Width = Width;
  336. p->In.Format.Format.Video.Height = Height;
  337. if (p->UpdateSize)
  338. Result = p->UpdateSize(p);
  339. if (Result == ERR_NONE)
  340. Result = Prepair(p);
  341. }
  342. return Result;
  343. }
  344. static int UpdateInput(codecidct* p)
  345. {
  346. int Result = ERR_NONE;
  347. Flush(p);
  348. if (!PacketFormatMatch(p->Node.Class, &p->In.Format))
  349. PacketFormatClear(&p->In.Format);
  350. memset(&p->IDCT.Format,0,sizeof(video));
  351. if (p->UpdateInput)
  352. Result = p->UpdateInput(p);
  353. if (Result != ERR_NONE)
  354. PacketFormatClear(&p->In.Format);
  355. if (p->In.Format.Type != PACKET_VIDEO && p->IDCT.Ptr)
  356. p->IDCT.Ptr->Set(p->IDCT.Ptr,IDCT_FORMAT,NULL,0);
  357. return Result;
  358. }
  359. static int Process(codecidct* p, const packet* Packet, const flowstate* State)
  360. {
  361. int Result;
  362. idct* IDCT = p->IDCT.Ptr;
  363. if (p->IDCT.Count<=0 && p->IDCT.Width>0 && p->IDCT.Height>0)
  364. return ERR_INVALID_DATA;
  365. p->State.CurrTime = State->CurrTime;
  366. if (State->DropLevel > 1)
  367. Discontinuity(p);
  368. if (p->Show>=0) // pending frame?
  369. {
  370. Result = IDCT->Send(IDCT,p->RefTime,&p->State);
  371. if (Result == ERR_BUFFER_FULL)
  372. return Result;
  373. p->Show = -1;
  374. }
  375. if (!Packet) // end of file or dropped
  376. return IDCT->Null(IDCT,State,0);
  377. if ((p->In.Format.Format.Video.Pixel.Flags & PF_FRAGMENTED) && p->FindNext)
  378. {
  379. bool_t Processed = 0;
  380. //DEBUG_MSG2(DEBUG_CODEC,T("%d %d"),Packet->Length,Packet->RefTime);
  381. for (;;)
  382. {
  383. if (!p->FindNext(p))
  384. {
  385. if (Processed)
  386. {
  387. Result = ERR_NEED_MORE_DATA;
  388. break;
  389. }
  390. p->FrameEnd -= p->Buffer.ReadPos;
  391. BufferPack(&p->Buffer,0);
  392. BufferWrite(&p->Buffer,Packet->Data[0],Packet->Length,32768);
  393. Processed = 1;
  394. if (Packet->RefTime >= 0)
  395. {
  396. if (!p->RefUpdated)
  397. {
  398. p->RefTime = Packet->RefTime;
  399. p->RefUpdated = 1;
  400. // if (p->IDCT.Count >= 3 && p->FrameTime>0 && p->RefTime >= p->FrameTime)
  401. // p->RefTime -= p->FrameTime;
  402. }
  403. }
  404. else
  405. p->RefUpdated = 0;
  406. }
  407. else
  408. {
  409. //static tick_t Last = 0;
  410. //DEBUG_MSG2(DEBUG_CODEC,T("%d %d"),p->RefTime,p->RefTime-Last);
  411. //Last = p->RefTime;
  412. if (!p->FrameTime && !p->RefUpdated)
  413. p->RefTime = State->CurrTime;
  414. p->State.DropLevel = p->RefTime >= 0 && State->CurrTime >= 0 &&  
  415.                      p->RefTime < (State->CurrTime - p->DropTolerance);
  416. if (State->DropLevel > 1)
  417. {
  418. p->IDCT.Ptr->Null(p->IDCT.Ptr,NULL,0);
  419. Result = ERR_NONE;
  420. }
  421. else
  422. Result = p->Frame(p,p->Buffer.Data+p->Buffer.ReadPos,p->FrameEnd-p->Buffer.ReadPos); 
  423. p->Buffer.ReadPos = p->FrameEnd;
  424. if (p->RefTime >= 0)
  425. p->RefTime += p->FrameTime; 
  426. p->RefUpdated = 0;
  427. if (Result==ERR_NONE && p->Show>=0)
  428. {
  429. if (!Processed)
  430. Result = ERR_BUFFER_FULL; // resend packet next time
  431. break;
  432. }
  433. }
  434. }
  435. }
  436. else
  437. {
  438. if (State->DropLevel > 1)
  439. {
  440. p->IDCT.Ptr->Null(p->IDCT.Ptr,NULL,0);
  441. Result = ERR_NONE;
  442. }
  443. else
  444. {
  445. p->State.DropLevel = State->DropLevel;
  446. p->RefTime = Packet->RefTime;
  447. // if (p->IDCT.Count >= 3 && p->FrameTime>0 && p->RefTime >= p->FrameTime)
  448. // p->RefTime -= p->FrameTime;
  449. Result = p->Frame(p,Packet->Data[0],Packet->Length);
  450. }
  451. }
  452. if (p->Show>=0 && IDCT->Send(IDCT,p->RefTime,&p->State) != ERR_BUFFER_FULL)
  453. p->Show = -1;
  454. return Result;
  455. }
  456. int CodecIDCTSet(codecidct* p, int No, const void* Data, int Size)
  457. {
  458. node* Advanced;
  459. int Result = ERR_INVALID_PARAM;
  460. switch (No)
  461. {
  462. case CODECIDCT_INPUT: SETVALUE(p->In.Pin,pin,ERR_NONE); break;
  463. case CODECIDCT_INPUT|PIN_FORMAT: SETPACKETFORMAT(p->In.Format,packetformat,UpdateInput(p)); break;
  464. case CODECIDCT_IDCT:
  465. assert(Size==sizeof(idct*));
  466. Result = SetIDCT(p,*(idct**)Data);
  467. break;
  468. case FLOW_NOT_SUPPORTED: SETVALUE(p->NotSupported,pin,ERR_NONE); break;
  469. case FLOW_FLUSH: Result = Flush(p); break;
  470. case NODE_SETTINGSCHANGED:
  471. Advanced = Context()->Advanced;
  472. if (Advanced)
  473. Advanced->Get(Advanced,ADVANCED_DROPTOL,&p->DropTolerance,sizeof(tick_t));
  474. break;
  475. }
  476. return Result;
  477. }
  478. int CodecIDCTGet(codecidct* p, int No, void* Data, int Size)
  479. {
  480. int Result = ERR_INVALID_PARAM;
  481. switch (No)
  482. {
  483. case CODECIDCT_INPUT: GETVALUE(p->In.Pin,pin); break;
  484. case CODECIDCT_INPUT|PIN_FORMAT: GETVALUE(p->In.Format,packetformat); break;
  485. case CODECIDCT_INPUT|PIN_PROCESS: GETVALUE((packetprocess)Process,packetprocess); break;
  486. case CODECIDCT_IDCT: GETVALUE(p->IDCT.Ptr,idct*); break;
  487. }
  488. return Result;
  489. }
  490. static int Create(codecidct* p)
  491. {
  492. p->Node.Enum = CodecIDCTEnum;
  493. p->Node.Get = (nodeget)CodecIDCTGet;
  494. p->Node.Set = (nodeset)CodecIDCTSet;
  495. return ERR_NONE;
  496. }
  497. static void Delete(codecidct* p)
  498. {
  499. PacketFormatClear(&p->In.Format);
  500. if (p->UpdateInput)
  501. p->UpdateInput(p);
  502. }
  503. static const nodedef CodecIDCT =
  504. {
  505. sizeof(codecidct)|CF_ABSTRACT,
  506. CODECIDCT_CLASS,
  507. FLOW_CLASS,
  508. PRI_DEFAULT,
  509. (nodecreate)Create,
  510. (nodedelete)Delete,
  511. };
  512. void IDCT_Init()
  513. {
  514. NodeRegisterClass(&IDCT);
  515. NodeRegisterClass(&CodecIDCT);
  516. }
  517. void IDCT_Done()
  518. {
  519. NodeUnRegisterClass(CODECIDCT_CLASS);
  520. NodeUnRegisterClass(IDCT_CLASS);
  521. }