AVIReader.st
author Claus Gittinger <cg@exept.de>
Mon, 14 Apr 1997 13:59:34 +0200
changeset 525 59e97643a8bc
child 526 263d3775d846
permissions -rw-r--r--
*** empty log message ***

'From Smalltalk/X, Version:3.1.5 on 11-apr-1997 at 6:49:43 pm'                  !

RIFFReader subclass:#AVIReader
	instanceVariableNames:'frames nframes frameBuffer frameBufferSize imageBuffer redPalette
		greenPalette bluePalette flags frameDelay streamType depth
		compression colorTable numColors deltaMethod'
	classVariableNames:'MAXCOLORS UnsupportedFormatErrorSignal'
	poolDictionaries:''
	category:'Graphics-Images-Support'
!

!AVIReader class methodsFor:'documentation'!

documentation
"
    Read frames from a AVI file.

    this is a very first attempt in reading FLI files;
    its very experimental and may change.
    (will introduce a new class hierarchy based upon
     MovieReader ...).

    When used like an imageReader, #fromFile: will return
    the very first frame.

    Warning: right now, the complete movie is read and huge
    amounts of memoru are allocated. The interface will be changed
    to allow stream operation ...

    [author:]
        Claus Gittinger

    [see also:]
        ImageReader
"
!

examples
"
    |reader film view tNext|

    reader := AVIReader readFile:'/usr/local/AVI/jeffmild.fli'.
    reader isNil ifTrue:[^ nil].
    film := reader images.
    view := StandardSystemView extent:(film first extent).
    view openAndWait.

    tNext := Time millisecondClockValue + (reader frameDelay).
    film do:[:frame |
        frame displayOn:view x:0 y:0.
        (Delay untilMilliseconds:tNext) wait.
        tNext := tNext + (reader frameDelay).
    ].
"
! !

!AVIReader class methodsFor:'class initialization'!

initialize
    MAXCOLORS := 256.

    UnsupportedFormatErrorSignal isNil ifTrue:[
        UnsupportedFormatErrorSignal := ErrorSignal newSignalMayProceed:true.
        UnsupportedFormatErrorSignal nameClass:self message:#unsupportedFormatErrorSignal.
    ].

    "
     AVIReader initialize
    "

    "Created: 4.4.1997 / 22:35:52 / cg"
    "Modified: 5.4.1997 / 14:37:08 / cg"
! !

!AVIReader class methodsFor:'testing'!

isValidImageFile:aFileName
    "return true, if aFileName contains an AVI-movie"

    |data1 len data3 inStream|

    inStream := self streamReadingFile:aFileName.
    inStream isNil ifTrue:[^ false].
    inStream binary.

    data1 := String new:4.
    inStream nextBytes:4 into:data1.
    len := inStream nextLongMSB:true.
    data3 := String new:4.
    inStream nextBytes:4 into:data3.

    ((data1 = 'RIFF')
    and:[data3 = 'AVI ']) ifTrue:[
        ^ true
    ].
    inStream close.
    ^ false.

    "
     AVIReader isValidImageFile:'bitmaps/magtape.xpm'    
     AVIReader isValidImageFile:'/home2/pd_stuff/movies/avi/drlair.avi'      
    "

    "Created: 4.4.1997 / 22:35:52 / cg"
    "Modified: 4.4.1997 / 23:15:39 / cg"
! !

!AVIReader methodsFor:'accessing'!

frameDelay
    "return the value of the instance variable 'frameDelay' (automatically generated)"

    ^ frameDelay

    "Created: 4.4.1997 / 22:35:52 / cg"
!

hasMultipleImages
    ^ frames size > 1

    "Modified: 4.4.1997 / 21:42:59 / cg"
    "Created: 4.4.1997 / 22:35:52 / cg"
!

images
    "return a collection of all images as represented by myself"

    |images image depth|

    depth := self bitsPerPixel.

    images := OrderedCollection new.
    frames do:[:aFrame |
        image := (Image implementorForDepth:depth) new.
        image 
            width:width 
            height:height
            photometric:photometric
            samplesPerPixel:samplesPerPixel
            bitsPerSample:bitsPerSample
            colorMap:colorMap
            bits:aFrame
            mask:mask.
        images add:image.
    ].
    ^ images

    "Modified: 20.6.1996 / 17:09:04 / cg"
    "Created: 4.4.1997 / 22:35:52 / cg"
! !

!AVIReader methodsFor:'decoders'!

AVI_Decode_CRAM:data
"

/*
 * Routine to Decode an AVI CRAM chunk
 */

#define AVI_CRAM_C1(ip,clr,rdec) { \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; ip -= rdec; \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; ip -= rdec; \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; ip -= rdec; \
 *ip++ = clr; *ip++ = clr; *ip++ = clr; *ip = clr; }

#define AVI_CRAM_C2(ip,flag,cA,cB,rdec) { \
  *ip++ =(flag&0x01)?(cB):(cA); *ip++ =(flag&0x02)?(cB):(cA); \
  *ip++ =(flag&0x04)?(cB):(cA); *ip   =(flag&0x08)?(cB):(cA); ip-=rdec; \
  *ip++ =(flag&0x10)?(cB):(cA); *ip++ =(flag&0x20)?(cB):(cA); \
  *ip++ =(flag&0x40)?(cB):(cA); *ip   =(flag&0x80)?(cB):(cA); }

