/src/ffmpeg/libavformat/asfdec_o.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Microsoft Advanced Streaming Format demuxer |
3 | | * Copyright (c) 2014 Alexandra Hájková |
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 <time.h> |
23 | | |
24 | | #include "libavutil/attributes.h" |
25 | | #include "libavutil/common.h" |
26 | | #include "libavutil/dict.h" |
27 | | #include "libavutil/internal.h" |
28 | | #include "libavutil/mathematics.h" |
29 | | #include "libavutil/mem.h" |
30 | | #include "libavutil/time_internal.h" |
31 | | |
32 | | #include "avformat.h" |
33 | | #include "avlanguage.h" |
34 | | #include "demux.h" |
35 | | #include "internal.h" |
36 | | #include "riff.h" |
37 | | #include "asf.h" |
38 | | #include "asfcrypt.h" |
39 | | |
40 | 324 | #define ASF_BOOL 0x2 |
41 | 0 | #define ASF_WORD 0x5 |
42 | 49 | #define ASF_GUID 0x6 |
43 | 152 | #define ASF_DWORD 0x3 |
44 | 17 | #define ASF_QWORD 0x4 |
45 | 1.21k | #define ASF_UNICODE 0x0 |
46 | 1.96k | #define ASF_FLAG_BROADCAST 0x1 |
47 | 824 | #define ASF_BYTE_ARRAY 0x1 |
48 | | #define ASF_TYPE_AUDIO 0x2 |
49 | | #define ASF_TYPE_VIDEO 0x1 |
50 | 12.6k | #define ASF_STREAM_NUM 0x7F |
51 | 16.5k | #define ASF_MAX_STREAMS 128 |
52 | 122 | #define BMP_HEADER_SIZE 40 |
53 | 8.04k | #define ASF_NUM_OF_PAYLOADS 0x3F |
54 | 646 | #define ASF_ERROR_CORRECTION_LENGTH_TYPE 0x60 |
55 | 329 | #define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2 |
56 | | |
57 | | typedef struct GUIDParseTable { |
58 | | const char *name; |
59 | | ff_asf_guid guid; |
60 | | int (*read_object)(AVFormatContext *, const struct GUIDParseTable *); |
61 | | int is_subobject; |
62 | | } GUIDParseTable; |
63 | | |
64 | | typedef struct ASFPacket { |
65 | | AVPacket *avpkt; |
66 | | int64_t dts; |
67 | | uint32_t frame_num; // ASF payloads with the same number are parts of the same frame |
68 | | int flags; |
69 | | int data_size; |
70 | | int duration; |
71 | | int size_left; |
72 | | uint8_t stream_index; |
73 | | } ASFPacket; |
74 | | |
75 | | typedef struct ASFStream { |
76 | | uint8_t stream_index; // from packet header |
77 | | int index; // stream index in AVFormatContext, set in asf_read_stream_properties |
78 | | int type; |
79 | | int indexed; // added index entries from the Simple Index Object or not |
80 | | int8_t span; // for deinterleaving |
81 | | uint16_t virtual_pkt_len; |
82 | | uint16_t virtual_chunk_len; |
83 | | int16_t lang_idx; |
84 | | ASFPacket pkt; |
85 | | } ASFStream; |
86 | | |
87 | | typedef struct ASFStreamData{ |
88 | | char langs[32]; |
89 | | AVDictionary *asf_met; // for storing per-stream metadata |
90 | | AVRational aspect_ratio; |
91 | | } ASFStreamData; |
92 | | |
93 | | typedef struct ASFContext { |
94 | | int data_reached; |
95 | | int is_simple_index; // is simple index present or not 1/0 |
96 | | int is_header; |
97 | | |
98 | | uint64_t preroll; |
99 | | uint64_t nb_packets; // ASF packets |
100 | | uint32_t packet_size; |
101 | | int64_t send_time; |
102 | | int duration; |
103 | | |
104 | | uint32_t b_flags; // flags with broadcast flag |
105 | | uint32_t prop_flags; // file properties object flags |
106 | | |
107 | | uint64_t data_size; // data object size |
108 | | uint64_t unknown_size; // size of the unknown object |
109 | | |
110 | | int64_t offset; // offset of the current object |
111 | | |
112 | | int64_t data_offset; |
113 | | int64_t first_packet_offset; // packet offset |
114 | | int64_t unknown_offset; // for top level header objects or subobjects without specified behavior |
115 | | int in_asf_read_unknown; |
116 | | |
117 | | // ASF file must not contain more than 128 streams according to the specification |
118 | | ASFStream *asf_st[ASF_MAX_STREAMS]; |
119 | | ASFStreamData asf_sd[ASF_MAX_STREAMS]; |
120 | | int nb_streams; |
121 | | |
122 | | int stream_index; // from packet header, for the subpayload case |
123 | | |
124 | | // packet parameters |
125 | | uint64_t sub_header_offset; // offset of subpayload header |
126 | | int64_t sub_dts; |
127 | | uint8_t dts_delta; // for subpayloads |
128 | | uint32_t packet_size_internal; // packet size stored inside ASFPacket, can be 0 |
129 | | int64_t packet_offset; // offset of the current packet inside Data Object |
130 | | uint32_t pad_len; // padding after payload |
131 | | uint32_t rep_data_len; |
132 | | |
133 | | // packet state |
134 | | uint64_t sub_left; // subpayloads left or not |
135 | | unsigned int nb_sub; // number of subpayloads read so far from the current ASF packet |
136 | | uint16_t mult_sub_len; // total length of subpayloads array inside multiple payload |
137 | | uint64_t nb_mult_left; // multiple payloads left |
138 | | int return_subpayload; |
139 | | enum { |
140 | | PARSE_PACKET_HEADER, |
141 | | READ_SINGLE, |
142 | | READ_MULTI, |
143 | | READ_MULTI_SUB |
144 | | } state; |
145 | | } ASFContext; |
146 | | |
147 | | static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size); |
148 | | static const GUIDParseTable *find_guid(ff_asf_guid guid); |
149 | | |
150 | | static int asf_probe(const AVProbeData *pd) |
151 | 924k | { |
152 | | /* check file header */ |
153 | 924k | if (!ff_guidcmp(pd->buf, &ff_asf_header)) |
154 | 3.65k | return AVPROBE_SCORE_MAX/2; |
155 | 920k | else |
156 | 920k | return 0; |
157 | 924k | } |
158 | | |
159 | | static void swap_guid(ff_asf_guid guid) |
160 | 259k | { |
161 | 259k | FFSWAP(unsigned char, guid[0], guid[3]); |
162 | 259k | FFSWAP(unsigned char, guid[1], guid[2]); |
163 | 259k | FFSWAP(unsigned char, guid[4], guid[5]); |
164 | 259k | FFSWAP(unsigned char, guid[6], guid[7]); |
165 | 259k | } |
166 | | |
167 | | static void align_position(AVIOContext *pb, int64_t offset, uint64_t size) |
168 | 15.9k | { |
169 | 15.9k | if (size < INT64_MAX - offset && avio_tell(pb) != offset + size) |
170 | 1.17k | avio_seek(pb, offset + size, SEEK_SET); |
171 | 15.9k | } |
172 | | |
173 | | static int asf_read_unknown(AVFormatContext *s, const GUIDParseTable *g) |
174 | 242k | { |
175 | 242k | ASFContext *asf = s->priv_data; |
176 | 242k | AVIOContext *pb = s->pb; |
177 | 242k | uint64_t size = avio_rl64(pb); |
178 | 242k | int ret; |
179 | | |
180 | 242k | if (size > INT64_MAX || asf->in_asf_read_unknown > 5) |
181 | 107k | return AVERROR_INVALIDDATA; |
182 | | |
183 | 135k | if (asf->is_header) |
184 | 61 | asf->unknown_size = size; |
185 | 135k | asf->is_header = 0; |
186 | 135k | if (!g->is_subobject) { |
187 | 91 | if (!(ret = strcmp(g->name, "Header Extension"))) |
188 | 91 | avio_skip(pb, 22); // skip reserved fields and Data Size |
189 | 91 | asf->in_asf_read_unknown ++; |
190 | 91 | ret = detect_unknown_subobject(s, asf->unknown_offset, |
191 | 91 | asf->unknown_size); |
192 | 91 | asf->in_asf_read_unknown --; |
193 | 91 | if (ret < 0) |
194 | 35 | return ret; |
195 | 135k | } else { |
196 | 135k | if (size < 24) { |
197 | 21.9k | av_log(s, AV_LOG_ERROR, "Too small size %"PRIu64" (< 24).\n", size); |
198 | 21.9k | return AVERROR_INVALIDDATA; |
199 | 21.9k | } |
200 | 113k | avio_skip(pb, size - 24); |
201 | 113k | } |
202 | | |
203 | 113k | return 0; |
204 | 135k | } |
205 | | |
206 | | static int get_asf_string(AVIOContext *pb, int maxlen, char *buf, int buflen) |
207 | 24.8k | { |
208 | 24.8k | char *q = buf; |
209 | 24.8k | int ret = 0; |
210 | 24.8k | if (buflen <= 0) |
211 | 0 | return AVERROR(EINVAL); |
212 | 663k | while (ret + 1 < maxlen) { |
213 | 653k | uint8_t tmp; |
214 | 653k | uint32_t ch; |
215 | 653k | GET_UTF16(ch, (ret += 2) <= maxlen ? avio_rl16(pb) : 0, break;); |
216 | 638k | PUT_UTF8(ch, tmp, if (q - buf < buflen - 1) *q++ = tmp;) |
217 | 638k | } |
218 | 24.8k | *q = 0; |
219 | | |
220 | 24.8k | return ret; |
221 | 24.8k | } |
222 | | |
223 | | static int asf_read_marker(AVFormatContext *s, const GUIDParseTable *g) |
224 | 46 | { |
225 | 46 | ASFContext *asf = s->priv_data; |
226 | 46 | AVIOContext *pb = s->pb; |
227 | 46 | uint64_t size = avio_rl64(pb); |
228 | 46 | int i, nb_markers, ret; |
229 | 46 | size_t len; |
230 | 46 | char name[1024]; |
231 | | |
232 | 46 | avio_skip(pb, 8); |
233 | 46 | avio_skip(pb, 8); // skip reserved GUID |
234 | 46 | nb_markers = avio_rl32(pb); |
235 | 46 | avio_skip(pb, 2); // skip reserved field |
236 | 46 | len = avio_rl16(pb); |
237 | 50.3k | for (i = 0; i < len; i++) |
238 | 50.3k | avio_skip(pb, 1); |
239 | | |
240 | 23.5k | for (i = 0; i < nb_markers; i++) { |
241 | 23.5k | int64_t pts; |
242 | | |
243 | 23.5k | avio_skip(pb, 8); |
244 | 23.5k | pts = avio_rl64(pb); |
245 | 23.5k | pts -= asf->preroll * 10000; |
246 | 23.5k | avio_skip(pb, 2); // entry length |
247 | 23.5k | avio_skip(pb, 4); // send time |
248 | 23.5k | avio_skip(pb, 4); // flags |
249 | 23.5k | len = avio_rl32(pb); |
250 | | |
251 | 23.5k | if (avio_feof(pb)) |
252 | 1 | return AVERROR_INVALIDDATA; |
253 | | |
254 | 23.5k | if ((ret = avio_get_str16le(pb, len, name, |
255 | 23.5k | sizeof(name))) < len) |
256 | 23.2k | avio_skip(pb, len - ret); |
257 | 23.5k | avpriv_new_chapter(s, i, (AVRational) { 1, 10000000 }, pts, |
258 | 23.5k | AV_NOPTS_VALUE, name); |
259 | 23.5k | } |
260 | 45 | align_position(pb, asf->offset, size); |
261 | | |
262 | 45 | return 0; |
263 | 46 | } |
264 | | |
265 | | static int asf_read_metadata(AVFormatContext *s, const char *title, uint16_t len, |
266 | | unsigned char *ch, uint16_t buflen) |
267 | 145 | { |
268 | 145 | AVIOContext *pb = s->pb; |
269 | | |
270 | 145 | avio_get_str16le(pb, len, ch, buflen); |
271 | 145 | if (ch[0]) { |
272 | 33 | if (av_dict_set(&s->metadata, title, ch, 0) < 0) |
273 | 0 | av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); |
274 | 33 | } |
275 | | |
276 | 145 | return 0; |
277 | 145 | } |
278 | | |
279 | | static int asf_read_value(AVFormatContext *s, const uint8_t *name, |
280 | | uint16_t val_len, int type, AVDictionary **met) |
281 | 939 | { |
282 | 939 | int ret; |
283 | 939 | uint8_t *value; |
284 | 939 | uint16_t buflen = 2 * val_len + 1; |
285 | 939 | AVIOContext *pb = s->pb; |
286 | | |
287 | 939 | value = av_malloc(buflen); |
288 | 939 | if (!value) |
289 | 0 | return AVERROR(ENOMEM); |
290 | 939 | if (type == ASF_UNICODE) { |
291 | | // get_asf_string reads UTF-16 and converts it to UTF-8 which needs longer buffer |
292 | 271 | if ((ret = get_asf_string(pb, val_len, value, buflen)) < 0) |
293 | 0 | goto failed; |
294 | 271 | if (av_dict_set(met, name, value, 0) < 0) |
295 | 0 | av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); |
296 | 668 | } else { |
297 | 668 | char buf[256]; |
298 | 668 | if (val_len > sizeof(buf)) { |
299 | 665 | ret = AVERROR_INVALIDDATA; |
300 | 665 | goto failed; |
301 | 665 | } |
302 | 3 | if ((ret = avio_read(pb, value, val_len)) < 0) |
303 | 0 | goto failed; |
304 | 3 | if (ret < 2 * val_len) |
305 | 3 | value[ret] = '\0'; |
306 | 0 | else |
307 | 0 | value[2 * val_len - 1] = '\0'; |
308 | 3 | snprintf(buf, sizeof(buf), "%s", value); |
309 | 3 | if (av_dict_set(met, name, buf, 0) < 0) |
310 | 0 | av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); |
311 | 3 | } |
312 | 274 | av_freep(&value); |
313 | | |
314 | 274 | return 0; |
315 | | |
316 | 665 | failed: |
317 | 665 | av_freep(&value); |
318 | 665 | return ret; |
319 | 939 | } |
320 | | static int asf_read_generic_value(AVIOContext *pb, int type, uint64_t *value) |
321 | 272 | { |
322 | | |
323 | 272 | switch (type) { |
324 | 63 | case ASF_BOOL: |
325 | 63 | *value = avio_rl16(pb); |
326 | 63 | break; |
327 | 95 | case ASF_DWORD: |
328 | 95 | *value = avio_rl32(pb); |
329 | 95 | break; |
330 | 17 | case ASF_QWORD: |
331 | 17 | *value = avio_rl64(pb); |
332 | 17 | break; |
333 | 0 | case ASF_WORD: |
334 | 0 | *value = avio_rl16(pb); |
335 | 0 | break; |
336 | 97 | default: |
337 | 97 | return AVERROR_INVALIDDATA; |
338 | 272 | } |
339 | | |
340 | 175 | return 0; |
341 | 272 | } |
342 | | |
343 | | static int asf_set_metadata(AVFormatContext *s, const uint8_t *name, |
344 | | int type, AVDictionary **met) |
345 | 272 | { |
346 | 272 | AVIOContext *pb = s->pb; |
347 | 272 | uint64_t value; |
348 | 272 | char buf[32]; |
349 | 272 | int ret; |
350 | | |
351 | 272 | ret = asf_read_generic_value(pb, type, &value); |
352 | 272 | if (ret < 0) |
353 | 97 | return ret; |
354 | | |
355 | 175 | snprintf(buf, sizeof(buf), "%"PRIu64, value); |
356 | 175 | if (av_dict_set(met, name, buf, 0) < 0) |
357 | 0 | av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); |
358 | | |
359 | 175 | return 0; |
360 | 272 | } |
361 | | |
362 | | static int process_metadata(AVFormatContext *s, const uint8_t *name, uint16_t name_len, |
363 | | uint16_t val_len, uint16_t type, AVDictionary **met) |
364 | 1.42k | { |
365 | 1.42k | int ret; |
366 | 1.42k | ff_asf_guid guid; |
367 | | |
368 | 1.42k | if (val_len) { |
369 | 1.41k | switch (type) { |
370 | 271 | case ASF_UNICODE: |
371 | 271 | asf_read_value(s, name, val_len, type, met); |
372 | 271 | break; |
373 | 824 | case ASF_BYTE_ARRAY: |
374 | 824 | if (ff_asf_handle_byte_array(s, name, val_len) > 0) |
375 | 668 | asf_read_value(s, name, val_len, type, met); |
376 | 824 | break; |
377 | 49 | case ASF_GUID: |
378 | 49 | ff_get_guid(s->pb, &guid); |
379 | 49 | break; |
380 | 272 | default: |
381 | 272 | if ((ret = asf_set_metadata(s, name, type, met)) < 0) |
382 | 97 | return ret; |
383 | 175 | break; |
384 | 1.41k | } |
385 | 1.41k | } |
386 | | |
387 | 1.33k | return 0; |
388 | 1.42k | } |
389 | | |
390 | | static int asf_read_ext_content(AVFormatContext *s, const GUIDParseTable *g) |
391 | 74 | { |
392 | 74 | ASFContext *asf = s->priv_data; |
393 | 74 | AVIOContext *pb = s->pb; |
394 | 74 | uint64_t size = avio_rl64(pb); |
395 | 74 | uint16_t nb_desc = avio_rl16(pb); |
396 | 74 | int i, ret; |
397 | | |
398 | 335 | for (i = 0; i < nb_desc; i++) { |
399 | 261 | uint16_t name_len, type, val_len; |
400 | 261 | uint8_t *name = NULL; |
401 | | |
402 | 261 | name_len = avio_rl16(pb); |
403 | 261 | if (!name_len) |
404 | 0 | return AVERROR_INVALIDDATA; |
405 | 261 | name = av_malloc(name_len); |
406 | 261 | if (!name) |
407 | 0 | return AVERROR(ENOMEM); |
408 | 261 | avio_get_str16le(pb, name_len, name, |
409 | 261 | name_len); |
410 | 261 | type = avio_rl16(pb); |
411 | | // BOOL values are 16 bits long in the Metadata Object |
412 | | // but 32 bits long in the Extended Content Description Object |
413 | 261 | if (type == ASF_BOOL) |
414 | 57 | type = ASF_DWORD; |
415 | 261 | val_len = avio_rl16(pb); |
416 | | |
417 | 261 | ret = process_metadata(s, name, name_len, val_len, type, &s->metadata); |
418 | 261 | av_freep(&name); |
419 | 261 | if (ret < 0) |
420 | 0 | return ret; |
421 | 261 | } |
422 | | |
423 | 74 | align_position(pb, asf->offset, size); |
424 | 74 | return 0; |
425 | 74 | } |
426 | | |
427 | | static AVStream *find_stream(AVFormatContext *s, uint16_t st_num) |
428 | 3.96k | { |
429 | 3.96k | AVStream *st = NULL; |
430 | 3.96k | ASFContext *asf = s->priv_data; |
431 | 3.96k | int i; |
432 | | |
433 | 18.2k | for (i = 0; i < asf->nb_streams; i++) { |
434 | 14.3k | if (asf->asf_st[i]->stream_index == st_num) { |
435 | 114 | st = s->streams[asf->asf_st[i]->index]; |
436 | 114 | break; |
437 | 114 | } |
438 | 14.3k | } |
439 | | |
440 | 3.96k | return st; |
441 | 3.96k | } |
442 | | |
443 | | static int asf_store_aspect_ratio(AVFormatContext *s, uint8_t st_num, uint8_t *name, int type) |
444 | 0 | { |
445 | 0 | ASFContext *asf = s->priv_data; |
446 | 0 | AVIOContext *pb = s->pb; |
447 | 0 | uint64_t value = 0; |
448 | 0 | int ret; |
449 | |
|
450 | 0 | ret = asf_read_generic_value(pb, type, &value); |
451 | 0 | if (ret < 0) |
452 | 0 | return ret; |
453 | | |
454 | 0 | if (st_num < ASF_MAX_STREAMS) { |
455 | 0 | if (!strcmp(name, "AspectRatioX")) |
456 | 0 | asf->asf_sd[st_num].aspect_ratio.num = value; |
457 | 0 | else |
458 | 0 | asf->asf_sd[st_num].aspect_ratio.den = value; |
459 | 0 | } |
460 | 0 | return 0; |
461 | 0 | } |
462 | | |
463 | | static int asf_read_metadata_obj(AVFormatContext *s, const GUIDParseTable *g) |
464 | 201 | { |
465 | 201 | ASFContext *asf = s->priv_data; |
466 | 201 | AVIOContext *pb = s->pb; |
467 | 201 | uint64_t size = avio_rl64(pb); |
468 | 201 | uint16_t nb_recs = avio_rl16(pb); // number of records in the Description Records list |
469 | 201 | int i, ret; |
470 | | |
471 | 2.84k | for (i = 0; i < nb_recs; i++) { |
472 | 2.82k | uint16_t name_len, buflen, type, val_len, st_num; |
473 | 2.82k | uint8_t *name = NULL; |
474 | | |
475 | 2.82k | avio_skip(pb, 2); // skip reserved field |
476 | 2.82k | st_num = avio_rl16(pb); |
477 | 2.82k | name_len = avio_rl16(pb); |
478 | 2.82k | buflen = 2 * name_len + 1; |
479 | 2.82k | if (!name_len) |
480 | 78 | break; |
481 | 2.74k | type = avio_rl16(pb); |
482 | 2.74k | val_len = avio_rl32(pb); |
483 | 2.74k | name = av_malloc(buflen); |
484 | 2.74k | if (!name) |
485 | 0 | return AVERROR(ENOMEM); |
486 | 2.74k | avio_get_str16le(pb, name_len, name, |
487 | 2.74k | buflen); |
488 | 2.74k | if (!strcmp(name, "AspectRatioX") || !strcmp(name, "AspectRatioY")) { |
489 | 0 | ret = asf_store_aspect_ratio(s, st_num, name, type); |
490 | 0 | if (ret < 0) { |
491 | 0 | av_freep(&name); |
492 | 0 | break; |
493 | 0 | } |
494 | 2.74k | } else { |
495 | 2.74k | if (st_num < ASF_MAX_STREAMS) { |
496 | 1.16k | if ((ret = process_metadata(s, name, name_len, val_len, type, |
497 | 1.16k | st_num ? &asf->asf_sd[st_num].asf_met |
498 | 1.16k | : &s->metadata)) < 0) { |
499 | 97 | av_freep(&name); |
500 | 97 | break; |
501 | 97 | } |
502 | 1.16k | } |
503 | 2.74k | } |
504 | 2.64k | av_freep(&name); |
505 | 2.64k | } |
506 | | |
507 | 201 | align_position(pb, asf->offset, size); |
508 | 201 | return 0; |
509 | 201 | } |
510 | | |
511 | | static int asf_read_content_desc(AVFormatContext *s, const GUIDParseTable *g) |
512 | 29 | { |
513 | 29 | ASFContext *asf = s->priv_data; |
514 | 29 | AVIOContext *pb = s->pb; |
515 | 29 | int i; |
516 | 29 | static const char *const titles[] = |
517 | 29 | { "Title", "Author", "Copyright", "Description", "Rate" }; |
518 | 29 | uint16_t len[5], buflen[5] = { 0 }; |
519 | 29 | uint8_t *ch; |
520 | 29 | uint64_t size = avio_rl64(pb); |
521 | | |
522 | 174 | for (i = 0; i < 5; i++) { |
523 | 145 | len[i] = avio_rl16(pb); |
524 | | // utf8 string should be <= 2 * utf16 string, extra byte for the terminator |
525 | 145 | buflen[i] = 2 * len[i] + 1; |
526 | 145 | } |
527 | | |
528 | 174 | for (i = 0; i < 5; i++) { |
529 | 145 | ch = av_malloc(buflen[i]); |
530 | 145 | if (!ch) |
531 | 0 | return(AVERROR(ENOMEM)); |
532 | 145 | asf_read_metadata(s, titles[i], len[i], ch, buflen[i]); |
533 | 145 | av_freep(&ch); |
534 | 145 | } |
535 | 29 | align_position(pb, asf->offset, size); |
536 | | |
537 | 29 | return 0; |
538 | 29 | } |
539 | | |
540 | | static int asf_read_properties(AVFormatContext *s, const GUIDParseTable *g) |
541 | 139 | { |
542 | 139 | ASFContext *asf = s->priv_data; |
543 | 139 | AVIOContext *pb = s->pb; |
544 | 139 | time_t creation_time; |
545 | | |
546 | 139 | avio_rl64(pb); // read object size |
547 | 139 | avio_skip(pb, 16); // skip File ID |
548 | 139 | avio_skip(pb, 8); // skip File size |
549 | 139 | creation_time = avio_rl64(pb); |
550 | 139 | if (!(asf->b_flags & ASF_FLAG_BROADCAST)) { |
551 | 92 | struct tm tmbuf; |
552 | 92 | struct tm *tm; |
553 | 92 | char buf[64]; |
554 | | |
555 | | // creation date is in 100 ns units from 1 Jan 1601, conversion to s |
556 | 92 | creation_time /= 10000000; |
557 | | // there are 11644473600 seconds between 1 Jan 1601 and 1 Jan 1970 |
558 | 92 | creation_time -= 11644473600; |
559 | 92 | tm = gmtime_r(&creation_time, &tmbuf); |
560 | 92 | if (tm) { |
561 | 92 | if (!strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)) |
562 | 0 | buf[0] = '\0'; |
563 | 92 | } else |
564 | 0 | buf[0] = '\0'; |
565 | 92 | if (buf[0]) { |
566 | 92 | if (av_dict_set(&s->metadata, "creation_time", buf, 0) < 0) |
567 | 0 | av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); |
568 | 92 | } |
569 | 92 | } |
570 | 139 | asf->nb_packets = avio_rl64(pb); |
571 | 139 | asf->duration = avio_rl64(pb) / 10000; // stream duration |
572 | 139 | avio_skip(pb, 8); // skip send duration |
573 | 139 | asf->preroll = avio_rl64(pb); |
574 | 139 | asf->duration -= asf->preroll; |
575 | 139 | asf->b_flags = avio_rl32(pb); |
576 | 139 | avio_skip(pb, 4); // skip minimal packet size |
577 | 139 | asf->packet_size = avio_rl32(pb); |
578 | 139 | avio_skip(pb, 4); // skip max_bitrate |
579 | | |
580 | 139 | return 0; |
581 | 139 | } |
582 | | |
583 | | static int parse_video_info(AVFormatContext *avfmt, AVIOContext *pb, AVStream *st) |
584 | 78 | { |
585 | 78 | uint16_t size_asf; // ASF-specific Format Data size |
586 | 78 | uint32_t size_bmp; // BMP_HEADER-specific Format Data size |
587 | 78 | unsigned int tag; |
588 | | |
589 | 78 | st->codecpar->width = avio_rl32(pb); |
590 | 78 | st->codecpar->height = avio_rl32(pb); |
591 | 78 | avio_skip(pb, 1); // skip reserved flags |
592 | 78 | size_asf = avio_rl16(pb); |
593 | 78 | tag = ff_get_bmp_header(pb, st, &size_bmp); |
594 | 78 | st->codecpar->codec_tag = tag; |
595 | 78 | st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); |
596 | 78 | size_bmp = FFMAX(size_asf, size_bmp); |
597 | | |
598 | 78 | if (size_bmp > BMP_HEADER_SIZE) { |
599 | 44 | int ret = ff_get_extradata(avfmt, st->codecpar, pb, size_bmp - BMP_HEADER_SIZE); |
600 | | |
601 | 44 | if (ret < 0) |
602 | 1 | return ret; |
603 | 44 | } |
604 | 77 | return 0; |
605 | 78 | } |
606 | | |
607 | | static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable *g) |
608 | 359 | { |
609 | 359 | ASFContext *asf = s->priv_data; |
610 | 359 | AVIOContext *pb = s->pb; |
611 | 359 | uint64_t size; |
612 | 359 | uint32_t err_data_len, ts_data_len; // type specific data length |
613 | 359 | uint16_t flags; |
614 | 359 | ff_asf_guid stream_type; |
615 | 359 | enum AVMediaType type; |
616 | 359 | int i, ret; |
617 | 359 | uint8_t stream_index; |
618 | 359 | AVStream *st; |
619 | 359 | ASFStream *asf_st; |
620 | | |
621 | | // ASF file must not contain more than 128 streams according to the specification |
622 | 359 | if (asf->nb_streams >= ASF_MAX_STREAMS) |
623 | 0 | return AVERROR_INVALIDDATA; |
624 | | |
625 | 359 | size = avio_rl64(pb); |
626 | 359 | ff_get_guid(pb, &stream_type); |
627 | 359 | if (!ff_guidcmp(&stream_type, &ff_asf_audio_stream)) |
628 | 130 | type = AVMEDIA_TYPE_AUDIO; |
629 | 229 | else if (!ff_guidcmp(&stream_type, &ff_asf_video_stream)) |
630 | 78 | type = AVMEDIA_TYPE_VIDEO; |
631 | 151 | else if (!ff_guidcmp(&stream_type, &ff_asf_jfif_media)) |
632 | 63 | type = AVMEDIA_TYPE_VIDEO; |
633 | 88 | else if (!ff_guidcmp(&stream_type, &ff_asf_command_stream)) |
634 | 60 | type = AVMEDIA_TYPE_DATA; |
635 | 28 | else if (!ff_guidcmp(&stream_type, |
636 | 28 | &ff_asf_ext_stream_embed_stream_header)) |
637 | 26 | type = AVMEDIA_TYPE_UNKNOWN; |
638 | 2 | else |
639 | 2 | return AVERROR_INVALIDDATA; |
640 | | |
641 | 357 | ff_get_guid(pb, &stream_type); // error correction type |
642 | 357 | avio_skip(pb, 8); // skip the time offset |
643 | 357 | ts_data_len = avio_rl32(pb); |
644 | 357 | err_data_len = avio_rl32(pb); |
645 | 357 | flags = avio_rl16(pb); // bit 15 - Encrypted Content |
646 | | |
647 | 357 | stream_index = flags & ASF_STREAM_NUM; |
648 | 904 | for (i = 0; i < asf->nb_streams; i++) |
649 | 693 | if (stream_index == asf->asf_st[i]->stream_index) { |
650 | 146 | av_log(s, AV_LOG_WARNING, |
651 | 146 | "Duplicate stream found, this stream will be ignored.\n"); |
652 | 146 | align_position(pb, asf->offset, size); |
653 | 146 | return 0; |
654 | 146 | } |
655 | | |
656 | 211 | st = avformat_new_stream(s, NULL); |
657 | 211 | if (!st) |
658 | 0 | return AVERROR(ENOMEM); |
659 | 211 | avpriv_set_pts_info(st, 32, 1, 1000); // pts should be dword, in milliseconds |
660 | 211 | st->codecpar->codec_type = type; |
661 | 211 | asf->asf_st[asf->nb_streams] = av_mallocz(sizeof(*asf_st)); |
662 | 211 | if (!asf->asf_st[asf->nb_streams]) |
663 | 0 | return AVERROR(ENOMEM); |
664 | 211 | asf_st = asf->asf_st[asf->nb_streams]; |
665 | 211 | asf->nb_streams++; |
666 | 211 | asf_st->stream_index = stream_index; |
667 | 211 | asf_st->index = st->index; |
668 | 211 | asf_st->indexed = 0; |
669 | 211 | st->id = flags & ASF_STREAM_NUM; |
670 | 211 | asf_st->pkt.data_size = 0; |
671 | 211 | asf_st->pkt.avpkt = av_packet_alloc(); |
672 | 211 | if (!asf_st->pkt.avpkt) |
673 | 0 | return AVERROR(ENOMEM); |
674 | 211 | avio_skip(pb, 4); // skip reserved field |
675 | | |
676 | 211 | switch (type) { |
677 | 67 | case AVMEDIA_TYPE_AUDIO: |
678 | 67 | asf_st->type = AVMEDIA_TYPE_AUDIO; |
679 | 67 | if ((ret = ff_get_wav_header(s, pb, st->codecpar, ts_data_len, 0)) < 0) |
680 | 0 | return ret; |
681 | 67 | break; |
682 | 78 | case AVMEDIA_TYPE_VIDEO: |
683 | 78 | asf_st->type = AVMEDIA_TYPE_VIDEO; |
684 | 78 | if ((ret = parse_video_info(s, pb, st)) < 0) |
685 | 1 | return ret; |
686 | 77 | break; |
687 | 77 | default: |
688 | 66 | avio_skip(pb, ts_data_len); |
689 | 66 | break; |
690 | 211 | } |
691 | | |
692 | 210 | if (err_data_len) { |
693 | 186 | if (type == AVMEDIA_TYPE_AUDIO) { |
694 | 65 | uint8_t span = avio_r8(pb); |
695 | 65 | if (span > 1) { |
696 | 16 | asf_st->span = span; |
697 | 16 | asf_st->virtual_pkt_len = avio_rl16(pb); |
698 | 16 | asf_st->virtual_chunk_len = avio_rl16(pb); |
699 | 16 | if (!asf_st->virtual_chunk_len || !asf_st->virtual_pkt_len) |
700 | 0 | return AVERROR_INVALIDDATA; |
701 | 16 | avio_skip(pb, err_data_len - 5); |
702 | 16 | } else |
703 | 49 | avio_skip(pb, err_data_len - 1); |
704 | 65 | } else |
705 | 121 | avio_skip(pb, err_data_len); |
706 | 186 | } |
707 | | |
708 | 210 | align_position(pb, asf->offset, size); |
709 | | |
710 | 210 | return 0; |
711 | 210 | } |
712 | | |
713 | | static void set_language(AVFormatContext *s, const char *rfc1766, AVDictionary **met) |
714 | 114 | { |
715 | | // language abbr should contain at least 2 chars |
716 | 114 | if (rfc1766 && strlen(rfc1766) > 1) { |
717 | 17 | const char primary_tag[3] = { rfc1766[0], rfc1766[1], '\0' }; // ignore country code if any |
718 | 17 | const char *iso6392 = ff_convert_lang_to(primary_tag, |
719 | 17 | AV_LANG_ISO639_2_BIBL); |
720 | 17 | if (iso6392) |
721 | 11 | if (av_dict_set(met, "language", iso6392, 0) < 0) |
722 | 0 | av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); |
723 | 17 | } |
724 | 114 | } |
725 | | |
726 | | static int asf_read_ext_stream_properties(AVFormatContext *s, const GUIDParseTable *g) |
727 | 88 | { |
728 | 88 | ASFContext *asf = s->priv_data; |
729 | 88 | AVIOContext *pb = s->pb; |
730 | 88 | AVStream *st = NULL; |
731 | 88 | ff_asf_guid guid; |
732 | 88 | uint16_t nb_st_name, nb_pay_exts, st_num, lang_idx; |
733 | 88 | int i, ret; |
734 | 88 | uint32_t bitrate; |
735 | 88 | uint64_t start_time, end_time, time_per_frame; |
736 | 88 | uint64_t size = avio_rl64(pb); |
737 | | |
738 | 88 | start_time = avio_rl64(pb); |
739 | 88 | end_time = avio_rl64(pb); |
740 | 88 | bitrate = avio_rl32(pb); |
741 | 88 | avio_skip(pb, 28); // skip some unused values |
742 | 88 | st_num = avio_rl16(pb); |
743 | 88 | st_num &= ASF_STREAM_NUM; |
744 | 88 | lang_idx = avio_rl16(pb); // Stream Language ID Index |
745 | 88 | if (lang_idx >= ASF_MAX_STREAMS) |
746 | 0 | return AVERROR_INVALIDDATA; |
747 | 204 | for (i = 0; i < asf->nb_streams; i++) { |
748 | 165 | if (st_num == asf->asf_st[i]->stream_index) { |
749 | 49 | st = s->streams[asf->asf_st[i]->index]; |
750 | 49 | asf->asf_st[i]->lang_idx = lang_idx; |
751 | 49 | break; |
752 | 49 | } |
753 | 165 | } |
754 | 88 | time_per_frame = avio_rl64(pb); // average time per frame |
755 | 88 | if (st) { |
756 | 49 | st->start_time = start_time; |
757 | 49 | st->duration = end_time - start_time; |
758 | 49 | st->codecpar->bit_rate = bitrate; |
759 | 49 | st->avg_frame_rate.num = 10000000; |
760 | 49 | st->avg_frame_rate.den = time_per_frame; |
761 | 49 | } |
762 | 88 | nb_st_name = avio_rl16(pb); |
763 | 88 | nb_pay_exts = avio_rl16(pb); |
764 | 30.2k | for (i = 0; i < nb_st_name; i++) { |
765 | 30.1k | uint16_t len; |
766 | | |
767 | 30.1k | avio_rl16(pb); // Language ID Index |
768 | 30.1k | len = avio_rl16(pb); |
769 | 30.1k | avio_skip(pb, len); |
770 | 30.1k | } |
771 | | |
772 | 155k | for (i = 0; i < nb_pay_exts; i++) { |
773 | 155k | uint32_t len; |
774 | 155k | avio_skip(pb, 16); // Extension System ID |
775 | 155k | avio_skip(pb, 2); // Extension Data Size |
776 | 155k | len = avio_rl32(pb); |
777 | 155k | avio_skip(pb, len); |
778 | 155k | } |
779 | | |
780 | 88 | if ((ret = ff_get_guid(pb, &guid)) < 0) { |
781 | 10 | align_position(pb, asf->offset, size); |
782 | | |
783 | 10 | return 0; |
784 | 10 | } |
785 | | |
786 | 78 | g = find_guid(guid); |
787 | 78 | if (g && !(strcmp(g->name, "Stream Properties"))) { |
788 | 2 | if ((ret = g->read_object(s, g)) < 0) |
789 | 0 | return ret; |
790 | 2 | } |
791 | | |
792 | 78 | align_position(pb, asf->offset, size); |
793 | 78 | return 0; |
794 | 78 | } |
795 | | |
796 | | static int asf_read_language_list(AVFormatContext *s, const GUIDParseTable *g) |
797 | 537 | { |
798 | 537 | ASFContext *asf = s->priv_data; |
799 | 537 | AVIOContext *pb = s->pb; |
800 | 537 | int i, ret; |
801 | 537 | uint64_t size = avio_rl64(pb); |
802 | 537 | uint16_t nb_langs = avio_rl16(pb); |
803 | | |
804 | 537 | if (nb_langs < ASF_MAX_STREAMS) { |
805 | 25.1k | for (i = 0; i < nb_langs; i++) { |
806 | 24.5k | size_t len; |
807 | 24.5k | len = avio_r8(pb); |
808 | 24.5k | if (!len) |
809 | 3.23k | len = 6; |
810 | 24.5k | if ((ret = get_asf_string(pb, len, asf->asf_sd[i].langs, |
811 | 24.5k | sizeof(asf->asf_sd[i].langs))) < 0) { |
812 | 0 | return ret; |
813 | 0 | } |
814 | 24.5k | } |
815 | 534 | } |
816 | | |
817 | 537 | align_position(pb, asf->offset, size); |
818 | 537 | return 0; |
819 | 537 | } |
820 | | |
821 | | // returns data object offset when reading this object for the first time |
822 | | static int asf_read_data(AVFormatContext *s, const GUIDParseTable *g) |
823 | 191 | { |
824 | 191 | ASFContext *asf = s->priv_data; |
825 | 191 | AVIOContext *pb = s->pb; |
826 | 191 | uint64_t size = asf->data_size = avio_rl64(pb); |
827 | 191 | int i; |
828 | | |
829 | 191 | if (!asf->data_reached) { |
830 | 57 | asf->data_reached = 1; |
831 | 57 | asf->data_offset = asf->offset; |
832 | 57 | } |
833 | | |
834 | 722 | for (i = 0; i < asf->nb_streams; i++) { |
835 | 531 | if (!(asf->b_flags & ASF_FLAG_BROADCAST)) |
836 | 363 | s->streams[i]->duration = asf->duration; |
837 | 531 | } |
838 | 191 | asf->nb_mult_left = 0; |
839 | 191 | asf->sub_left = 0; |
840 | 191 | asf->state = PARSE_PACKET_HEADER; |
841 | 191 | asf->return_subpayload = 0; |
842 | 191 | asf->packet_size_internal = 0; |
843 | 191 | avio_skip(pb, 16); // skip File ID |
844 | 191 | size = avio_rl64(pb); // Total Data Packets |
845 | 191 | if (size != asf->nb_packets) |
846 | 171 | av_log(s, AV_LOG_WARNING, |
847 | 171 | "Number of Packets from File Properties Object is not equal to Total" |
848 | 171 | "Datapackets value! num of packets %"PRIu64" total num %"PRIu64".\n", |
849 | 171 | size, asf->nb_packets); |
850 | 191 | avio_skip(pb, 2); // skip reserved field |
851 | 191 | asf->first_packet_offset = avio_tell(pb); |
852 | 191 | if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !(asf->b_flags & ASF_FLAG_BROADCAST)) |
853 | 144 | align_position(pb, asf->offset, asf->data_size); |
854 | | |
855 | 191 | return 0; |
856 | 191 | } |
857 | | |
858 | | static int asf_read_simple_index(AVFormatContext *s, const GUIDParseTable *g) |
859 | 27 | { |
860 | 27 | ASFContext *asf = s->priv_data; |
861 | 27 | AVIOContext *pb = s->pb; |
862 | 27 | AVStream *st = NULL; |
863 | 27 | uint64_t interval; // index entry time interval in 100 ns units, usually it's 1s |
864 | 27 | uint32_t pkt_num, nb_entries; |
865 | 27 | int32_t prev_pkt_num = -1; |
866 | 27 | int i; |
867 | 27 | int64_t offset; |
868 | 27 | uint64_t size = avio_rl64(pb); |
869 | | |
870 | 27 | if (size < 24) |
871 | 0 | return AVERROR_INVALIDDATA; |
872 | | |
873 | | // simple index objects should be ordered by stream number, this loop tries to find |
874 | | // the first not indexed video stream |
875 | 35 | for (i = 0; i < asf->nb_streams; i++) { |
876 | 31 | if ((asf->asf_st[i]->type == AVMEDIA_TYPE_VIDEO) && !asf->asf_st[i]->indexed) { |
877 | 23 | asf->asf_st[i]->indexed = 1; |
878 | 23 | st = s->streams[asf->asf_st[i]->index]; |
879 | 23 | break; |
880 | 23 | } |
881 | 31 | } |
882 | 27 | if (!st) { |
883 | 4 | avio_skip(pb, size - 24); // if there's no video stream, skip index object |
884 | 4 | return 0; |
885 | 4 | } |
886 | 23 | avio_skip(pb, 16); // skip File ID |
887 | 23 | interval = avio_rl64(pb); |
888 | 23 | avio_skip(pb, 4); |
889 | 23 | nb_entries = avio_rl32(pb); |
890 | 343k | for (i = 0; i < nb_entries; i++) { |
891 | 343k | pkt_num = avio_rl32(pb); |
892 | 343k | offset = avio_skip(pb, 2); |
893 | 343k | if (offset < 0) { |
894 | 4 | av_log(s, AV_LOG_ERROR, "Skipping failed in asf_read_simple_index.\n"); |
895 | 4 | return offset; |
896 | 4 | } |
897 | 343k | if (asf->first_packet_offset > INT64_MAX - asf->packet_size * pkt_num) |
898 | 1 | return AVERROR_INVALIDDATA; |
899 | 343k | if (prev_pkt_num != pkt_num) { |
900 | 302k | av_add_index_entry(st, asf->first_packet_offset + asf->packet_size * |
901 | 302k | pkt_num, av_rescale(interval, i, 10000), |
902 | 302k | asf->packet_size, 0, AVINDEX_KEYFRAME); |
903 | 302k | prev_pkt_num = pkt_num; |
904 | 302k | } |
905 | 343k | } |
906 | 18 | asf->is_simple_index = 1; |
907 | 18 | align_position(pb, asf->offset, size); |
908 | | |
909 | 18 | return 0; |
910 | 23 | } |
911 | | |
912 | | static const GUIDParseTable gdef[] = { |
913 | | { "Data", { 0x75, 0xB2, 0x26, 0x36, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_data, 1 }, |
914 | | { "Simple Index", { 0x33, 0x00, 0x08, 0x90, 0xE5, 0xB1, 0x11, 0xCF, 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }, asf_read_simple_index, 1 }, |
915 | | { "Content Description", { 0x75, 0xB2, 0x26, 0x33, 0x66 ,0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_content_desc, 1 }, |
916 | | { "Extended Content Description", { 0xD2, 0xD0, 0xA4, 0x40, 0xE3, 0x07, 0x11, 0xD2, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5e, 0xA8, 0x50 }, asf_read_ext_content, 1 }, |
917 | | { "Stream Bitrate Properties", { 0x7B, 0xF8, 0x75, 0xCE, 0x46, 0x8D, 0x11, 0xD1, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2 }, asf_read_unknown, 1 }, |
918 | | { "File Properties", { 0x8C, 0xAB, 0xDC, 0xA1, 0xA9, 0x47, 0x11, 0xCF, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_properties, 1 }, |
919 | | { "Header Extension", { 0x5F, 0xBF, 0x03, 0xB5, 0xA9, 0x2E, 0x11, 0xCF, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_unknown, 0 }, |
920 | | { "Stream Properties", { 0xB7, 0xDC, 0x07, 0x91, 0xA9, 0xB7, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_stream_properties, 1 }, |
921 | | { "Codec List", { 0x86, 0xD1, 0x52, 0x40, 0x31, 0x1D, 0x11, 0xD0, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown, 1 }, |
922 | | { "Marker", { 0xF4, 0x87, 0xCD, 0x01, 0xA9, 0x51, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_marker, 1 }, |
923 | | { "Script Command", { 0x1E, 0xFB, 0x1A, 0x30, 0x0B, 0x62, 0x11, 0xD0, 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown, 1 }, |
924 | | { "Language List", { 0x7C, 0x43, 0x46, 0xa9, 0xef, 0xe0, 0x4B, 0xFC, 0xB2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 }, asf_read_language_list, 1}, |
925 | | { "Padding", { 0x18, 0x06, 0xD4, 0x74, 0xCA, 0xDF, 0x45, 0x09, 0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8 }, asf_read_unknown, 1 }, |
926 | | { "DRMv1 Header", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, |
927 | | { "DRMv2 Header", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9c }, asf_read_unknown, 1 }, |
928 | | { "Index", { 0xD6, 0xE2, 0x29, 0xD3, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, |
929 | | { "Media Object Index", { 0xFE, 0xB1, 0x03, 0xF8, 0x12, 0xAD, 0x4C, 0x64, 0x84, 0x0F, 0x2A, 0x1D, 0x2F, 0x7A, 0xD4, 0x8C }, asf_read_unknown, 1 }, |
930 | | { "Timecode Index", { 0x3C, 0xB7, 0x3F, 0xD0, 0x0C, 0x4A, 0x48, 0x03, 0x95, 0x3D, 0xED, 0xF7, 0xB6, 0x22, 0x8F, 0x0C }, asf_read_unknown, 0 }, |
931 | | { "Bitrate_Mutual_Exclusion", { 0xD6, 0xE2, 0x29, 0xDC, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, |
932 | | { "Error Correction", { 0x75, 0xB2, 0x26, 0x35, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_unknown, 1 }, |
933 | | { "Content Branding", { 0x22, 0x11, 0xB3, 0xFA, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, |
934 | | { "Content Encryption", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, |
935 | | { "Extended Content Encryption", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9C }, asf_read_unknown, 1 }, |
936 | | { "Digital Signature", { 0x22, 0x11, 0xB3, 0xFC, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown, 1 }, |
937 | | { "Extended Stream Properties", { 0x14, 0xE6, 0xA5, 0xCB, 0xC6, 0x72, 0x43, 0x32, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A }, asf_read_ext_stream_properties, 1 }, |
938 | | { "Advanced Mutual Exclusion", { 0xA0, 0x86, 0x49, 0xCF, 0x47, 0x75, 0x46, 0x70, 0x8A, 0x16, 0x6E, 0x35, 0x35, 0x75, 0x66, 0xCD }, asf_read_unknown, 1 }, |
939 | | { "Group Mutual Exclusion", { 0xD1, 0x46, 0x5A, 0x40, 0x5A, 0x79, 0x43, 0x38, 0xB7, 0x1B, 0xE3, 0x6B, 0x8F, 0xD6, 0xC2, 0x49 }, asf_read_unknown, 1}, |
940 | | { "Stream Prioritization", { 0xD4, 0xFE, 0xD1, 0x5B, 0x88, 0xD3, 0x45, 0x4F, 0x81, 0xF0, 0xED, 0x5C, 0x45, 0x99, 0x9E, 0x24 }, asf_read_unknown, 1 }, |
941 | | { "Bandwidth Sharing Object", { 0xA6, 0x96, 0x09, 0xE6, 0x51, 0x7B, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 }, |
942 | | { "Metadata", { 0xC5, 0xF8, 0xCB, 0xEA, 0x5B, 0xAF, 0x48, 0x77, 0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA }, asf_read_metadata_obj, 1 }, |
943 | | { "Metadata Library", { 0x44, 0x23, 0x1C, 0x94, 0x94, 0x98, 0x49, 0xD1, 0xA1, 0x41, 0x1D, 0x13, 0x4E, 0x45, 0x70, 0x54 }, asf_read_metadata_obj, 1 }, |
944 | | { "Audio Spread", { 0xBF, 0xC3, 0xCD, 0x50, 0x61, 0x8F, 0x11, 0xCF, 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20 }, asf_read_unknown, 1 }, |
945 | | { "Index Parameters", { 0xD6, 0xE2, 0x29, 0xDF, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, |
946 | | { "Content Encryption System Windows Media DRM Network Devices", |
947 | | { 0x7A, 0x07, 0x9B, 0xB6, 0xDA, 0XA4, 0x4e, 0x12, 0xA5, 0xCA, 0x91, 0xD3, 0x8D, 0xC1, 0x1A, 0x8D }, asf_read_unknown, 1 }, |
948 | | { "Mutex Language", { 0xD6, 0xE2, 0x2A, 0x00, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, |
949 | | { "Mutex Bitrate", { 0xD6, 0xE2, 0x2A, 0x01, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, |
950 | | { "Mutex Unknown", { 0xD6, 0xE2, 0x2A, 0x02, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown, 1 }, |
951 | | { "Bandwidth Sharing Exclusive", { 0xAF, 0x60, 0x60, 0xAA, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 }, |
952 | | { "Bandwidth Sharing Partial", { 0xAF, 0x60, 0x60, 0xAB, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown, 1 }, |
953 | | { "Payload Extension System Timecode", { 0x39, 0x95, 0x95, 0xEC, 0x86, 0x67, 0x4E, 0x2D, 0x8F, 0xDB, 0x98, 0x81, 0x4C, 0xE7, 0x6C, 0x1E }, asf_read_unknown, 1 }, |
954 | | { "Payload Extension System File Name", { 0xE1, 0x65, 0xEC, 0x0E, 0x19, 0xED, 0x45, 0xD7, 0xB4, 0xA7, 0x25, 0xCB, 0xD1, 0xE2, 0x8E, 0x9B }, asf_read_unknown, 1 }, |
955 | | { "Payload Extension System Content Type", { 0xD5, 0x90, 0xDC, 0x20, 0x07, 0xBC, 0x43, 0x6C, 0x9C, 0xF7, 0xF3, 0xBB, 0xFB, 0xF1, 0xA4, 0xDC }, asf_read_unknown, 1 }, |
956 | | { "Payload Extension System Pixel Aspect Ratio", { 0x1, 0x1E, 0xE5, 0x54, 0xF9, 0xEA, 0x4B, 0xC8, 0x82, 0x1A, 0x37, 0x6B, 0x74, 0xE4, 0xC4, 0xB8 }, asf_read_unknown, 1 }, |
957 | | { "Payload Extension System Sample Duration", { 0xC6, 0xBD, 0x94, 0x50, 0x86, 0x7F, 0x49, 0x07, 0x83, 0xA3, 0xC7, 0x79, 0x21, 0xB7, 0x33, 0xAD }, asf_read_unknown, 1 }, |
958 | | { "Payload Extension System Encryption Sample ID", { 0x66, 0x98, 0xB8, 0x4E, 0x0A, 0xFA, 0x43, 0x30, 0xAE, 0xB2, 0x1C, 0x0A, 0x98, 0xD7, 0xA4, 0x4D }, asf_read_unknown, 1 }, |
959 | | { "Payload Extension System Degradable JPEG", { 0x00, 0xE1, 0xAF, 0x06, 0x7B, 0xEC, 0x11, 0xD1, 0xA5, 0x82, 0x00, 0xC0, 0x4F, 0xC2, 0x9C, 0xFB }, asf_read_unknown, 1 }, |
960 | | }; |
961 | | |
962 | | #define READ_LEN(flag, name, len) \ |
963 | 58.3k | do { \ |
964 | 58.3k | if ((flag) == name ## IS_BYTE) \ |
965 | 58.3k | len = avio_r8(pb); \ |
966 | 58.3k | else if ((flag) == name ## IS_WORD) \ |
967 | 47.5k | len = avio_rl16(pb); \ |
968 | 47.5k | else if ((flag) == name ## IS_DWORD) \ |
969 | 46.5k | len = avio_rl32(pb); \ |
970 | 46.5k | else \ |
971 | 46.5k | len = 0; \ |
972 | 58.3k | } while(0) |
973 | | |
974 | | static int asf_read_subpayload(AVFormatContext *s, AVPacket *pkt, int is_header) |
975 | 828k | { |
976 | 828k | ASFContext *asf = s->priv_data; |
977 | 828k | AVIOContext *pb = s->pb; |
978 | 828k | uint8_t sub_len; |
979 | 828k | int ret, i; |
980 | | |
981 | 828k | if (is_header) { |
982 | 10.2k | asf->dts_delta = avio_r8(pb); |
983 | 10.2k | if (asf->nb_mult_left) { |
984 | 10.2k | asf->mult_sub_len = avio_rl16(pb); // total |
985 | 10.2k | } |
986 | 10.2k | asf->sub_header_offset = avio_tell(pb); |
987 | 10.2k | asf->nb_sub = 0; |
988 | 10.2k | asf->sub_left = 1; |
989 | 10.2k | } |
990 | 828k | sub_len = avio_r8(pb); |
991 | 828k | if ((ret = av_get_packet(pb, pkt, sub_len)) < 0) // each subpayload is entire frame |
992 | 0 | return ret; |
993 | 829k | for (i = 0; i < asf->nb_streams; i++) { |
994 | 829k | if (asf->stream_index == asf->asf_st[i]->stream_index) { |
995 | 828k | pkt->stream_index = asf->asf_st[i]->index; |
996 | 828k | break; |
997 | 828k | } |
998 | 829k | } |
999 | 828k | asf->return_subpayload = 1; |
1000 | 828k | if (!sub_len) |
1001 | 18.3k | asf->return_subpayload = 0; |
1002 | | |
1003 | 828k | if (sub_len) |
1004 | 810k | asf->nb_sub++; |
1005 | 828k | pkt->dts = asf->sub_dts + (asf->nb_sub - 1) * asf->dts_delta - asf->preroll; |
1006 | 828k | if (asf->nb_mult_left && (avio_tell(pb) >= |
1007 | 826k | (asf->sub_header_offset + asf->mult_sub_len))) { |
1008 | 7.26k | asf->sub_left = 0; |
1009 | 7.26k | asf->nb_mult_left--; |
1010 | 7.26k | } |
1011 | 828k | if (avio_tell(pb) >= asf->packet_offset + asf->packet_size - asf->pad_len) { |
1012 | 9.43k | asf->sub_left = 0; |
1013 | 9.43k | if (!asf->nb_mult_left) { |
1014 | 6.45k | avio_skip(pb, asf->pad_len); |
1015 | 6.45k | if (avio_tell(pb) != asf->packet_offset + asf->packet_size) { |
1016 | 1.51k | if (!asf->packet_size) |
1017 | 0 | return AVERROR_INVALIDDATA; |
1018 | 1.51k | av_log(s, AV_LOG_WARNING, |
1019 | 1.51k | "Position %"PRId64" wrong, should be %"PRId64"\n", |
1020 | 1.51k | avio_tell(pb), asf->packet_offset + asf->packet_size); |
1021 | 1.51k | avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); |
1022 | 1.51k | } |
1023 | 6.45k | } |
1024 | 9.43k | } |
1025 | | |
1026 | 828k | return 0; |
1027 | 828k | } |
1028 | | |
1029 | | static void reset_packet(ASFPacket *asf_pkt) |
1030 | 120 | { |
1031 | 120 | asf_pkt->size_left = 0; |
1032 | 120 | asf_pkt->data_size = 0; |
1033 | 120 | asf_pkt->duration = 0; |
1034 | 120 | asf_pkt->flags = 0; |
1035 | 120 | asf_pkt->dts = 0; |
1036 | 120 | av_packet_unref(asf_pkt->avpkt); |
1037 | 120 | } |
1038 | | |
1039 | | static int asf_read_replicated_data(AVFormatContext *s, ASFPacket *asf_pkt) |
1040 | 142 | { |
1041 | 142 | ASFContext *asf = s->priv_data; |
1042 | 142 | AVIOContext *pb = s->pb; |
1043 | 142 | int ret, data_size; |
1044 | | |
1045 | 142 | if (!asf_pkt->data_size) { |
1046 | 121 | data_size = avio_rl32(pb); // read media object size |
1047 | 121 | if (data_size <= 0) |
1048 | 5 | return AVERROR_INVALIDDATA; |
1049 | 116 | if ((ret = av_new_packet(asf_pkt->avpkt, data_size)) < 0) |
1050 | 0 | return ret; |
1051 | 116 | asf_pkt->data_size = asf_pkt->size_left = data_size; |
1052 | 116 | } else |
1053 | 21 | avio_skip(pb, 4); // reading of media object size is already done |
1054 | 137 | asf_pkt->dts = avio_rl32(pb); // read presentation time |
1055 | 137 | if (asf->rep_data_len >= 8) |
1056 | 137 | avio_skip(pb, asf->rep_data_len - 8); // skip replicated data |
1057 | | |
1058 | 137 | return 0; |
1059 | 142 | } |
1060 | | |
1061 | | static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, |
1062 | | ASFPacket *asf_pkt) |
1063 | 10.4k | { |
1064 | 10.4k | ASFContext *asf = s->priv_data; |
1065 | 10.4k | AVIOContext *pb = s->pb; |
1066 | 10.4k | uint16_t pay_len; |
1067 | 10.4k | unsigned char *p; |
1068 | 10.4k | int ret; |
1069 | 10.4k | int skip = 0; |
1070 | | |
1071 | | // if replicated length is 1, subpayloads are present |
1072 | 10.4k | if (asf->rep_data_len == 1) { |
1073 | 10.2k | asf->sub_left = 1; |
1074 | 10.2k | asf->state = READ_MULTI_SUB; |
1075 | 10.2k | pkt->flags = asf_pkt->flags; |
1076 | 10.2k | if ((ret = asf_read_subpayload(s, pkt, 1)) < 0) |
1077 | 0 | return ret; |
1078 | 10.2k | } else { |
1079 | 161 | if (asf->rep_data_len) |
1080 | 142 | if ((ret = asf_read_replicated_data(s, asf_pkt)) < 0) |
1081 | 5 | return ret; |
1082 | 156 | pay_len = avio_rl16(pb); // payload length should be WORD |
1083 | 156 | if (pay_len > asf->packet_size) { |
1084 | 3 | av_log(s, AV_LOG_ERROR, |
1085 | 3 | "Error: invalid data packet size, pay_len %"PRIu16", " |
1086 | 3 | "asf->packet_size %"PRIu32", offset %"PRId64".\n", |
1087 | 3 | pay_len, asf->packet_size, avio_tell(pb)); |
1088 | 3 | return AVERROR_INVALIDDATA; |
1089 | 3 | } |
1090 | 153 | p = asf_pkt->avpkt->data + asf_pkt->data_size - asf_pkt->size_left; |
1091 | 153 | if (pay_len > asf_pkt->size_left) { |
1092 | 8 | av_log(s, AV_LOG_ERROR, |
1093 | 8 | "Error: invalid buffer size, pay_len %d, data size left %d.\n", |
1094 | 8 | pay_len, asf_pkt->size_left); |
1095 | 8 | skip = pay_len - asf_pkt->size_left; |
1096 | 8 | pay_len = asf_pkt->size_left; |
1097 | 8 | } |
1098 | 153 | if (asf_pkt->size_left <= 0) |
1099 | 9 | return AVERROR_INVALIDDATA; |
1100 | 144 | if ((ret = avio_read(pb, p, pay_len)) < 0) |
1101 | 1 | return ret; |
1102 | 143 | if (s->key && s->keylen == 20) |
1103 | 0 | ff_asfcrypt_dec(s->key, p, ret); |
1104 | 143 | avio_skip(pb, skip); |
1105 | 143 | asf_pkt->size_left -= pay_len; |
1106 | 143 | asf->nb_mult_left--; |
1107 | 143 | } |
1108 | | |
1109 | 10.3k | return 0; |
1110 | 10.4k | } |
1111 | | |
1112 | | static int asf_read_single_payload(AVFormatContext *s, ASFPacket *asf_pkt) |
1113 | 33 | { |
1114 | 33 | ASFContext *asf = s->priv_data; |
1115 | 33 | AVIOContext *pb = s->pb; |
1116 | 33 | int64_t offset; |
1117 | 33 | uint64_t size; |
1118 | 33 | unsigned char *p; |
1119 | 33 | int ret, data_size; |
1120 | | |
1121 | 33 | if (!asf_pkt->data_size) { |
1122 | 25 | data_size = avio_rl32(pb); // read media object size |
1123 | 25 | if (data_size <= 0) |
1124 | 9 | return AVERROR_EOF; |
1125 | 16 | if ((ret = av_new_packet(asf_pkt->avpkt, data_size)) < 0) |
1126 | 0 | return ret; |
1127 | 16 | asf_pkt->data_size = asf_pkt->size_left = data_size; |
1128 | 16 | } else |
1129 | 8 | avio_skip(pb, 4); // skip media object size |
1130 | 24 | asf_pkt->dts = avio_rl32(pb); // read presentation time |
1131 | 24 | if (asf->rep_data_len >= 8) |
1132 | 6 | avio_skip(pb, asf->rep_data_len - 8); // skip replicated data |
1133 | 24 | offset = avio_tell(pb); |
1134 | | |
1135 | | // size of the payload - size of the packet without header and padding |
1136 | 24 | if (asf->packet_size_internal) |
1137 | 6 | size = asf->packet_size_internal - offset + asf->packet_offset - asf->pad_len; |
1138 | 18 | else |
1139 | 18 | size = asf->packet_size - offset + asf->packet_offset - asf->pad_len; |
1140 | 24 | if (size > asf->packet_size) { |
1141 | 4 | av_log(s, AV_LOG_ERROR, |
1142 | 4 | "Error: invalid data packet size, offset %"PRId64".\n", |
1143 | 4 | avio_tell(pb)); |
1144 | 4 | return AVERROR_INVALIDDATA; |
1145 | 4 | } |
1146 | 20 | p = asf_pkt->avpkt->data + asf_pkt->data_size - asf_pkt->size_left; |
1147 | 20 | if (size > asf_pkt->size_left || asf_pkt->size_left <= 0) |
1148 | 4 | return AVERROR_INVALIDDATA; |
1149 | 16 | if (asf_pkt->size_left > size) |
1150 | 16 | asf_pkt->size_left -= size; |
1151 | 0 | else |
1152 | 0 | asf_pkt->size_left = 0; |
1153 | 16 | if ((ret = avio_read(pb, p, size)) < 0) |
1154 | 0 | return ret; |
1155 | 16 | if (s->key && s->keylen == 20) |
1156 | 0 | ff_asfcrypt_dec(s->key, p, ret); |
1157 | 16 | if (asf->packet_size_internal) |
1158 | 2 | avio_skip(pb, asf->packet_size - asf->packet_size_internal); |
1159 | 16 | avio_skip(pb, asf->pad_len); // skip padding |
1160 | | |
1161 | 16 | return 0; |
1162 | 16 | } |
1163 | | |
1164 | | static int asf_read_payload(AVFormatContext *s, AVPacket *pkt) |
1165 | 830k | { |
1166 | 830k | ASFContext *asf = s->priv_data; |
1167 | 830k | AVIOContext *pb = s->pb; |
1168 | 830k | int ret, i; |
1169 | 830k | ASFPacket *asf_pkt = NULL; |
1170 | | |
1171 | 830k | if (!asf->sub_left) { |
1172 | 11.9k | uint32_t off_len, media_len; |
1173 | 11.9k | uint8_t stream_num; |
1174 | | |
1175 | 11.9k | stream_num = avio_r8(pb); |
1176 | 11.9k | asf->stream_index = stream_num & ASF_STREAM_NUM; |
1177 | 14.8k | for (i = 0; i < asf->nb_streams; i++) { |
1178 | 13.3k | if (asf->stream_index == asf->asf_st[i]->stream_index) { |
1179 | 10.4k | asf_pkt = &asf->asf_st[i]->pkt; |
1180 | 10.4k | asf_pkt->stream_index = asf->asf_st[i]->index; |
1181 | 10.4k | break; |
1182 | 10.4k | } |
1183 | 13.3k | } |
1184 | 11.9k | if (!asf_pkt) { |
1185 | 1.50k | if (asf->packet_offset + asf->packet_size <= asf->data_offset + asf->data_size) { |
1186 | 1.50k | if (!asf->packet_size) { |
1187 | 2 | av_log(s, AV_LOG_ERROR, "Invalid packet size 0.\n"); |
1188 | 2 | return AVERROR_INVALIDDATA; |
1189 | 2 | } |
1190 | 1.50k | avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); |
1191 | 1.50k | av_log(s, AV_LOG_WARNING, "Skipping the stream with the invalid stream index %d.\n", |
1192 | 1.50k | asf->stream_index); |
1193 | 1.50k | return AVERROR(EAGAIN); |
1194 | 1.50k | } else |
1195 | 0 | return AVERROR_INVALIDDATA; |
1196 | 1.50k | } |
1197 | | |
1198 | 10.4k | if (stream_num >> 7) |
1199 | 6 | asf_pkt->flags |= AV_PKT_FLAG_KEY; |
1200 | 10.4k | READ_LEN(asf->prop_flags & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE, |
1201 | 10.4k | ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_, media_len); |
1202 | 10.4k | READ_LEN(asf->prop_flags & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE, |
1203 | 10.4k | ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_, off_len); |
1204 | 10.4k | READ_LEN(asf->prop_flags & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE, |
1205 | 10.4k | ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_, asf->rep_data_len); |
1206 | 10.4k | if (asf_pkt->size_left && (asf_pkt->frame_num != media_len)) { |
1207 | 120 | av_log(s, AV_LOG_WARNING, "Unfinished frame will be ignored\n"); |
1208 | 120 | reset_packet(asf_pkt); |
1209 | 120 | } |
1210 | 10.4k | asf_pkt->frame_num = media_len; |
1211 | 10.4k | asf->sub_dts = off_len; |
1212 | 10.4k | if (asf->nb_mult_left) { |
1213 | 10.4k | if ((ret = asf_read_multiple_payload(s, pkt, asf_pkt)) < 0) |
1214 | 18 | return ret; |
1215 | 10.4k | } else if (asf->rep_data_len == 1) { |
1216 | 31 | asf->sub_left = 1; |
1217 | 31 | asf->state = READ_SINGLE; |
1218 | 31 | pkt->flags = asf_pkt->flags; |
1219 | 31 | if ((ret = asf_read_subpayload(s, pkt, 1)) < 0) |
1220 | 0 | return ret; |
1221 | 33 | } else { |
1222 | 33 | if ((ret = asf_read_single_payload(s, asf_pkt)) < 0) |
1223 | 17 | return ret; |
1224 | 33 | } |
1225 | 818k | } else { |
1226 | 819k | for (i = 0; i <= asf->nb_streams; i++) { |
1227 | 819k | if (asf->stream_index == asf->asf_st[i]->stream_index) { |
1228 | 818k | asf_pkt = &asf->asf_st[i]->pkt; |
1229 | 818k | break; |
1230 | 818k | } |
1231 | 819k | } |
1232 | 818k | if (!asf_pkt) |
1233 | 0 | return AVERROR_INVALIDDATA; |
1234 | 818k | pkt->flags = asf_pkt->flags; |
1235 | 818k | pkt->dts = asf_pkt->dts; |
1236 | 818k | pkt->stream_index = asf->asf_st[i]->index; |
1237 | 818k | if ((ret = asf_read_subpayload(s, pkt, 0)) < 0) // read subpayload without its header |
1238 | 0 | return ret; |
1239 | 818k | } |
1240 | | |
1241 | 829k | return 0; |
1242 | 830k | } |
1243 | | |
1244 | | static int asf_read_packet_header(AVFormatContext *s) |
1245 | 8.96k | { |
1246 | 8.96k | ASFContext *asf = s->priv_data; |
1247 | 8.96k | AVIOContext *pb = s->pb; |
1248 | 8.96k | uint64_t size; |
1249 | 8.96k | uint32_t av_unused seq; |
1250 | 8.96k | unsigned char error_flags, len_flags, pay_flags; |
1251 | | |
1252 | 8.96k | asf->packet_offset = avio_tell(pb); |
1253 | 8.96k | if (asf->packet_offset > INT64_MAX/2) |
1254 | 20 | asf->packet_offset = 0; |
1255 | 8.96k | error_flags = avio_r8(pb); // read Error Correction Flags |
1256 | 8.96k | if (error_flags & ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT) { |
1257 | 646 | if (!(error_flags & ASF_ERROR_CORRECTION_LENGTH_TYPE)) { |
1258 | 329 | size = error_flags & ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; |
1259 | 329 | avio_skip(pb, size); |
1260 | 329 | } |
1261 | 646 | len_flags = avio_r8(pb); |
1262 | 646 | } else |
1263 | 8.32k | len_flags = error_flags; |
1264 | 8.96k | asf->prop_flags = avio_r8(pb); |
1265 | 8.96k | READ_LEN(len_flags & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE, |
1266 | 8.96k | ASF_PPI_FLAG_PACKET_LENGTH_FIELD_, asf->packet_size_internal); |
1267 | 8.96k | READ_LEN(len_flags & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE, |
1268 | 8.96k | ASF_PPI_FLAG_SEQUENCE_FIELD_, seq); |
1269 | 8.96k | READ_LEN(len_flags & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE, |
1270 | 8.96k | ASF_PPI_FLAG_PADDING_LENGTH_FIELD_, asf->pad_len ); |
1271 | 8.96k | asf->send_time = avio_rl32(pb); // send time |
1272 | 8.96k | avio_skip(pb, 2); // skip duration |
1273 | 8.96k | if (len_flags & ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT) { // Multiple Payloads present |
1274 | 8.04k | pay_flags = avio_r8(pb); |
1275 | 8.04k | asf->nb_mult_left = (pay_flags & ASF_NUM_OF_PAYLOADS); |
1276 | 8.04k | } |
1277 | | |
1278 | 8.96k | return 0; |
1279 | 8.96k | } |
1280 | | |
1281 | | static int asf_deinterleave(AVFormatContext *s, ASFPacket *asf_pkt, int st_num) |
1282 | 0 | { |
1283 | 0 | ASFContext *asf = s->priv_data; |
1284 | 0 | ASFStream *asf_st = asf->asf_st[st_num]; |
1285 | 0 | unsigned char *p = asf_pkt->avpkt->data; |
1286 | 0 | uint16_t pkt_len = asf->asf_st[st_num]->virtual_pkt_len; |
1287 | 0 | uint16_t chunk_len = asf->asf_st[st_num]->virtual_chunk_len; |
1288 | 0 | int nchunks = pkt_len / chunk_len; |
1289 | 0 | uint8_t *data; |
1290 | 0 | int pos = 0, j, l, ret; |
1291 | | |
1292 | |
|
1293 | 0 | data = av_malloc(asf_pkt->data_size + AV_INPUT_BUFFER_PADDING_SIZE); |
1294 | 0 | if (!data) |
1295 | 0 | return AVERROR(ENOMEM); |
1296 | 0 | memset(data + asf_pkt->data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
1297 | |
|
1298 | 0 | while (asf_pkt->data_size >= asf_st->span * pkt_len + pos) { |
1299 | 0 | if (pos >= asf_pkt->data_size) { |
1300 | 0 | break; |
1301 | 0 | } |
1302 | 0 | for (l = 0; l < pkt_len; l++) { |
1303 | 0 | if (pos >= asf_pkt->data_size) { |
1304 | 0 | break; |
1305 | 0 | } |
1306 | 0 | for (j = 0; j < asf_st->span; j++) { |
1307 | 0 | if ((pos + chunk_len) >= asf_pkt->data_size) |
1308 | 0 | break; |
1309 | 0 | memcpy(data + pos, |
1310 | 0 | p + (j * nchunks + l) * chunk_len, |
1311 | 0 | chunk_len); |
1312 | 0 | pos += chunk_len; |
1313 | 0 | } |
1314 | 0 | } |
1315 | 0 | p += asf_st->span * pkt_len; |
1316 | 0 | if (p > asf_pkt->avpkt->data + asf_pkt->data_size) |
1317 | 0 | break; |
1318 | 0 | } |
1319 | 0 | av_packet_unref(asf_pkt->avpkt); |
1320 | 0 | ret = av_packet_from_data(asf_pkt->avpkt, data, asf_pkt->data_size); |
1321 | 0 | if (ret < 0) |
1322 | 0 | av_free(data); |
1323 | |
|
1324 | 0 | return ret; |
1325 | 0 | } |
1326 | | |
1327 | | static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) |
1328 | 810k | { |
1329 | 810k | ASFContext *asf = s->priv_data; |
1330 | 810k | AVIOContext *pb = s->pb; |
1331 | 810k | int ret, i; |
1332 | | |
1333 | 810k | if ((avio_tell(pb) >= asf->data_offset + asf->data_size) && |
1334 | 810k | !(asf->b_flags & ASF_FLAG_BROADCAST)) |
1335 | 14 | return AVERROR_EOF; |
1336 | 830k | while (!pb->eof_reached) { |
1337 | 830k | if (asf->state == PARSE_PACKET_HEADER) { |
1338 | 8.96k | asf_read_packet_header(s); |
1339 | 8.96k | if (pb->eof_reached) |
1340 | 0 | break; |
1341 | 8.96k | if (!asf->nb_mult_left) |
1342 | 596 | asf->state = READ_SINGLE; |
1343 | 8.37k | else |
1344 | 8.37k | asf->state = READ_MULTI; |
1345 | 8.96k | } |
1346 | 830k | ret = asf_read_payload(s, pkt); |
1347 | 830k | if (ret == AVERROR(EAGAIN)) { |
1348 | 1.50k | asf->state = PARSE_PACKET_HEADER; |
1349 | 1.50k | continue; |
1350 | 1.50k | } |
1351 | 829k | else if (ret < 0) |
1352 | 37 | return ret; |
1353 | | |
1354 | 829k | switch (asf->state) { |
1355 | 2.67k | case READ_SINGLE: |
1356 | 2.67k | if (!asf->sub_left) |
1357 | 47 | asf->state = PARSE_PACKET_HEADER; |
1358 | 2.67k | break; |
1359 | 826k | case READ_MULTI_SUB: |
1360 | 826k | if (!asf->sub_left && !asf->nb_mult_left) { |
1361 | 7.26k | asf->state = PARSE_PACKET_HEADER; |
1362 | 7.26k | if (!asf->return_subpayload && |
1363 | 7.26k | (avio_tell(pb) <= asf->packet_offset + |
1364 | 32 | asf->packet_size - asf->pad_len)) |
1365 | 32 | avio_skip(pb, asf->pad_len); // skip padding |
1366 | 7.26k | if (asf->packet_offset + asf->packet_size > avio_tell(pb)) |
1367 | 843 | avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); |
1368 | 819k | } else if (!asf->sub_left) |
1369 | 2.98k | asf->state = READ_MULTI; |
1370 | 826k | break; |
1371 | 143 | case READ_MULTI: |
1372 | 143 | if (!asf->nb_mult_left) { |
1373 | 131 | asf->state = PARSE_PACKET_HEADER; |
1374 | 131 | if (!asf->return_subpayload && |
1375 | 131 | (avio_tell(pb) <= asf->packet_offset + |
1376 | 131 | asf->packet_size - asf->pad_len)) |
1377 | 4 | avio_skip(pb, asf->pad_len); // skip padding |
1378 | 131 | if (asf->packet_offset + asf->packet_size > avio_tell(pb)) |
1379 | 4 | avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); |
1380 | 131 | } |
1381 | 143 | break; |
1382 | 829k | } |
1383 | 829k | if (asf->return_subpayload) { |
1384 | 810k | asf->return_subpayload = 0; |
1385 | 810k | return 0; |
1386 | 810k | } |
1387 | 37.0k | for (i = 0; i < asf->nb_streams; i++) { |
1388 | 18.5k | ASFPacket *asf_pkt = &asf->asf_st[i]->pkt; |
1389 | 18.5k | if (asf_pkt && !asf_pkt->size_left && asf_pkt->data_size) { |
1390 | 1 | if (asf->asf_st[i]->span > 1 && |
1391 | 1 | asf->asf_st[i]->type == AVMEDIA_TYPE_AUDIO) |
1392 | 0 | if ((ret = asf_deinterleave(s, asf_pkt, i)) < 0) |
1393 | 0 | return ret; |
1394 | 1 | av_packet_move_ref(pkt, asf_pkt->avpkt); |
1395 | 1 | pkt->stream_index = asf->asf_st[i]->index; |
1396 | 1 | pkt->flags = asf_pkt->flags; |
1397 | 1 | pkt->dts = asf_pkt->dts - asf->preroll; |
1398 | 1 | asf_pkt->data_size = 0; |
1399 | 1 | asf_pkt->frame_num = 0; |
1400 | 1 | return 0; |
1401 | 1 | } |
1402 | 18.5k | } |
1403 | 18.5k | } |
1404 | | |
1405 | 5 | if (pb->eof_reached) |
1406 | 5 | return AVERROR_EOF; |
1407 | | |
1408 | 0 | return 0; |
1409 | 5 | } |
1410 | | |
1411 | | static int asf_read_close(AVFormatContext *s) |
1412 | 68 | { |
1413 | 68 | ASFContext *asf = s->priv_data; |
1414 | 68 | int i; |
1415 | | |
1416 | 8.77k | for (i = 0; i < ASF_MAX_STREAMS; i++) { |
1417 | 8.70k | av_dict_free(&asf->asf_sd[i].asf_met); |
1418 | 8.70k | if (i < asf->nb_streams) { |
1419 | 211 | av_packet_free(&asf->asf_st[i]->pkt.avpkt); |
1420 | 211 | av_freep(&asf->asf_st[i]); |
1421 | 211 | } |
1422 | 8.70k | } |
1423 | | |
1424 | 68 | asf->nb_streams = 0; |
1425 | 68 | return 0; |
1426 | 68 | } |
1427 | | |
1428 | | static void reset_packet_state(AVFormatContext *s) |
1429 | 0 | { |
1430 | 0 | ASFContext *asf = s->priv_data; |
1431 | 0 | int i; |
1432 | |
|
1433 | 0 | asf->state = PARSE_PACKET_HEADER; |
1434 | 0 | asf->offset = 0; |
1435 | 0 | asf->return_subpayload = 0; |
1436 | 0 | asf->sub_left = 0; |
1437 | 0 | asf->sub_header_offset = 0; |
1438 | 0 | asf->packet_offset = asf->first_packet_offset; |
1439 | 0 | asf->pad_len = 0; |
1440 | 0 | asf->rep_data_len = 0; |
1441 | 0 | asf->dts_delta = 0; |
1442 | 0 | asf->mult_sub_len = 0; |
1443 | 0 | asf->nb_mult_left = 0; |
1444 | 0 | asf->nb_sub = 0; |
1445 | 0 | asf->prop_flags = 0; |
1446 | 0 | asf->sub_dts = 0; |
1447 | 0 | for (i = 0; i < asf->nb_streams; i++) { |
1448 | 0 | ASFPacket *pkt = &asf->asf_st[i]->pkt; |
1449 | 0 | reset_packet(pkt); |
1450 | 0 | } |
1451 | 0 | } |
1452 | | |
1453 | | /* |
1454 | | * Find a timestamp for the requested position within the payload |
1455 | | * where the pos (position) is the offset inside the Data Object. |
1456 | | * When position is not on the packet boundary, asf_read_timestamp tries |
1457 | | * to find the closest packet offset after this position. If this packet |
1458 | | * is a key frame, this packet timestamp is read and an index entry is created |
1459 | | * for the packet. If this packet belongs to the requested stream, |
1460 | | * asf_read_timestamp upgrades pos to the packet beginning offset and |
1461 | | * returns this packet's dts. So returned dts is the dts of the first key frame with |
1462 | | * matching stream number after given position. |
1463 | | */ |
1464 | | static int64_t asf_read_timestamp(AVFormatContext *s, int stream_index, |
1465 | | int64_t *pos, int64_t pos_limit) |
1466 | 0 | { |
1467 | 0 | ASFContext *asf = s->priv_data; |
1468 | 0 | int64_t pkt_pos = *pos, pkt_offset, dts = AV_NOPTS_VALUE, data_end; |
1469 | 0 | AVPacket *pkt = av_packet_alloc(); |
1470 | 0 | int n; |
1471 | |
|
1472 | 0 | if (!pkt) |
1473 | 0 | return AVERROR(ENOMEM); |
1474 | | |
1475 | 0 | data_end = asf->data_offset + asf->data_size; |
1476 | |
|
1477 | 0 | n = (pkt_pos - asf->first_packet_offset + asf->packet_size - 1) / |
1478 | 0 | asf->packet_size; |
1479 | 0 | n = av_clip(n, 0, ((data_end - asf->first_packet_offset) / asf->packet_size - 1)); |
1480 | 0 | pkt_pos = asf->first_packet_offset + n * asf->packet_size; |
1481 | |
|
1482 | 0 | avio_seek(s->pb, pkt_pos, SEEK_SET); |
1483 | 0 | pkt_offset = pkt_pos; |
1484 | |
|
1485 | 0 | reset_packet_state(s); |
1486 | 0 | while (avio_tell(s->pb) < data_end) { |
1487 | |
|
1488 | 0 | int i, ret, st_found; |
1489 | |
|
1490 | 0 | pkt_offset = avio_tell(s->pb); |
1491 | 0 | if ((ret = asf_read_packet(s, pkt)) < 0) { |
1492 | 0 | av_packet_free(&pkt); |
1493 | 0 | dts = AV_NOPTS_VALUE; |
1494 | 0 | return ret; |
1495 | 0 | } |
1496 | | // ASFPacket may contain fragments of packets belonging to different streams, |
1497 | | // pkt_offset is the offset of the first fragment within it. |
1498 | 0 | if ((pkt_offset >= (pkt_pos + asf->packet_size))) |
1499 | 0 | pkt_pos += asf->packet_size; |
1500 | 0 | for (i = 0; i < asf->nb_streams; i++) { |
1501 | 0 | ASFStream *st = asf->asf_st[i]; |
1502 | |
|
1503 | 0 | st_found = 0; |
1504 | 0 | if (pkt->flags & AV_PKT_FLAG_KEY) { |
1505 | 0 | dts = pkt->dts; |
1506 | 0 | if (dts) { |
1507 | 0 | av_add_index_entry(s->streams[pkt->stream_index], pkt_pos, |
1508 | 0 | dts, pkt->size, 0, AVINDEX_KEYFRAME); |
1509 | 0 | if (stream_index == st->index) { |
1510 | 0 | st_found = 1; |
1511 | 0 | break; |
1512 | 0 | } |
1513 | 0 | } |
1514 | 0 | } |
1515 | 0 | } |
1516 | 0 | if (st_found) |
1517 | 0 | break; |
1518 | 0 | av_packet_unref(pkt); |
1519 | 0 | } |
1520 | 0 | *pos = pkt_pos; |
1521 | |
|
1522 | 0 | av_packet_free(&pkt); |
1523 | 0 | return dts; |
1524 | 0 | } |
1525 | | |
1526 | | static int asf_read_seek(AVFormatContext *s, int stream_index, |
1527 | | int64_t timestamp, int flags) |
1528 | 0 | { |
1529 | 0 | ASFContext *asf = s->priv_data; |
1530 | 0 | AVStream *const st = s->streams[stream_index]; |
1531 | 0 | FFStream *const sti = ffstream(st); |
1532 | 0 | int idx, ret; |
1533 | |
|
1534 | 0 | if (sti->nb_index_entries && asf->is_simple_index) { |
1535 | 0 | idx = av_index_search_timestamp(st, timestamp, flags); |
1536 | 0 | if (idx < 0 || idx >= sti->nb_index_entries) |
1537 | 0 | return AVERROR_INVALIDDATA; |
1538 | 0 | avio_seek(s->pb, sti->index_entries[idx].pos, SEEK_SET); |
1539 | 0 | } else { |
1540 | 0 | if ((ret = ff_seek_frame_binary(s, stream_index, timestamp, flags)) < 0) |
1541 | 0 | return ret; |
1542 | 0 | } |
1543 | | |
1544 | 0 | reset_packet_state(s); |
1545 | |
|
1546 | 0 | return 0; |
1547 | 0 | } |
1548 | | |
1549 | | static const GUIDParseTable *find_guid(ff_asf_guid guid) |
1550 | 259k | { |
1551 | 259k | int j, ret; |
1552 | 259k | const GUIDParseTable *g; |
1553 | | |
1554 | 259k | swap_guid(guid); |
1555 | 259k | g = gdef; |
1556 | 12.1M | for (j = 0; j < FF_ARRAY_ELEMS(gdef); j++) { |
1557 | 11.8M | if (!(ret = memcmp(guid, g->guid, sizeof(g->guid)))) |
1558 | 1.99k | return g; |
1559 | 11.8M | g++; |
1560 | 11.8M | } |
1561 | | |
1562 | 257k | return NULL; |
1563 | 259k | } |
1564 | | |
1565 | | static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size) |
1566 | 91 | { |
1567 | 91 | ASFContext *asf = s->priv_data; |
1568 | 91 | AVIOContext *pb = s->pb; |
1569 | 91 | const GUIDParseTable *g = NULL; |
1570 | 91 | ff_asf_guid guid; |
1571 | 91 | int ret; |
1572 | | |
1573 | 91 | if (offset > INT64_MAX - size) |
1574 | 0 | return AVERROR_INVALIDDATA; |
1575 | | |
1576 | 244k | while (avio_tell(pb) <= offset + size) { |
1577 | 244k | if (avio_tell(pb) == asf->offset) |
1578 | 0 | break; |
1579 | 244k | asf->offset = avio_tell(pb); |
1580 | 244k | if ((ret = ff_get_guid(pb, &guid)) < 0) |
1581 | 19 | return ret; |
1582 | 244k | g = find_guid(guid); |
1583 | 244k | if (g) { |
1584 | 1.84k | if ((ret = g->read_object(s, g)) < 0) |
1585 | 16 | return ret; |
1586 | 242k | } else { |
1587 | 242k | GUIDParseTable g2; |
1588 | | |
1589 | 242k | g2.name = "Unknown"; |
1590 | 242k | g2.is_subobject = 1; |
1591 | 242k | asf_read_unknown(s, &g2); |
1592 | 242k | } |
1593 | 244k | } |
1594 | | |
1595 | 56 | return 0; |
1596 | 91 | } |
1597 | | |
1598 | | static int asf_read_header(AVFormatContext *s) |
1599 | 93 | { |
1600 | 93 | ASFContext *asf = s->priv_data; |
1601 | 93 | AVIOContext *pb = s->pb; |
1602 | 93 | const GUIDParseTable *g = NULL; |
1603 | 93 | ff_asf_guid guid; |
1604 | 93 | int i, ret; |
1605 | 93 | uint64_t size; |
1606 | | |
1607 | 93 | asf->preroll = 0; |
1608 | 93 | asf->is_simple_index = 0; |
1609 | 93 | ff_get_guid(pb, &guid); |
1610 | 93 | if (ff_guidcmp(&guid, &ff_asf_header)) |
1611 | 25 | return AVERROR_INVALIDDATA; |
1612 | 68 | avio_skip(pb, 8); // skip header object size |
1613 | 68 | avio_skip(pb, 6); // skip number of header objects and 2 reserved bytes |
1614 | 68 | asf->data_reached = 0; |
1615 | | |
1616 | | /* 1 is here instead of pb->eof_reached because (when not streaming), Data are skipped |
1617 | | * for the first time, |
1618 | | * Index object is processed and got eof and then seeking back to the Data is performed. |
1619 | | */ |
1620 | 14.5k | while (1) { |
1621 | | // for the cases when object size is invalid |
1622 | 14.5k | if (avio_tell(pb) == asf->offset) |
1623 | 14 | break; |
1624 | 14.5k | asf->offset = avio_tell(pb); |
1625 | 14.5k | if ((ret = ff_get_guid(pb, &guid)) < 0) { |
1626 | 9 | if (ret == AVERROR_EOF && asf->data_reached) |
1627 | 0 | break; |
1628 | 9 | else |
1629 | 9 | goto failed; |
1630 | 9 | } |
1631 | 14.5k | g = find_guid(guid); |
1632 | 14.5k | if (g) { |
1633 | 119 | asf->unknown_offset = asf->offset; |
1634 | 119 | asf->is_header = 1; |
1635 | 119 | if ((ret = g->read_object(s, g)) < 0) |
1636 | 28 | goto failed; |
1637 | 14.4k | } else { |
1638 | 14.4k | size = avio_rl64(pb); |
1639 | 14.4k | align_position(pb, asf->offset, size); |
1640 | 14.4k | } |
1641 | 14.5k | if (asf->data_reached && |
1642 | 14.5k | (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || |
1643 | 1.08k | (asf->b_flags & ASF_FLAG_BROADCAST))) |
1644 | 17 | break; |
1645 | 14.5k | } |
1646 | | |
1647 | 31 | if (!asf->data_reached) { |
1648 | 0 | av_log(s, AV_LOG_ERROR, "Data Object was not found.\n"); |
1649 | 0 | ret = AVERROR_INVALIDDATA; |
1650 | 0 | goto failed; |
1651 | 0 | } |
1652 | 31 | if (pb->seekable & AVIO_SEEKABLE_NORMAL) |
1653 | 31 | avio_seek(pb, asf->first_packet_offset, SEEK_SET); |
1654 | | |
1655 | 145 | for (i = 0; i < asf->nb_streams; i++) { |
1656 | 114 | const char *rfc1766 = asf->asf_sd[asf->asf_st[i]->lang_idx].langs; |
1657 | 114 | AVStream *st = s->streams[asf->asf_st[i]->index]; |
1658 | 114 | set_language(s, rfc1766, &st->metadata); |
1659 | 114 | } |
1660 | | |
1661 | 3.99k | for (i = 0; i < ASF_MAX_STREAMS; i++) { |
1662 | 3.96k | AVStream *st = NULL; |
1663 | | |
1664 | 3.96k | st = find_stream(s, i); |
1665 | 3.96k | if (st) { |
1666 | 114 | av_dict_copy(&st->metadata, asf->asf_sd[i].asf_met, AV_DICT_IGNORE_SUFFIX); |
1667 | 114 | if (asf->asf_sd[i].aspect_ratio.num > 0 && asf->asf_sd[i].aspect_ratio.den > 0) { |
1668 | 0 | st->sample_aspect_ratio.num = asf->asf_sd[i].aspect_ratio.num; |
1669 | 0 | st->sample_aspect_ratio.den = asf->asf_sd[i].aspect_ratio.den; |
1670 | 0 | } |
1671 | 114 | } |
1672 | 3.96k | } |
1673 | | |
1674 | 31 | return 0; |
1675 | | |
1676 | 37 | failed: |
1677 | 37 | asf_read_close(s); |
1678 | 37 | return ret; |
1679 | 31 | } |
1680 | | |
1681 | | const FFInputFormat ff_asf_o_demuxer = { |
1682 | | .p.name = "asf_o", |
1683 | | .p.long_name = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"), |
1684 | | .p.flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH, |
1685 | | .priv_data_size = sizeof(ASFContext), |
1686 | | .read_probe = asf_probe, |
1687 | | .read_header = asf_read_header, |
1688 | | .read_packet = asf_read_packet, |
1689 | | .read_close = asf_read_close, |
1690 | | .read_timestamp = asf_read_timestamp, |
1691 | | .read_seek = asf_read_seek, |
1692 | | }; |