func: static int wsvqa_read_header(AVFormatContext *s,
  
                               AVFormatParameters *ap)
  
  {
  
      WsVqaDemuxContext *wsvqa = s->priv_data;
  
      AVIOContext *pb = s->pb;
  
      AVStream *st;
  
      unsigned char *header;
  
      unsigned char scratch[VQA_PREAMBLE_SIZE];
  
      unsigned int chunk_tag;
  
      unsigned int chunk_size;
  
  
  
      /* initialize the video decoder stream */
  
      st = av_new_stream(s, 0);
  
      if (!st)
  
          return AVERROR(ENOMEM);
  
      av_set_pts_info(st, 33, 1, VQA_FRAMERATE);
  
      wsvqa->video_stream_index = st->index;
  
      st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  
      st->codec->codec_id = CODEC_ID_WS_VQA;
  
      st->codec->codec_tag = 0;  /* no fourcc */
  
  
  
      /* skip to the start of the VQA header */
  
      avio_seek(pb, 20, SEEK_SET);
  
  
  
      /* the VQA header needs to go to the decoder */
  
      st->codec->extradata_size = VQA_HEADER_SIZE;
  
      st->codec->extradata = av_mallocz(VQA_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
  
      header = (unsigned char *)st->codec->extradata;
  
      if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) !=
  
          VQA_HEADER_SIZE) {
  
          av_free(st->codec->extradata);
  
          return AVERROR(EIO);
  
      }
  
      st->codec->width = AV_RL16(&header[6]);
  
      st->codec->height = AV_RL16(&header[8]);
  
  
  
      /* initialize the audio decoder stream for VQA v1 or nonzero samplerate */
  
      if (AV_RL16(&header[24]) || (AV_RL16(&header[0]) == 1 && AV_RL16(&header[2]) == 1)) {
  
          st = av_new_stream(s, 0);
  
          if (!st)
  
              return AVERROR(ENOMEM);
  
          av_set_pts_info(st, 33, 1, VQA_FRAMERATE);
  
          st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
  
          if (AV_RL16(&header[0]) == 1)
  
              st->codec->codec_id = CODEC_ID_WESTWOOD_SND1;
  
          else
  
              st->codec->codec_id = CODEC_ID_ADPCM_IMA_WS;
  
          st->codec->codec_tag = 0;  /* no tag */
  
          st->codec->sample_rate = AV_RL16(&header[24]);
  
          if (!st->codec->sample_rate)
  
              st->codec->sample_rate = 22050;
  
          st->codec->channels = header[26];
  
          if (!st->codec->channels)
  
              st->codec->channels = 1;
  
          st->codec->bits_per_coded_sample = 16;
  
          st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
  
              st->codec->bits_per_coded_sample / 4;
  
          st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
  
  
  
          wsvqa->audio_stream_index = st->index;
  
          wsvqa->audio_samplerate = st->codec->sample_rate;
  
          wsvqa->audio_channels = st->codec->channels;
  
          wsvqa->audio_frame_counter = 0;
  
      }
  
  
  
      /* there are 0 or more chunks before the FINF chunk; iterate until
  
       * FINF has been skipped and the file will be ready to be demuxed */
  
      do {
  
          if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE) {
  
              av_free(st->codec->extradata);
  
              return AVERROR(EIO);
  
          }
  
          chunk_tag = AV_RB32(&scratch[0]);
  
          chunk_size = AV_RB32(&scratch[4]);
  
  
  
          /* catch any unknown header tags, for curiousity */
  
          switch (chunk_tag) {
  
          case CINF_TAG:
  
          case CINH_TAG:
  
          case CIND_TAG:
  
          case PINF_TAG:
  
          case PINH_TAG:
  
          case PIND_TAG:
  
          case FINF_TAG:
  
          case CMDS_TAG:
  
              break;
  
  
  
          default:
  
              av_log (s, AV_LOG_ERROR, " note: unknown chunk seen (%c%c%c%c)\n",
  
                  scratch[0], scratch[1],
  
                  scratch[2], scratch[3]);
  
              break;
  
          }
  
  
  
          avio_skip(pb, chunk_size);
  
      } while (chunk_tag != FINF_TAG);
  
  
  
      return 0;
  
  }
  