LCOV - code coverage report
Current view: top level - libavformat - bethsoftvid.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 118 152 77.6 %
Date: 2017-12-17 23:02:56 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Bethsoft VID format Demuxer
       3             :  * Copyright (c) 2007 Nicholas Tung
       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             :  * @brief Bethesda Softworks VID (.vid) file demuxer
      25             :  * @author Nicholas Tung [ntung (at. ntung com] (2007-03)
      26             :  * @see http://wiki.multimedia.cx/index.php?title=Bethsoft_VID
      27             :  * @see http://www.svatopluk.com/andux/docs/dfvid.html
      28             :  */
      29             : 
      30             : #include "libavutil/channel_layout.h"
      31             : #include "libavutil/intreadwrite.h"
      32             : #include "avformat.h"
      33             : #include "internal.h"
      34             : #include "libavcodec/bethsoftvideo.h"
      35             : 
      36             : #define BVID_PALETTE_SIZE 3 * 256
      37             : 
      38             : #define DEFAULT_SAMPLE_RATE 11111
      39             : 
      40             : typedef struct BVID_DemuxContext
      41             : {
      42             :     int nframes;
      43             :     int sample_rate;        /**< audio sample rate */
      44             :     int width;              /**< video width       */
      45             :     int height;             /**< video height      */
      46             :     /** delay value between frames, added to individual frame delay.
      47             :      * custom units, which will be added to other custom units (~=16ms according
      48             :      * to free, unofficial documentation) */
      49             :     int bethsoft_global_delay;
      50             :     int video_index;        /**< video stream index */
      51             :     int audio_index;        /**< audio stream index */
      52             :     uint8_t *palette;
      53             : 
      54             :     int is_finished;
      55             : 
      56             : } BVID_DemuxContext;
      57             : 
      58        6130 : static int vid_probe(AVProbeData *p)
      59             : {
      60             :     // little-endian VID tag, file starts with "VID\0"
      61        6130 :     if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
      62        6129 :         return 0;
      63             : 
      64           1 :     if (p->buf[4] != 2)
      65           0 :         return AVPROBE_SCORE_MAX / 4;
      66             : 
      67           1 :     return AVPROBE_SCORE_MAX;
      68             : }
      69             : 
      70           1 : static int vid_read_header(AVFormatContext *s)
      71             : {
      72           1 :     BVID_DemuxContext *vid = s->priv_data;
      73           1 :     AVIOContext *pb = s->pb;
      74             : 
      75             :     /* load main header. Contents:
      76             :     *    bytes: 'V' 'I' 'D'
      77             :     *    int16s: always_512, nframes, width, height, delay, always_14
      78             :     */
      79           1 :     avio_skip(pb, 5);
      80           1 :     vid->nframes = avio_rl16(pb);
      81           1 :     vid->width   = avio_rl16(pb);
      82           1 :     vid->height  = avio_rl16(pb);
      83           1 :     vid->bethsoft_global_delay = avio_rl16(pb);
      84           1 :     avio_rl16(pb);
      85             : 
      86             :     // wait until the first packet to create each stream
      87           1 :     vid->video_index = -1;
      88           1 :     vid->audio_index = -1;
      89           1 :     vid->sample_rate = DEFAULT_SAMPLE_RATE;
      90           1 :     s->ctx_flags |= AVFMTCTX_NOHEADER;
      91             : 
      92           1 :     return 0;
      93             : }
      94             : 
      95             : #define BUFFER_PADDING_SIZE 1000
      96          76 : static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt,
      97             :                       uint8_t block_type, AVFormatContext *s)
      98             : {
      99          76 :     uint8_t * vidbuf_start = NULL;
     100          76 :     int vidbuf_nbytes = 0;
     101             :     int code;
     102          76 :     int bytes_copied = 0;
     103             :     int position, duration, npixels;
     104             :     unsigned int vidbuf_capacity;
     105          76 :     int ret = 0;
     106             :     AVStream *st;
     107             : 
     108          76 :     if (vid->video_index < 0) {
     109           1 :         st = avformat_new_stream(s, NULL);
     110           1 :         if (!st)
     111           0 :             return AVERROR(ENOMEM);
     112           1 :         vid->video_index = st->index;
     113           1 :         if (vid->audio_index < 0) {
     114           0 :             avpriv_request_sample(s, "Using default video time base since "
     115             :                                   "having no audio packet before the first "
     116             :                                   "video packet");
     117             :         }
     118           1 :         avpriv_set_pts_info(st, 64, 185, vid->sample_rate);
     119           1 :         st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     120           1 :         st->codecpar->codec_id   = AV_CODEC_ID_BETHSOFTVID;
     121           1 :         st->codecpar->width      = vid->width;
     122           1 :         st->codecpar->height     = vid->height;
     123             :     }
     124          76 :     st      = s->streams[vid->video_index];
     125          76 :     npixels = st->codecpar->width * st->codecpar->height;
     126             : 
     127          76 :     vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE);
     128          76 :     if(!vidbuf_start)
     129           0 :         return AVERROR(ENOMEM);
     130             : 
     131             :     // save the file position for the packet, include block type
     132          76 :     position = avio_tell(pb) - 1;
     133             : 
     134          76 :     vidbuf_start[vidbuf_nbytes++] = block_type;
     135             : 
     136             :     // get the current packet duration
     137          76 :     duration = vid->bethsoft_global_delay + avio_rl16(pb);
     138             : 
     139             :     // set the y offset if it exists (decoder header data should be in data section)
     140          76 :     if(block_type == VIDEO_YOFF_P_FRAME){
     141          75 :         if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) {
     142           0 :             ret = AVERROR(EIO);
     143           0 :             goto fail;
     144             :         }
     145          75 :         vidbuf_nbytes += 2;
     146             :     }
     147             : 
     148             :     do{
     149      231332 :         vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE);
     150      231332 :         if(!vidbuf_start)
     151           0 :             return AVERROR(ENOMEM);
     152             : 
     153      231332 :         code = avio_r8(pb);
     154      231332 :         vidbuf_start[vidbuf_nbytes++] = code;
     155             : 
     156      231332 :         if(code >= 0x80){ // rle sequence
     157      119038 :             if(block_type == VIDEO_I_FRAME)
     158         504 :                 vidbuf_start[vidbuf_nbytes++] = avio_r8(pb);
     159      112294 :         } else if(code){ // plain sequence
     160      112219 :             if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code) {
     161           0 :                 ret = AVERROR(EIO);
     162           0 :                 goto fail;
     163             :             }
     164      112219 :             vidbuf_nbytes += code;
     165             :         }
     166      231332 :         bytes_copied += code & 0x7F;
     167      231332 :         if(bytes_copied == npixels){ // sometimes no stop character is given, need to keep track of bytes copied
     168             :             // may contain a 0 byte even if read all pixels
     169           1 :             if(avio_r8(pb))
     170           1 :                 avio_seek(pb, -1, SEEK_CUR);
     171           1 :             break;
     172             :         }
     173      231331 :         if (bytes_copied > npixels) {
     174           0 :             ret = AVERROR_INVALIDDATA;
     175           0 :             goto fail;
     176             :         }
     177      231331 :     } while(code);
     178             : 
     179             :     // copy data into packet
     180          76 :     if ((ret = av_new_packet(pkt, vidbuf_nbytes)) < 0)
     181           0 :         goto fail;
     182          76 :     memcpy(pkt->data, vidbuf_start, vidbuf_nbytes);
     183             : 
     184          76 :     pkt->pos = position;
     185          76 :     pkt->stream_index = vid->video_index;
     186          76 :     pkt->duration = duration;
     187          76 :     if (block_type == VIDEO_I_FRAME)
     188           1 :         pkt->flags |= AV_PKT_FLAG_KEY;
     189             : 
     190             :     /* if there is a new palette available, add it to packet side data */
     191          76 :     if (vid->palette) {
     192           1 :         uint8_t *pdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
     193             :                                                  BVID_PALETTE_SIZE);
     194           1 :         if (!pdata) {
     195           0 :             ret = AVERROR(ENOMEM);
     196           0 :             av_log(s, AV_LOG_ERROR, "Failed to allocate palette side data\n");
     197           0 :             goto fail;
     198             :         }
     199           1 :         memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
     200             : 
     201           1 :         av_freep(&vid->palette);
     202             :     }
     203             : 
     204          76 :     vid->nframes--;  // used to check if all the frames were read
     205          76 : fail:
     206          76 :     av_free(vidbuf_start);
     207          76 :     return ret;
     208             : }
     209             : 
     210         149 : static int vid_read_packet(AVFormatContext *s,
     211             :                            AVPacket *pkt)
     212             : {
     213         149 :     BVID_DemuxContext *vid = s->priv_data;
     214         149 :     AVIOContext *pb = s->pb;
     215             :     unsigned char block_type;
     216             :     int audio_length;
     217             :     int ret_value;
     218             : 
     219         149 :     if(vid->is_finished || avio_feof(pb))
     220           0 :         return AVERROR_EOF;
     221             : 
     222         149 :     block_type = avio_r8(pb);
     223         149 :     switch(block_type){
     224           1 :         case PALETTE_BLOCK:
     225           1 :             if (vid->palette) {
     226           0 :                 av_log(s, AV_LOG_WARNING, "discarding unused palette\n");
     227           0 :                 av_freep(&vid->palette);
     228             :             }
     229           1 :             vid->palette = av_malloc(BVID_PALETTE_SIZE);
     230           1 :             if (!vid->palette)
     231           0 :                 return AVERROR(ENOMEM);
     232           1 :             if (avio_read(pb, vid->palette, BVID_PALETTE_SIZE) != BVID_PALETTE_SIZE) {
     233           0 :                 av_freep(&vid->palette);
     234           0 :                 return AVERROR(EIO);
     235             :             }
     236           1 :             return vid_read_packet(s, pkt);
     237             : 
     238           2 :         case FIRST_AUDIO_BLOCK:
     239           2 :             avio_rl16(pb);
     240             :             // soundblaster DAC used for sample rate, as on specification page (link above)
     241           2 :             vid->sample_rate = 1000000 / (256 - avio_r8(pb));
     242          72 :         case AUDIO_BLOCK:
     243          72 :             if (vid->audio_index < 0) {
     244           1 :                 AVStream *st = avformat_new_stream(s, NULL);
     245           1 :                 if (!st)
     246           0 :                     return AVERROR(ENOMEM);
     247           1 :                 vid->audio_index                 = st->index;
     248           1 :                 st->codecpar->codec_type            = AVMEDIA_TYPE_AUDIO;
     249           1 :                 st->codecpar->codec_id              = AV_CODEC_ID_PCM_U8;
     250           1 :                 st->codecpar->channels              = 1;
     251           1 :                 st->codecpar->channel_layout        = AV_CH_LAYOUT_MONO;
     252           1 :                 st->codecpar->bits_per_coded_sample = 8;
     253           1 :                 st->codecpar->sample_rate           = vid->sample_rate;
     254           1 :                 st->codecpar->bit_rate              = 8 * st->codecpar->sample_rate;
     255           1 :                 st->start_time                   = 0;
     256           1 :                 avpriv_set_pts_info(st, 64, 1, vid->sample_rate);
     257             :             }
     258          72 :             audio_length = avio_rl16(pb);
     259          72 :             if ((ret_value = av_get_packet(pb, pkt, audio_length)) != audio_length) {
     260           0 :                 if (ret_value < 0)
     261           0 :                     return ret_value;
     262           0 :                 av_log(s, AV_LOG_ERROR, "incomplete audio block\n");
     263           0 :                 return AVERROR(EIO);
     264             :             }
     265          72 :             pkt->stream_index = vid->audio_index;
     266          72 :             pkt->duration     = audio_length;
     267          72 :             pkt->flags |= AV_PKT_FLAG_KEY;
     268          72 :             return 0;
     269             : 
     270          76 :         case VIDEO_P_FRAME:
     271             :         case VIDEO_YOFF_P_FRAME:
     272             :         case VIDEO_I_FRAME:
     273          76 :             return read_frame(vid, pb, pkt, block_type, s);
     274             : 
     275           0 :         case EOF_BLOCK:
     276           0 :             if(vid->nframes != 0)
     277           0 :                 av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n");
     278           0 :             vid->is_finished = 1;
     279           0 :             return AVERROR(EIO);
     280           0 :         default:
     281           0 :             av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n",
     282             :                    block_type, block_type, block_type);
     283           0 :             return AVERROR_INVALIDDATA;
     284             :     }
     285             : }
     286             : 
     287           1 : static int vid_read_close(AVFormatContext *s)
     288             : {
     289           1 :     BVID_DemuxContext *vid = s->priv_data;
     290           1 :     av_freep(&vid->palette);
     291           1 :     return 0;
     292             : }
     293             : 
     294             : AVInputFormat ff_bethsoftvid_demuxer = {
     295             :     .name           = "bethsoftvid",
     296             :     .long_name      = NULL_IF_CONFIG_SMALL("Bethesda Softworks VID"),
     297             :     .priv_data_size = sizeof(BVID_DemuxContext),
     298             :     .read_probe     = vid_probe,
     299             :     .read_header    = vid_read_header,
     300             :     .read_packet    = vid_read_packet,
     301             :     .read_close     = vid_read_close,
     302             : };

Generated by: LCOV version 1.13