/src/ffmpeg/libavformat/usmdec.c
Line | Count | Source |
1 | | /* |
2 | | * USM demuxer |
3 | | * Copyright (c) 2023 Paul B Mahol |
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 "libavutil/intfloat.h" |
23 | | #include "libavutil/intreadwrite.h" |
24 | | #include "libavutil/mem.h" |
25 | | #include "libavcodec/bytestream.h" |
26 | | |
27 | | #include "avformat.h" |
28 | | #include "demux.h" |
29 | | #include "internal.h" |
30 | | |
31 | 60.1M | #define VIDEOI 0 |
32 | 35.0M | #define AUDIOI 1 |
33 | 2.13M | #define ALPHAI 2 |
34 | 2.75k | #define SUBTTI 3 |
35 | | |
36 | | typedef struct USMChannel { |
37 | | int index; |
38 | | int used; |
39 | | int type; |
40 | | int codec_id; |
41 | | int nb_channels; |
42 | | int nb_frames; |
43 | | AVRational rate; |
44 | | int width, height; |
45 | | int64_t duration; |
46 | | int64_t extradata_pos; |
47 | | } USMChannel; |
48 | | |
49 | | typedef struct USMDemuxContext { |
50 | | USMChannel ch[4][256]; |
51 | | int nb_channels[4]; |
52 | | uint8_t *header; |
53 | | unsigned header_size; |
54 | | } USMDemuxContext; |
55 | | |
56 | | static int usm_probe(const AVProbeData *p) |
57 | 936k | { |
58 | 936k | if (AV_RL32(p->buf) != MKTAG('C','R','I','D')) |
59 | 935k | return 0; |
60 | | |
61 | 769 | if (AV_RN32(p->buf + 4) == 0) |
62 | 148 | return 0; |
63 | | |
64 | 621 | return AVPROBE_SCORE_MAX / 3; |
65 | 769 | } |
66 | | |
67 | | static int usm_read_header(AVFormatContext *s) |
68 | 7.85k | { |
69 | 7.85k | s->ctx_flags |= AVFMTCTX_NOHEADER; |
70 | 7.85k | return 0; |
71 | 7.85k | } |
72 | | |
73 | | static int parse_utf(AVFormatContext *s, AVIOContext *pb, |
74 | | USMChannel *ch, int ch_type, |
75 | | uint32_t parent_chunk_size) |
76 | 7.81k | { |
77 | 7.81k | USMDemuxContext *usm = s->priv_data; |
78 | 7.81k | GetByteContext gb, ugb, sgb; |
79 | 7.81k | uint32_t chunk_type, chunk_size, offset; |
80 | 7.81k | uint32_t unique_offset, string_offset; |
81 | 7.81k | int nb_items, unique_size, nb_dictionaries; |
82 | 7.81k | AVRational fps = { 0 }; |
83 | 7.81k | int type; |
84 | | |
85 | 7.81k | chunk_type = avio_rb32(pb); |
86 | 7.81k | chunk_size = avio_rb32(pb); |
87 | | |
88 | 7.81k | if (chunk_type != MKBETAG('@','U','T','F')) |
89 | 687 | return AVERROR_INVALIDDATA; |
90 | | |
91 | 7.12k | if (!chunk_size || chunk_size >= parent_chunk_size) |
92 | 53 | return AVERROR_INVALIDDATA; |
93 | | |
94 | 7.07k | av_fast_malloc(&usm->header, &usm->header_size, chunk_size); |
95 | 7.07k | if (!usm->header) |
96 | 37 | return AVERROR(ENOMEM); |
97 | | |
98 | 7.03k | if (avio_read(pb, usm->header, chunk_size) != chunk_size) |
99 | 137 | return AVERROR_EOF; |
100 | | |
101 | 6.90k | bytestream2_init(&gb, usm->header, chunk_size); |
102 | 6.90k | ugb = gb; |
103 | 6.90k | sgb = gb; |
104 | 6.90k | unique_offset = bytestream2_get_be32(&gb); |
105 | 6.90k | string_offset = bytestream2_get_be32(&gb); |
106 | 6.90k | /*byte_offset =*/ bytestream2_get_be32(&gb); |
107 | 6.90k | /*payload_name_offset =*/ bytestream2_get_be32(&gb); |
108 | 6.90k | nb_items = bytestream2_get_be16(&gb); |
109 | 6.90k | unique_size = bytestream2_get_be16(&gb); |
110 | 6.90k | nb_dictionaries = bytestream2_get_be32(&gb); |
111 | 6.90k | if (nb_dictionaries == 0) |
112 | 35 | return AVERROR_INVALIDDATA; |
113 | | |
114 | 6.86k | bytestream2_skip(&ugb, unique_offset); |
115 | 6.86k | if (bytestream2_get_bytes_left(&ugb) < unique_size) |
116 | 41 | return AVERROR_INVALIDDATA; |
117 | 6.82k | bytestream2_init(&ugb, ugb.buffer, unique_size); |
118 | | |
119 | 6.82k | bytestream2_skip(&sgb, string_offset); |
120 | | |
121 | 35.0M | for (int i = 0; i < nb_items; i++) { |
122 | 35.0M | GetByteContext *xgb; |
123 | 35.0M | uint8_t key[256]; |
124 | 35.0M | int64_t value = -1; |
125 | 35.0M | int n = 0; |
126 | | |
127 | 35.0M | type = bytestream2_get_byte(&gb); |
128 | 35.0M | offset = bytestream2_get_be32(&gb); |
129 | | |
130 | 35.0M | bytestream2_seek(&sgb, string_offset + offset, SEEK_SET); |
131 | 176M | while (bytestream2_get_bytes_left(&sgb) > 0) { |
132 | 151M | key[n] = bytestream2_get_byte(&sgb); |
133 | 151M | if (!key[n]) |
134 | 9.68M | break; |
135 | 141M | if (n >= sizeof(key) - 1) |
136 | 76.2k | break; |
137 | 141M | n++; |
138 | 141M | } |
139 | 35.0M | key[n] = '\0'; |
140 | | |
141 | 35.0M | if ((type >> 5) == 1) |
142 | 70.7k | xgb = &gb; |
143 | 34.9M | else |
144 | 34.9M | xgb = &ugb; |
145 | | |
146 | 35.0M | switch (type & 0x1F) { |
147 | 27.6k | case 0x10: |
148 | 40.5k | case 0x11: |
149 | 40.5k | value = bytestream2_get_byte(xgb); |
150 | 40.5k | break; |
151 | 12.5k | case 0x12: |
152 | 34.8k | case 0x13: |
153 | 34.8k | value = bytestream2_get_be16(xgb); |
154 | 34.8k | break; |
155 | 23.1k | case 0x14: |
156 | 41.2k | case 0x15: |
157 | 41.2k | value = bytestream2_get_be32(xgb); |
158 | 41.2k | break; |
159 | 10.8k | case 0x16: |
160 | 40.4k | case 0x17: |
161 | 40.4k | value = bytestream2_get_be64(xgb); |
162 | 40.4k | break; |
163 | 10.3k | case 0x18: |
164 | 10.3k | value = av_int2float(bytestream2_get_be32(xgb)); |
165 | 10.3k | break; |
166 | 10.1k | case 0x19: |
167 | 10.1k | value = av_int2double(bytestream2_get_be64(xgb)); |
168 | 10.1k | break; |
169 | 4.65k | case 0x1A: |
170 | 4.65k | break; |
171 | 35.0M | } |
172 | | |
173 | 35.0M | if (ch_type == AUDIOI) { |
174 | 4.97M | if (!strcmp(key, "sampling_rate")) { |
175 | 27.6k | ch->rate.num = value; |
176 | 27.6k | ch->rate.den = 1; |
177 | 4.94M | } else if (!strcmp(key, "num_channels")) { |
178 | 282 | ch->nb_channels = value; |
179 | 4.94M | } else if (!strcmp(key, "total_samples")) { |
180 | 256k | ch->duration = value; |
181 | 4.68M | } else if (!strcmp(key, "audio_codec")) { |
182 | 413k | switch (value) { |
183 | 209 | case 2: |
184 | 209 | ch->codec_id = AV_CODEC_ID_ADPCM_ADX; |
185 | 209 | break; |
186 | 104 | case 4: |
187 | 104 | ch->codec_id = AV_CODEC_ID_HCA; |
188 | 104 | break; |
189 | 413k | default: |
190 | 413k | av_log(s, AV_LOG_ERROR, "unsupported audio: %d\n", (int)value); |
191 | 413k | break; |
192 | 413k | } |
193 | 413k | } |
194 | 30.0M | } else if (ch_type == VIDEOI || ch_type == ALPHAI) { |
195 | 29.4M | if (!strcmp(key, "width")) { |
196 | 114k | ch->width = value; |
197 | 29.3M | } else if (!strcmp(key, "height")) { |
198 | 181k | ch->height = value; |
199 | 29.1M | } else if (!strcmp(key, "total_frames")) { |
200 | 83.4k | ch->nb_frames = value; |
201 | 29.1M | } else if (!strcmp(key, "framerate_n")) { |
202 | 735k | fps.num = value; |
203 | 28.3M | } else if (!strcmp(key, "framerate_d")) { |
204 | 45.1k | fps.den = value; |
205 | 28.3M | } else if (!strcmp(key, "mpeg_codec")) { |
206 | 73.6k | switch (value) { |
207 | 229 | case 1: |
208 | 229 | ch->codec_id = AV_CODEC_ID_MPEG1VIDEO; |
209 | 229 | break; |
210 | 4.39k | case 5: |
211 | 4.39k | ch->codec_id = AV_CODEC_ID_H264; |
212 | 4.39k | break; |
213 | 114 | case 9: |
214 | 114 | ch->codec_id = AV_CODEC_ID_VP9; |
215 | 114 | break; |
216 | 68.9k | default: |
217 | 68.9k | av_log(s, AV_LOG_ERROR, "unsupported video: %d\n", (int)value); |
218 | 68.9k | break; |
219 | 73.6k | } |
220 | 73.6k | } |
221 | 29.4M | } |
222 | 35.0M | } |
223 | | |
224 | 6.82k | if (ch_type == VIDEOI && fps.num && fps.den) |
225 | 113 | ch->rate = fps; |
226 | | |
227 | 6.82k | return 0; |
228 | 6.82k | } |
229 | | |
230 | | static int64_t parse_chunk(AVFormatContext *s, AVIOContext *pb, |
231 | | uint32_t chunk_type, uint32_t chunk_size, |
232 | | AVPacket *pkt) |
233 | 48.3k | { |
234 | 48.3k | const int is_audio = chunk_type == MKBETAG('@','S','F','A'); |
235 | 48.3k | const int is_alpha = chunk_type == MKBETAG('@','A','L','P'); |
236 | 48.3k | const int is_subtt = chunk_type == MKBETAG('@','S','B','T'); |
237 | 48.3k | USMDemuxContext *usm = s->priv_data; |
238 | 48.3k | int padding_size, payload_type, payload_offset; |
239 | 48.3k | const int ch_type = is_subtt ? SUBTTI : is_audio ? AUDIOI : is_alpha ? ALPHAI : VIDEOI; |
240 | 48.3k | int stream_index, frame_rate; |
241 | 48.3k | int64_t chunk_start, ret; |
242 | | |
243 | 48.3k | ret = avio_tell(pb); |
244 | 48.3k | if (ret < 0) |
245 | 0 | return ret; |
246 | 48.3k | chunk_start = ret; |
247 | 48.3k | avio_skip(pb, 1); |
248 | 48.3k | payload_offset = avio_r8(pb); |
249 | 48.3k | padding_size = avio_rb16(pb); |
250 | 48.3k | stream_index = avio_r8(pb); |
251 | 48.3k | avio_skip(pb, 2); |
252 | 48.3k | payload_type = avio_r8(pb); |
253 | 48.3k | /*frame_time =*/ avio_rb32(pb); |
254 | 48.3k | frame_rate = avio_rb32(pb); |
255 | 48.3k | avio_skip(pb, 8); |
256 | 48.3k | ret = avio_tell(pb); |
257 | 48.3k | if (ret < 0) |
258 | 0 | return ret; |
259 | 48.3k | ret = avio_skip(pb, FFMAX(0, (ret - chunk_start) - payload_offset)); |
260 | 48.3k | if (ret < 0) |
261 | 24 | return ret; |
262 | | |
263 | 48.2k | if (payload_type == 1) { |
264 | 10.4k | if (usm->ch[ch_type][stream_index].used == 0) { |
265 | 7.81k | USMChannel *ch = &usm->ch[ch_type][stream_index]; |
266 | | |
267 | 7.81k | switch (ch_type) { |
268 | 119 | case ALPHAI: |
269 | 6.45k | case VIDEOI: |
270 | 6.45k | ch->type = AVMEDIA_TYPE_VIDEO; |
271 | 6.45k | break; |
272 | 1.05k | case AUDIOI: |
273 | 1.05k | ch->type = AVMEDIA_TYPE_AUDIO; |
274 | 1.05k | break; |
275 | 299 | case SUBTTI: |
276 | 299 | ch->type = AVMEDIA_TYPE_SUBTITLE; |
277 | 299 | break; |
278 | 0 | default: |
279 | 0 | return AVERROR_INVALIDDATA; |
280 | 7.81k | } |
281 | | |
282 | 7.81k | ch->used = 1; |
283 | 7.81k | ch->index = -1; |
284 | 7.81k | usm->nb_channels[ch_type]++; |
285 | | |
286 | 7.81k | ret = parse_utf(s, pb, ch, ch_type, chunk_size); |
287 | 7.81k | if (ret < 0) |
288 | 990 | return ret; |
289 | 7.81k | } |
290 | 37.8k | } else if (payload_type == 0) { |
291 | 34.7k | if (usm->ch[ch_type][stream_index].used == 1) { |
292 | 31.8k | USMChannel *ch = &usm->ch[ch_type][stream_index]; |
293 | 31.8k | int get_extradata = 0; |
294 | 31.8k | uint32_t pkt_size; |
295 | 31.8k | AVStream *st; |
296 | | |
297 | 31.8k | if (ch->index < 0) { |
298 | 6.37k | AVCodecParameters *par; |
299 | 6.37k | st = avformat_new_stream(s, NULL); |
300 | 6.37k | if (!st) |
301 | 0 | return AVERROR(ENOMEM); |
302 | 6.37k | par = st->codecpar; |
303 | 6.37k | par->codec_type = ch->type; |
304 | 6.37k | par->codec_id = ch->codec_id; |
305 | 6.37k | st->start_time = 0; |
306 | | |
307 | 6.37k | switch (ch->type) { |
308 | 5.58k | case AVMEDIA_TYPE_VIDEO: |
309 | 5.58k | par->width = ch->width; |
310 | 5.58k | par->height = ch->height; |
311 | 5.58k | st->nb_frames = ch->nb_frames; |
312 | 5.58k | break; |
313 | 545 | case AVMEDIA_TYPE_AUDIO: |
314 | 545 | par->sample_rate = ch->rate.num; |
315 | 545 | par->ch_layout.nb_channels = ch->nb_channels; |
316 | 545 | st->duration = ch->duration; |
317 | 545 | break; |
318 | 6.37k | } |
319 | | |
320 | 6.37k | ch->index = st->index; |
321 | 6.37k | if (!ch->rate.num || !ch->rate.den) |
322 | 6.21k | ch->rate = av_make_q(frame_rate, 100); |
323 | 6.37k | avpriv_set_pts_info(st, 64, ch->rate.den, ch->rate.num); |
324 | | |
325 | 6.37k | ffstream(st)->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; |
326 | 6.37k | get_extradata = ch->codec_id == AV_CODEC_ID_ADPCM_ADX; |
327 | 6.37k | ch->extradata_pos = avio_tell(pb); |
328 | 6.37k | } |
329 | | |
330 | 31.8k | ret = avio_tell(pb); |
331 | 31.8k | if (ret < 0) |
332 | 0 | return ret; |
333 | | |
334 | 31.8k | pkt_size = chunk_size - (ret - chunk_start) - padding_size; |
335 | 31.8k | if (get_extradata) { |
336 | 15 | if ((ret = ff_get_extradata(s, st->codecpar, pb, pkt_size)) < 0) |
337 | 3 | return ret; |
338 | 31.8k | } else { |
339 | 31.8k | if (ret == ch->extradata_pos && ch->codec_id == AV_CODEC_ID_ADPCM_ADX) { |
340 | 0 | avio_skip(pb, pkt_size); |
341 | 0 | ret = 0; |
342 | 31.8k | } else { |
343 | 31.8k | ret = av_get_packet(pb, pkt, pkt_size); |
344 | 31.8k | if (ret < 0) |
345 | 1.07k | return ret; |
346 | | |
347 | 30.7k | pkt->stream_index = ch->index; |
348 | 30.7k | } |
349 | 31.8k | } |
350 | | |
351 | 30.7k | avio_skip(pb, padding_size); |
352 | | |
353 | 30.7k | if (ret != pkt_size) |
354 | 338 | return AVERROR_EOF; |
355 | 30.4k | if (get_extradata == 0) |
356 | 30.4k | return ret; |
357 | 30.4k | } |
358 | 34.7k | } |
359 | | |
360 | 15.4k | ret = avio_tell(pb); |
361 | 15.4k | if (ret < 0) |
362 | 0 | return ret; |
363 | 15.4k | ret = avio_skip(pb, FFMAX(0, chunk_size - (ret - chunk_start))); |
364 | 15.4k | if (ret < 0) |
365 | 952 | return ret; |
366 | 14.5k | return FFERROR_REDO; |
367 | 15.4k | } |
368 | | |
369 | | static int usm_read_packet(AVFormatContext *s, AVPacket *pkt) |
370 | 64.5k | { |
371 | 64.5k | AVIOContext *pb = s->pb; |
372 | 64.5k | int64_t ret = AVERROR_EOF; |
373 | | |
374 | 679k | while (!avio_feof(pb)) { |
375 | 668k | uint32_t chunk_type, chunk_size; |
376 | 668k | int got_packet = 0; |
377 | 668k | int64_t pos; |
378 | | |
379 | 668k | pos = avio_tell(pb); |
380 | 668k | if (pos < 0) |
381 | 0 | return pos; |
382 | 668k | chunk_type = avio_rb32(pb); |
383 | 668k | chunk_size = avio_rb32(pb); |
384 | 668k | if (!chunk_size) |
385 | 3.81k | return AVERROR_INVALIDDATA; |
386 | | |
387 | 665k | switch (chunk_type) { |
388 | 22 | case MKBETAG('C','R','I','D'): |
389 | 616k | default: |
390 | 616k | ret = avio_skip(pb, chunk_size); |
391 | 616k | break; |
392 | 290 | case MKBETAG('@','A','L','P'): |
393 | 2.74k | case MKBETAG('@','S','B','T'): |
394 | 5.89k | case MKBETAG('@','S','F','A'): |
395 | 48.3k | case MKBETAG('@','S','F','V'): |
396 | 48.3k | ret = parse_chunk(s, pb, chunk_type, chunk_size, pkt); |
397 | 48.3k | got_packet = ret > 0; |
398 | 48.3k | break; |
399 | 665k | } |
400 | | |
401 | 665k | if (got_packet) |
402 | 30.1k | pkt->pos = pos; |
403 | | |
404 | 665k | if (got_packet || ret < 0) |
405 | 50.3k | break; |
406 | 665k | } |
407 | | |
408 | 60.6k | return ret; |
409 | 64.5k | } |
410 | | |
411 | | static int usm_read_close(AVFormatContext *s) |
412 | 7.85k | { |
413 | 7.85k | USMDemuxContext *usm = s->priv_data; |
414 | 7.85k | av_freep(&usm->header); |
415 | 7.85k | usm->header_size = 0; |
416 | 7.85k | return 0; |
417 | 7.85k | } |
418 | | |
419 | | const FFInputFormat ff_usm_demuxer = { |
420 | | .p.name = "usm", |
421 | | .p.long_name = NULL_IF_CONFIG_SMALL("CRI USM"), |
422 | | .p.extensions = "usm", |
423 | | .p.flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK | AVFMT_NOBINSEARCH, |
424 | | .priv_data_size = sizeof(USMDemuxContext), |
425 | | .read_probe = usm_probe, |
426 | | .read_header = usm_read_header, |
427 | | .read_packet = usm_read_packet, |
428 | | .read_close = usm_read_close, |
429 | | }; |