]> git.sesse.net Git - vlc/blob - modules/mux/avi.c
Replace argument = realloc( argument, size ); with realloc_or_free() in modules/...
[vlc] / modules / mux / avi.c
1 /*****************************************************************************
2  * avi.c
3  *****************************************************************************
4  * Copyright (C) 2001-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 /* TODO: add OpenDML write support */
28
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <assert.h>
35
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_sout.h>
39 #include <vlc_block.h>
40 #include <vlc_codecs.h>
41 #include <vlc_memory.h>
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open   ( vlc_object_t * );
47 static void Close  ( vlc_object_t * );
48
49 vlc_module_begin ()
50     set_description( N_("AVI muxer") )
51     set_category( CAT_SOUT )
52     set_subcategory( SUBCAT_SOUT_MUX )
53     set_capability( "sout mux", 5 )
54     add_shortcut( "avi" )
55     set_callbacks( Open, Close )
56 vlc_module_end ()
57
58
59 /*****************************************************************************
60  * Local prototypes
61  *****************************************************************************/
62 static int Control( sout_mux_t *, int, va_list );
63 static int AddStream( sout_mux_t *, sout_input_t * );
64 static int DelStream( sout_mux_t *, sout_input_t * );
65 static int Mux      ( sout_mux_t * );
66
67 typedef struct avi_stream_s
68 {
69     int i_cat;
70
71     char fcc[4];
72
73     mtime_t i_duration;       // in µs
74
75     int     i_frames;        // total frame count
76     int64_t i_totalsize;    // total stream size
77
78     float   f_fps;
79     int     i_bitrate;
80
81     BITMAPINFOHEADER    *p_bih;
82     WAVEFORMATEX        *p_wf;
83
84 } avi_stream_t;
85
86 typedef struct avi_idx1_entry_s
87 {
88     char     fcc[4];
89     uint32_t i_flags;
90     uint32_t i_pos;
91     uint32_t i_length;
92
93 } avi_idx1_entry_t;
94
95 typedef struct avi_idx1_s
96 {
97     unsigned int i_entry_count;
98     unsigned int i_entry_max;
99
100     avi_idx1_entry_t *entry;
101 } avi_idx1_t;
102
103 struct sout_mux_sys_t
104 {
105     bool b_write_header;
106
107     int i_streams;
108     int i_stream_video;
109
110     off_t i_movi_size;
111     avi_stream_t stream[100];
112
113     avi_idx1_t idx1;
114     off_t i_idx1_size;
115
116 };
117
118 // FIXME FIXME
119 #define HDR_SIZE 10240
120
121 /* Flags in avih */
122 #define AVIF_HASINDEX       0x00000010  // Index at end of file?
123 #define AVIF_ISINTERLEAVED  0x00000100
124 #define AVIF_TRUSTCKTYPE    0x00000800  // Use CKType to find key frames?
125
126 /* Flags for index */
127 #define AVIIF_KEYFRAME      0x00000010L /* this frame is a key frame.*/
128
129
130 static block_t *avi_HeaderCreateRIFF( sout_mux_t * );
131 static block_t *avi_HeaderCreateidx1( sout_mux_t * );
132
133 static void SetFCC( uint8_t *p, char *fcc )
134 {
135     memcpy( p, fcc, 4 );
136 }
137
138 /*****************************************************************************
139  * Open:
140  *****************************************************************************/
141 static int Open( vlc_object_t *p_this )
142 {
143     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
144     sout_mux_sys_t  *p_sys;
145
146     msg_Dbg( p_mux, "AVI muxer opened" );
147
148     p_sys = malloc( sizeof( sout_mux_sys_t ) );
149     if( !p_sys )
150         return VLC_ENOMEM;
151     p_sys->i_streams = 0;
152     p_sys->i_stream_video = -1;
153     p_sys->i_movi_size = 0;
154
155     p_sys->idx1.i_entry_count = 0;
156     p_sys->idx1.i_entry_max = 10000;
157     p_sys->idx1.entry = calloc( p_sys->idx1.i_entry_max,
158                                 sizeof( avi_idx1_entry_t ) );
159     if( !p_sys->idx1.entry )
160     {
161         free( p_sys );
162         return VLC_ENOMEM;
163     }
164     p_sys->b_write_header = true;
165
166
167     p_mux->pf_control   = Control;
168     p_mux->pf_addstream = AddStream;
169     p_mux->pf_delstream = DelStream;
170     p_mux->pf_mux       = Mux;
171     p_mux->p_sys        = p_sys;
172
173     return VLC_SUCCESS;
174 }
175
176 /*****************************************************************************
177  * Close:
178  *****************************************************************************/
179 static void Close( vlc_object_t * p_this )
180 {
181     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
182     sout_mux_sys_t  *p_sys = p_mux->p_sys;
183
184     block_t       *p_hdr, *p_idx1;
185     int                 i_stream;
186
187     msg_Dbg( p_mux, "AVI muxer closed" );
188
189     /* first create idx1 chunk (write at the end of the stream */
190     p_idx1 = avi_HeaderCreateidx1( p_mux );
191     p_sys->i_idx1_size = p_idx1->i_buffer;
192     sout_AccessOutWrite( p_mux->p_access, p_idx1 );
193
194     /* calculate some value for headers creations */
195     for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
196     {
197         avi_stream_t *p_stream;
198
199         p_stream = &p_sys->stream[i_stream];
200
201         p_stream->f_fps = 25;
202         if( p_stream->i_duration > 0 )
203         {
204             p_stream->f_fps = (float)p_stream->i_frames /
205                               ( (float)p_stream->i_duration /
206                                 (float)1000000 );
207         }
208         p_stream->i_bitrate = 128 * 1024;
209         if( p_stream->i_duration > 0 )
210         {
211             p_stream->i_bitrate =
212                 8 * (uint64_t)1000000 *
213                     (uint64_t)p_stream->i_totalsize /
214                     (uint64_t)p_stream->i_duration;
215         }
216         msg_Info( p_mux, "stream[%d] duration:%"PRId64" totalsize:%"PRId64
217                   " frames:%d fps:%f kb/s:%d",
218                   i_stream,
219                   (int64_t)p_stream->i_duration / (int64_t)1000000,
220                   p_stream->i_totalsize,
221                   p_stream->i_frames,
222                   p_stream->f_fps, p_stream->i_bitrate/1024 );
223     }
224
225     p_hdr = avi_HeaderCreateRIFF( p_mux );
226     sout_AccessOutSeek( p_mux->p_access, 0 );
227     sout_AccessOutWrite( p_mux->p_access, p_hdr );
228 }
229
230 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
231 {
232     VLC_UNUSED(p_mux);
233     bool *pb_bool;
234     char **ppsz;
235
236    switch( i_query )
237    {
238        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
239            pb_bool = (bool*)va_arg( args, bool * );
240            *pb_bool = false;
241            return VLC_SUCCESS;
242
243        case MUX_GET_ADD_STREAM_WAIT:
244            pb_bool = (bool*)va_arg( args, bool * );
245            *pb_bool = true;
246            return VLC_SUCCESS;
247
248        case MUX_GET_MIME:
249            ppsz = (char**)va_arg( args, char ** );
250            *ppsz = strdup( "video/avi" );
251            return VLC_SUCCESS;
252
253         default:
254             return VLC_EGENERIC;
255    }
256 }
257
258 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
259 {
260     sout_mux_sys_t  *p_sys = p_mux->p_sys;
261     avi_stream_t    *p_stream;
262
263     if( p_sys->i_streams >= 100 )
264     {
265         msg_Err( p_mux, "too many streams" );
266         return VLC_EGENERIC;
267     }
268
269     msg_Dbg( p_mux, "adding input" );
270     p_input->p_sys = malloc( sizeof( int ) );
271     if( !p_input->p_sys )
272         return VLC_ENOMEM;
273
274     *((int*)p_input->p_sys) = p_sys->i_streams;
275     p_stream = &p_sys->stream[p_sys->i_streams];
276
277     switch( p_input->p_fmt->i_cat )
278     {
279         case AUDIO_ES:
280             p_stream->i_cat = AUDIO_ES;
281             p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
282             p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
283             p_stream->fcc[2] = 'w';
284             p_stream->fcc[3] = 'b';
285
286             p_stream->p_bih = NULL;
287
288             p_stream->p_wf  = malloc( sizeof( WAVEFORMATEX ) +
289                                       p_input->p_fmt->i_extra );
290             if( !p_stream->p_wf )
291             {
292                 free( p_input->p_sys );
293                 return VLC_ENOMEM;
294             }
295 #define p_wf p_stream->p_wf
296             p_wf->cbSize = p_input->p_fmt->i_extra;
297             if( p_wf->cbSize > 0 )
298             {
299                 memcpy( &p_wf[1],
300                         p_input->p_fmt->p_extra,
301                         p_input->p_fmt->i_extra );
302             }
303             p_wf->nChannels      = p_input->p_fmt->audio.i_channels;
304             p_wf->nSamplesPerSec = p_input->p_fmt->audio.i_rate;
305             p_wf->nBlockAlign    = p_input->p_fmt->audio.i_blockalign;
306             p_wf->nAvgBytesPerSec= p_input->p_fmt->i_bitrate / 8;
307             p_wf->wBitsPerSample = 0;
308
309             switch( p_input->p_fmt->i_codec )
310             {
311                 case VLC_CODEC_A52:
312                     p_wf->wFormatTag = WAVE_FORMAT_A52;
313                     break;
314                 case VLC_CODEC_MPGA:
315                     p_wf->wFormatTag = WAVE_FORMAT_MPEGLAYER3;
316                     break;
317                 case VLC_CODEC_WMA1:
318                     p_wf->wFormatTag = WAVE_FORMAT_WMA1;
319                     break;
320                 case VLC_CODEC_WMA2:
321                     p_wf->wFormatTag = WAVE_FORMAT_WMA2;
322                     break;
323                 case VLC_CODEC_WMAP:
324                     p_wf->wFormatTag = WAVE_FORMAT_WMAP;
325                     break;
326                 case VLC_CODEC_WMAL:
327                     p_wf->wFormatTag = WAVE_FORMAT_WMAL;
328                     break;
329                     /* raw codec */
330                 case VLC_CODEC_U8:
331                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
332                     p_wf->nBlockAlign= p_wf->nChannels;
333                     p_wf->wBitsPerSample = 8;
334                     break;
335                 case VLC_CODEC_S16L:
336                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
337                     p_wf->nBlockAlign= 2 * p_wf->nChannels;
338                     p_wf->wBitsPerSample = 16;
339                     break;
340                 case VLC_CODEC_S24L:
341                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
342                     p_wf->nBlockAlign= 3 * p_wf->nChannels;
343                     p_wf->wBitsPerSample = 24;
344                     break;
345                 case VLC_CODEC_S32L:
346                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
347                     p_wf->nBlockAlign= 4 * p_wf->nChannels;
348                     p_wf->wBitsPerSample = 32;
349                     break;
350                 default:
351                     return VLC_EGENERIC;
352             }
353 #undef p_wf
354             break;
355         case VIDEO_ES:
356             p_stream->i_cat = VIDEO_ES;
357             p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
358             p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
359             p_stream->fcc[2] = 'd';
360             p_stream->fcc[3] = 'c';
361             if( p_sys->i_stream_video < 0 )
362             {
363                 p_sys->i_stream_video = p_sys->i_streams;
364             }
365             p_stream->p_wf  = NULL;
366             p_stream->p_bih = malloc( sizeof( BITMAPINFOHEADER ) +
367                                       p_input->p_fmt->i_extra );
368             if( !p_stream->p_bih )
369             {
370                 free( p_input->p_sys );
371                 return VLC_ENOMEM;
372             }
373 #define p_bih p_stream->p_bih
374             p_bih->biSize  = sizeof( BITMAPINFOHEADER ) +
375                              p_input->p_fmt->i_extra;
376             if( p_input->p_fmt->i_extra > 0 )
377             {
378                 memcpy( &p_bih[1],
379                         p_input->p_fmt->p_extra,
380                         p_input->p_fmt->i_extra );
381             }
382             p_bih->biWidth = p_input->p_fmt->video.i_width;
383             p_bih->biHeight= p_input->p_fmt->video.i_height;
384             p_bih->biPlanes= 1;
385             p_bih->biBitCount       = 24;
386             p_bih->biSizeImage      = 0;
387             p_bih->biXPelsPerMeter  = 0;
388             p_bih->biYPelsPerMeter  = 0;
389             p_bih->biClrUsed        = 0;
390             p_bih->biClrImportant   = 0;
391             switch( p_input->p_fmt->i_codec )
392             {
393                 case VLC_CODEC_MP4V:
394                     p_bih->biCompression = VLC_FOURCC( 'X', 'V', 'I', 'D' );
395                     break;
396                 default:
397                     p_bih->biCompression = p_input->p_fmt->i_original_fourcc ?: p_input->p_fmt->i_codec;
398                     break;
399             }
400 #undef p_bih
401             break;
402         default:
403             return( VLC_EGENERIC );
404     }
405     p_stream->i_totalsize = 0;
406     p_stream->i_frames    = 0;
407     p_stream->i_duration  = 0;
408
409     /* fixed later */
410     p_stream->f_fps = 25;
411     p_stream->i_bitrate = 128 * 1024;
412
413     p_sys->i_streams++;
414     return( VLC_SUCCESS );
415 }
416
417 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
418 {
419     msg_Dbg( p_mux, "removing input" );
420
421     free( p_input->p_sys );
422     return 0;
423 }
424
425 static int Mux      ( sout_mux_t *p_mux )
426 {
427     sout_mux_sys_t  *p_sys = p_mux->p_sys;
428     avi_stream_t    *p_stream;
429     int i_stream, i;
430
431     if( p_sys->b_write_header )
432     {
433         block_t *p_hdr;
434
435         msg_Dbg( p_mux, "writing header" );
436
437         p_hdr = avi_HeaderCreateRIFF( p_mux );
438         sout_AccessOutWrite( p_mux->p_access, p_hdr );
439
440         p_sys->b_write_header = false;
441     }
442
443     for( i = 0; i < p_mux->i_nb_inputs; i++ )
444     {
445         int i_count;
446         block_fifo_t *p_fifo;
447
448         i_stream = *((int*)p_mux->pp_inputs[i]->p_sys );
449         p_stream = &p_sys->stream[i_stream];
450
451         p_fifo = p_mux->pp_inputs[i]->p_fifo;
452         i_count = block_FifoCount(  p_fifo );
453         while( i_count > 1 )
454         {
455             avi_idx1_entry_t *p_idx;
456             block_t *p_data;
457
458             p_data = block_FifoGet( p_fifo );
459             if( block_FifoCount( p_fifo ) > 0 )
460             {
461                 block_t *p_next = block_FifoShow( p_fifo );
462                 p_data->i_length = p_next->i_dts - p_data->i_dts;
463             }
464
465             p_stream->i_frames++;
466             if( p_data->i_length < 0 )
467             {
468                 msg_Warn( p_mux, "argg length < 0 l" );
469                 block_Release( p_data );
470                 i_count--;
471                 continue;
472             }
473             p_stream->i_duration  += p_data->i_length;
474             p_stream->i_totalsize += p_data->i_buffer;
475
476             /* add idx1 entry for this frame */
477             p_idx = &p_sys->idx1.entry[p_sys->idx1.i_entry_count];
478             memcpy( p_idx->fcc, p_stream->fcc, 4 );
479             p_idx->i_flags = 0;
480             if( ( p_data->i_flags & BLOCK_FLAG_TYPE_MASK ) == 0 || ( p_data->i_flags & BLOCK_FLAG_TYPE_I ) )
481                 p_idx->i_flags = AVIIF_KEYFRAME;
482             p_idx->i_pos   = p_sys->i_movi_size + 4;
483             p_idx->i_length= p_data->i_buffer;
484             p_sys->idx1.i_entry_count++;
485             if( p_sys->idx1.i_entry_count >= p_sys->idx1.i_entry_max )
486             {
487                 p_sys->idx1.i_entry_max += 10000;
488                 p_sys->idx1.entry = realloc_or_free( p_sys->idx1.entry,
489                        p_sys->idx1.i_entry_max * sizeof( avi_idx1_entry_t ) );
490                 assert( p_sys->idx1.entry );
491             }
492
493             p_data = block_Realloc( p_data, 8, p_data->i_buffer );
494             if( p_data )
495             {
496                 SetFCC( p_data->p_buffer, p_stream->fcc );
497                 SetDWLE( p_data->p_buffer + 4, p_data->i_buffer - 8 );
498
499                 if( p_data->i_buffer & 0x01 )
500                 {
501                     p_data = block_Realloc( p_data, 0, p_data->i_buffer + 1 );
502                     p_data->p_buffer[ p_data->i_buffer - 1 ] = '\0';
503                 }
504
505                 p_sys->i_movi_size += p_data->i_buffer;
506                 sout_AccessOutWrite( p_mux->p_access, p_data );
507             }
508
509             i_count--;
510         }
511
512     }
513     return( 0 );
514 }
515
516 /****************************************************************************/
517 /****************************************************************************/
518 /****************************************************************************/
519 /****************************************************************************/
520
521 typedef struct buffer_out_s
522 {
523     int      i_buffer_size;
524     int      i_buffer;
525     uint8_t  *p_buffer;
526
527 } buffer_out_t;
528
529 static void bo_Init( buffer_out_t *p_bo, int i_size, uint8_t *p_buffer )
530 {
531     p_bo->i_buffer_size = i_size;
532     p_bo->i_buffer = 0;
533     p_bo->p_buffer = p_buffer;
534 }
535 static void bo_AddByte( buffer_out_t *p_bo, uint8_t i )
536 {
537     if( p_bo->i_buffer < p_bo->i_buffer_size )
538     {
539         p_bo->p_buffer[p_bo->i_buffer] = i;
540     }
541     p_bo->i_buffer++;
542 }
543 static void bo_AddWordLE( buffer_out_t *p_bo, uint16_t i )
544 {
545     bo_AddByte( p_bo, i &0xff );
546     bo_AddByte( p_bo, ( ( i >> 8) &0xff ) );
547 }
548 static void bo_AddWordBE( buffer_out_t *p_bo, uint16_t i )
549 {
550     bo_AddByte( p_bo, ( ( i >> 8) &0xff ) );
551     bo_AddByte( p_bo, i &0xff );
552 }
553 static void bo_AddDWordLE( buffer_out_t *p_bo, uint32_t i )
554 {
555     bo_AddWordLE( p_bo, i &0xffff );
556     bo_AddWordLE( p_bo, ( ( i >> 16) &0xffff ) );
557 }
558 static void bo_AddDWordBE( buffer_out_t *p_bo, uint32_t i )
559 {
560     bo_AddWordBE( p_bo, ( ( i >> 16) &0xffff ) );
561     bo_AddWordBE( p_bo, i &0xffff );
562 }
563 #if 0
564 static void bo_AddLWordLE( buffer_out_t *p_bo, uint64_t i )
565 {
566     bo_AddDWordLE( p_bo, i &0xffffffff );
567     bo_AddDWordLE( p_bo, ( ( i >> 32) &0xffffffff ) );
568 }
569 static void bo_AddLWordBE( buffer_out_t *p_bo, uint64_t i )
570 {
571     bo_AddDWordBE( p_bo, ( ( i >> 32) &0xffffffff ) );
572     bo_AddDWordBE( p_bo, i &0xffffffff );
573 }
574 #endif
575
576 static void bo_AddFCC( buffer_out_t *p_bo, const char *fcc )
577 {
578     bo_AddByte( p_bo, fcc[0] );
579     bo_AddByte( p_bo, fcc[1] );
580     bo_AddByte( p_bo, fcc[2] );
581     bo_AddByte( p_bo, fcc[3] );
582 }
583
584 static void bo_AddMem( buffer_out_t *p_bo, int i_size, uint8_t *p_mem )
585 {
586     int i;
587
588     for( i = 0; i < i_size; i++ )
589     {
590         bo_AddByte( p_bo, p_mem[i] );
591     }
592 }
593
594 /****************************************************************************
595  ****************************************************************************
596  **
597  ** avi header generation
598  **
599  ****************************************************************************
600  ****************************************************************************/
601 #define AVI_BOX_ENTER( fcc ) \
602     buffer_out_t _bo_sav_; \
603     bo_AddFCC( p_bo, fcc ); \
604     _bo_sav_ = *p_bo; \
605     bo_AddDWordLE( p_bo, 0 )
606
607 #define AVI_BOX_ENTER_LIST( fcc ) \
608     AVI_BOX_ENTER( "LIST" ); \
609     bo_AddFCC( p_bo, fcc )
610
611 #define AVI_BOX_EXIT( i_err ) \
612     if( p_bo->i_buffer&0x01 ) bo_AddByte( p_bo, 0 ); \
613     bo_AddDWordLE( &_bo_sav_, p_bo->i_buffer - _bo_sav_.i_buffer - 4 ); \
614     return( i_err );
615
616 static int avi_HeaderAdd_avih( sout_mux_t *p_mux,
617                                buffer_out_t *p_bo )
618 {
619     sout_mux_sys_t  *p_sys = p_mux->p_sys;
620     avi_stream_t    *p_video = NULL;
621     int         i_stream;
622     uint32_t    i_microsecperframe;
623     int         i_maxbytespersec;
624     int         i_totalframes;
625     AVI_BOX_ENTER( "avih" );
626
627     if( p_sys->i_stream_video >= 0 )
628     {
629         p_video = &p_sys->stream[p_sys->i_stream_video];
630         if( p_video->i_frames <= 0 )
631         {
632         //    p_video = NULL;
633         }
634     }
635
636     if( p_video )
637     {
638         i_microsecperframe =
639             (uint32_t)( (float)1000000 /
640                         (float)p_sys->stream[p_sys->i_stream_video].f_fps );
641         i_totalframes = p_sys->stream[p_sys->i_stream_video].i_frames;
642     }
643     else
644     {
645         msg_Warn( p_mux, "avi file without video track isn't a good idea..." );
646         i_microsecperframe = 0;
647         i_totalframes = 0;
648     }
649
650     for( i_stream = 0,i_maxbytespersec = 0; i_stream < p_sys->i_streams; i_stream++ )
651     {
652         if( p_sys->stream[i_stream].i_duration > 0 )
653         {
654             i_maxbytespersec +=
655                 p_sys->stream[i_stream].i_totalsize /
656                 p_sys->stream[i_stream].i_duration;
657         }
658     }
659
660     bo_AddDWordLE( p_bo, i_microsecperframe );
661     bo_AddDWordLE( p_bo, i_maxbytespersec );
662     bo_AddDWordLE( p_bo, 0 );                   /* padding */
663     bo_AddDWordLE( p_bo, AVIF_TRUSTCKTYPE |
664                          AVIF_HASINDEX |
665                          AVIF_ISINTERLEAVED );  /* flags */
666     bo_AddDWordLE( p_bo, i_totalframes );
667     bo_AddDWordLE( p_bo, 0 );                   /* initial frame */
668     bo_AddDWordLE( p_bo, p_sys->i_streams );    /* streams count */
669     bo_AddDWordLE( p_bo, 1024 * 1024 );         /* suggested buffer size */
670     if( p_video )
671     {
672         bo_AddDWordLE( p_bo, p_video->p_bih->biWidth );
673         bo_AddDWordLE( p_bo, p_video->p_bih->biHeight );
674     }
675     else
676     {
677         bo_AddDWordLE( p_bo, 0 );
678         bo_AddDWordLE( p_bo, 0 );
679     }
680     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
681     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
682     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
683     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
684
685     AVI_BOX_EXIT( 0 );
686 }
687 static int avi_HeaderAdd_strh( buffer_out_t *p_bo, avi_stream_t *p_stream )
688 {
689     AVI_BOX_ENTER( "strh" );
690
691     switch( p_stream->i_cat )
692     {
693         case VIDEO_ES:
694             {
695                 bo_AddFCC( p_bo, "vids" );
696                 bo_AddDWordBE( p_bo, p_stream->p_bih->biCompression );
697                 bo_AddDWordLE( p_bo, 0 );   /* flags */
698                 bo_AddWordLE(  p_bo, 0 );   /* priority */
699                 bo_AddWordLE(  p_bo, 0 );   /* langage */
700                 bo_AddDWordLE( p_bo, 0 );   /* initial frame */
701                 bo_AddDWordLE( p_bo, 1000 );/* scale */
702                 bo_AddDWordLE( p_bo, (uint32_t)( 1000 * p_stream->f_fps ));
703                 bo_AddDWordLE( p_bo, 0 );   /* start */
704                 bo_AddDWordLE( p_bo, p_stream->i_frames );
705                 bo_AddDWordLE( p_bo, 1024 * 1024 );
706                 bo_AddDWordLE( p_bo, -1 );  /* quality */
707                 bo_AddDWordLE( p_bo, 0 );   /* samplesize */
708                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
709                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
710                 bo_AddWordLE(  p_bo, p_stream->p_bih->biWidth );
711                 bo_AddWordLE(  p_bo, p_stream->p_bih->biHeight );
712             }
713             break;
714         case AUDIO_ES:
715             {
716                 int i_rate, i_scale, i_samplesize;
717
718                 i_samplesize = p_stream->p_wf->nBlockAlign;
719                 if( i_samplesize > 1 )
720                 {
721                     i_scale = i_samplesize;
722                     i_rate = /*i_scale **/ p_stream->i_bitrate / 8;
723                 }
724                 else
725                 {
726                     i_samplesize = 1;
727                     i_scale = 1000;
728                     i_rate = 1000 * p_stream->i_bitrate / 8;
729                 }
730                 bo_AddFCC( p_bo, "auds" );
731                 bo_AddDWordLE( p_bo, 0 );   /* tag */
732                 bo_AddDWordLE( p_bo, 0 );   /* flags */
733                 bo_AddWordLE(  p_bo, 0 );   /* priority */
734                 bo_AddWordLE(  p_bo, 0 );   /* langage */
735                 bo_AddDWordLE( p_bo, 0 );   /* initial frame */
736                 bo_AddDWordLE( p_bo, i_scale );/* scale */
737                 bo_AddDWordLE( p_bo, i_rate );
738                 bo_AddDWordLE( p_bo, 0 );   /* start */
739                 bo_AddDWordLE( p_bo, p_stream->i_frames );
740                 bo_AddDWordLE( p_bo, 10 * 1024 );
741                 bo_AddDWordLE( p_bo, -1 );  /* quality */
742                 bo_AddDWordLE( p_bo, i_samplesize );
743                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
744                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
745                 bo_AddWordLE(  p_bo, 0 );
746                 bo_AddWordLE(  p_bo, 0 );
747             }
748             break;
749     }
750
751     AVI_BOX_EXIT( 0 );
752 }
753
754 static int avi_HeaderAdd_strf( buffer_out_t *p_bo, avi_stream_t *p_stream )
755 {
756     AVI_BOX_ENTER( "strf" );
757
758     switch( p_stream->i_cat )
759     {
760         case AUDIO_ES:
761             bo_AddWordLE( p_bo, p_stream->p_wf->wFormatTag );
762             bo_AddWordLE( p_bo, p_stream->p_wf->nChannels );
763             bo_AddDWordLE( p_bo, p_stream->p_wf->nSamplesPerSec );
764             bo_AddDWordLE( p_bo, p_stream->p_wf->nAvgBytesPerSec );
765             bo_AddWordLE( p_bo, p_stream->p_wf->nBlockAlign );
766             bo_AddWordLE( p_bo, p_stream->p_wf->wBitsPerSample );
767             bo_AddWordLE( p_bo, p_stream->p_wf->cbSize );
768             bo_AddMem( p_bo, p_stream->p_wf->cbSize, (uint8_t*)&p_stream->p_wf[1] );
769             break;
770         case VIDEO_ES:
771             bo_AddDWordLE( p_bo, p_stream->p_bih->biSize );
772             bo_AddDWordLE( p_bo, p_stream->p_bih->biWidth );
773             bo_AddDWordLE( p_bo, p_stream->p_bih->biHeight );
774             bo_AddWordLE( p_bo, p_stream->p_bih->biPlanes );
775             bo_AddWordLE( p_bo, p_stream->p_bih->biBitCount );
776             if( VLC_FOURCC( 0, 0, 0, 1 ) == 0x00000001 )
777             {
778                 bo_AddDWordBE( p_bo, p_stream->p_bih->biCompression );
779             }
780             else
781             {
782                 bo_AddDWordLE( p_bo, p_stream->p_bih->biCompression );
783             }
784             bo_AddDWordLE( p_bo, p_stream->p_bih->biSizeImage );
785             bo_AddDWordLE( p_bo, p_stream->p_bih->biXPelsPerMeter );
786             bo_AddDWordLE( p_bo, p_stream->p_bih->biYPelsPerMeter );
787             bo_AddDWordLE( p_bo, p_stream->p_bih->biClrUsed );
788             bo_AddDWordLE( p_bo, p_stream->p_bih->biClrImportant );
789             bo_AddMem( p_bo,
790                        p_stream->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
791                        (uint8_t*)&p_stream->p_bih[1] );
792             break;
793     }
794
795     AVI_BOX_EXIT( 0 );
796 }
797
798 static int avi_HeaderAdd_strl( buffer_out_t *p_bo, avi_stream_t *p_stream )
799 {
800     AVI_BOX_ENTER_LIST( "strl" );
801
802     avi_HeaderAdd_strh( p_bo, p_stream );
803     avi_HeaderAdd_strf( p_bo, p_stream );
804
805     AVI_BOX_EXIT( 0 );
806 }
807
808 static block_t *avi_HeaderCreateRIFF( sout_mux_t *p_mux )
809 {
810     sout_mux_sys_t      *p_sys = p_mux->p_sys;
811     block_t       *p_hdr;
812     int                 i_stream;
813     int                 i_junk;
814     buffer_out_t        bo;
815
816     p_hdr = block_New( p_mux, HDR_SIZE );
817     memset( p_hdr->p_buffer, 0, HDR_SIZE );
818
819     bo_Init( &bo, HDR_SIZE, p_hdr->p_buffer );
820
821     bo_AddFCC( &bo, "RIFF" );
822     bo_AddDWordLE( &bo, p_sys->i_movi_size + HDR_SIZE - 8 + p_sys->i_idx1_size );
823     bo_AddFCC( &bo, "AVI " );
824
825     bo_AddFCC( &bo, "LIST" );
826     bo_AddDWordLE( &bo, HDR_SIZE - 8);
827     bo_AddFCC( &bo, "hdrl" );
828
829     avi_HeaderAdd_avih( p_mux, &bo );
830     for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
831     {
832         avi_HeaderAdd_strl( &bo, &p_sys->stream[i_stream] );
833     }
834
835     i_junk = HDR_SIZE - bo.i_buffer - 8 - 12;
836     bo_AddFCC( &bo, "JUNK" );
837     bo_AddDWordLE( &bo, i_junk );
838
839     bo.i_buffer += i_junk;
840     bo_AddFCC( &bo, "LIST" );
841     bo_AddDWordLE( &bo, p_sys->i_movi_size + 4 );
842     bo_AddFCC( &bo, "movi" );
843
844     return( p_hdr );
845 }
846
847 static block_t * avi_HeaderCreateidx1( sout_mux_t *p_mux )
848 {
849     sout_mux_sys_t      *p_sys = p_mux->p_sys;
850     block_t       *p_idx1;
851     uint32_t            i_idx1_size;
852     unsigned int        i;
853     buffer_out_t        bo;
854
855     i_idx1_size = 16 * p_sys->idx1.i_entry_count;
856
857     p_idx1 = block_New( p_mux, i_idx1_size + 8 );
858     memset( p_idx1->p_buffer, 0, i_idx1_size );
859
860     bo_Init( &bo, i_idx1_size, p_idx1->p_buffer );
861     bo_AddFCC( &bo, "idx1" );
862     bo_AddDWordLE( &bo, i_idx1_size );
863
864     for( i = 0; i < p_sys->idx1.i_entry_count; i++ )
865     {
866         bo_AddFCC( &bo, p_sys->idx1.entry[i].fcc );
867         bo_AddDWordLE( &bo, p_sys->idx1.entry[i].i_flags );
868         bo_AddDWordLE( &bo, p_sys->idx1.entry[i].i_pos );
869         bo_AddDWordLE( &bo, p_sys->idx1.entry[i].i_length );
870     }
871
872     return( p_idx1 );
873 }
874