Revision 4e114829

View differences:

CREDITS
30 30
Jeff Muizelaar
31 31
Michael Niedermayer
32 32
François Revol
33
Peter Ross
33 34
Måns Rullgård
34 35
Roman Shaposhnik
35 36
Dieter Shirley
Changelog
36 36
- AIFF/AIFF-C audio format, encoding and decoding
37 37
- ADTS AAC file reading and writing
38 38
- Creative VOC file reading and writing
39
- American Laser Games multimedia (*.mm) playback system
39 40

  
40 41
version 0.4.9-pre1:
41 42

  
doc/ffmpeg-doc.texi
698 698
@item Nullsoft Video (NSV) format @tab    @tab X
699 699
@item ADTS AAC audio @tab X @tab X
700 700
@item Creative VOC @tab X @tab X @tab Created for the Sound Blaster Pro.
701
@item American Laser Games MM  @tab    @tab X
702
@tab Multimedia format used in games like Mad Dog McCree
701 703
@end multitable
702 704

  
703 705
@code{X} means that encoding (resp. decoding) is supported.
......
788 790
@item Autodesk Animator Studio Codec  @tab     @tab  X @tab fourcc: AASC
789 791
@item Fraps FPS1             @tab     @tab  X @tab
790 792
@item CamStudio              @tab     @tab  X @tab fourcc: CSCD
793
@item American Laser Games Video  @tab    @tab X @tab Used in games like Mad Dog McCree
791 794
@end multitable
792 795

  
793 796
@code{X} means that encoding (resp. decoding) is supported.
libavcodec/Makefile
218 218
ifeq ($(CONFIG_BMP_DECODER),yes)
219 219
	OBJS+= bmp.o
220 220
endif
221
ifeq ($(CONFIG_MMVIDEO_DECODER),yes)
222
	OBJS+= mmvideo.o
223
endif
221 224

  
222 225
AMROBJS=
223 226
ifeq ($(AMR_NB),yes)
libavcodec/allcodecs.c
539 539
    register_avcodec(&bmp_decoder);
540 540
#endif
541 541

  
542
#if CONFIG_MMVIDEO_DECODER
543
    register_avcodec(&mmvideo_decoder);
544
#endif //CONFIG_MMVIDEO_DECODER
545

  
542 546
    /* pcm codecs */
543 547
#if defined (CONFIG_ENCODERS) && defined (CONFIG_DECODERS)
544 548
    #define PCM_CODEC(id, name) \
libavcodec/avcodec.h
115 115
    CODEC_ID_TRUEMOTION2,
116 116
    CODEC_ID_BMP,
117 117
    CODEC_ID_CSCD,
118
    CODEC_ID_MMVIDEO,
118 119

  
119 120
    /* various pcm "codecs" */
120 121
    CODEC_ID_PCM_S16LE= 0x10000,
......
2226 2227
extern AVCodec libgsm_encoder;
2227 2228
extern AVCodec libgsm_decoder;
2228 2229
extern AVCodec bmp_decoder;
2230
extern AVCodec mmvideo_decoder;
2229 2231

  
2230 2232
/* pcm codecs */
2231 2233
#define PCM_CODEC(id, name) \
libavcodec/mmvideo.c
1
/*
2
 * American Laser Games MM Video Decoder
3
 * Copyright (c) 2006 Peter Ross
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19

  
20
/**
21
 * @file mm.c
22
 * American Laser Games MM Video Decoder
23
 * by Peter Ross (suxen_drol at hotmail dot com)
24
 *
25
 * The MM format was used by IBM-PC ports of ALG's "arcade shooter" games,
26
 * including Mad Dog McCree and Crime Patrol.
27
 *
28
 * Technical details here:
29
 *  http://wiki.multimedia.cx/index.php?title=American_Laser_Games_MM
30
 */
