LCOV - code coverage report
Current view: top level - libavformat - sierravmd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 134 171 78.4 %
Date: 2017-12-12 03:56:30 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Sierra VMD Format Demuxer
       3             :  * Copyright (c) 2004 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             :  * Sierra VMD file demuxer
      25             :  * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
      26             :  * for more information on the Sierra VMD file format, visit:
      27             :  *   http://www.pcisys.net/~melanson/codecs/
      28             :  */
      29             : 
      30             : #include "libavutil/channel_layout.h"
      31             : #include "libavutil/intreadwrite.h"
      32             : #include "avformat.h"
      33             : #include "internal.h"
      34             : #include "avio_internal.h"
      35             : 
      36             : #define VMD_HEADER_SIZE 0x0330
      37             : #define BYTES_PER_FRAME_RECORD 16
      38             : 
      39             : typedef struct vmd_frame {
      40             :   int stream_index;
      41             :   int64_t frame_offset;
      42             :   unsigned int frame_size;
      43             :   int64_t pts;
      44             :   int keyframe;
      45             :   unsigned char frame_record[BYTES_PER_FRAME_RECORD];
      46             : } vmd_frame;
      47             : 
      48             : typedef struct VmdDemuxContext {
      49             :     int video_stream_index;
      50             :     int audio_stream_index;
      51             : 
      52             :     unsigned int frame_count;
      53             :     unsigned int frames_per_block;
      54             :     vmd_frame *frame_table;
      55             :     unsigned int current_frame;
      56             :     int is_indeo3;
      57             : 
      58             :     int sample_rate;
      59             :     int64_t audio_sample_counter;
      60             :     int skiphdr;
      61             : 
      62             :     unsigned char vmd_header[VMD_HEADER_SIZE];
      63             : } VmdDemuxContext;
      64             : 
      65        6130 : static int vmd_probe(AVProbeData *p)
      66             : {
      67             :     int w, h, sample_rate;
      68        6130 :     if (p->buf_size < 806)
      69          34 :         return 0;
      70             :     /* check if the first 2 bytes of the file contain the appropriate size
      71             :      * of a VMD header chunk */
      72        6096 :     if (AV_RL16(&p->buf[0]) != VMD_HEADER_SIZE - 2)
      73        6093 :         return 0;
      74           3 :     w = AV_RL16(&p->buf[12]);
      75           3 :     h = AV_RL16(&p->buf[14]);
      76           3 :     sample_rate = AV_RL16(&p->buf[804]);
      77           3 :     if ((!w || w > 2048 || !h || h > 2048) &&
      78             :         sample_rate != 22050)
      79           0 :         return 0;
      80             : 
      81             :     /* only return half certainty since this check is a bit sketchy */
      82           3 :     return AVPROBE_SCORE_EXTENSION;
      83             : }
      84             : 
      85           3 : static int vmd_read_header(AVFormatContext *s)
      86             : {
      87           3 :     VmdDemuxContext *vmd = s->priv_data;
      88           3 :     AVIOContext *pb = s->pb;
      89           3 :     AVStream *st = NULL, *vst = NULL;
      90             :     unsigned int toc_offset;
      91             :     unsigned char *raw_frame_table;
      92             :     int raw_frame_table_size;
      93             :     int64_t current_offset;
      94             :     int i, j, ret;
      95             :     int width, height;
      96             :     unsigned int total_frames;
      97           3 :     int64_t current_audio_pts = 0;
      98             :     unsigned char chunk[BYTES_PER_FRAME_RECORD];
      99             :     int num, den;
     100             :     int sound_buffers;
     101             : 
     102             :     /* fetch the main header, including the 2 header length bytes */
     103           3 :     avio_seek(pb, 0, SEEK_SET);
     104           3 :     if (avio_read(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
     105           0 :         return AVERROR(EIO);
     106             : 
     107           3 :     width = AV_RL16(&vmd->vmd_header[12]);
     108           3 :     height = AV_RL16(&vmd->vmd_header[14]);
     109           3 :     if (width && height) {
     110           3 :         if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3') {
     111           0 :             vmd->is_indeo3 = 1;
     112             :         } else {
     113           3 :             vmd->is_indeo3 = 0;
     114             :         }
     115             :         /* start up the decoders */
     116           3 :         vst = avformat_new_stream(s, NULL);
     117           3 :         if (!vst)
     118           0 :             return AVERROR(ENOMEM);
     119           3 :         avpriv_set_pts_info(vst, 33, 1, 10);
     120           3 :         vmd->video_stream_index = vst->index;
     121           3 :         vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     122           3 :         vst->codecpar->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO;
     123           3 :         vst->codecpar->codec_tag = 0;  /* no fourcc */
     124           3 :         vst->codecpar->width = width;
     125           3 :         vst->codecpar->height = height;
     126           3 :         if(vmd->is_indeo3 && vst->codecpar->width > 320){
     127           0 :             vst->codecpar->width >>= 1;
     128           0 :             vst->codecpar->height >>= 1;
     129             :         }
     130           3 :         if (ff_alloc_extradata(vst->codecpar, VMD_HEADER_SIZE))
     131           0 :             return AVERROR(ENOMEM);
     132           3 :         memcpy(vst->codecpar->extradata, vmd->vmd_header, VMD_HEADER_SIZE);
     133             :     }
     134             : 
     135             :     /* if sample rate is 0, assume no audio */
     136           3 :     vmd->sample_rate = AV_RL16(&vmd->vmd_header[804]);
     137           3 :     if (vmd->sample_rate) {
     138           3 :         st = avformat_new_stream(s, NULL);
     139           3 :         if (!st)
     140           0 :             return AVERROR(ENOMEM);
     141           3 :         vmd->audio_stream_index = st->index;
     142           3 :         st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
     143           3 :         st->codecpar->codec_id   = AV_CODEC_ID_VMDAUDIO;
     144           3 :         st->codecpar->codec_tag  = 0;  /* no fourcc */
     145           3 :         st->codecpar->sample_rate = vmd->sample_rate;
     146           3 :         st->codecpar->block_align = AV_RL16(&vmd->vmd_header[806]);
     147           3 :         if (st->codecpar->block_align & 0x8000) {
     148           0 :             st->codecpar->bits_per_coded_sample = 16;
     149           0 :             st->codecpar->block_align = -(st->codecpar->block_align - 0x10000);
     150             :         } else {
     151           3 :             st->codecpar->bits_per_coded_sample = 8;
     152             :         }
     153           3 :         if (vmd->vmd_header[811] & 0x80) {
     154           0 :             st->codecpar->channels       = 2;
     155           0 :             st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
     156           3 :         } else if (vmd->vmd_header[811] & 0x2) {
     157             :             /* Shivers 2 stereo audio */
     158             :             /* Frame length is for 1 channel */
     159           0 :             st->codecpar->channels       = 2;
     160           0 :             st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
     161           0 :             st->codecpar->block_align = st->codecpar->block_align << 1;
     162             :         } else {
     163           3 :             st->codecpar->channels       = 1;
     164           3 :             st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
     165             :         }
     166          12 :         st->codecpar->bit_rate = st->codecpar->sample_rate *
     167           9 :             st->codecpar->bits_per_coded_sample * st->codecpar->channels;
     168             : 
     169             :         /* calculate pts */
     170           3 :         num = st->codecpar->block_align;
     171           3 :         den = st->codecpar->sample_rate * st->codecpar->channels;
     172           3 :         av_reduce(&num, &den, num, den, (1UL<<31)-1);
     173           3 :         if (vst)
     174           3 :             avpriv_set_pts_info(vst, 33, num, den);
     175           3 :         avpriv_set_pts_info(st, 33, num, den);
     176             :     }
     177             : 
     178           3 :     toc_offset = AV_RL32(&vmd->vmd_header[812]);
     179           3 :     vmd->frame_count = AV_RL16(&vmd->vmd_header[6]);
     180           3 :     vmd->frames_per_block = AV_RL16(&vmd->vmd_header[18]);
     181           3 :     avio_seek(pb, toc_offset, SEEK_SET);
     182             : 
     183           3 :     raw_frame_table = NULL;
     184           3 :     vmd->frame_table = NULL;
     185           3 :     sound_buffers = AV_RL16(&vmd->vmd_header[808]);
     186           3 :     raw_frame_table_size = vmd->frame_count * 6;
     187           3 :     if(vmd->frame_count * vmd->frames_per_block >= UINT_MAX / sizeof(vmd_frame) - sound_buffers){
     188           0 :         av_log(s, AV_LOG_ERROR, "vmd->frame_count * vmd->frames_per_block too large\n");
     189           0 :         return -1;
     190             :     }
     191           3 :     raw_frame_table = av_malloc(raw_frame_table_size);
     192           3 :     vmd->frame_table = av_malloc_array(vmd->frame_count * vmd->frames_per_block + sound_buffers, sizeof(vmd_frame));
     193           3 :     if (!raw_frame_table || !vmd->frame_table) {
     194           0 :         ret = AVERROR(ENOMEM);
     195           0 :         goto error;
     196             :     }
     197           3 :     if (avio_read(pb, raw_frame_table, raw_frame_table_size) !=
     198             :         raw_frame_table_size) {
     199           0 :         ret = AVERROR(EIO);
     200           0 :         goto error;
     201             :     }
     202             : 
     203           3 :     total_frames = 0;
     204         648 :     for (i = 0; i < vmd->frame_count; i++) {
     205             : 
     206         645 :         current_offset = AV_RL32(&raw_frame_table[6 * i + 2]);
     207             : 
     208             :         /* handle each entry in index block */
     209        1935 :         for (j = 0; j < vmd->frames_per_block; j++) {
     210             :             int type;
     211             :             uint32_t size;
     212             : 
     213        1290 :             if ((ret = avio_read(pb, chunk, BYTES_PER_FRAME_RECORD)) != BYTES_PER_FRAME_RECORD) {
     214           0 :                 av_log(s, AV_LOG_ERROR, "Failed to read frame record\n");
     215           0 :                 if (ret >= 0)
     216           0 :                     ret = AVERROR_INVALIDDATA;
     217           0 :                 goto error;
     218             :             }
     219        1290 :             type = chunk[0];
     220        1290 :             size = AV_RL32(&chunk[2]);
     221        1290 :             if (size > INT_MAX / 2) {
     222           0 :                 av_log(s, AV_LOG_ERROR, "Invalid frame size\n");
     223           0 :                 ret = AVERROR_INVALIDDATA;
     224           0 :                 goto error;
     225             :             }
     226        1290 :             if(!size && type != 1)
     227         294 :                 continue;
     228         996 :             switch(type) {
     229         645 :             case 1: /* Audio Chunk */
     230         645 :                 if (!st) break;
     231             :                 /* first audio chunk contains several audio buffers */
     232         645 :                 vmd->frame_table[total_frames].frame_offset = current_offset;
     233         645 :                 vmd->frame_table[total_frames].stream_index = vmd->audio_stream_index;
     234         645 :                 vmd->frame_table[total_frames].frame_size = size;
     235         645 :                 memcpy(vmd->frame_table[total_frames].frame_record, chunk, BYTES_PER_FRAME_RECORD);
     236         645 :                 vmd->frame_table[total_frames].pts = current_audio_pts;
     237         645 :                 total_frames++;
     238         645 :                 if(!current_audio_pts)
     239           3 :                     current_audio_pts += sound_buffers - 1;
     240             :                 else
     241         642 :                     current_audio_pts++;
     242         645 :                 break;
     243         351 :             case 2: /* Video Chunk */
     244         351 :                 vmd->frame_table[total_frames].frame_offset = current_offset;
     245         351 :                 vmd->frame_table[total_frames].stream_index = vmd->video_stream_index;
     246         351 :                 vmd->frame_table[total_frames].frame_size = size;
     247         351 :                 memcpy(vmd->frame_table[total_frames].frame_record, chunk, BYTES_PER_FRAME_RECORD);
     248         351 :                 vmd->frame_table[total_frames].pts = i;
     249         351 :                 total_frames++;
     250         351 :                 break;
     251             :             }
     252         996 :             current_offset += size;
     253             :         }
     254             :     }
     255             : 
     256           3 :     av_free(raw_frame_table);
     257             : 
     258           3 :     vmd->current_frame = 0;
     259           3 :     vmd->frame_count = total_frames;
     260             : 
     261           3 :     return 0;
     262             : 
     263           0 : error:
     264           0 :     av_freep(&raw_frame_table);
     265           0 :     av_freep(&vmd->frame_table);
     266           0 :     return ret;
     267             : }
     268             : 
     269         705 : static int vmd_read_packet(AVFormatContext *s,
     270             :                            AVPacket *pkt)
     271             : {
     272         705 :     VmdDemuxContext *vmd = s->priv_data;
     273         705 :     AVIOContext *pb = s->pb;
     274         705 :     int ret = 0;
     275             :     vmd_frame *frame;
     276             : 
     277         705 :     if (vmd->current_frame >= vmd->frame_count)
     278           2 :         return AVERROR_EOF;
     279             : 
     280         703 :     frame = &vmd->frame_table[vmd->current_frame];
     281             :     /* position the stream (will probably be there already) */
     282         703 :     avio_seek(pb, frame->frame_offset, SEEK_SET);
     283             : 
     284         703 :     if(ffio_limit(pb, frame->frame_size) != frame->frame_size)
     285           0 :         return AVERROR(EIO);
     286         703 :     if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD))
     287           0 :         return AVERROR(ENOMEM);
     288         703 :     pkt->pos= avio_tell(pb);
     289         703 :     memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD);
     290         703 :     if(vmd->is_indeo3 && frame->frame_record[0] == 0x02)
     291           0 :         ret = avio_read(pb, pkt->data, frame->frame_size);
     292             :     else
     293         703 :         ret = avio_read(pb, pkt->data + BYTES_PER_FRAME_RECORD,
     294         703 :             frame->frame_size);
     295             : 
     296         703 :     if (ret != frame->frame_size) {
     297           0 :         av_packet_unref(pkt);
     298           0 :         ret = AVERROR(EIO);
     299             :     }
     300         703 :     pkt->stream_index = frame->stream_index;
     301         703 :     pkt->pts = frame->pts;
     302        2109 :     av_log(s, AV_LOG_DEBUG, " dispatching %s frame with %d bytes and pts %"PRId64"\n",
     303         703 :             (frame->frame_record[0] == 0x02) ? "video" : "audio",
     304         703 :             frame->frame_size + BYTES_PER_FRAME_RECORD,
     305             :             pkt->pts);
     306             : 
     307         703 :     vmd->current_frame++;
     308             : 
     309         703 :     return ret;
     310             : }
     311             : 
     312           3 : static int vmd_read_close(AVFormatContext *s)
     313             : {
     314           3 :     VmdDemuxContext *vmd = s->priv_data;
     315             : 
     316           3 :     av_freep(&vmd->frame_table);
     317             : 
     318           3 :     return 0;
     319             : }
     320             : 
     321             : AVInputFormat ff_vmd_demuxer = {
     322             :     .name           = "vmd",
     323             :     .long_name      = NULL_IF_CONFIG_SMALL("Sierra VMD"),
     324             :     .priv_data_size = sizeof(VmdDemuxContext),
     325             :     .read_probe     = vmd_probe,
     326             :     .read_header    = vmd_read_header,
     327             :     .read_packet    = vmd_read_packet,
     328             :     .read_close     = vmd_read_close,
     329             : };

Generated by: LCOV version 1.13