• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/wc3movie.c

Go to the documentation of this file.
00001 /*
00002  * Wing Commander III Movie (.mve) File Demuxer
00003  * Copyright (c) 2003 The ffmpeg Project
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 
00030 #include "libavutil/intreadwrite.h"
00031 #include "avformat.h"
00032 
00033 #define FORM_TAG MKTAG('F', 'O', 'R', 'M')
00034 #define MOVE_TAG MKTAG('M', 'O', 'V', 'E')
00035 #define  PC__TAG MKTAG('_', 'P', 'C', '_')
00036 #define SOND_TAG MKTAG('S', 'O', 'N', 'D')
00037 #define BNAM_TAG MKTAG('B', 'N', 'A', 'M')
00038 #define SIZE_TAG MKTAG('S', 'I', 'Z', 'E')
00039 #define PALT_TAG MKTAG('P', 'A', 'L', 'T')
00040 #define INDX_TAG MKTAG('I', 'N', 'D', 'X')
00041 #define BRCH_TAG MKTAG('B', 'R', 'C', 'H')
00042 #define SHOT_TAG MKTAG('S', 'H', 'O', 'T')
00043 #define VGA__TAG MKTAG('V', 'G', 'A', ' ')
00044 #define TEXT_TAG MKTAG('T', 'E', 'X', 'T')
00045 #define AUDI_TAG MKTAG('A', 'U', 'D', 'I')
00046 
00047 /* video resolution unless otherwise specified */
00048 #define WC3_DEFAULT_WIDTH 320
00049 #define WC3_DEFAULT_HEIGHT 165
00050 
00051 /* always use the same PCM audio parameters */
00052 #define WC3_SAMPLE_RATE 22050
00053 #define WC3_AUDIO_CHANNELS 1
00054 #define WC3_AUDIO_BITS 16
00055 
00056 /* nice, constant framerate */
00057 #define WC3_FRAME_FPS 15
00058 
00059 #define PALETTE_SIZE (256 * 3)
00060 #define PALETTE_COUNT 256
00061 
00062 typedef struct Wc3DemuxContext {
00063     int width;
00064     int height;
00065     unsigned char *palettes;
00066     int palette_count;
00067     int64_t pts;
00068     int video_stream_index;
00069     int audio_stream_index;
00070 
00071     AVPaletteControl palette_control;
00072 
00073 } Wc3DemuxContext;
00074 
00087 static const unsigned char wc3_pal_lookup[] = {
00088   0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E,
00089   0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A,
00090   0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
00091   0x27, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x2F,
00092   0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
00093   0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
00094   0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B,
00095   0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
00096   0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
00097   0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
00098   0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C,
00099   0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
00100   0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
00101   0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
00102   0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
00103   0x8C, 0x8D, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
00104   0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x99,
00105   0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1,
00106   0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
00107   0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
00108   0xB0, 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
00109   0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
00110   0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4,
00111   0xC5, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
00112   0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1,
00113   0xD2, 0xD3, 0xD4, 0xD5, 0xD5, 0xD6, 0xD7, 0xD8,
00114   0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
00115   0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE4, 0xE5,
00116   0xE6, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEB, 0xEC,
00117   0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2,
00118   0xF3, 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9,
00119   0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD
00120 };
00121 
00122 
00123 static int wc3_probe(AVProbeData *p)
00124 {
00125     if (p->buf_size < 12)
00126         return 0;
00127 
00128     if ((AV_RL32(&p->buf[0]) != FORM_TAG) ||
00129         (AV_RL32(&p->buf[8]) != MOVE_TAG))
00130         return 0;
00131 
00132     return AVPROBE_SCORE_MAX;
00133 }
00134 
00135 static int wc3_read_header(AVFormatContext *s,
00136                            AVFormatParameters *ap)
00137 {
00138     Wc3DemuxContext *wc3 = s->priv_data;
00139     ByteIOContext *pb = s->pb;
00140     unsigned int fourcc_tag;
00141     unsigned int size;
00142     AVStream *st;
00143     int ret = 0;
00144     int current_palette = 0;
00145     char *buffer;
00146     int i;
00147     unsigned char rotate;
00148 
00149     /* default context members */
00150     wc3->width = WC3_DEFAULT_WIDTH;
00151     wc3->height = WC3_DEFAULT_HEIGHT;
00152     wc3->palettes = NULL;
00153     wc3->palette_count = 0;
00154     wc3->pts = 0;
00155     wc3->video_stream_index = wc3->audio_stream_index = 0;
00156 
00157     /* skip the first 3 32-bit numbers */
00158     url_fseek(pb, 12, SEEK_CUR);
00159 
00160     /* traverse through the chunks and load the header information before
00161      * the first BRCH tag */
00162     fourcc_tag = get_le32(pb);
00163     size = (get_be32(pb) + 1) & (~1);
00164 
00165     do {
00166         switch (fourcc_tag) {
00167 
00168         case SOND_TAG:
00169         case INDX_TAG:
00170             /* SOND unknown, INDX unnecessary; ignore both */
00171             url_fseek(pb, size, SEEK_CUR);
00172             break;
00173 
00174         case PC__TAG:
00175             /* need the number of palettes */
00176             url_fseek(pb, 8, SEEK_CUR);
00177             wc3->palette_count = get_le32(pb);
00178             if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){
00179                 wc3->palette_count= 0;
00180                 return -1;
00181             }
00182             wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE);
00183             break;
00184 
00185         case BNAM_TAG:
00186             /* load up the name */
00187             buffer = av_malloc(size+1);
00188             if (!buffer)
00189                 return AVERROR(ENOMEM);
00190             if ((ret = get_buffer(pb, buffer, size)) != size)
00191                 return AVERROR(EIO);
00192             buffer[size] = 0;
00193             av_metadata_set2(&s->metadata, "title", buffer,
00194                                    AV_METADATA_DONT_STRDUP_VAL);
00195             break;
00196 
00197         case SIZE_TAG:
00198             /* video resolution override */
00199             wc3->width  = get_le32(pb);
00200             wc3->height = get_le32(pb);
00201             break;
00202 
00203         case PALT_TAG:
00204             /* one of several palettes */
00205             if ((unsigned)current_palette >= wc3->palette_count)
00206                 return AVERROR_INVALIDDATA;
00207             if ((ret = get_buffer(pb,
00208                 &wc3->palettes[current_palette * PALETTE_SIZE],
00209                 PALETTE_SIZE)) != PALETTE_SIZE)
00210                 return AVERROR(EIO);
00211 
00212             /* transform the current palette in place */
00213             for (i = current_palette * PALETTE_SIZE;
00214                  i < (current_palette + 1) * PALETTE_SIZE; i++) {
00215                 /* rotate each palette component left by 2 and use the result
00216                  * as an index into the color component table */
00217                 rotate = ((wc3->palettes[i] << 2) & 0xFF) |
00218                          ((wc3->palettes[i] >> 6) & 0xFF);
00219                 wc3->palettes[i] = wc3_pal_lookup[rotate];
00220             }
00221             current_palette++;
00222             break;
00223 
00224         default:
00225             av_log(s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
00226                 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
00227                 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
00228             return AVERROR_INVALIDDATA;
00229             break;
00230         }
00231 
00232         fourcc_tag = get_le32(pb);
00233         /* chunk sizes are 16-bit aligned */
00234         size = (get_be32(pb) + 1) & (~1);
00235         if (url_feof(pb))
00236             return AVERROR(EIO);
00237 
00238     } while (fourcc_tag != BRCH_TAG);
00239 
00240     /* initialize the decoder streams */
00241     st = av_new_stream(s, 0);
00242     if (!st)
00243         return AVERROR(ENOMEM);
00244     av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
00245     wc3->video_stream_index = st->index;
00246     st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00247     st->codec->codec_id = CODEC_ID_XAN_WC3;
00248     st->codec->codec_tag = 0;  /* no fourcc */
00249     st->codec->width = wc3->width;
00250     st->codec->height = wc3->height;
00251 
00252     /* palette considerations */
00253     st->codec->palctrl = &wc3->palette_control;
00254 
00255     st = av_new_stream(s, 0);
00256     if (!st)
00257         return AVERROR(ENOMEM);
00258     av_set_pts_info(st, 33, 1, WC3_FRAME_FPS);
00259     wc3->audio_stream_index = st->index;
00260     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00261     st->codec->codec_id = CODEC_ID_PCM_S16LE;
00262     st->codec->codec_tag = 1;
00263     st->codec->channels = WC3_AUDIO_CHANNELS;
00264     st->codec->bits_per_coded_sample = WC3_AUDIO_BITS;
00265     st->codec->sample_rate = WC3_SAMPLE_RATE;
00266     st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
00267         st->codec->bits_per_coded_sample;
00268     st->codec->block_align = WC3_AUDIO_BITS * WC3_AUDIO_CHANNELS;
00269 
00270     return 0;
00271 }
00272 
00273 static int wc3_read_packet(AVFormatContext *s,
00274                            AVPacket *pkt)
00275 {
00276     Wc3DemuxContext *wc3 = s->priv_data;
00277     ByteIOContext *pb = s->pb;
00278     unsigned int fourcc_tag;
00279     unsigned int size;
00280     int packet_read = 0;
00281     int ret = 0;
00282     unsigned char text[1024];
00283     unsigned int palette_number;
00284     int i;
00285     unsigned char r, g, b;
00286     int base_palette_index;
00287 
00288     while (!packet_read) {
00289 
00290         fourcc_tag = get_le32(pb);
00291         /* chunk sizes are 16-bit aligned */
00292         size = (get_be32(pb) + 1) & (~1);
00293         if (url_feof(pb))
00294             return AVERROR(EIO);
00295 
00296         switch (fourcc_tag) {
00297 
00298         case BRCH_TAG:
00299             /* no-op */
00300             break;
00301 
00302         case SHOT_TAG:
00303             /* load up new palette */
00304             palette_number = get_le32(pb);
00305             if (palette_number >= wc3->palette_count)
00306                 return AVERROR_INVALIDDATA;
00307             base_palette_index = palette_number * PALETTE_COUNT * 3;
00308             for (i = 0; i < PALETTE_COUNT; i++) {
00309                 r = wc3->palettes[base_palette_index + i * 3 + 0];
00310                 g = wc3->palettes[base_palette_index + i * 3 + 1];
00311                 b = wc3->palettes[base_palette_index + i * 3 + 2];
00312                 wc3->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
00313             }
00314             wc3->palette_control.palette_changed = 1;
00315             break;
00316 
00317         case VGA__TAG:
00318             /* send out video chunk */
00319             ret= av_get_packet(pb, pkt, size);
00320             pkt->stream_index = wc3->video_stream_index;
00321             pkt->pts = wc3->pts;
00322             packet_read = 1;
00323             break;
00324 
00325         case TEXT_TAG:
00326             /* subtitle chunk */
00327 #if 0
00328             url_fseek(pb, size, SEEK_CUR);
00329 #else
00330             if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size)
00331                 ret = AVERROR(EIO);
00332             else {
00333                 int i = 0;
00334                 av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
00335                 av_log (s, AV_LOG_DEBUG, "  inglish: %s\n", &text[i + 1]);
00336                 i += text[i] + 1;
00337                 av_log (s, AV_LOG_DEBUG, "  doytsch: %s\n", &text[i + 1]);
00338                 i += text[i] + 1;
00339                 av_log (s, AV_LOG_DEBUG, "  fronsay: %s\n", &text[i + 1]);
00340             }
00341 #endif
00342             break;
00343 
00344         case AUDI_TAG:
00345             /* send out audio chunk */
00346             ret= av_get_packet(pb, pkt, size);
00347             pkt->stream_index = wc3->audio_stream_index;
00348             pkt->pts = wc3->pts;
00349 
00350             /* time to advance pts */
00351             wc3->pts++;
00352 
00353             packet_read = 1;
00354             break;
00355 
00356         default:
00357             av_log (s, AV_LOG_ERROR, "  unrecognized WC3 chunk: %c%c%c%c (0x%02X%02X%02X%02X)\n",
00358                 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24),
00359                 (uint8_t)fourcc_tag, (uint8_t)(fourcc_tag >> 8), (uint8_t)(fourcc_tag >> 16), (uint8_t)(fourcc_tag >> 24));
00360             ret = AVERROR_INVALIDDATA;
00361             packet_read = 1;
00362             break;
00363         }
00364     }
00365 
00366     return ret;
00367 }
00368 
00369 static int wc3_read_close(AVFormatContext *s)
00370 {
00371     Wc3DemuxContext *wc3 = s->priv_data;
00372 
00373     av_free(wc3->palettes);
00374 
00375     return 0;
00376 }
00377 
00378 AVInputFormat wc3_demuxer = {
00379     "wc3movie",
00380     NULL_IF_CONFIG_SMALL("Wing Commander III movie format"),
00381     sizeof(Wc3DemuxContext),
00382     wc3_probe,
00383     wc3_read_header,
00384     wc3_read_packet,
00385     wc3_read_close,
00386 };

Generated on Fri Sep 16 2011 17:17:51 for FFmpeg by  doxygen 1.7.1