31

  
32
#include "avcodec.h"
33

  
34
#define MM_PREAMBLE_SIZE    6
35

  
36
#define MM_TYPE_INTER       0x5
37
#define MM_TYPE_INTRA       0x8
38
#define MM_TYPE_INTRA_HH    0xc
39
#define MM_TYPE_INTER_HH    0xd
40
#define MM_TYPE_INTRA_HHV   0xe
41
#define MM_TYPE_INTER_HHV   0xf
42

  
43
typedef struct MmContext {
44
    AVCodecContext *avctx;
45
    AVFrame frame;
46
} MmContext;
47

  
48
static int mm_decode_init(AVCodecContext *avctx)
49
{
50
    MmContext *s = avctx->priv_data;
51

  
52
    s->avctx = avctx;
53

  
54
    if (s->avctx->palctrl == NULL) {
55
        av_log(avctx, AV_LOG_ERROR, "mmvideo: palette expected.\n");
56
        return -1;
57
    }
58

  
59
    avctx->pix_fmt = PIX_FMT_PAL8;
60
    avctx->has_b_frames = 0;
61

  
62
    if (avcodec_check_dimensions(avctx, avctx->width, avctx->height))
63
        return -1;
64

  
65
    s->frame.reference = 1;
66
    if (avctx->get_buffer(avctx, &s->frame)) {
67
        av_log(s->avctx, AV_LOG_ERROR, "mmvideo: get_buffer() failed\n");
68
        return -1;
69
    }
70

  
71
    return 0;
72
}
73

  
74
static void mm_decode_intra(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size)
75
{
76
    int i, x, y;
77
    i=0; x=0; y=0;
78

  
79
    while(i<buf_size) {
80
        int run_length, color;
81

  
82
        if (buf[i] & 0x80) {
83
            run_length = 1;
84
            color = buf[i];
85
            i++;
86
        }else{
87
            run_length = (buf[i] & 0x7f) + 2;
88
            color = buf[i+1];
89
            i+=2;
90
        }
91

  
92
        if (half_horiz)
93
            run_length *=2;
94

  
95
        if (color) {
96
            memset(s->frame.data[0] + y*s->frame.linesize[0] + x, color, run_length);
97
            if (half_vert)
98
                memset(s->frame.data[0] + (y+1)*s->frame.linesize[0] + x, color, run_length);
99
        }
100
        x+= run_length;
101

  
102
        if (x >= s->avctx->width) {
103
            x=0;
104
            y += half_vert ? 2 : 1;
105
        }
106
    }
107
}
108

  
109
static void mm_decode_inter(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size)
110
{
111
    const int data_ptr = 2 + LE_16(&buf[0]);
112
    int d, r, y;
113
    d = data_ptr; r = 2; y = 0;
114

  
115
    while(r < data_ptr) {
116
        int i, j;
117
        int length = buf[r] & 0x7f;
118
        int x = buf[r+1] + ((buf[r] & 0x80) << 1);
119
        r += 2;
120

  
121
        if (length==0) {
122
            y += x;
123
            continue;
124
        }
125

  
126
        for(i=0; i<length; i++) {
127
            for(j=0; j<8; j++) {
128
                int replace = (buf[r+i] >> (7-j)) & 1;
129
                if (replace) {
130
                    int color = buf[d];
131
                    s->frame.data[0][y*s->frame.linesize[0] + x] = color;
132
                    if (half_horiz)
133
                        s->frame.data[0][y*s->frame.linesize[0] + x + 1] = color;
134
                    if (half_vert) {
135
                        s->frame.data[0][(y+1)*s->frame.linesize[0] + x] = color;
136
                        if (half_horiz)
137
                            s->frame.data[0][(y+1)*s->frame.linesize[0] + x + 1] = color;
138
                    }
139
                    d++;
140
                }
141
                x += half_horiz ? 2 : 1;
142
            }
143
        }
144

  
145
        r += length;
146
        y += half_vert ? 2 : 1;
147
    }
148
}
149

  
150
static int mm_decode_frame(AVCodecContext *avctx,
151
                            void *data, int *data_size,
152
                            uint8_t *buf, int buf_size)
