LCOV - code coverage report
Current view: top level - libavformat - tmv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 63 89 70.8 %
Date: 2017-12-13 18:07:29 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /*
       2             :  * 8088flex TMV file demuxer
       3             :  * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
       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             :  * 8088flex TMV file demuxer
      25             :  * @author Daniel Verkamp
      26             :  * @see http://www.oldskool.org/pc/8088_Corruption
      27             :  */
      28             : 
      29             : #include "libavutil/channel_layout.h"
      30             : #include "libavutil/intreadwrite.h"
      31             : #include "avformat.h"
      32             : #include "internal.h"
      33             : 
      34             : enum {
      35             :     TMV_PADDING = 0x01,
      36             :     TMV_STEREO  = 0x02,
      37             : };
      38             : 
      39             : #define TMV_TAG MKTAG('T', 'M', 'A', 'V')
      40             : 
      41             : typedef struct TMVContext {
      42             :     unsigned audio_chunk_size;
      43             :     unsigned video_chunk_size;
      44             :     unsigned padding;
      45             :     unsigned stream_index;
      46             : } TMVContext;
      47             : 
      48             : #define TMV_HEADER_SIZE       12
      49             : 
      50             : #define PROBE_MIN_SAMPLE_RATE 5000
      51             : #define PROBE_MAX_FPS         120
      52             : #define PROBE_MIN_AUDIO_SIZE  (PROBE_MIN_SAMPLE_RATE / PROBE_MAX_FPS)
      53             : 
      54        6130 : static int tmv_probe(AVProbeData *p)
      55             : {
      56        6131 :     if (AV_RL32(p->buf)   == TMV_TAG &&
      57           2 :         AV_RL16(p->buf+4) >= PROBE_MIN_SAMPLE_RATE &&
      58           2 :         AV_RL16(p->buf+6) >= PROBE_MIN_AUDIO_SIZE  &&
      59           2 :                !p->buf[8] && // compression method
      60           2 :                 p->buf[9] && // char cols
      61           1 :                 p->buf[10])  // char rows
      62           2 :         return AVPROBE_SCORE_MAX /
      63           2 :             ((p->buf[9] == 40 && p->buf[10] == 25) ? 1 : 4);
      64        6129 :     return 0;
      65             : }
      66             : 
      67           1 : static int tmv_read_header(AVFormatContext *s)
      68             : {
      69           1 :     TMVContext *tmv   = s->priv_data;
      70           1 :     AVIOContext *pb = s->pb;
      71             :     AVStream *vst, *ast;
      72             :     AVRational fps;
      73             :     unsigned comp_method, char_cols, char_rows, features;
      74             : 
      75           1 :     if (avio_rl32(pb) != TMV_TAG)
      76           0 :         return -1;
      77             : 
      78           1 :     if (!(vst = avformat_new_stream(s, NULL)))
      79           0 :         return AVERROR(ENOMEM);
      80             : 
      81           1 :     if (!(ast = avformat_new_stream(s, NULL)))
      82           0 :         return AVERROR(ENOMEM);
      83             : 
      84           1 :     ast->codecpar->sample_rate = avio_rl16(pb);
      85           1 :     if (!ast->codecpar->sample_rate) {
      86           0 :         av_log(s, AV_LOG_ERROR, "invalid sample rate\n");
      87           0 :         return -1;
      88             :     }
      89             : 
      90           1 :     tmv->audio_chunk_size   = avio_rl16(pb);
      91           1 :     if (!tmv->audio_chunk_size) {
      92           0 :         av_log(s, AV_LOG_ERROR, "invalid audio chunk size\n");
      93           0 :         return -1;
      94             :     }
      95             : 
      96           1 :     comp_method             = avio_r8(pb);
      97           1 :     if (comp_method) {
      98           0 :         av_log(s, AV_LOG_ERROR, "unsupported compression method %d\n",
      99             :                comp_method);
     100           0 :         return -1;
     101             :     }
     102             : 
     103           1 :     char_cols = avio_r8(pb);
     104           1 :     char_rows = avio_r8(pb);
     105           1 :     tmv->video_chunk_size = char_cols * char_rows * 2;
     106             : 
     107           1 :     features  = avio_r8(pb);
     108           1 :     if (features & ~(TMV_PADDING | TMV_STEREO)) {
     109           0 :         av_log(s, AV_LOG_ERROR, "unsupported features 0x%02x\n",
     110             :                features & ~(TMV_PADDING | TMV_STEREO));
     111           0 :         return -1;
     112             :     }
     113             : 
     114           1 :     ast->codecpar->codec_type            = AVMEDIA_TYPE_AUDIO;
     115           1 :     ast->codecpar->codec_id              = AV_CODEC_ID_PCM_U8;
     116           1 :     if (features & TMV_STEREO) {
     117           0 :         ast->codecpar->channels       = 2;
     118           0 :         ast->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
     119             :     } else {
     120           1 :         ast->codecpar->channels       = 1;
     121           1 :         ast->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
     122             :     }
     123           1 :     ast->codecpar->bits_per_coded_sample = 8;
     124           2 :     ast->codecpar->bit_rate              = ast->codecpar->sample_rate *
     125           1 :                                            ast->codecpar->bits_per_coded_sample;
     126           1 :     avpriv_set_pts_info(ast, 32, 1, ast->codecpar->sample_rate);
     127             : 
     128           1 :     fps.num = ast->codecpar->sample_rate * ast->codecpar->channels;
     129           1 :     fps.den = tmv->audio_chunk_size;
     130           1 :     av_reduce(&fps.num, &fps.den, fps.num, fps.den, 0xFFFFFFFFLL);
     131             : 
     132           1 :     vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     133           1 :     vst->codecpar->codec_id   = AV_CODEC_ID_TMV;
     134           1 :     vst->codecpar->format     = AV_PIX_FMT_PAL8;
     135           1 :     vst->codecpar->width      = char_cols * 8;
     136           1 :     vst->codecpar->height     = char_rows * 8;
     137           1 :     avpriv_set_pts_info(vst, 32, fps.den, fps.num);
     138             : 
     139           1 :     if (features & TMV_PADDING)
     140           0 :         tmv->padding =
     141           0 :             ((tmv->video_chunk_size + tmv->audio_chunk_size + 511) & ~511) -
     142           0 :              (tmv->video_chunk_size + tmv->audio_chunk_size);
     143             : 
     144           4 :     vst->codecpar->bit_rate = ((tmv->video_chunk_size + tmv->padding) *
     145           3 :                                fps.num * 8) / fps.den;
     146             : 
     147           1 :     return 0;
     148             : }
     149             : 
     150         222 : static int tmv_read_packet(AVFormatContext *s, AVPacket *pkt)
     151             : {
     152         222 :     TMVContext *tmv   = s->priv_data;
     153         222 :     AVIOContext *pb = s->pb;
     154         444 :     int ret, pkt_size = tmv->stream_index ?
     155         222 :                         tmv->audio_chunk_size : tmv->video_chunk_size;
     156             : 
     157         222 :     if (avio_feof(pb))
     158           1 :         return AVERROR_EOF;
     159             : 
     160         221 :     ret = av_get_packet(pb, pkt, pkt_size);
     161             : 
     162         221 :     if (tmv->stream_index)
     163         110 :         avio_skip(pb, tmv->padding);
     164             : 
     165         221 :     pkt->stream_index  = tmv->stream_index;
     166         221 :     tmv->stream_index ^= 1;
     167         221 :     pkt->flags        |= AV_PKT_FLAG_KEY;
     168             : 
     169         221 :     return ret;
     170             : }
     171             : 
     172           0 : static int tmv_read_seek(AVFormatContext *s, int stream_index,
     173             :                          int64_t timestamp, int flags)
     174             : {
     175           0 :     TMVContext *tmv = s->priv_data;
     176             :     int64_t pos;
     177             : 
     178           0 :     if (stream_index)
     179           0 :         return -1;
     180             : 
     181           0 :     pos = timestamp *
     182           0 :           (tmv->audio_chunk_size + tmv->video_chunk_size + tmv->padding);
     183             : 
     184           0 :     if (avio_seek(s->pb, pos + TMV_HEADER_SIZE, SEEK_SET) < 0)
     185           0 :         return -1;
     186           0 :     tmv->stream_index = 0;
     187           0 :     return 0;
     188             : }
     189             : 
     190             : AVInputFormat ff_tmv_demuxer = {
     191             :     .name           = "tmv",
     192             :     .long_name      = NULL_IF_CONFIG_SMALL("8088flex TMV"),
     193             :     .priv_data_size = sizeof(TMVContext),
     194             :     .read_probe     = tmv_probe,
     195             :     .read_header    = tmv_read_header,
     196             :     .read_packet    = tmv_read_packet,
     197             :     .read_seek      = tmv_read_seek,
     198             :     .flags          = AVFMT_GENERIC_INDEX,
     199             : };

Generated by: LCOV version 1.13