1/* 2 * Interplay C93 demuxer 3 * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> 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#include "avformat.h" 23#include "voc.h" 24 25typedef struct { 26 uint16_t index; 27 uint8_t length; 28 uint8_t frames; 29} C93BlockRecord; 30 31typedef struct { 32 VocDecContext voc; 33 34 C93BlockRecord block_records[512]; 35 int current_block; 36 37 uint32_t frame_offsets[32]; 38 int current_frame; 39 int next_pkt_is_audio; 40 41 AVStream *audio; 42} C93DemuxContext; 43 44static int probe(AVProbeData *p) 45{ 46 if (p->buf[0] == 0x01 && p->buf[1] == 0x00 && 47 p->buf[4] == 0x01 + p->buf[2] && 48 p->buf[8] == p->buf[4] + p->buf[6] && 49 p->buf[12] == p->buf[8] + p->buf[10]) 50 return AVPROBE_SCORE_MAX; 51 52 return 0; 53} 54 55static int read_header(AVFormatContext *s, 56 AVFormatParameters *ap) 57{ 58 AVStream *video; 59 ByteIOContext *pb = s->pb; 60 C93DemuxContext *c93 = s->priv_data; 61 int i; 62 int framecount = 0; 63 64 for (i = 0; i < 512; i++) { 65 c93->block_records[i].index = get_le16(pb); 66 c93->block_records[i].length = get_byte(pb); 67 c93->block_records[i].frames = get_byte(pb); 68 if (c93->block_records[i].frames > 32) { 69 av_log(s, AV_LOG_ERROR, "too many frames in block\n"); 70 return AVERROR_INVALIDDATA; 71 } 72 framecount += c93->block_records[i].frames; 73 } 74 75 /* Audio streams are added if audio packets are found */ 76 s->ctx_flags |= AVFMTCTX_NOHEADER; 77 78 video = av_new_stream(s, 0); 79 if (!video) 80 return AVERROR(ENOMEM); 81 82 video->codec->codec_type = CODEC_TYPE_VIDEO; 83 video->codec->codec_id = CODEC_ID_C93; 84 video->codec->width = 320; 85 video->codec->height = 192; 86 /* 4:3 320x200 with 8 empty lines */ 87 video->sample_aspect_ratio = (AVRational) { 5, 6 }; 88 video->time_base = (AVRational) { 2, 25 }; 89 video->nb_frames = framecount; 90 video->duration = framecount; 91 video->start_time = 0; 92 93 c93->current_block = 0; 94 c93->current_frame = 0; 95 c93->next_pkt_is_audio = 0; 96 return 0; 97} 98 99#define C93_HAS_PALETTE 0x01 100#define C93_FIRST_FRAME 0x02 101 102static int read_packet(AVFormatContext *s, AVPacket *pkt) 103{ 104 ByteIOContext *pb = s->pb; 105 C93DemuxContext *c93 = s->priv_data; 106 C93BlockRecord *br = &c93->block_records[c93->current_block]; 107 int datasize; 108 int ret, i; 109 110 if (c93->next_pkt_is_audio) { 111 c93->current_frame++; 112 c93->next_pkt_is_audio = 0; 113 datasize = get_le16(pb); 114 if (datasize > 42) { 115 if (!c93->audio) { 116 c93->audio = av_new_stream(s, 1); 117 if (!c93->audio) 118 return AVERROR(ENOMEM); 119 c93->audio->codec->codec_type = CODEC_TYPE_AUDIO; 120 } 121 url_fskip(pb, 26); /* VOC header */ 122 ret = voc_get_packet(s, pkt, c93->audio, datasize - 26); 123 if (ret > 0) { 124 pkt->stream_index = 1; 125 pkt->flags |= PKT_FLAG_KEY; 126 return ret; 127 } 128 } 129 } 130 if (c93->current_frame >= br->frames) { 131 if (c93->current_block >= 511 || !br[1].length) 132 return AVERROR(EIO); 133 br++; 134 c93->current_block++; 135 c93->current_frame = 0; 136 } 137 138 if (c93->current_frame == 0) { 139 url_fseek(pb, br->index * 2048, SEEK_SET); 140 for (i = 0; i < 32; i++) { 141 c93->frame_offsets[i] = get_le32(pb); 142 } 143 } 144 145 url_fseek(pb,br->index * 2048 + 146 c93->frame_offsets[c93->current_frame], SEEK_SET); 147 datasize = get_le16(pb); /* video frame size */ 148 149 ret = av_new_packet(pkt, datasize + 768 + 1); 150 if (ret < 0) 151 return ret; 152 pkt->data[0] = 0; 153 pkt->size = datasize + 1; 154 155 ret = get_buffer(pb, pkt->data + 1, datasize); 156 if (ret < datasize) { 157 ret = AVERROR(EIO); 158 goto fail; 159 } 160 161 datasize = get_le16(pb); /* palette size */ 162 if (datasize) { 163 if (datasize != 768) { 164 av_log(s, AV_LOG_ERROR, "invalid palette size %u\n", datasize); 165 ret = AVERROR_INVALIDDATA; 166 goto fail; 167 } 168 pkt->data[0] |= C93_HAS_PALETTE; 169 ret = get_buffer(pb, pkt->data + pkt->size, datasize); 170 if (ret < datasize) { 171 ret = AVERROR(EIO); 172 goto fail; 173 } 174 pkt->size += 768; 175 } 176 pkt->stream_index = 0; 177 c93->next_pkt_is_audio = 1; 178 179 /* only the first frame is guaranteed to not reference previous frames */ 180 if (c93->current_block == 0 && c93->current_frame == 0) { 181 pkt->flags |= PKT_FLAG_KEY; 182 pkt->data[0] |= C93_FIRST_FRAME; 183 } 184 return 0; 185 186 fail: 187 av_free_packet(pkt); 188 return ret; 189} 190 191AVInputFormat c93_demuxer = { 192 "c93", 193 NULL_IF_CONFIG_SMALL("Interplay C93"), 194 sizeof(C93DemuxContext), 195 probe, 196 read_header, 197 read_packet, 198}; 199