153
{
154
    MmContext *s = avctx->priv_data;
155
    AVPaletteControl *palette_control = avctx->palctrl;
156
    int type;
157

  
158
    if (palette_control->palette_changed) {
159
        memcpy(s->frame.data[1], palette_control->palette, AVPALETTE_SIZE);
160
        palette_control->palette_changed = 0;
161
    }
162

  
163
    type = LE_16(&buf[0]);
164
    buf += MM_PREAMBLE_SIZE;
165
    buf_size -= MM_PREAMBLE_SIZE;
166

  
167
    switch(type) {
168
    case MM_TYPE_INTRA     : mm_decode_intra(s, 0, 0, buf, buf_size); break;
169
    case MM_TYPE_INTRA_HH  : mm_decode_intra(s, 1, 0, buf, buf_size); break;
170
    case MM_TYPE_INTRA_HHV : mm_decode_intra(s, 1, 1, buf, buf_size); break;
171
    case MM_TYPE_INTER     : mm_decode_inter(s, 0, 0, buf, buf_size); break;
172
    case MM_TYPE_INTER_HH  : mm_decode_inter(s, 1, 0, buf, buf_size); break;
173
    case MM_TYPE_INTER_HHV : mm_decode_inter(s, 1, 1, buf, buf_size); break;
174
    default :
175
        return -1;
176
    }
177

  
178
    *data_size = sizeof(AVFrame);
179
    *(AVFrame*)data = s->frame;
180

  
181
    return buf_size;
182
}
183

  
184
static int mm_decode_end(AVCodecContext *avctx)
185
{
186
    MmContext *s = avctx->priv_data;
187

  
188
    if(s->frame.data[0])
189
        avctx->release_buffer(avctx, &s->frame);
190

  
191
    return 0;
192
}
193

  
194
AVCodec mmvideo_decoder = {
195
    "mmvideo",
196
    CODEC_TYPE_VIDEO,
197
    CODEC_ID_MMVIDEO,
198
    sizeof(MmContext),
199
    mm_decode_init,
200
    NULL,
201
    mm_decode_end,
202
    mm_decode_frame,
203
    CODEC_CAP_DR1,
204
};
libavformat/Makefile
23 23
      nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.o \
24 24
      sierravmd.o matroska.o sol.o electronicarts.o nsvdec.o asf.o \
25 25
      ogg2.o oggparsevorbis.o oggparsetheora.o oggparseflac.o daud.o aiff.o \
26
      voc.o tta.o
26
      voc.o tta.o mm.o
27 27

  
28 28
# muxers
29 29
ifeq ($(CONFIG_MUXERS),yes)
libavformat/allformats.c
79 79
    idcin_init();
80 80
    flic_init();
81 81
    vmd_init();
82
    mm_init();
82 83

  
83 84
#if defined(AMR_NB) || defined(AMR_NB_FIXED) || defined(AMR_WB)
84 85
    amr_init();
libavformat/avformat.h
561 561
/* adts.c */
562 562
int ff_adts_init(void);
563 563

  
564
/* mm.c */
565
int mm_init(void);
566

  
564 567
#include "rtp.h"
565 568

  
566 569
#include "rtsp.h"
libavformat/mm.c
1
/*
2
 * American Laser Games MM Format Demuxer
3
 * Copyright (c) 2006 Peter Ross
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19

  
20
/**
21
 * @file mm.c
22
 * American Laser Games MM Format Demuxer
23
 * by Peter Ross (suxen_drol at hotmail dot com)
24
 *
25
 * The MM format was used by IBM-PC ports of ALG's "arcade shooter" games,
26
 * including Mad Dog McCree and Crime Patrol.
27
 *
28
 * Technical details here:
29
 *  http://wiki.multimedia.cx/index.php?title=American_Laser_Games_MM
30
 */
