Statistics
| Branch: | Revision:

ffmpeg / libavformat / avienc.c @ f560dd82

History | View | Annotate | Download (13.5 KB)

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

    
22
/*
23
 * TODO: 
24
 *  - fill all fields if non streamed (nb_frames for example)
25
 */
26

    
27
typedef struct AVIIndex {
28
    unsigned char tag[4];
29
    unsigned int flags, pos, len;
30
    struct AVIIndex *next;
31
} AVIIndex;
32

    
33
typedef struct {
34
    offset_t movi_list, frames_hdr_all, frames_hdr_strm[MAX_STREAMS];
35
    int audio_strm_length[MAX_STREAMS];
36
    AVIIndex *first, *last;
37
} AVIContext;
38

    
39
offset_t start_tag(ByteIOContext *pb, const char *tag)
40
{
41
    put_tag(pb, tag);
42
    put_le32(pb, 0);
43
    return url_ftell(pb);
44
}
45

    
46
void end_tag(ByteIOContext *pb, offset_t start)
47
{
48
    offset_t pos;
49

    
50
    pos = url_ftell(pb);
51
    url_fseek(pb, start - 4, SEEK_SET);
52
    put_le32(pb, (UINT32)(pos - start));
53
    url_fseek(pb, pos, SEEK_SET);
54
}
55

    
56
/* Note: when encoding, the first matching tag is used, so order is
57
   important if multiple tags possible for a given codec. */
