LCOV - code coverage report
Current view: top level - libavformat - westwood_vqa.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 101 122 82.8 %
Date: 2017-12-11 04:34:20 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Westwood Studios VQA Format Demuxer
       3             :  * Copyright (c) 2003 The FFmpeg project
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : /**
      23             :  * @file
      24             :  * Westwood Studios VQA file demuxer
      25             :  * by Mike Melanson (melanson@pcisys.net)
      26             :  * for more information on the Westwood file formats, visit:
      27             :  *   http://www.pcisys.net/~melanson/codecs/
      28             :  *   http://www.geocities.com/SiliconValley/8682/aud3.txt
      29             :  */
      30             : 
      31             : #include "libavutil/intreadwrite.h"
      32             : #include "avformat.h"
      33             : #include "internal.h"
      34             : 
      35             : #define FORM_TAG MKBETAG('F', 'O', 'R', 'M')
      36             : #define WVQA_TAG MKBETAG('W', 'V', 'Q', 'A')
      37             : #define VQHD_TAG MKBETAG('V', 'Q', 'H', 'D')
      38             : #define FINF_TAG MKBETAG('F', 'I', 'N', 'F')
      39             : #define SND0_TAG MKBETAG('S', 'N', 'D', '0')
      40             : #define SND1_TAG MKBETAG('S', 'N', 'D', '1')
      41             : #define SND2_TAG MKBETAG('S', 'N', 'D', '2')
      42             : #define VQFR_TAG MKBETAG('V', 'Q', 'F', 'R')
      43             : 
      44             : /* don't know what these tags are for, but acknowledge their existence */
      45             : #define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
      46             : #define CINH_TAG MKBETAG('C', 'I', 'N', 'H')
      47             : #define CIND_TAG MKBETAG('C', 'I', 'N', 'D')
      48             : #define PINF_TAG MKBETAG('P', 'I', 'N', 'F')
      49             : #define PINH_TAG MKBETAG('P', 'I', 'N', 'H')
      50             : #define PIND_TAG MKBETAG('P', 'I', 'N', 'D')
      51             : #define CMDS_TAG MKBETAG('C', 'M', 'D', 'S')
      52             : 
      53             : #define VQA_HEADER_SIZE 0x2A
      54             : #define VQA_PREAMBLE_SIZE 8
      55             : 
      56             : typedef struct WsVqaDemuxContext {
      57             :     int version;
      58             :     int bps;
      59             :     int channels;
      60             :     int sample_rate;
      61             :     int audio_stream_index;
      62             :     int video_stream_index;
      63             : } WsVqaDemuxContext;
      64             : 
      65        6130 : static int wsvqa_probe(AVProbeData *p)
      66             : {
      67             :     /* need 12 bytes to qualify */
      68        6130 :     if (p->buf_size < 12)
      69           0 :         return 0;
      70             : 
      71             :     /* check for the VQA signatures */
      72        6144 :     if ((AV_RB32(&p->buf[0]) != FORM_TAG) ||
      73          14 :         (AV_RB32(&p->buf[8]) != WVQA_TAG))
      74        6127 :         return 0;
      75             : 
      76           3 :     return AVPROBE_SCORE_MAX;
      77             : }
      78             : 
      79           3 : static int wsvqa_read_header(AVFormatContext *s)
      80             : {
      81           3 :     WsVqaDemuxContext *wsvqa = s->priv_data;
      82           3 :     AVIOContext *pb = s->pb;
      83             :     AVStream *st;
      84             :     uint8_t *header;
      85             :     uint8_t scratch[VQA_PREAMBLE_SIZE];
      86             :     uint32_t chunk_tag;
      87             :     uint32_t chunk_size;
      88             :     int fps;
      89             : 
      90             :     /* initialize the video decoder stream */
      91           3 :     st = avformat_new_stream(s, NULL);
      92           3 :     if (!st)
      93           0 :         return AVERROR(ENOMEM);
      94           3 :     st->start_time = 0;
      95           3 :     wsvqa->video_stream_index = st->index;
      96           3 :     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
      97           3 :     st->codecpar->codec_id = AV_CODEC_ID_WS_VQA;
      98           3 :     st->codecpar->codec_tag = 0;  /* no fourcc */
      99             : 
     100             :     /* skip to the start of the VQA header */
     101           3 :     avio_seek(pb, 20, SEEK_SET);
     102             : 
     103             :     /* the VQA header needs to go to the decoder */
     104           3 :     if (ff_get_extradata(s, st->codecpar, pb, VQA_HEADER_SIZE) < 0)
     105           0 :         return AVERROR(ENOMEM);
     106           3 :     header = st->codecpar->extradata;
     107           3 :     st->codecpar->width = AV_RL16(&header[6]);
     108           3 :     st->codecpar->height = AV_RL16(&header[8]);
     109           3 :     fps = header[12];
     110           3 :     st->nb_frames =
     111           3 :     st->duration  = AV_RL16(&header[4]);
     112           3 :     if (fps < 1 || fps > 30) {
     113           0 :         av_log(s, AV_LOG_ERROR, "invalid fps: %d\n", fps);
     114           0 :         return AVERROR_INVALIDDATA;
     115             :     }
     116           3 :     avpriv_set_pts_info(st, 64, 1, fps);
     117             : 
     118           3 :     wsvqa->version      = AV_RL16(&header[ 0]);
     119           3 :     wsvqa->sample_rate  = AV_RL16(&header[24]);
     120           3 :     wsvqa->channels     = header[26];
     121           3 :     wsvqa->bps          = header[27];
     122           3 :     wsvqa->audio_stream_index = -1;
     123             : 
     124           3 :     s->ctx_flags |= AVFMTCTX_NOHEADER;
     125             : 
     126             :     /* there are 0 or more chunks before the FINF chunk; iterate until
     127             :      * FINF has been skipped and the file will be ready to be demuxed */
     128             :     do {
     129           3 :         if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE)
     130           0 :             return AVERROR(EIO);
     131           3 :         chunk_tag = AV_RB32(&scratch[0]);
     132           3 :         chunk_size = AV_RB32(&scratch[4]);
     133             : 
     134             :         /* catch any unknown header tags, for curiosity */
     135           3 :         switch (chunk_tag) {
     136           3 :         case CINF_TAG:
     137             :         case CINH_TAG:
     138             :         case CIND_TAG:
     139             :         case PINF_TAG:
     140             :         case PINH_TAG:
     141             :         case PIND_TAG:
     142             :         case FINF_TAG:
     143             :         case CMDS_TAG:
     144           3 :             break;
     145             : 
     146           0 :         default:
     147           0 :             av_log(s, AV_LOG_ERROR, " note: unknown chunk seen (%s)\n",
     148           0 :                    av_fourcc2str(chunk_tag));
     149           0 :             break;
     150             :         }
     151             : 
     152           3 :         avio_skip(pb, chunk_size);
     153           3 :     } while (chunk_tag != FINF_TAG);
     154             : 
     155           3 :     return 0;
     156             : }
     157             : 
     158         186 : static int wsvqa_read_packet(AVFormatContext *s,
     159             :                              AVPacket *pkt)
     160             : {
     161         186 :     WsVqaDemuxContext *wsvqa = s->priv_data;
     162         186 :     AVIOContext *pb = s->pb;
     163         186 :     int ret = -1;
     164             :     uint8_t preamble[VQA_PREAMBLE_SIZE];
     165             :     uint32_t chunk_type;
     166             :     uint32_t chunk_size;
     167             :     int skip_byte;
     168             : 
     169         373 :     while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) {
     170         181 :         chunk_type = AV_RB32(&preamble[0]);
     171         181 :         chunk_size = AV_RB32(&preamble[4]);
     172             : 
     173         181 :         skip_byte = chunk_size & 0x01;
     174             : 
     175         181 :         if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
     176          90 :             (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
     177             : 
     178         180 :             ret= av_get_packet(pb, pkt, chunk_size);
     179         180 :             if (ret<0)
     180           0 :                 return AVERROR(EIO);
     181             : 
     182         180 :             switch (chunk_type) {
     183          91 :             case SND0_TAG:
     184             :             case SND1_TAG:
     185             :             case SND2_TAG:
     186          91 :                 if (wsvqa->audio_stream_index == -1) {
     187           3 :                     AVStream *st = avformat_new_stream(s, NULL);
     188           3 :                     if (!st)
     189           0 :                         return AVERROR(ENOMEM);
     190             : 
     191           3 :                     wsvqa->audio_stream_index = st->index;
     192           3 :                     if (!wsvqa->sample_rate)
     193           1 :                         wsvqa->sample_rate = 22050;
     194           3 :                     if (!wsvqa->channels)
     195           1 :                         wsvqa->channels = 1;
     196           3 :                     if (!wsvqa->bps)
     197           1 :                         wsvqa->bps = 8;
     198           3 :                     st->codecpar->sample_rate = wsvqa->sample_rate;
     199           3 :                     st->codecpar->bits_per_coded_sample = wsvqa->bps;
     200           3 :                     st->codecpar->channels = wsvqa->channels;
     201           3 :                     st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
     202             : 
     203           3 :                     avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
     204             : 
     205           3 :                     switch (chunk_type) {
     206           0 :                     case SND0_TAG:
     207           0 :                         if (wsvqa->bps == 16)
     208           0 :                             st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
     209             :                         else
     210           0 :                             st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
     211           0 :                         break;
     212           1 :                     case SND1_TAG:
     213           1 :                         st->codecpar->codec_id = AV_CODEC_ID_WESTWOOD_SND1;
     214           1 :                         break;
     215           2 :                     case SND2_TAG:
     216           2 :                         st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
     217           2 :                         if (ff_alloc_extradata(st->codecpar, 2))
     218           0 :                             return AVERROR(ENOMEM);
     219           2 :                         AV_WL16(st->codecpar->extradata, wsvqa->version);
     220           2 :                         break;
     221             :                     }
     222             :                 }
     223             : 
     224          91 :                 pkt->stream_index = wsvqa->audio_stream_index;
     225          91 :                 switch (chunk_type) {
     226          11 :                 case SND1_TAG:
     227             :                     /* unpacked size is stored in header */
     228          11 :                     if(pkt->data)
     229          11 :                         pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
     230          11 :                     break;
     231          80 :                 case SND2_TAG:
     232             :                     /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
     233          80 :                     pkt->duration = (chunk_size * 2) / wsvqa->channels;
     234          80 :                     break;
     235             :                 }
     236          91 :                 break;
     237          89 :             case VQFR_TAG:
     238          89 :                 pkt->stream_index = wsvqa->video_stream_index;
     239          89 :                 pkt->duration = 1;
     240          89 :                 break;
     241             :             }
     242             : 
     243             :             /* stay on 16-bit alignment */
     244         180 :             if (skip_byte)
     245          85 :                 avio_skip(pb, 1);
     246             : 
     247         180 :             return ret;
     248             :         } else {
     249           1 :             switch(chunk_type){
     250           1 :             case CMDS_TAG:
     251           1 :                 break;
     252           0 :             default:
     253           0 :                 av_log(s, AV_LOG_INFO, "Skipping unknown chunk %s\n",
     254           0 :                        av_fourcc2str(av_bswap32(chunk_type)));
     255             :             }
     256           1 :             avio_skip(pb, chunk_size + skip_byte);
     257             :         }
     258             :     }
     259             : 
     260           6 :     return ret;
     261             : }
     262             : 
     263             : AVInputFormat ff_wsvqa_demuxer = {
     264             :     .name           = "wsvqa",
     265             :     .long_name      = NULL_IF_CONFIG_SMALL("Westwood Studios VQA"),
     266             :     .priv_data_size = sizeof(WsVqaDemuxContext),
     267             :     .read_probe     = wsvqa_probe,
     268             :     .read_header    = wsvqa_read_header,
     269             :     .read_packet    = wsvqa_read_packet,
     270             : };

Generated by: LCOV version 1.13