avienc.c 24.3 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1 2
/*
 * AVI encoder.
3
 * Copyright (c) 2000 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7 8
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
9
 *
10
 * This library is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
14
 *
15 16 17
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Fabrice Bellard's avatar
Fabrice Bellard committed
18 19 20 21 22 23 24 25 26
 */
#include "avformat.h"
#include "avi.h"

/*
 * TODO: 
 *  - fill all fields if non streamed (nb_frames for example)
 */

27
#ifdef CONFIG_ENCODERS
28
typedef struct AVIIentry {
Fabrice Bellard's avatar
Fabrice Bellard committed
29
    unsigned int flags, pos, len;
30 31 32 33 34 35 36 37 38
} AVIIentry;

#define AVI_INDEX_CLUSTER_SIZE 16384

typedef struct AVIIndex {
    offset_t    indx_start;
    int         entry;
    int         ents_allocated;
    AVIIentry** cluster;
Fabrice Bellard's avatar
Fabrice Bellard committed
39 40 41
} AVIIndex;

typedef struct {
42 43
    offset_t riff_start, movi_list, odml_list;
    offset_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS];
44
    int audio_strm_length[MAX_STREAMS];
45
    int riff_id;
46
    int packet_count[MAX_STREAMS];
47 48

    AVIIndex indexes[MAX_STREAMS];
Fabrice Bellard's avatar
Fabrice Bellard committed
49 50
} AVIContext;

51 52 53 54 55 56 57
static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) 
{
    int cl = ent_id / AVI_INDEX_CLUSTER_SIZE;
    int id = ent_id % AVI_INDEX_CLUSTER_SIZE;
    return &idx->cluster[cl][id];
}

58
offset_t start_tag(ByteIOContext *pb, const char *tag)
Fabrice Bellard's avatar
Fabrice Bellard committed
59 60 61 62 63 64 65 66 67 68 69 70
{
    put_tag(pb, tag);
    put_le32(pb, 0);
    return url_ftell(pb);
}

void end_tag(ByteIOContext *pb, offset_t start)
{
    offset_t pos;

    pos = url_ftell(pb);
    url_fseek(pb, start - 4, SEEK_SET);
71
    put_le32(pb, (uint32_t)(pos - start));
Fabrice Bellard's avatar
Fabrice Bellard committed
72 73
    url_fseek(pb, pos, SEEK_SET);
}
74
#endif //CONFIG_ENCODERS
Fabrice Bellard's avatar
Fabrice Bellard committed
75 76 77

/* Note: when encoding, the first matching tag is used, so order is
   important if multiple tags possible for a given codec. */
