asfenc.c 36 KB
Newer Older
1
/*
2
 * ASF muxer
3
 * Copyright (c) 2000, 2001 Fabrice Bellard
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * 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 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

22
#include "libavutil/avassert.h"
23
#include "libavutil/dict.h"
24
#include "libavutil/mathematics.h"
25
#include "avformat.h"
26
#include "avio_internal.h"
27
#include "internal.h"
28
#include "riff.h"
29 30 31 32 33
#include "asf.h"

#undef NDEBUG
#include <assert.h>

34

35
#define ASF_INDEXED_INTERVAL    10000000
36
#define ASF_INDEX_BLOCK         (1<<9)
37
#define ASF_PAYLOADS_PER_PACKET 63
38

39
#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
40 41 42
#define ASF_PACKET_ERROR_CORRECTION_FLAGS          \
    (ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT |    \
     ASF_PACKET_ERROR_CORRECTION_DATA_SIZE)
43 44 45 46 47 48 49

#if (ASF_PACKET_ERROR_CORRECTION_FLAGS != 0)
#   define ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE 1
#else
#   define ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE 0
#endif

50 51 52 53 54
#define ASF_PPI_PROPERTY_FLAGS                                       \
    (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE           |    \
     ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD |    \
     ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE       |    \
     ASF_PL_FLAG_STREAM_NUMBER_LENGTH_FIELD_IS_BYTE)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

#define ASF_PPI_LENGTH_TYPE_FLAGS 0

#define ASF_PAYLOAD_FLAGS ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD

#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
#   define ASF_PPI_SEQUENCE_FIELD_SIZE 1
#endif
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
#   define ASF_PPI_SEQUENCE_FIELD_SIZE 2
#endif
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
#   define ASF_PPI_SEQUENCE_FIELD_SIZE 4
#endif
#ifndef ASF_PPI_SEQUENCE_FIELD_SIZE
#   define ASF_PPI_SEQUENCE_FIELD_SIZE 0
#endif

#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
#   define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 1
#endif
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
#   define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 2
#endif
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
#   define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 4
#endif
#ifndef ASF_PPI_PACKET_LENGTH_FIELD_SIZE
#   define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 0
#endif

#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
#   define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 1
#endif
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
#   define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 2
#endif
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
#   define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 4
#endif
#ifndef ASF_PPI_PADDING_LENGTH_FIELD_SIZE
#   define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 0
#endif

#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 1
#endif
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 2
#endif
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 4
#endif
#ifndef ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE
#   define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 0
#endif

#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 1
#endif
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 2
#endif
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 4
#endif
#ifndef ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE
#   define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 0
#endif

#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 1
#endif
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 2
#endif
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 4
#endif
#ifndef ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE
#   define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 0
#endif

#if (ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_BYTE == (ASF_PAYLOAD_FLAGS & ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_LENGTH_FIELD_SIZE 1
#endif
#if (ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD == (ASF_PAYLOAD_FLAGS & ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE))
#   define ASF_PAYLOAD_LENGTH_FIELD_SIZE 2
#endif
#ifndef ASF_PAYLOAD_LENGTH_FIELD_SIZE
#   define ASF_PAYLOAD_LENGTH_FIELD_SIZE 0
#endif

148 149 150 151 152 153 154 155 156 157
#define PACKET_HEADER_MIN_SIZE \
    (ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE +       \
     ASF_PACKET_ERROR_CORRECTION_DATA_SIZE +              \
     1 +        /* Length Type Flags */                   \
     1 +        /* Property Flags */                      \
     ASF_PPI_PACKET_LENGTH_FIELD_SIZE +                   \
     ASF_PPI_SEQUENCE_FIELD_SIZE +                        \
     ASF_PPI_PADDING_LENGTH_FIELD_SIZE +                  \
     4 +        /* Send Time Field */                     \
     2)         /* Duration Field */
158 159 160 161

// Replicated Data shall be at least 8 bytes long.
#define ASF_PAYLOAD_REPLICATED_DATA_LENGTH 0x08

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
#define PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD                \
    (1 +     /* Stream Number */                          \
     ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE +         \
     ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE +    \
     ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE +      \
     ASF_PAYLOAD_REPLICATED_DATA_LENGTH)

#define PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS             \
    (1 +        /* Stream Number */                       \
     ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE +         \
     ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE +    \
     ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE +      \
     ASF_PAYLOAD_REPLICATED_DATA_LENGTH +                 \
     ASF_PAYLOAD_LENGTH_FIELD_SIZE)

#define SINGLE_PAYLOAD_DATA_LENGTH                        \
    (PACKET_SIZE -                                        \
     PACKET_HEADER_MIN_SIZE -                             \
     PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD)

#define MULTI_PAYLOAD_CONSTANT                            \
    (PACKET_SIZE -                                        \
     PACKET_HEADER_MIN_SIZE -                             \
     1 -         /* Payload Flags */                      \
     2 * PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS)
