00001 /* 00002 * American Laser Games MM Video Decoder 00003 * Copyright (c) 2006,2008 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 "avcodec.h" 00036 00037 #define MM_PREAMBLE_SIZE 6 00038 00039 #define MM_TYPE_INTER 0x5 00040 #define MM_TYPE_INTRA 0x8 00041 #define MM_TYPE_INTRA_HH 0xc 00042 #define MM_TYPE_INTER_HH 0xd 00043 #define MM_TYPE_INTRA_HHV 0xe 00044 #define MM_TYPE_INTER_HHV 0xf 00045 #define MM_TYPE_PALETTE 0x31 00046 00047 typedef struct MmContext { 00048 AVCodecContext *avctx; 00049 AVFrame frame; 00050 int palette[AVPALETTE_COUNT]; 00051 } MmContext; 00052 00053 static av_cold int mm_decode_init(AVCodecContext *avctx) 00054 { 00055 MmContext *s = avctx->priv_data; 00056 00057 s->avctx = avctx; 00058 00059 avctx->pix_fmt = PIX_FMT_PAL8; 00060 00061 if (avcodec_check_dimensions(avctx, avctx->width, avctx->height)) 00062 return -1; 00063 00064 s->frame.reference = 1; 00065 if (avctx->get_buffer(avctx, &s->frame)) { 00066 av_log(s->avctx, AV_LOG_ERROR, "mmvideo: get_buffer() failed\n"); 00067 return -1; 00068 } 00069 00070 return 0; 00071 } 00072 00073 static void mm_decode_pal(MmContext *s, const uint8_t *buf, const uint8_t *buf_end) 00074 { 00075 int i; 00076 buf += 4; 00077 for (i=0; i<128 && buf+2<buf_end; i++) { 00078 s->palette[i] = AV_RB24(buf); 00079 s->palette[i+128] = s->palette[i]<<2; 00080 buf += 3; 00081 } 00082 } 00083 00084 static void mm_decode_intra(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size) 00085 { 00086 int i, x, y; 00087 i=0; x=0; y=0; 00088 00089 while(i<buf_size) { 00090 int run_length, color; 00091 00092 if (buf[i] & 0x80) { 00093 run_length = 1; 00094 color = buf[i]; 00095 i++; 00096 }else{ 00097 run_length = (buf[i] & 0x7f) + 2; 00098 color = buf[i+1]; 00099 i+=2; 00100 } 00101 00102 if (half_horiz) 00103 run_length *=2; 00104 00105 if (color) { 00106 memset(s->frame.data[0] + y*s->frame.linesize[0] + x, color, run_length); 00107 if (half_vert) 00108 memset(s->frame.data[0] + (y+1)*s->frame.linesize[0] + x, color, run_length); 00109 } 00110 x+= run_length; 00111 00112 if (x >= s->avctx->width) { 00113 x=0; 00114 y += half_vert ? 2 : 1; 00115 } 00116 } 00117 } 00118 00119 static void mm_decode_inter(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size) 00120 { 00121 const int data_ptr = 2 + AV_RL16(&buf[0]); 00122 int d, r, y; 00123 d = data_ptr; r = 2; y = 0; 00124 00125 while(r < data_ptr) { 00126 int i, j; 00127 int length = buf[r] & 0x7f; 00128 int x = buf[r+1] + ((buf[r] & 0x80) << 1); 00129 r += 2; 00130 00131 if (length==0) { 00132 y += x; 00133 continue; 00134 } 00135 00136 for(i=0; i<length; i++) { 00137 for(j=0; j<8; j++) { 00138 int replace = (buf[r+i] >> (7-j)) & 1; 00139 if (replace) { 00140 int color = buf[d]; 00141 s->frame.data[0][y*s->frame.linesize[0] + x] = color; 00142 if (half_horiz) 00143 s->frame.data[0][y*s->frame.linesize[0] + x + 1] = color; 00144 if (half_vert) { 00145 s->frame.data[0][(y+1)*s->frame.linesize[0] + x] = color; 00146 if (half_horiz) 00147 s->frame.data[0][(y+1)*s->frame.linesize[0] + x + 1] = color; 00148 } 00149 d++; 00150 } 00151 x += half_horiz ? 2 : 1; 00152 } 00153 } 00154 00155 r += length; 00156 y += half_vert ? 2 : 1; 00157 } 00158 } 00159 00160 static int mm_decode_frame(AVCodecContext *avctx, 00161 void *data, int *data_size, 00162 const uint8_t *buf, int buf_size) 00163 { 00164 MmContext *s = avctx->priv_data; 00165 const uint8_t *buf_end = buf+buf_size; 00166 int type; 00167 00168 type = AV_RL16(&buf[0]); 00169 buf += MM_PREAMBLE_SIZE; 00170 buf_size -= MM_PREAMBLE_SIZE; 00171 00172 switch(type) { 00173 case MM_TYPE_PALETTE : mm_decode_pal(s, buf, buf_end); return buf_size; 00174 case MM_TYPE_INTRA : mm_decode_intra(s, 0, 0, buf, buf_size); break; 00175 case MM_TYPE_INTRA_HH : mm_decode_intra(s, 1, 0, buf, buf_size); break; 00176 case MM_TYPE_INTRA_HHV : mm_decode_intra(s, 1, 1, buf, buf_size); break; 00177 case MM_TYPE_INTER : mm_decode_inter(s, 0, 0, buf, buf_size); break; 00178 case MM_TYPE_INTER_HH : mm_decode_inter(s, 1, 0, buf, buf_size); break; 00179 case MM_TYPE_INTER_HHV : mm_decode_inter(s, 1, 1, buf, buf_size); break; 00180 default : 00181 return -1; 00182 } 00183 00184 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); 00185 00186 *data_size = sizeof(AVFrame); 00187 *(AVFrame*)data = s->frame; 00188 00189 return buf_size; 00190 } 00191 00192 static av_cold int mm_decode_end(AVCodecContext *avctx) 00193 { 00194 MmContext *s = avctx->priv_data; 00195 00196 if(s->frame.data[0]) 00197 avctx->release_buffer(avctx, &s->frame); 00198 00199 return 0; 00200 } 00201 00202 AVCodec mmvideo_decoder = { 00203 "mmvideo", 00204 CODEC_TYPE_VIDEO, 00205 CODEC_ID_MMVIDEO, 00206 sizeof(MmContext), 00207 mm_decode_init, 00208 NULL, 00209 mm_decode_end, 00210 mm_decode_frame, 00211 CODEC_CAP_DR1, 00212 .long_name = NULL_IF_CONFIG_SMALL("American Laser Games MM Video"), 00213 };