Libav 0.7.1
|
00001 /* 00002 * American Laser Games MM Video Decoder 00003 * Copyright (c) 2006,2008 Peter Ross 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav 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 * Libav 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 Libav; 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 00063 return 0; 00064 } 00065 00066 static void mm_decode_pal(MmContext *s, const uint8_t *buf, const uint8_t *buf_end) 00067 { 00068 int i; 00069 buf += 4; 00070 for (i=0; i<128 && buf+2<buf_end; i++) { 00071 s->palette[i] = AV_RB24(buf); 00072 s->palette[i+128] = s->palette[i]<<2; 00073 buf += 3; 00074 } 00075 } 00076 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 (y >= s->avctx->height) 00090 return; 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 += 1 + half_vert; 00115 } 00116 } 00117 } 00118 00119 /* 00120 * @param half_horiz Half horizontal resolution (0 or 1) 00121 * @param half_vert Half vertical resolution (0 or 1) 00122 */ 00123 static void mm_decode_inter(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size) 00124 { 00125 const int data_ptr = 2 + AV_RL16(&buf[0]); 00126 int d, r, y; 00127 d = data_ptr; r = 2; y = 0; 00128 00129 while(r < data_ptr) { 00130 int i, j; 00131 int length = buf[r] & 0x7f; 00132 int x = buf[r+1] + ((buf[r] & 0x80) << 1); 00133 r += 2; 00134 00135 if (length==0) { 00136 y += x; 00137 continue; 00138 } 00139 00140 if (y + half_vert >= s->avctx->height) 00141 return; 00142 00143 for(i=0; i<length; i++) { 00144 for(j=0; j<8; j++) { 00145 int replace = (buf[r+i] >> (7-j)) & 1; 00146 if (replace) { 00147 int color = buf[d]; 00148 s->frame.data[0][y*s->frame.linesize[0] + x] = color; 00149 if (half_horiz) 00150 s->frame.data[0][y*s->frame.linesize[0] + x + 1] = color; 00151 if (half_vert) { 00152 s->frame.data[0][(y+1)*s->frame.linesize[0] + x] = color; 00153 if (half_horiz) 00154 s->frame.data[0][(y+1)*s->frame.linesize[0] + x + 1] = color; 00155 } 00156 d++; 00157 } 00158 x += 1 + half_horiz; 00159 } 00160 } 00161 00162 r += length; 00163 y += 1 + half_vert; 00164 } 00165 } 00166 00167 static int mm_decode_frame(AVCodecContext *avctx, 00168 void *data, int *data_size, 00169 AVPacket *avpkt) 00170 { 00171 const uint8_t *buf = avpkt->data; 00172 int buf_size = avpkt->size; 00173 MmContext *s = avctx->priv_data; 00174 const uint8_t *buf_end = buf+buf_size; 00175 int type; 00176 00177 type = AV_RL16(&buf[0]); 00178 buf += MM_PREAMBLE_SIZE; 00179 buf_size -= MM_PREAMBLE_SIZE; 00180 00181 if (avctx->reget_buffer(avctx, &s->frame) < 0) { 00182 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00183 return -1; 00184 } 00185 00186 switch(type) { 00187 case MM_TYPE_PALETTE : mm_decode_pal(s, buf, buf_end); return buf_size; 00188 case MM_TYPE_INTRA : mm_decode_intra(s, 0, 0, buf, buf_size); break; 00189 case MM_TYPE_INTRA_HH : mm_decode_intra(s, 1, 0, buf, buf_size); break; 00190 case MM_TYPE_INTRA_HHV : mm_decode_intra(s, 1, 1, buf, buf_size); break; 00191 case MM_TYPE_INTER : mm_decode_inter(s, 0, 0, buf, buf_size); break; 00192 case MM_TYPE_INTER_HH : mm_decode_inter(s, 1, 0, buf, buf_size); break; 00193 case MM_TYPE_INTER_HHV : mm_decode_inter(s, 1, 1, buf, buf_size); break; 00194 default : 00195 return -1; 00196 } 00197 00198 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); 00199 00200 *data_size = sizeof(AVFrame); 00201 *(AVFrame*)data = s->frame; 00202 00203 return buf_size; 00204 } 00205 00206 static av_cold int mm_decode_end(AVCodecContext *avctx) 00207 { 00208 MmContext *s = avctx->priv_data; 00209 00210 if(s->frame.data[0]) 00211 avctx->release_buffer(avctx, &s->frame); 00212 00213 return 0; 00214 } 00215 00216 AVCodec ff_mmvideo_decoder = { 00217 "mmvideo", 00218 AVMEDIA_TYPE_VIDEO, 00219 CODEC_ID_MMVIDEO, 00220 sizeof(MmContext), 00221 mm_decode_init, 00222 NULL, 00223 mm_decode_end, 00224 mm_decode_frame, 00225 CODEC_CAP_DR1, 00226 .long_name = NULL_IF_CONFIG_SMALL("American Laser Games MM Video"), 00227 };