asfenc.c 30.5 KB
Newer Older
1
/*
2
 * ASF muxer
3
 * Copyright (c) 2000, 2001 Fabrice Bellard
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 21
 */
#include "avformat.h"
22
#include "internal.h"
23
#include "riff.h"
24
#include "asf.h"
25
#include "avio_internal.h"
26
#include "libavutil/dict.h"
27 28 29 30

#undef NDEBUG
#include <assert.h>

31

32 33
#define ASF_INDEXED_INTERVAL    10000000
#define ASF_INDEX_BLOCK         600
34

35 36
#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
#define ASF_PACKET_ERROR_CORRECTION_FLAGS (\
37 38 39
                ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT | \
                ASF_PACKET_ERROR_CORRECTION_DATA_SIZE\
                )
40 41 42 43 44 45 46 47

#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

#define ASF_PPI_PROPERTY_FLAGS (\
48 49 50 51 52
                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 \
                )
53 54 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

#define PACKET_HEADER_MIN_SIZE (\
148 149 150 151 152 153 154 155 156 157
                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 162 163


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

#define PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD (\
164 165 166 167 168 169
                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 \
                )
170

171
#define PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS (\
172 173 174 175 176 177 178
                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 \
                )
179 180

#define SINGLE_PAYLOAD_DATA_LENGTH (\
181 182 183 184
                PACKET_SIZE - \
                PACKET_HEADER_MIN_SIZE - \
                PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD \
                )
185 186

#define MULTI_PAYLOAD_CONSTANT (\
187 188 189 190 191
                PACKET_SIZE - \
                PACKET_HEADER_MIN_SIZE - \
                1 - /*Payload Flags*/ \
                2*PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS \
                )
192

193 194 195 196 197 198 199 200 201 202 203 204 205 206
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;
    int packet_timestamp_start;
    int packet_timestamp_end;
    unsigned int packet_nb_payloads;
    uint8_t packet_buf[PACKET_SIZE];
207
    AVIOContext pb;
208 209 210 211 212 213 214 215 216 217
    /* only for reading */
    uint64_t data_offset;                ///< beginning of the first data packet

    int64_t last_indexed_pts;
    ASFIndex* index_ptr;
    uint32_t nb_index_count;
    uint32_t nb_index_memory_alloc;
    uint16_t maximum_packet;
} ASFContext;

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

225
#define PREROLL_TIME 3100
226

227
static void put_guid(AVIOContext *s, const ff_asf_guid *g)
228
{
Michael Niedermayer's avatar
Michael Niedermayer committed
229
    assert(sizeof(*g) == 16);
230
    avio_write(s, *g, sizeof(*g));
231 232
}

233
static void put_str16(AVIOContext *s, const char *tag)
234 235 236
{
    int len;
    uint8_t *pb;
237
    AVIOContext *dyn_buf;
238
    if (avio_open_dyn_buf(&dyn_buf) < 0)
239 240
        return;

241
    avio_put_str16le(dyn_buf, tag);
242
    len = avio_close_dyn_buf(dyn_buf, &pb);
243 244
    avio_wl16(s, len);
    avio_write(s, pb, len);
245
    av_freep(&pb);
246 247
}

248
static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g)
249 250 251
{
    int64_t pos;

252
    pos = avio_tell(pb);
253
    put_guid(pb, g);
254
    avio_wl64(pb, 24);
255 256 257 258
    return pos;
}

/* update header size */
259
static void end_header(AVIOContext *pb, int64_t pos)
260 261 262
{
    int64_t pos1;

263
    pos1 = avio_tell(pb);
264
    avio_seek(pb, pos + 16, SEEK_SET);
265
    avio_wl64(pb, pos1 - pos);
266
    avio_seek(pb, pos1, SEEK_SET);
267 268 269 270 271 272
}

/* write an asf chunk (only used in streaming case) */
static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags)
{
    ASFContext *asf = s->priv_data;
273
    AVIOContext *pb = s->pb;
274 275 276
    int length;

    length = payload_length + 8;
277 278 279 280 281
    avio_wl16(pb, type);
    avio_wl16(pb, length);    //size
    avio_wl32(pb, asf->seqno);//sequence number
    avio_wl16(pb, flags); /* unknown bytes */
    avio_wl16(pb, length);    //size_confirm
282 283 284 285 286 287 288 289
    asf->seqno++;
}

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

290 291
    t = ti * INT64_C(10000000);
    t += INT64_C(116444736000000000);
