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

libavformat/mm.c

Go to the documentation of this file.
00001 /*
00002  * American Laser Games MM Format Demuxer
00003  * Copyright (c) 2006 Peter Ross
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 
00034 #include "libavutil/intreadwrite.h"
00035 #include "avformat.h"
00036 #include "internal.h"
00037 
00038 #define MM_PREAMBLE_SIZE    6
00039 
00040 #define MM_TYPE_HEADER      0x0
00041 #define MM_TYPE_INTER       0x5
00042 #define MM_TYPE_INTRA       0x8
00043 #define MM_TYPE_INTRA_HH    0xc
00044 #define MM_TYPE_INTER_HH    0xd
00045 #define MM_TYPE_INTRA_HHV   0xe
00046 #define MM_TYPE_INTER_HHV   0xf
00047 #define MM_TYPE_AUDIO       0x15
00048 #define MM_TYPE_PALETTE     0x31
00049 
00050 #define MM_HEADER_LEN_V     0x16    /* video only */
00051 #define MM_HEADER_LEN_AV    0x18    /* video + audio */
00052 
00053 #define MM_PALETTE_COUNT    128
00054 #define MM_PALETTE_SIZE     (MM_PALETTE_COUNT*3)
00055 
00056 typedef struct {
00057   unsigned int audio_pts, video_pts;
00058 } MmDemuxContext;
00059 
00060 static int probe(AVProbeData *p)
00061 {
00062     int len, type, fps, w, h;
00063     if (p->buf_size < MM_HEADER_LEN_AV + MM_PREAMBLE_SIZE)
00064         return 0;
00065     /* the first chunk is always the header */
00066     if (AV_RL16(&p->buf[0]) != MM_TYPE_HEADER)
00067         return 0;
00068     len = AV_RL32(&p->buf[2]);
00069     if (len != MM_HEADER_LEN_V && len != MM_HEADER_LEN_AV)
00070         return 0;
00071     fps = AV_RL16(&p->buf[8]);
00072     w = AV_RL16(&p->buf[12]);
00073     h = AV_RL16(&p->buf[14]);
00074     if (!fps || fps > 60 || !w || w > 2048 || !h || h > 2048)
00075         return 0;
00076     type = AV_RL16(&p->buf[len]);
00077     if (!type || type > 0x31)
00078         return 0;
00079 
00080     /* only return half certainty since this check is a bit sketchy */
00081     return AVPROBE_SCORE_MAX / 2;
00082 }
00083 
00084 static int read_header(AVFormatContext *s,
00085                            AVFormatParameters *ap)
00086 {
00087     MmDemuxContext *mm = s->priv_data;
00088     AVIOContext *pb = s->pb;
00089     AVStream *st;
00090 
00091     unsigned int type, length;
00092     unsigned int frame_rate, width, height;
00093 
00094     type = avio_rl16(pb);
00095     length = avio_rl32(pb);
00096 
00097     if (type != MM_TYPE_HEADER)
00098         return AVERROR_INVALIDDATA;
00099 
00100     /* read header */
00101     avio_rl16(pb);   /* total number of chunks */
00102     frame_rate = avio_rl16(pb);
00103     avio_rl16(pb);   /* ibm-pc video bios mode */
00104     width = avio_rl16(pb);
00105     height = avio_rl16(pb);
00106     avio_skip(pb, length - 10);  /* unknown data */
00107 
00108     /* video stream */
00109     st = avformat_new_stream(s, NULL);
00110     if (!st)
00111         return AVERROR(ENOMEM);
00112     st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00113     st->codec->codec_id = CODEC_ID_MMVIDEO;
00114     st->codec->codec_tag = 0;  /* no fourcc */
00115     st->codec->width = width;
00116     st->codec->height = height;
00117     avpriv_set_pts_info(st, 64, 1, frame_rate);
00118 
00119     /* audio stream */
00120     if (length == MM_HEADER_LEN_AV) {
00121         st = avformat_new_stream(s, NULL);
00122         if (!st)
00123             return AVERROR(ENOMEM);
00124         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00125         st->codec->codec_tag = 0; /* no fourcc */
00126         st->codec->codec_id = CODEC_ID_PCM_U8;
00127         st->codec->channels = 1;
00128         st->codec->sample_rate = 8000;
00129         avpriv_set_pts_info(st, 64, 1, 8000); /* 8000 hz */
00130     }
00131 
00132     mm->audio_pts = 0;
00133     mm->video_pts = 0;
00134     return 0;
00135 }
00136 
00137 static int read_packet(AVFormatContext *s,
00138                            AVPacket *pkt)
00139 {
00140     MmDemuxContext *mm = s->priv_data;
00141     AVIOContext *pb = s->pb;
00142     unsigned char preamble[MM_PREAMBLE_SIZE];
00143     unsigned int type, length;
00144 
00145     while(1) {
00146 
00147         if (avio_read(pb, preamble, MM_PREAMBLE_SIZE) != MM_PREAMBLE_SIZE) {
00148             return AVERROR(EIO);
00149         }
00150 
00151         type = AV_RL16(&preamble[0]);
00152         length = AV_RL16(&preamble[2]);
00153 
00154         switch(type) {
00155         case MM_TYPE_PALETTE :
00156         case MM_TYPE_INTER :
00157         case MM_TYPE_INTRA :
00158         case MM_TYPE_INTRA_HH :
00159         case MM_TYPE_INTER_HH :
00160         case MM_TYPE_INTRA_HHV :
00161         case MM_TYPE_INTER_HHV :
00162             /* output preamble + data */
00163             if (av_new_packet(pkt, length + MM_PREAMBLE_SIZE))
00164                 return AVERROR(ENOMEM);
00165             memcpy(pkt->data, preamble, MM_PREAMBLE_SIZE);
00166             if (avio_read(pb, pkt->data + MM_PREAMBLE_SIZE, length) != length)
00167                 return AVERROR(EIO);
00168             pkt->size = length + MM_PREAMBLE_SIZE;
00169             pkt->stream_index = 0;
00170             pkt->pts = mm->video_pts;
00171             if (type!=MM_TYPE_PALETTE)
00172                 mm->video_pts++;
00173             return 0;
00174 
00175         case MM_TYPE_AUDIO :
00176             if (av_get_packet(s->pb, pkt, length)<0)
00177                 return AVERROR(ENOMEM);
00178             pkt->stream_index = 1;
00179             pkt->pts = mm->audio_pts++;
00180             return 0;
00181 
00182         default :
00183             av_log(s, AV_LOG_INFO, "unknown chunk type 0x%x\n", type);
00184             avio_skip(pb, length);
00185         }
00186     }
00187 }
00188 
00189 AVInputFormat ff_mm_demuxer = {
00190     .name           = "mm",
00191     .long_name      = NULL_IF_CONFIG_SMALL("American Laser Games MM format"),
00192     .priv_data_size = sizeof(MmDemuxContext),
00193     .read_probe     = probe,
00194     .read_header    = read_header,
00195     .read_packet    = read_packet,
00196 };
Generated on Fri Feb 1 2013 14:34:52 for FFmpeg by doxygen 1.7.1