avilib.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:33k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  *  Some utilities for writing and reading AVI files.
  3.  *  These are not intended to serve for a full blown
  4.  *  AVI handling software (this would be much too complex)
  5.  *  The only intention is to write out MJPEG encoded
  6.  *  AVIs with sound and to be able to read them back again.
  7.  *  These utilities should work with other types of codecs too, however.
  8.  *
  9.  *  Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
  10.  *
  11.  *  This program is free software; you can redistribute it and/or modify
  12.  *  it under the terms of the GNU General Public License as published by
  13.  *  the Free Software Foundation; either version 2 of the License, or
  14.  *  (at your option) any later version.
  15.  *
  16.  *  This program is distributed in the hope that it will be useful,
  17.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  *  GNU General Public License for more details.
  20.  *
  21.  *  You should have received a copy of the GNU General Public License
  22.  *  along with this program; if not, write to the Free Software
  23.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25. #include "systems.h"
  26. #include "avilib.h"
  27. /* The following variable indicates the kind of error */
  28. long AVI_errno = 0;
  29. /*******************************************************************
  30.  *                                                                 *
  31.  *    Utilities for writing an AVI File                            *
  32.  *                                                                 *
  33.  *******************************************************************/
  34. /* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below
  35.     the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */
  36. #define AVI_MAX_LEN 2000000000
  37. /* HEADERBYTES: The number of bytes to reserve for the header */
  38. #define HEADERBYTES 2048
  39. #define PAD_EVEN(x) ( ((x)+1) & ~1 )
  40. /* Copy n into dst as a 4 byte, little endian number.
  41.    Should also work on big endian machines */
  42. static void long2str(unsigned char *dst, int n)
  43. {
  44.    dst[0] = (n    )&0xff;
  45.    dst[1] = (n>> 8)&0xff;
  46.    dst[2] = (n>>16)&0xff;
  47.    dst[3] = (n>>24)&0xff;
  48. }
  49. /* Convert a string of 4 or 2 bytes to a number,
  50.    also working on big endian machines */
  51. static unsigned long str2ulong(unsigned char *str)
  52. {
  53.    return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
  54. }
  55. static unsigned long str2ushort(unsigned char *str)
  56. {
  57.    return ( str[0] | (str[1]<<8) );
  58. }
  59. /* Calculate audio sample size from number of bits and number of channels.
  60.    This may have to be adjusted for eg. 12 bits and stereo */
  61. static int avi_sampsize(avi_t *AVI)
  62. {
  63.    int s;
  64.    s = ((AVI->a_bits+7)/8)*AVI->a_chans;
  65.    if(s==0) s=1; /* avoid possible zero divisions */
  66.    return s;
  67. }
  68. /* Add a chunk (=tag and data) to the AVI file,
  69.    returns -1 on write error, 0 on success */
  70. static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, int length)
  71. {
  72.    unsigned char c[8];
  73.    /* Copy tag and length int c, so that we need only 1 write system call
  74.       for these two values */
  75.    memcpy(c,tag,4);
  76.    long2str(c+4,length);
  77.    /* Output tag, length and data, restore previous position
  78.       if the write fails */
  79.    length = PAD_EVEN(length);
  80.    if( write(AVI->fdes,c,8) != 8 ||
  81.        write(AVI->fdes,data,length) != length )
  82.    {
  83.       lseek(AVI->fdes,AVI->pos,SEEK_SET);
  84.       AVI_errno = AVI_ERR_WRITE;
  85.       return -1;
  86.    }
  87.    /* Update file position */
  88.    AVI->pos += 8 + length;
  89.    return 0;
  90. }
  91. static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, long pos, long len)
  92. {
  93.    void *ptr;
  94.    if(AVI->n_idx>=AVI->max_idx)
  95.    {
  96.       ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
  97.       if(ptr == 0)
  98.       {
  99.          AVI_errno = AVI_ERR_NO_MEM;
  100.          return -1;
  101.       }
  102.       AVI->max_idx += 4096;
  103.       AVI->idx = (unsigned char((*)[16]) ) ptr;
  104.    }
  105.    /* Add index entry */
  106.    memcpy(AVI->idx[AVI->n_idx],tag,4);
  107.    long2str(AVI->idx[AVI->n_idx]+ 4,flags);
  108.    long2str(AVI->idx[AVI->n_idx]+ 8,pos);
  109.    long2str(AVI->idx[AVI->n_idx]+12,len);
  110.    /* Update counter */
  111.    AVI->n_idx++;
  112.    return 0;
  113. }
  114. /*
  115.    AVI_open_output_file: Open an AVI File and write a bunch
  116.                          of zero bytes as space for the header.
  117.    returns a pointer to avi_t on success, a zero pointer on error
  118. */
  119. avi_t* AVI_open_output_file(char * filename)
  120. {
  121.    avi_t *AVI;
  122.    int i;
  123.    unsigned char AVI_header[HEADERBYTES];
  124.    /* Allocate the avi_t struct and zero it */
  125.    AVI = (avi_t *) malloc(sizeof(avi_t));
  126.    if(AVI==0)
  127.    {
  128.       AVI_errno = AVI_ERR_NO_MEM;
  129.       return 0;
  130.    }
  131.    memset((void *)AVI,0,sizeof(avi_t));
  132.    /* Since Linux needs a long time when deleting big files,
  133.       we do not truncate the file when we open it.
  134.       Instead it is truncated when the AVI file is closed */
  135.    AVI->fdes = open(filename,OPEN_RDWR|OPEN_CREAT,0600);
  136.    if (AVI->fdes < 0)
  137.    {
  138.       AVI_errno = AVI_ERR_OPEN;
  139.       free(AVI);
  140.       return 0;
  141.    }
  142.    /* Write out HEADERBYTES bytes, the header will go here
  143.       when we are finished with writing */
  144.    for (i=0;i<HEADERBYTES;i++) AVI_header[i] = 0;
  145.    i = write(AVI->fdes,AVI_header,HEADERBYTES);
  146.    if (i != HEADERBYTES)
  147.    {
  148.       close(AVI->fdes);
  149.       AVI_errno = AVI_ERR_WRITE;
  150.       free(AVI);
  151.       return 0;
  152.    }
  153.    AVI->pos  = HEADERBYTES;
  154.    AVI->mode = AVI_MODE_WRITE; /* open for writing */
  155.    return AVI;
  156. }
  157. void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor)
  158. {
  159.    /* may only be called if file is open for writing */
  160.    if(AVI->mode==AVI_MODE_READ) return;
  161.    AVI->width  = width;
  162.    AVI->height = height;
  163.    AVI->fps    = fps;
  164.    memcpy(AVI->compressor,compressor,4);
  165.    AVI->compressor[4] = 0;
  166. }
  167. void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format)
  168. {
  169.    /* may only be called if file is open for writing */
  170.    if(AVI->mode==AVI_MODE_READ) return;
  171.    AVI->a_chans = channels;
  172.    AVI->a_rate  = rate;
  173.    AVI->a_bits  = bits;
  174.    AVI->a_fmt   = format;
  175. }
  176. #define OUT4CC(s) 
  177.    if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
  178. #define OUTLONG(n) 
  179.    if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb,n); nhb += 4
  180. #define OUTSHRT(n) 
  181.    if(nhb<=HEADERBYTES-2) { 
  182.       AVI_header[nhb  ] = (n   )&0xff; 
  183.       AVI_header[nhb+1] = (n>>8)&0xff; 
  184.    } 
  185.    nhb += 2
  186. /*
  187.   Write the header of an AVI file and close it.
  188.   returns 0 on success, -1 on write error.
  189. */
  190. static int avi_close_output_file(avi_t *AVI)
  191. {
  192.    int ret, njunk, sampsize, hasIndex, ms_per_frame, idxerror, flag;
  193.    int movi_len, hdrl_start, strl_start;
  194.    unsigned char AVI_header[HEADERBYTES];
  195.    long nhb;
  196.    /* Calculate length of movi list */
  197.    movi_len = AVI->pos - HEADERBYTES + 4;
  198.    /* Try to ouput the index entries. This may fail e.g. if no space
  199.       is left on device. We will report this as an error, but we still
  200.       try to write the header correctly (so that the file still may be
  201.       readable in the most cases */
  202.    idxerror = 0;
  203.    ret = avi_add_chunk(AVI,"idx1",(void*)AVI->idx,AVI->n_idx*16);
  204.    hasIndex = (ret==0);
  205.    if(ret)
  206.    {
  207.       idxerror = 1;
  208.       AVI_errno = AVI_ERR_WRITE_INDEX;
  209.    }
  210.    /* Calculate Microseconds per frame */
  211.    if(AVI->fps < 0.001)
  212.       ms_per_frame = 0;
  213.    else
  214.       ms_per_frame = 1000000./AVI->fps + 0.5;
  215.    /* Prepare the file header */
  216.    nhb = 0;
  217.    /* The RIFF header */
  218.    OUT4CC ("RIFF");
  219.    OUTLONG(AVI->pos - 8);    /* # of bytes to follow */
  220.    OUT4CC ("AVI ");
  221.    /* Start the header list */
  222.    OUT4CC ("LIST");
  223.    OUTLONG(0);        /* Length of list in bytes, don't know yet */
  224.    hdrl_start = nhb;  /* Store start position */
  225.    OUT4CC ("hdrl");
  226.    /* The main AVI header */
  227.    /* The Flags in AVI File header */
  228. #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
  229. #define AVIF_MUSTUSEINDEX       0x00000020
  230. #define AVIF_ISINTERLEAVED      0x00000100
  231. #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
  232. #define AVIF_WASCAPTUREFILE     0x00010000
  233. #define AVIF_COPYRIGHTED        0x00020000
  234.    OUT4CC ("avih");
  235.    OUTLONG(56);                 /* # of bytes to follow */
  236.    OUTLONG(ms_per_frame);       /* Microseconds per frame */
  237.    OUTLONG(10000000);           /* MaxBytesPerSec, I hope this will never be used */
  238.    OUTLONG(0);                  /* PaddingGranularity (whatever that might be) */
  239.                                 /* Other sources call it 'reserved' */
  240.    flag = AVIF_WASCAPTUREFILE;
  241.    if(hasIndex) flag |= AVIF_HASINDEX;
  242.    if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
  243.    OUTLONG(flag);               /* Flags */
  244.    OUTLONG(AVI->video_frames);  /* TotalFrames */
  245.    OUTLONG(0);                  /* InitialFrames */
  246.    if (AVI->audio_bytes)
  247.       { OUTLONG(2); }           /* Streams */
  248.    else
  249.       { OUTLONG(1); }           /* Streams */
  250.    OUTLONG(0);                  /* SuggestedBufferSize */
  251.    OUTLONG(AVI->width);         /* Width */
  252.    OUTLONG(AVI->height);        /* Height */
  253.                                 /* MS calls the following 'reserved': */
  254.    OUTLONG(0);                  /* TimeScale:  Unit used to measure time */
  255.    OUTLONG(0);                  /* DataRate:   Data rate of playback     */
  256.    OUTLONG(0);                  /* StartTime:  Starting time of AVI data */
  257.    OUTLONG(0);                  /* DataLength: Size of AVI data chunk    */
  258.    /* Start the video stream list ---------------------------------- */
  259.    OUT4CC ("LIST");
  260.    OUTLONG(0);        /* Length of list in bytes, don't know yet */
  261.    strl_start = nhb;  /* Store start position */
  262.    OUT4CC ("strl");
  263.    /* The video stream header */
  264.    OUT4CC ("strh");
  265.    OUTLONG(64);                 /* # of bytes to follow */
  266.    OUT4CC ("vids");             /* Type */
  267.    OUT4CC (AVI->compressor);    /* Handler */
  268.    OUTLONG(0);                  /* Flags */
  269.    OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
  270.    OUTLONG(0);                  /* InitialFrames */
  271.    OUTLONG(ms_per_frame);       /* Scale */
  272.    OUTLONG(1000000);            /* Rate: Rate/Scale == samples/second */
  273.    OUTLONG(0);                  /* Start */
  274.    OUTLONG(AVI->video_frames);  /* Length */
  275.    OUTLONG(0);                  /* SuggestedBufferSize */
  276.    OUTLONG(-1);                 /* Quality */
  277.    OUTLONG(0);                  /* SampleSize */
  278.    OUTLONG(0);                  /* Frame */
  279.    OUTLONG(0);                  /* Frame */
  280.    OUTLONG(0);                  /* Frame */
  281.    OUTLONG(0);                  /* Frame */
  282.    /* The video stream format */
  283.    OUT4CC ("strf");
  284.    OUTLONG(40);                 /* # of bytes to follow */
  285.    OUTLONG(40);                 /* Size */
  286.    OUTLONG(AVI->width);         /* Width */
  287.    OUTLONG(AVI->height);        /* Height */
  288.    OUTSHRT(1); OUTSHRT(24);     /* Planes, Count */
  289.    OUT4CC (AVI->compressor);    /* Compression */
  290.    OUTLONG(AVI->width*AVI->height);  /* SizeImage (in bytes?) */
  291.    OUTLONG(0);                  /* XPelsPerMeter */
  292.    OUTLONG(0);                  /* YPelsPerMeter */
  293.    OUTLONG(0);                  /* ClrUsed: Number of colors used */
  294.    OUTLONG(0);                  /* ClrImportant: Number of colors important */
  295.    /* Finish stream list, i.e. put number of bytes in the list to proper pos */
  296.    long2str(AVI_header+strl_start-4,nhb-strl_start);
  297.    if (AVI->a_chans && AVI->audio_bytes)
  298.    {
  299.    sampsize = avi_sampsize(AVI);
  300.    /* Start the audio stream list ---------------------------------- */
  301.    OUT4CC ("LIST");
  302.    OUTLONG(0);        /* Length of list in bytes, don't know yet */
  303.    strl_start = nhb;  /* Store start position */
  304.    OUT4CC ("strl");
  305.    /* The audio stream header */
  306.    OUT4CC ("strh");
  307.    OUTLONG(64);            /* # of bytes to follow */
  308.    OUT4CC ("auds");
  309.    OUT4CC ("");
  310.    OUTLONG(0);             /* Flags */
  311.    OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
  312.    OUTLONG(0);             /* InitialFrames */
  313.    OUTLONG(sampsize);      /* Scale */
  314.    OUTLONG(sampsize*AVI->a_rate); /* Rate: Rate/Scale == samples/second */
  315.    OUTLONG(0);             /* Start */
  316.    OUTLONG(AVI->audio_bytes/sampsize);   /* Length */
  317.    OUTLONG(0);             /* SuggestedBufferSize */
  318.    OUTLONG(-1);            /* Quality */
  319.    OUTLONG(sampsize);      /* SampleSize */
  320.    OUTLONG(0);             /* Frame */
  321.    OUTLONG(0);             /* Frame */
  322.    OUTLONG(0);             /* Frame */
  323.    OUTLONG(0);             /* Frame */
  324.    /* The audio stream format */
  325.    OUT4CC ("strf");
  326.    OUTLONG(16);                   /* # of bytes to follow */
  327.    OUTSHRT(AVI->a_fmt);           /* Format */
  328.    OUTSHRT(AVI->a_chans);         /* Number of channels */
  329.    OUTLONG(AVI->a_rate);          /* SamplesPerSec */
  330.    OUTLONG(sampsize*AVI->a_rate); /* AvgBytesPerSec */
  331.    OUTSHRT(sampsize);             /* BlockAlign */
  332.    OUTSHRT(AVI->a_bits);          /* BitsPerSample */
  333.    /* Finish stream list, i.e. put number of bytes in the list to proper pos */
  334.    long2str(AVI_header+strl_start-4,nhb-strl_start);
  335.    }
  336.    /* Finish header list */
  337.    long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
  338.    /* Calculate the needed amount of junk bytes, output junk */
  339.    njunk = HEADERBYTES - nhb - 8 - 12;
  340.    /* Safety first: if njunk <= 0, somebody has played with
  341.       HEADERBYTES without knowing what (s)he did.
  342.       This is a fatal error */
  343.    if(njunk<=0)
  344.    {
  345.       fprintf(stderr,"AVI_close_output_file: # of header bytes too smalln");
  346.       exit(1);
  347.    }
  348.    OUT4CC ("JUNK");
  349.    OUTLONG(njunk);
  350.    memset(AVI_header+nhb,0,njunk);
  351.    nhb += njunk;
  352.    /* Start the movi list */
  353.    OUT4CC ("LIST");
  354.    OUTLONG(movi_len); /* Length of list in bytes */
  355.    OUT4CC ("movi");
  356.    /* Output the header, truncate the file to the number of bytes
  357.       actually written, report an error if someting goes wrong */
  358.    if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
  359.         write(AVI->fdes,AVI_header,HEADERBYTES)!=HEADERBYTES ||
  360. #ifndef _WINDOWS
  361.         ftruncate(AVI->fdes,AVI->pos)<0
  362. #else
  363. _chsize(AVI->fdes,AVI->pos)<0 
  364. #endif
  365. )
  366.    {
  367.       AVI_errno = AVI_ERR_CLOSE;
  368.       return -1;
  369.    }
  370.    if(idxerror) return -1;
  371.    return 0;
  372. }
  373. /*
  374.    AVI_write_data:
  375.    Add video or audio data to the file;
  376.    Return values:
  377.     0    No error;
  378.    -1    Error, AVI_errno is set appropriatly;
  379. */
  380. static int avi_write_data(avi_t *AVI, char *data, long length, int audio)
  381. {
  382.    int n;
  383.    /* Check for maximum file length */
  384.    if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN )
  385.    {
  386.       AVI_errno = AVI_ERR_SIZELIM;
  387.       return -1;
  388.    }
  389.    /* Add index entry */
  390.    if(audio)
  391.       n = avi_add_index_entry(AVI,"01wb",0x00,AVI->pos,length);
  392.    else
  393.       n = avi_add_index_entry(AVI,"00db",0x10,AVI->pos,length);
  394.    if(n) return -1;
  395.    /* Output tag and data */
  396.    if(audio)
  397.       n = avi_add_chunk(AVI,"01wb",data,length);
  398.    else
  399.       n = avi_add_chunk(AVI,"00db",data,length);
  400.    if (n) return -1;
  401.    return 0;
  402. }
  403. int AVI_write_frame(avi_t *AVI, char *data, long bytes)
  404. {
  405.    long pos;
  406.    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  407.    pos = AVI->pos;
  408.    if( avi_write_data(AVI,data,bytes,0) ) return -1;
  409.    AVI->last_pos = pos;
  410.    AVI->last_len = bytes;
  411.    AVI->video_frames++;
  412.    return 0;
  413. }
  414. int AVI_dup_frame(avi_t *AVI)
  415. {
  416.    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  417.    if(AVI->last_pos==0) return 0; /* No previous real frame */
  418.    if(avi_add_index_entry(AVI,"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
  419.    AVI->video_frames++;
  420.    AVI->must_use_index = 1;
  421.    return 0;
  422. }
  423. int AVI_write_audio(avi_t *AVI, char *data, long bytes)
  424. {
  425.    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  426.    if( avi_write_data(AVI,data,bytes,1) ) return -1;
  427.    AVI->audio_bytes += bytes;
  428.    return 0;
  429. }
  430. long AVI_bytes_remain(avi_t *AVI)
  431. {
  432.    if(AVI->mode==AVI_MODE_READ) return 0;
  433.    return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx));
  434. }
  435. /*******************************************************************
  436.  *                                                                 *
  437.  *    Utilities for reading video and audio from an AVI File       *
  438.  *                                                                 *
  439.  *******************************************************************/
  440. int AVI_close(avi_t *AVI)
  441. {
  442.    int ret;
  443.    /* If the file was open for writing, the header and index still have
  444.       to be written */
  445.    if(AVI->mode == AVI_MODE_WRITE)
  446.       ret = avi_close_output_file(AVI);
  447.    else
  448.       ret = 0;
  449.    /* Even if there happened a error, we first clean up */
  450.    close(AVI->fdes);
  451.    if(AVI->idx) free(AVI->idx);
  452.    if(AVI->video_index) free(AVI->video_index);
  453.    if(AVI->audio_index) free(AVI->audio_index);
  454.    free(AVI);
  455.    return ret;
  456. }
  457. #define ERR_EXIT(x) 
  458.    AVI_close(AVI); 
  459.    AVI_errno = x; 
  460.    return 0; 
  461. }
  462. avi_t *AVI_open_input_file(const char *filename, int getIndex)
  463. {
  464.    avi_t *AVI;
  465.    long i, n, rate, scale, idx_type;
  466.    unsigned char *hdrl_data;
  467.    long hdrl_len;
  468.    long nvi, nai, ioff;
  469.    long tot;
  470.    int lasttag = 0;
  471.    int vids_strh_seen = 0;
  472.    int vids_strf_seen = 0;
  473.    int auds_strh_seen = 0;
  474.    int auds_strf_seen = 0;
  475.    int num_stream = 0;
  476.    char data[256];
  477.    /* Create avi_t structure */
  478.    AVI = (avi_t *) malloc(sizeof(avi_t));
  479.    if(AVI==NULL)
  480.    {
  481.       AVI_errno = AVI_ERR_NO_MEM;
  482.       return 0;
  483.    }
  484.    memset((void *)AVI,0,sizeof(avi_t));
  485.    AVI->mode = AVI_MODE_READ; /* open for reading */
  486.    /* Open the file */
  487.    AVI->fdes = open(filename,OPEN_RDONLY);
  488.    if(AVI->fdes < 0)
  489.    {
  490.       AVI_errno = AVI_ERR_OPEN;
  491.       free(AVI);
  492.       return 0;
  493.    }
  494.    /* Read first 12 bytes and check that this is an AVI file */
  495.    if( read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ)
  496.    if( strncasecmp(data  ,"RIFF",4) !=0 ||
  497.        strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
  498.    /* Go through the AVI file and extract the header list,
  499.       the start position of the 'movi' list and an optionally
  500.       present idx1 tag */
  501.    hdrl_data = 0;
  502.    while(1)
  503.    {
  504.       if( read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */
  505.       n = str2ulong(data+4);
  506.       n = PAD_EVEN(n);
  507.       if(strncasecmp(data,"LIST",4) == 0)
  508.       {
  509.          if( read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
  510.          n -= 4;
  511.          if(strncasecmp(data,"hdrl",4) == 0)
  512.          {
  513.             hdrl_len = n;
  514.             hdrl_data = (unsigned char *) malloc(n);
  515.             if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM)
  516.             if( read(AVI->fdes,hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ)
  517.          }
  518.          else if(strncasecmp(data,"movi",4) == 0)
  519.          {
  520.             AVI->movi_start = lseek(AVI->fdes,0,SEEK_CUR);
  521.             lseek(AVI->fdes,n,SEEK_CUR);
  522.          }
  523.          else
  524.             lseek(AVI->fdes,n,SEEK_CUR);
  525.       }
  526.       else if(strncasecmp(data,"idx1",4) == 0)
  527.       {
  528.          /* n must be a multiple of 16, but the reading does not
  529.             break if this is not the case */
  530.          AVI->n_idx = AVI->max_idx = n/16;
  531.          AVI->idx = (unsigned  char((*)[16]) ) malloc(n);
  532.          if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
  533.          if( read(AVI->fdes,AVI->idx,n) != n ) ERR_EXIT(AVI_ERR_READ)
  534.       }
  535.       else
  536.          lseek(AVI->fdes,n,SEEK_CUR);
  537.    }
  538.    if(!hdrl_data      ) ERR_EXIT(AVI_ERR_NO_HDRL)
  539.    if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
  540.    /* Interpret the header list */
  541.    for(i=0;i<hdrl_len;)
  542.    {
  543.       /* List tags are completly ignored */
  544.       if(strncasecmp(hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
  545.       n = str2ulong(hdrl_data+i+4);
  546.       n = PAD_EVEN(n);
  547.       /* Interpret the tag and its args */
  548.       if(strncasecmp(hdrl_data+i,"strh",4)==0)
  549.       {
  550.          i += 8;
  551.          if(strncasecmp(hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
  552.          {
  553.             memcpy(AVI->compressor,hdrl_data+i+4,4);
  554.             AVI->compressor[4] = 0;
  555.             scale = str2ulong(hdrl_data+i+20);
  556.             rate  = str2ulong(hdrl_data+i+24);
  557.             if(scale!=0) AVI->fps = (double)rate/(double)scale;
  558.             AVI->video_frames = str2ulong(hdrl_data+i+32);
  559.             AVI->video_strn = num_stream;
  560.             vids_strh_seen = 1;
  561.             lasttag = 1; /* vids */
  562.          }
  563.          else if (strncasecmp (hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
  564.          {
  565.             AVI->audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI);
  566.             AVI->audio_strn = num_stream;
  567.             auds_strh_seen = 1;
  568.             lasttag = 2; /* auds */
  569.          }
  570.          else
  571.             lasttag = 0;
  572.          num_stream++;
  573.       }
  574.       else if(strncasecmp(hdrl_data+i,"strf",4)==0)
  575.       {
  576.          i += 8;
  577.          if(lasttag == 1)
  578.          {
  579.             AVI->width  = str2ulong(hdrl_data+i+4);
  580.             AVI->height = str2ulong(hdrl_data+i+8);
  581.             vids_strf_seen = 1;
  582.          }
  583.          else if(lasttag == 2)
  584.          {
  585.             AVI->a_fmt   = str2ushort(hdrl_data+i  );
  586.             AVI->a_chans = str2ushort(hdrl_data+i+2);
  587.             AVI->a_rate  = str2ulong (hdrl_data+i+4);
  588.             AVI->a_bits  = str2ushort(hdrl_data+i+14);
  589.             auds_strf_seen = 1;
  590.          }
  591.          lasttag = 0;
  592.       }
  593.       else
  594.       {
  595.          i += 8;
  596.          lasttag = 0;
  597.       }
  598.       i += n;
  599.    }
  600.    free(hdrl_data);
  601.    if(!vids_strh_seen || !vids_strf_seen || AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS)
  602.    AVI->video_tag[0] = AVI->video_strn/10 + '0';
  603.    AVI->video_tag[1] = AVI->video_strn%10 + '0';
  604.    AVI->video_tag[2] = 'd';
  605.    AVI->video_tag[3] = 'b';
  606.    /* Audio tag is set to "99wb" if no audio present */
  607.    if(!AVI->a_chans) AVI->audio_strn = 99;
  608.    AVI->audio_tag[0] = AVI->audio_strn/10 + '0';
  609.    AVI->audio_tag[1] = AVI->audio_strn%10 + '0';
  610.    AVI->audio_tag[2] = 'w';
  611.    AVI->audio_tag[3] = 'b';
  612.    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
  613.    /* get index if wanted */
  614.    if(!getIndex) return AVI;
  615.    /* if the file has an idx1, check if this is relative
  616.       to the start of the file or to the start of the movi list */
  617.    idx_type = 0;
  618.    if(AVI->idx)
  619.    {
  620.       long pos;
  621. unsigned long len;
  622.       /* Search the first videoframe in the idx1 and look where
  623.          it is in the file */
  624.       for(i=0;i<AVI->n_idx;i++)
  625.          if( strncasecmp(AVI->idx[i],AVI->video_tag,3)==0 ) break;
  626.       if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
  627.       pos = str2ulong(AVI->idx[i]+ 8);
  628.       len = str2ulong(AVI->idx[i]+12);
  629.       lseek(AVI->fdes,pos,SEEK_SET);
  630.       if(read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
  631.       if( strncasecmp(data,AVI->idx[i],4)==0 && str2ulong(data+4)==len )
  632.       {
  633.          idx_type = 1; /* Index from start of file */
  634.       }
  635.       else
  636.       {
  637.          lseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
  638.          if(read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
  639.          if( strncasecmp(data,AVI->idx[i],4)==0 && str2ulong(data+4)==len )
  640.          {
  641.             idx_type = 2; /* Index from start of movi list */
  642.          }
  643.       }
  644.       /* idx_type remains 0 if neither of the two tests above succeeds */
  645.    }
  646.    if(idx_type == 0)
  647.    {
  648.       /* we must search through the file to get the index */
  649.       lseek(AVI->fdes, AVI->movi_start, SEEK_SET);
  650.       AVI->n_idx = 0;
  651.       while(1)
  652.       {
  653.          if( read(AVI->fdes,data,8) != 8 ) break;
  654.          n = str2ulong(data+4);
  655.          /* The movi list may contain sub-lists, ignore them */
  656.          if(strncasecmp(data,"LIST",4)==0)
  657.          {
  658.             lseek(AVI->fdes,4,SEEK_CUR);
  659.             continue;
  660.          }
  661.          /* Check if we got a tag ##db, ##dc or ##wb */
  662.          if( ( (data[2]=='d' || data[2]=='D') &&
  663.                (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
  664.           || ( (data[2]=='w' || data[2]=='W') &&
  665.                (data[3]=='b' || data[3]=='B') ) )
  666.          {
  667.             avi_add_index_entry(AVI,data,0,lseek(AVI->fdes,0,SEEK_CUR)-8,n);
  668.          }
  669.          lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
  670.       }
  671.       idx_type = 1;
  672.    }
  673.    /* Now generate the video index and audio index arrays */
  674.    nvi = 0;
  675.    nai = 0;
  676.    for(i=0;i<AVI->n_idx;i++)
  677.    {
  678.       if(strncasecmp(AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
  679.       if(strncasecmp(AVI->idx[i],AVI->audio_tag,4) == 0) nai++;
  680.    }
  681.    AVI->video_frames = nvi;
  682.    AVI->audio_chunks = nai;
  683.    if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS)
  684.    AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
  685.    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM)
  686.    if(AVI->audio_chunks)
  687.    {
  688.       AVI->audio_index = (audio_index_entry *) malloc(nai*sizeof(audio_index_entry));
  689.       if(AVI->audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM)
  690.    }
  691.    nvi = 0;
  692.    nai = 0;
  693.    tot = 0;
  694.    ioff = idx_type == 1 ? 8 : AVI->movi_start+4;
  695.    for(i=0;i<AVI->n_idx;i++)
  696.    {
  697.       if(strncasecmp(AVI->idx[i],AVI->video_tag,3) == 0)
  698.       {
  699.          AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
  700.          AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
  701.          nvi++;
  702.       }
  703.       if(strncasecmp(AVI->idx[i],AVI->audio_tag,4) == 0)
  704.       {
  705.          AVI->audio_index[nai].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
  706.          AVI->audio_index[nai].len = str2ulong(AVI->idx[i]+12);
  707.          AVI->audio_index[nai].tot = tot;
  708.          tot += AVI->audio_index[nai].len;
  709.          nai++;
  710.       }
  711.    }
  712.    AVI->audio_bytes = tot;
  713.    /* Reposition the file */
  714.    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
  715.    AVI->video_pos = 0;
  716.    return AVI;
  717. }
  718. long AVI_video_frames(avi_t *AVI)
  719. {
  720.    return AVI->video_frames;
  721. }
  722. int  AVI_video_width(avi_t *AVI)
  723. {
  724.    return AVI->width;
  725. }
  726. int  AVI_video_height(avi_t *AVI)
  727. {
  728.    return AVI->height;
  729. }
  730. double AVI_video_frame_rate(avi_t *AVI)
  731. {
  732.    return AVI->fps;
  733. }
  734. char* AVI_video_compressor(avi_t *AVI)
  735. {
  736.    return AVI->compressor;
  737. }
  738. int AVI_audio_channels(avi_t *AVI)
  739. {
  740.    return AVI->a_chans;
  741. }
  742. int AVI_audio_bits(avi_t *AVI)
  743. {
  744.    return AVI->a_bits;
  745. }
  746. int AVI_audio_format(avi_t *AVI)
  747. {
  748.    return AVI->a_fmt;
  749. }
  750. long AVI_audio_rate(avi_t *AVI)
  751. {
  752.    return AVI->a_rate;
  753. }
  754. long AVI_audio_bytes(avi_t *AVI)
  755. {
  756.    return AVI->audio_bytes;
  757. }
  758. long AVI_frame_size(avi_t *AVI, long frame)
  759. {
  760.    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  761.    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
  762.    if(frame < 0 || frame >= AVI->video_frames) return 0;
  763.    return(AVI->video_index[frame].len);
  764. }
  765. int AVI_seek_start(avi_t *AVI)
  766. {
  767.    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  768.    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
  769.    AVI->video_pos = 0;
  770.    AVI->audio_posc = 0;
  771.    AVI->audio_posb = 0;
  772.    return 0;
  773. }
  774. int AVI_set_video_position(avi_t *AVI, long frame, long *frame_len)
  775. {
  776.    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  777.    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
  778.    if (frame < 0 ) frame = 0;
  779.    AVI->video_pos = frame;
  780.    if (frame_len != NULL)
  781.      *frame_len = AVI->video_index[frame].len;
  782.    return 0;
  783. }
  784.       
  785. long AVI_read_frame(avi_t *AVI, char *vidbuf)
  786. {
  787.    long n;
  788.    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  789.    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
  790.    if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return 0;
  791.    n = AVI->video_index[AVI->video_pos].len;
  792.    lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
  793.    if (read(AVI->fdes,vidbuf,n) != n)
  794.    {
  795.       AVI_errno = AVI_ERR_READ;
  796.       return -1;
  797.    }
  798.    AVI->video_pos++;
  799.    return n;
  800. }
  801. int AVI_set_audio_position(avi_t *AVI, long byte)
  802. {
  803.    long n0, n1, n;
  804.    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  805.    if(!AVI->audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
  806.    if(byte < 0) byte = 0;
  807.    /* Binary search in the audio chunks */
  808.    n0 = 0;
  809.    n1 = AVI->audio_chunks;
  810.    while(n0<n1-1)
  811.    {
  812.       n = (n0+n1)/2;
  813.       if(AVI->audio_index[n].tot>byte)
  814.          n1 = n;
  815.       else
  816.          n0 = n;
  817.    }
  818.    AVI->audio_posc = n0;
  819.    AVI->audio_posb = byte - AVI->audio_index[n0].tot;
  820.    return 0;
  821. }
  822. int AVI_set_audio_frame (avi_t *AVI, long frame, long *frame_len)
  823. {
  824.   if (AVI->audio_posc >= AVI->audio_chunks - 1) { return -1; }
  825.   AVI->audio_posc = frame;
  826.   AVI->audio_posb = 0;
  827.   if (frame_len != NULL)
  828.     *frame_len = AVI->audio_index[frame].len;
  829.   return 0;
  830. }
  831. long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes)
  832. {
  833.    long nr, pos, left, todo;
  834.    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
  835.    if(!AVI->audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
  836.    nr = 0; /* total number of bytes read */
  837.    while(bytes>0)
  838.    {
  839.       left = AVI->audio_index[AVI->audio_posc].len - AVI->audio_posb;
  840.       if(left==0)
  841.       {
  842.          if(AVI->audio_posc>=AVI->audio_chunks-1) return nr;
  843.          AVI->audio_posc++;
  844.          AVI->audio_posb = 0;
  845.          continue;
  846.       }
  847.       if(bytes<left)
  848.          todo = bytes;
  849.       else
  850.          todo = left;
  851.       pos = AVI->audio_index[AVI->audio_posc].pos + AVI->audio_posb;
  852.       lseek(AVI->fdes, pos, SEEK_SET);
  853.       if (read(AVI->fdes,audbuf+nr,todo) != todo)
  854.       {
  855.          AVI_errno = AVI_ERR_READ;
  856.          return -1;
  857.       }
  858.       bytes -= todo;
  859.       nr    += todo;
  860.       AVI->audio_posb += todo;
  861.    }
  862.    return nr;
  863. }
  864. /* AVI_read_data: Special routine for reading the next audio or video chunk
  865.                   without having an index of the file. */
  866. int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf,
  867.                               char *audbuf, long max_audbuf,
  868.                               long *len)
  869. {
  870. /*
  871.  * Return codes:
  872.  *
  873.  *    1 = video data read
  874.  *    2 = audio data read
  875.  *    0 = reached EOF
  876.  *   -1 = video buffer too small
  877.  *   -2 = audio buffer too small
  878.  */
  879.    int n;
  880.    char data[8];
  881.    if(AVI->mode==AVI_MODE_WRITE) return 0;
  882.    while(1)
  883.    {
  884.       /* Read tag and length */
  885.       if( read(AVI->fdes,data,8) != 8 ) return 0;
  886.       /* if we got a list tag, ignore it */
  887.       if(strncasecmp(data,"LIST",4) == 0)
  888.       {
  889.          lseek(AVI->fdes,4,SEEK_CUR);
  890.          continue;
  891.       }
  892.       n = PAD_EVEN(str2ulong(data+4));
  893.       if(strncasecmp(data,AVI->video_tag,3) == 0)
  894.       {
  895.          *len = n;
  896.          AVI->video_pos++;
  897.          if(n>max_vidbuf)
  898.          {
  899.             lseek(AVI->fdes,n,SEEK_CUR);
  900.             return -1;
  901.          }
  902.          if(read(AVI->fdes,vidbuf,n) != n ) return 0;
  903.          return 1;
  904.       }
  905.       else if(strncasecmp(data,AVI->audio_tag,4) == 0)
  906.       {
  907.          *len = n;
  908.          if(n>max_audbuf)
  909.          {
  910.             lseek(AVI->fdes,n,SEEK_CUR);
  911.             return -2;
  912.          }
  913.          if(read(AVI->fdes,audbuf,n) != n ) return 0;
  914.          return 2;
  915.          break;
  916.       }
  917.       else
  918.          if(lseek(AVI->fdes,n,SEEK_CUR)<0)  return 0;
  919.    }
  920. }
  921. /* AVI_print_error: Print most recent error (similar to perror) */
  922. char *(avi_errors[]) =
  923. {
  924.   /*  0 */ "avilib - No Error",
  925.   /*  1 */ "avilib - AVI file size limit reached",
  926.   /*  2 */ "avilib - Error opening AVI file",
  927.   /*  3 */ "avilib - Error reading from AVI file",
  928.   /*  4 */ "avilib - Error writing to AVI file",
  929.   /*  5 */ "avilib - Error writing index (file may still be useable)",
  930.   /*  6 */ "avilib - Error closing AVI file",
  931.   /*  7 */ "avilib - Operation (read/write) not permitted",
  932.   /*  8 */ "avilib - Out of memory (malloc failed)",
  933.   /*  9 */ "avilib - Not an AVI file",
  934.   /* 10 */ "avilib - AVI file has no header list (corrupted?)",
  935.   /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)",
  936.   /* 12 */ "avilib - AVI file has no video data",
  937.   /* 13 */ "avilib - operation needs an index",
  938.   /* 14 */ "avilib - Unkown Error"
  939. };
  940. static int num_avi_errors = sizeof(avi_errors)/sizeof(char*);
  941. static char error_string[4096];
  942. void AVI_print_error(char *str)
  943. {
  944.    int aerrno;
  945.    aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
  946.    fprintf(stderr,"%s: %sn",str,avi_errors[aerrno]);
  947.    /* for the following errors, perror should report a more detailed reason: */
  948.    if(AVI_errno == AVI_ERR_OPEN ||
  949.       AVI_errno == AVI_ERR_READ ||
  950.       AVI_errno == AVI_ERR_WRITE ||
  951.       AVI_errno == AVI_ERR_WRITE_INDEX ||
  952.       AVI_errno == AVI_ERR_CLOSE )
  953.    {
  954.       perror("REASON");
  955.    }
  956. }
  957. char *AVI_strerror()
  958. {
  959.    int aerrno;
  960.    aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
  961.    if(AVI_errno == AVI_ERR_OPEN ||
  962.       AVI_errno == AVI_ERR_READ ||
  963.       AVI_errno == AVI_ERR_WRITE ||
  964.       AVI_errno == AVI_ERR_WRITE_INDEX ||
  965.       AVI_errno == AVI_ERR_CLOSE )
  966.    {
  967.       sprintf(error_string,"%s - %s",avi_errors[aerrno],
  968. #ifndef _WINDOWS
  969. strerror(errno)
  970. #else
  971. _strerror(NULL)
  972. #endif
  973. );
  974.       return error_string;
  975.    }
  976.    else
  977.    {
  978.       return avi_errors[aerrno];
  979.    }
  980. }