• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/tmv.c

Go to the documentation of this file.
00001 /*
00002  * 8088flex TMV file demuxer
00003  * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00029 #include "libavutil/intreadwrite.h"
00030 #include "avformat.h"
00031 
00032 enum {
00033     TMV_PADDING = 0x01,
00034     TMV_STEREO  = 0x02,
00035 };
00036 
00037 #define TMV_TAG MKTAG('T', 'M', 'A', 'V')
00038 
00039 typedef struct TMVContext {
00040     unsigned audio_chunk_size;
00041     unsigned video_chunk_size;
00042     unsigned padding;
00043     unsigned stream_index;
00044 } TMVContext;
00045 
00046 #define TMV_HEADER_SIZE       12
00047 
00048 #define PROBE_MIN_SAMPLE_RATE 5000
00049 #define PROBE_MAX_FPS         120
00050 #define PROBE_MIN_AUDIO_SIZE  (PROBE_MIN_SAMPLE_RATE / PROBE_MAX_FPS)
00051 
00052 static int tmv_probe(AVProbeData *p)
00053 {
00054     if (AV_RL32(p->buf)   == TMV_TAG &&
00055         AV_RL16(p->buf+4) >= PROBE_MIN_SAMPLE_RATE &&
00056         AV_RL16(p->buf+6) >= PROBE_MIN_AUDIO_SIZE  &&
00057                !p->buf[8] && // compression method
00058                 p->buf[9] && // char cols
00059                 p->buf[10])  // char rows
00060         return AVPROBE_SCORE_MAX /
00061             ((p->buf[9] == 40 && p->buf[10] == 25) ? 1 : 4);
00062     return 0;
00063 }
00064 
00065 static int tmv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00066 {
00067     TMVContext *tmv   = s->priv_data;
00068     ByteIOContext *pb = s->pb;
00069     AVStream *vst, *ast;
00070     AVRational fps;
00071     unsigned comp_method, char_cols, char_rows, features;
00072 
00073     if (get_le32(pb) != TMV_TAG)
00074         return -1;
00075 
00076     if (!(vst = av_new_stream(s, 0)))
00077         return AVERROR(ENOMEM);
00078 
00079     if (!(ast = av_new_stream(s, 0)))
00080         return AVERROR(ENOMEM);
00081 
00082     ast->codec->sample_rate = get_le16(pb);
00083     if (!ast->codec->sample_rate) {
00084         av_log(s, AV_LOG_ERROR, "invalid sample rate\n");
00085         return -1;
00086     }
00087 
00088     tmv->audio_chunk_size   = get_le16(pb);
00089     if (!tmv->audio_chunk_size) {
00090         av_log(s, AV_LOG_ERROR, "invalid audio chunk size\n");
00091         return -1;
00092     }
00093 
00094     comp_method             = get_byte(pb);
00095     if (comp_method) {
00096         av_log(s, AV_LOG_ERROR, "unsupported compression method %d\n",
00097                comp_method);
00098         return -1;
00099     }
00100 
00101     char_cols = get_byte(pb);
00102     char_rows = get_byte(pb);
00103     tmv->video_chunk_size = char_cols * char_rows * 2;
00104 
00105     features  = get_byte(pb);
00106     if (features & ~(TMV_PADDING | TMV_STEREO)) {
00107         av_log(s, AV_LOG_ERROR, "unsupported features 0x%02x\n",
00108                features & ~(TMV_PADDING | TMV_STEREO));
00109         return -1;
00110     }
00111 
00112     ast->codec->codec_type            = AVMEDIA_TYPE_AUDIO;
00113     ast->codec->codec_id              = CODEC_ID_PCM_U8;
00114     ast->codec->channels              = features & TMV_STEREO ? 2 : 1;
00115     ast->codec->bits_per_coded_sample = 8;
00116     ast->codec->bit_rate              = ast->codec->sample_rate *
00117                                         ast->codec->bits_per_coded_sample;
00118     av_set_pts_info(ast, 32, 1, ast->codec->sample_rate);
00119 
00120     fps.num = ast->codec->sample_rate * ast->codec->channels;
00121     fps.den = tmv->audio_chunk_size;
00122     av_reduce(&fps.num, &fps.den, fps.num, fps.den, 0xFFFFFFFFLL);
00123 
00124     vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00125     vst->codec->codec_id   = CODEC_ID_TMV;
00126     vst->codec->pix_fmt    = PIX_FMT_PAL8;
00127     vst->codec->width      = char_cols * 8;
00128     vst->codec->height     = char_rows * 8;
00129     av_set_pts_info(vst, 32, fps.den, fps.num);
00130 
00131     if (features & TMV_PADDING)
00132         tmv->padding =
00133             ((tmv->video_chunk_size + tmv->audio_chunk_size + 511) & ~511) -
00134              (tmv->video_chunk_size + tmv->audio_chunk_size);
00135 
00136     vst->codec->bit_rate = ((tmv->video_chunk_size + tmv->padding) *
00137                             fps.num * 8) / fps.den;
00138 
00139     return 0;
00140 }
00141 
00142 static int tmv_read_packet(AVFormatContext *s, AVPacket *pkt)
00143 {
00144     TMVContext *tmv   = s->priv_data;
00145     ByteIOContext *pb = s->pb;
00146     int ret, pkt_size = tmv->stream_index ?
00147                         tmv->audio_chunk_size : tmv->video_chunk_size;
00148 
00149     if (url_feof(pb))
00150         return AVERROR_EOF;
00151 
00152     ret = av_get_packet(pb, pkt, pkt_size);
00153 
00154     if (tmv->stream_index)
00155         url_fskip(pb, tmv->padding);
00156 
00157     pkt->stream_index  = tmv->stream_index;
00158     tmv->stream_index ^= 1;
00159     pkt->flags        |= AV_PKT_FLAG_KEY;
00160 
00161     return ret;
00162 }
00163 
00164 static int tmv_read_seek(AVFormatContext *s, int stream_index,
00165                          int64_t timestamp, int flags)
00166 {
00167     TMVContext *tmv = s->priv_data;
00168     int64_t pos;
00169 
00170     if (stream_index)
00171         return -1;
00172 
00173     pos = timestamp *
00174           (tmv->audio_chunk_size + tmv->video_chunk_size + tmv->padding);
00175 
00176     url_fseek(s->pb, pos + TMV_HEADER_SIZE, SEEK_SET);
00177     tmv->stream_index = 0;
00178     return 0;
00179 }
00180 
00181 AVInputFormat tmv_demuxer = {
00182     "tmv",
00183     NULL_IF_CONFIG_SMALL("8088flex TMV"),
00184     sizeof(TMVContext),
00185     tmv_probe,
00186     tmv_read_header,
00187     tmv_read_packet,
00188     NULL,
00189     tmv_read_seek,
00190     .flags = AVFMT_GENERIC_INDEX,
00191 };

Generated on Fri Sep 16 2011 17:17:44 for FFmpeg by  doxygen 1.7.1