187

188 189
#define DATA_HEADER_SIZE 50

190 191 192 193 194 195 196 197 198 199
typedef struct {
    uint32_t seqno;
    int is_streamed;
    ASFStream streams[128];              ///< it's max number and it's not that big
    /* non streamed additonnal info */
    uint64_t nb_packets;                 ///< how many packets are there in the file, invalid if broadcasting
    int64_t duration;                    ///< in 100ns units
    /* packet filling */
    unsigned char multi_payloads_present;
    int packet_size_left;
200 201
    int64_t packet_timestamp_start;
    int64_t packet_timestamp_end;
202 203
    unsigned int packet_nb_payloads;
    uint8_t packet_buf[PACKET_SIZE];
204
    AVIOContext pb;
205 206 207
    /* only for reading */
    uint64_t data_offset;                ///< beginning of the first data packet

208
    ASFIndex *index_ptr;
209 210
    uint32_t nb_index_memory_alloc;
    uint16_t maximum_packet;
211 212
    uint32_t next_packet_number;
    uint16_t next_packet_count;
213
    uint64_t next_packet_offset;
214 215
    int      next_start_sec;
    int      end_sec;
216 217
} ASFContext;

218
static const AVCodecTag codec_asf_bmp_tags[] = {
219
    { AV_CODEC_ID_MPEG4,     MKTAG('M', '4', 'S', '2') },
220
    { AV_CODEC_ID_MPEG4,     MKTAG('M', 'P', '4', 'S') },
221
    { AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
222
    { AV_CODEC_ID_NONE,      0 },
223 224
};

225
#define PREROLL_TIME 3100
226

227
static void put_str16(AVIOContext *s, const char *tag)
228 229 230
{
    int len;
    uint8_t *pb;
231
    AVIOContext *dyn_buf;
232
    if (avio_open_dyn_buf(&dyn_buf) < 0)
233 234
        return;

235
    avio_put_str16le(dyn_buf, tag);
236
    len = avio_close_dyn_buf(dyn_buf, &pb);
237 238
    avio_wl16(s, len);
    avio_write(s, pb, len);
239
    av_freep(&pb);
240 241
}

242
static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g)
243 244 245
{
    int64_t pos;

246
    pos = avio_tell(pb);
247
    ff_put_guid(pb, g);
248
    avio_wl64(pb, 24);
249 250 251 252
    return pos;
}

/* update header size */
253
static void end_header(AVIOContext *pb, int64_t pos)
254 255 256
{
    int64_t pos1;

257
    pos1 = avio_tell(pb);
258
    avio_seek(pb, pos + 16, SEEK_SET);
259
    avio_wl64(pb, pos1 - pos);
260
    avio_seek(pb, pos1, SEEK_SET);
261 262 263
}

/* write an asf chunk (only used in streaming case) */
264 265
static void put_chunk(AVFormatContext *s, int type,
                      int payload_length, int flags)
266 267
{
    ASFContext *asf = s->priv_data;
268
    AVIOContext *pb = s->pb;
269 270 271
    int length;

    length = payload_length + 8;
272
    avio_wl16(pb, type);
273 274 275 276
    avio_wl16(pb, length);      // size
    avio_wl32(pb, asf->seqno);  // sequence number
    avio_wl16(pb, flags);       // unknown bytes
    avio_wl16(pb, length);      // size_confirm
277 278 279 280 281 282 283 284
    asf->seqno++;
}

/* convert from unix to windows time */
static int64_t unix_to_file_time(int ti)
{
    int64_t t;

285
    t  = ti * INT64_C(10000000);
286
    t += INT64_C(116444736000000000);
287 288 289
    return t;
}

290 291 292 293 294
static int32_t get_send_time(ASFContext *asf, int64_t pres_time, uint64_t *offset)
{
    int i;
    int32_t send_time = 0;
    *offset = asf->data_offset + DATA_HEADER_SIZE;
295
    for (i = 0; i < asf->next_start_sec; i++) {
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
        if (pres_time <= asf->index_ptr[i].send_time)
            break;
        send_time = asf->index_ptr[i].send_time;
        *offset   = asf->index_ptr[i].offset;
    }

    return send_time / 10000;
}

