Win32: add a new build-script helper
[vlc.git] / modules / mux / avi.c
blobb4a55a2a756b3a4ee4ef051c8d5e86d3355ed5b6
1 /*****************************************************************************
2 * avi.c
3 *****************************************************************************
4 * Copyright (C) 2001-2009 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 /* TODO: add OpenDML write support */
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_sout.h>
37 #include <vlc_block.h>
38 #include <vlc_codecs.h>
39 #include <vlc_boxes.h>
41 /*****************************************************************************
42 * Module descriptor
43 *****************************************************************************/
44 static int Open ( vlc_object_t * );
45 static void Close ( vlc_object_t * );
47 #define SOUT_CFG_PREFIX "sout-avi-"
49 #define CFG_ARTIST_TEXT N_("Artist")
50 #define CFG_DATE_TEXT N_("Date")
51 #define CFG_GENRE_TEXT N_("Genre")
52 #define CFG_COPYRIGHT_TEXT N_("Copyright")
53 #define CFG_COMMENT_TEXT N_("Comment")
54 #define CFG_NAME_TEXT N_("Name")
55 #define CFG_SUBJECT_TEXT N_("Subject")
56 #define CFG_ENCODER_TEXT N_("Encoder")
57 #define CFG_KEYWORDS_TEXT N_("Keywords")
59 vlc_module_begin ()
60 set_description( N_("AVI muxer") )
61 set_category( CAT_SOUT )
62 set_subcategory( SUBCAT_SOUT_MUX )
63 set_capability( "sout mux", 5 )
64 add_shortcut( "avi" )
66 add_string( SOUT_CFG_PREFIX "artist", NULL, CFG_ARTIST_TEXT, NULL, true )
67 add_string( SOUT_CFG_PREFIX "date", NULL, CFG_DATE_TEXT, NULL, true )
68 add_string( SOUT_CFG_PREFIX "genre", NULL, CFG_GENRE_TEXT, NULL, true )
69 add_string( SOUT_CFG_PREFIX "copyright", NULL, CFG_COPYRIGHT_TEXT, NULL, true )
70 add_string( SOUT_CFG_PREFIX "comment", NULL, CFG_COMMENT_TEXT, NULL, true )
71 add_string( SOUT_CFG_PREFIX "name", NULL, CFG_NAME_TEXT, NULL, true )
72 add_string( SOUT_CFG_PREFIX "subject", NULL, CFG_SUBJECT_TEXT, NULL, true )
73 add_string( SOUT_CFG_PREFIX "encoder",
74 "VLC Media Player - " VERSION_MESSAGE,
75 CFG_ENCODER_TEXT, NULL, true )
76 add_string( SOUT_CFG_PREFIX "keywords", NULL, CFG_KEYWORDS_TEXT, NULL, true )
78 set_callbacks( Open, Close )
79 vlc_module_end ()
82 /*****************************************************************************
83 * Local prototypes
84 *****************************************************************************/
85 static int Control( sout_mux_t *, int, va_list );
86 static int AddStream( sout_mux_t *, sout_input_t * );
87 static void DelStream( sout_mux_t *, sout_input_t * );
88 static int Mux ( sout_mux_t * );
90 typedef struct avi_stream_s
92 int i_cat;
94 char fcc[4];
96 mtime_t i_duration; // in µs
98 int i_frames; // total frame count
99 int64_t i_totalsize; // total stream size
101 float f_fps;
102 int i_bitrate;
104 VLC_BITMAPINFOHEADER *p_bih;
105 WAVEFORMATEX *p_wf;
107 } avi_stream_t;
109 typedef struct avi_idx1_entry_s
111 char fcc[4];
112 uint32_t i_flags;
113 uint32_t i_pos;
114 uint32_t i_length;
116 } avi_idx1_entry_t;
118 typedef struct avi_idx1_s
120 unsigned int i_entry_count;
121 unsigned int i_entry_max;
123 avi_idx1_entry_t *entry;
124 } avi_idx1_t;
126 struct sout_mux_sys_t
128 bool b_write_header;
130 int i_streams;
131 int i_stream_video;
133 off_t i_movi_size;
134 avi_stream_t stream[100];
136 avi_idx1_t idx1;
137 off_t i_idx1_size;
141 #define HDR_BASE_SIZE 512 /* single video&audio ~ 400 bytes header */
143 /* Flags in avih */
144 #define AVIF_HASINDEX 0x00000010 // Index at end of file?
145 #define AVIF_ISINTERLEAVED 0x00000100
146 #define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames?
148 /* Flags for index */
149 #define AVIIF_KEYFRAME 0x00000010L /* this frame is a key frame.*/
152 static block_t *avi_HeaderCreateRIFF( sout_mux_t * );
153 static block_t *avi_HeaderCreateidx1( sout_mux_t * );
155 static void SetFCC( uint8_t *p, char *fcc )
157 memcpy( p, fcc, 4 );
160 /*****************************************************************************
161 * Open:
162 *****************************************************************************/
163 static int Open( vlc_object_t *p_this )
165 sout_mux_t *p_mux = (sout_mux_t*)p_this;
166 sout_mux_sys_t *p_sys;
168 msg_Dbg( p_mux, "AVI muxer opened" );
170 p_sys = malloc( sizeof( sout_mux_sys_t ) );
171 if( !p_sys )
172 return VLC_ENOMEM;
173 p_sys->i_streams = 0;
174 p_sys->i_stream_video = -1;
175 p_sys->i_movi_size = 0;
177 p_sys->idx1.i_entry_count = 0;
178 p_sys->idx1.i_entry_max = 10000;
179 p_sys->idx1.entry = calloc( p_sys->idx1.i_entry_max,
180 sizeof( avi_idx1_entry_t ) );
181 if( !p_sys->idx1.entry )
183 free( p_sys );
184 return VLC_ENOMEM;
186 p_sys->b_write_header = true;
189 p_mux->pf_control = Control;
190 p_mux->pf_addstream = AddStream;
191 p_mux->pf_delstream = DelStream;
192 p_mux->pf_mux = Mux;
193 p_mux->p_sys = p_sys;
195 return VLC_SUCCESS;
198 /*****************************************************************************
199 * Close:
200 *****************************************************************************/
201 static void Close( vlc_object_t * p_this )
203 sout_mux_t *p_mux = (sout_mux_t*)p_this;
204 sout_mux_sys_t *p_sys = p_mux->p_sys;
206 block_t *p_hdr, *p_idx1;
207 int i_stream;
209 msg_Dbg( p_mux, "AVI muxer closed" );
211 /* first create idx1 chunk (write at the end of the stream */
212 p_idx1 = avi_HeaderCreateidx1( p_mux );
213 if( p_idx1 )
215 p_sys->i_idx1_size = p_idx1->i_buffer;
216 sout_AccessOutWrite( p_mux->p_access, p_idx1 );
218 else p_sys->i_idx1_size = 0;
220 /* calculate some value for headers creations */
221 for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
223 avi_stream_t *p_stream;
225 p_stream = &p_sys->stream[i_stream];
227 p_stream->f_fps = 25;
228 if( p_stream->i_duration > 0 )
230 p_stream->f_fps = (float)p_stream->i_frames /
231 ( (float)p_stream->i_duration /
232 (float)1000000 );
234 p_stream->i_bitrate = 128 * 1024;
235 if( p_stream->i_duration > 0 )
237 p_stream->i_bitrate =
238 8 * (uint64_t)1000000 *
239 (uint64_t)p_stream->i_totalsize /
240 (uint64_t)p_stream->i_duration;
242 msg_Info( p_mux, "stream[%d] duration:%"PRId64" totalsize:%"PRId64
243 " frames:%d fps:%f KiB/s:%d",
244 i_stream,
245 (int64_t)p_stream->i_duration / (int64_t)1000000,
246 p_stream->i_totalsize,
247 p_stream->i_frames,
248 p_stream->f_fps, p_stream->i_bitrate/1024 );
251 p_hdr = avi_HeaderCreateRIFF( p_mux );
252 if ( p_hdr )
254 sout_AccessOutSeek( p_mux->p_access, 0 );
255 sout_AccessOutWrite( p_mux->p_access, p_hdr );
258 for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
260 avi_stream_t *p_stream;
261 p_stream = &p_sys->stream[i_stream];
262 free( p_stream->p_bih );
263 free( p_stream->p_wf );
265 free( p_sys->idx1.entry );
266 free( p_sys );
269 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
271 VLC_UNUSED(p_mux);
272 bool *pb_bool;
273 char **ppsz;
275 switch( i_query )
277 case MUX_CAN_ADD_STREAM_WHILE_MUXING:
278 pb_bool = va_arg( args, bool * );
279 *pb_bool = false;
280 return VLC_SUCCESS;
282 case MUX_GET_ADD_STREAM_WAIT:
283 pb_bool = va_arg( args, bool * );
284 *pb_bool = true;
285 return VLC_SUCCESS;
287 case MUX_GET_MIME:
288 ppsz = va_arg( args, char ** );
289 *ppsz = strdup( "video/avi" );
290 return VLC_SUCCESS;
292 default:
293 return VLC_EGENERIC;
297 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
299 sout_mux_sys_t *p_sys = p_mux->p_sys;
300 avi_stream_t *p_stream;
302 if( p_sys->i_streams >= 100 )
304 msg_Err( p_mux, "too many streams" );
305 return VLC_EGENERIC;
308 msg_Dbg( p_mux, "adding input" );
309 p_input->p_sys = malloc( sizeof( int ) );
310 if( !p_input->p_sys )
311 return VLC_ENOMEM;
313 *((int*)p_input->p_sys) = p_sys->i_streams;
314 p_stream = &p_sys->stream[p_sys->i_streams];
316 switch( p_input->p_fmt->i_cat )
318 case AUDIO_ES:
319 p_stream->i_cat = AUDIO_ES;
320 p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
321 p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
322 p_stream->fcc[2] = 'w';
323 p_stream->fcc[3] = 'b';
325 p_stream->p_bih = NULL;
327 WAVEFORMATEX *p_wf = malloc( sizeof( WAVEFORMATEX ) +
328 p_input->p_fmt->i_extra );
329 if( !p_wf )
331 free( p_input->p_sys );
332 p_input->p_sys = NULL;
333 return VLC_ENOMEM;
336 p_wf->cbSize = p_input->p_fmt->i_extra;
337 if( p_wf->cbSize > 0 )
339 memcpy( &p_wf[1],
340 p_input->p_fmt->p_extra,
341 p_input->p_fmt->i_extra );
343 p_wf->nChannels = p_input->p_fmt->audio.i_channels;
344 p_wf->nSamplesPerSec = p_input->p_fmt->audio.i_rate;
345 p_wf->nBlockAlign = p_input->p_fmt->audio.i_blockalign;
346 p_wf->nAvgBytesPerSec= p_input->p_fmt->i_bitrate / 8;
347 p_wf->wBitsPerSample = 0;
349 switch( p_input->p_fmt->i_codec )
351 case VLC_CODEC_A52:
352 p_wf->wFormatTag = WAVE_FORMAT_A52;
353 p_wf->nBlockAlign= 1;
354 break;
355 case VLC_CODEC_MP3:
356 p_wf->wFormatTag = WAVE_FORMAT_MPEGLAYER3;
357 p_wf->nBlockAlign= 1;
358 break;
359 case VLC_CODEC_WMA1:
360 p_wf->wFormatTag = WAVE_FORMAT_WMA1;
361 break;
362 case VLC_CODEC_WMA2:
363 p_wf->wFormatTag = WAVE_FORMAT_WMA2;
364 break;
365 case VLC_CODEC_WMAP:
366 p_wf->wFormatTag = WAVE_FORMAT_WMAP;
367 break;
368 case VLC_CODEC_WMAL:
369 p_wf->wFormatTag = WAVE_FORMAT_WMAL;
370 break;
371 case VLC_CODEC_ALAW:
372 p_wf->wFormatTag = WAVE_FORMAT_ALAW;
373 break;
374 case VLC_CODEC_MULAW:
375 p_wf->wFormatTag = WAVE_FORMAT_MULAW;
376 break;
377 /* raw codec */
378 case VLC_CODEC_U8:
379 p_wf->wFormatTag = WAVE_FORMAT_PCM;
380 p_wf->nBlockAlign= p_wf->nChannels;
381 p_wf->wBitsPerSample = 8;
382 p_wf->nAvgBytesPerSec = (p_wf->wBitsPerSample/8) *
383 p_wf->nSamplesPerSec * p_wf->nChannels;
384 break;
385 case VLC_CODEC_S16L:
386 p_wf->wFormatTag = WAVE_FORMAT_PCM;
387 p_wf->nBlockAlign= 2 * p_wf->nChannels;
388 p_wf->wBitsPerSample = 16;
389 p_wf->nAvgBytesPerSec = (p_wf->wBitsPerSample/8) *
390 p_wf->nSamplesPerSec * p_wf->nChannels;
391 break;
392 case VLC_CODEC_S24L:
393 p_wf->wFormatTag = WAVE_FORMAT_PCM;
394 p_wf->nBlockAlign= 3 * p_wf->nChannels;
395 p_wf->wBitsPerSample = 24;
396 p_wf->nAvgBytesPerSec = (p_wf->wBitsPerSample/8) *
397 p_wf->nSamplesPerSec * p_wf->nChannels;
398 break;
399 case VLC_CODEC_S32L:
400 p_wf->wFormatTag = WAVE_FORMAT_PCM;
401 p_wf->nBlockAlign= 4 * p_wf->nChannels;
402 p_wf->wBitsPerSample = 32;
403 p_wf->nAvgBytesPerSec = (p_wf->wBitsPerSample/8) *
404 p_wf->nSamplesPerSec * p_wf->nChannels;
405 break;
406 default:
407 free( p_wf );
408 free( p_input->p_sys );
409 p_input->p_sys = NULL;
410 return VLC_EGENERIC;
412 p_stream->p_wf = p_wf;
413 break;
414 case VIDEO_ES:
415 p_stream->i_cat = VIDEO_ES;
416 p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
417 p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
418 p_stream->fcc[2] = 'd';
419 p_stream->fcc[3] = 'c';
420 if( p_sys->i_stream_video < 0 )
422 p_sys->i_stream_video = p_sys->i_streams;
424 p_stream->p_wf = NULL;
425 VLC_BITMAPINFOHEADER *p_bih = malloc( sizeof( VLC_BITMAPINFOHEADER ) +
426 p_input->p_fmt->i_extra );
427 if( !p_bih )
429 free( p_input->p_sys );
430 p_input->p_sys = NULL;
431 return VLC_ENOMEM;
434 p_bih->biSize = sizeof( VLC_BITMAPINFOHEADER ) +
435 p_input->p_fmt->i_extra;
436 if( p_input->p_fmt->i_extra > 0 )
438 memcpy( &p_bih[1],
439 p_input->p_fmt->p_extra,
440 p_input->p_fmt->i_extra );
442 p_bih->biWidth = p_input->p_fmt->video.i_width;
443 p_bih->biHeight= p_input->p_fmt->video.i_height;
444 p_bih->biPlanes= 1;
445 p_bih->biBitCount = 24;
446 p_bih->biSizeImage = 0;
447 p_bih->biXPelsPerMeter = 0;
448 p_bih->biYPelsPerMeter = 0;
449 p_bih->biClrUsed = 0;
450 p_bih->biClrImportant = 0;
451 switch( p_input->p_fmt->i_codec )
453 case VLC_CODEC_MP4V:
454 p_bih->biCompression = VLC_FOURCC( 'X', 'V', 'I', 'D' );
455 break;
456 default:
457 p_bih->biCompression = p_input->p_fmt->i_original_fourcc ?: p_input->p_fmt->i_codec;
458 break;
460 p_stream->p_bih = p_bih;
461 break;
462 default:
463 free( p_input->p_sys );
464 p_input->p_sys = NULL;
465 return( VLC_EGENERIC );
467 p_stream->i_totalsize = 0;
468 p_stream->i_frames = 0;
469 p_stream->i_duration = 0;
471 /* fixed later */
472 p_stream->f_fps = 25;
473 p_stream->i_bitrate = 128 * 1024;
475 p_sys->i_streams++;
476 return( VLC_SUCCESS );
479 static void DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
481 msg_Dbg( p_mux, "removing input" );
483 free( p_input->p_sys );
486 static int Mux ( sout_mux_t *p_mux )
488 sout_mux_sys_t *p_sys = p_mux->p_sys;
489 avi_stream_t *p_stream;
490 int i_stream, i;
492 if( p_sys->b_write_header )
494 msg_Dbg( p_mux, "writing header" );
496 block_t *p_hdr = avi_HeaderCreateRIFF( p_mux );
497 if ( !p_hdr )
498 return VLC_EGENERIC;
499 sout_AccessOutWrite( p_mux->p_access, p_hdr );
501 p_sys->b_write_header = false;
504 for( i = 0; i < p_mux->i_nb_inputs; i++ )
506 int i_count;
507 block_fifo_t *p_fifo;
509 if (!p_mux->pp_inputs[i]->p_sys)
510 continue;
512 i_stream = *((int*)p_mux->pp_inputs[i]->p_sys );
513 p_stream = &p_sys->stream[i_stream];
515 p_fifo = p_mux->pp_inputs[i]->p_fifo;
516 i_count = block_FifoCount( p_fifo );
517 while( i_count > 1 )
519 avi_idx1_entry_t *p_idx;
520 block_t *p_data;
522 p_data = block_FifoGet( p_fifo );
523 if( block_FifoCount( p_fifo ) > 0 )
525 block_t *p_next = block_FifoShow( p_fifo );
526 p_data->i_length = p_next->i_dts - p_data->i_dts;
530 if( p_stream->i_frames == 0 &&p_stream->i_cat == VIDEO_ES )
532 /* Add header present at the end of BITMAP info header
533 to first frame in case of XVID */
534 if( p_stream->p_bih->biCompression
535 == VLC_FOURCC( 'X', 'V', 'I', 'D' ) )
537 int i_header_length =
538 p_stream->p_bih->biSize - sizeof(VLC_BITMAPINFOHEADER);
539 p_data = block_Realloc( p_data,
540 i_header_length, p_data->i_buffer );
541 if( !p_data)
542 return VLC_ENOMEM;
543 memcpy(p_data->p_buffer,&p_stream->p_bih[1], i_header_length);
547 p_stream->i_frames++;
548 if( p_data->i_length < 0 )
550 msg_Warn( p_mux, "argg length < 0 l" );
551 block_Release( p_data );
552 i_count--;
553 continue;
555 p_stream->i_duration += p_data->i_length;
556 p_stream->i_totalsize += p_data->i_buffer;
558 /* add idx1 entry for this frame */
559 p_idx = &p_sys->idx1.entry[p_sys->idx1.i_entry_count];
560 memcpy( p_idx->fcc, p_stream->fcc, 4 );
561 p_idx->i_flags = 0;
562 if( ( p_data->i_flags & BLOCK_FLAG_TYPE_MASK ) == 0 || ( p_data->i_flags & BLOCK_FLAG_TYPE_I ) )
563 p_idx->i_flags = AVIIF_KEYFRAME;
564 p_idx->i_pos = p_sys->i_movi_size + 4;
565 p_idx->i_length= p_data->i_buffer;
566 p_sys->idx1.i_entry_count++;
567 if( p_sys->idx1.i_entry_count >= p_sys->idx1.i_entry_max )
569 p_sys->idx1.i_entry_max += 10000;
570 p_sys->idx1.entry = xrealloc( p_sys->idx1.entry,
571 p_sys->idx1.i_entry_max * sizeof( avi_idx1_entry_t ) );
574 p_data = block_Realloc( p_data, 8, p_data->i_buffer );
575 if( p_data )
577 SetFCC( p_data->p_buffer, p_stream->fcc );
578 SetDWLE( p_data->p_buffer + 4, p_data->i_buffer - 8 );
580 if( p_data->i_buffer & 0x01 )
582 p_data = block_Realloc( p_data, 0, p_data->i_buffer + 1 );
583 if ( p_data )
584 p_data->p_buffer[ p_data->i_buffer - 1 ] = '\0';
587 if ( p_data )
589 p_sys->i_movi_size += p_data->i_buffer;
590 sout_AccessOutWrite( p_mux->p_access, p_data );
594 i_count--;
598 return( 0 );
601 /****************************************************************************
602 ****************************************************************************
604 ** avi header generation
606 ****************************************************************************
607 ****************************************************************************/
608 #define AVI_BOX_ENTER( fcc ) \
609 int i_datasize_offset; \
610 bo_add_fourcc( p_bo, fcc ); \
611 i_datasize_offset = p_bo->b->i_buffer; \
612 bo_add_32le( p_bo, 0 )
614 #define AVI_BOX_ENTER_LIST( fcc ) \
615 AVI_BOX_ENTER( "LIST" ); \
616 bo_add_fourcc( p_bo, fcc )
618 #define AVI_BOX_EXIT( i_err ) \
619 if( p_bo->b->i_buffer&0x01 ) bo_add_8( p_bo, 0 ); \
620 bo_set_32le( p_bo, i_datasize_offset, p_bo->b->i_buffer - i_datasize_offset - 4 ); \
621 return( i_err );
623 static int avi_HeaderAdd_avih( sout_mux_t *p_mux,
624 bo_t *p_bo )
626 sout_mux_sys_t *p_sys = p_mux->p_sys;
627 avi_stream_t *p_video = NULL;
628 int i_stream;
629 uint32_t i_microsecperframe;
630 int i_maxbytespersec;
631 int i_totalframes;
632 AVI_BOX_ENTER( "avih" );
634 if( p_sys->i_stream_video >= 0 )
636 p_video = &p_sys->stream[p_sys->i_stream_video];
637 if( p_video->i_frames <= 0 )
639 // p_video = NULL;
643 if( p_video )
645 i_microsecperframe =
646 (uint32_t)( (float)1000000 /
647 (float)p_sys->stream[p_sys->i_stream_video].f_fps );
648 i_totalframes = p_sys->stream[p_sys->i_stream_video].i_frames;
650 else
652 msg_Warn( p_mux, "avi file without video track isn't a good idea..." );
653 i_microsecperframe = 0;
654 i_totalframes = 0;
657 for( i_stream = 0,i_maxbytespersec = 0; i_stream < p_sys->i_streams; i_stream++ )
659 if( p_sys->stream[i_stream].i_duration > 0 )
661 i_maxbytespersec +=
662 p_sys->stream[i_stream].i_totalsize /
663 p_sys->stream[i_stream].i_duration;
667 bo_add_32le( p_bo, i_microsecperframe );
668 bo_add_32le( p_bo, i_maxbytespersec );
669 bo_add_32le( p_bo, 0 ); /* padding */
670 bo_add_32le( p_bo, AVIF_TRUSTCKTYPE |
671 AVIF_HASINDEX |
672 AVIF_ISINTERLEAVED ); /* flags */
673 bo_add_32le( p_bo, i_totalframes );
674 bo_add_32le( p_bo, 0 ); /* initial frame */
675 bo_add_32le( p_bo, p_sys->i_streams ); /* streams count */
676 bo_add_32le( p_bo, 1024 * 1024 ); /* suggested buffer size */
677 if( p_video )
679 bo_add_32le( p_bo, p_video->p_bih->biWidth );
680 bo_add_32le( p_bo, p_video->p_bih->biHeight );
682 else
684 bo_add_32le( p_bo, 0 );
685 bo_add_32le( p_bo, 0 );
687 bo_add_32le( p_bo, 0 ); /* ???? */
688 bo_add_32le( p_bo, 0 ); /* ???? */
689 bo_add_32le( p_bo, 0 ); /* ???? */
690 bo_add_32le( p_bo, 0 ); /* ???? */
692 AVI_BOX_EXIT( 0 );
694 static int avi_HeaderAdd_strh( bo_t *p_bo, avi_stream_t *p_stream )
696 AVI_BOX_ENTER( "strh" );
698 switch( p_stream->i_cat )
700 case VIDEO_ES:
702 bo_add_fourcc( p_bo, "vids" );
703 bo_add_32be( p_bo, p_stream->p_bih->biCompression );
704 bo_add_32le( p_bo, 0 ); /* flags */
705 bo_add_16le( p_bo, 0 ); /* priority */
706 bo_add_16le( p_bo, 0 ); /* langage */
707 bo_add_32le( p_bo, 0 ); /* initial frame */
708 bo_add_32le( p_bo, 1000 );/* scale */
709 bo_add_32le( p_bo, (uint32_t)( 1000 * p_stream->f_fps ));
710 bo_add_32le( p_bo, 0 ); /* start */
711 bo_add_32le( p_bo, p_stream->i_frames );
712 bo_add_32le( p_bo, 1024 * 1024 );
713 bo_add_32le( p_bo, -1 ); /* quality */
714 bo_add_32le( p_bo, 0 ); /* samplesize */
715 bo_add_16le( p_bo, 0 ); /* ??? */
716 bo_add_16le( p_bo, 0 ); /* ??? */
717 bo_add_16le( p_bo, p_stream->p_bih->biWidth );
718 bo_add_16le( p_bo, p_stream->p_bih->biHeight );
720 break;
721 case AUDIO_ES:
723 int i_rate, i_scale, i_samplesize;
725 i_samplesize = p_stream->p_wf->nBlockAlign;
726 if( i_samplesize > 1 )
728 i_scale = i_samplesize;
729 i_rate = /*i_scale **/ p_stream->i_bitrate / 8;
731 else
733 i_samplesize = 1;
734 i_scale = 1000;
735 i_rate = 1000 * p_stream->i_bitrate / 8;
737 bo_add_fourcc( p_bo, "auds" );
738 bo_add_32le( p_bo, 0 ); /* tag */
739 bo_add_32le( p_bo, 0 ); /* flags */
740 bo_add_16le( p_bo, 0 ); /* priority */
741 bo_add_16le( p_bo, 0 ); /* langage */
742 bo_add_32le( p_bo, 0 ); /* initial frame */
743 bo_add_32le( p_bo, i_scale );/* scale */
744 bo_add_32le( p_bo, i_rate );
745 bo_add_32le( p_bo, 0 ); /* start */
746 bo_add_32le( p_bo, p_stream->i_frames );
747 bo_add_32le( p_bo, 10 * 1024 );
748 bo_add_32le( p_bo, -1 ); /* quality */
749 bo_add_32le( p_bo, i_samplesize );
750 bo_add_16le( p_bo, 0 ); /* ??? */
751 bo_add_16le( p_bo, 0 ); /* ??? */
752 bo_add_16le( p_bo, 0 );
753 bo_add_16le( p_bo, 0 );
755 break;
758 AVI_BOX_EXIT( 0 );
761 static int avi_HeaderAdd_strf( bo_t *p_bo, avi_stream_t *p_stream )
763 AVI_BOX_ENTER( "strf" );
765 switch( p_stream->i_cat )
767 case AUDIO_ES:
768 bo_add_16le( p_bo, p_stream->p_wf->wFormatTag );
769 bo_add_16le( p_bo, p_stream->p_wf->nChannels );
770 bo_add_32le( p_bo, p_stream->p_wf->nSamplesPerSec );
771 bo_add_32le( p_bo, p_stream->p_wf->nAvgBytesPerSec );
772 bo_add_16le( p_bo, p_stream->p_wf->nBlockAlign );
773 bo_add_16le( p_bo, p_stream->p_wf->wBitsPerSample );
774 bo_add_16le( p_bo, p_stream->p_wf->cbSize );
775 bo_add_mem( p_bo, p_stream->p_wf->cbSize, (uint8_t*)&p_stream->p_wf[1] );
776 break;
777 case VIDEO_ES:
778 bo_add_32le( p_bo, p_stream->p_bih->biSize );
779 bo_add_32le( p_bo, p_stream->p_bih->biWidth );
780 bo_add_32le( p_bo, p_stream->p_bih->biHeight );
781 bo_add_16le( p_bo, p_stream->p_bih->biPlanes );
782 bo_add_16le( p_bo, p_stream->p_bih->biBitCount );
783 if( VLC_FOURCC( 0, 0, 0, 1 ) == 0x00000001 )
785 bo_add_32be( p_bo, p_stream->p_bih->biCompression );
787 else
789 bo_add_32le( p_bo, p_stream->p_bih->biCompression );
791 bo_add_32le( p_bo, p_stream->p_bih->biSizeImage );
792 bo_add_32le( p_bo, p_stream->p_bih->biXPelsPerMeter );
793 bo_add_32le( p_bo, p_stream->p_bih->biYPelsPerMeter );
794 bo_add_32le( p_bo, p_stream->p_bih->biClrUsed );
795 bo_add_32le( p_bo, p_stream->p_bih->biClrImportant );
796 bo_add_mem( p_bo,
797 p_stream->p_bih->biSize - sizeof( VLC_BITMAPINFOHEADER ),
798 (uint8_t*)&p_stream->p_bih[1] );
799 break;
802 AVI_BOX_EXIT( 0 );
805 static int avi_HeaderAdd_strl( bo_t *p_bo, avi_stream_t *p_stream )
807 AVI_BOX_ENTER_LIST( "strl" );
809 avi_HeaderAdd_strh( p_bo, p_stream );
810 avi_HeaderAdd_strf( p_bo, p_stream );
812 AVI_BOX_EXIT( 0 );
815 static int avi_HeaderAdd_meta( bo_t *p_bo, const char psz_meta[4],
816 const char *psz_data )
818 if ( psz_data == NULL ) return 1;
819 const char *psz = psz_data;
820 AVI_BOX_ENTER( psz_meta );
821 while (*psz) bo_add_8( p_bo, *psz++ );
822 bo_add_8( p_bo, 0 );
823 AVI_BOX_EXIT( 0 );
826 static int avi_HeaderAdd_INFO( sout_mux_t *p_mux, bo_t *p_bo )
828 char *psz;
830 #define APPLY_META(var, fourcc) \
831 psz = var_InheritString( p_mux, SOUT_CFG_PREFIX var );\
832 if ( psz )\
834 avi_HeaderAdd_meta( p_bo, fourcc, psz );\
835 free( psz );\
838 AVI_BOX_ENTER_LIST( "INFO" );
840 APPLY_META( "artist", "IART")
841 APPLY_META( "comment", "ICMT")
842 APPLY_META( "copyright","ICOP")
843 APPLY_META( "date", "ICRD")
844 APPLY_META( "genre", "IGNR")
845 APPLY_META( "name", "INAM")
846 APPLY_META( "keywords", "IKEY")
847 APPLY_META( "subject", "ISBJ")
848 APPLY_META( "encoder", "ISFT")
849 /* Some are missing, but are they really useful ?? */
851 #undef APPLY_META
853 AVI_BOX_EXIT( 0 );
856 static block_t *avi_HeaderCreateRIFF( sout_mux_t *p_mux )
858 sout_mux_sys_t *p_sys = p_mux->p_sys;
859 int i_stream;
860 int i_junk;
861 bo_t bo;
863 struct
865 int i_riffsize;
866 int i_hdrllistsize;
867 int i_hdrldatastart;
868 } offsets;
870 if (! bo_init( &bo, HDR_BASE_SIZE ) )
871 return NULL;
873 bo_add_fourcc( &bo, "RIFF" );
874 offsets.i_riffsize = bo.b->i_buffer;
875 bo_add_32le( &bo, 0xEFBEADDE );
876 bo_add_fourcc( &bo, "AVI " );
878 bo_add_fourcc( &bo, "LIST" );
879 /* HDRL List size should exclude following data in HDR buffer
880 * -12 (RIFF, RIFF size, 'AVI ' tag),
881 * - 8 (hdr1 LIST tag and its size)
882 * - 12 (movi LIST tag, size, 'movi' listType )
884 offsets.i_hdrllistsize = bo.b->i_buffer;
885 bo_add_32le( &bo, 0xEFBEADDE );
886 bo_add_fourcc( &bo, "hdrl" );
887 offsets.i_hdrldatastart = bo.b->i_buffer;
889 avi_HeaderAdd_avih( p_mux, &bo );
890 for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
892 avi_HeaderAdd_strl( &bo, &p_sys->stream[i_stream] );
895 /* align on 16 bytes */
896 int i_align = ( ( bo.b->i_buffer + 12 + 0xE ) & ~ 0xF );
897 i_junk = i_align - bo.b->i_buffer;
898 bo_add_fourcc( &bo, "JUNK" );
899 bo_add_32le( &bo, i_junk );
900 for( int i=0; i< i_junk; i++ )
902 bo_add_8( &bo, 0 );
905 /* Now set hdrl size */
906 bo_set_32le( &bo, offsets.i_hdrllistsize,
907 bo.b->i_buffer - offsets.i_hdrldatastart );
909 avi_HeaderAdd_INFO( p_mux, &bo );
911 bo_add_fourcc( &bo, "LIST" );
912 bo_add_32le( &bo, p_sys->i_movi_size + 4 );
913 bo_add_fourcc( &bo, "movi" );
915 /* Now set RIFF size */
916 bo_set_32le( &bo, offsets.i_riffsize, bo.b->i_buffer - 8
917 + p_sys->i_movi_size + p_sys->i_idx1_size );
919 return( bo.b );
922 static block_t * avi_HeaderCreateidx1( sout_mux_t *p_mux )
924 sout_mux_sys_t *p_sys = p_mux->p_sys;
925 uint32_t i_idx1_size;
926 bo_t bo;
928 i_idx1_size = 16 * p_sys->idx1.i_entry_count + 8;
930 if (!i_idx1_size || !bo_init( &bo, i_idx1_size ) )
931 return NULL;
932 memset( bo.b->p_buffer, 0, i_idx1_size);
934 bo_add_fourcc( &bo, "idx1" );
935 bo_add_32le( &bo, i_idx1_size - 8);
937 for( unsigned i = 0; i < p_sys->idx1.i_entry_count; i++ )
939 bo_add_fourcc( &bo, p_sys->idx1.entry[i].fcc );
940 bo_add_32le( &bo, p_sys->idx1.entry[i].i_flags );
941 bo_add_32le( &bo, p_sys->idx1.entry[i].i_pos );
942 bo_add_32le( &bo, p_sys->idx1.entry[i].i_length );
945 return( bo.b );