History

Electronic Arts Madcow decoder

Originally committed as revision 19178 to svn://svn.ffmpeg.org/ffmpeg/trunk

Peter Ross committed 17 years ago

Commit c63ea921 parent 86b61d46 files · +324 −1Browse files

Unified · Split

6 files
  1. Changelog +1 −0
  2. doc/general.texi +1 −0
  3. libavcodec/Makefile +1 −0
  4. libavcodec/allcodecs.c +1 −0
  5. libavcodec/avcodec.h +2 −1
  6. libavcodec/eamad.c +318 −0
Changelog+1−0
@@ -24,6 +24,7 @@ version <next>: · 23 unmodified lines
2424 - SoX native format muxer and demuxer
2525 - AMR-NB decoding/encoding, AMR-WB decoding via OpenCORE libraries
2626 - DPX image decoder
27+- Electronic Arts Madcow decoder
2728
2829
2930
doc/general.texi+1−0
@@ -356,6 +356,7 @@ following image formats are supported: · 355 unmodified lines
356356 @tab Codec originally used in Feeble Files game.
357357 @item Electronic Arts CMV video @tab @tab X
358358 @tab Used in NHL 95 game.
359+@item Electronic Arts Madcow video @tab @tab X
359360 @item Electronic Arts TGV video @tab @tab X
360361 @item Electronic Arts TGQ video @tab @tab X
361362 @item Electronic Arts TQI video @tab @tab X
libavcodec/Makefile+1−0
@@ -76,6 +76,7 @@ OBJS-$(CONFIG_DVVIDEO_ENCODER) += dv.o · 75 unmodified lines
7676 OBJS-$(CONFIG_DXA_DECODER) += dxa.o
7777 OBJS-$(CONFIG_EAC3_DECODER) += eac3dec.o ac3dec.o ac3tab.o ac3dec_data.o ac3.o
7878 OBJS-$(CONFIG_EACMV_DECODER) += eacmv.o
79+OBJS-$(CONFIG_EAMAD_DECODER) += eamad.o eaidct.o
7980 OBJS-$(CONFIG_EATGQ_DECODER) += eatgq.o eaidct.o
8081 OBJS-$(CONFIG_EATGV_DECODER) += eatgv.o
8182 OBJS-$(CONFIG_EATQI_DECODER) += eatqi.o eaidct.o mpeg12.o mpeg12data.o mpegvideo.o error_resilience.o
libavcodec/allcodecs.c+1−0
@@ -81,6 +81,7 @@ void avcodec_register_all(void) · 80 unmodified lines
8181 REGISTER_ENCDEC (DVVIDEO, dvvideo);
8282 REGISTER_DECODER (DXA, dxa);
8383 REGISTER_DECODER (EACMV, eacmv);
84+ REGISTER_DECODER (EAMAD, eamad);
8485 REGISTER_DECODER (EATGQ, eatgq);
8586 REGISTER_DECODER (EATGV, eatgv);
8687 REGISTER_DECODER (EATQI, eatqi);
libavcodec/avcodec.h+2−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #include "libavutil/avutil.h"
3131
3232 #define LIBAVCODEC_VERSION_MAJOR 52
33−#define LIBAVCODEC_VERSION_MINOR 30
33+#define LIBAVCODEC_VERSION_MINOR 31
3434 #define LIBAVCODEC_VERSION_MICRO 2
3535
3636 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
@@ -197,6 +197,7 @@ enum CodecID { · 160 unmodified lines
197197 CODEC_ID_TMV,
198198 CODEC_ID_V210,
199199 CODEC_ID_DPX,
200+ CODEC_ID_MAD,
200201
201202 /* various PCM "codecs" */
202203 CODEC_ID_PCM_S16LE= 0x10000,
libavcodec/eamad.c+318−0
@@ -0,0 +1,318 @@
1+/*
2+ * Electronic Arts Madcow Video Decoder
3+ * Copyright (c) 2007-2009 Peter Ross
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 St, Fifth Floor, Boston, MA 02110-1301 USA
20+ */
21+
22+/**
23+ * @file libavcodec/eamad.c
24+ * Electronic Arts Madcow Video Decoder
25+ * by Peter Ross <pross@xvid.org>
26+ *
27+ * Technical details here:
28+ * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_MAD
29+ */
30+
31+#include "avcodec.h"
32+#include "get_bits.h"
33+#include "dsputil.h"
34+#include "aandcttab.h"
35+#include "mpeg12.h"
36+#include "mpeg12data.h"
37+
38+#define EA_PREAMBLE_SIZE 8
39+#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD i-frame */
40+#define MADm_TAG MKTAG('M', 'A', 'D', 'm') /* MAD p-frame */
41+#define MADe_TAG MKTAG('M', 'A', 'D', 'e') /* MAD lqp-frame */
42+
43+typedef struct MadContext {
44+ MpegEncContext s;
45+ AVFrame frame;
46+ AVFrame last_frame;
47+ void *bitstream_buf;
48+ unsigned int bitstream_buf_size;
49+ DECLARE_ALIGNED_16(DCTELEM, block[64]);
50+} MadContext;
51+
52+static void bswap16_buf(uint16_t *dst, const uint16_t *src, int count)
53+{
54+ int i;
55+ for (i=0; i<count; i++)
56+ dst[i] = bswap_16(src[i]);
57+}
58+
59+static av_cold int decode_init(AVCodecContext *avctx)
60+{
61+ MadContext *t = avctx->priv_data;
62+ MpegEncContext *s = &t->s;
63+ s->avctx = avctx;
64+ avctx->pix_fmt = PIX_FMT_YUV420P;
65+ if (avctx->idct_algo == FF_IDCT_AUTO)
66+ avctx->idct_algo = FF_IDCT_EA;
67+ dsputil_init(&s->dsp, avctx);
68+ ff_init_scantable(s->dsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct);
69+ ff_mpeg12_init_vlcs();
70+ return 0;
71+}
72+
73+static inline void comp(unsigned char *dst, int dst_stride,
74+ unsigned char *src, int src_stride, int add)
75+{
76+ int j, i;
77+ for (j=0; j<8; j++)
78+ for (i=0; i<8; i++)
79+ dst[j*dst_stride + i] = av_clip_uint8(src[j*src_stride + i] + add);
80+}
81+
82+static inline void comp_block(MadContext *t, int mb_x, int mb_y,
83+ int j, int mv_x, int mv_y, int add)
84+{
85+ MpegEncContext *s = &t->s;
86+ if (j < 4) {
87+ comp(t->frame.data[0] + (mb_y*16 + ((j&2)<<2))*t->frame.linesize[0] + mb_x*16 + ((j&1)<<3),
88+ t->frame.linesize[0],
89+ t->last_frame.data[0] + (mb_y*16 + ((j&2)<<2) + mv_y)*t->last_frame.linesize[0] + mb_x*16 + ((j&1)<<3) + mv_x,
90+ t->last_frame.linesize[0], add);
91+ } else if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
92+ int index = j - 3;
93+ comp(t->frame.data[index] + (mb_y*8)*t->frame.linesize[index] + mb_x * 8,
94+ t->frame.linesize[index],
95+ t->last_frame.data[index] + (mb_y * 8 + (mv_y/2))*t->last_frame.linesize[index] + mb_x * 8 + (mv_x/2),
96+ t->last_frame.linesize[index], add);
97+ }
98+}
99+
100+static inline void idct_put(MadContext *t, DCTELEM *block, int mb_x, int mb_y, int j)
101+{
102+ MpegEncContext *s = &t->s;
103+ if (j < 4) {
104+ s->dsp.idct_put(
105+ t->frame.data[0] + (mb_y*16 + ((j&2)<<2))*t->frame.linesize[0] + mb_x*16 + ((j&1)<<3),
106+ t->frame.linesize[0], block);
107+ } else if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
108+ int index = j - 3;
109+ s->dsp.idct_put(
110+ t->frame.data[index] + (mb_y*8)*t->frame.linesize[index] + mb_x*8,
111+ t->frame.linesize[index], block);
112+ }
113+}
114+
115+static inline void decode_block_intra(MadContext * t, DCTELEM * block)
116+{
117+ MpegEncContext *s = &t->s;
118+ int level, i, j, run;
119+ RLTable *rl = &ff_rl_mpeg1;
120+ const uint8_t *scantable = s->intra_scantable.permutated;
121+ int16_t *quant_matrix = s->intra_matrix;
122+
123+ block[0] = (128 + get_sbits(&s->gb, 8)) * quant_matrix[0];
124+
125+ /* The RL decoder is derived from mpeg1_decode_block_intra;
126+ Escaped level and run values a decoded differently */
127+ {
128+ OPEN_READER(re, &s->gb);
129+ /* now quantify & encode AC coefficients */
130+ for (;;) {
131+ UPDATE_CACHE(re, &s->gb);
132+ GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0);
133+
134+ if (level == 127) {
135+ break;
136+ } else if (level != 0) {
137+ i += run;
138+ j = scantable[i];
139+ level = (level*quant_matrix[j]) >> 4;
140+ level = (level-1)|1;
141+ level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1);
142+ LAST_SKIP_BITS(re, &s->gb, 1);
143+ } else {
144+ /* escape */
145+ UPDATE_CACHE(re, &s->gb);
146+ level = SHOW_SBITS(re, &s->gb, 10); SKIP_BITS(re, &s->gb, 10);
147+
148+ UPDATE_CACHE(re, &s->gb);
149+ run = SHOW_UBITS(re, &s->gb, 6)+1; LAST_SKIP_BITS(re, &s->gb, 6);
150+
151+ i += run;
152+ j = scantable[i];
153+ if (level < 0) {
154+ level = -level;
155+ level = (level*quant_matrix[j]) >> 4;
156+ level = (level-1)|1;
157+ level = -level;
158+ } else {
159+ level = (level*quant_matrix[j]) >> 4;
160+ level = (level-1)|1;
161+ }
162+ }
163+ if (i > 63) {
164+ av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y);
165+ return;
166+ }
167+
168+ block[j] = level;
169+ }
170+ CLOSE_READER(re, &s->gb);
171+ }
172+}
173+
174+static int decode_motion(GetBitContext *gb)
175+{
176+ int value = 0;
177+ if (get_bits1(gb)) {
178+ if (get_bits1(gb))
179+ value = -17;
180+ value += get_bits(gb, 4) + 1;
181+ }
182+ return value;
183+}
184+
185+static void decode_mb(MadContext *t, int inter)
186+{
187+ MpegEncContext *s = &t->s;
188+ int mv_map = 0;
189+ int mv_x, mv_y;
190+ int j;
191+
192+ if (inter) {
193+ int v = decode210(&s->gb);
194+ if (v < 2) {
195+ mv_map = v ? get_bits(&s->gb, 6) : 63;
196+ mv_x = decode_motion(&s->gb);
197+ mv_y = decode_motion(&s->gb);
198+ } else {
199+ mv_map = 0;
200+ }
201+ }
202+
203+ for (j=0; j<6; j++) {
204+ if (mv_map & (1<<j)) { // mv_x and mv_y are guarded by mv_map
205+ int add = 2*decode_motion(&s->gb);
206+ comp_block(t, s->mb_x, s->mb_y, j, mv_x, mv_y, add);
207+ } else {
208+ s->dsp.clear_block(t->block);
209+ decode_block_intra(t, t->block);
210+ idct_put(t, t->block, s->mb_x, s->mb_y, j);
211+ }
212+ }
213+}
214+
215+static void calc_intra_matrix(MadContext *t, int qscale)
216+{
217+ MpegEncContext *s = &t->s;
218+ int i;
219+
220+ if (s->avctx->idct_algo == FF_IDCT_EA) {
221+ s->intra_matrix[0] = (ff_inv_aanscales[0]*ff_mpeg1_default_intra_matrix[0]) >> 11;
222+ for (i=1; i<64; i++)
223+ s->intra_matrix[i] = (ff_inv_aanscales[i]*ff_mpeg1_default_intra_matrix[i]*qscale + 32) >> 10;
224+ } else {
225+ s->intra_matrix[0] = ff_mpeg1_default_intra_matrix[0];
226+ for (i=1; i<64; i++)
227+ s->intra_matrix[i] = (ff_mpeg1_default_intra_matrix[i]*qscale) << 1;
228+ }
229+}
230+
231+static int decode_frame(AVCodecContext *avctx,
232+ void *data, int *data_size,
233+ AVPacket *avpkt)
234+{
235+ const uint8_t *buf = avpkt->data;
236+ int buf_size = avpkt->size;
237+ const uint8_t *buf_end = buf+buf_size;
238+ MadContext *t = avctx->priv_data;
239+ MpegEncContext *s = &t->s;
240+ int chunk_type;
241+ int inter;
242+
243+ if (buf_size < 17) {
244+ av_log(avctx, AV_LOG_ERROR, "Input buffer too small\n");
245+ *data_size = 0;
246+ return -1;
247+ }
248+
249+ chunk_type = AV_RL32(&buf[0]);
250+ inter = (chunk_type == MADm_TAG || chunk_type == MADe_TAG);
251+ buf += 8;
252+
253+ av_reduce(&avctx->time_base.num, &avctx->time_base.den,
254+ AV_RL16(&buf[6]), 1000, 1<<30);
255+
256+ s->width = AV_RL16(&buf[8]);
257+ s->height = AV_RL16(&buf[10]);
258+ calc_intra_matrix(t, buf[13]);
259+ buf += 16;
260+
261+ if (avctx->width != s->width || avctx->height != s->height) {
262+ if (avcodec_check_dimensions(avctx, s->width, s->height) < 0)
263+ return -1;
264+ avcodec_set_dimensions(avctx, s->width, s->height);
265+ if (t->frame.data[0])
266+ avctx->release_buffer(avctx, &t->frame);
267+ }
268+
269+ t->frame.reference = 1;
270+ if (!t->frame.data[0]) {
271+ if (avctx->get_buffer(avctx, &t->frame) < 0) {
272+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
273+ return -1;
274+ }
275+ }
276+
277+ av_fast_malloc(&t->bitstream_buf, &t->bitstream_buf_size, (buf_end-buf) + FF_INPUT_BUFFER_PADDING_SIZE);
278+ if (!t->bitstream_buf)
279+ return AVERROR(ENOMEM);
280+ bswap16_buf(t->bitstream_buf, (const uint16_t*)buf, (buf_end-buf)/2);
281+ init_get_bits(&s->gb, t->bitstream_buf, 8*(buf_end-buf));
282+
283+ for (s->mb_y=0; s->mb_y < (avctx->height+15)/16; s->mb_y++)
284+ for (s->mb_x=0; s->mb_x < (avctx->width +15)/16; s->mb_x++)
285+ decode_mb(t, inter);
286+
287+ *data_size = sizeof(AVFrame);
288+ *(AVFrame*)data = t->frame;
289+
290+ if (chunk_type != MADe_TAG)
291+ FFSWAP(AVFrame, t->frame, t->last_frame);
292+
293+ return buf_size;
294+}
295+
296+static av_cold int decode_end(AVCodecContext *avctx)
297+{
298+ MadContext *t = avctx->priv_data;
299+ if (t->frame.data[0])
300+ avctx->release_buffer(avctx, &t->frame);
301+ if (t->last_frame.data[0])
302+ avctx->release_buffer(avctx, &t->last_frame);
303+ av_free(t->bitstream_buf);
304+ return 0;
305+}
306+
307+AVCodec eamad_decoder = {
308+ "eamad",
309+ CODEC_TYPE_VIDEO,
310+ CODEC_ID_MAD,
311+ sizeof(MadContext),
312+ decode_init,
313+ NULL,
314+ decode_end,
315+ decode_frame,
316+ CODEC_CAP_DR1,
317+ .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts Madcow Video")
318+};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t