2 * Microsoft Advanced Streaming Format demuxer
3 * Copyright (c) 2014 Alexandra Hájková
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/attributes.h"
23 #include "libavutil/avassert.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/bswap.h"
26 #include "libavutil/common.h"
27 #include "libavutil/dict.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/mathematics.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/time_internal.h"
34 #include "avio_internal.h"
35 #include "avlanguage.h"
47 #define ASF_UNICODE 0x0
48 #define ASF_FLAG_BROADCAST 0x1
49 #define ASF_BYTE_ARRAY 0x1
50 #define ASF_TYPE_AUDIO 0x2
51 #define ASF_TYPE_VIDEO 0x1
52 #define ASF_STREAM_NUM 0x7F
53 #define ASF_MAX_STREAMS 128
54 #define BMP_HEADER_SIZE 40
55 #define ASF_NUM_OF_PAYLOADS 0x3F
56 #define ASF_ERROR_CORRECTION_LENGTH_TYPE 0x60
57 #define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
59 typedef struct GUIDParseTable
{
62 int (*read_object
)(AVFormatContext
*, const struct GUIDParseTable
*);
66 typedef struct ASFPacket
{
69 uint32_t frame_num
; // ASF payloads with the same number are parts of the same frame
77 typedef struct ASFStream
{
78 uint8_t stream_index
; // from packet header
79 int index
; // stream index in AVFormatContext, set in asf_read_stream_properties
81 int indexed
; // added index entries from the Simple Index Object or not
82 int8_t span
; // for deinterleaving
83 uint16_t virtual_pkt_len
;
84 uint16_t virtual_chunk_len
;
89 typedef struct ASFStreamData
{
91 AVDictionary
*asf_met
; // for storing per-stream metadata
92 AVRational aspect_ratio
;
95 typedef struct ASFContext
{
97 int is_simple_index
; // is simple index present or not 1/0
101 uint64_t nb_packets
; // ASF packets
102 uint32_t packet_size
;
106 uint32_t b_flags
; // flags with broadcast flag
107 uint32_t prop_flags
; // file properties object flags
109 uint64_t data_size
; // data object size
110 uint64_t unknown_size
; // size of the unknown object
112 int64_t offset
; // offset of the current object
115 int64_t first_packet_offset
; // packet offset
116 int64_t unknown_offset
; // for top level header objects or subobjects without specified behavior
118 // ASF file must not contain more than 128 streams according to the specification
119 ASFStream
*asf_st
[ASF_MAX_STREAMS
];
120 ASFStreamData asf_sd
[ASF_MAX_STREAMS
];
123 int stream_index
; // from packet header, for the subpayload case
125 // packet parameteres
126 uint64_t sub_header_offset
; // offset of subplayload header
128 uint8_t dts_delta
; // for subpayloads
129 uint32_t packet_size_internal
; // packet size stored inside ASFPacket, can be 0
130 int64_t packet_offset
; // offset of the current packet inside Data Object
131 uint32_t pad_len
; // padding after payload
132 uint32_t rep_data_len
;
135 uint64_t sub_left
; // subpayloads left or not
136 unsigned int nb_sub
; // number of subpayloads read so far from the current ASF packet
137 uint16_t mult_sub_len
; // total length of subpayloads array inside multiple payload
138 uint64_t nb_mult_left
; // multiple payloads left
139 int return_subpayload
;
148 static int detect_unknown_subobject(AVFormatContext
*s
, int64_t offset
, int64_t size
);
149 static const GUIDParseTable
*find_guid(ff_asf_guid guid
);
151 static int asf_probe(AVProbeData
*pd
)
153 /* check file header */
154 if (!ff_guidcmp(pd
->buf
, &ff_asf_header
))
155 return AVPROBE_SCORE_MAX
;
160 static void swap_guid(ff_asf_guid guid
)
162 FFSWAP(unsigned char, guid
[0], guid
[3]);
163 FFSWAP(unsigned char, guid
[1], guid
[2]);
164 FFSWAP(unsigned char, guid
[4], guid
[5]);
165 FFSWAP(unsigned char, guid
[6], guid
[7]);
168 static void align_position(AVIOContext
*pb
, int64_t offset
, uint64_t size
)
170 if (avio_tell(pb
) != offset
+ size
)
171 avio_seek(pb
, offset
+ size
, SEEK_SET
);
174 static int asf_read_unknown(AVFormatContext
*s
, const GUIDParseTable
*g
)
176 ASFContext
*asf
= s
->priv_data
;
177 AVIOContext
*pb
= s
->pb
;
178 uint64_t size
= avio_rl64(pb
);
182 asf
->unknown_size
= size
;
184 if (!g
->is_subobject
) {
185 if (!(ret
= strcmp(g
->name
, "Header Extension")))
186 avio_skip(pb
, 22); // skip reserved fields and Data Size
187 if ((ret
= detect_unknown_subobject(s
, asf
->unknown_offset
,
188 asf
->unknown_size
)) < 0)
191 avio_skip(pb
, size
- 24);
196 static int get_asf_string(AVIOContext
*pb
, int maxlen
, char *buf
, int buflen
)
201 return AVERROR(EINVAL
);
202 while (ret
+ 1 < maxlen
) {
205 GET_UTF16(ch
, (ret
+= 2) <= maxlen ?
avio_rl16(pb
) : 0, break;);
206 PUT_UTF8(ch
, tmp
, if (q
- buf
< buflen
- 1) *q
++ = tmp
;)
213 static int asf_read_marker(AVFormatContext
*s
, const GUIDParseTable
*g
)
215 ASFContext
*asf
= s
->priv_data
;
216 AVIOContext
*pb
= s
->pb
;
217 uint64_t size
= avio_rl64(pb
);
218 int i
, nb_markers
, ret
;
223 avio_skip(pb
, 8); // skip reserved GUID
224 nb_markers
= avio_rl32(pb
);
225 avio_skip(pb
, 2); // skip reserved field
227 for (i
= 0; i
< len
; i
++)
230 for (i
= 0; i
< nb_markers
; i
++) {
235 pts
-= asf
->preroll
* 10000;
236 avio_skip(pb
, 2); // entry length
237 avio_skip(pb
, 4); // send time
238 avio_skip(pb
, 4); // flags
241 if ((ret
= avio_get_str16le(pb
, len
, name
,
242 sizeof(name
))) < len
)
243 avio_skip(pb
, len
- ret
);
244 avpriv_new_chapter(s
, i
, (AVRational
) { 1, 10000000 }, pts
,
245 AV_NOPTS_VALUE
, name
);
247 align_position(pb
, asf
->offset
, size
);
252 static int asf_read_metadata(AVFormatContext
*s
, const char *title
, uint16_t len
,
253 unsigned char *ch
, uint16_t buflen
)
255 AVIOContext
*pb
= s
->pb
;
257 avio_get_str16le(pb
, len
, ch
, buflen
);
259 if (av_dict_set(&s
->metadata
, title
, ch
, 0) < 0)
260 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
266 static int asf_read_value(AVFormatContext
*s
, const uint8_t *name
, uint16_t name_len
,
267 uint16_t val_len
, int type
, AVDictionary
**met
)
271 uint16_t buflen
= 2 * val_len
+ 1;
272 AVIOContext
*pb
= s
->pb
;
274 value
= av_malloc(buflen
);
276 return AVERROR(ENOMEM
);
277 if (type
== ASF_UNICODE
) {
278 // get_asf_string reads UTF-16 and converts it to UTF-8 which needs longer buffer
279 if ((ret
= get_asf_string(pb
, val_len
, value
, buflen
)) < 0)
281 if (av_dict_set(met
, name
, value
, 0) < 0)
282 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
285 if (val_len
> sizeof(buf
)) {
286 ret
= AVERROR_INVALIDDATA
;
289 if ((ret
= avio_read(pb
, value
, val_len
)) < 0)
291 if (ret
< 2 * val_len
)
294 value
[2 * val_len
- 1] = '\0';
295 snprintf(buf
, sizeof(buf
), "%s", value
);
296 if (av_dict_set(met
, name
, buf
, 0) < 0)
297 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
307 static int asf_read_generic_value(AVIOContext
*pb
, int type
, uint64_t *value
)
312 *value
= avio_rl16(pb
);
315 *value
= avio_rl32(pb
);
318 *value
= avio_rl64(pb
);
321 *value
= avio_rl16(pb
);
324 return AVERROR_INVALIDDATA
;
330 static int asf_set_metadata(AVFormatContext
*s
, const uint8_t *name
,
331 uint16_t name_len
, int type
, AVDictionary
**met
)
333 AVIOContext
*pb
= s
->pb
;
338 ret
= asf_read_generic_value(pb
, type
, &value
);
342 snprintf(buf
, sizeof(buf
), "%"PRIu64
, value
);
343 if (av_dict_set(met
, name
, buf
, 0) < 0)
344 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
349 /* MSDN claims that this should be "compatible with the ID3 frame, APIC",
350 * but in reality this is only loosely similar */
351 static int asf_read_picture(AVFormatContext
*s
, int len
)
353 ASFContext
*asf
= s
->priv_data
;
354 AVPacket pkt
= { 0 };
355 const CodecMime
*mime
= ff_id3v2_mime_tags
;
356 enum AVCodecID id
= AV_CODEC_ID_NONE
;
358 uint8_t *desc
= NULL
;
360 int ret
, type
, picsize
, desc_len
;
363 /* type + picsize + mime + desc */
364 if (len
< 1 + 4 + 2 + 2) {
365 av_log(s
, AV_LOG_ERROR
, "Invalid attached picture size: %d.\n", len
);
366 return AVERROR_INVALIDDATA
;
370 type
= avio_r8(s
->pb
);
372 if (type
>= FF_ARRAY_ELEMS(ff_id3v2_picture_types
) || type
< 0) {
373 av_log(s
, AV_LOG_WARNING
, "Unknown attached picture type: %d.\n", type
);
377 /* picture data size */
378 picsize
= avio_rl32(s
->pb
);
381 /* picture MIME type */
382 len
-= avio_get_str16le(s
->pb
, len
, mimetype
, sizeof(mimetype
));
383 while (mime
->id
!= AV_CODEC_ID_NONE
) {
384 if (!strncmp(mime
->str
, mimetype
, sizeof(mimetype
))) {
390 if (id
== AV_CODEC_ID_NONE
) {
391 av_log(s
, AV_LOG_ERROR
, "Unknown attached picture mimetype: %s.\n",
396 if (picsize
>= len
) {
397 av_log(s
, AV_LOG_ERROR
, "Invalid attached picture data size: %d >= %d.\n",
399 return AVERROR_INVALIDDATA
;
402 /* picture description */
403 desc_len
= (len
- picsize
) * 2 + 1;
404 desc
= av_malloc(desc_len
);
406 return AVERROR(ENOMEM
);
407 len
-= avio_get_str16le(s
->pb
, len
- picsize
, desc
, desc_len
);
409 ret
= av_get_packet(s
->pb
, &pkt
, picsize
);
413 st
= avformat_new_stream(s
, NULL
);
415 ret
= AVERROR(ENOMEM
);
418 asf
->asf_st
[asf
->nb_streams
] = av_mallocz(sizeof(*asf_st
));
419 asf_st
= asf
->asf_st
[asf
->nb_streams
];
421 ret
= AVERROR(ENOMEM
);
425 st
->disposition
|= AV_DISPOSITION_ATTACHED_PIC
;
426 st
->codec
->codec_type
= asf_st
->type
= AVMEDIA_TYPE_VIDEO
;
427 st
->codec
->codec_id
= id
;
428 st
->attached_pic
= pkt
;
429 st
->attached_pic
.stream_index
= asf_st
->index
= st
->index
;
430 st
->attached_pic
.flags
|= AV_PKT_FLAG_KEY
;
435 if (av_dict_set(&st
->metadata
, "title", desc
, AV_DICT_DONT_STRDUP_VAL
) < 0)
436 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
440 if (av_dict_set(&st
->metadata
, "comment", ff_id3v2_picture_types
[type
], 0) < 0)
441 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
447 av_packet_unref(&pkt
);
451 static void get_id3_tag(AVFormatContext
*s
, int len
)
453 ID3v2ExtraMeta
*id3v2_extra_meta
= NULL
;
455 ff_id3v2_read(s
, ID3v2_DEFAULT_MAGIC
, &id3v2_extra_meta
);
456 if (id3v2_extra_meta
)
457 ff_id3v2_parse_apic(s
, &id3v2_extra_meta
);
458 ff_id3v2_free_extra_meta(&id3v2_extra_meta
);
461 static int process_metadata(AVFormatContext
*s
, const uint8_t *name
, uint16_t name_len
,
462 uint16_t val_len
, uint16_t type
, AVDictionary
**met
)
470 asf_read_value(s
, name
, name_len
, val_len
, type
, met
);
473 if (!strcmp(name
, "WM/Picture")) // handle cover art
474 asf_read_picture(s
, val_len
);
475 else if (!strcmp(name
, "ID3")) // handle ID3 tag
476 get_id3_tag(s
, val_len
);
478 asf_read_value(s
, name
, name_len
, val_len
, type
, met
);
481 ff_get_guid(s
->pb
, &guid
);
484 if ((ret
= asf_set_metadata(s
, name
, name_len
, type
, met
)) < 0)
493 static int asf_read_ext_content(AVFormatContext
*s
, const GUIDParseTable
*g
)
495 ASFContext
*asf
= s
->priv_data
;
496 AVIOContext
*pb
= s
->pb
;
497 uint64_t size
= avio_rl64(pb
);
498 uint16_t nb_desc
= avio_rl16(pb
);
501 for (i
= 0; i
< nb_desc
; i
++) {
502 uint16_t name_len
, type
, val_len
;
503 uint8_t *name
= NULL
;
505 name_len
= avio_rl16(pb
);
507 return AVERROR_INVALIDDATA
;
508 name
= av_malloc(name_len
);
510 return AVERROR(ENOMEM
);
511 avio_get_str16le(pb
, name_len
, name
,
513 type
= avio_rl16(pb
);
514 // BOOL values are 16 bits long in the Metadata Object
515 // but 32 bits long in the Extended Content Description Object
516 if (type
== ASF_BOOL
)
518 val_len
= avio_rl16(pb
);
520 ret
= process_metadata(s
, name
, name_len
, val_len
, type
, &s
->metadata
);
526 align_position(pb
, asf
->offset
, size
);
530 static AVStream
*find_stream(AVFormatContext
*s
, uint16_t st_num
)
533 ASFContext
*asf
= s
->priv_data
;
536 for (i
= 0; i
< asf
->nb_streams
; i
++) {
537 if (asf
->asf_st
[i
]->stream_index
== st_num
) {
538 st
= s
->streams
[asf
->asf_st
[i
]->index
];
546 static int asf_store_aspect_ratio(AVFormatContext
*s
, uint8_t st_num
, uint8_t *name
, int type
)
548 ASFContext
*asf
= s
->priv_data
;
549 AVIOContext
*pb
= s
->pb
;
553 ret
= asf_read_generic_value(pb
, type
, &value
);
557 if (st_num
< ASF_MAX_STREAMS
) {
558 if (!strcmp(name
, "AspectRatioX"))
559 asf
->asf_sd
[st_num
].aspect_ratio
.num
= value
;
561 asf
->asf_sd
[st_num
].aspect_ratio
.den
= value
;
566 static int asf_read_metadata_obj(AVFormatContext
*s
, const GUIDParseTable
*g
)
568 ASFContext
*asf
= s
->priv_data
;
569 AVIOContext
*pb
= s
->pb
;
570 uint64_t size
= avio_rl64(pb
);
571 uint16_t nb_recs
= avio_rl16(pb
); // number of records in the Description Records list
574 for (i
= 0; i
< nb_recs
; i
++) {
575 uint16_t name_len
, buflen
, type
, val_len
, st_num
;
576 uint8_t *name
= NULL
;
578 avio_skip(pb
, 2); // skip reserved field
579 st_num
= avio_rl16(pb
);
580 name_len
= avio_rl16(pb
);
581 buflen
= 2 * name_len
+ 1;
584 type
= avio_rl16(pb
);
585 val_len
= avio_rl32(pb
);
586 name
= av_malloc(buflen
);
588 return AVERROR(ENOMEM
);
589 avio_get_str16le(pb
, name_len
, name
,
591 if (!strcmp(name
, "AspectRatioX") || !strcmp(name
, "AspectRatioY")) {
592 ret
= asf_store_aspect_ratio(s
, st_num
, name
, type
);
598 if (st_num
< ASF_MAX_STREAMS
) {
599 if ((ret
= process_metadata(s
, name
, name_len
, val_len
, type
,
600 &asf
->asf_sd
[st_num
].asf_met
)) < 0) {
609 align_position(pb
, asf
->offset
, size
);
613 static int asf_read_content_desc(AVFormatContext
*s
, const GUIDParseTable
*g
)
615 ASFContext
*asf
= s
->priv_data
;
616 AVIOContext
*pb
= s
->pb
;
618 static const char *const titles
[] =
619 { "Title", "Author", "Copyright", "Description", "Rate" };
620 uint16_t len
[5], buflen
[5] = { 0 };
622 uint64_t size
= avio_rl64(pb
);
624 for (i
= 0; i
< 5; i
++) {
625 len
[i
] = avio_rl16(pb
);
626 // utf8 string should be <= 2 * utf16 string, extra byte for the terminator
627 buflen
[i
] = 2 * len
[i
] + 1;
630 for (i
= 0; i
< 5; i
++) {
631 ch
= av_malloc(buflen
[i
]);
633 return(AVERROR(ENOMEM
));
634 asf_read_metadata(s
, titles
[i
], len
[i
], ch
, buflen
[i
]);
637 align_position(pb
, asf
->offset
, size
);
642 static int asf_read_properties(AVFormatContext
*s
, const GUIDParseTable
*g
)
644 ASFContext
*asf
= s
->priv_data
;
645 AVIOContext
*pb
= s
->pb
;
646 time_t creation_time
;
648 avio_rl64(pb
); // read object size
649 avio_skip(pb
, 16); // skip File ID
650 avio_skip(pb
, 8); // skip File size
651 creation_time
= avio_rl64(pb
);
652 if (!(asf
->b_flags
& ASF_FLAG_BROADCAST
)) {
657 // creation date is in 100 ns units from 1 Jan 1601, conversion to s
658 creation_time
/= 10000000;
659 // there are 11644473600 seconds between 1 Jan 1601 and 1 Jan 1970
660 creation_time
-= 11644473600;
661 tm
= gmtime_r(&creation_time
, &tmbuf
);
663 if (!strftime(buf
, sizeof(buf
), "%Y-%m-%d %H:%M:%S", tm
))
668 if (av_dict_set(&s
->metadata
, "creation_time", buf
, 0) < 0)
669 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
672 asf
->nb_packets
= avio_rl64(pb
);
673 asf
->duration
= avio_rl64(pb
) / 10000; // stream duration
674 avio_skip(pb
, 8); // skip send duration
675 asf
->preroll
= avio_rl64(pb
);
676 asf
->duration
-= asf
->preroll
;
677 asf
->b_flags
= avio_rl32(pb
);
678 avio_skip(pb
, 4); // skip minimal packet size
679 asf
->packet_size
= avio_rl32(pb
);
680 avio_skip(pb
, 4); // skip max_bitrate
685 static int parse_video_info(AVIOContext
*pb
, AVStream
*st
)
690 st
->codec
->width
= avio_rl32(pb
);
691 st
->codec
->height
= avio_rl32(pb
);
692 avio_skip(pb
, 1); // skip reserved flags
693 size
= avio_rl16(pb
); // size of the Format Data
694 tag
= ff_get_bmp_header(pb
, st
);
695 st
->codec
->codec_tag
= tag
;
696 st
->codec
->codec_id
= ff_codec_get_id(ff_codec_bmp_tags
, tag
);
698 if (size
> BMP_HEADER_SIZE
) {
700 st
->codec
->extradata_size
= size
- BMP_HEADER_SIZE
;
701 if (!(st
->codec
->extradata
= av_malloc(st
->codec
->extradata_size
+
702 AV_INPUT_BUFFER_PADDING_SIZE
))) {
703 st
->codec
->extradata_size
= 0;
704 return AVERROR(ENOMEM
);
706 memset(st
->codec
->extradata
+ st
->codec
->extradata_size
, 0,
707 AV_INPUT_BUFFER_PADDING_SIZE
);
708 if ((ret
= avio_read(pb
, st
->codec
->extradata
,
709 st
->codec
->extradata_size
)) < 0)
715 static int asf_read_stream_properties(AVFormatContext
*s
, const GUIDParseTable
*g
)
717 ASFContext
*asf
= s
->priv_data
;
718 AVIOContext
*pb
= s
->pb
;
720 uint32_t err_data_len
, ts_data_len
; // type specific data length
722 ff_asf_guid stream_type
;
723 enum AVMediaType type
;
725 uint8_t stream_index
;
729 // ASF file must not contain more than 128 streams according to the specification
730 if (asf
->nb_streams
>= ASF_MAX_STREAMS
)
731 return AVERROR_INVALIDDATA
;
733 size
= avio_rl64(pb
);
734 ff_get_guid(pb
, &stream_type
);
735 if (!ff_guidcmp(&stream_type
, &ff_asf_audio_stream
))
736 type
= AVMEDIA_TYPE_AUDIO
;
737 else if (!ff_guidcmp(&stream_type
, &ff_asf_video_stream
))
738 type
= AVMEDIA_TYPE_VIDEO
;
739 else if (!ff_guidcmp(&stream_type
, &ff_asf_jfif_media
))
740 type
= AVMEDIA_TYPE_VIDEO
;
741 else if (!ff_guidcmp(&stream_type
, &ff_asf_command_stream
))
742 type
= AVMEDIA_TYPE_DATA
;
743 else if (!ff_guidcmp(&stream_type
,
744 &ff_asf_ext_stream_embed_stream_header
))
745 type
= AVMEDIA_TYPE_UNKNOWN
;
747 return AVERROR_INVALIDDATA
;
749 ff_get_guid(pb
, &stream_type
); // error correction type
750 avio_skip(pb
, 8); // skip the time offset
751 ts_data_len
= avio_rl32(pb
);
752 err_data_len
= avio_rl32(pb
);
753 flags
= avio_rl16(pb
); // bit 15 - Encrypted Content
755 stream_index
= flags
& ASF_STREAM_NUM
;
756 for (i
= 0; i
< asf
->nb_streams
; i
++)
757 if (stream_index
== asf
->asf_st
[i
]->stream_index
) {
758 av_log(s
, AV_LOG_WARNING
,
759 "Duplicate stream found, this stream will be ignored.\n");
760 align_position(pb
, asf
->offset
, size
);
764 st
= avformat_new_stream(s
, NULL
);
766 return AVERROR(ENOMEM
);
767 avpriv_set_pts_info(st
, 32, 1, 1000); // pts should be dword, in milliseconds
768 st
->codec
->codec_type
= type
;
769 asf
->asf_st
[asf
->nb_streams
] = av_mallocz(sizeof(*asf_st
));
770 if (!asf
->asf_st
[asf
->nb_streams
])
771 return AVERROR(ENOMEM
);
772 asf_st
= asf
->asf_st
[asf
->nb_streams
];
774 asf_st
->stream_index
= stream_index
;
775 asf_st
->index
= st
->index
;
777 st
->id
= flags
& ASF_STREAM_NUM
;
778 av_init_packet(&asf_st
->pkt
.avpkt
);
779 asf_st
->pkt
.data_size
= 0;
780 avio_skip(pb
, 4); // skip reserved field
783 case AVMEDIA_TYPE_AUDIO
:
784 asf_st
->type
= AVMEDIA_TYPE_AUDIO
;
785 if ((ret
= ff_get_wav_header(s
, pb
, st
->codec
, ts_data_len
)) < 0)
788 case AVMEDIA_TYPE_VIDEO
:
789 asf_st
->type
= AVMEDIA_TYPE_VIDEO
;
790 if ((ret
= parse_video_info(pb
, st
)) < 0)
794 avio_skip(pb
, ts_data_len
);
799 if (type
== AVMEDIA_TYPE_AUDIO
) {
800 uint8_t span
= avio_r8(pb
);
803 asf_st
->virtual_pkt_len
= avio_rl16(pb
);
804 asf_st
->virtual_chunk_len
= avio_rl16(pb
);
805 if (!asf_st
->virtual_chunk_len
|| !asf_st
->virtual_pkt_len
)
806 return AVERROR_INVALIDDATA
;
807 avio_skip(pb
, err_data_len
- 5);
809 avio_skip(pb
, err_data_len
- 1);
811 avio_skip(pb
, err_data_len
);
814 align_position(pb
, asf
->offset
, size
);
819 static void set_language(AVFormatContext
*s
, const char *rfc1766
, AVDictionary
**met
)
821 // language abbr should contain at least 2 chars
822 if (rfc1766
&& strlen(rfc1766
) > 1) {
823 const char primary_tag
[3] = { rfc1766
[0], rfc1766
[1], '\0' }; // ignore country code if any
824 const char *iso6392
= av_convert_lang_to(primary_tag
,
825 AV_LANG_ISO639_2_BIBL
);
827 if (av_dict_set(met
, "language", iso6392
, 0) < 0)
828 av_log(s
, AV_LOG_WARNING
, "av_dict_set failed.\n");
832 static int asf_read_ext_stream_properties(AVFormatContext
*s
, const GUIDParseTable
*g
)
834 ASFContext
*asf
= s
->priv_data
;
835 AVIOContext
*pb
= s
->pb
;
838 uint16_t nb_st_name
, nb_pay_exts
, st_num
, lang_idx
;
841 uint64_t start_time
, end_time
, time_per_frame
;
842 uint64_t size
= avio_rl64(pb
);
844 start_time
= avio_rl64(pb
);
845 end_time
= avio_rl64(pb
);
846 bitrate
= avio_rl32(pb
);
847 avio_skip(pb
, 28); // skip some unused values
848 st_num
= avio_rl16(pb
);
849 st_num
&= ASF_STREAM_NUM
;
850 lang_idx
= avio_rl16(pb
); // Stream Language ID Index
851 for (i
= 0; i
< asf
->nb_streams
; i
++) {
852 if (st_num
== asf
->asf_st
[i
]->stream_index
) {
853 st
= s
->streams
[asf
->asf_st
[i
]->index
];
854 asf
->asf_st
[i
]->lang_idx
= lang_idx
;
858 time_per_frame
= avio_rl64(pb
); // average time per frame
860 st
->start_time
= start_time
;
861 st
->duration
= end_time
- start_time
;
862 st
->codec
->bit_rate
= bitrate
;
863 st
->avg_frame_rate
.num
= 10000000;
864 st
->avg_frame_rate
.den
= time_per_frame
;
866 nb_st_name
= avio_rl16(pb
);
867 nb_pay_exts
= avio_rl16(pb
);
868 for (i
= 0; i
< nb_st_name
; i
++) {
871 avio_rl16(pb
); // Language ID Index
876 for (i
= 0; i
< nb_pay_exts
; i
++) {
878 avio_skip(pb
, 16); // Extension System ID
879 avio_skip(pb
, 2); // Extension Data Size
884 if ((ret
= ff_get_guid(pb
, &guid
)) < 0) {
885 align_position(pb
, asf
->offset
, size
);
891 if (g
&& !(strcmp(g
->name
, "Stream Properties"))) {
892 if ((ret
= g
->read_object(s
, g
)) < 0)
896 align_position(pb
, asf
->offset
, size
);
900 static int asf_read_language_list(AVFormatContext
*s
, const GUIDParseTable
*g
)
902 ASFContext
*asf
= s
->priv_data
;
903 AVIOContext
*pb
= s
->pb
;
905 uint64_t size
= avio_rl64(pb
);
906 uint16_t nb_langs
= avio_rl16(pb
);
908 if (nb_langs
< ASF_MAX_STREAMS
) {
909 for (i
= 0; i
< nb_langs
; i
++) {
914 if ((ret
= get_asf_string(pb
, len
, asf
->asf_sd
[i
].langs
,
915 sizeof(asf
->asf_sd
[i
].langs
))) < 0) {
921 align_position(pb
, asf
->offset
, size
);
925 // returns data object offset when reading this object for the first time
926 static int asf_read_data(AVFormatContext
*s
, const GUIDParseTable
*g
)
928 ASFContext
*asf
= s
->priv_data
;
929 AVIOContext
*pb
= s
->pb
;
930 uint64_t size
= asf
->data_size
= avio_rl64(pb
);
933 if (!asf
->data_reached
) {
934 asf
->data_reached
= 1;
935 asf
->data_offset
= asf
->offset
;
938 for (i
= 0; i
< asf
->nb_streams
; i
++) {
939 if (!(asf
->b_flags
& ASF_FLAG_BROADCAST
))
940 s
->streams
[i
]->duration
= asf
->duration
;
942 asf
->nb_mult_left
= 0;
944 asf
->state
= PARSE_PACKET_HEADER
;
945 asf
->return_subpayload
= 0;
946 asf
->packet_size_internal
= 0;
947 avio_skip(pb
, 16); // skip File ID
948 size
= avio_rl64(pb
); // Total Data Packets
949 if (size
!= asf
->nb_packets
)
950 av_log(s
, AV_LOG_WARNING
,
951 "Number of Packets from File Properties Object is not equal to Total"
952 "Datapackets value! num of packets %"PRIu64
" total num %"PRIu64
".\n",
953 size
, asf
->nb_packets
);
954 avio_skip(pb
, 2); // skip reserved field
955 asf
->first_packet_offset
= avio_tell(pb
);
956 if (pb
->seekable
&& !(asf
->b_flags
& ASF_FLAG_BROADCAST
))
957 align_position(pb
, asf
->offset
, asf
->data_size
);
962 static int asf_read_simple_index(AVFormatContext
*s
, const GUIDParseTable
*g
)
964 ASFContext
*asf
= s
->priv_data
;
965 AVIOContext
*pb
= s
->pb
;
967 uint64_t interval
; // index entry time interval in 100 ns units, usually it's 1s
968 uint32_t pkt_num
, nb_entries
;
969 int32_t prev_pkt_num
= -1;
971 uint64_t size
= avio_rl64(pb
);
973 // simple index objects should be ordered by stream number, this loop tries to find
974 // the first not indexed video stream
975 for (i
= 0; i
< asf
->nb_streams
; i
++) {
976 if ((asf
->asf_st
[i
]->type
== AVMEDIA_TYPE_VIDEO
) && !asf
->asf_st
[i
]->indexed
) {
977 asf
->asf_st
[i
]->indexed
= 1;
978 st
= s
->streams
[asf
->asf_st
[i
]->index
];
983 avio_skip(pb
, size
- 24); // if there's no video stream, skip index object
986 avio_skip(pb
, 16); // skip File ID
987 interval
= avio_rl64(pb
);
989 nb_entries
= avio_rl32(pb
);
990 for (i
= 0; i
< nb_entries
; i
++) {
991 pkt_num
= avio_rl32(pb
);
993 if (prev_pkt_num
!= pkt_num
) {
994 av_add_index_entry(st
, asf
->first_packet_offset
+ asf
->packet_size
*
995 pkt_num
, av_rescale(interval
, i
, 10000),
996 asf
->packet_size
, 0, AVINDEX_KEYFRAME
);
997 prev_pkt_num
= pkt_num
;
1000 asf
->is_simple_index
= 1;
1001 align_position(pb
, asf
->offset
, size
);
1006 static const GUIDParseTable gdef
[] = {
1007 { "Data", { 0x75, 0xB2, 0x26, 0x36, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_data
, 1 },
1008 { "Simple Index", { 0x33, 0x00, 0x08, 0x90, 0xE5, 0xB1, 0x11, 0xCF, 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }, asf_read_simple_index
, 1 },
1009 { "Content Description", { 0x75, 0xB2, 0x26, 0x33, 0x66 ,0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_content_desc
, 1 },
1010 { "Extended Content Description", { 0xD2, 0xD0, 0xA4, 0x40, 0xE3, 0x07, 0x11, 0xD2, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5e, 0xA8, 0x50 }, asf_read_ext_content
, 1 },
1011 { "Stream Bitrate Properties", { 0x7B, 0xF8, 0x75, 0xCE, 0x46, 0x8D, 0x11, 0xD1, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2 }, asf_read_unknown
, 1 },
1012 { "File Properties", { 0x8C, 0xAB, 0xDC, 0xA1, 0xA9, 0x47, 0x11, 0xCF, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_properties
, 1 },
1013 { "Header Extension", { 0x5F, 0xBF, 0x03, 0xB5, 0xA9, 0x2E, 0x11, 0xCF, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_unknown
, 0 },
1014 { "Stream Properties", { 0xB7, 0xDC, 0x07, 0x91, 0xA9, 0xB7, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_stream_properties
, 1 },
1015 { "Codec List", { 0x86, 0xD1, 0x52, 0x40, 0x31, 0x1D, 0x11, 0xD0, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown
, 1 },
1016 { "Marker", { 0xF4, 0x87, 0xCD, 0x01, 0xA9, 0x51, 0x11, 0xCF, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, asf_read_marker
, 1 },
1017 { "Script Command", { 0x1E, 0xFB, 0x1A, 0x30, 0x0B, 0x62, 0x11, 0xD0, 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, asf_read_unknown
, 1 },
1018 { "Language List", { 0x7C, 0x43, 0x46, 0xa9, 0xef, 0xe0, 0x4B, 0xFC, 0xB2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 }, asf_read_language_list
, 1},
1019 { "Padding", { 0x18, 0x06, 0xD4, 0x74, 0xCA, 0xDF, 0x45, 0x09, 0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8 }, asf_read_unknown
, 1 },
1020 { "DRMv1 Header", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown
, 1 },
1021 { "DRMv2 Header", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9c }, asf_read_unknown
, 1 },
1022 { "Index", { 0xD6, 0xE2, 0x29, 0xD3, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown
, 1 },
1023 { "Media Object Index", { 0xFE, 0xB1, 0x03, 0xF8, 0x12, 0xAD, 0x4C, 0x64, 0x84, 0x0F, 0x2A, 0x1D, 0x2F, 0x7A, 0xD4, 0x8C }, asf_read_unknown
, 1 },
1024 { "Timecode Index", { 0x3C, 0xB7, 0x3F, 0xD0, 0x0C, 0x4A, 0x48, 0x03, 0x95, 0x3D, 0xED, 0xF7, 0xB6, 0x22, 0x8F, 0x0C }, asf_read_unknown
, 0 },
1025 { "Bitrate_Mutual_Exclusion", { 0xD6, 0xE2, 0x29, 0xDC, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown
, 1 },
1026 { "Error Correction", { 0x75, 0xB2, 0x26, 0x35, 0x66, 0x8E, 0x11, 0xCF, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, asf_read_unknown
, 1 },
1027 { "Content Branding", { 0x22, 0x11, 0xB3, 0xFA, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown
, 1 },
1028 { "Content Encryption", { 0x22, 0x11, 0xB3, 0xFB, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown
, 1 },
1029 { "Extended Content Encryption", { 0x29, 0x8A, 0xE6, 0x14, 0x26, 0x22, 0x4C, 0x17, 0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9C }, asf_read_unknown
, 1 },
1030 { "Digital Signature", { 0x22, 0x11, 0xB3, 0xFC, 0xBD, 0x23, 0x11, 0xD2, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, asf_read_unknown
, 1 },
1031 { "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 },
1032 { "Advanced Mutual Exclusion", { 0xA0, 0x86, 0x49, 0xCF, 0x47, 0x75, 0x46, 0x70, 0x8A, 0x16, 0x6E, 0x35, 0x35, 0x75, 0x66, 0xCD }, asf_read_unknown
, 1 },
1033 { "Group Mutual Exclusion", { 0xD1, 0x46, 0x5A, 0x40, 0x5A, 0x79, 0x43, 0x38, 0xB7, 0x1B, 0xE3, 0x6B, 0x8F, 0xD6, 0xC2, 0x49 }, asf_read_unknown
, 1},
1034 { "Stream Prioritization", { 0xD4, 0xFE, 0xD1, 0x5B, 0x88, 0xD3, 0x45, 0x4F, 0x81, 0xF0, 0xED, 0x5C, 0x45, 0x99, 0x9E, 0x24 }, asf_read_unknown
, 1 },
1035 { "Bandwidth Sharing Object", { 0xA6, 0x96, 0x09, 0xE6, 0x51, 0x7B, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown
, 1 },
1036 { "Metadata", { 0xC5, 0xF8, 0xCB, 0xEA, 0x5B, 0xAF, 0x48, 0x77, 0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA }, asf_read_metadata_obj
, 1 },
1037 { "Metadata Library", { 0x44, 0x23, 0x1C, 0x94, 0x94, 0x98, 0x49, 0xD1, 0xA1, 0x41, 0x1D, 0x13, 0x4E, 0x45, 0x70, 0x54 }, asf_read_metadata_obj
, 1 },
1038 { "Audio Spread", { 0xBF, 0xC3, 0xCD, 0x50, 0x61, 0x8F, 0x11, 0xCF, 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20 }, asf_read_unknown
, 1 },
1039 { "Index Parameters", { 0xD6, 0xE2, 0x29, 0xDF, 0x35, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown
, 1 },
1040 { "Content Encryption System Windows Media DRM Network Devices",
1041 { 0x7A, 0x07, 0x9B, 0xB6, 0xDA, 0XA4, 0x4e, 0x12, 0xA5, 0xCA, 0x91, 0xD3, 0x8D, 0xC1, 0x1A, 0x8D }, asf_read_unknown
, 1 },
1042 { "Mutex Language", { 0xD6, 0xE2, 0x2A, 0x00, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown
, 1 },
1043 { "Mutex Bitrate", { 0xD6, 0xE2, 0x2A, 0x01, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown
, 1 },
1044 { "Mutex Unknown", { 0xD6, 0xE2, 0x2A, 0x02, 0x25, 0xDA, 0x11, 0xD1, 0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE }, asf_read_unknown
, 1 },
1045 { "Bandwith Sharing Exclusive", { 0xAF, 0x60, 0x60, 0xAA, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown
, 1 },
1046 { "Bandwith Sharing Partial", { 0xAF, 0x60, 0x60, 0xAB, 0x51, 0x97, 0x11, 0xD2, 0xB6, 0xAF, 0x00, 0xC0, 0x4F, 0xD9, 0x08, 0xE9 }, asf_read_unknown
, 1 },
1047 { "Payload Extension System Timecode", { 0x39, 0x95, 0x95, 0xEC, 0x86, 0x67, 0x4E, 0x2D, 0x8F, 0xDB, 0x98, 0x81, 0x4C, 0xE7, 0x6C, 0x1E }, asf_read_unknown
, 1 },
1048 { "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 },
1049 { "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 },
1050 { "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 },
1051 { "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 },
1052 { "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 },
1053 { "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 },
1056 #define READ_LEN(flag, name, len) \
1058 if ((flag) == name ## IS_BYTE) \
1059 len = avio_r8(pb); \
1060 else if ((flag) == name ## IS_WORD) \
1061 len = avio_rl16(pb); \
1062 else if ((flag) == name ## IS_DWORD) \
1063 len = avio_rl32(pb); \
1068 static int asf_read_subpayload(AVFormatContext
*s
, AVPacket
*pkt
, int is_header
)
1070 ASFContext
*asf
= s
->priv_data
;
1071 AVIOContext
*pb
= s
->pb
;
1076 asf
->dts_delta
= avio_r8(pb
);
1077 if (asf
->nb_mult_left
) {
1078 asf
->mult_sub_len
= avio_rl16(pb
); // total
1080 asf
->sub_header_offset
= avio_tell(pb
);
1084 sub_len
= avio_r8(pb
);
1085 if ((ret
= av_get_packet(pb
, pkt
, sub_len
)) < 0) // each subpayload is entire frame
1087 for (i
= 0; i
< asf
->nb_streams
; i
++) {
1088 if (asf
->stream_index
== asf
->asf_st
[i
]->stream_index
) {
1089 pkt
->stream_index
= asf
->asf_st
[i
]->index
;
1093 asf
->return_subpayload
= 1;
1095 asf
->return_subpayload
= 0;
1099 pkt
->dts
= asf
->sub_dts
+ (asf
->nb_sub
- 1) * asf
->dts_delta
- asf
->preroll
;
1100 if (asf
->nb_mult_left
&& (avio_tell(pb
) >=
1101 (asf
->sub_header_offset
+ asf
->mult_sub_len
))) {
1103 asf
->nb_mult_left
--;
1105 if (avio_tell(pb
) >= asf
->packet_offset
+ asf
->packet_size
- asf
->pad_len
) {
1107 if (!asf
->nb_mult_left
) {
1108 avio_skip(pb
, asf
->pad_len
);
1109 if (avio_tell(pb
) != asf
->packet_offset
+ asf
->packet_size
) {
1110 if (!asf
->packet_size
)
1111 return AVERROR_INVALIDDATA
;
1112 av_log(s
, AV_LOG_WARNING
,
1113 "Position %"PRId64
" wrong, should be %"PRId64
"\n",
1114 avio_tell(pb
), asf
->packet_offset
+ asf
->packet_size
);
1115 avio_seek(pb
, asf
->packet_offset
+ asf
->packet_size
, SEEK_SET
);
1123 static void reset_packet(ASFPacket
*asf_pkt
)
1125 asf_pkt
->size_left
= 0;
1126 asf_pkt
->data_size
= 0;
1127 asf_pkt
->duration
= 0;
1130 asf_pkt
->duration
= 0;
1131 av_packet_unref(&asf_pkt
->avpkt
);
1132 av_init_packet(&asf_pkt
->avpkt
);
1135 static int asf_read_replicated_data(AVFormatContext
*s
, ASFPacket
*asf_pkt
)
1137 ASFContext
*asf
= s
->priv_data
;
1138 AVIOContext
*pb
= s
->pb
;
1141 if (!asf_pkt
->data_size
) {
1142 data_size
= avio_rl32(pb
); // read media object size
1144 return AVERROR_INVALIDDATA
;
1145 if ((ret
= av_new_packet(&asf_pkt
->avpkt
, data_size
)) < 0)
1147 asf_pkt
->data_size
= asf_pkt
->size_left
= data_size
;
1149 avio_skip(pb
, 4); // reading of media object size is already done
1150 asf_pkt
->dts
= avio_rl32(pb
); // read presentation time
1151 if (asf
->rep_data_len
&& (asf
->rep_data_len
>= 8))
1152 avio_skip(pb
, asf
->rep_data_len
- 8); // skip replicated data
1157 static int asf_read_multiple_payload(AVFormatContext
*s
, AVPacket
*pkt
,
1160 ASFContext
*asf
= s
->priv_data
;
1161 AVIOContext
*pb
= s
->pb
;
1167 // if replicated lenght is 1, subpayloads are present
1168 if (asf
->rep_data_len
== 1) {
1170 asf
->state
= READ_MULTI_SUB
;
1171 pkt
->flags
= asf_pkt
->flags
;
1172 if ((ret
= asf_read_subpayload(s
, pkt
, 1)) < 0)
1175 if (asf
->rep_data_len
)
1176 if ((ret
= asf_read_replicated_data(s
, asf_pkt
)) < 0)
1178 pay_len
= avio_rl16(pb
); // payload length should be WORD
1179 if (pay_len
> asf
->packet_size
) {
1180 av_log(s
, AV_LOG_ERROR
,
1181 "Error: invalid data packet size, pay_len %"PRIu16
", "
1182 "asf->packet_size %"PRIu32
", offset %"PRId64
".\n",
1183 pay_len
, asf
->packet_size
, avio_tell(pb
));
1184 return AVERROR_INVALIDDATA
;
1186 p
= asf_pkt
->avpkt
.data
+ asf_pkt
->data_size
- asf_pkt
->size_left
;
1187 if (pay_len
> asf_pkt
->size_left
) {
1188 av_log(s
, AV_LOG_ERROR
,
1189 "Error: invalid buffer size, pay_len %d, data size left %d.\n",
1190 pay_len
, asf_pkt
->size_left
);
1191 skip
= pay_len
- asf_pkt
->size_left
;
1192 pay_len
= asf_pkt
->size_left
;
1194 if (asf_pkt
->size_left
<= 0)
1195 return AVERROR_INVALIDDATA
;
1196 if ((ret
= avio_read(pb
, p
, pay_len
)) < 0)
1198 if (s
->key
&& s
->keylen
== 20)
1199 ff_asfcrypt_dec(s
->key
, p
, ret
);
1200 avio_skip(pb
, skip
);
1201 asf_pkt
->size_left
-= pay_len
;
1202 asf
->nb_mult_left
--;
1208 static int asf_read_single_payload(AVFormatContext
*s
, AVPacket
*pkt
,
1211 ASFContext
*asf
= s
->priv_data
;
1212 AVIOContext
*pb
= s
->pb
;
1218 if (!asf_pkt
->data_size
) {
1219 data_size
= avio_rl32(pb
); // read media objectgg size
1222 if ((ret
= av_new_packet(&asf_pkt
->avpkt
, data_size
)) < 0)
1224 asf_pkt
->data_size
= asf_pkt
->size_left
= data_size
;
1226 avio_skip(pb
, 4); // skip media object size
1227 asf_pkt
->dts
= avio_rl32(pb
); // read presentation time
1228 if (asf
->rep_data_len
>= 8)
1229 avio_skip(pb
, asf
->rep_data_len
- 8); // skip replicated data
1230 offset
= avio_tell(pb
);
1232 // size of the payload - size of the packet without header and padding
1233 if (asf
->packet_size_internal
)
1234 size
= asf
->packet_size_internal
- offset
+ asf
->packet_offset
- asf
->pad_len
;
1236 size
= asf
->packet_size
- offset
+ asf
->packet_offset
- asf
->pad_len
;
1237 if (size
> asf
->packet_size
) {
1238 av_log(s
, AV_LOG_ERROR
,
1239 "Error: invalid data packet size, offset %"PRId64
".\n",
1241 return AVERROR_INVALIDDATA
;
1243 p
= asf_pkt
->avpkt
.data
+ asf_pkt
->data_size
- asf_pkt
->size_left
;
1244 if (size
> asf_pkt
->size_left
|| asf_pkt
->size_left
<= 0)
1245 return AVERROR_INVALIDDATA
;
1246 if (asf_pkt
->size_left
> size
)
1247 asf_pkt
->size_left
-= size
;
1249 asf_pkt
->size_left
= 0;
1250 if ((ret
= avio_read(pb
, p
, size
)) < 0)
1252 if (s
->key
&& s
->keylen
== 20)
1253 ff_asfcrypt_dec(s
->key
, p
, ret
);
1254 if (asf
->packet_size_internal
)
1255 avio_skip(pb
, asf
->packet_size
- asf
->packet_size_internal
);
1256 avio_skip(pb
, asf
->pad_len
); // skip padding
1261 static int asf_read_payload(AVFormatContext
*s
, AVPacket
*pkt
)
1263 ASFContext
*asf
= s
->priv_data
;
1264 AVIOContext
*pb
= s
->pb
;
1266 ASFPacket
*asf_pkt
= NULL
;
1268 if (!asf
->sub_left
) {
1269 uint32_t off_len
, media_len
;
1272 stream_num
= avio_r8(pb
);
1273 asf
->stream_index
= stream_num
& ASF_STREAM_NUM
;
1274 for (i
= 0; i
< asf
->nb_streams
; i
++) {
1275 if (asf
->stream_index
== asf
->asf_st
[i
]->stream_index
) {
1276 asf_pkt
= &asf
->asf_st
[i
]->pkt
;
1277 asf_pkt
->stream_index
= asf
->asf_st
[i
]->index
;
1282 if (asf
->packet_offset
+ asf
->packet_size
<= asf
->data_offset
+ asf
->data_size
) {
1283 avio_seek(pb
, asf
->packet_offset
+ asf
->packet_size
, SEEK_SET
);
1284 av_log(s
, AV_LOG_WARNING
, "Skipping the stream with the invalid stream index %d.\n",
1286 return AVERROR(EAGAIN
);
1288 return AVERROR_INVALIDDATA
;
1291 if (stream_num
>> 7)
1292 asf_pkt
->flags
|= AV_PKT_FLAG_KEY
;
1293 READ_LEN(asf
->prop_flags
& ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE
,
1294 ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_
, media_len
);
1295 READ_LEN(asf
->prop_flags
& ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE
,
1296 ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_
, off_len
);
1297 READ_LEN(asf
->prop_flags
& ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE
,
1298 ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_
, asf
->rep_data_len
);
1299 if (asf_pkt
->size_left
&& (asf_pkt
->frame_num
!= media_len
)) {
1300 av_log(s
, AV_LOG_WARNING
, "Unfinished frame will be ignored\n");
1301 reset_packet(asf_pkt
);
1303 asf_pkt
->frame_num
= media_len
;
1304 asf
->sub_dts
= off_len
;
1305 if (asf
->nb_mult_left
) {
1306 if ((ret
= asf_read_multiple_payload(s
, pkt
, asf_pkt
)) < 0)
1308 } else if (asf
->rep_data_len
== 1) {
1310 asf
->state
= READ_SINGLE
;
1311 pkt
->flags
= asf_pkt
->flags
;
1312 if ((ret
= asf_read_subpayload(s
, pkt
, 1)) < 0)
1315 if ((ret
= asf_read_single_payload(s
, pkt
, asf_pkt
)) < 0)
1319 for (i
= 0; i
<= asf
->nb_streams
; i
++) {
1320 if (asf
->stream_index
== asf
->asf_st
[i
]->stream_index
) {
1321 asf_pkt
= &asf
->asf_st
[i
]->pkt
;
1326 return AVERROR_INVALIDDATA
;
1327 pkt
->flags
= asf_pkt
->flags
;
1328 pkt
->dts
= asf_pkt
->dts
;
1329 pkt
->stream_index
= asf
->asf_st
[i
]->index
;
1330 if ((ret
= asf_read_subpayload(s
, pkt
, 0)) < 0) // read subpayload without its header
1337 static int asf_read_packet_header(AVFormatContext
*s
)
1339 ASFContext
*asf
= s
->priv_data
;
1340 AVIOContext
*pb
= s
->pb
;
1342 uint32_t av_unused seq
;
1343 unsigned char error_flags
, len_flags
, pay_flags
;
1345 asf
->packet_offset
= avio_tell(pb
);
1346 error_flags
= avio_r8(pb
); // read Error Correction Flags
1347 if (error_flags
& ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT
) {
1348 if (!(error_flags
& ASF_ERROR_CORRECTION_LENGTH_TYPE
)) {
1349 size
= error_flags
& ASF_PACKET_ERROR_CORRECTION_DATA_SIZE
;
1350 avio_skip(pb
, size
);
1352 len_flags
= avio_r8(pb
);
1354 len_flags
= error_flags
;
1355 asf
->prop_flags
= avio_r8(pb
);
1356 READ_LEN(len_flags
& ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE
,
1357 ASF_PPI_FLAG_PACKET_LENGTH_FIELD_
, asf
->packet_size_internal
);
1358 READ_LEN(len_flags
& ASF_PPI_MASK_SEQUENCE_FIELD_SIZE
,
1359 ASF_PPI_FLAG_SEQUENCE_FIELD_
, seq
);
1360 READ_LEN(len_flags
& ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE
,
1361 ASF_PPI_FLAG_PADDING_LENGTH_FIELD_
, asf
->pad_len
);
1362 asf
->send_time
= avio_rl32(pb
); // send time
1363 avio_skip(pb
, 2); // skip duration
1364 if (len_flags
& ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT
) { // Multiple Payloads present
1365 pay_flags
= avio_r8(pb
);
1366 asf
->nb_mult_left
= (pay_flags
& ASF_NUM_OF_PAYLOADS
);
1372 static int asf_deinterleave(AVFormatContext
*s
, ASFPacket
*asf_pkt
, int st_num
)
1374 ASFContext
*asf
= s
->priv_data
;
1375 ASFStream
*asf_st
= asf
->asf_st
[st_num
];
1376 unsigned char *p
= asf_pkt
->avpkt
.data
;
1377 uint16_t pkt_len
= asf
->asf_st
[st_num
]->virtual_pkt_len
;
1378 uint16_t chunk_len
= asf
->asf_st
[st_num
]->virtual_chunk_len
;
1379 int nchunks
= pkt_len
/ chunk_len
;
1381 int pos
= 0, j
, l
, ret
;
1384 if ((ret
= av_new_packet(&pkt
, asf_pkt
->data_size
)) < 0)
1387 while (asf_pkt
->data_size
>= asf_st
->span
* pkt_len
+ pos
) {
1388 if (pos
>= asf_pkt
->data_size
) {
1391 for (l
= 0; l
< pkt_len
; l
++) {
1392 if (pos
>= asf_pkt
->data_size
) {
1395 for (j
= 0; j
< asf_st
->span
; j
++) {
1396 if ((pos
+ chunk_len
) >= asf_pkt
->data_size
)
1398 memcpy(pkt
.data
+ pos
,
1399 p
+ (j
* nchunks
+ l
) * chunk_len
,
1404 p
+= asf_st
->span
* pkt_len
;
1405 if (p
> asf_pkt
->avpkt
.data
+ asf_pkt
->data_size
)
1408 av_packet_unref(&asf_pkt
->avpkt
);
1409 asf_pkt
->avpkt
= pkt
;
1414 static int asf_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
1416 ASFContext
*asf
= s
->priv_data
;
1417 AVIOContext
*pb
= s
->pb
;
1420 if ((avio_tell(pb
) >= asf
->data_offset
+ asf
->data_size
) &&
1421 !(asf
->b_flags
& ASF_FLAG_BROADCAST
))
1423 while (!pb
->eof_reached
) {
1424 if (asf
->state
== PARSE_PACKET_HEADER
) {
1425 asf_read_packet_header(s
);
1426 if (!asf
->nb_mult_left
)
1427 asf
->state
= READ_SINGLE
;
1429 asf
->state
= READ_MULTI
;
1431 ret
= asf_read_payload(s
, pkt
);
1432 if (ret
== AVERROR(EAGAIN
)) {
1433 asf
->state
= PARSE_PACKET_HEADER
;
1439 switch (asf
->state
) {
1442 asf
->state
= PARSE_PACKET_HEADER
;
1444 case READ_MULTI_SUB
:
1445 if (!asf
->sub_left
&& !asf
->nb_mult_left
) {
1446 asf
->state
= PARSE_PACKET_HEADER
;
1447 if (!asf
->return_subpayload
&&
1448 (avio_tell(pb
) <= asf
->packet_offset
+
1449 asf
->packet_size
- asf
->pad_len
))
1450 avio_skip(pb
, asf
->pad_len
); // skip padding
1451 if (asf
->packet_offset
+ asf
->packet_size
> avio_tell(pb
))
1452 avio_seek(pb
, asf
->packet_offset
+ asf
->packet_size
, SEEK_SET
);
1453 } else if (!asf
->sub_left
)
1454 asf
->state
= READ_MULTI
;
1457 if (!asf
->nb_mult_left
) {
1458 asf
->state
= PARSE_PACKET_HEADER
;
1459 if (!asf
->return_subpayload
&&
1460 (avio_tell(pb
) <= asf
->packet_offset
+
1461 asf
->packet_size
- asf
->pad_len
))
1462 avio_skip(pb
, asf
->pad_len
); // skip padding
1463 if (asf
->packet_offset
+ asf
->packet_size
> avio_tell(pb
))
1464 avio_seek(pb
, asf
->packet_offset
+ asf
->packet_size
, SEEK_SET
);
1468 if (asf
->return_subpayload
) {
1469 asf
->return_subpayload
= 0;
1472 for (i
= 0; i
< s
->nb_streams
; i
++) {
1473 ASFPacket
*asf_pkt
= &asf
->asf_st
[i
]->pkt
;
1474 if (asf_pkt
&& !asf_pkt
->size_left
&& asf_pkt
->data_size
) {
1475 if (asf
->asf_st
[i
]->span
> 1 &&
1476 asf
->asf_st
[i
]->type
== AVMEDIA_TYPE_AUDIO
)
1477 if ((ret
= asf_deinterleave(s
, asf_pkt
, i
)) < 0)
1479 av_packet_move_ref(pkt
, &asf_pkt
->avpkt
);
1480 pkt
->stream_index
= asf
->asf_st
[i
]->index
;
1481 pkt
->flags
= asf_pkt
->flags
;
1482 pkt
->dts
= asf_pkt
->dts
- asf
->preroll
;
1483 asf_pkt
->data_size
= 0;
1484 asf_pkt
->frame_num
= 0;
1490 if (pb
->eof_reached
)
1496 static int asf_read_close(AVFormatContext
*s
)
1498 ASFContext
*asf
= s
->priv_data
;
1501 for (i
= 0; i
< ASF_MAX_STREAMS
; i
++) {
1502 av_dict_free(&asf
->asf_sd
[i
].asf_met
);
1503 if (i
< asf
->nb_streams
) {
1504 av_packet_unref(&asf
->asf_st
[i
]->pkt
.avpkt
);
1505 av_freep(&asf
->asf_st
[i
]);
1509 asf
->nb_streams
= 0;
1513 static void reset_packet_state(AVFormatContext
*s
)
1515 ASFContext
*asf
= s
->priv_data
;
1518 asf
->state
= PARSE_PACKET_HEADER
;
1520 asf
->return_subpayload
= 0;
1522 asf
->sub_header_offset
= 0;
1523 asf
->packet_offset
= asf
->first_packet_offset
;
1525 asf
->rep_data_len
= 0;
1527 asf
->mult_sub_len
= 0;
1528 asf
->nb_mult_left
= 0;
1530 asf
->prop_flags
= 0;
1532 for (i
= 0; i
< asf
->nb_streams
; i
++) {
1533 ASFPacket
*pkt
= &asf
->asf_st
[i
]->pkt
;
1540 av_packet_unref(&pkt
->avpkt
);
1541 av_init_packet(&pkt
->avpkt
);
1546 * Find a timestamp for the requested position within the payload
1547 * where the pos (position) is the offset inside the Data Object.
1548 * When position is not on the packet boundary, asf_read_timestamp tries
1549 * to find the closest packet offset after this position. If this packet
1550 * is a key frame, this packet timestamp is read and an index entry is created
1551 * for the packet. If this packet belongs to the requested stream,
1552 * asf_read_timestamp upgrades pos to the packet beginning offset and
1553 * returns this packet's dts. So returned dts is the dts of the first key frame with
1554 * matching stream number after given position.
1556 static int64_t asf_read_timestamp(AVFormatContext
*s
, int stream_index
,
1557 int64_t *pos
, int64_t pos_limit
)
1559 ASFContext
*asf
= s
->priv_data
;
1560 int64_t pkt_pos
= *pos
, pkt_offset
, dts
= AV_NOPTS_VALUE
, data_end
;
1564 data_end
= asf
->data_offset
+ asf
->data_size
;
1566 n
= (pkt_pos
- asf
->first_packet_offset
+ asf
->packet_size
- 1) /
1568 n
= av_clip(n
, 0, ((data_end
- asf
->first_packet_offset
) / asf
->packet_size
- 1));
1569 pkt_pos
= asf
->first_packet_offset
+ n
* asf
->packet_size
;
1571 avio_seek(s
->pb
, pkt_pos
, SEEK_SET
);
1572 pkt_offset
= pkt_pos
;
1574 reset_packet_state(s
);
1575 while (avio_tell(s
->pb
) < data_end
) {
1577 int i
, ret
, st_found
;
1579 av_init_packet(&pkt
);
1580 pkt_offset
= avio_tell(s
->pb
);
1581 if ((ret
= asf_read_packet(s
, &pkt
)) < 0) {
1582 dts
= AV_NOPTS_VALUE
;
1585 // ASFPacket may contain fragments of packets belonging to different streams,
1586 // pkt_offset is the offset of the first fragment within it.
1587 if ((pkt_offset
>= (pkt_pos
+ asf
->packet_size
)))
1588 pkt_pos
+= asf
->packet_size
;
1589 for (i
= 0; i
< asf
->nb_streams
; i
++) {
1590 ASFStream
*st
= asf
->asf_st
[i
];
1593 if (pkt
.flags
& AV_PKT_FLAG_KEY
) {
1596 av_add_index_entry(s
->streams
[pkt
.stream_index
], pkt_pos
,
1597 dts
, pkt
.size
, 0, AVINDEX_KEYFRAME
);
1598 if (stream_index
== st
->index
) {
1607 av_packet_unref(&pkt
);
1611 av_packet_unref(&pkt
);
1615 static int asf_read_seek(AVFormatContext
*s
, int stream_index
,
1616 int64_t timestamp
, int flags
)
1618 ASFContext
*asf
= s
->priv_data
;
1621 if (s
->streams
[stream_index
]->nb_index_entries
&& asf
->is_simple_index
) {
1622 idx
= av_index_search_timestamp(s
->streams
[stream_index
], timestamp
, flags
);
1623 if (idx
< 0 || idx
>= s
->streams
[stream_index
]->nb_index_entries
)
1624 return AVERROR_INVALIDDATA
;
1625 avio_seek(s
->pb
, s
->streams
[stream_index
]->index_entries
[idx
].pos
, SEEK_SET
);
1627 if ((ret
= ff_seek_frame_binary(s
, stream_index
, timestamp
, flags
)) < 0)
1631 reset_packet_state(s
);
1636 static const GUIDParseTable
*find_guid(ff_asf_guid guid
)
1639 const GUIDParseTable
*g
;
1643 for (j
= 0; j
< FF_ARRAY_ELEMS(gdef
); j
++) {
1644 if (!(ret
= memcmp(guid
, g
->guid
, sizeof(g
->guid
))))
1652 static int detect_unknown_subobject(AVFormatContext
*s
, int64_t offset
, int64_t size
)
1654 ASFContext
*asf
= s
->priv_data
;
1655 AVIOContext
*pb
= s
->pb
;
1656 const GUIDParseTable
*g
= NULL
;
1660 while (avio_tell(pb
) <= offset
+ size
) {
1661 if (avio_tell(pb
) == asf
->offset
)
1663 asf
->offset
= avio_tell(pb
);
1664 if ((ret
= ff_get_guid(pb
, &guid
)) < 0)
1666 g
= find_guid(guid
);
1668 if ((ret
= g
->read_object(s
, g
)) < 0)
1673 g2
.name
= "Unknown";
1674 g2
.is_subobject
= 1;
1675 asf_read_unknown(s
, &g2
);
1682 static int asf_read_header(AVFormatContext
*s
)
1684 ASFContext
*asf
= s
->priv_data
;
1685 AVIOContext
*pb
= s
->pb
;
1686 const GUIDParseTable
*g
= NULL
;
1692 asf
->is_simple_index
= 0;
1693 ff_get_guid(pb
, &guid
);
1694 if (ff_guidcmp(&guid
, &ff_asf_header
))
1695 return AVERROR_INVALIDDATA
;
1696 avio_skip(pb
, 8); // skip header object size
1697 avio_skip(pb
, 6); // skip number of header objects and 2 reserved bytes
1698 asf
->data_reached
= 0;
1700 /* 1 is here instead of pb->eof_reached because (when not streaming), Data are skipped
1701 * for the first time,
1702 * Index object is processed and got eof and then seeking back to the Data is performed.
1705 // for the cases when object size is invalid
1706 if (avio_tell(pb
) == asf
->offset
)
1708 asf
->offset
= avio_tell(pb
);
1709 if ((ret
= ff_get_guid(pb
, &guid
)) < 0) {
1710 if (ret
== AVERROR_EOF
&& asf
->data_reached
)
1715 g
= find_guid(guid
);
1717 asf
->unknown_offset
= asf
->offset
;
1719 if ((ret
= g
->read_object(s
, g
)) < 0)
1722 size
= avio_rl64(pb
);
1723 align_position(pb
, asf
->offset
, size
);
1725 if (asf
->data_reached
&& (!pb
->seekable
|| (asf
->b_flags
& ASF_FLAG_BROADCAST
)))
1729 if (!asf
->data_reached
) {
1730 av_log(s
, AV_LOG_ERROR
, "Data Object was not found.\n");
1731 ret
= AVERROR_INVALIDDATA
;
1735 avio_seek(pb
, asf
->first_packet_offset
, SEEK_SET
);
1737 for (i
= 0; i
< asf
->nb_streams
; i
++) {
1738 const char *rfc1766
= asf
->asf_sd
[asf
->asf_st
[i
]->lang_idx
].langs
;
1739 AVStream
*st
= s
->streams
[asf
->asf_st
[i
]->index
];
1740 set_language(s
, rfc1766
, &st
->metadata
);
1743 for (i
= 0; i
< ASF_MAX_STREAMS
; i
++) {
1744 AVStream
*st
= NULL
;
1746 st
= find_stream(s
, i
);
1748 av_dict_copy(&st
->metadata
, asf
->asf_sd
[i
].asf_met
, AV_DICT_IGNORE_SUFFIX
);
1749 if (asf
->asf_sd
[i
].aspect_ratio
.num
> 0 && asf
->asf_sd
[i
].aspect_ratio
.den
> 0) {
1750 st
->sample_aspect_ratio
.num
= asf
->asf_sd
[i
].aspect_ratio
.num
;
1751 st
->sample_aspect_ratio
.den
= asf
->asf_sd
[i
].aspect_ratio
.den
;
1763 AVInputFormat ff_asf_demuxer
= {
1765 .long_name
= NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"),
1766 .priv_data_size
= sizeof(ASFContext
),
1767 .read_probe
= asf_probe
,
1768 .read_header
= asf_read_header
,
1769 .read_packet
= asf_read_packet
,
1770 .read_close
= asf_read_close
,
1771 .read_timestamp
= asf_read_timestamp
,
1772 .read_seek
= asf_read_seek
,
1773 .flags
= AVFMT_NOBINSEARCH
| AVFMT_NOGENSEARCH
,