292 293 294 295 296 297 298
    return t;
}

/* write the header (used two times if non streamed) */
static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size)
{
    ASFContext *asf = s->priv_data;
299
    AVIOContext *pb = s->pb;
300
    AVDictionaryEntry *tags[5];
301 302
    int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
    int has_title;
303
    int metadata_count;
304 305 306
    AVCodecContext *enc;
    int64_t header_offset, cur_pos, hpos;
    int bit_rate;
307
    int64_t duration;
308

309
    ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
310

311 312 313 314 315
    tags[0] = av_dict_get(s->metadata, "title"    , NULL, 0);
    tags[1] = av_dict_get(s->metadata, "author"   , NULL, 0);
    tags[2] = av_dict_get(s->metadata, "copyright", NULL, 0);
    tags[3] = av_dict_get(s->metadata, "comment"  , NULL, 0);
    tags[4] = av_dict_get(s->metadata, "rating"   , NULL, 0);
316

317
    duration = asf->duration + PREROLL_TIME * 10000;
318
    has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4];
319
    metadata_count = s->metadata ? s->metadata->count : 0;
320 321 322

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

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

327 328 329 330 331 332 333
        bit_rate += enc->bit_rate;
    }

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

334
    put_guid(pb, &ff_asf_header);
335 336 337 338
    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); /* ??? */
339 340

    /* file header */
341
    header_offset = avio_tell(pb);
342 343
    hpos = put_header(pb, &ff_asf_file_header);
    put_guid(pb, &ff_asf_my_guid);
344
    avio_wl64(pb, file_size);
345
    file_time = 0;
346 347 348 349 350
    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 */
351
    avio_wl32(pb, (asf->is_streamed || !pb->seekable ) ? 3 : 2); /* ??? */
352 353 354
    avio_wl32(pb, s->packet_size); /* packet size */
    avio_wl32(pb, s->packet_size); /* packet size */
    avio_wl32(pb, bit_rate); /* Nominal data rate in bps */
355 356 357
    end_header(pb, hpos);

    /* unknown headers */
358 359
    hpos = put_header(pb, &ff_asf_head1_guid);
    put_guid(pb, &ff_asf_head2_guid);
360 361
    avio_wl32(pb, 6);
    avio_wl16(pb, 0);
362 363 364 365
    end_header(pb, hpos);

    /* title and other infos */
    if (has_title) {
366 367
        int len;
        uint8_t *buf;
368
        AVIOContext *dyn_buf;
369

370
        if (avio_open_dyn_buf(&dyn_buf) < 0)
371 372
            return AVERROR(ENOMEM);

373
        hpos = put_header(pb, &ff_asf_comment_header);
374 375

        for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) {
376
            len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0;
377
            avio_wl16(pb, len);
378
        }
379
        len = avio_close_dyn_buf(dyn_buf, &buf);
380
        avio_write(pb, buf, len);
381
        av_freep(&buf);
382 383
        end_header(pb, hpos);
    }
384
    if (metadata_count) {
385
        AVDictionaryEntry *tag = NULL;
386
        hpos = put_header(pb, &ff_asf_extended_content_header);
387
        avio_wl16(pb, metadata_count);
388
        while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
389
            put_str16(pb, tag->key);
390
            avio_wl16(pb, 0);
391
            put_str16(pb, tag->value);
392 393 394
        }
        end_header(pb, hpos);
    }
395 396 397 398 399 400

    /* stream headers */
    for(n=0;n<s->nb_streams;n++) {
        int64_t es_pos;
        //        ASFStream *stream = &asf->streams[n];

401
        enc = s->streams[n]->codec;
402 403 404
        asf->streams[n].num = n + 1;
        asf->streams[n].seq = 0;

405

406
        switch(enc->codec_type) {
407
        case AVMEDIA_TYPE_AUDIO:
408 409
            wav_extra_size = 0;
            extra_size = 18 + wav_extra_size;
410
            extra_size2 = 8;
411 412
            break;
        default:
413
        case AVMEDIA_TYPE_VIDEO:
414 415
            wav_extra_size = enc->extradata_size;
            extra_size = 0x33 + wav_extra_size;
416 417 418 419
            extra_size2 = 0;
            break;
        }

420
        hpos = put_header(pb, &ff_asf_stream_header);
421
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
422 423
            put_guid(pb, &ff_asf_audio_stream);
            put_guid(pb, &ff_asf_audio_conceal_spread);
424
        } else {
425 426
            put_guid(pb, &ff_asf_video_stream);
            put_guid(pb, &ff_asf_video_conceal_none);
427
        }