static int asf_write_markers(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
    AVIOContext *pb = s->pb;
    int i;
    AVRational scale = {1, 10000000};
    int64_t hpos = put_header(pb, &ff_asf_marker_header);

313
    ff_put_guid(pb, &ff_asf_reserved_4);// ASF spec mandates this reserved value
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
    avio_wl32(pb, s->nb_chapters);     // markers count
    avio_wl16(pb, 0);                  // ASF spec mandates 0 for this
    avio_wl16(pb, 0);                  // name length 0, no name given

    for (i = 0; i < s->nb_chapters; i++) {
        AVChapter *c = s->chapters[i];
        AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
        int64_t pres_time = av_rescale_q(c->start, c->time_base, scale);
        uint64_t offset;
        int32_t send_time = get_send_time(asf, pres_time, &offset);
        int len = 0;
        uint8_t *buf;
        AVIOContext *dyn_buf;
        if (t) {
            if (avio_open_dyn_buf(&dyn_buf) < 0)
                return AVERROR(ENOMEM);
            avio_put_str16le(dyn_buf, t->value);
            len = avio_close_dyn_buf(dyn_buf, &buf);
        }
        avio_wl64(pb, offset);            // offset of the packet with send_time
        avio_wl64(pb, pres_time + PREROLL_TIME * 10000); // presentation time
        avio_wl16(pb, 12 + len);          // entry length
        avio_wl32(pb, send_time);         // send time
        avio_wl32(pb, 0);                 // flags, should be 0
        avio_wl32(pb, len / 2);           // marker desc length in WCHARS!
        if (t) {
            avio_write(pb, buf, len);     // marker desc
            av_freep(&buf);
        }
    }
    end_header(pb, hpos);
    return 0;
}

348
/* write the header (used two times if non streamed) */
349 350
static int asf_write_header1(AVFormatContext *s, int64_t file_size,
                             int64_t data_chunk_size)
351 352
{
    ASFContext *asf = s->priv_data;
353
    AVIOContext *pb = s->pb;
354
    AVDictionaryEntry *tags[5];
355
    int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
356
    int has_title, has_aspect_ratio = 0;
357
    int metadata_count;
358 359 360
    AVCodecContext *enc;
    int64_t header_offset, cur_pos, hpos;
    int bit_rate;
361
    int64_t duration;
362

363
    ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
364

365 366
    tags[0] = av_dict_get(s->metadata, "title", NULL, 0);
    tags[1] = av_dict_get(s->metadata, "author", NULL, 0);
367
    tags[2] = av_dict_get(s->metadata, "copyright", NULL, 0);
368 369
    tags[3] = av_dict_get(s->metadata, "comment", NULL, 0);
    tags[4] = av_dict_get(s->metadata, "rating", NULL, 0);
370

371 372
    duration       = asf->duration + PREROLL_TIME * 10000;
    has_title      = tags[0] || tags[1] || tags[2] || tags[3] || tags[4];
373
    metadata_count = av_dict_count(s->metadata);
374 375

    bit_rate = 0;
376
    for (n = 0; n < s->nb_streams; n++) {
377
        enc = s->streams[n]->codec;
378

379
        avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */
380

381
        bit_rate += enc->bit_rate;
382 383 384 385
        if (   enc->codec_type == AVMEDIA_TYPE_VIDEO
            && enc->sample_aspect_ratio.num > 0
            && enc->sample_aspect_ratio.den > 0)
            has_aspect_ratio++;
386 387 388 389 390 391
    }

    if (asf->is_streamed) {
        put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
    }

392
    ff_put_guid(pb, &ff_asf_header);
393 394 395 396
    avio_wl64(pb, -1); /* header length, will be patched after */
    avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */
    avio_w8(pb, 1); /* ??? */
    avio_w8(pb, 2); /* ??? */
397 398

    /* file header */
399
    header_offset = avio_tell(pb);
400
    hpos          = put_header(pb, &ff_asf_file_header);
401
    ff_put_guid(pb, &ff_asf_my_guid);
402
    avio_wl64(pb, file_size);
403
    file_time = 0;
404 405 406 407 408
    avio_wl64(pb, unix_to_file_time(file_time));
    avio_wl64(pb, asf->nb_packets); /* number of packets */
    avio_wl64(pb, duration); /* end time stamp (in 100ns units) */
    avio_wl64(pb, asf->duration); /* duration (in 100ns units) */
    avio_wl64(pb, PREROLL_TIME); /* start time stamp */
409
    avio_wl32(pb, (asf->is_streamed || !pb->seekable) ? 3 : 2);  /* ??? */
410 411
    avio_wl32(pb, s->packet_size); /* packet size */
    avio_wl32(pb, s->packet_size); /* packet size */
412
    avio_wl32(pb, bit_rate ? bit_rate : -1); /* Maximum data rate in bps */
413 414 415
    end_header(pb, hpos);

    /* unknown headers */
416
    hpos = put_header(pb, &ff_asf_head1_guid);
417
    ff_put_guid(pb, &ff_asf_head2_guid);
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
    avio_wl16(pb, 6);
    if (has_aspect_ratio) {
        int64_t hpos2;
        avio_wl32(pb, 26 + has_aspect_ratio * 84);
        hpos2 = put_header(pb, &ff_asf_metadata_header);
        avio_wl16(pb, 2 * has_aspect_ratio);
        for (n = 0; n < s->nb_streams; n++) {
            enc = s->streams[n]->codec;
            if (   enc->codec_type == AVMEDIA_TYPE_VIDEO
                && enc->sample_aspect_ratio.num > 0
                && enc->sample_aspect_ratio.den > 0) {
                AVRational sar = enc->sample_aspect_ratio;
                avio_wl16(pb, 0);
                // the stream number is set like this below
                avio_wl16(pb, n + 1);
                avio_wl16(pb, 26); // name_len
                avio_wl16(pb,  3); // value_type
                avio_wl32(pb,  4); // value_len
                avio_put_str16le(pb, "AspectRatioX");
                avio_wl32(pb, sar.num);
                avio_wl16(pb, 0);
                // the stream number is set like this below
                avio_wl16(pb, n + 1);
                avio_wl16(pb, 26); // name_len
                avio_wl16(pb,  3); // value_type
                avio_wl32(pb,  4); // value_len
                avio_put_str16le(pb, "AspectRatioY");
                avio_wl32(pb, sar.den);
            }
        }
        end_header(pb, hpos2);
    } else {
        avio_wl32(pb, 0);
    }
452 453 454 455
    end_header(pb, hpos);

    /* title and other infos */
    if (has_title) {
456 457
        int len;
        uint8_t *buf;
458
        AVIOContext *dyn_buf;
459

460
        if (avio_open_dyn_buf(&dyn_buf) < 0)
461 462
            return AVERROR(ENOMEM);

463
        hpos = put_header(pb, &ff_asf_comment_header);
464 465

        for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) {
466
            len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0;
467
            avio_wl16(pb, len);
468
        }
469
        len = avio_close_dyn_buf(dyn_buf, &buf);
470
        avio_write(pb, buf, len);
471
        av_freep(&buf);
472 473
        end_header(pb, hpos);
    }