#define AVI_CRAM_C4(ip,flag,cA0,cA1,cB0,cB1,rdec) { \
  *ip++ =(flag&0x01)?(cB0):(cA0); *ip++ =(flag&0x02)?(cB0):(cA0); \
  *ip++ =(flag&0x04)?(cB1):(cA1); *ip   =(flag&0x08)?(cB1):(cA1); ip-=rdec; \
  *ip++ =(flag&0x10)?(cB0):(cA0); *ip++ =(flag&0x20)?(cB0):(cA0); \
  *ip++ =(flag&0x40)?(cB1):(cA1); *ip   =(flag&0x80)?(cB1):(cA1); }

#define AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y) { \
    if (x < min_x) min_x = x; if (y > max_y) max_y = y; \
    if (x > max_x) max_x = x; if (y < min_y) min_y = y; } 

#define AVI_BLOCK_INC(x,y,imagex) { x += 4; if (x>=imagex) { x=0; y -= 4; } }

#define AVI_GET_16(data,dptr) { data = *dptr++; data |= (*dptr++) << 8; }

#define AVI_CRAM_rgbC1(ip,r,g,b) { \
 *ip++=r; *ip++=g; *ip++=b; *ip++=r; *ip++=g; *ip++=b; \
 *ip++=r; *ip++=g; *ip++=b; *ip++=r; *ip++=g; *ip  =b; }

#define AVI_CRAM_rgbC2(ip,flag,rA,gA,bA,rB,gB,bB) { \
  if (flag&0x01) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else           {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x02) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else           {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x04) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else           {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x08) {*ip++=rB; *ip++=gB; *ip  =bB;} \
  else           {*ip++=rA; *ip++=gA; *ip  =bA;}  }

#define AVI_CRAM_rgbC4(ip,flag,rA,gA,bA,rB,gB,bB) { \
  if (flag&0x01) {*ip++=rB; *ip++=gB; *ip++=bB;} \
  else           {*ip++=rA; *ip++=gA; *ip++=bA;} \
  if (flag&0x02) {*ip++=rB; *ip++=gB; *ip  =bB;} \
  else           {*ip++=rA; *ip++=gA; *ip  =bA;} }

#define AVI_Get_RGBColor(r,g,b,color) \
{ register ULONG _r,_g,_b; \
  _r = (color >> 10) & 0x1f; r = (_r << 3) | (_r >> 2); \
  _g = (color >>  5) & 0x1f; g = (_g << 3) | (_g >> 2); \
  _b =  color & 0x1f;        b = (_b << 3) | (_b >> 2); \
  if (xa_gamma_flag==TRUE) { r = xa_gamma_adj[r]>>8;    \
     g = xa_gamma_adj[g]>>8; b = xa_gamma_adj[b]>>8; } }


ULONG
AVI_Decode_CRAM(image,delta,dsize,chdr,map,map_flag,imagex,imagey,imaged,
                                                xs,ys,xe,ye,special,extra)