31

  
32
#include "avformat.h"
33

  
34
#define MM_PREAMBLE_SIZE    6
35

  
36
#define MM_TYPE_HEADER      0x0
37
#define MM_TYPE_INTER       0x5
38
#define MM_TYPE_INTRA       0x8
39
#define MM_TYPE_INTRA_HH    0xc
40
#define MM_TYPE_INTER_HH    0xd
41
#define MM_TYPE_INTRA_HHV   0xe
42
#define MM_TYPE_INTER_HHV   0xf
43
#define MM_TYPE_AUDIO       0x15
44
#define MM_TYPE_PALETTE     0x31
45

  
46
#define MM_HEADER_LEN_V     0x16    /* video only */
47
#define MM_HEADER_LEN_AV    0x18    /* video + audio */
48

  
49
#define MM_PALETTE_COUNT    128
50
#define MM_PALETTE_SIZE     (MM_PALETTE_COUNT*3)
51

  
52
typedef struct {
53
  AVPaletteControl palette_control;
54
  unsigned int audio_pts, video_pts;
55
} MmDemuxContext;
56

  
57
static int mm_probe(AVProbeData *p)
58
{
59
    /* the first chunk is always the header */
60
    if (p->buf_size < MM_PREAMBLE_SIZE)
61
        return 0;
62
    if (LE_16(&p->buf[0]) != MM_TYPE_HEADER)
63
        return 0;
64
    if (LE_32(&p->buf[2]) != MM_HEADER_LEN_V && LE_32(&p->buf[2]) != MM_HEADER_LEN_AV)
65
        return 0;
66

  
67
    /* only return half certainty since this check is a bit sketchy */
68
    return AVPROBE_SCORE_MAX / 2;
69
}
70

  
71
static int mm_read_header(AVFormatContext *s,
72
                           AVFormatParameters *ap)
73
{
74
    MmDemuxContext *mm = (MmDemuxContext *)s->priv_data;
75
    ByteIOContext *pb = &s->pb;
76
    AVStream *st;
77

  
78
    unsigned int type, length;
79
    unsigned int frame_rate, width, height;
80

  
81
    type = get_le16(pb);
82
    length = get_le32(pb);
83

  
84
    if (type != MM_TYPE_HEADER)
85
        return AVERROR_INVALIDDATA;
86

  
87
    /* read header */
88
    get_le16(pb);   /* total number of chunks */
89
    frame_rate = get_le16(pb);
90
    get_le16(pb);   /* ibm-pc video bios mode */
91
    width = get_le16(pb);
92
    height = get_le16(pb);
93
    url_fseek(pb, length - 10, SEEK_CUR);  /* unknown data */
94

  
95
    /* video stream */
96
    st = av_new_stream(s, 0);
97
    if (!st)
98
        return AVERROR_NOMEM;
99
    st->codec->codec_type = CODEC_TYPE_VIDEO;
100
    st->codec->codec_id = CODEC_ID_MMVIDEO;
101
    st->codec->codec_tag = 0;  /* no fourcc */
102
    st->codec->width = width;
103
    st->codec->height = height;
104
    st->codec->palctrl = &mm->palette_control;
105
    av_set_pts_info(st, 64, 1, frame_rate);
106

  
107
    /* audio stream */
108
    if (length == MM_HEADER_LEN_AV) {
109
        st = av_new_stream(s, 0);
110
        if (!st)
111
            return AVERROR_NOMEM;
112
        st->codec->codec_type = CODEC_TYPE_AUDIO;
113
        st->codec->codec_tag = 0; /* no fourcc */
114
        st->codec->codec_id = CODEC_ID_PCM_U8;
115
        st->codec->channels = 1;
116
        st->codec->sample_rate = 8000;
117
        av_set_pts_info(st, 64, 1, 8000); /* 8000 hz */
118
    }
119

  
120
    mm->palette_control.palette_changed = 0;
121
    mm->audio_pts = 0;
122
    mm->video_pts = 0;
123
    return 0;
124
}
125

  
126
static int mm_read_packet(AVFormatContext *s,
127
                           AVPacket *pkt)