474
    if (metadata_count) {
475
        AVDictionaryEntry *tag = NULL;
476
        hpos = put_header(pb, &ff_asf_extended_content_header);
477
        avio_wl16(pb, metadata_count);
478
        while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
479
            put_str16(pb, tag->key);
480
            avio_wl16(pb, 0);
481
            put_str16(pb, tag->value);
482 483 484
        }
        end_header(pb, hpos);
    }
485 486 487 488 489 490
    /* chapters using ASF markers */
    if (!asf->is_streamed && s->nb_chapters) {
        int ret;
        if (ret = asf_write_markers(s))
            return ret;
    }
491
    /* stream headers */
492
    for (n = 0; n < s->nb_streams; n++) {
493 494 495
        int64_t es_pos;
        //        ASFStream *stream = &asf->streams[n];

496
        enc                 = s->streams[n]->codec;
497
        asf->streams[n].num = n + 1;
498
        asf->streams[n].seq = 1;
499

500
        switch (enc->codec_type) {
501
        case AVMEDIA_TYPE_AUDIO:
502
            wav_extra_size = 0;
503 504
            extra_size     = 18 + wav_extra_size;
            extra_size2    = 8;
505 506
            break;
        default:
507
        case AVMEDIA_TYPE_VIDEO:
508
            wav_extra_size = enc->extradata_size;
509 510
            extra_size     = 0x33 + wav_extra_size;
            extra_size2    = 0;
511 512 513
            break;
        }

514
        hpos = put_header(pb, &ff_asf_stream_header);
515
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
516 517
            ff_put_guid(pb, &ff_asf_audio_stream);
            ff_put_guid(pb, &ff_asf_audio_conceal_spread);
518
        } else {
519 520
            ff_put_guid(pb, &ff_asf_video_stream);
            ff_put_guid(pb, &ff_asf_video_conceal_none);
521
        }
522
        avio_wl64(pb, 0); /* ??? */
523
        es_pos = avio_tell(pb);
524 525 526 527
        avio_wl32(pb, extra_size); /* wav header len */
        avio_wl32(pb, extra_size2); /* additional data len */
        avio_wl16(pb, n + 1); /* stream number */
        avio_wl32(pb, 0); /* ??? */
528

529
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
530
            /* WAVEFORMATEX header */
531
            int wavsize = ff_put_wav_header(pb, enc, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX);
532 533 534 535

            if (wavsize < 0)
                return -1;
            if (wavsize != extra_size) {
536
                cur_pos = avio_tell(pb);
537
                avio_seek(pb, es_pos, SEEK_SET);
538
                avio_wl32(pb, wavsize); /* wav header len */
539
                avio_seek(pb, cur_pos, SEEK_SET);
540
            }
541
            /* ERROR Correction */
542
            avio_w8(pb, 0x01);