58
const CodecTag codec_bmp_tags[] = {
59
    { CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
60
    { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
61
    { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
62
    { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
63
    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X'), .invalid_asf = 1 },
64
    { CODEC_ID_MPEG4, MKTAG('d', 'i', 'v', 'x'), .invalid_asf = 1 },
65
    { CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0'), .invalid_asf = 1 },
66
    { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D'), .invalid_asf = 1 },
67
    { CODEC_ID_MPEG4, MKTAG('x', 'v', 'i', 'd'), .invalid_asf = 1 },
68
    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 's'), .invalid_asf = 1 },
69
    { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
70
    { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
71
    { CODEC_ID_MPEG4, MKTAG('m', '4', 's', '2') },
72
    { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
73
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3'), .invalid_asf = 1 }, /* default signature when using MSMPEG4 */
74
    { CODEC_ID_MSMPEG4V3, MKTAG('d', 'i', 'v', '3'), .invalid_asf = 1 },
75
    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, 
76
    { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') }, 
77
    { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') }, 
78
    { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') }, 
79
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') }, 
80
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') }, 
81
    { CODEC_ID_DVVIDEO, MKTAG('D', 'V', 'S', 'D') }, 
82
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') }, 
83
    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') }, 
84
    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') }, 
85
    { CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') }, 
86
    { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
87
    { CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') },
88
    { CODEC_ID_HUFFYUV, MKTAG('h', 'f', 'y', 'u') },
89
    { 0, 0 },
90
};
91

    
92
unsigned int codec_get_tag(const CodecTag *tags, int id)
93
{
94
    while (tags->id != 0) {
95
        if (tags->id == id)
96
            return tags->tag;
97
        tags++;
98
    }
99
    return 0;
100
}
101

    
102
static unsigned int codec_get_asf_tag(const CodecTag *tags, int id)
103
{
104
    while (tags->id != 0) {
105
        if (!tags->invalid_asf && tags->id == id)
106
            return tags->tag;
107
        tags++;
108
    }
109
    return 0;
110
}
111

    
112
int codec_get_id(const CodecTag *tags, unsigned int tag)
113
{
114
    while (tags->id != 0) {
115
        if (tags->tag == tag)
116
            return tags->id;
117
        tags++;
118
    }
119
    return 0;
120
}
121

    
122
unsigned int codec_get_bmp_tag(int id)
123
{
124
    return codec_get_tag(codec_bmp_tags, id);
125
}
126

    
127
/* BITMAPINFOHEADER header */
128
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc, const CodecTag *tags, int for_asf)
129
{
130
    put_le32(pb, 40); /* size */
131
    put_le32(pb, enc->width);
132
    put_le32(pb, enc->height);
133
    put_le16(pb, 1); /* planes */
134
    put_le16(pb, 24); /* depth */
135
    /* compression type */
136
    put_le32(pb, for_asf ? codec_get_asf_tag(tags, enc->codec_id) : codec_get_tag(tags, enc->codec_id));
137
    put_le32(pb, enc->width * enc->height * 3);
138
    put_le32(pb, 0);
139
    put_le32(pb, 0);
140
    put_le32(pb, 0);
141
    put_le32(pb, 0);
142
}
143

    
144
static void parse_specific_params(AVCodecContext *stream, int *au_byterate, int *au_ssize, int *au_scale)
145
{
146
    switch(stream->codec_id) {
147
    case CODEC_ID_PCM_S16LE:
148
       *au_scale = *au_ssize = 2*stream->channels;
149
       *au_byterate = *au_ssize * stream->sample_rate;
150
        break;
151
    case CODEC_ID_PCM_U8:
152
    case CODEC_ID_PCM_ALAW:
153
    case CODEC_ID_PCM_MULAW:
154
        *au_scale = *au_ssize = stream->channels;
155
        *au_byterate = *au_ssize * stream->sample_rate;
156
        break;
157
    case CODEC_ID_MP2:
158
        *au_ssize = 1;
159
        *au_scale = 1;
160
        *au_byterate = stream->bit_rate / 8;
161
    case CODEC_ID_MP3LAME:
162
        *au_ssize = 1;
163
        *au_scale = 1;
164
        *au_byterate = stream->bit_rate / 8;    
165
    default:
166
        *au_ssize = 1;
167
        *au_scale = 1; 
168
        *au_byterate = stream->bit_rate / 8;
169
        break;
170
    }
171
}
172

    
173
static int avi_write_header(AVFormatContext *s)
174
{
175
    AVIContext *avi = s->priv_data;
176
    ByteIOContext *pb = &s->pb;
177
    int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
178
    AVCodecContext *stream, *video_enc;
179
    offset_t list1, list2, strh, strf;
180

    
181
    put_tag(pb, "RIFF");
182
    put_le32(pb, 0); /* file length */
183
    put_tag(pb, "AVI ");
184

    
185
    /* header list */
186
    list1 = start_tag(pb, "LIST");
187
    put_tag(pb, "hdrl");
188

    
189
    /* avi header */
190
    put_tag(pb, "avih");
191
    put_le32(pb, 14 * 4);
192
    bitrate = 0;
193

    
194
    video_enc = NULL;
195
    for(n=0;n<s->nb_streams;n++) {
196
        stream = &s->streams[n]->codec;
197
        bitrate += stream->bit_rate;
198
        if (stream->codec_type == CODEC_TYPE_VIDEO)
199
            video_enc = stream;
200
    }
201
    
202
    if (!video_enc) {
203
        av_free(avi);
204
        return -1;
205
    }
206
    nb_frames = 0;
207

    
208
    put_le32(pb, (UINT32)(INT64_C(1000000) * FRAME_RATE_BASE / video_enc->frame_rate));
209
    put_le32(pb, bitrate / 8); /* XXX: not quite exact */
210
    put_le32(pb, 0); /* padding */
211
    put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
212
    avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */
213
    put_le32(pb, nb_frames); /* nb frames, filled later */
214
    put_le32(pb, 0); /* initial frame */
215
    put_le32(pb, s->nb_streams); /* nb streams */
216
    put_le32(pb, 1024 * 1024); /* suggested buffer size */
217
    put_le32(pb, video_enc->width);
218
    put_le32(pb, video_enc->height);
219
    put_le32(pb, 0); /* reserved */
220
    put_le32(pb, 0); /* reserved */
221
    put_le32(pb, 0); /* reserved */
222
    put_le32(pb, 0); /* reserved */
223
    
224
    /* stream list */
225
    for(i=0;i<n;i++) {
226
        list2 = start_tag(pb, "LIST");
227
        put_tag(pb, "strl");
228
    
229
        stream = &s->streams[i]->codec;
230

    
231
        /* stream generic header */
232
        strh = start_tag(pb, "strh");
233
        switch(stream->codec_type) {
234
        case CODEC_TYPE_VIDEO:
235
            put_tag(pb, "vids");
236
            put_le32(pb, codec_get_bmp_tag(stream->codec_id));
237
            put_le32(pb, 0); /* flags */
238
            put_le16(pb, 0); /* priority */
239
            put_le16(pb, 0); /* language */
240
            put_le32(pb, 0); /* initial frame */
241
            put_le32(pb, 1000); /* scale */
242
            put_le32(pb, (1000 * stream->frame_rate) / FRAME_RATE_BASE); /* rate */
243
            put_le32(pb, 0); /* start */
244
            avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
245
            put_le32(pb, nb_frames); /* length, XXX: fill later */
246
            put_le32(pb, 1024 * 1024); /* suggested buffer size */
247
            put_le32(pb, -1); /* quality */
248
            put_le32(pb, stream->width * stream->height * 3); /* sample size */
249
            put_le16(pb, 0);
250
            put_le16(pb, 0);
251
            put_le16(pb, stream->width);
252
            put_le16(pb, stream->height);
253
            break;
254
        case CODEC_TYPE_AUDIO:
255
            put_tag(pb, "auds");
256
            put_le32(pb, 1); /* tag */
257
            put_le32(pb, 0); /* flags */
258
            put_le16(pb, 0); /* priority */
259
            put_le16(pb, 0); /* language */
260
            put_le32(pb, 0); /* initial frame */
261
            parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
262
            put_le32(pb, au_scale); /* scale */
263
            put_le32(pb, au_byterate); /* rate */
264
            put_le32(pb, 0); /* start */
265
            avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
266
            put_le32(pb, 0); /* length, XXX: filled later */
267
            put_le32(pb, 12 * 1024); /* suggested buffer size */
268
            put_le32(pb, -1); /* quality */
269
            put_le32(pb, au_ssize); /* sample size */
270
            put_le32(pb, 0);
271
            put_le32(pb, 0);
272
            break;
273
        default:
274
            av_abort();
275
        }
276
        end_tag(pb, strh);
277

    
278
        strf = start_tag(pb, "strf");
279
        switch(stream->codec_type) {
280
        case CODEC_TYPE_VIDEO:
281
            put_bmp_header(pb, stream, codec_bmp_tags, 0);
282
            break;
283
        case CODEC_TYPE_AUDIO:
284
            if (put_wav_header(pb, stream) < 0) {
285
                av_free(avi);
286
                return -1;
287
            }
288
            break;
289
        default:
290
            av_abort();
291
        }
292
        end_tag(pb, strf);
293
        end_tag(pb, list2);
294
    }
295

    
296
    end_tag(pb, list1);
297
    
298
    avi->movi_list = start_tag(pb, "LIST");
299
    avi->first = NULL;
300
    avi->last = NULL;
301
    put_tag(pb, "movi");
302

    
303
    put_flush_packet(pb);
304

    
305
    return 0;
306
}
307

    
308
static int avi_write_packet(AVFormatContext *s, int stream_index,
309
                            UINT8 *buf, int size, int force_pts)
310
{
311
    AVIContext *avi = s->priv_data;
312
    ByteIOContext *pb = &s->pb;
313
    AVIIndex *idx;
314
    unsigned char tag[5];
315
    unsigned int flags;
316
    AVCodecContext *enc;
317
    
318
    enc = &s->streams[stream_index]->codec;
319

    
320
    tag[0] = '0';
321
    tag[1] = '0' + stream_index;
322
    if (enc->codec_type == CODEC_TYPE_VIDEO) {
323
        tag[2] = 'd';
324
        tag[3] = 'c';
325
        flags = enc->coded_frame->key_frame ? 0x10 : 0x00;
326
    } else {
327
        tag[2] = 'w';
328
        tag[3] = 'b';
329
        flags = 0x10;
330
    }
331
    if (enc->codec_type == CODEC_TYPE_AUDIO) 
332
       avi->audio_strm_length[stream_index] += size;
333

    
334
    if (!url_is_streamed(&s->pb)) {
335
        idx = av_malloc(sizeof(AVIIndex));
336
        memcpy(idx->tag, tag, 4);
337
        idx->flags = flags;
338
        idx->pos = url_ftell(pb) - avi->movi_list;
339
        idx->len = size;
340
        idx->next = NULL;
341
        if (!avi->last)
342
            avi->first = idx;
343
        else
344
            avi->last->next = idx;
345
        avi->last = idx;
346
    }
347
    
348
    put_buffer(pb, tag, 4);
349
    put_le32(pb, size);
350
    put_buffer(pb, buf, size);
351
    if (size & 1)
352
        put_byte(pb, 0);
353

    
354
    put_flush_packet(pb);
355
    return 0;
356
}
357

    
358
static int avi_write_trailer(AVFormatContext *s)
359
{
360
    ByteIOContext *pb = &s->pb;
361
    AVIContext *avi = s->priv_data;
362
    offset_t file_size, idx_chunk;
363
    int n, nb_frames, au_byterate, au_ssize, au_scale;
364
    AVCodecContext *stream;
365
    AVIIndex *idx;
366

    
367
    if (!url_is_streamed(&s->pb)) {
368
        end_tag(pb, avi->movi_list);
369

    
370
        idx_chunk = start_tag(pb, "idx1");
371
        idx = avi->first;
372
        while (idx != NULL) {
373
            put_buffer(pb, idx->tag, 4);
374
            put_le32(pb, idx->flags);
375
            put_le32(pb, idx->pos);
376
            put_le32(pb, idx->len);
377
            idx = idx->next;
378
        }
379
        end_tag(pb, idx_chunk);
380
        
381
        /* update file size */
382
        file_size = url_ftell(pb);
383
        url_fseek(pb, 4, SEEK_SET);
384
        put_le32(pb, (UINT32)(file_size - 8));
385

    
386
        /* Fill in frame/sample counters */
387
        nb_frames = 0;
388
        for(n=0;n<s->nb_streams;n++) {
389
            if (avi->frames_hdr_strm[n] != 0) {
390
                stream = &s->streams[n]->codec;
391
                url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET);
392
                if (stream->codec_type == CODEC_TYPE_VIDEO) {
393
                    put_le32(pb, stream->frame_number); 
394
                    if (nb_frames < stream->frame_number)
395
                        nb_frames = stream->frame_number;
396
                } else {
397
                    if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3LAME) {
398
                        put_le32(pb, stream->frame_number);
399
                        nb_frames += stream->frame_number;
400
                    } else {
401
                        parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
402
                        put_le32(pb, avi->audio_strm_length[n] / au_ssize);
403
                    }
404
                }
405
            }
406
       }
407
       if (avi->frames_hdr_all != 0) {
408
           url_fseek(pb, avi->frames_hdr_all, SEEK_SET);
409
           put_le32(pb, nb_frames); 
410
       }
411
        url_fseek(pb, file_size, SEEK_SET);
412
    }
413
    put_flush_packet(pb);
414
    return 0;
415
}
416

    
417
static AVOutputFormat avi_oformat = {
418
    "avi",
419
    "avi format",
420
    "video/x-msvideo",
421
    "avi",
422
    sizeof(AVIContext),
423
    CODEC_ID_MP2,
424
    CODEC_ID_MSMPEG4V3,
425
    avi_write_header,
426
    avi_write_packet,
427
    avi_write_trailer,
428
};
429

    
430
int avienc_init(void)
431
{
432
    av_register_output_format(&avi_oformat);
433
    return 0;
434
}