/src/ffmpeg/libavformat/avs.c
Line | Count | Source |
1 | | /* |
2 | | * AVS demuxer. |
3 | | * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> |
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 | | /** |
23 | | * @file |
24 | | * Argonaut Games' Creature Shock demuxer |
25 | | * @see http://wiki.multimedia.cx/index.php?title=AVS |
26 | | */ |
27 | | |
28 | | #include "avformat.h" |
29 | | #include "avio_internal.h" |
30 | | #include "demux.h" |
31 | | #include "voc.h" |
32 | | |
33 | | |
34 | | typedef struct avs_format { |
35 | | VocDecContext voc; |
36 | | AVStream *st_video; |
37 | | AVStream *st_audio; |
38 | | int width; |
39 | | int height; |
40 | | int bits_per_sample; |
41 | | int fps; |
42 | | int nb_frames; |
43 | | int remaining_frame_size; |
44 | | int remaining_audio_size; |
45 | | } AvsFormat; |
46 | | |
47 | | typedef enum avs_block_type { |
48 | | AVS_NONE = 0x00, |
49 | | AVS_VIDEO = 0x01, |
50 | | AVS_AUDIO = 0x02, |
51 | | AVS_PALETTE = 0x03, |
52 | | AVS_GAME_DATA = 0x04, |
53 | | } AvsBlockType; |
54 | | |
55 | | static int avs_probe(const AVProbeData * p) |
56 | 958k | { |
57 | 958k | const uint8_t *d; |
58 | | |
59 | 958k | d = p->buf; |
60 | 958k | if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0) |
61 | | /* Ensure the buffer probe scores higher than the extension probe. |
62 | | * This avoids problems with misdetection as AviSynth scripts. */ |
63 | 273 | return AVPROBE_SCORE_EXTENSION + 5; |
64 | | |
65 | 958k | return 0; |
66 | 958k | } |
67 | | |
68 | | static int avs_read_header(AVFormatContext * s) |
69 | 3.95k | { |
70 | 3.95k | AvsFormat *avs = s->priv_data; |
71 | | |
72 | 3.95k | s->ctx_flags |= AVFMTCTX_NOHEADER; |
73 | | |
74 | 3.95k | avio_skip(s->pb, 4); |
75 | 3.95k | avs->width = avio_rl16(s->pb); |
76 | 3.95k | avs->height = avio_rl16(s->pb); |
77 | 3.95k | avs->bits_per_sample = avio_rl16(s->pb); |
78 | 3.95k | avs->fps = avio_rl16(s->pb); |
79 | 3.95k | avs->nb_frames = avio_rl32(s->pb); |
80 | 3.95k | avs->remaining_frame_size = 0; |
81 | 3.95k | avs->remaining_audio_size = 0; |
82 | | |
83 | 3.95k | avs->st_video = avs->st_audio = NULL; |
84 | | |
85 | 3.95k | if (avs->width != 318 || avs->height != 198) |
86 | 3.92k | av_log(s, AV_LOG_ERROR, "This avs pretend to be %dx%d " |
87 | 3.92k | "when the avs format is supposed to be 318x198 only.\n", |
88 | 3.92k | avs->width, avs->height); |
89 | | |
90 | 3.95k | return 0; |
91 | 3.95k | } |
92 | | |
93 | | static int |
94 | | avs_read_video_packet(AVFormatContext * s, AVPacket * pkt, |
95 | | AvsBlockType type, int sub_type, int size, |
96 | | uint8_t * palette, int palette_size) |
97 | 774k | { |
98 | 774k | AvsFormat *avs = s->priv_data; |
99 | 774k | int ret; |
100 | | |
101 | 774k | ret = av_new_packet(pkt, size + palette_size); |
102 | 774k | if (ret < 0) |
103 | 0 | return ret; |
104 | | |
105 | 774k | if (palette_size) { |
106 | 333 | pkt->data[0] = 0x00; |
107 | 333 | pkt->data[1] = 0x03; |
108 | 333 | pkt->data[2] = palette_size & 0xFF; |
109 | 333 | pkt->data[3] = (palette_size >> 8) & 0xFF; |
110 | 333 | memcpy(pkt->data + 4, palette, palette_size - 4); |
111 | 333 | } |
112 | | |
113 | 774k | pkt->data[palette_size + 0] = sub_type; |
114 | 774k | pkt->data[palette_size + 1] = type; |
115 | 774k | pkt->data[palette_size + 2] = size & 0xFF; |
116 | 774k | pkt->data[palette_size + 3] = (size >> 8) & 0xFF; |
117 | 774k | ret = ffio_read_size(s->pb, pkt->data + palette_size + 4, size - 4) + 4; |
118 | 774k | if (ret < 0) |
119 | 214 | return ret; |
120 | | |
121 | 774k | pkt->size = ret + palette_size; |
122 | 774k | pkt->stream_index = avs->st_video->index; |
123 | 774k | if (sub_type == 0) |
124 | 345k | pkt->flags |= AV_PKT_FLAG_KEY; |
125 | | |
126 | 774k | return 0; |
127 | 774k | } |
128 | | |
129 | | static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt) |
130 | 92.6k | { |
131 | 92.6k | AvsFormat *avs = s->priv_data; |
132 | 92.6k | int ret; |
133 | 92.6k | int64_t size; |
134 | | |
135 | 92.6k | size = avio_tell(s->pb); |
136 | 92.6k | ret = ff_voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size); |
137 | 92.6k | size = avio_tell(s->pb) - size; |
138 | 92.6k | avs->remaining_audio_size -= size; |
139 | | |
140 | 92.6k | if (ret == AVERROR(EIO)) |
141 | 0 | return 0; /* this indicate EOS */ |
142 | 92.6k | if (ret < 0) |
143 | 8.59k | return ret; |
144 | 84.0k | if (size != (int)size) { |
145 | 128 | av_packet_unref(pkt); |
146 | 128 | return AVERROR(EDOM); |
147 | 128 | } |
148 | | |
149 | 83.9k | pkt->stream_index = avs->st_audio->index; |
150 | 83.9k | pkt->flags |= AV_PKT_FLAG_KEY; |
151 | | |
152 | 83.9k | return size; |
153 | 84.0k | } |
154 | | |
155 | | static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) |
156 | 865k | { |
157 | 865k | AvsFormat *avs = s->priv_data; |
158 | 865k | int sub_type = 0, size = 0; |
159 | 865k | AvsBlockType type = AVS_NONE; |
160 | 865k | int palette_size = 0; |
161 | 865k | uint8_t palette[4 + 3 * 256]; |
162 | 865k | int ret; |
163 | | |
164 | 865k | if (avs->remaining_audio_size > 0) |
165 | 89.0k | if (avs_read_audio_packet(s, pkt) > 0) |
166 | 81.9k | return 0; |
167 | | |
168 | 860k | while (1) { |
169 | 860k | if (avs->remaining_frame_size <= 0) { |
170 | 88.2k | if (!avio_rl16(s->pb)) /* found EOF */ |
171 | 2.90k | return AVERROR_INVALIDDATA; |
172 | 85.3k | avs->remaining_frame_size = avio_rl16(s->pb) - 4; |
173 | 85.3k | } |
174 | | |
175 | 883k | while (avs->remaining_frame_size > 0) { |
176 | 806k | sub_type = avio_r8(s->pb); |
177 | 806k | type = avio_r8(s->pb); |
178 | 806k | size = avio_rl16(s->pb); |
179 | 806k | if (size < 4) |
180 | 2.88k | return AVERROR_INVALIDDATA; |
181 | 803k | avs->remaining_frame_size -= size; |
182 | | |
183 | 803k | switch (type) { |
184 | 525 | case AVS_PALETTE: |
185 | 525 | if (size - 4 > sizeof(palette)) |
186 | 22 | return AVERROR_INVALIDDATA; |
187 | 503 | ret = ffio_read_size(s->pb, palette, size - 4); |
188 | 503 | if (ret < 0) |
189 | 32 | return ret; |
190 | 471 | palette_size = size; |
191 | 471 | break; |
192 | | |
193 | 774k | case AVS_VIDEO: |
194 | 774k | if (!avs->st_video) { |
195 | 992 | avs->st_video = avformat_new_stream(s, NULL); |
196 | 992 | if (!avs->st_video) |
197 | 0 | return AVERROR(ENOMEM); |
198 | 992 | avs->st_video->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
199 | 992 | avs->st_video->codecpar->codec_id = AV_CODEC_ID_AVS; |
200 | 992 | avs->st_video->codecpar->width = avs->width; |
201 | 992 | avs->st_video->codecpar->height = avs->height; |
202 | 992 | avs->st_video->codecpar->bits_per_coded_sample=avs->bits_per_sample; |
203 | 992 | avs->st_video->nb_frames = avs->nb_frames; |
204 | 992 | #if FF_API_R_FRAME_RATE |
205 | 992 | avs->st_video->r_frame_rate = |
206 | 992 | #endif |
207 | 992 | avs->st_video->avg_frame_rate = (AVRational){avs->fps, 1}; |
208 | 992 | } |
209 | 774k | return avs_read_video_packet(s, pkt, type, sub_type, size, |
210 | 774k | palette, palette_size); |
211 | | |
212 | 3.63k | case AVS_AUDIO: |
213 | 3.63k | if (!avs->st_audio) { |
214 | 2.92k | avs->st_audio = avformat_new_stream(s, NULL); |
215 | 2.92k | if (!avs->st_audio) |
216 | 0 | return AVERROR(ENOMEM); |
217 | 2.92k | avs->st_audio->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
218 | 2.92k | } |
219 | 3.63k | avs->remaining_audio_size = size - 4; |
220 | 3.63k | size = avs_read_audio_packet(s, pkt); |
221 | 3.63k | if (size != 0) |
222 | 3.63k | return size; |
223 | 0 | break; |
224 | | |
225 | 25.3k | default: |
226 | 25.3k | avio_skip(s->pb, size - 4); |
227 | 803k | } |
228 | 803k | } |
229 | 857k | } |
230 | 783k | } |
231 | | |
232 | | const FFInputFormat ff_avs_demuxer = { |
233 | | .p.name = "avs", |
234 | | .p.long_name = NULL_IF_CONFIG_SMALL("Argonaut Games Creature Shock"), |
235 | | .priv_data_size = sizeof(AvsFormat), |
236 | | .read_probe = avs_probe, |
237 | | .read_header = avs_read_header, |
238 | | .read_packet = avs_read_packet, |
239 | | }; |