128
{
129
    MmDemuxContext *mm = (MmDemuxContext *)s->priv_data;
130
    ByteIOContext *pb = &s->pb;
131
    unsigned char preamble[MM_PREAMBLE_SIZE];
132
    unsigned char pal[MM_PALETTE_SIZE];
133
    unsigned int type, length;
134
    int i;
135

  
136
    while(1) {
137

  
138
        if (get_buffer(pb, preamble, MM_PREAMBLE_SIZE) != MM_PREAMBLE_SIZE) {
139
            return AVERROR_IO;
140
        }
141

  
142
        type = LE_16(&preamble[0]);
143
        length = LE_16(&preamble[2]);
144

  
145
        switch(type) {
146
        case MM_TYPE_PALETTE :
147
            url_fseek(pb, 4, SEEK_CUR);  /* unknown data */
148
            if (get_buffer(pb, pal, MM_PALETTE_SIZE) != MM_PALETTE_SIZE)
149
                return AVERROR_IO;
150
            url_fseek(pb, length - (4 + MM_PALETTE_SIZE), SEEK_CUR);
151

  
152
            for (i=0; i<MM_PALETTE_COUNT; i++) {
153
                int r = pal[i*3 + 0];
154
                int g = pal[i*3 + 1];
155
                int b = pal[i*3 + 2];
156
                mm->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
157
                /* repeat palette, where each components is multiplied by four */
158
                mm->palette_control.palette[i+128] = (r << 18) | (g << 10) | (b<<2);
159
            }
160
            mm->palette_control.palette_changed = 1;
161
            break;
162

  
163
        case MM_TYPE_INTER :
164
        case MM_TYPE_INTRA :
165
        case MM_TYPE_INTRA_HH :
166
        case MM_TYPE_INTER_HH :
167
        case MM_TYPE_INTRA_HHV :
168
        case MM_TYPE_INTER_HHV :
169
            /* output preamble + data */
170
            if (av_new_packet(pkt, length + MM_PREAMBLE_SIZE))
171
                return AVERROR_NOMEM;
172
            memcpy(pkt->data, preamble, MM_PREAMBLE_SIZE);
173
            if (get_buffer(pb, pkt->data + MM_PREAMBLE_SIZE, length) != length)
174
                return AVERROR_IO;
175
            pkt->size = length + MM_PREAMBLE_SIZE;
176
            pkt->stream_index = 0;
177
            pkt->pts = mm->video_pts++;
178
            return 0;
179

  
180
        case MM_TYPE_AUDIO :
181
            if (av_get_packet(&s->pb, pkt, length)<0)
182
                return AVERROR_NOMEM;
183
            pkt->size = length;
184
            pkt->stream_index = 1;
185
            pkt->pts = mm->audio_pts++;
186
            return 0;
187

  
188
        default :
189
            av_log(NULL, AV_LOG_INFO, "mm: unknown chunk type 0x%x\n", type);
190
            url_fseek(pb, length, SEEK_CUR);
191
        }
192
    }
193

  
194
    return 0;
195
}
196

  
197
static int mm_read_close(AVFormatContext *s)
198
{
199
    return 0;
200
}
201

  
202
static AVInputFormat mm_iformat = {
203
    "mm",
204
    "American Laser Games MM format",
205
    sizeof(MmDemuxContext),
206
    mm_probe,
207
    mm_read_header,
208
    mm_read_packet,
209
    mm_read_close,
210
};
211

  
212
int mm_init(void)
213
{
214
    av_register_input_format(&mm_iformat);
215
    return 0;
216
}

Also available in: Unified diff