00001 /* 00002 * Interplay C93 demuxer 00003 * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> 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 00022 #include "avformat.h" 00023 #include "voc.h" 00024 00025 typedef struct { 00026 uint16_t index; 00027 uint8_t length; 00028 uint8_t frames; 00029 } C93BlockRecord; 00030 00031 typedef struct { 00032 VocDecContext voc; 00033 00034 C93BlockRecord block_records[512]; 00035 int current_block; 00036 00037 uint32_t frame_offsets[32]; 00038 int current_frame; 00039 int next_pkt_is_audio; 00040 00041 AVStream *audio; 00042 } C93DemuxContext; 00043 00044 static int probe(AVProbeData *p) 00045 { 00046 if (p->buf[0] == 0x01 && p->buf[1] == 0x00 && 00047 p->buf[4] == 0x01 + p->buf[2] && 00048 p->buf[8] == p->buf[4] + p->buf[6] && 00049 p->buf[12] == p->buf[8] + p->buf[10]) 00050 return AVPROBE_SCORE_MAX; 00051 00052 return 0; 00053 } 00054 00055 static int read_header(AVFormatContext *s, 00056 AVFormatParameters *ap) 00057 { 00058 AVStream *video; 00059 ByteIOContext *pb = s->pb; 00060 C93DemuxContext *c93 = s->priv_data; 00061 int i; 00062 int framecount = 0; 00063 00064 for (i = 0; i < 512; i++) { 00065 c93->block_records[i].index = get_le16(pb); 00066 c93->block_records[i].length = get_byte(pb); 00067 c93->block_records[i].frames = get_byte(pb); 00068 if (c93->block_records[i].frames > 32) { 00069 av_log(s, AV_LOG_ERROR, "too many frames in block\n"); 00070 return AVERROR_INVALIDDATA; 00071 } 00072 framecount += c93->block_records[i].frames; 00073 } 00074 00075 /* Audio streams are added if audio packets are found */ 00076 s->ctx_flags |= AVFMTCTX_NOHEADER; 00077 00078 video = av_new_stream(s, 0); 00079 if (!video) 00080 return AVERROR(ENOMEM); 00081 00082 video->codec->codec_type = CODEC_TYPE_VIDEO; 00083 video->codec->codec_id = CODEC_ID_C93; 00084 video->codec->width = 320; 00085 video->codec->height = 192; 00086 /* 4:3 320x200 with 8 empty lines */ 00087 video->sample_aspect_ratio = (AVRational) { 5, 6 }; 00088 video->time_base = (AVRational) { 2, 25 }; 00089 video->nb_frames = framecount; 00090 video->duration = framecount; 00091 video->start_time = 0; 00092 00093 c93->current_block = 0; 00094 c93->current_frame = 0; 00095 c93->next_pkt_is_audio = 0; 00096 return 0; 00097 } 00098 00099 #define C93_HAS_PALETTE 0x01 00100 #define C93_FIRST_FRAME 0x02 00101 00102 static int read_packet(AVFormatContext *s, AVPacket *pkt) 00103 { 00104 ByteIOContext *pb = s->pb; 00105 C93DemuxContext *c93 = s->priv_data; 00106 C93BlockRecord *br = &c93->block_records[c93->current_block]; 00107 int datasize; 00108 int ret, i; 00109 00110 if (c93->next_pkt_is_audio) { 00111 c93->current_frame++; 00112 c93->next_pkt_is_audio = 0; 00113 datasize = get_le16(pb); 00114 if (datasize > 42) { 00115 if (!c93->audio) { 00116 c93->audio = av_new_stream(s, 1); 00117 if (!c93->audio) 00118 return AVERROR(ENOMEM); 00119 c93->audio->codec->codec_type = CODEC_TYPE_AUDIO; 00120 } 00121 url_fskip(pb, 26); /* VOC header */ 00122 ret = voc_get_packet(s, pkt, c93->audio, datasize - 26); 00123 if (ret > 0) { 00124 pkt->stream_index = 1; 00125 pkt->flags |= PKT_FLAG_KEY; 00126 return ret; 00127 } 00128 } 00129 } 00130 if (c93->current_frame >= br->frames) { 00131 if (c93->current_block >= 511 || !br[1].length) 00132 return AVERROR(EIO); 00133 br++; 00134 c93->current_block++; 00135 c93->current_frame = 0; 00136 } 00137 00138 if (c93->current_frame == 0) { 00139 url_fseek(pb, br->index * 2048, SEEK_SET); 00140 for (i = 0; i < 32; i++) { 00141 c93->frame_offsets[i] = get_le32(pb); 00142 } 00143 } 00144 00145 url_fseek(pb,br->index * 2048 + 00146 c93->frame_offsets[c93->current_frame], SEEK_SET); 00147 datasize = get_le16(pb); /* video frame size */ 00148 00149 ret = av_new_packet(pkt, datasize + 768 + 1); 00150 if (ret < 0) 00151 return ret; 00152 pkt->data[0] = 0; 00153 pkt->size = datasize + 1; 00154 00155 ret = get_buffer(pb, pkt->data + 1, datasize); 00156 if (ret < datasize) { 00157 ret = AVERROR(EIO); 00158 goto fail; 00159 } 00160 00161 datasize = get_le16(pb); /* palette size */ 00162 if (datasize) { 00163 if (datasize != 768) { 00164 av_log(s, AV_LOG_ERROR, "invalid palette size %u\n", datasize); 00165 ret = AVERROR_INVALIDDATA; 00166 goto fail; 00167 } 00168 pkt->data[0] |= C93_HAS_PALETTE; 00169 ret = get_buffer(pb, pkt->data + pkt->size, datasize); 00170 if (ret < datasize) { 00171 ret = AVERROR(EIO); 00172 goto fail; 00173 } 00174 pkt->size += 768; 00175 } 00176 pkt->stream_index = 0; 00177 c93->next_pkt_is_audio = 1; 00178 00179 /* only the first frame is guaranteed to not reference previous frames */ 00180 if (c93->current_block == 0 && c93->current_frame == 0) { 00181 pkt->flags |= PKT_FLAG_KEY; 00182 pkt->data[0] |= C93_FIRST_FRAME; 00183 } 00184 return 0; 00185 00186 fail: 00187 av_free_packet(pkt); 00188 return ret; 00189 } 00190 00191 AVInputFormat c93_demuxer = { 00192 "c93", 00193 NULL_IF_CONFIG_SMALL("Interplay C93"), 00194 sizeof(C93DemuxContext), 00195 probe, 00196 read_header, 00197 read_packet, 00198 };