428
        avio_wl64(pb, 0); /* ??? */
429
        es_pos = avio_tell(pb);
430 431 432 433
        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); /* ??? */
434

435
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
436
            /* WAVEFORMATEX header */
437
            int wavsize = ff_put_wav_header(pb, enc);
438 439 440 441

            if (wavsize < 0)
                return -1;
            if (wavsize != extra_size) {
442
                cur_pos = avio_tell(pb);
443
                avio_seek(pb, es_pos, SEEK_SET);
444
                avio_wl32(pb, wavsize); /* wav header len */
445
                avio_seek(pb, cur_pos, SEEK_SET);
446
            }
447
            /* ERROR Correction */
448
            avio_w8(pb, 0x01);
449
            if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){
450 451
                avio_wl16(pb, 0x0190);
                avio_wl16(pb, 0x0190);
452
            }else{
453 454
                avio_wl16(pb, enc->block_align);
                avio_wl16(pb, enc->block_align);
455
            }
456 457
            avio_wl16(pb, 0x01);
            avio_w8(pb, 0x00);
458
        } else {
459 460 461 462
            avio_wl32(pb, enc->width);
            avio_wl32(pb, enc->height);
            avio_w8(pb, 2); /* ??? */
            avio_wl16(pb, 40 + enc->extradata_size); /* size */
463 464

            /* BITMAPINFOHEADER header */
465
            ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1);
466 467 468 469 470 471
        }
        end_header(pb, hpos);
    }

    /* media comments */

472 473
    hpos = put_header(pb, &ff_asf_codec_comment_header);
    put_guid(pb, &ff_asf_codec_comment1_header);
474
    avio_wl32(pb, s->nb_streams);
475 476
    for(n=0;n<s->nb_streams;n++) {
        AVCodec *p;
Anton Khirnov's avatar
Anton Khirnov committed
477
        const char *desc;
478 479
        int len;
        uint8_t *buf;
480
        AVIOContext *dyn_buf;
481

482
        enc = s->streams[n]->codec;
483 484
        p = avcodec_find_encoder(enc->codec_id);

485
        if(enc->codec_type == AVMEDIA_TYPE_AUDIO)
486
            avio_wl16(pb, 2);
487
        else if(enc->codec_type == AVMEDIA_TYPE_VIDEO)
488
            avio_wl16(pb, 1);
489
        else
490
            avio_wl16(pb, -1);
491 492

        if(enc->codec_id == CODEC_ID_WMAV2)
Anton Khirnov's avatar
Anton Khirnov committed
493
            desc = "Windows Media Audio V8";
494
        else
Anton Khirnov's avatar
Anton Khirnov committed
495
            desc = p ? p->name : enc->codec_name;
496

497
        if ( avio_open_dyn_buf(&dyn_buf) < 0)
498 499
            return AVERROR(ENOMEM);

500
        avio_put_str16le(dyn_buf, desc);
501
        len = avio_close_dyn_buf(dyn_buf, &buf);
502
        avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2
503

504
        avio_write(pb, buf, len);
505 506
        av_freep(&buf);

507
        avio_wl16(pb, 0); /* no parameters */
508 509


510
        /* id */
511
        if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
512 513
            avio_wl16(pb, 2);
            avio_wl16(pb, enc->codec_tag);
514
        } else {
515 516
            avio_wl16(pb, 4);
            avio_wl32(pb, enc->codec_tag);
517
        }
Michael Niedermayer's avatar
Michael Niedermayer committed
518 519
        if(!enc->codec_tag)
            return -1;
520 521 522 523 524
    }
    end_header(pb, hpos);

    /* patch the header size fields */

525
    cur_pos = avio_tell(pb);
526 527 528 529
    header_size = cur_pos - header_offset;
    if (asf->is_streamed) {
        header_size += 8 + 30 + 50;

530
        avio_seek(pb, header_offset - 10 - 30, SEEK_SET);
531
        avio_wl16(pb, header_size);
532
        avio_seek(pb, header_offset - 2 - 30, SEEK_SET);
533
        avio_wl16(pb, header_size);
534 535 536 537

        header_size -= 8 + 30 + 50;
    }
    header_size += 24 + 6;
538
    avio_seek(pb, header_offset - 14, SEEK_SET);
539
    avio_wl64(pb, header_size);
