/src/ffmpeg/libavformat/moflex.c
Line | Count | Source |
1 | | /* |
2 | | * MOFLEX demuxer |
3 | | * Copyright (c) 2015-2016 Florian Nouwt |
4 | | * Copyright (c) 2017 Adib Surani |
5 | | * Copyright (c) 2020 Paul B Mahol |
6 | | * |
7 | | * This file is part of FFmpeg. |
8 | | * |
9 | | * FFmpeg is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * FFmpeg is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with FFmpeg; if not, write to the Free Software |
21 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | | */ |
23 | | |
24 | | #include "libavcodec/bytestream.h" |
25 | | |
26 | | #include "avformat.h" |
27 | | #include "demux.h" |
28 | | #include "internal.h" |
29 | | |
30 | | typedef struct BitReader { |
31 | | unsigned last; |
32 | | unsigned pos; |
33 | | } BitReader; |
34 | | |
35 | | typedef struct MOFLEXDemuxContext { |
36 | | unsigned size; |
37 | | int64_t pos; |
38 | | int64_t ts; |
39 | | int flags; |
40 | | int in_block; |
41 | | |
42 | | BitReader br; |
43 | | } MOFLEXDemuxContext; |
44 | | |
45 | | static int pop(BitReader *br, AVIOContext *pb) |
46 | 263M | { |
47 | 263M | if (avio_feof(pb)) |
48 | 1.19k | return AVERROR_EOF; |
49 | | |
50 | 263M | if ((br->pos & 7) == 0) |
51 | 33.2M | br->last = (unsigned)avio_r8(pb) << 24U; |
52 | 230M | else |
53 | 230M | br->last <<= 1; |
54 | | |
55 | 263M | br->pos++; |
56 | 263M | return !!(br->last & 0x80000000); |
57 | 263M | } |
58 | | |
59 | | static int pop_int(BitReader *br, AVIOContext *pb, int n) |
60 | 18.3M | { |
61 | 18.3M | int value = 0; |
62 | | |
63 | 225M | for (int i = 0; i < n; i++) { |
64 | 208M | int ret = pop(br, pb); |
65 | | |
66 | 208M | if (ret < 0) |
67 | 1.04k | return ret; |
68 | 208M | if (ret > INT_MAX - value - value) |
69 | 1.53M | return AVERROR_INVALIDDATA; |
70 | 206M | value = 2 * value + ret; |
71 | 206M | } |
72 | | |
73 | 16.8M | return value; |
74 | 18.3M | } |
75 | | |
76 | | static int pop_length(BitReader *br, AVIOContext *pb) |
77 | 13.7M | { |
78 | 13.7M | int ret, n = 1; |
79 | | |
80 | 45.8M | while ((ret = pop(br, pb)) == 0) |
81 | 32.0M | n++; |
82 | | |
83 | 13.7M | if (ret < 0) |
84 | 128 | return ret; |
85 | 13.7M | return n; |
86 | 13.7M | } |
87 | | |
88 | | static int read_var_byte(AVFormatContext *s, unsigned *out) |
89 | 346k | { |
90 | 346k | AVIOContext *pb = s->pb; |
91 | 346k | unsigned value = 0, data; |
92 | | |
93 | 346k | data = avio_r8(pb); |
94 | 346k | if (!(data & 0x80)) { |
95 | 234k | *out = data; |
96 | 234k | return 0; |
97 | 234k | } |
98 | | |
99 | 111k | value = (data & 0x7F) << 7; |
100 | 111k | data = avio_r8(pb); |
101 | 111k | if (!(data & 0x80)) { |
102 | 37.9k | value |= data; |
103 | 37.9k | *out = value; |
104 | 37.9k | return 0; |
105 | 37.9k | } |
106 | | |
107 | 73.2k | value = ((data & 0x7F) | value) << 7; |
108 | 73.2k | data = avio_r8(pb); |
109 | 73.2k | if (!(data & 0x80)) { |
110 | 7.87k | value |= data; |
111 | 7.87k | *out = value; |
112 | 7.87k | return 0; |
113 | 7.87k | } |
114 | | |
115 | 65.3k | value = (((data & 0x7F) | value) << 7) | avio_r8(pb); |
116 | 65.3k | *out = value; |
117 | | |
118 | 65.3k | return 0; |
119 | 73.2k | } |
120 | | |
121 | | static int moflex_probe(const AVProbeData *p) |
122 | 942k | { |
123 | 942k | GetByteContext gb; |
124 | 942k | int score = 0; |
125 | | |
126 | 942k | bytestream2_init(&gb, p->buf, p->buf_size); |
127 | | |
128 | 942k | if (bytestream2_get_be16(&gb) != 0x4C32) |
129 | 937k | return 0; |
130 | 5.07k | score += 10; |
131 | | |
132 | 5.07k | bytestream2_skip(&gb, 10); |
133 | 5.07k | if (bytestream2_get_be16(&gb) == 0) |
134 | 543 | return 0; |
135 | 4.53k | score += 5; |
136 | | |
137 | 131k | while (bytestream2_get_bytes_left(&gb) > 0) { |
138 | 129k | int type = bytestream2_get_byte(&gb); |
139 | 129k | int size = bytestream2_get_byte(&gb); |
140 | | |
141 | 129k | if (type == 0) { |
142 | 2.56k | score += 5 * (size == 0); |
143 | 2.56k | break; |
144 | 2.56k | } |
145 | 126k | if ((type == 1 && size == 12) || |
146 | 119k | (type == 2 && size == 6) || |
147 | 117k | (type == 3 && size == 13) || |
148 | 117k | (type == 4 && size == 2)) |
149 | 13.0k | score += 20; |
150 | 126k | bytestream2_skip(&gb, size); |
151 | 126k | } |
152 | | |
153 | 4.53k | return FFMIN(AVPROBE_SCORE_MAX, score); |
154 | 5.07k | } |
155 | | |
156 | | static int moflex_read_sync(AVFormatContext *s) |
157 | 6.68M | { |
158 | 6.68M | MOFLEXDemuxContext *m = s->priv_data; |
159 | 6.68M | AVIOContext *pb = s->pb; |
160 | | |
161 | 6.68M | if (avio_rb16(pb) != 0x4C32) { |
162 | 6.67M | if (avio_feof(pb)) |
163 | 743 | return AVERROR_EOF; |
164 | 6.67M | avio_seek(pb, -2, SEEK_CUR); |
165 | 6.67M | return 1; |
166 | 6.67M | } |
167 | | |
168 | 9.70k | avio_skip(pb, 2); |
169 | 9.70k | m->ts = avio_rb64(pb); |
170 | 9.70k | m->size = avio_rb16(pb) + 1; |
171 | | |
172 | 175k | while (!avio_feof(pb)) { |
173 | 173k | unsigned type, ssize, codec_id = 0; |
174 | 173k | unsigned codec_type, width = 0, height = 0, sample_rate = 0, channels = 0; |
175 | 173k | int stream_index = -1; |
176 | 173k | AVRational tb = av_make_q(0, 1); |
177 | | |
178 | 173k | read_var_byte(s, &type); |
179 | 173k | read_var_byte(s, &ssize); |
180 | | |
181 | 173k | switch (type) { |
182 | 6.58k | case 0: |
183 | 6.58k | if (ssize > 0) |
184 | 2.38k | avio_skip(pb, ssize); |
185 | 6.58k | return 0; |
186 | 4.66k | case 2: |
187 | 4.66k | codec_type = AVMEDIA_TYPE_AUDIO; |
188 | 4.66k | stream_index = avio_r8(pb); |
189 | 4.66k | codec_id = avio_r8(pb); |
190 | 4.66k | switch (codec_id) { |
191 | 3.08k | case 0: codec_id = AV_CODEC_ID_FASTAUDIO; break; |
192 | 142 | case 1: codec_id = AV_CODEC_ID_ADPCM_IMA_MOFLEX; break; |
193 | 1.33k | case 2: codec_id = AV_CODEC_ID_PCM_S16LE; break; |
194 | 99 | default: |
195 | 99 | av_log(s, AV_LOG_ERROR, "Unsupported audio codec: %d\n", codec_id); |
196 | 99 | return AVERROR_PATCHWELCOME; |
197 | 4.66k | } |
198 | 4.56k | sample_rate = avio_rb24(pb) + 1; |
199 | 4.56k | tb = av_make_q(1, sample_rate); |
200 | 4.56k | channels = avio_r8(pb) + 1; |
201 | 4.56k | break; |
202 | 19.0k | case 1: |
203 | 40.4k | case 3: |
204 | 40.4k | codec_type = AVMEDIA_TYPE_VIDEO; |
205 | 40.4k | stream_index = avio_r8(pb); |
206 | 40.4k | codec_id = avio_r8(pb); |
207 | 40.4k | switch (codec_id) { |
208 | 40.2k | case 0: codec_id = AV_CODEC_ID_MOBICLIP; break; |
209 | 215 | default: |
210 | 215 | av_log(s, AV_LOG_ERROR, "Unsupported video codec: %d\n", codec_id); |
211 | 215 | return AVERROR_PATCHWELCOME; |
212 | 40.4k | } |
213 | 40.2k | tb.den = avio_rb16(pb); |
214 | 40.2k | tb.num = avio_rb16(pb); |
215 | 40.2k | width = avio_rb16(pb); |
216 | 40.2k | height = avio_rb16(pb); |
217 | 40.2k | avio_skip(pb, type == 3 ? 3 : 2); |
218 | 40.2k | break; |
219 | 5.56k | case 4: |
220 | 5.56k | codec_type = AVMEDIA_TYPE_DATA; |
221 | 5.56k | stream_index = avio_r8(pb); |
222 | 5.56k | avio_skip(pb, 1); |
223 | 5.56k | break; |
224 | 173k | } |
225 | | |
226 | 166k | if (stream_index == s->nb_streams) { |
227 | 5.14k | AVStream *st = avformat_new_stream(s, NULL); |
228 | | |
229 | 5.14k | if (!st) |
230 | 0 | return AVERROR(ENOMEM); |
231 | | |
232 | 5.14k | st->codecpar->codec_type = codec_type; |
233 | 5.14k | st->codecpar->codec_id = codec_id; |
234 | 5.14k | st->codecpar->width = width; |
235 | 5.14k | st->codecpar->height = height; |
236 | 5.14k | st->codecpar->sample_rate= sample_rate; |
237 | 5.14k | st->codecpar->ch_layout.nb_channels = channels; |
238 | 5.14k | st->priv_data = av_packet_alloc(); |
239 | 5.14k | if (!st->priv_data) |
240 | 0 | return AVERROR(ENOMEM); |
241 | | |
242 | 5.14k | if (tb.num) |
243 | 2.70k | avpriv_set_pts_info(st, 63, tb.num, tb.den); |
244 | 5.14k | } |
245 | 166k | } |
246 | | |
247 | 2.81k | return 0; |
248 | 9.70k | } |
249 | | |
250 | | static int moflex_read_header(AVFormatContext *s) |
251 | 3.54k | { |
252 | 3.54k | int ret; |
253 | | |
254 | 3.54k | ret = moflex_read_sync(s); |
255 | 3.54k | if (ret < 0) |
256 | 155 | return ret; |
257 | | |
258 | 3.39k | s->ctx_flags |= AVFMTCTX_NOHEADER; |
259 | 3.39k | avio_seek(s->pb, 0, SEEK_SET); |
260 | | |
261 | 3.39k | return 0; |
262 | 3.54k | } |
263 | | |
264 | | static int moflex_read_packet(AVFormatContext *s, AVPacket *pkt) |
265 | 4.57M | { |
266 | 4.57M | MOFLEXDemuxContext *m = s->priv_data; |
267 | 4.57M | AVIOContext *pb = s->pb; |
268 | 4.57M | BitReader *br = &m->br; |
269 | 4.57M | int ret; |
270 | | |
271 | 11.2M | while (!avio_feof(pb)) { |
272 | 11.2M | if (!m->in_block) { |
273 | 6.68M | m->pos = avio_tell(pb); |
274 | | |
275 | 6.68M | ret = moflex_read_sync(s); |
276 | 6.68M | if (ret < 0) |
277 | 902 | return ret; |
278 | | |
279 | 6.68M | m->flags = avio_r8(pb); |
280 | 6.68M | if (m->flags & 2) |
281 | 735k | avio_skip(pb, 2); |
282 | 6.68M | } |
283 | | |
284 | 11.3M | while ((avio_tell(pb) < m->pos + m->size) && !avio_feof(pb) && avio_r8(pb)) { |
285 | 4.62M | int stream_index, bits, pkt_size, endframe; |
286 | 4.62M | AVPacket *packet; |
287 | | |
288 | 4.62M | m->in_block = 1; |
289 | | |
290 | 4.62M | avio_seek(pb, -1, SEEK_CUR); |
291 | 4.62M | br->pos = br->last = 0; |
292 | | |
293 | 4.62M | bits = pop_length(br, pb); |
294 | 4.62M | if (bits < 0) |
295 | 0 | return bits; |
296 | 4.62M | stream_index = pop_int(br, pb, bits); |
297 | 4.62M | if (stream_index < 0) |
298 | 47 | return stream_index; |
299 | 4.62M | if (stream_index >= s->nb_streams) |
300 | 1.07k | return AVERROR_INVALIDDATA; |
301 | | |
302 | 4.62M | endframe = pop(br, pb); |
303 | 4.62M | if (endframe < 0) |
304 | 0 | return endframe; |
305 | 4.62M | if (endframe) { |
306 | 4.57M | bits = pop_length(br, pb); |
307 | 4.57M | if (bits < 0) |
308 | 17 | return bits; |
309 | 4.57M | pop_int(br, pb, bits); |
310 | 4.57M | pop(br, pb); |
311 | 4.57M | bits = pop_length(br, pb); |
312 | 4.57M | if (bits < 0) |
313 | 111 | return bits; |
314 | 4.57M | pop_int(br, pb, bits * 2 + 26); |
315 | 4.57M | } |
316 | | |
317 | 4.62M | pkt_size = pop_int(br, pb, 13) + 1; |
318 | 4.62M | if (pkt_size > m->size) |
319 | 1.10k | return AVERROR_INVALIDDATA; |
320 | 4.61M | packet = s->streams[stream_index]->priv_data; |
321 | 4.61M | if (!packet) { |
322 | 0 | avio_skip(pb, pkt_size); |
323 | 0 | continue; |
324 | 0 | } |
325 | | |
326 | 4.61M | ret = av_append_packet(pb, packet, pkt_size); |
327 | 4.61M | if (ret < 0) |
328 | 120 | return ret; |
329 | 4.61M | if (endframe && packet->size > 0) { |
330 | 4.57M | av_packet_move_ref(pkt, packet); |
331 | 4.57M | pkt->pos = m->pos; |
332 | 4.57M | pkt->stream_index = stream_index; |
333 | 4.57M | if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { |
334 | 4.04M | pkt->duration = 1; |
335 | 4.04M | if (pkt->data[0] & 0x80) |
336 | 4.03M | pkt->flags |= AV_PKT_FLAG_KEY; |
337 | 4.04M | } else { |
338 | 529k | pkt->flags |= AV_PKT_FLAG_KEY; |
339 | 529k | } |
340 | 4.57M | return ret; |
341 | 4.57M | } |
342 | 4.61M | } |
343 | | |
344 | 6.68M | m->in_block = 0; |
345 | | |
346 | 6.68M | if (m->flags % 2 == 0) { |
347 | 5.82M | if (m->size <= 0) |
348 | 243 | return AVERROR_INVALIDDATA; |
349 | 5.82M | avio_seek(pb, m->pos + m->size, SEEK_SET); |
350 | 5.82M | } |
351 | 6.68M | } |
352 | | |
353 | 2.90k | return AVERROR_EOF; |
354 | 4.57M | } |
355 | | |
356 | | static int moflex_read_seek(AVFormatContext *s, int stream_index, |
357 | | int64_t pts, int flags) |
358 | 0 | { |
359 | 0 | MOFLEXDemuxContext *m = s->priv_data; |
360 | |
|
361 | 0 | m->in_block = 0; |
362 | |
|
363 | 0 | return -1; |
364 | 0 | } |
365 | | |
366 | | static int moflex_read_close(AVFormatContext *s) |
367 | 3.54k | { |
368 | 8.69k | for (int i = 0; i < s->nb_streams; i++) { |
369 | 5.14k | av_packet_free((AVPacket **)&s->streams[i]->priv_data); |
370 | 5.14k | } |
371 | | |
372 | 3.54k | return 0; |
373 | 3.54k | } |
374 | | |
375 | | const FFInputFormat ff_moflex_demuxer = { |
376 | | .p.name = "moflex", |
377 | | .p.long_name = NULL_IF_CONFIG_SMALL("MobiClip MOFLEX"), |
378 | | .p.extensions = "moflex", |
379 | | .p.flags = AVFMT_GENERIC_INDEX, |
380 | | .priv_data_size = sizeof(MOFLEXDemuxContext), |
381 | | .read_probe = moflex_probe, |
382 | | .read_header = moflex_read_header, |
383 | | .read_packet = moflex_read_packet, |
384 | | .read_seek = moflex_read_seek, |
385 | | .read_close = moflex_read_close, |
386 | | .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP, |
387 | | }; |