543
            if (enc->codec_id == AV_CODEC_ID_ADPCM_G726 || !enc->block_align) {
544 545
                avio_wl16(pb, 0x0190);
                avio_wl16(pb, 0x0190);
546
            } else {
547 548
                avio_wl16(pb, enc->block_align);
                avio_wl16(pb, enc->block_align);
549
            }
550 551
            avio_wl16(pb, 0x01);
            avio_w8(pb, 0x00);
552
        } else {
553 554 555 556
            avio_wl32(pb, enc->width);
            avio_wl32(pb, enc->height);
            avio_w8(pb, 2); /* ??? */
            avio_wl16(pb, 40 + enc->extradata_size); /* size */
557 558

            /* BITMAPINFOHEADER header */
559
            ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1, 0);
560 561 562 563 564 565
        }
        end_header(pb, hpos);
    }

    /* media comments */

566
    hpos = put_header(pb, &ff_asf_codec_comment_header);
567
    ff_put_guid(pb, &ff_asf_codec_comment1_header);
568
    avio_wl32(pb, s->nb_streams);
569
    for (n = 0; n < s->nb_streams; n++) {
570
        const AVCodecDescriptor *codec_desc;
Anton Khirnov's avatar
Anton Khirnov committed
571
        const char *desc;
572

573 574
        enc  = s->streams[n]->codec;
        codec_desc = avcodec_descriptor_get(enc->codec_id);
575

576
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
577
            avio_wl16(pb, 2);
578
        else if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
579
            avio_wl16(pb, 1);
580
        else
581
            avio_wl16(pb, -1);
582

583
        if (enc->codec_id == AV_CODEC_ID_WMAV2)
Anton Khirnov's avatar
Anton Khirnov committed
584
            desc = "Windows Media Audio V8";
585
        else
586
            desc = codec_desc ? codec_desc->name : NULL;
587

588 589 590 591
        if (desc) {
            AVIOContext *dyn_buf;
            uint8_t *buf;
            int len;
592

593 594
            if (avio_open_dyn_buf(&dyn_buf) < 0)
                return AVERROR(ENOMEM);
595

596 597 598 599 600 601 602 603
            avio_put_str16le(dyn_buf, desc);
            len = avio_close_dyn_buf(dyn_buf, &buf);
            avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2

            avio_write(pb, buf, len);
            av_freep(&buf);
        } else
            avio_wl16(pb, 0);
604

605
        avio_wl16(pb, 0); /* no parameters */
606

607
        /* id */
608
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
609 610
            avio_wl16(pb, 2);
            avio_wl16(pb, enc->codec_tag);
611
        } else {
612 613
            avio_wl16(pb, 4);
            avio_wl32(pb, enc->codec_tag);
614
        }
615
        if (!enc->codec_tag)
Michael Niedermayer's avatar
Michael Niedermayer committed
616
            return -1;
617 618 619 620 621
    }
    end_header(pb, hpos);

    /* patch the header size fields */

622
    cur_pos     = avio_tell(pb);
623 624
    header_size = cur_pos - header_offset;
    if (asf->is_streamed) {
625
        header_size += 8 + 30 + DATA_HEADER_SIZE;
626

627
        avio_seek(pb, header_offset - 10 - 30, SEEK_SET);
628
        avio_wl16(pb, header_size);
629
        avio_seek(pb, header_offset - 2 - 30, SEEK_SET);
630
        avio_wl16(pb, header_size);
631

632
        header_size -= 8 + 30 + DATA_HEADER_SIZE;
633 634
    }
    header_size += 24 + 6;
635
    avio_seek(pb, header_offset - 14, SEEK_SET);
636
    avio_wl64(pb, header_size);
637
    avio_seek(pb, cur_pos, SEEK_SET);
638 639 640

    /* movie chunk, followed by packets of packet_size */
    asf->data_offset = cur_pos;
641
    ff_put_guid(pb, &ff_asf_data_header);
642
    avio_wl64(pb, data_chunk_size);
643
    ff_put_guid(pb, &ff_asf_my_guid);
644 645 646
    avio_wl64(pb, asf->nb_packets); /* nb packets */
    avio_w8(pb, 1); /* ??? */
    avio_w8(pb, 1); /* ??? */
647 648 649 650 651 652 653
    return 0;
}

static int asf_write_header(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;

654
    s->packet_size  = PACKET_SIZE;
655
    s->max_interleave_delta = 0;
656
    asf->nb_packets = 0;
657

658
    asf->index_ptr             = av_malloc(sizeof(ASFIndex) * ASF_INDEX_BLOCK);
659
    asf->nb_index_memory_alloc = ASF_INDEX_BLOCK;
660
    asf->maximum_packet        = 0;
661

662 663 664 665
    /* the data-chunk-size has to be 50 (DATA_HEADER_SIZE), which is
     * data_size - asf->data_offset at the moment this function is done.
     * It is needed to use asf as a streamable format. */
    if (asf_write_header1(s, 0, DATA_HEADER_SIZE) < 0) {
666 667 668 669
        //av_free(asf);
        return -1;
    }

670
    avio_flush(s->pb);
671

672
    asf->packet_nb_payloads     = 0;
673
    asf->packet_timestamp_start = -1;
674
    asf->packet_timestamp_end   = -1;
675
    ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
676
                      NULL, NULL, NULL, NULL);
