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