540
    avio_seek(pb, cur_pos, SEEK_SET);
541 542 543

    /* movie chunk, followed by packets of packet_size */
    asf->data_offset = cur_pos;
544
    put_guid(pb, &ff_asf_data_header);
545
    avio_wl64(pb, data_chunk_size);
546
    put_guid(pb, &ff_asf_my_guid);
547 548 549
    avio_wl64(pb, asf->nb_packets); /* nb packets */
    avio_w8(pb, 1); /* ??? */
    avio_w8(pb, 1); /* ??? */
550 551 552 553 554 555 556
    return 0;
}

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

557
    s->packet_size  = PACKET_SIZE;
558
    asf->nb_packets = 0;
559

560
    asf->last_indexed_pts = 0;
561
    asf->index_ptr = av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK );
562 563 564
    asf->nb_index_memory_alloc = ASF_INDEX_BLOCK;
    asf->nb_index_count = 0;
    asf->maximum_packet = 0;
565

Patric Stout's avatar
Patric Stout committed
566 567 568 569
    /* the data-chunk-size has to be 50, which is data_size - asf->data_offset
     *  at the moment this function is done. It is needed to use asf as
     *  streamable format. */
    if (asf_write_header1(s, 0, 50) < 0) {
570 571 572 573
        //av_free(asf);
        return -1;
    }

574
    avio_flush(s->pb);
575

576
    asf->packet_nb_payloads = 0;
577 578
    asf->packet_timestamp_start = -1;
    asf->packet_timestamp_end = -1;
579
    ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
580 581 582 583 584 585 586 587 588 589 590 591 592 593
                  NULL, NULL, NULL, NULL);

    return 0;
}

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

    asf->is_streamed = 1;

    return asf_write_header(s);
}

594 595
static int put_payload_parsing_info(
                                AVFormatContext *s,
596
                                unsigned int    sendtime,
597
                                unsigned int    duration,
598
                                int             nb_payloads,
599 600
                                int             padsize
            )
601 602
{
    ASFContext *asf = s->priv_data;
603
    AVIOContext *pb = s->pb;
604
    int ppi_size, i;
605
    int64_t start= avio_tell(pb);
606 607

    int iLengthTypeFlags = ASF_PPI_LENGTH_TYPE_FLAGS;
608

609 610 611 612 613
    padsize -= PACKET_HEADER_MIN_SIZE;
    if(asf->multi_payloads_present)
        padsize--;
    assert(padsize>=0);

614
    avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS);
615
    for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++){
616
        avio_w8(pb, 0x0);
617 618
    }

619 620
    if (asf->multi_payloads_present)
        iLengthTypeFlags |= ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT;
621 622 623

    if (padsize > 0) {
        if (padsize < 256)
624
            iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE;
625
        else
626
            iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD;
627
    }
628
    avio_w8(pb, iLengthTypeFlags);
629

630
    avio_w8(pb, ASF_PPI_PROPERTY_FLAGS);
631 632

    if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD)
633
        avio_wl16(pb, padsize - 2);
634
    if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE)
635
        avio_w8(pb, padsize - 1);
636

637 638
    avio_wl32(pb, sendtime);
    avio_wl16(pb, duration);
639
    if (asf->multi_payloads_present)
640
        avio_w8(pb, nb_payloads | ASF_PAYLOAD_FLAGS);
641

642
    ppi_size = avio_tell(pb) - start;
643

644
    return ppi_size;
645 646 647 648 649
}

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

652 653
    assert(asf->packet_timestamp_end >= asf->packet_timestamp_start);

654
    if (asf->is_streamed) {
655
        put_chunk(s, 0x4424, s->packet_size, 0);
656 657 658 659 660 661 662 663 664
    }

    packet_hdr_size = put_payload_parsing_info(
                            s,
                            asf->packet_timestamp_start,
                            asf->packet_timestamp_end - asf->packet_timestamp_start,
                            asf->packet_nb_payloads,
                            asf->packet_size_left
                        );
665

666 667
    packet_filled_size = PACKET_SIZE - asf->packet_size_left;
    assert(packet_hdr_size <= asf->packet_size_left);
668
    memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
669

670
    avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size);
671

672
    avio_flush(s->pb);
673
    asf->nb_packets++;
674
    asf->packet_nb_payloads = 0;
675 676
    asf->packet_timestamp_start = -1;
    asf->packet_timestamp_end = -1;
677
    ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