677

678 679 680
    if (s->avoid_negative_ts < 0)
        s->avoid_negative_ts = 1;

681 682 683 684 685 686 687 688 689 690 691 692
    return 0;
}

static int asf_write_stream_header(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;

    asf->is_streamed = 1;

    return asf_write_header(s);
}

693 694 695
static int put_payload_parsing_info(AVFormatContext *s,
                                    unsigned sendtime, unsigned duration,
                                    int nb_payloads, int padsize)
696 697
{
    ASFContext *asf = s->priv_data;
698
    AVIOContext *pb = s->pb;
699
    int ppi_size, i;
700
    int64_t start = avio_tell(pb);
701 702

    int iLengthTypeFlags = ASF_PPI_LENGTH_TYPE_FLAGS;
703

704
    padsize -= PACKET_HEADER_MIN_SIZE;
705
    if (asf->multi_payloads_present)
706
        padsize--;
707
    av_assert0(padsize >= 0);
708

709
    avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS);
710
    for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++)
711
        avio_w8(pb, 0x0);
712

713 714
    if (asf->multi_payloads_present)
        iLengthTypeFlags |= ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT;
715 716 717

    if (padsize > 0) {
        if (padsize < 256)
718
            iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE;
719
        else
720
            iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD;
721
    }
722
    avio_w8(pb, iLengthTypeFlags);
723

724
    avio_w8(pb, ASF_PPI_PROPERTY_FLAGS);
725 726

    if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD)
727
        avio_wl16(pb, padsize - 2);
728
    if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE)
729
        avio_w8(pb, padsize - 1);
730

731 732
    avio_wl32(pb, sendtime);
    avio_wl16(pb, duration);
733
    if (asf->multi_payloads_present)
734
        avio_w8(pb, nb_payloads | ASF_PAYLOAD_FLAGS);
735

736
    ppi_size = avio_tell(pb) - start;
737

738
    return ppi_size;
739 740 741 742 743
}

static void flush_packet(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
744
    int packet_hdr_size, packet_filled_size;
745

746
    av_assert0(asf->packet_timestamp_end >= asf->packet_timestamp_start);
747

748
    if (asf->is_streamed)
749
        put_chunk(s, 0x4424, s->packet_size, 0);
750

751 752
    packet_hdr_size = put_payload_parsing_info(s,
                                               asf->packet_timestamp_start,
753
                                               asf->packet_timestamp_end - asf->packet_timestamp_start,
754 755
                                               asf->packet_nb_payloads,
                                               asf->packet_size_left);
756

757
    packet_filled_size = PACKET_SIZE - asf->packet_size_left;
758
    av_assert0(packet_hdr_size <= asf->packet_size_left);
759
    memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
760

761
    avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size);
762

763
    avio_flush(s->pb);
764
    asf->nb_packets++;
765
    asf->packet_nb_payloads     = 0;
766
    asf->packet_timestamp_start = -1;
767
    asf->packet_timestamp_end   = -1;
768
    ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
769
                      NULL, NULL, NULL, NULL);
770 771
}

772
static void put_payload_header(AVFormatContext *s, ASFStream *stream,
773
                               int64_t presentation_time, int m_obj_size,
774
                               int m_obj_offset, int payload_len, int flags)
775 776
{
    ASFContext *asf = s->priv_data;
777
    AVIOContext *pb = &asf->pb;
778
    int val;
779

780
    val = stream->num;
781
    if (flags & AV_PKT_FLAG_KEY)
782
        val |= ASF_PL_FLAG_KEY_FRAME;
783
    avio_w8(pb, val);
784

785 786
    avio_w8(pb, stream->seq);     // Media object number
    avio_wl32(pb, m_obj_offset);  // Offset Into Media Object
787

788
    // Replicated Data shall be at least 8 bytes long.
789
    // The first 4 bytes of data shall contain the
790
    // Size of the Media Object that the payload belongs to.
791
    // The next 4 bytes of data shall contain the
792
    // Presentation Time for the media object that the payload belongs to.
793
    avio_w8(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH);
794

795
    avio_wl32(pb, m_obj_size);        // Replicated Data - Media Object Size
796
    avio_wl32(pb, (uint32_t) presentation_time); // Replicated Data - Presentation Time
797

798 799
    if (asf->multi_payloads_present) {
        avio_wl16(pb, payload_len);   // payload length
800
    }
801 802
}