UBYTE *image;           /* Image Buffer. */
UBYTE *delta;           /* delta data. */
ULONG dsize;            /* delta size */
XA_CHDR *chdr;          /* color map info */
ULONG *map;             /* used if it's going to be remapped. */
ULONG map_flag;         /* whether or not to use remap_map info. */
ULONG imagex,imagey;    /* Size of image buffer. */
ULONG imaged;           /* Depth of Image. (IFF specific) */
ULONG *xs,*ys;          /* pos of changed area. */
ULONG *xe,*ye;          /* size of changed area. */
ULONG special;          /* Special Info. */
void *extra;            /* extra info needed to decode delta */
{
  ULONG row_dec,exitflag,changed,block_cnt;
  ULONG code0,code1;
  LONG x,y,min_x,max_x,min_y,max_y;
  UBYTE *dptr;

  changed = 0;
  max_x = max_y = 0;    min_x = imagex; min_y = imagey;
  dptr = delta;
  row_dec = imagex + 3;
  x = 0;
  y = imagey - 1;
  exitflag = 0;
  block_cnt = ((imagex * imagey) >> 4) + 1;

  if (map_flag == TRUE)
  {
    if (x11_bytes_pixel == 4)
    {
      while(!!exitflag)
      {
        code0 =  *dptr++;       code1 =  *dptr++;       block_cnt--;
        if ( ((code1==0) && (code0==0) && !!block_cnt) || (y<0)) exitflag = 1;
        else
        {
          if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
          { ULONG skip = ((code1 - 0x84) << 8) + code0;
            block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
          }
          else /* single block encoded */
          {
            if (code1 >= 0x90) /* 8 color quadrant encoding */
            { ULONG cA0,cA1,cB0,cB1;
              ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
              cB0 = (ULONG)map[*dptr++];  cA0 = (ULONG)map[*dptr++];
              cB1 = (ULONG)map[*dptr++];  cA1 = (ULONG)map[*dptr++];
              AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
              cB0 = (ULONG)map[*dptr++];  cA0 = (ULONG)map[*dptr++];
              cB1 = (ULONG)map[*dptr++];  cA1 = (ULONG)map[*dptr++];
              AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
            } else if (code1 < 0x80) /* 2 color encoding */
            { register ULONG clr_A,clr_B;
              ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
              clr_B = (ULONG)map[*dptr++];   clr_A = (ULONG)map[*dptr++];
              AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
              AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
            }
            else /* 1 color encoding */
            { ULONG clr = (ULONG)map[code0]; 
              ULONG *i_ptr = (ULONG *)(image + ((y * imagex + x) << 2) );
              AVI_CRAM_C1(i_ptr,clr,row_dec);
            }
            AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
            changed = 1; AVI_BLOCK_INC(x,y,imagex);
          } /* end of single block */
        } /* end of not term code */
      } /* end of not while exit */
    } /* end of 4 bytes pixel */
    else if (x11_bytes_pixel == 2)
    {
      while(!!exitflag)
      {
        code0 =  *dptr++;       code1 =  *dptr++;       block_cnt--;
        if ( ((code1==0) && (code0==0) && !!block_cnt) || (y<0)) exitflag = 1;
        else
        {
          if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
          { ULONG skip = ((code1 - 0x84) << 8) + code0;
            block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
          } else /* single block encoded */
          {
            if (code1 >= 0x90) /* 8 color quadrant encoding */
            {
              USHORT cA0,cA1,cB0,cB1;
              USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
              cB0 = map[*dptr++];  cA0 = map[*dptr++];
              cB1 = map[*dptr++];  cA1 = map[*dptr++];
              AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
              cB0 = map[*dptr++];  cA0 = map[*dptr++];
              cB1 = map[*dptr++];  cA1 = map[*dptr++];
              AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
            } /* end of 8 color quadrant encoding */
            else if (code1 < 0x80) /* 2 color encoding */
            { USHORT clr_A,clr_B;
              USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
              clr_B = (USHORT)map[*dptr++];   clr_A = (USHORT)map[*dptr++];
              AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
              AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
            } /* end of 2 color */
            else /* 1 color encoding */
            { USHORT clr = (USHORT)map[code0];
              USHORT *i_ptr = (USHORT *)(image + ((y * imagex + x) << 1) );
              AVI_CRAM_C1(i_ptr,clr,row_dec);
            }
            AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
            changed = 1; AVI_BLOCK_INC(x,y,imagex);
          } /* end of single block */
        } /* end of not term code */
      } /* end of not while exit */
    } /* end of 2 bytes pixel */
    else /* (x11_bytes_pixel == 1) */
    {
      while(!!exitflag)
      {
        code0 =  *dptr++;       code1 =  *dptr++;       block_cnt--;
        if ( ((code1==0) && (code0==0) && !!block_cnt) || (y<0)) exitflag = 1;
        else
        {
          if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
          { ULONG skip = ((code1 - 0x84) << 8) + code0;
            block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
          } else /* single block encoded */
          { 
            if (code1 >= 0x90) /* 8 color quadrant encoding */
            { UBYTE cA0,cA1,cB0,cB1;
              UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
              cB0 = (UBYTE)map[*dptr++];  cA0 = (UBYTE)map[*dptr++];
              cB1 = (UBYTE)map[*dptr++];  cA1 = (UBYTE)map[*dptr++];
              AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
              cB0 = (UBYTE)map[*dptr++];  cA0 = (UBYTE)map[*dptr++];
              cB1 = (UBYTE)map[*dptr++];  cA1 = (UBYTE)map[*dptr++];
              AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
            } 
            else if (code1 < 0x80) /* 2 color encoding */
            { UBYTE clr_A,clr_B;
              UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
              clr_B = (UBYTE)map[*dptr++];   clr_A = (UBYTE)map[*dptr++];
              AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
              AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
            }
            else /* 1 color encoding */
            { UBYTE clr = (UBYTE)map[code0];
              UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
              AVI_CRAM_C1(i_ptr,clr,row_dec);
            }
            AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
            changed = 1; AVI_BLOCK_INC(x,y,imagex);
          } /* end of single block */
        } /* end of not term code */
      } /* end of not while exit */
    } /* end of 1 bytes pixel */
  } /* end of map is TRUE */
  else
  {
      while(!!exitflag)
      {
        code0 =  *dptr++;       code1 =  *dptr++;       block_cnt--;
        if ( ((code1==0) && (code0==0) && !!block_cnt) || (y<0)) exitflag = 1;
        else
        {
          if ((code1 >= 0x84) && (code1 <= 0x87)) /* skip */
          { ULONG skip = ((code1 - 0x84) << 8) + code0;
            block_cnt -= (skip-1); while(skip--) AVI_BLOCK_INC(x,y,imagex);
          } else /* single block encoded */
          {
            if (code1 >= 0x90) /* 8 color quadrant encoding */
            {
              UBYTE cA0,cA1,cB0,cB1;
              UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
              cB0 = (UBYTE)*dptr++;  cA0 = (UBYTE)*dptr++;
              cB1 = (UBYTE)*dptr++;  cA1 = (UBYTE)*dptr++;
              AVI_CRAM_C4(i_ptr,code0,cA0,cA1,cB0,cB1,row_dec); i_ptr -=row_dec;
              cB0 = (UBYTE)*dptr++;  cA0 = (UBYTE)*dptr++;
              cB1 = (UBYTE)*dptr++;  cA1 = (UBYTE)*dptr++;
              AVI_CRAM_C4(i_ptr,code1,cA0,cA1,cB0,cB1,row_dec);
            } 
            else if (code1 < 0x80) /* 2 color encoding */
            { UBYTE clr_A,clr_B;
              UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
              clr_B = (UBYTE)*dptr++;   clr_A = (UBYTE)*dptr++;
              AVI_CRAM_C2(i_ptr,code0,clr_A,clr_B,row_dec); i_ptr -= row_dec;
              AVI_CRAM_C2(i_ptr,code1,clr_A,clr_B,row_dec);
            } /* end of 2 color */
            else /* 1 color encoding */
            {
              UBYTE clr = (UBYTE)code0;
              UBYTE *i_ptr = (UBYTE *)(image + y * imagex + x);
              AVI_CRAM_C1(i_ptr,clr,row_dec);
            }
            AVI_MIN_MAX_CHECK(x,y,min_x,max_x,min_y,max_y);
            changed = 1; AVI_BLOCK_INC(x,y,imagex);
          } /* end of single block */
        } /* end of not term code */
      } /* end of not while exit */
  }
  if (xa_optimize_flag == TRUE)
  {
    if (changed) { *xs=min_x; *ys=min_y - 3; *xe=max_x + 4; *ye=max_y + 1; }
    else  { *xs = *ys = *xe = *ye = 0; return(ACT_DLTA_NOP); }
  }
  else { *xs = *ys = 0; *xe = imagex; *ye = imagey; }
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

"

    'AVI_Decode_CRAM' infoPrint.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 16:06:10 / cg"
    "Modified: 11.4.1997 / 14:03:32 / cg"
! !

!AVIReader methodsFor:'helpers'!

alignHeightTo:multiple
    "make height a multiple of the argument"

    height := multiple * ((height + multiple - 1) // multiple).

    "Modified: 5.4.1997 / 14:47:36 / cg"
!

alignTo:multiple
    "make width & height a multiple of the argument"

    width := multiple * ((width + multiple - 1) // multiple).
    height := multiple * ((height + multiple - 1) // multiple).

    "Created: 5.4.1997 / 14:47:54 / cg"
!

alignWidthTo:multiple
    "make height a multiple of the argument"

    width := multiple * ((width + multiple - 1) // multiple).

    "Created: 5.4.1997 / 14:47:16 / cg"
    "Modified: 5.4.1997 / 14:47:41 / cg"
! !

!AVIReader methodsFor:'reading from stream'!

fromStream:aStream
    "read a AVI-movie from aStream. Return a frame sequence."

    inStream := aStream.
    inStream binary.

    [inStream atEnd] whileFalse:[
        self getChunk
    ].

    "/ return the first frame as image

    colorMap := Colormap 
                    redVector:redPalette 
                    greenVector:greenPalette 
                    blueVector:bluePalette.

    photometric := #palette.
    samplesPerPixel := 1.
    bitsPerSample := #(8).

    frames notNil ifTrue:[
        data := frames at:1.
    ]

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/drlair.avi'      
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 22:35:53 / cg"
    "Modified: 5.4.1997 / 14:34:54 / cg"
! !

!AVIReader ignoredMethodsFor:'reading from stream'!

getChunk
    "get a single chunk"

    |id sel sTyp|

    'getChunk -> ' infoPrint.

    id := '    '.
    inStream nextBytes:4 into:id startingAt:1.
    chunkSize := inStream nextLongMSB:false.

    (id at:1) == $0 ifTrue:[
        sTyp := streamTypes at:((id at:2) digitValue + 1).
        sel := 'getChunk_' , sTyp , '_' , (id copyFrom:3).

"/id infoPrint. ' -> ' infoPrint. sel infoPrintCR.
        sel := sel asSymbolIfInterned.
        (sel isNil or:[(self respondsTo:sel) not]) ifTrue:[
            sel := 'getChunk_' , sTyp , '_Unknown'.
"/'  ' infoPrint. id infoPrint. ' -> ' infoPrint. sel infoPrintCR.
            sel := sel asSymbolIfInterned.
            (sel isNil or:[(self respondsTo:sel) not]) ifTrue:[
                '[' infoPrint. ('getChunk_' , sTyp , '_' , (id copyFrom:3)) infoPrint. '] ' infoPrint.
                sel := #'getChunk_Unknown'.    
"/'    ' infoPrint. id infoPrint. ' -> ' infoPrint. sel infoPrintCR.
            ].
        ]
    ] ifFalse:[
        (id at:4) == Character space ifTrue:[
            id := id copyTo:3
        ].
        sel := ('getChunk_' , id) asSymbolIfInterned.
        (sel isNil or:[(self respondsTo:sel) not]) ifTrue:[
            '[' infoPrint. ('getChunk_' , id) infoPrint. '] ' infoPrint.
            sel := #'getChunk_Unknown'    
        ].
"/id infoPrint. ' -> ' infoPrint. sel infoPrintCR.
    ].

    self perform:sel.
    '' infoPrintCR.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 22:50:13 / cg"
    "Modified: 5.4.1997 / 15:47:48 / cg"
! !

!AVIReader methodsFor:'reading from stream'!

getChunk_DISP
    "process (ignore) a DISP chunk"

    'getChunk_DISP -> ' infoPrint.

    self skipChunk

    "Created: 5.4.1997 / 15:19:10 / cg"
!

getChunk_ISBJ
    "process (ignore) a ISBJ chunk"

    'getChunk_ISBJ -> ' infoPrint.

    self skipChunk

    "Created: 5.4.1997 / 15:19:17 / cg"
!

getChunk_JUNK
    "ignore JUNK chunk"

    'getChunk_JUNK -> ' infoPrint.

    self skipChunk

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 14:12:27 / cg"
    "Modified: 5.4.1997 / 14:34:47 / cg"
!

getChunk_LIST
    "process a LIST chunk"

    'getChunk_LIST' infoPrint.

    inStream skip:4.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 23:18:33 / cg"
    "Modified: 5.4.1997 / 14:34:45 / cg"
!

getChunk_RIFF
    "process a RIFF chunk"

    'getChunk_RIFF' infoPrint.

    inStream skip:4.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 23:18:08 / cg"
    "Modified: 5.4.1997 / 14:34:42 / cg"
!

getChunk_Unknown
    "ignore any other chunk"

    'getChunk_Unknown -> ' infoPrint.

    self skipChunk

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 00:03:43 / cg"
    "Modified: 5.4.1997 / 14:34:39 / cg"
!

getChunk_auds
    "process an auds chunk"

    |format channels rate av_bps align size|

    'getChunk_auds' infoPrint.

    format      := inStream nextShortMSB:false.
    channels    := inStream nextShortMSB:false.
    rate        := inStream nextLongMSB:false.
    av_bps      := inStream nextLongMSB:false.
    align       := inStream nextShortMSB:false.
    size        := inStream nextShortMSB:false.

    inStream skip:(chunkSize - 16).

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 00:01:15 / cg"
    "Modified: 5.4.1997 / 14:34:36 / cg"
!

getChunk_auds_wb
    "process (ignore for now) an auds chunk"

    'getChunk_auds_wb -> ' infoPrint.

    self skipChunk

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 13:57:56 / cg"
    "Modified: 5.4.1997 / 14:34:33 / cg"
!

getChunk_avih
    "process an avih chunk"

    |us_frame max_bps pad_gram flags tot_frames init_frames nstreams
     sug_bsize scale rate start length|

    'getChunk_avih' infoPrint.

    chunkSize ~~ 56 ifTrue:[
        self halt:'bad chunk size'.
    ].

    us_frame    := inStream nextLongMSB:false.
    max_bps     := inStream nextLongMSB:false.
    pad_gram    := inStream nextLongMSB:false.
    flags       := inStream nextLongMSB:false.
    tot_frames  := inStream nextLongMSB:false.
    init_frames := inStream nextLongMSB:false.
    nstreams    := inStream nextLongMSB:false.
    sug_bsize   := inStream nextLongMSB:false.
    width       := inStream nextLongMSB:false.
    height      := inStream nextLongMSB:false.
    scale       := inStream nextLongMSB:false.
    rate        := inStream nextLongMSB:false.
    start       := inStream nextLongMSB:false.
    length      := inStream nextLongMSB:false.

    streamTypes := OrderedCollection new:nstreams.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 23:19:37 / cg"
    "Modified: 5.4.1997 / 14:34:30 / cg"
!

getChunk_hdrl
    "process (ignore) a hdrl chunk"

    'getChunk_hdrl -> ' infoPrint.

    self skipChunk

    "Created: 5.4.1997 / 15:18:07 / cg"
!

getChunk_idx1
    "process (ignore) a idx1 chunk"

    'getChunk_idx1 -> ' infoPrint.

    self skipChunk

    "Created: 5.4.1997 / 15:17:53 / cg"
!

getChunk_strf
    "process a strf chunk"

    |sel|

    'getChunk_strf -> ' infoPrint.

    sel := ('getChunk_' , streamType) asSymbolIfInterned.
    (sel isNil or:[(self respondsTo:sel) not]) ifTrue:[
        '[' infoPrint. ('getChunk_' , streamType) infoPrint. '] ' infoPrint.
        sel := #'getChunk_Unknown'
    ].
    self perform:sel.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 23:41:09 / cg"
    "Modified: 5.4.1997 / 15:05:00 / cg"
!

getChunk_strh
    "process a strh chunk"

    |fcc_type fcc_handler priority flags rate init_frames streams
     sug_bsize scale start length quality samp_size size|

    'getChunk_strh' infoPrint.

    chunkSize < 48 ifTrue:[
        self halt:'bad chunk size'.
    ].

    fcc_type    := String new:4.
                   inStream nextBytes:4 into:fcc_type.
    fcc_handler := inStream nextLongMSB:true.
    flags       := inStream nextLongMSB:false.
    priority    := inStream nextLongMSB:false.
    init_frames := inStream nextLongMSB:false.
    scale       := inStream nextLongMSB:false.
    rate        := inStream nextLongMSB:false.
    start       := inStream nextLongMSB:false.
    length      := inStream nextLongMSB:false.
    sug_bsize   := inStream nextLongMSB:false.
    quality     := inStream nextLongMSB:false.
    samp_size   := inStream nextLongMSB:false.

    size := chunkSize.
    (size bitTest:1) ifTrue:[
        size := size + 1
    ].
    inStream skip:(size - 48).

    streamTypes add:fcc_type.
    streamType := fcc_type.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 23:25:54 / cg"
    "Modified: 5.4.1997 / 14:34:23 / cg"
!

getChunk_strl
    "process (ignore) a strl chunk"

    'getChunk_strl -> ' infoPrint.

    self skipChunk

    "Created: 5.4.1997 / 15:18:01 / cg"
!

getChunk_vedt
    "process (ignore) a vedt chunk"

    'getChunk_vedt -> ' infoPrint.

    self skipChunk

    "Created: 5.4.1997 / 15:17:43 / cg"
!

getChunk_vids
    "process a vids chunk"

    |size sz
     width height planes image_size
     xpels_meter ypels_meter num_colors imp_colors
     sel nMore|

    'getChunk_vids -> ' infoPrint.

    sz := chunkSize.
    (sz bitTest:1) ifTrue:[
        sz := sz + 1
    ].
    colorTable := true.

    size        := inStream nextLongMSB:false.
    width       := inStream nextLongMSB:false.
    height      := inStream nextLongMSB:false.
    planes      := inStream nextShortMSB:false.
    depth       := inStream nextShortMSB:false.
    compression := String new:4.
                   inStream nextBytes:4 into:compression.
    image_size  := inStream nextLongMSB:false.
    xpels_meter := inStream nextLongMSB:false.
    ypels_meter := inStream nextLongMSB:false.
    num_colors  := inStream nextLongMSB:false.
    imp_colors  := inStream nextLongMSB:false.
    sz := sz - 40.

    numColors := num_colors.
    (numColors == 0 and:[depth <= 8]) ifTrue:[
        numColors := 1 bitShift:depth.
    ].

    sel := ('setupData_vids_' , compression) asSymbolIfInterned.
    (sel isNil or:[(self respondsTo:sel) not]) ifTrue:[
        '[' infoPrint. ('setupData_vids_' , compression) infoPrint. '] ' infoPrint.
        sel := #'setupData_vids_Unknown'
    ].

    "/ setup compression-specific data
    self perform:sel.

    "/ read a colorTable - if any
    ((depth <= 8) and:[colorTable]) ifTrue:[
        redPalette := ByteArray new:256.
        greenPalette := ByteArray new:256.
        bluePalette := ByteArray new:256.

        1 to:numColors do:[:i |
            sz > 0 ifTrue:[
                bluePalette at:i put:(inStream nextByte).
                greenPalette at:i put:(inStream nextByte).
                redPalette at:i put:(inStream nextByte).
                inStream nextByte. "/ padding
                sz := sz - 4.
            ].
        ]
    ].

    "/ read more compression-specific data
    sel := ('readData_vids2_' , compression) asSymbolIfInterned.
    (sel isNil or:[(self respondsTo:sel) not]) ifTrue:[
    ] ifFalse:[
        nMore := self perform:sel.
        sz := sz  - nMore.
    ].

    inStream skip:sz.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 4.4.1997 / 23:25:54 / cg"
    "Modified: 5.4.1997 / 15:32:10 / cg"
!

getChunk_vids_dc
    "process a vids chunk"

    |sz data sel|

    'getChunk_vids_dc -> ' infoPrint.

    sz := chunkSize.
    (sz bitTest:1) ifTrue:[
        sz := sz + 1
    ].

    sz == 0 ifTrue:[
        "/ NOP wait frame
        ^ self
    ].

    data := ByteArray new:sz.
    inStream nextBytes:sz into:data startingAt:1.

    sel := deltaMethod.
    (self respondsTo:sel) not ifTrue:[
        '[' infoPrint. deltaMethod infoPrint. '] ' infoPrint.
        ^ self
    ].

    self perform:deltaMethod with:data.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 01:01:37 / cg"
    "Modified: 5.4.1997 / 15:44:46 / cg"
!

readData_vids2_IJPG
    "more extra data here"

    |offset jsize format cspace|

    'readData_vids2_IJPG' infoPrint.

    offset := inStream nextLongMSB:false.
    jsize := inStream nextLongMSB:false.
    format := inStream nextLongMSB:false.
    cspace := inStream nextLongMSB:false.

    self JFIF_Read_IJPG_Tables.

    ^ 16 + 128.

    "Created: 5.4.1997 / 15:08:04 / cg"
!

readData_vids2_JPEG
    "more extra data here"

    |offset jsize format cspace bits hsubsamp vsubsamp|

    'readData_vids2_IJPG' infoPrint.

    offset := inStream nextLongMSB:false.
    jsize := inStream nextLongMSB:false.
    format := inStream nextLongMSB:false.
    cspace := inStream nextLongMSB:false.
    bits := inStream nextLongMSB:false.
    hsubsamp := inStream nextLongMSB:false.
    vsubsamp := inStream nextLongMSB:false.

    ^ 28.

    "Created: 5.4.1997 / 15:08:43 / cg"
!

setupData_vids_CRAM
    "CRAM specific setup"

    'setupData_vids_CRAM' infoPrint.

    "/ need to be multiple of 4
    self alignTo:4.

    depth == 8 ifTrue:[
        deltaMethod := #AVI_Decode_CRAM:
    ] ifFalse:[
        depth == 16 ifTrue:[
            deltaMethod := #AVI_Decode_CRAM16:
        ] ifFalse:[
"/            'AVI [info]: CRAM but depth ~~ 8/16 format not supported' errorPrintCR.
            UnsupportedFormatErrorSignal raiseErrorString:'CRAM but depth ~~ 8/16'.
        ]
    ]

    "Modified: 5.4.1997 / 15:42:12 / cg"
!

setupData_vids_CVID
    "CVID specific setup"

    'setupData_vids_CVID' infoPrint.

"/    'AVI [info]: Radius Cinepak format not supported' errorPrintCR.
    UnsupportedFormatErrorSignal raiseErrorString:'Radius Cinepak format not supported'.

    "Modified: 5.4.1997 / 15:42:38 / cg"
!

setupData_vids_IJPG
    "IJPG specific setup"

    'setupData_vids_IJPG' infoPrint.

    "/ need to be multiple of 4@2
    self alignWidthTo:4.
    self alignHeightTo:2.

    depth > 8 ifTrue:[
        self QT_Gen_YUV_Tabs.
    ] ifFalse:[
        colorTable := false
    ].
    self jpg_alloc_MCU_bufs:width.

    depth ~~ 24 ifTrue:[
"/    'AVI [info]: IJPG but depth ~~ 24' errorPrintCR.
        UnsupportedFormatErrorSignal raiseErrorString:'IJPG but depth ~~ 24'.
        ^ self
    ].
    deltaMethod := #JFIF_Decode_JPEG:

    "Modified: 5.4.1997 / 15:55:55 / cg"
!

setupData_vids_IV31
    "IV31 specific setup"

    'setupData_vids_IV31' infoPrint.

"/    'AVI [info]: AVI: Intel Indeo Video Codec Not Supported' errorPrintCR.
    UnsupportedFormatErrorSignal raiseErrorString:'AVI: Intel Indeo Video Codec Not Supported'.

    "Created: 5.4.1997 / 15:56:43 / cg"
!

setupData_vids_IV32
    "IV32 specific setup"

    'setupData_vids_IV32' infoPrint.

"/    'AVI [info]: AVI: Intel Indeo Video Codec Not Supported' errorPrintCR.
    UnsupportedFormatErrorSignal raiseErrorString:'AVI: Intel Indeo Video Codec Not Supported'.

    "Created: 5.4.1997 / 15:56:49 / cg"
!

setupData_vids_JPEG
    "JPEG specific setup"

    'setupData_vids_JPEG' infoPrint.

    "/ need to be multiple of 4@2
    self alignWidthTo:4.
    self alignHeightTo:2.

    depth > 8 ifTrue:[
        self QT_Gen_YUV_Tabs.
    ] ifFalse:[
        colorTable := false
    ].
    self jpg_alloc_MCU_bufs:width.

    depth ~~ 8 ifTrue:[
        depth ~~ 24 ifTrue:[
"/        'AVI [info]: JPEG but depth ~~ 8/24' errorPrintCR.
            UnsupportedFormatErrorSignal raiseErrorString:'JPEG but depth ~~ 8/24'.
            ^ self
        ]
    ].
    deltaMethod := #JFIF_Decode_JPEG:

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:55:05 / cg"
!

setupData_vids_MJPG
    "MJPG specific setup"

    'setupData_vids_MJPG' infoPrint.

    UnsupportedFormatErrorSignal raiseErrorString:'MJPG not yet supported'.

    "/ need to be multiple of 4@2
    self alignWidthTo:4.
    self alignHeightTo:2.

    depth > 8 ifTrue:[
        self QT_Gen_YUV_Tabs.
    ] ifFalse:[
        colorTable := false
    ].
    self jpg_alloc_MCU_bufs:width.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:53:08 / cg"
!

setupData_vids_MSVC
    "MSVC specific setup"

    'setupData_vids_MSVC' infoPrint.

    "/ need to be multiple of 4
    self alignTo:4.

    depth == 8 ifTrue:[
        deltaMethod := #AVI_Decode_CRAM:
    ] ifFalse:[
        depth == 16 ifTrue:[
            deltaMethod := #AVI_Decode_CRAM16:
        ] ifFalse:[
"/            'AVI [info]: MSVC but depth ~~ 8/16 format not supported' errorPrintCR.
            UnsupportedFormatErrorSignal raiseErrorString:'MSVC but depth ~~ 8/16'.
        ]
    ]

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:41:56 / cg"
!

setupData_vids_NONE
    "NONE specific setup"

    'setupData_vids_NONE' infoPrint.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:34:25 / cg"
!

setupData_vids_PACK
    "PACK specific setup"

    'setupData_vids_PACK' infoPrint.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:34:31 / cg"
!

setupData_vids_RGB
    "RGB specific setup"

    'setupData_vids_RGB' infoPrint.

    depth == 8 ifTrue:[
        deltaMethod := #AVI_Decode_RGB:
    ] ifFalse:[
        depth == 24 ifTrue:[
            deltaMethod := #AVI_Decode_RGB24:
        ] ifFalse:[
"/            'AVI [info]: RGB but depth ~~ 8/24 format not supported' errorPrintCR.
            UnsupportedFormatErrorSignal raiseErrorString:'RGB but depth ~~ 8/24'.
        ]
    ]

    "Modified: 5.4.1997 / 15:41:56 / cg"
    "Created: 5.4.1997 / 15:48:47 / cg"
!

setupData_vids_RLE4
    "RLE4 specific setup"

    'setupData_vids_RLE4' infoPrint.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:34:38 / cg"
!

setupData_vids_RLE8
    "RLE8 specific setup"

    'setupData_vids_RLE8' infoPrint.

    depth ~~ 8 ifTrue:[
"/        'AVI [info]: RLE8 but depth ~~ 8 format not supported' errorPrintCR.
        UnsupportedFormatErrorSignal raiseErrorString:'RLE8 but depth ~~ 8'.
        ^ self
    ].
    deltaMethod := #AVI_Decode_RLE8:

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:43:22 / cg"
!

setupData_vids_RT21
    "RT21 specific setup"

    'setupData_vids_RT21' infoPrint.

"/    'AVI [info]: AVI: Intel Indeo Video Codec Not Supported' errorPrintCR.
    UnsupportedFormatErrorSignal raiseErrorString:'AVI: Intel Indeo Video Codec Not Supported'.

    "Created: 5.4.1997 / 15:56:37 / cg"
!

setupData_vids_TRAN
    "TRAN specific setup"

    'setupData_vids_TRAN' infoPrint.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:34:53 / cg"
!

setupData_vids_ULTI
    "ULTI specific setup"

    'setupData_vids_ULTI' infoPrint.

    depth == 16 ifTrue:[
        deltaMethod := #AVI_Decode_ULTI:
    ] ifFalse:[
"/        'AVI [info]: ULTI depth ~~ 16 format not supported' errorPrintCR.
        UnsupportedFormatErrorSignal raiseErrorString:'ULTI depth ~~ 16'.
        ^ self.
    ].

    "/ need to be multiple of 8
    self alignTo:8.

    self AVI_ULTI_Gen_YUV.
    self AVI_Ulti_Gen_LTC.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:46:14 / cg"
!

setupData_vids_Unknown
    "ignore an unknown vids chunk"

    'setupData_vids_Unknown' infoPrint.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:32:52 / cg"
!

setupData_vids_XMPG
    "XMPG specific setup"

    'setupData_vids_XMPG' infoPrint.

    "/ need to be multiple of 4
    self alignTo:4.

    self QT_Gen_YUV_Tabs.
    self jpg_alloc_MCU_bufs:width.
    self jpg_setup_samp_limit_table.
    self mpg_init_stuff.

    deltaMethod := #MPG_Decode_I:

    "Modified: 5.4.1997 / 15:49:53 / cg"
!

setupData_vids_YUV9
    "YUV9 specific setup"

    'setupData_vids_YUV9' infoPrint.

    self QT_Gen_YUV_Tabs.
    self jpg_setup_samp_limit_table.

    "/ need to be multiple of 4
    self alignTo:4.

    deltaMethod := #AVI_Decode_YUV9:

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:49:19 / cg"
!

setupData_vids_YVU9
    "YVU9 specific setup"

    'setupData_vids_YVU9' infoPrint.

    self QT_Gen_YUV_Tabs.
    self jpg_setup_samp_limit_table.

    "/ need to be multiple of 4
    self alignTo:4.

    deltaMethod := #AVI_Decode_YUV9:

    "Modified: 5.4.1997 / 15:49:32 / cg"
!

setupData_vids_cvid
    "same as CVID"

    'setupData_vids_cvid' infoPrint.
    compression := 'CVID'.
    ^ self setupData_vids_CVID.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:35:32 / cg"
!

setupData_vids_iv31
    "same as IV31"

    'setupData_vids_iv31' infoPrint.
    compression := 'IV31'.
    ^ self setupData_vids_IV31.

    "Created: 5.4.1997 / 15:29:54 / cg"
    "Modified: 5.4.1997 / 15:35:39 / cg"
!

setupData_vids_iv32
    "same as IV32"

    'setupData_vids_iv32' infoPrint.
    compression := 'IV32'.
    ^ self setupData_vids_IV32.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:35:45 / cg"
!

setupData_vids_jpeg
    "same as JPEG"

    'setupData_vids_jpeg' infoPrint.
    compression := 'JPEG'.
    ^ self setupData_vids_JPEG.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:35:53 / cg"
!

setupData_vids_none
    "same as NONE"

    'setupData_vids_none' infoPrint.
    compression := 'NONE'.
    ^ self setupData_vids_NONE.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:02 / cg"
!

setupData_vids_pack
    "same as PACK"

    'setupData_vids_pack' infoPrint.
    compression := 'PACK'.
    ^ self setupData_vids_PACK.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:08 / cg"
!

setupData_vids_rle4
    "same as RLE4"

    'setupData_vids_rle4' infoPrint.
    compression := 'RLE4'.
    ^ self setupData_vids_RLE4.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:14 / cg"
!

setupData_vids_rle8
    "same as RLE8"

    'setupData_vids_rle8' infoPrint.
    compression := 'RLE8'.
    ^ self setupData_vids_RLE8.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:21 / cg"
!

setupData_vids_rt21
    "same as RT21"

    'setupData_vids_rt21' infoPrint.
    compression := 'RT21'.
    ^ self setupData_vids_RT21.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:28 / cg"
!

setupData_vids_tran
    "same as TRAN"

    'setupData_vids_tran' infoPrint.
    compression := 'TRAN'.
    ^ self setupData_vids_TRAN.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:35 / cg"
!

setupData_vids_xmpg
    "same as XMPG"

    'setupData_vids_xmpg' infoPrint.
    compression := 'XMPG'.
    ^ self setupData_vids_XMPG.

    "Created: 5.4.1997 / 15:29:55 / cg"
    "Modified: 5.4.1997 / 15:36:43 / cg"
!

skipChunk
    "skip a chunk"

    |sz|

    'skipChunk' infoPrint.

    sz := chunkSize.
    (sz bitTest:1) ifTrue:[
        sz := sz + 1
    ].

    inStream skip:sz.

    "
     AVIReader fromFile:'/home2/pd_stuff/movies/avi/hangldm.avi'      
    "

    "Created: 5.4.1997 / 14:13:43 / cg"
    "Modified: 5.4.1997 / 14:34:07 / cg"
! !

!AVIReader class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libview2/AVIReader.st,v 1.1 1997-04-14 11:59:31 cg Exp $'
! !
AVIReader initialize!