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