678 679 680
                  NULL, NULL, NULL, NULL);
}

681 682 683 684 685 686
static void put_payload_header(
                                AVFormatContext *s,
                                ASFStream       *stream,
                                int             presentation_time,
                                int             m_obj_size,
                                int             m_obj_offset,
687 688
                                int             payload_len,
                                int             flags
689
            )
690 691
{
    ASFContext *asf = s->priv_data;
692
    AVIOContext *pb = &asf->pb;
693
    int val;
694

695
    val = stream->num;
696
    if (flags & AV_PKT_FLAG_KEY)
697
        val |= ASF_PL_FLAG_KEY_FRAME;
698
    avio_w8(pb, val);
699

700 701
    avio_w8(pb, stream->seq);  //Media object number
    avio_wl32(pb, m_obj_offset); //Offset Into Media Object
702

703
    // Replicated Data shall be at least 8 bytes long.
704
    // The first 4 bytes of data shall contain the
705
    // Size of the Media Object that the payload belongs to.
706
    // The next 4 bytes of data shall contain the
707
    // Presentation Time for the media object that the payload belongs to.
708
    avio_w8(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH);
709

710 711
    avio_wl32(pb, m_obj_size);       //Replicated Data - Media Object Size
    avio_wl32(pb, presentation_time);//Replicated Data - Presentation Time
712

713
    if (asf->multi_payloads_present){
714
        avio_wl16(pb, payload_len);   //payload length
715
    }
716 717
}

718 719 720
static void put_frame(
                    AVFormatContext *s,
                    ASFStream       *stream,
721
                    AVStream        *avst,
722
                    int             timestamp,
723
                    const uint8_t   *buf,
724
                    int             m_obj_size,
725
                    int             flags
726
                )
727 728
{
    ASFContext *asf = s->priv_data;
729 730 731 732 733 734 735
    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);
736

737
            asf->packet_size_left = PACKET_SIZE;
738 739 740 741 742 743
            if (asf->multi_payloads_present){
                frag_len1 = MULTI_PAYLOAD_CONSTANT - 1;
            }
            else {
                frag_len1 = SINGLE_PAYLOAD_DATA_LENGTH;
            }
744
            asf->packet_timestamp_start = timestamp;
745 746 747
        }
        else {
            // multi payloads
748
            frag_len1 = asf->packet_size_left - PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS - PACKET_HEADER_MIN_SIZE - 1;
749

750
            if(frag_len1 < payload_len && avst->codec->codec_type == AVMEDIA_TYPE_AUDIO){
751 752 753
                flush_packet(s);
                continue;
            }
754
        }
755
        if (frag_len1 > 0) {
756 757 758 759
            if (payload_len > frag_len1)
                payload_len = frag_len1;
            else if (payload_len == (frag_len1 - 1))
                payload_len = frag_len1 - 2;  //additional byte need to put padding length
760

761
            put_payload_header(s, stream, timestamp+PREROLL_TIME, m_obj_size, m_obj_offset, payload_len, flags);
762
            avio_write(&asf->pb, buf, payload_len);
763 764 765 766 767

            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);
768
            asf->packet_timestamp_end = timestamp;
769

770
            asf->packet_nb_payloads++;
771
        } else {
772
            payload_len = 0;
773
        }
774 775 776 777 778
        m_obj_offset += payload_len;
        buf += payload_len;

        if (!asf->multi_payloads_present)
            flush_packet(s);
779
        else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1))
780 781 782 783 784
            flush_packet(s);
    }
    stream->seq++;
}

