1/* 2 * Wing Commander III Movie (.mve) File Demuxer 3 * Copyright (c) 2003 The ffmpeg Project 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 Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * Wing Commander III Movie file demuxer 25 * by Mike Melanson (melanson@pcisys.net) 26 * for more information on the WC3 .mve file format, visit: 27 * http://www.pcisys.net/~melanson/codecs/ 28 */ 29 30#include "libavutil/intreadwrite.h" 31#include "avformat.h" 32 33#define FORM_TAG MKTAG('F', 'O', 'R', 'M') 34#define MOVE_TAG MKTAG('M', 'O', 'V', 'E') 35#define PC__TAG MKTAG('_', 'P', 'C', '_') 36#define SOND_TAG MKTAG('S', 'O', 'N', 'D') 37#define BNAM_TAG MKTAG('B', 'N', 'A', 'M') 38#define SIZE_TAG MKTAG('S', 'I', 'Z', 'E') 39#define PALT_TAG MKTAG('P', 'A', 'L', 'T') 40#define INDX_TAG MKTAG('I', 'N', 'D', 'X') 41#define BRCH_TAG MKTAG('B', 'R', 'C', 'H') 42#define SHOT_TAG MKTAG('S', 'H', 'O', 'T') 43#define VGA__TAG MKTAG('V', 'G', 'A', ' ') 44#define TEXT_TAG MKTAG('T', 'E', 'X', 'T') 45#define AUDI_TAG MKTAG('A', 'U', 'D', 'I') 46 47/* video resolution unless otherwise specified */ 48#define WC3_DEFAULT_WIDTH 320 49#define WC3_DEFAULT_HEIGHT 165 50 51/* always use the same PCM audio parameters */ 52#define WC3_SAMPLE_RATE 22050 53#define WC3_AUDIO_CHANNELS 1 54#define WC3_AUDIO_BITS 16 55 56/* nice, constant framerate */ 57#define WC3_FRAME_FPS 15 58 59#define PALETTE_SIZE (256 * 3) 60#define PALETTE_COUNT 256 61 62typedef struct Wc3DemuxContext { 63 int width; 64 int height; 65 unsigned char *palettes; 66 int palette_count; 67 int64_t pts; 68 int video_stream_index; 69 int audio_stream_index; 70 71 AVPaletteControl palette_control; 72 73} Wc3DemuxContext; 74 75/** 76 * palette lookup table that does gamma correction 77 * 78 * can be calculated by this formula: 79 * for i between 0 and 251 inclusive: 80 * wc3_pal_lookup[i] = round(pow(i / 256.0, 0.8) * 256); 81 * values 252, 253, 254 and 255 are all 0xFD 82 * calculating this at runtime should not cause any 83 * rounding issues, the maximum difference between 84 * the table values and the calculated doubles is 85 * about 0.497527 86 */ 87static const unsigned char wc3_pal_lookup[] = { 88 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 89 0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A, 90 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 91 0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F, 92 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39, 93 0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42, 94 0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B, 95 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 96 0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 97 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 98 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 99 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 100 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 101 0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 102 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 103 0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 104 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99, 105 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 106 0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 107 0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 108 0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 109 0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 110 0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 111 0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 112 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1, 113 0xD2, 0xD3, 0xD4, 0xD5, 0xD5, 0xD6, 0xD7, 0xD8, 114 0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 115 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE4, 0xE5, 116 0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC, 117 0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2, 118 0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9, 119 0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD 120}; 121 122 123static int wc3_probe(AVProbeData *p) 124{ 125 if (p->buf_size < 12) 126 return 0; 127 128 if ((AV_RL32(&p->buf[0]) != FORM_TAG) || 129 (AV_RL32(&p->buf[8]) != MOVE_TAG)) 130 return 0; 131 132 return AVPROBE_SCORE_MAX; 133} 134 135static int wc3_read_header(AVFormatContext *s, 136 AVFormatParameters *ap) 137{ 138 Wc3DemuxContext *wc3 = s->priv_data; 139 ByteIOContext *pb = s->pb; 140 unsigned int fourcc_tag; 141 unsigned int size; 142 AVStream *st; 143 int ret = 0; 144 int current_palette = 0; 145 char *buffer; 146 int i; 147 unsigned char rotate; 148 149 /* default context members */ 150 wc3->width = WC3_DEFAULT_WIDTH; 151 wc3->height = WC3_DEFAULT_HEIGHT; 152 wc3->palettes = NULL; 153 wc3->palette_count = 0; 154 wc3->pts = 0; 155 wc3->video_stream_index = wc3->audio_stream_index = 0; 156 157 /* skip the first 3 32-bit numbers */ 158 url_fseek(pb, 12, SEEK_CUR); 159 160 /* traverse through the chunks and load the header information before 161 * the first BRCH tag */ 162 fourcc_tag = get_le32(pb); 163 size = (get_be32(pb) + 1) & (~1); 164 165 do { 166 switch (fourcc_tag) { 167 168 case SOND_TAG: 169 case INDX_TAG: 170 /* SOND unknown, INDX unnecessary; ignore both */ 171 url_fseek(pb, size, SEEK_CUR); 172 break; 173 174 case PC__TAG: 175 /* need the number of palettes */ 176 url_fseek(pb, 8, SEEK_CUR); 177 wc3->palette_count = get_le32(pb); 178 if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){ 179 wc3->palette_count= 0; 180 return -1; 181 } 182 wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE); 183 break; 184 185 case BNAM_TAG: 186 /* load up the name */ 187 buffer = av_malloc(size+1); 188 if (!buffer) 189 return AVERROR(ENOMEM); 190 if ((ret = get_buffer(pb, buffer, size)) != size) 191 return AVERROR(EIO); 192 buffer[size] = 0; 193 av_metadata_set2(&s->metadata, "title", buffer, 194 AV_METADATA_DONT_STRDUP_VAL); 195 break; 196 197 case SIZE_TAG: 198 /* video resolution override */ 199 wc3->width = get_le32(pb); 200 wc3->height = get_le32(pb); 201 break; 202 203 case PALT_TAG: 204 /* one of several palettes */ 205 if ((unsigned)current_palette >= wc3->palette_count) 206 return AVERROR_INVALIDDATA; 207 if ((ret = get_buffer(pb, 208 &wc3->palettes[current_palette * PALETTE_SIZE], 209 PALETTE_SIZE)) != PALETTE_SIZE) 210 return AVERROR(EIO); 211 212 /* transform the current palette in place */ 213 for (i = current_palette * PALETTE_SIZE; 214 i < (current_palette + 1) * PALETTE_SIZE; i++) { 215 /* rotate each palette component left by 2 and use the result 216 * as an index into the color component table */ 217 rotate = ((wc3->palettes[i] << 2) & 0xFF) | 218 ((wc3->palettes[i] >> 6) & 0xFF); 219 wc3->palettes[i] = wc3_pal_lookup[rotate]; 220 } 221 current_palette++; 222 break; 223 224 default: 225 av_log(s, AV_LOG_ERROR, " unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n", 226 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24), 227 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24)); 228 return AVERROR_INVALIDDATA; 229 break; 230 } 231 232 fourcc_tag = get_le32(pb); 233 /* chunk sizes are 16-bit aligned */ 234 size = (get_be32(pb) + 1) & (~1); 235 if (url_feof(pb)) 236 return AVERROR(EIO); 237 238 } while (fourcc_tag != BRCH_TAG); 239 240 /* initialize the decoder streams */ 241 st = av_new_stream(s, 0); 242 if (!st) 243 return AVERROR(ENOMEM); 244 av_set_pts_info(st, 33, 1, WC3_FRAME_FPS); 245 wc3->video_stream_index = st->index; 246 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 247 st->codec->codec_id = CODEC_ID_XAN_WC3; 248 st->codec->codec_tag = 0; /* no fourcc */ 249 st->codec->width = wc3->width; 250 st->codec->height = wc3->height; 251 252 /* palette considerations */ 253 st->codec->palctrl = &wc3->palette_control; 254 255 st = av_new_stream(s, 0); 256 if (!st) 257 return AVERROR(ENOMEM); 258 av_set_pts_info(st, 33, 1, WC3_FRAME_FPS); 259 wc3->audio_stream_index = st->index; 260 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 261 st->codec->codec_id = CODEC_ID_PCM_S16LE; 262 st->codec->codec_tag = 1; 263 st->codec->channels = WC3_AUDIO_CHANNELS; 264 st->codec->bits_per_coded_sample = WC3_AUDIO_BITS; 265 st->codec->sample_rate = WC3_SAMPLE_RATE; 266 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * 267 st->codec->bits_per_coded_sample; 268 st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS; 269 270 return 0; 271} 272 273static int wc3_read_packet(AVFormatContext *s, 274 AVPacket *pkt) 275{ 276 Wc3DemuxContext *wc3 = s->priv_data; 277 ByteIOContext *pb = s->pb; 278 unsigned int fourcc_tag; 279 unsigned int size; 280 int packet_read = 0; 281 int ret = 0; 282 unsigned char text[1024]; 283 unsigned int palette_number; 284 int i; 285 unsigned char r, g, b; 286 int base_palette_index; 287 288 while (!packet_read) { 289 290 fourcc_tag = get_le32(pb); 291 /* chunk sizes are 16-bit aligned */ 292 size = (get_be32(pb) + 1) & (~1); 293 if (url_feof(pb)) 294 return AVERROR(EIO); 295 296 switch (fourcc_tag) { 297 298 case BRCH_TAG: 299 /* no-op */ 300 break; 301 302 case SHOT_TAG: 303 /* load up new palette */ 304 palette_number = get_le32(pb); 305 if (palette_number >= wc3->palette_count) 306 return AVERROR_INVALIDDATA; 307 base_palette_index = palette_number * PALETTE_COUNT * 3; 308 for (i = 0; i < PALETTE_COUNT; i++) { 309 r = wc3->palettes[base_palette_index + i * 3 + 0]; 310 g = wc3->palettes[base_palette_index + i * 3 + 1]; 311 b = wc3->palettes[base_palette_index + i * 3 + 2]; 312 wc3->palette_control.palette[i] = (r << 16) | (g << 8) | (b); 313 } 314 wc3->palette_control.palette_changed = 1; 315 break; 316 317 case VGA__TAG: 318 /* send out video chunk */ 319 ret= av_get_packet(pb, pkt, size); 320 pkt->stream_index = wc3->video_stream_index; 321 pkt->pts = wc3->pts; 322 packet_read = 1; 323 break; 324 325 case TEXT_TAG: 326 /* subtitle chunk */ 327#if 0 328 url_fseek(pb, size, SEEK_CUR); 329#else 330 if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size) 331 ret = AVERROR(EIO); 332 else { 333 int i = 0; 334 av_log (s, AV_LOG_DEBUG, "Subtitle time!\n"); 335 av_log (s, AV_LOG_DEBUG, " inglish: %s\n", &text[i + 1]); 336 i += text[i] + 1; 337 av_log (s, AV_LOG_DEBUG, " doytsch: %s\n", &text[i + 1]); 338 i += text[i] + 1; 339 av_log (s, AV_LOG_DEBUG, " fronsay: %s\n", &text[i + 1]); 340 } 341#endif 342 break; 343 344 case AUDI_TAG: 345 /* send out audio chunk */ 346 ret= av_get_packet(pb, pkt, size); 347 pkt->stream_index = wc3->audio_stream_index; 348 pkt->pts = wc3->pts; 349 350 /* time to advance pts */ 351 wc3->pts++; 352 353 packet_read = 1; 354 break; 355 356 default: 357 av_log (s, AV_LOG_ERROR, " unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n", 358 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24), 359 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24)); 360 ret = AVERROR_INVALIDDATA; 361 packet_read = 1; 362 break; 363 } 364 } 365 366 return ret; 367} 368 369static int wc3_read_close(AVFormatContext *s) 370{ 371 Wc3DemuxContext *wc3 = s->priv_data; 372 373 av_free(wc3->palettes); 374 375 return 0; 376} 377 378AVInputFormat wc3_demuxer = { 379 "wc3movie", 380 NULL_IF_CONFIG_SMALL("Wing Commander III movie format"), 381 sizeof(Wc3DemuxContext), 382 wc3_probe, 383 wc3_read_header, 384 wc3_read_packet, 385 wc3_read_close, 386}; 387