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