1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001-2009 VLC authors and VideoLAN
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 /*****************************************************************************
26 *****************************************************************************/
27 /* TODO: add OpenDML write support */
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <vlc_block.h>
38 #include <vlc_codecs.h>
39 #include <vlc_boxes.h>
41 /*****************************************************************************
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")
60 set_description( N_("AVI muxer") )
61 set_category( CAT_SOUT
)
62 set_subcategory( SUBCAT_SOUT_MUX
)
63 set_capability( "sout mux", 5 )
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
)
82 /*****************************************************************************
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
96 mtime_t i_duration
; // in µs
98 int i_frames
; // total frame count
99 int64_t i_totalsize
; // total stream size
104 VLC_BITMAPINFOHEADER
*p_bih
;
109 typedef struct avi_idx1_entry_s
118 typedef struct avi_idx1_s
120 unsigned int i_entry_count
;
121 unsigned int i_entry_max
;
123 avi_idx1_entry_t
*entry
;
126 struct sout_mux_sys_t
134 avi_stream_t stream
[100];
141 #define HDR_BASE_SIZE 512 /* single video&audio ~ 400 bytes header */
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
)
160 /*****************************************************************************
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
) );
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
)
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
;
193 p_mux
->p_sys
= p_sys
;
198 /*****************************************************************************
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
;
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
);
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
/
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",
245 (int64_t)p_stream
->i_duration
/ (int64_t)1000000,
246 p_stream
->i_totalsize
,
248 p_stream
->f_fps
, p_stream
->i_bitrate
/1024 );
251 p_hdr
= avi_HeaderCreateRIFF( p_mux
);
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
);
269 static int Control( sout_mux_t
*p_mux
, int i_query
, va_list args
)
277 case MUX_CAN_ADD_STREAM_WHILE_MUXING
:
278 pb_bool
= va_arg( args
, bool * );
282 case MUX_GET_ADD_STREAM_WAIT
:
283 pb_bool
= va_arg( args
, bool * );
288 ppsz
= va_arg( args
, char ** );
289 *ppsz
= strdup( "video/avi" );
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" );
308 msg_Dbg( p_mux
, "adding input" );
309 p_input
->p_sys
= malloc( sizeof( int ) );
310 if( !p_input
->p_sys
)
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
)
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
);
331 free( p_input
->p_sys
);
332 p_input
->p_sys
= NULL
;
336 p_wf
->cbSize
= p_input
->p_fmt
->i_extra
;
337 if( p_wf
->cbSize
> 0 )
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
)
352 p_wf
->wFormatTag
= WAVE_FORMAT_A52
;
353 p_wf
->nBlockAlign
= 1;
356 p_wf
->wFormatTag
= WAVE_FORMAT_MPEGLAYER3
;
357 p_wf
->nBlockAlign
= 1;
360 p_wf
->wFormatTag
= WAVE_FORMAT_WMA1
;
363 p_wf
->wFormatTag
= WAVE_FORMAT_WMA2
;
366 p_wf
->wFormatTag
= WAVE_FORMAT_WMAP
;
369 p_wf
->wFormatTag
= WAVE_FORMAT_WMAL
;
372 p_wf
->wFormatTag
= WAVE_FORMAT_ALAW
;
374 case VLC_CODEC_MULAW
:
375 p_wf
->wFormatTag
= WAVE_FORMAT_MULAW
;
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
;
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
;
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
;
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
;
408 free( p_input
->p_sys
);
409 p_input
->p_sys
= NULL
;
412 p_stream
->p_wf
= p_wf
;
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
);
429 free( p_input
->p_sys
);
430 p_input
->p_sys
= NULL
;
434 p_bih
->biSize
= sizeof( VLC_BITMAPINFOHEADER
) +
435 p_input
->p_fmt
->i_extra
;
436 if( p_input
->p_fmt
->i_extra
> 0 )
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
;
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
)
454 p_bih
->biCompression
= VLC_FOURCC( 'X', 'V', 'I', 'D' );
457 p_bih
->biCompression
= p_input
->p_fmt
->i_original_fourcc
?: p_input
->p_fmt
->i_codec
;
460 p_stream
->p_bih
= p_bih
;
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;
472 p_stream
->f_fps
= 25;
473 p_stream
->i_bitrate
= 128 * 1024;
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
;
492 if( p_sys
->b_write_header
)
494 msg_Dbg( p_mux
, "writing header" );
496 block_t
*p_hdr
= avi_HeaderCreateRIFF( p_mux
);
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
++ )
507 block_fifo_t
*p_fifo
;
509 if (!p_mux
->pp_inputs
[i
]->p_sys
)
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
);
519 avi_idx1_entry_t
*p_idx
;
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
);
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
);
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 );
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
);
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 );
584 p_data
->p_buffer
[ p_data
->i_buffer
- 1 ] = '\0';
589 p_sys
->i_movi_size
+= p_data
->i_buffer
;
590 sout_AccessOutWrite( p_mux
->p_access
, p_data
);
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 ); \
623 static int avi_HeaderAdd_avih( sout_mux_t
*p_mux
,
626 sout_mux_sys_t
*p_sys
= p_mux
->p_sys
;
627 avi_stream_t
*p_video
= NULL
;
629 uint32_t i_microsecperframe
;
630 int i_maxbytespersec
;
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 )
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
;
652 msg_Warn( p_mux
, "avi file without video track isn't a good idea..." );
653 i_microsecperframe
= 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 )
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
|
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 */
679 bo_add_32le( p_bo
, p_video
->p_bih
->biWidth
);
680 bo_add_32le( p_bo
, p_video
->p_bih
->biHeight
);
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 ); /* ???? */
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
)
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
);
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;
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 );
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
)
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] );
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
);
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
);
797 p_stream
->p_bih
->biSize
- sizeof( VLC_BITMAPINFOHEADER
),
798 (uint8_t*)&p_stream
->p_bih
[1] );
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
);
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
++ );
826 static int avi_HeaderAdd_INFO( sout_mux_t
*p_mux
, bo_t
*p_bo
)
830 #define APPLY_META(var, fourcc) \
831 psz = var_InheritString( p_mux, SOUT_CFG_PREFIX var );\
834 avi_HeaderAdd_meta( p_bo, fourcc, 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 ?? */
856 static block_t
*avi_HeaderCreateRIFF( sout_mux_t
*p_mux
)
858 sout_mux_sys_t
*p_sys
= p_mux
->p_sys
;
870 if (! bo_init( &bo
, HDR_BASE_SIZE
) )
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
++ )
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
);
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
;
928 i_idx1_size
= 16 * p_sys
->idx1
.i_entry_count
+ 8;
930 if (!i_idx1_size
|| !bo_init( &bo
, i_idx1_size
) )
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
);