803
static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
804
                      int64_t timestamp, const uint8_t *buf,
805
                      int m_obj_size, int flags)
806 807
{
    ASFContext *asf = s->priv_data;
808 809 810 811 812 813 814
    int m_obj_offset, payload_len, frag_len1;

    m_obj_offset = 0;
    while (m_obj_offset < m_obj_size) {
        payload_len = m_obj_size - m_obj_offset;
        if (asf->packet_timestamp_start == -1) {
            asf->multi_payloads_present = (payload_len < MULTI_PAYLOAD_CONSTANT);
815

816
            asf->packet_size_left = PACKET_SIZE;
817
            if (asf->multi_payloads_present) {
818
                frag_len1 = MULTI_PAYLOAD_CONSTANT - 1;
819
            } else {
820 821
                frag_len1 = SINGLE_PAYLOAD_DATA_LENGTH;
            }
822
            asf->packet_timestamp_start = timestamp;
823
        } else {
824
            // multi payloads
825 826 827
            frag_len1 = asf->packet_size_left -
                        PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS -
                        PACKET_HEADER_MIN_SIZE - 1;
828

829 830
            if (frag_len1 < payload_len &&
                avst->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
831 832 833
                flush_packet(s);
                continue;
            }
834
        }
835
        if (frag_len1 > 0) {
836 837 838
            if (payload_len > frag_len1)
                payload_len = frag_len1;
            else if (payload_len == (frag_len1 - 1))
839
                payload_len = frag_len1 - 2;  // additional byte need to put padding length
840

841 842
            put_payload_header(s, stream, timestamp + PREROLL_TIME,
                               m_obj_size, m_obj_offset, payload_len, flags);
843
            avio_write(&asf->pb, buf, payload_len);
844 845 846 847 848

            if (asf->multi_payloads_present)
                asf->packet_size_left -= (payload_len + PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS);
            else
                asf->packet_size_left -= (payload_len + PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD);
849
            asf->packet_timestamp_end = timestamp;
850

851
            asf->packet_nb_payloads++;
852
        } else {
853
            payload_len = 0;
854
        }
855
        m_obj_offset += payload_len;
856
        buf          += payload_len;
857 858 859

        if (!asf->multi_payloads_present)
            flush_packet(s);
860
        else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1))
861
            flush_packet(s);
862 863
        else if (asf->packet_nb_payloads == ASF_PAYLOADS_PER_PACKET)
            flush_packet(s);
864 865 866 867
    }
    stream->seq++;
}

868
static int update_index(AVFormatContext *s, int start_sec,
869 870
                         uint32_t packet_number, uint16_t packet_count,
                         uint64_t packet_offset)
871 872 873 874 875 876 877 878 879
{
    ASFContext *asf = s->priv_data;

    if (start_sec > asf->next_start_sec) {
        int i;

        if (!asf->next_start_sec) {
            asf->next_packet_number = packet_number;
            asf->next_packet_count  = packet_count;
880
            asf->next_packet_offset = packet_offset;
881 882 883
        }

        if (start_sec > asf->nb_index_memory_alloc) {
884
            int err;
885
            asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1);
886 887 888 889 890 891
            if ((err = av_reallocp_array(&asf->index_ptr,
                                         asf->nb_index_memory_alloc,
                                         sizeof(*asf->index_ptr))) < 0) {
                asf->nb_index_memory_alloc = 0;
                return err;
            }
892 893 894 895
        }
        for (i = asf->next_start_sec; i < start_sec; i++) {
            asf->index_ptr[i].packet_number = asf->next_packet_number;
            asf->index_ptr[i].packet_count  = asf->next_packet_count;
896 897 898
            asf->index_ptr[i].send_time     = asf->next_start_sec * INT64_C(10000000);
            asf->index_ptr[i].offset        = asf->next_packet_offset;

899 900 901 902 903
        }
    }
    asf->maximum_packet     = FFMAX(asf->maximum_packet, packet_count);
    asf->next_packet_number = packet_number;
    asf->next_packet_count  = packet_count;
904
    asf->next_packet_offset = packet_offset;
905
    asf->next_start_sec     = start_sec;
906 907

    return 0;
908 909
}