78
const CodecTag codec_bmp_tags[] = {
79 80
    { CODEC_ID_H264, MKTAG('H', '2', '6', '4') },

Juanjo's avatar
Juanjo committed
81 82
    { CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
    { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
Fabrice Bellard's avatar
Fabrice Bellard committed
83
    { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
Roberto Togni's avatar
Roberto Togni committed
84
    { CODEC_ID_H261, MKTAG('H', '2', '6', '1') },
85 86 87 88 89

    /* added based on MPlayer */
    { CODEC_ID_H263P, MKTAG('U', '2', '6', '3') },
    { CODEC_ID_H263P, MKTAG('v', 'i', 'v', '1') },

90 91 92
    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X'), .invalid_asf = 1 },
    { CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0'), .invalid_asf = 1 },
    { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D'), .invalid_asf = 1 },
93 94
    { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
    { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
95
    { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
96 97 98 99 100 101 102

    /* added based on MPlayer */
    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') },
    { CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') },
    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
    { CODEC_ID_MPEG4, MKTAG('U', 'M', 'P', '4') },

103
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3'), .invalid_asf = 1 }, /* default signature when using MSMPEG4 */
104
    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, 
105 106 107 108 109 110 111 112 113 114

    /* added based on MPlayer */
    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') }, 
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '5') }, 
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '6') }, 
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '4') }, 
    { CODEC_ID_MSMPEG4V3, MKTAG('A', 'P', '4', '1') }, 
    { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '1') }, 
    { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '0') }, 

115
    { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') }, 
116 117 118 119

    /* added based on MPlayer */
    { CODEC_ID_MSMPEG4V2, MKTAG('D', 'I', 'V', '2') },
 
Michael Niedermayer's avatar
Michael Niedermayer committed
120
    { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') }, 
121

Michael Niedermayer's avatar
Michael Niedermayer committed
122
    { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') }, 
123 124

    /* added based on MPlayer */
125
    { CODEC_ID_WMV2, MKTAG('W', 'M', 'V', '2') }, 
Fabrice Bellard's avatar
Fabrice Bellard committed
126 127
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') }, 
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') }, 
128 129
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') }, 
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') },
130 131
    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') }, 
    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') }, 
132
    { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') }, 
133
    { CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') }, 
Michael Niedermayer's avatar
Michael Niedermayer committed
134
    { CODEC_ID_MPEG1VIDEO, MKTAG('V', 'C', 'R', '2') }, 
Michael Niedermayer's avatar
Michael Niedermayer committed
135 136
    { CODEC_ID_MPEG1VIDEO, 0x10000001 }, 
    { CODEC_ID_MPEG2VIDEO, 0x10000002 }, 
137
    { CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') },
Alex Beregszaszi's avatar
Alex Beregszaszi committed
138
    { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
Alex Beregszaszi's avatar
Alex Beregszaszi committed
139
    { CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') },
Michael Niedermayer's avatar
Michael Niedermayer committed
140
    { CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') },
Alex Beregszaszi's avatar
Alex Beregszaszi committed
141
    { CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */
142
    { CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') },
143
    { CODEC_ID_CYUV, MKTAG('C', 'Y', 'U', 'V') },
144
    { CODEC_ID_RAWVIDEO, MKTAG('Y', '4', '2', '2') },
145
    { CODEC_ID_RAWVIDEO, MKTAG('I', '4', '2', '0') },
146 147
    { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') },
    { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') },
148
    { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
149
    { CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') },
150
    { CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') },
Michael Niedermayer's avatar
Michael Niedermayer committed
151
    { CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') },
Michael Niedermayer's avatar
Michael Niedermayer committed
152
    { CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
153
    { CODEC_ID_XAN_WC4, MKTAG('X', 'x', 'a', 'n') },
154 155 156 157 158 159 160 161 162
    { CODEC_ID_MSRLE, MKTAG('m', 'r', 'l', 'e') },
    { CODEC_ID_MSRLE, MKTAG(0x1, 0x0, 0x0, 0x0) },
    { CODEC_ID_MSVIDEO1, MKTAG('M', 'S', 'V', 'C') },
    { CODEC_ID_MSVIDEO1, MKTAG('m', 's', 'v', 'c') },
    { CODEC_ID_MSVIDEO1, MKTAG('C', 'R', 'A', 'M') },
    { CODEC_ID_MSVIDEO1, MKTAG('c', 'r', 'a', 'm') },
    { CODEC_ID_MSVIDEO1, MKTAG('W', 'H', 'A', 'M') },
    { CODEC_ID_MSVIDEO1, MKTAG('w', 'h', 'a', 'm') },
    { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') },
Mike Melanson's avatar
Mike Melanson committed
163
    { CODEC_ID_TRUEMOTION1, MKTAG('D', 'U', 'C', 'K') },
164 165
    { CODEC_ID_MSZH, MKTAG('M', 'S', 'Z', 'H') },
    { CODEC_ID_ZLIB, MKTAG('Z', 'L', 'I', 'B') },
166
    { CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') },
Michael Niedermayer's avatar
Michael Niedermayer committed
167
    { CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') },
Michael Niedermayer's avatar
Michael Niedermayer committed
168
    { CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') },
169
    { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') },
170
    { CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') },
171
    { CODEC_ID_ULTI, MKTAG('U', 'L', 'T', 'I') },
Michael Niedermayer's avatar
Michael Niedermayer committed
172
    { CODEC_ID_RAWVIDEO, 0 },
Fabrice Bellard's avatar
Fabrice Bellard committed
173 174 175
    { 0, 0 },
};

Zdenek Kabelac's avatar
Zdenek Kabelac committed
176
unsigned int codec_get_tag(const CodecTag *tags, int id)
Fabrice Bellard's avatar
Fabrice Bellard committed
177 178 179 180 181 182 183 184 185
{
    while (tags->id != 0) {
        if (tags->id == id)
            return tags->tag;
        tags++;
    }
    return 0;
}

186
static unsigned int codec_get_asf_tag(const CodecTag *tags, unsigned int id)
187 188 189 190 191 192 193 194 195
{
    while (tags->id != 0) {
        if (!tags->invalid_asf && tags->id == id)
            return tags->tag;
        tags++;
    }
    return 0;
}

Zdenek Kabelac's avatar
Zdenek Kabelac committed
196
enum CodecID codec_get_id(const CodecTag *tags, unsigned int tag)
Fabrice Bellard's avatar
Fabrice Bellard committed
197 198
{
    while (tags->id != 0) {
199 200 201 202
        if(   toupper((tag >> 0)&0xFF) == toupper((tags->tag >> 0)&0xFF)
           && toupper((tag >> 8)&0xFF) == toupper((tags->tag >> 8)&0xFF)
           && toupper((tag >>16)&0xFF) == toupper((tags->tag >>16)&0xFF)
           && toupper((tag >>24)&0xFF) == toupper((tags->tag >>24)&0xFF))
Fabrice Bellard's avatar
Fabrice Bellard committed
203 204 205
            return tags->id;
        tags++;
    }
Zdenek Kabelac's avatar
Zdenek Kabelac committed
206
    return CODEC_ID_NONE;
Fabrice Bellard's avatar
Fabrice Bellard committed
207 208 209 210 211 212 213
}

unsigned int codec_get_bmp_tag(int id)
{
    return codec_get_tag(codec_bmp_tags, id);
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
unsigned int codec_get_wav_tag(int id)
{
    return codec_get_tag(codec_wav_tags, id);
}

enum CodecID codec_get_bmp_id(unsigned int tag)
{
    return codec_get_id(codec_bmp_tags, tag);
}

enum CodecID codec_get_wav_id(unsigned int tag)
{
    return codec_get_id(codec_wav_tags, tag);
}

229
#ifdef CONFIG_ENCODERS
Fabrice Bellard's avatar
Fabrice Bellard committed
230
/* BITMAPINFOHEADER header */
231
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc, const CodecTag *tags, int for_asf)
Fabrice Bellard's avatar
Fabrice Bellard committed
232
{
233
    put_le32(pb, 40 + enc->extradata_size); /* size */
Fabrice Bellard's avatar
Fabrice Bellard committed
234 235 236
    put_le32(pb, enc->width);
    put_le32(pb, enc->height);
    put_le16(pb, 1); /* planes */
237 238
    
    put_le16(pb, enc->bits_per_sample ? enc->bits_per_sample : 24); /* depth */
Fabrice Bellard's avatar
Fabrice Bellard committed
239
    /* compression type */
240
    put_le32(pb, for_asf ? codec_get_asf_tag(tags, enc->codec_id) : enc->codec_tag);
Fabrice Bellard's avatar
Fabrice Bellard committed
241 242 243 244 245
    put_le32(pb, enc->width * enc->height * 3);
    put_le32(pb, 0);
    put_le32(pb, 0);
    put_le32(pb, 0);
    put_le32(pb, 0);
246 247 248 249 250
    
    put_buffer(pb, enc->extradata, enc->extradata_size);

    if (enc->extradata_size & 1)
        put_byte(pb, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
251 252
}

253
static void parse_specific_params(AVCodecContext *stream, int *au_byterate, int *au_ssize, int *au_scale)
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
{
    switch(stream->codec_id) {
    case CODEC_ID_PCM_S16LE:
       *au_scale = *au_ssize = 2*stream->channels;
       *au_byterate = *au_ssize * stream->sample_rate;
        break;
    case CODEC_ID_PCM_U8:
    case CODEC_ID_PCM_ALAW:
    case CODEC_ID_PCM_MULAW:
        *au_scale = *au_ssize = stream->channels;
        *au_byterate = *au_ssize * stream->sample_rate;
        break;
    case CODEC_ID_MP2:
        *au_ssize = 1;
        *au_scale = 1;
        *au_byterate = stream->bit_rate / 8;
270
    case CODEC_ID_MP3:
271 272 273
        *au_ssize = 1;
        *au_scale = 1;
        *au_byterate = stream->bit_rate / 8;    
274 275 276 277 278 279 280 281
    default:
        *au_ssize = 1;
        *au_scale = 1; 
        *au_byterate = stream->bit_rate / 8;
        break;
    }
}

282 283 284 285
static offset_t avi_start_new_riff(AVIContext *avi, ByteIOContext *pb, 
                                   const char* riff_tag, const char* list_tag)
{
    offset_t loff;
286 287 288 289 290 291
    int i;
    
    avi->riff_id++;
    for (i=0; i<MAX_STREAMS; i++)
         avi->indexes[i].entry = 0;
    
292 293 294 295 296 297 298
    avi->riff_start = start_tag(pb, "RIFF");
    put_tag(pb, riff_tag);
    loff = start_tag(pb, "LIST");
    put_tag(pb, list_tag);
    return loff;
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
static unsigned char* avi_stream2fourcc(unsigned char* tag, int index, 
                                        enum CodecType type)
{
    tag[0] = '0';
    tag[1] = '0' + index;
    if (type == CODEC_TYPE_VIDEO) {
        tag[2] = 'd';
        tag[3] = 'c';
    } else {
        tag[2] = 'w';
        tag[3] = 'b';
    }
    tag[4] = '\0';
    return tag;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
315 316
static int avi_write_header(AVFormatContext *s)
{
Fabrice Bellard's avatar
Fabrice Bellard committed
317
    AVIContext *avi = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
318
    ByteIOContext *pb = &s->pb;
319
    int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
Fabrice Bellard's avatar
Fabrice Bellard committed
320 321 322 323
    AVCodecContext *stream, *video_enc;
    offset_t list1, list2, strh, strf;

    /* header list */
324
    avi->riff_id = 0;
325
    list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl");
Fabrice Bellard's avatar
Fabrice Bellard committed
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

    /* avi header */
    put_tag(pb, "avih");
    put_le32(pb, 14 * 4);
    bitrate = 0;

    video_enc = NULL;
    for(n=0;n<s->nb_streams;n++) {
        stream = &s->streams[n]->codec;
        bitrate += stream->bit_rate;
        if (stream->codec_type == CODEC_TYPE_VIDEO)
            video_enc = stream;
    }
    
    nb_frames = 0;

342
    if(video_enc){
343
        put_le32(pb, (uint32_t)(int64_t_C(1000000) * video_enc->frame_rate_base / video_enc->frame_rate));
344 345 346
    } else {
	put_le32(pb, 0);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
347 348 349
    put_le32(pb, bitrate / 8); /* XXX: not quite exact */
    put_le32(pb, 0); /* padding */
    put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
350
    avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */
Fabrice Bellard's avatar
Fabrice Bellard committed
351 352 353 354
    put_le32(pb, nb_frames); /* nb frames, filled later */
    put_le32(pb, 0); /* initial frame */
    put_le32(pb, s->nb_streams); /* nb streams */
    put_le32(pb, 1024 * 1024); /* suggested buffer size */
355
    if(video_enc){    
Fabrice Bellard's avatar
Fabrice Bellard committed
356 357
    put_le32(pb, video_enc->width);
    put_le32(pb, video_enc->height);
358 359 360 361
    } else {
	put_le32(pb, 0);
	put_le32(pb, 0);
    }	
Fabrice Bellard's avatar
Fabrice Bellard committed
362 363 364 365 366 367 368 369 370 371 372 373
    put_le32(pb, 0); /* reserved */
    put_le32(pb, 0); /* reserved */
    put_le32(pb, 0); /* reserved */
    put_le32(pb, 0); /* reserved */
    
    /* stream list */
    for(i=0;i<n;i++) {
        list2 = start_tag(pb, "LIST");
        put_tag(pb, "strl");
    
        stream = &s->streams[i]->codec;

374 375 376 377 378
        /* FourCC should really be set by the codec itself */
        if (! stream->codec_tag) {
            stream->codec_tag = codec_get_bmp_tag(stream->codec_id);
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
379 380 381 382 383
        /* stream generic header */
        strh = start_tag(pb, "strh");
        switch(stream->codec_type) {
        case CODEC_TYPE_VIDEO:
            put_tag(pb, "vids");
384
            put_le32(pb, stream->codec_tag);
Fabrice Bellard's avatar
Fabrice Bellard committed
385 386 387 388
            put_le32(pb, 0); /* flags */
            put_le16(pb, 0); /* priority */
            put_le16(pb, 0); /* language */
            put_le32(pb, 0); /* initial frame */
389
            
390 391
            put_le32(pb, stream->frame_rate_base); /* scale */
            put_le32(pb, stream->frame_rate); /* rate */
392
            av_set_pts_info(s->streams[i], 64, stream->frame_rate_base, stream->frame_rate);
393

Fabrice Bellard's avatar
Fabrice Bellard committed
394
            put_le32(pb, 0); /* start */
395
            avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
Fabrice Bellard's avatar
Fabrice Bellard committed
396 397
            put_le32(pb, nb_frames); /* length, XXX: fill later */
            put_le32(pb, 1024 * 1024); /* suggested buffer size */
398
            put_le32(pb, -1); /* quality */
Fabrice Bellard's avatar
Fabrice Bellard committed
399 400 401 402 403 404 405 406
            put_le32(pb, stream->width * stream->height * 3); /* sample size */
            put_le16(pb, 0);
            put_le16(pb, 0);
            put_le16(pb, stream->width);
            put_le16(pb, stream->height);
            break;
        case CODEC_TYPE_AUDIO:
            put_tag(pb, "auds");
407
            put_le32(pb, 1); /* tag */
Fabrice Bellard's avatar
Fabrice Bellard committed
408 409 410 411
            put_le32(pb, 0); /* flags */
            put_le16(pb, 0); /* priority */
            put_le16(pb, 0); /* language */
            put_le32(pb, 0); /* initial frame */
412 413 414
            parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
            put_le32(pb, au_scale); /* scale */
            put_le32(pb, au_byterate); /* rate */
415
//            av_set_pts_info(&s->streams[i], 64, au_scale, au_byterate);
Fabrice Bellard's avatar
Fabrice Bellard committed
416
            put_le32(pb, 0); /* start */
417
            avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
Fabrice Bellard's avatar
Fabrice Bellard committed
418 419 420
            put_le32(pb, 0); /* length, XXX: filled later */
            put_le32(pb, 12 * 1024); /* suggested buffer size */
            put_le32(pb, -1); /* quality */
421
            put_le32(pb, au_ssize); /* sample size */
Fabrice Bellard's avatar
Fabrice Bellard committed
422 423 424
            put_le32(pb, 0);
            put_le32(pb, 0);
            break;
425
        default:
426
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
427 428 429 430 431 432
        }
        end_tag(pb, strh);

        strf = start_tag(pb, "strf");
        switch(stream->codec_type) {
        case CODEC_TYPE_VIDEO:
433
	    put_bmp_header(pb, stream, codec_bmp_tags, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
434 435
            break;
        case CODEC_TYPE_AUDIO:
436
            if (put_wav_header(pb, stream) < 0) {
437
                av_free(avi);
438 439
                return -1;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
440
            break;
441
        default:
442
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
443 444
        }
        end_tag(pb, strf);
445 446 447
	
	if (!url_is_streamed(pb)) {
	    unsigned char tag[5];
448
	    int j;
449 450 451
    
            /* Starting to lay out AVI OpenDML master index. 
	     * We want to make it JUNK entry for now, since we'd
452
	     * like to get away without making AVI an OpenDML one 
453 454 455 456 457 458 459 460 461 462 463 464
	     * for compatibility reasons.
	     */
	    avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0;
	    avi->indexes[i].indx_start = start_tag(pb, "JUNK"); 
	    put_le16(pb, 4);        /* wLongsPerEntry */
	    put_byte(pb, 0);        /* bIndexSubType (0 == frame index) */
	    put_byte(pb, 0);        /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
	    put_le32(pb, 0);        /* nEntriesInUse (will fill out later on) */
	    put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type));
	                            /* dwChunkId */
	    put_le64(pb, 0);        /* dwReserved[3]
	    put_le32(pb, 0);           Must be 0.    */
465 466
	    for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
	         put_le64(pb, 0);
467 468 469
	    end_tag(pb, avi->indexes[i].indx_start);
	}
	
Fabrice Bellard's avatar
Fabrice Bellard committed
470 471
        end_tag(pb, list2);
    }
472
    
473 474 475 476 477 478 479 480 481 482
    if (!url_is_streamed(pb)) {
        /* AVI could become an OpenDML one, if it grows beyond 2Gb range */
        avi->odml_list = start_tag(pb, "JUNK");
        put_tag(pb, "odml");
        put_tag(pb, "dmlh");
        put_le32(pb, 248);
        for (i = 0; i < 248; i+= 4)
             put_le32(pb, 0);
        end_tag(pb, avi->odml_list);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
483 484 485 486 487 488 489 490 491 492 493

    end_tag(pb, list1);
    
    avi->movi_list = start_tag(pb, "LIST");
    put_tag(pb, "movi");

    put_flush_packet(pb);

    return 0;
}

494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
static int avi_write_ix(AVFormatContext *s)
{
    ByteIOContext *pb = &s->pb;
    AVIContext *avi = s->priv_data;
    unsigned char tag[5];
    unsigned char ix_tag[] = "ix00";
    int i, j;
    
    if (avi->riff_id > AVI_MASTER_INDEX_SIZE)
        return -1;
    
    for (i=0;i<s->nb_streams;i++) {
	 offset_t ix, pos;
	 
	 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec.codec_type);
	 ix_tag[3] = '0' + i;
	 
	 /* Writing AVI OpenDML leaf index chunk */
	 ix = url_ftell(pb); 
	 put_tag(pb, &ix_tag[0]);     /* ix?? */
	 put_le32(pb, avi->indexes[i].entry * 8 + 24); 
	                              /* chunk size */
         put_le16(pb, 2);             /* wLongsPerEntry */
	 put_byte(pb, 0);             /* bIndexSubType (0 == frame index) */ 
	 put_byte(pb, 1);             /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */
	 put_le32(pb, avi->indexes[i].entry);          
	                              /* nEntriesInUse */
	 put_tag(pb, &tag[0]);        /* dwChunkId */
	 put_le64(pb, avi->movi_list);/* qwBaseOffset */
	 put_le32(pb, 0);             /* dwReserved_3 (must be 0) */

         for (j=0; j<avi->indexes[i].entry; j++) {
             AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j);
	     put_le32(pb, ie->pos + 8);
	     put_le32(pb, ((uint32_t)ie->len & ~0x80000000) |
	                  (ie->flags & 0x10 ? 0 : 0x80000000));
         }
	 put_flush_packet(pb);
         pos = url_ftell(pb);
	
	 /* Updating one entry in the AVI OpenDML master index */
	 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET);
	 put_tag(pb, "indx");                 /* enabling this entry */
	 url_fskip(pb, 8);
	 put_le32(pb, avi->riff_id);          /* nEntriesInUse */
	 url_fskip(pb, 16*avi->riff_id);
	 put_le64(pb, ix);                    /* qwOffset */
	 put_le32(pb, pos - ix);              /* dwSize */
	 put_le32(pb, avi->indexes[i].entry); /* dwDuration */

	 url_fseek(pb, pos, SEEK_SET);
    }
    return 0;
}

static int avi_write_idx1(AVFormatContext *s)
550 551 552 553
{
    ByteIOContext *pb = &s->pb;
    AVIContext *avi = s->priv_data;
    offset_t file_size, idx_chunk;
554
    int i, n, nb_frames, au_byterate, au_ssize, au_scale;
555
    AVCodecContext *stream;
556
    unsigned char tag[5];
557 558

    if (!url_is_streamed(pb)) {
559
	AVIIentry* ie = 0, *tie;
560
	int entry[MAX_STREAMS];
561
	int empty, stream_id = -1;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588

	idx_chunk = start_tag(pb, "idx1");
	memset(&entry[0], 0, sizeof(entry));
	do {
	    empty = 1;
	    for (i=0; i<s->nb_streams; i++) {
	         if (avi->indexes[i].entry <= entry[i])
		     continue;
		 
		 tie = avi_get_ientry(&avi->indexes[i], entry[i]);
		 if (empty || tie->pos < ie->pos) {
		     ie = tie; 
		     stream_id = i;
		 }
		 empty = 0;
	    }
	    if (!empty) {
	        avi_stream2fourcc(&tag[0], stream_id, 
		                  s->streams[stream_id]->codec.codec_type); 
	        put_tag(pb, &tag[0]);
		put_le32(pb, ie->flags);
                put_le32(pb, ie->pos);
                put_le32(pb, ie->len);
		entry[stream_id]++;
	    }
	} while (!empty);
	end_tag(pb, idx_chunk);
589 590

        /* Fill in frame/sample counters */
591
	file_size = url_ftell(pb);
592 593 594 595 596 597 598 599 600 601
        nb_frames = 0;
        for(n=0;n<s->nb_streams;n++) {
            if (avi->frames_hdr_strm[n] != 0) {
                stream = &s->streams[n]->codec;
                url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET);
                if (stream->codec_type == CODEC_TYPE_VIDEO) {
                    put_le32(pb, stream->frame_number); 
                    if (nb_frames < stream->frame_number)
                        nb_frames = stream->frame_number;
                } else {
602
                    if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) {
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
                        put_le32(pb, stream->frame_number);
                        nb_frames += stream->frame_number;
                    } else {
                        parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
                        put_le32(pb, avi->audio_strm_length[n] / au_ssize);
                    }
                }
            }
       }
       if (avi->frames_hdr_all != 0) {
           url_fseek(pb, avi->frames_hdr_all, SEEK_SET);
           put_le32(pb, nb_frames); 
       }
       url_fseek(pb, file_size, SEEK_SET);
    }
    return 0;
}

621
static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
622 623 624 625
{
    AVIContext *avi = s->priv_data;
    ByteIOContext *pb = &s->pb;
    unsigned char tag[5];
626 627
    unsigned int flags=0;
    const int stream_index= pkt->stream_index;
628
    AVCodecContext *enc= &s->streams[stream_index]->codec;
629
    int size= pkt->size;
630

631 632 633 634 635 636 637 638 639 640 641 642 643
//    av_log(s, AV_LOG_DEBUG, "%lld %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index);
    while(enc->codec_type == CODEC_TYPE_VIDEO && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){
        AVPacket empty_packet;

        av_init_packet(&empty_packet);
        empty_packet.size= 0;
        empty_packet.data= NULL;
        empty_packet.stream_index= stream_index;
        avi_write_packet(s, &empty_packet);
//        av_log(s, AV_LOG_DEBUG, "dup %lld %d\n", pkt->dts, avi->packet_count[stream_index]);
    }
    avi->packet_count[stream_index]++;

644
    if (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE) { 
645 646 647 648 649 650 651
        avi_write_ix(s);
        end_tag(pb, avi->movi_list);
        
	if (avi->riff_id == 1)
	    avi_write_idx1(s);

	end_tag(pb, avi->riff_start);
652 653
	avi->movi_list = avi_start_new_riff(avi, pb, "AVIX", "movi");
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
654
    
655
    avi_stream2fourcc(&tag[0], stream_index, enc->codec_type);
656 657
    if(pkt->flags&PKT_FLAG_KEY)
        flags = 0x10;
658
    if (enc->codec_type == CODEC_TYPE_AUDIO) {
659
       avi->audio_strm_length[stream_index] += size;
660
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
661 662

    if (!url_is_streamed(&s->pb)) {
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
        AVIIndex* idx = &avi->indexes[stream_index];
	int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
	int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
        if (idx->ents_allocated <= idx->entry) {
	    idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); 
	    if (!idx->cluster)
	        return -1;
            idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry));
	    if (!idx->cluster[cl])
		return -1;
	    idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
	}
 	
	idx->cluster[cl][id].flags = flags; 
        idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list;
        idx->cluster[cl][id].len = size;
	idx->entry++;
Fabrice Bellard's avatar
Fabrice Bellard committed
680 681 682 683
    }
    
    put_buffer(pb, tag, 4);
    put_le32(pb, size);
684
    put_buffer(pb, pkt->data, size);
Fabrice Bellard's avatar
Fabrice Bellard committed
685 686 687 688 689 690 691 692 693 694
    if (size & 1)
        put_byte(pb, 0);

    put_flush_packet(pb);
    return 0;
}

static int avi_write_trailer(AVFormatContext *s)
{
    AVIContext *avi = s->priv_data;
695 696
    ByteIOContext *pb = &s->pb;
    int res = 0;
697 698 699 700 701 702 703 704 705 706 707
    int i, j, n, nb_frames;
    offset_t file_size;

    if (avi->riff_id == 1) {
        end_tag(pb, avi->movi_list);
        res = avi_write_idx1(s);
	end_tag(pb, avi->riff_start);
    } else {
        avi_write_ix(s);
        end_tag(pb, avi->movi_list);
	end_tag(pb, avi->riff_start);
Fabrice Bellard's avatar
Fabrice Bellard committed
708 709

        file_size = url_ftell(pb);
710 711 712 713 714 715 716 717 718 719
	url_fseek(pb, avi->odml_list - 8, SEEK_SET);
	put_tag(pb, "LIST"); /* Making this AVI OpenDML one */
	url_fskip(pb, 16);

        for (n=nb_frames=0;n<s->nb_streams;n++) {
             AVCodecContext *stream = &s->streams[n]->codec;
             if (stream->codec_type == CODEC_TYPE_VIDEO) {
                 if (nb_frames < stream->frame_number)
                     nb_frames = stream->frame_number;
             } else {
720
                 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) {
721
                     nb_frames += stream->frame_number;
722 723
                }
            }
724 725 726
        }
	put_le32(pb, nb_frames);
	url_fseek(pb, file_size, SEEK_SET);
727
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
728
    put_flush_packet(pb);
729 730 731 732 733 734 735 736 737

    for (i=0; i<MAX_STREAMS; i++) {
	 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++)
              av_free(avi->indexes[i].cluster[j]);
	 av_free(avi->indexes[i].cluster);
	 avi->indexes[i].cluster = NULL;
	 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0;
    }
    
738
    return res;
Fabrice Bellard's avatar
Fabrice Bellard committed
739 740
}

Fabrice Bellard's avatar
Fabrice Bellard committed
741
static AVOutputFormat avi_oformat = {
Fabrice Bellard's avatar
Fabrice Bellard committed
742 743 744 745
    "avi",
    "avi format",
    "video/x-msvideo",
    "avi",
Fabrice Bellard's avatar
Fabrice Bellard committed
746
    sizeof(AVIContext),
Fabrice Bellard's avatar
Fabrice Bellard committed
747
    CODEC_ID_MP2,
748
    CODEC_ID_MPEG4,
Fabrice Bellard's avatar
Fabrice Bellard committed
749 750 751 752
    avi_write_header,
    avi_write_packet,
    avi_write_trailer,
};
Fabrice Bellard's avatar
Fabrice Bellard committed
753 754 755 756 757 758

int avienc_init(void)
{
    av_register_output_format(&avi_oformat);
    return 0;
}
759
#endif //CONFIG_ENCODERS