Import the current wip animation datatype and subclasses. further development will...
[AROS.git] / workbench / classes / datatypes / mpegvideo / mpegamiga.c
blobc63e3646a820fb6e4cb6860af64b6a8b0cd7addc
3 /*
4 **
5 ** $VER: mpegamiga.c 1.11 (2.11.97)
6 ** mpegvideo.datatype 1.11
7 **
8 ** amiga support functions
9 **
10 ** Written 1996/1997 by Roland 'Gizzy' Mainz
14 #ifndef DEBUG
15 # define DEBUG 0
16 #endif
17 #include <aros/debug.h>
19 /* project includes */
20 #include "mpegmyassert.h"
21 #include "mpegproto.h"
23 /* ansi includes */
24 #include "math.h"
25 #include "limits.h"
27 /* local prototypes */
28 static void InitStoreFrame( struct MPEGVideoInstData *mvid );
29 static void WritePixelArray8Fast( struct BitMap *, UBYTE * );
32 void mpeg_closedown( struct MPEGVideoInstData *mvid )
34 D(bug("[mpegvideo.datatype] %s()\n", __PRETTY_FUNCTION__));
36 if( mvid -> mvid_MPPool )
38 DeletePool( (mvid -> mvid_MPPool) );
39 mvid -> mvid_MPPool = NULL;
44 static
45 void InitStoreFrame( struct MPEGVideoInstData *mvid )
47 D(bug("[mpegvideo.datatype] %s()\n", __PRETTY_FUNCTION__));
49 /* Alloc bitmap as key bitmap */
50 if( mvid -> mvid_UseChunkyMap )
52 mvid -> mvid_KeyBitMap = AllocBitMap( (ULONG)anim_width, (ULONG)anim_height, (ULONG)anim_depth, (BMF_CLEAR | BMF_SPECIALFMT | SHIFT_PIXFMT( pixfmt )), NULL );
54 else
56 mvid -> mvid_KeyBitMap = AllocBitMap( (ULONG)anim_width, (ULONG)anim_height, (ULONG)anim_depth, (BMF_CLEAR | BMF_MINPLANES), NULL );
59 if( (mvid -> mvid_KeyBitMap) == NULL )
61 myexit( mvid, RETURN_FAIL, ERROR_NO_FREE_STORE );
66 void StoreFrame( struct MPEGVideoInstData *mvid, UBYTE *data )
68 D(bug("[mpegvideo.datatype] %s()\n", __PRETTY_FUNCTION__));
70 /* All ready to store the frames ? */
71 if( (mvid -> mvid_KeyBitMap) == NULL )
73 InitStoreFrame( mvid );
76 switch( ditherType )
78 #if !defined(__AROS__)
79 case HAM_DITHER:
81 ULONG *src = (ULONG *)data;
82 UBYTE *dest,
83 *tmp;
85 ULONG height = anim_height;
87 dest = tmp = (UBYTE *)mymalloc( mvid, (size_t)((anim_width + 15UL) * anim_height) );
89 while( height-- )
91 UBYTE *xrgb = (UBYTE *)src;
93 switch( anim_depth )
95 case 8:
96 CreateHAM8Line( (xrgb + 1), (xrgb + 2), (xrgb + 3), dest, sizeof( ULONG ), anim_width );
97 break;
99 case 6:
100 CreateHAM6Line( (xrgb + 1), (xrgb + 2), (xrgb + 3), dest, sizeof( ULONG ), anim_width );
101 break;
104 dest += anim_width;
105 src += anim_width;
108 AddFrame( mvid, tmp, NULL );
110 myfree( mvid, tmp );
112 break;
113 #endif
114 case FULL_COLOR_DITHER:
115 case FULL_COLOR_DITHER16:
117 AddFrame( mvid, data, NULL );
119 break;
121 default:
123 struct ColorMap *cm = NULL;
125 if( mvid -> mvid_PalettePerFrame )
127 if ((cm = GetColorMap( (1UL << anim_depth) ) ) != NULL)
129 ULONG i,
130 r, g, b;
132 /* Copy colors into colormap... */
133 for( i = 0UL ; i < used_cnt ; i++ )
135 /* Bump colors from 8 to 32 bits-per-gun */
136 r = ((ULONG)used_colors[ i ] . red) * 0x01010101UL;
137 g = ((ULONG)used_colors[ i ] . green) * 0x01010101UL;
138 b = ((ULONG)used_colors[ i ] . blue) * 0x01010101UL;
140 SetRGB32CM( cm, i, r, g, b );
143 /* Fill remaining colors with "black" */
144 for( ; i < (1UL << anim_depth) ; i++ )
146 SetRGB32CM( cm, i, 0UL, 0UL, 0UL );
151 AddFrame( mvid, data, cm );
153 break;
158 void AddFrame( struct MPEGVideoInstData *mvid, UBYTE *data, struct ColorMap *cm )
160 ULONG timestamp = totNumFrames++; /* timestamp of this frame */
161 struct FrameNode *fn;
163 D(bug("[mpegvideo.datatype] %s()\n", __PRETTY_FUNCTION__));
165 /* Image ? */
166 if( data )
168 BOOL created = FALSE;
170 /* Does we have already a frame with this timestamp ? ... */
171 if ((fn = FindFrameNode( (&(mvid -> mvid_FrameList)), timestamp ) ) != NULL)
173 /* ... really ? */
174 if( (fn -> fn_TimeStamp) != timestamp )
176 fn = NULL;
180 if( fn == NULL )
182 if( mvid -> mvid_IndexScan )
184 created = TRUE;
186 fn = AllocFrameNode( classbase, (mvid -> mvid_Pool) );
188 if( fn && (data != (UBYTE *)~0UL) )
190 /* Create a locked frame here if new HAD to create the fn and if we have data.
191 * This is TRUE for the keyframe and/or of the mvid_LoadAll flag is TRUE
193 fn -> fn_IsKeyFrame = TRUE; /* lock this bitmap that ADTM_UNLOADFRAME won't free it */
196 else
198 myexit( mvid, RETURN_ERROR, ERROR_INVALID_LOCK );
202 if( fn )
204 if( created )
206 /* Store frame count */
207 fn -> fn_TimeStamp =
208 fn -> fn_Frame = timestamp;
209 fn -> fn_BMOffset = mvid -> mvid_Last_PIC_SC_Pos;
210 fn -> fn_IFrame = mvid -> mvid_LastIFrameNode;
212 AddTail( (struct List *)(&(mvid -> mvid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
215 /* Does someone wants only to create an empty framenode here (e.g. data == (UBYTE *)~0UL) ? */
216 if( data != (UBYTE *)~0UL )
218 if( (fn -> fn_BitMap) == NULL )
220 if ((fn -> fn_BitMap = AllocFrameBitMap( mvid ) ) != NULL)
222 switch( ditherType )
224 case HAM_DITHER:
225 case GRAY_DITHER:
226 #if 0
227 case FAST_COLOR_DITHER:
228 #endif
229 case ORDERED_DITHER:
231 WritePixelArray8Fast( (fn -> fn_BitMap), data );
233 /* Store colormap */
234 fn -> fn_CMap = cm;
236 break;
238 case FULL_COLOR_DITHER:
239 case FULL_COLOR_DITHER16:
241 if( mvid -> mvid_UseChunkyMap )
243 APTR handle;
244 APTR plane = NULL; /* be safe ! (CyberGFX has some problems with tag parsing...) */
245 ULONG bpr = 0UL, /* be safe ! (CyberGFX has some problems with tag parsing...) */
246 height = 0UL; /* be safe ! (CyberGFX has some problems with tag parsing...) */
248 if( handle = LockBitMapTags( (fn -> fn_BitMap),
249 LBMI_BASEADDRESS, (&plane),
250 LBMI_BYTESPERROW, (&bpr),
251 LBMI_HEIGHT, (&height),
252 TAG_DONE ) )
254 CopyMem( data, plane, (bpr * height) );
256 UnLockBitMap( handle );
258 else
260 error_printf( mvid, "LockBitMapTags failed for bitmap @ 0x%p\n", fn->fn_BitMap);
263 else
265 if( anim_depth == 24UL )
267 struct BitMap red,
268 green,
269 blue;
270 ULONG i;
271 UBYTE *tmp,
272 *tmp_run;
273 ULONG size = anim_width * anim_height;
275 InitBitMap( (&red), 8, (ULONG)anim_width, (ULONG)anim_height );
276 InitBitMap( (&green), 8, (ULONG)anim_width, (ULONG)anim_height );
277 InitBitMap( (&blue), 8, (ULONG)anim_width, (ULONG)anim_height );
279 for( i = 0UL ; i < 24UL ; i++ )
281 if( i < 8 ) red . Planes[ i ] = fn -> fn_BitMap -> Planes[ i ]; else
282 if( i < 16 ) green . Planes[ i - 8 ] = fn -> fn_BitMap -> Planes[ i ]; else
283 blue . Planes[ i - 16 ] = fn -> fn_BitMap -> Planes[ i ];
286 /* Alloc temp memory for XRGB to RRR..., GGG..., BBB... array conversion */
287 tmp = mymalloc( mvid, (size_t)(size + 15UL) );
289 for( i = 0 ; i < 3 ; i++ )
291 ULONG j,
292 j_size = (size * 4UL) + i;
294 for( j = i, tmp_run = tmp ; j < j_size ; j += 4UL )
296 *tmp_run++ = data[ j ];
299 switch( i )
301 case 0: WritePixelArray8Fast( (&red), tmp ); break;
302 case 1: WritePixelArray8Fast( (&green), tmp ); break;
303 case 2: WritePixelArray8Fast( (&blue), tmp ); break;
307 myfree( mvid, tmp );
309 else
311 error_printf( mvid, "%dbit planar direct-RGB unsupported\n", anim_depth);
315 break;
318 else
320 /* no bitmap */
321 myexit( mvid, RETURN_ERROR, ERROR_NO_FREE_STORE );
326 else
328 /* can't alloc struct FrameNode */
329 myexit( mvid, RETURN_ERROR, ERROR_NO_FREE_STORE );
332 else
334 if( mvid -> mvid_IndexScan )
336 /* Find the nearest frame */
337 if ((fn = FindFrameNode( (&(mvid -> mvid_FrameList)), timestamp ) ) != NULL)
339 /* Bump the duration time of the predecessor (frame) */
340 fn -> fn_Duration = timestamp - (fn -> fn_TimeStamp);
348 /***************************************************************/
350 #if !defined(__AROS__)
351 static APTR AllocPooledVec( struct MPEGVideoInstData *mvid, APTR, ULONG );
352 static void FreePooledVec( struct MPEGVideoInstData *mvid, APTR, APTR );
353 #else
354 #define AllocPooledVec(mvid, pool, size) AllocVecPooled(pool, size)
355 #define FreePooledVec(mvid, pool, mem) FreeVecPooled(pool, mem)
356 #endif
357 static ULONG VecSize( APTR );
359 void *mymalloc( struct MPEGVideoInstData *mvid, size_t s )
361 void *mem;
363 if( (mvid -> mvid_MPPool) == NULL )
365 if( (mvid -> mvid_MPPool = CreatePool( (MEMF_PUBLIC | MEMF_CLEAR), 16384UL, 16384UL )) == NULL )
367 myexit( mvid, RETURN_FAIL, ERROR_NO_FREE_STORE );
371 if( (mem = (void *)AllocPooledVec( mvid, (mvid -> mvid_MPPool), (ULONG)s )) == NULL )
373 myexit( mvid, RETURN_ERROR, ERROR_NO_FREE_STORE );
376 return( mem );
380 void myfree( struct MPEGVideoInstData *mvid, void *mem )
382 FreePooledVec( mvid, (mvid -> mvid_MPPool), mem );
386 void *myrealloc( struct MPEGVideoInstData *mvid, void *oldmem, size_t newsize )
388 ULONG oldsize = 0UL;
389 APTR newmem = NULL;
391 if( oldmem )
393 oldsize = VecSize( oldmem );
396 if( newsize == oldsize )
398 return( oldmem );
401 if( newsize )
403 if ((newmem = AllocPooledVec( mvid, (mvid -> mvid_MPPool), (ULONG)newsize ) ) != NULL)
405 if( oldsize )
407 memcpy( newmem, oldmem, (size_t)MIN( oldsize, newsize ) );
410 FreePooledVec( mvid, (mvid -> mvid_MPPool), oldmem );
412 else
414 myexit( mvid, RETURN_FAIL, ERROR_NO_FREE_STORE );
418 return( newmem );
421 #if !defined(__AROS__)
422 static
423 APTR AllocPooledVec( struct MPEGVideoInstData *mvid, APTR pool, ULONG memsize )
425 ULONG *memory = NULL;
427 if( pool && memsize )
429 memsize += (ULONG)sizeof( ULONG );
431 if( memory = (ULONG *)AllocPooled( pool, memsize ) )
433 (*memory) = memsize;
434 memory++;
437 else
439 error_printf( mvid, "AllocPooledVec: illegal args %lx %lx\n", pool, memsize );
442 return( (APTR)memory );
446 static
447 void FreePooledVec( struct MPEGVideoInstData *mvid, APTR pool, APTR mem )
449 if( pool && mem )
451 ULONG *memory;
453 memory = (ULONG *)mem;
455 memory--;
457 FreePooled( pool, memory, (*memory) );
459 else
461 error_printf( mvid, "FreePooledVec: illegal args %lx %lx\n", pool, mem );
464 #endif
466 /* get size of an AllocPooledVec memory */
467 static
468 ULONG VecSize( APTR mem )
470 return( *(((ULONG *)mem) - 1) );
474 ULONG SearchColor( struct MPEGVideoInstData *mvid, struct ColorRegister *colortable, ULONG *numcolors, ULONG maxcount, struct ColorRegister *color )
476 ULONG i;
477 LONG error, minerror =
478 #if !defined(__AROS__)
479 LONG_MAX;
480 #else
481 INT_MAX;
482 #endif
483 ULONG minerrorindex = 0UL;
484 const ULONG nc = *numcolors; /* short cut to (*numcolors) (read only) */
485 WORD er, eg, eb;
487 D(bug("[mpegvideo.datatype] %s()\n", __PRETTY_FUNCTION__));
489 /* Check for a color in the specified range */
490 for( i = 0UL ; i < nc ; i++, colortable++ )
492 er = ABS( ((WORD)(colortable -> red) - (WORD)(color -> red)) );
493 eg = ABS( ((WORD)(colortable -> green) - (WORD)(color -> green)) );
494 eb = ABS( ((WORD)(colortable -> blue) - (WORD)(color -> blue)) );
496 error = er + eg + eb;
498 if( error < minerror )
500 if( error < (mvid -> mvid_ColorError) )
502 return( i );
505 minerror = error;
506 minerrorindex = i;
510 /* Any color entry free for this frame ? */
511 if( nc < maxcount )
513 *colortable = *color;
515 minerrorindex = nc;
517 (*numcolors)++;
520 return( minerrorindex );
524 static
525 void WritePixelArray8Fast( struct BitMap *dest, UBYTE *source )
527 ULONG *plane[ 8 ] = { 0 },
528 *chunky = (ULONG *)source; /* fetch 32 bits per cycle */
529 ULONG i;
530 ULONG numcycles = ((dest -> Rows) * (dest -> BytesPerRow)) / sizeof( ULONG );
532 D(bug("[mpegvideo.datatype] %s()\n", __PRETTY_FUNCTION__));
534 /* Copy plane ptrs */
535 for( i = 0UL ; i < (dest -> Depth) ; i++ )
537 plane[ i ] = (ULONG *)(dest -> Planes[ i ]);
540 /* Fill unused planes with plane 0, which will be written last, all prevoius accesses
541 * will be droped (assumes that a cache hides this "dummy" writes)
543 for( ; i < 8UL ; i++ )
545 plane[ i ] = (ULONG *)(dest -> Planes[ 0 ]);
548 /* Process bitmaps */
549 for( i = 0UL ; i < numcycles ; i++ )
551 ULONG tmp,
552 b0, b1, b2, b3, b4, b5, b6, b7;
554 /* process 32 pixels */
555 b0 = *chunky++; b4 = *chunky++;
556 b1 = *chunky++; b5 = *chunky++;
557 b2 = *chunky++; b6 = *chunky++;
558 b3 = *chunky++; b7 = *chunky++;
560 #define merge( a, b, mask, shift ) \
561 tmp = mask & (a ^ (b >> shift)); \
562 a ^= tmp; \
563 b ^= (tmp << shift)
565 merge( b0, b2, 0x0000ffff, 16 );
566 merge( b1, b3, 0x0000ffff, 16 );
567 merge( b4, b6, 0x0000ffff, 16 );
568 merge( b5, b7, 0x0000ffff, 16 );
570 merge( b0, b1, 0x00ff00ff, 8 );
571 merge( b2, b3, 0x00ff00ff, 8 );
572 merge( b4, b5, 0x00ff00ff, 8 );
573 merge( b6, b7, 0x00ff00ff, 8 );
575 merge( b0, b4, 0x0f0f0f0f, 4 );
576 merge( b1, b5, 0x0f0f0f0f, 4 );
577 merge( b2, b6, 0x0f0f0f0f, 4 );
578 merge( b3, b7, 0x0f0f0f0f, 4 );
580 merge( b0, b2, 0x33333333, 2 );
581 merge( b1, b3, 0x33333333, 2 );
582 merge( b4, b6, 0x33333333, 2 );
583 merge( b5, b7, 0x33333333, 2 );
585 merge( b0, b1, 0x55555555, 1 );
586 merge( b2, b3, 0x55555555, 1 );
587 merge( b4, b5, 0x55555555, 1 );
588 merge( b6, b7, 0x55555555, 1 );
590 *plane[ 7 ]++ = b0;
591 *plane[ 6 ]++ = b1;
592 *plane[ 5 ]++ = b2;
593 *plane[ 4 ]++ = b3;
594 *plane[ 3 ]++ = b4;
595 *plane[ 2 ]++ = b5;
596 *plane[ 1 ]++ = b6;
597 *plane[ 0 ]++ = b7;