910
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
911 912
{
    ASFContext *asf = s->priv_data;
913
    AVIOContext *pb = s->pb;
914 915
    ASFStream *stream;
    AVCodecContext *codec;
916 917
    uint32_t packet_number;
    int64_t pts;
918
    int start_sec;
919
    int flags = pkt->flags;
920
    int ret;
921
    uint64_t offset = avio_tell(pb);
922

923
    codec  = s->streams[pkt->stream_index]->codec;
924
    stream = &asf->streams[pkt->stream_index];
925

926
    if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
927
        flags &= ~AV_PKT_FLAG_KEY;
928

929
    pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts;
930
    av_assert0(pts != AV_NOPTS_VALUE);
931
    pts *= 10000;
932
    asf->duration = FFMAX(asf->duration, pts + pkt->duration * 10000);
933

934
    packet_number = asf->nb_packets;
935 936
    put_frame(s, stream, s->streams[pkt->stream_index],
              pkt->dts, pkt->data, pkt->size, flags);
937

938 939 940
    start_sec = (int)((PREROLL_TIME * 10000 + pts + ASF_INDEXED_INTERVAL - 1)
              / ASF_INDEXED_INTERVAL);

941
    /* check index */
942
    if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
943
        uint16_t packet_count = asf->nb_packets - packet_number;
944 945
        ret = update_index(s, start_sec, packet_number, packet_count, offset);
        if (ret < 0)
946
            return ret;
947
    }
948 949
    asf->end_sec = start_sec;

950 951 952
    return 0;
}

953
static int asf_write_index(AVFormatContext *s, const ASFIndex *index,
954
                           uint16_t max, uint32_t count)
955
{
956
    AVIOContext *pb = s->pb;
957 958
    int i;

959
    ff_put_guid(pb, &ff_asf_simple_index_header);
960
    avio_wl64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2) * count);
961
    ff_put_guid(pb, &ff_asf_my_guid);
962 963 964
    avio_wl64(pb, ASF_INDEXED_INTERVAL);
    avio_wl32(pb, max);
    avio_wl32(pb, count);
965
    for (i = 0; i < count; i++) {
966 967
        avio_wl32(pb, index[i].packet_number);
        avio_wl16(pb, index[i].packet_count);
968 969
    }

970 971 972 973 974 975
    return 0;
}

static int asf_write_trailer(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
976
    int64_t file_size, data_size;
977
    int ret;
978 979 980 981 982

    /* flush the current packet */
    if (asf->pb.buf_ptr > asf->pb.buffer)
        flush_packet(s);

983
    /* write index */
984
    data_size = avio_tell(s->pb);
985
    if (!asf->is_streamed && asf->next_start_sec) {
986
        if ((ret = update_index(s, asf->end_sec + 1, 0, 0, 0)) < 0)
987
            return ret;
988
        asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->next_start_sec);
989
    }
990
    avio_flush(s->pb);
991

992
    if (asf->is_streamed || !s->pb->seekable) {
993 994 995
        put_chunk(s, 0x4524, 0, 0); /* end of stream */
    } else {
        /* rewrite an updated header */
996
        file_size = avio_tell(s->pb);
997
        avio_seek(s->pb, 0, SEEK_SET);
998
        asf_write_header1(s, file_size, data_size - asf->data_offset);
999 1000
    }

1001
    av_freep(&asf->index_ptr);
1002 1003 1004
    return 0;
}

1005
#if CONFIG_ASF_MUXER
1006
AVOutputFormat ff_asf_muxer = {
1007
    .name           = "asf",
1008
    .long_name      = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"),
1009 1010 1011
    .mime_type      = "video/x-ms-asf",
    .extensions     = "asf,wmv,wma",
    .priv_data_size = sizeof(ASFContext),
1012
    .audio_codec    = AV_CODEC_ID_WMAV2,
1013
    .video_codec    = AV_CODEC_ID_MSMPEG4V3,
1014 1015 1016
    .write_header   = asf_write_header,
    .write_packet   = asf_write_packet,
    .write_trailer  = asf_write_trailer,
1017
    .flags          = AVFMT_GLOBALHEADER,
1018
    .codec_tag      = (const AVCodecTag * const []) {
1019 1020
        codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0
    },
1021
};
1022
#endif /* CONFIG_ASF_MUXER */
1023

1024
#if CONFIG_ASF_STREAM_MUXER
1025
AVOutputFormat ff_asf_stream_muxer = {
1026
    .name           = "asf_stream",
1027
    .long_name      = NULL_IF_CONFIG_SMALL("ASF (Advanced / Active Streaming Format)"),
1028 1029 1030
    .mime_type      = "video/x-ms-asf",
    .extensions     = "asf,wmv,wma",
    .priv_data_size = sizeof(ASFContext),
1031
    .audio_codec    = AV_CODEC_ID_WMAV2,
1032
    .video_codec    = AV_CODEC_ID_MSMPEG4V3,
1033 1034 1035
    .write_header   = asf_write_stream_header,
    .write_packet   = asf_write_packet,
    .write_trailer  = asf_write_trailer,
1036
    .flags          = AVFMT_GLOBALHEADER,
1037
    .codec_tag      = (const AVCodecTag * const []) {
1038 1039
        codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0
    },
1040
};
1041
#endif /* CONFIG_ASF_STREAM_MUXER */