785
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
786 787 788 789 790
{
    ASFContext *asf = s->priv_data;
    ASFStream *stream;
    int64_t duration;
    AVCodecContext *codec;
791
    int64_t packet_st,pts;
792
    int start_sec,i;
793
    int flags= pkt->flags;
794

795
    codec = s->streams[pkt->stream_index]->codec;
796
    stream = &asf->streams[pkt->stream_index];
797

798
    if(codec->codec_type == AVMEDIA_TYPE_AUDIO)
799
        flags &= ~AV_PKT_FLAG_KEY;
800

801
    pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts;
802 803
    assert(pts != AV_NOPTS_VALUE);
    duration = pts * 10000;
804
    asf->duration= FFMAX(asf->duration, duration + pkt->duration * 10000);
805

806
    packet_st = asf->nb_packets;
807
    put_frame(s, stream, s->streams[pkt->stream_index], pkt->dts, pkt->data, pkt->size, flags);
808 809

    /* check index */
810
    if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
811 812
        start_sec = (int)(duration / INT64_C(10000000));
        if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) {
813 814 815 816 817 818 819 820
            for(i=asf->nb_index_count;i<start_sec;i++) {
                if (i>=asf->nb_index_memory_alloc) {
                    asf->nb_index_memory_alloc += ASF_INDEX_BLOCK;
                    asf->index_ptr = (ASFIndex*)av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
                }
                // store
                asf->index_ptr[i].packet_number = (uint32_t)packet_st;
                asf->index_ptr[i].packet_count  = (uint16_t)(asf->nb_packets-packet_st);
Michael Niedermayer's avatar
Michael Niedermayer committed
821
                asf->maximum_packet = FFMAX(asf->maximum_packet, (uint16_t)(asf->nb_packets-packet_st));
822 823 824 825 826 827 828 829 830 831 832
            }
            asf->nb_index_count = start_sec;
            asf->last_indexed_pts = duration;
        }
    }
    return 0;
}

//
static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, uint32_t count)
{
833
    AVIOContext *pb = s->pb;
834 835
    int i;

836
    put_guid(pb, &ff_asf_simple_index_header);
837
    avio_wl64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count);
838
    put_guid(pb, &ff_asf_my_guid);
839 840 841
    avio_wl64(pb, ASF_INDEXED_INTERVAL);
    avio_wl32(pb, max);
    avio_wl32(pb, count);
842
    for(i=0; i<count; i++) {
843 844
        avio_wl32(pb, index[i].packet_number);
        avio_wl16(pb, index[i].packet_count);
845 846
    }

847 848 849 850 851 852
    return 0;
}

static int asf_write_trailer(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
853
    int64_t file_size,data_size;
854 855 856 857 858

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

859
    /* write index */
860
    data_size = avio_tell(s->pb);
861 862 863
    if ((!asf->is_streamed) && (asf->nb_index_count != 0)) {
        asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count);
    }
864
    avio_flush(s->pb);
865

866
    if (asf->is_streamed || !s->pb->seekable) {
867 868 869
        put_chunk(s, 0x4524, 0, 0); /* end of stream */
    } else {
        /* rewrite an updated header */
870
        file_size = avio_tell(s->pb);
871
        avio_seek(s->pb, 0, SEEK_SET);
872
        asf_write_header1(s, file_size, data_size - asf->data_offset);
873 874
    }

875
    avio_flush(s->pb);
876
    av_free(asf->index_ptr);
877 878 879
    return 0;
}

880
#if CONFIG_ASF_MUXER
881
AVOutputFormat ff_asf_muxer = {
882 883 884 885 886
    .name           = "asf",
    .long_name      = NULL_IF_CONFIG_SMALL("ASF format"),
    .mime_type      = "video/x-ms-asf",
    .extensions     = "asf,wmv,wma",
    .priv_data_size = sizeof(ASFContext),
887
#if CONFIG_LIBMP3LAME
888
    .audio_codec    = CODEC_ID_MP3,
889
#else
890
    .audio_codec    = CODEC_ID_MP2,
891
#endif
892 893 894 895
    .video_codec    = CODEC_ID_MSMPEG4V3,
    .write_header   = asf_write_header,
    .write_packet   = asf_write_packet,
    .write_trailer  = asf_write_trailer,
896
    .flags = AVFMT_GLOBALHEADER,
897
    .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0},
898
};
899
#endif
900

901
#if CONFIG_ASF_STREAM_MUXER
902
AVOutputFormat ff_asf_stream_muxer = {
903 904 905 906 907
    .name           = "asf_stream",
    .long_name      = NULL_IF_CONFIG_SMALL("ASF format"),
    .mime_type      = "video/x-ms-asf",
    .extensions     = "asf,wmv,wma",
    .priv_data_size = sizeof(ASFContext),
908
#if CONFIG_LIBMP3LAME
909
    .audio_codec    = CODEC_ID_MP3,
910
#else
911
    .audio_codec    = CODEC_ID_MP2,
912
#endif
913 914 915 916
    .video_codec    = CODEC_ID_MSMPEG4V3,
    .write_header   = asf_write_stream_header,
    .write_packet   = asf_write_packet,
    .write_trailer  = asf_write_trailer,
917
    .flags = AVFMT_GLOBALHEADER,
918
    .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0},
919
};
920
#endif //CONFIG_ASF_STREAM_MUXER