1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
30 #include <vlc/input.h>
35 /*****************************************************************************
37 *****************************************************************************/
38 static int Open ( vlc_object_t * );
39 static void Close ( vlc_object_t * );
41 #define SOUT_CFG_PREFIX "sout-asf-"
43 #define TITLE_TEXT N_("Title")
44 #define TITLE_LONGTEXT N_("Allows you to define the title that will be put " \
46 #define AUTHOR_TEXT N_("Author")
47 #define AUTHOR_LONGTEXT N_("Allows you to define the author that will be put " \
49 #define COPYRIGHT_TEXT N_("Copyright")
50 #define COPYRIGHT_LONGTEXT N_("Allows you to define the copyright string that "\
51 "will be put in ASF comments.")
52 #define COMMENT_TEXT N_("Comment")
53 #define COMMENT_LONGTEXT N_("Allows you to define the comment that will be " \
54 "put in ASF comments.")
55 #define RATING_TEXT N_("Rating")
56 #define RATING_LONGTEXT N_("Allows you to define the \"rating\" that will " \
57 "be put in ASF comments.")
60 set_description( _("ASF muxer") );
61 set_capability( "sout mux", 5 );
62 add_shortcut( "asf" );
63 add_shortcut( "asfh" );
64 set_callbacks( Open, Close );
66 add_string( SOUT_CFG_PREFIX "title", "", NULL, TITLE_TEXT, TITLE_LONGTEXT,
68 add_string( SOUT_CFG_PREFIX "author", "", NULL, AUTHOR_TEXT,
69 AUTHOR_LONGTEXT, VLC_TRUE );
70 add_string( SOUT_CFG_PREFIX "copyright","", NULL, COPYRIGHT_TEXT,
71 COPYRIGHT_LONGTEXT, VLC_TRUE );
72 add_string( SOUT_CFG_PREFIX "comment", "", NULL, COMMENT_TEXT,
73 COMMENT_LONGTEXT, VLC_TRUE );
74 add_string( SOUT_CFG_PREFIX "rating", "", NULL, RATING_TEXT,
75 RATING_LONGTEXT, VLC_TRUE );
78 /*****************************************************************************
80 *****************************************************************************/
81 static const char *ppsz_sout_options[] = {
82 "title", "author", "copyright", "comment", "rating", NULL
85 static int Capability(sout_mux_t *, int, void *, void * );
86 static int AddStream( sout_mux_t *, sout_input_t * );
87 static int DelStream( sout_mux_t *, sout_input_t * );
88 static int Mux ( sout_mux_t * );
103 /* codec informations */
104 uint16_t i_tag; /* for audio */
105 vlc_fourcc_t i_fourcc; /* for video */
106 char *psz_name; /* codec name */
114 struct sout_mux_sys_t
116 guid_t fid; /* file id */
118 int64_t i_packet_count;
124 asf_track_t track[128];
126 vlc_bool_t b_write_header;
133 vlc_bool_t b_asf_http;
144 static int MuxGetStream( sout_mux_t *, int *pi_stream, mtime_t *pi_dts );
146 static block_t *asf_header_create( sout_mux_t *, vlc_bool_t b_broadcast );
147 static block_t *asf_packet_create( sout_mux_t *,
148 asf_track_t *, block_t * );
149 static block_t *asf_stream_end_create( sout_mux_t *);
158 static void bo_init ( bo_t *, uint8_t *, int );
159 static void bo_add_u8 ( bo_t *, uint8_t );
160 static void bo_addle_u16( bo_t *, uint16_t );
161 static void bo_addle_u32( bo_t *, uint32_t );
162 static void bo_addle_u64( bo_t *, uint64_t );
163 static void bo_add_mem ( bo_t *, uint8_t *, int );
165 static void bo_addle_str16( bo_t *, char * );
167 /*****************************************************************************
169 *****************************************************************************/
170 static int Open( vlc_object_t *p_this )
172 sout_mux_t *p_mux = (sout_mux_t*)p_this;
173 sout_mux_sys_t *p_sys;
177 msg_Dbg( p_mux, "Asf muxer opened" );
178 sout_ParseCfg( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
180 p_mux->pf_capacity = Capability;
181 p_mux->pf_addstream = AddStream;
182 p_mux->pf_delstream = DelStream;
185 p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
186 p_sys->b_asf_http = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "asfh" );
187 if( p_sys->b_asf_http )
189 msg_Dbg( p_mux, "creating asf stream to be used with mmsh" );
192 p_sys->i_pk_used = 0;
193 p_sys->i_pk_frame = 0;
194 p_sys->i_dts_first = -1;
195 p_sys->i_dts_last = 0;
196 p_sys->i_bitrate = 0;
199 p_sys->b_write_header = VLC_TRUE;
201 p_sys->i_packet_size = 4096;
202 p_sys->i_packet_count= 0;
203 /* generate a random fid */
204 srand( mdate() & 0xffffffff );
205 p_sys->fid.v1 = 0xbabac001;
206 p_sys->fid.v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
207 p_sys->fid.v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
208 for( i = 0; i < 8; i++ )
210 p_sys->fid.v4[i] = ( (uint64_t)rand() << 8 ) / RAND_MAX;
213 var_Get( p_mux, SOUT_CFG_PREFIX "title", &val );
214 p_sys->psz_title = val.psz_string;
216 var_Get( p_mux, SOUT_CFG_PREFIX "author", &val );
217 p_sys->psz_author = val.psz_string;
219 var_Get( p_mux, SOUT_CFG_PREFIX "copyright", &val );
220 p_sys->psz_copyright = val.psz_string;
222 var_Get( p_mux, SOUT_CFG_PREFIX "comment", &val );
223 p_sys->psz_comment = val.psz_string;
225 var_Get( p_mux, SOUT_CFG_PREFIX "rating", &val );
226 p_sys->psz_rating = val.psz_string;
229 "meta data: title='%s' author='%s' copyright='%s' comment='%s' rating='%s'",
230 p_sys->psz_title, p_sys->psz_author, p_sys->psz_copyright,
231 p_sys->psz_comment, p_sys->psz_rating );
236 /*****************************************************************************
238 *****************************************************************************/
239 static void Close( vlc_object_t * p_this )
241 sout_mux_t *p_mux = (sout_mux_t*)p_this;
242 sout_mux_sys_t *p_sys = p_mux->p_sys;
246 msg_Dbg( p_mux, "Asf muxer closed" );
248 if( ( out = asf_stream_end_create( p_mux ) ) )
250 sout_AccessOutWrite( p_mux->p_access, out );
254 if( !sout_AccessOutSeek( p_mux->p_access, 0 ) )
256 out = asf_header_create( p_mux, VLC_FALSE );
257 sout_AccessOutWrite( p_mux->p_access, out );
260 for( i = 1; i < p_sys->i_track; i++ )
262 free( p_sys->track[i].p_extra );
267 /*****************************************************************************
269 *****************************************************************************/
270 static int Capability( sout_mux_t *p_mux, int i_query,
271 void *p_args, void *p_answer )
275 case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
276 *(vlc_bool_t*)p_answer = VLC_FALSE;
277 return( SOUT_MUX_CAP_ERR_OK );
279 return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
283 /*****************************************************************************
285 *****************************************************************************/
286 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
288 sout_mux_sys_t *p_sys = p_mux->p_sys;
292 msg_Dbg( p_mux, "adding input" );
293 if( p_sys->i_track > 127 )
295 msg_Dbg( p_mux, "cannot add this track (too much track)" );
299 tk = p_input->p_sys = &p_sys->track[p_sys->i_track];
300 tk->i_id = p_sys->i_track;
301 tk->i_cat = p_input->p_fmt->i_cat;
308 int i_blockalign = p_input->p_fmt->audio.i_blockalign;
309 int i_bitspersample = 0;
312 switch( p_input->p_fmt->i_codec )
314 case VLC_FOURCC( 'a', '5', '2', ' ' ):
315 tk->i_tag = WAVE_FORMAT_A52;
316 tk->psz_name = "A/52";
318 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
320 tk->psz_name = "MPEG Audio Layer 3";
321 tk->i_tag = WAVE_FORMAT_MPEGLAYER3;
326 tk->psz_name = "MPEG Audio Layer 1/2";
327 tk->i_tag = WAVE_FORMAT_MPEG;
332 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
333 tk->psz_name = "Windows Media Audio 1";
334 tk->i_tag = WAVE_FORMAT_WMA1;
336 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
337 tk->psz_name = "Windows Media Audio 2";
338 tk->i_tag = WAVE_FORMAT_WMA2;
340 case VLC_FOURCC( 'w', 'm', 'a', '3' ):
341 tk->psz_name = "Windows Media Audio 3";
342 tk->i_tag = WAVE_FORMAT_WMA3;
345 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
346 tk->psz_name = "Raw audio 8bits";
347 tk->i_tag = WAVE_FORMAT_PCM;
348 i_blockalign= p_input->p_fmt->audio.i_channels;
351 case VLC_FOURCC( 's', '1', '6', 'l' ):
352 tk->psz_name = "Raw audio 16bits";
353 tk->i_tag = WAVE_FORMAT_PCM;
354 i_blockalign= 2 * p_input->p_fmt->audio.i_channels;
355 i_bitspersample = 16;
357 case VLC_FOURCC( 's', '2', '4', 'l' ):
358 tk->psz_name = "Raw audio 24bits";
359 tk->i_tag = WAVE_FORMAT_PCM;
360 i_blockalign= 3 * p_input->p_fmt->audio.i_channels;
361 i_bitspersample = 24;
363 case VLC_FOURCC( 's', '3', '2', 'l' ):
364 tk->psz_name = "Raw audio 32bits";
365 tk->i_tag = WAVE_FORMAT_PCM;
366 i_blockalign= 4 * p_input->p_fmt->audio.i_channels;
367 i_bitspersample = 32;
374 tk->i_extra = sizeof( WAVEFORMATEX ) +
375 p_input->p_fmt->i_extra + i_extra;
376 tk->p_extra = malloc( tk->i_extra );
377 bo_init( &bo, tk->p_extra, tk->i_extra );
378 bo_addle_u16( &bo, tk->i_tag );
379 bo_addle_u16( &bo, p_input->p_fmt->audio.i_channels );
380 bo_addle_u32( &bo, p_input->p_fmt->audio.i_rate );
381 bo_addle_u32( &bo, p_input->p_fmt->i_bitrate / 8 );
382 bo_addle_u16( &bo, i_blockalign );
383 bo_addle_u16( &bo, i_bitspersample );
384 if( p_input->p_fmt->i_extra > 0 )
386 bo_addle_u16( &bo, p_input->p_fmt->i_extra );
387 bo_add_mem ( &bo, p_input->p_fmt->p_extra,
388 p_input->p_fmt->i_extra );
392 bo_addle_u16( &bo, i_extra );
393 if( tk->i_tag == WAVE_FORMAT_MPEGLAYER3 )
395 msg_Dbg( p_mux, "adding mp3 header" );
396 bo_addle_u16( &bo, 1 ); /* wId */
397 bo_addle_u32( &bo, 2 ); /* fdwFlags */
398 bo_addle_u16( &bo, 1152 ); /* nBlockSize */
399 bo_addle_u16( &bo, 1 ); /* nFramesPerBlock */
400 bo_addle_u16( &bo, 1393 ); /* nCodecDelay */
402 else if( tk->i_tag == WAVE_FORMAT_MPEG )
404 msg_Dbg( p_mux, "adding mp2 header" );
405 bo_addle_u16( &bo, 2 ); /* fwHeadLayer */
406 bo_addle_u32( &bo, p_input->p_fmt->i_bitrate );
407 bo_addle_u16( &bo, p_input->p_fmt->audio.i_channels == 2 ?1:8 );
408 bo_addle_u16( &bo, 0 ); /* fwHeadModeExt */
409 bo_addle_u16( &bo, 1 ); /* wHeadEmphasis */
410 bo_addle_u16( &bo, 16 ); /* fwHeadFlags */
411 bo_addle_u32( &bo, 0 ); /* dwPTSLow */
412 bo_addle_u32( &bo, 0 ); /* dwPTSHigh */
416 if( p_input->p_fmt->i_bitrate > 24000 )
418 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
422 p_sys->i_bitrate += 512000;
428 tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) +
429 p_input->p_fmt->i_extra;
430 tk->p_extra = malloc( tk->i_extra );
431 bo_init( &bo, tk->p_extra, tk->i_extra );
432 bo_addle_u32( &bo, p_input->p_fmt->video.i_width );
433 bo_addle_u32( &bo, p_input->p_fmt->video.i_height );
434 bo_add_u8 ( &bo, 0x02 ); /* flags */
435 bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) +
436 p_input->p_fmt->i_extra );
437 bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) +
438 p_input->p_fmt->i_extra );
439 bo_addle_u32( &bo, p_input->p_fmt->video.i_width );
440 bo_addle_u32( &bo, p_input->p_fmt->video.i_height );
441 bo_addle_u16( &bo, 1 );
442 bo_addle_u16( &bo, 24 );
443 if( p_input->p_fmt->i_codec == VLC_FOURCC('m','p','4','v') )
445 tk->psz_name = "MPEG-4 Video";
446 tk->i_fourcc = VLC_FOURCC( 'M', 'P', '4', 'S' );
448 else if( p_input->p_fmt->i_codec == VLC_FOURCC('D','I','V','3') )
450 tk->psz_name = "MSMPEG-4 V3 Video";
451 tk->i_fourcc = VLC_FOURCC( 'M', 'P', '4', '3' );
453 else if( p_input->p_fmt->i_codec == VLC_FOURCC('D','I','V','2') )
455 tk->psz_name = "MSMPEG-4 V2 Video";
456 tk->i_fourcc = VLC_FOURCC( 'M', 'P', '4', '2' );
458 else if( p_input->p_fmt->i_codec == VLC_FOURCC('D','I','V','1') )
460 tk->psz_name = "MSMPEG-4 V1 Video";
461 tk->i_fourcc = VLC_FOURCC( 'M', 'P', 'G', '4' );
463 else if( p_input->p_fmt->i_codec == VLC_FOURCC('W','M','V','1') )
465 tk->psz_name = "Windows Media Video 1";
466 tk->i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '1' );
468 else if( p_input->p_fmt->i_codec == VLC_FOURCC('W','M','V','2') )
470 tk->psz_name = "Windows Media Video 2";
471 tk->i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '2' );
475 tk->psz_name = _("Unknown Video");
476 tk->i_fourcc = p_input->p_fmt->i_codec;
478 bo_add_mem( &bo, (uint8_t*)&tk->i_fourcc, 4 );
479 bo_addle_u32( &bo, 0 );
480 bo_addle_u32( &bo, 0 );
481 bo_addle_u32( &bo, 0 );
482 bo_addle_u32( &bo, 0 );
483 bo_addle_u32( &bo, 0 );
484 if( p_input->p_fmt->i_extra > 0 )
486 bo_add_mem ( &bo, p_input->p_fmt->p_extra,
487 p_input->p_fmt->i_extra );
490 if( p_input->p_fmt->i_bitrate > 50000 )
492 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
496 p_sys->i_bitrate += 1000000;
501 msg_Err(p_mux, "unhandled track type" );
509 /*****************************************************************************
511 *****************************************************************************/
512 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
514 msg_Dbg( p_mux, "removing input" );
518 /*****************************************************************************
520 *****************************************************************************/
521 static int Mux ( sout_mux_t *p_mux )
523 sout_mux_sys_t *p_sys = p_mux->p_sys;
525 if( p_sys->b_write_header )
527 block_t *out = asf_header_create( p_mux, VLC_TRUE );
529 out->i_flags |= BLOCK_FLAG_HEADER;
530 sout_AccessOutWrite( p_mux->p_access, out );
532 p_sys->b_write_header = VLC_FALSE;
537 sout_input_t *p_input;
544 if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
546 /* not enough data */
550 if( p_sys->i_dts_first < 0 )
552 p_sys->i_dts_first = i_dts;
554 if( p_sys->i_dts_last < i_dts )
556 p_sys->i_dts_last = i_dts;
559 p_input = p_mux->pp_inputs[i_stream];
560 tk = (asf_track_t*)p_input->p_sys;
562 data = block_FifoGet( p_input->p_fifo );
564 if( ( pk = asf_packet_create( p_mux, tk, data ) ) )
566 sout_AccessOutWrite( p_mux->p_access, pk );
574 static int MuxGetStream( sout_mux_t *p_mux,
582 for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
584 sout_input_t *p_input = p_mux->pp_inputs[i];
587 if( p_input->p_fifo->i_depth <= 0 )
589 if( p_input->p_fmt->i_cat == AUDIO_ES ||
590 p_input->p_fmt->i_cat == VIDEO_ES )
592 /* We need that audio+video fifo contain at least 1 packet */
599 p_data = block_FifoShow( p_input->p_fifo );
600 if( i_stream == -1 ||
601 p_data->i_dts < i_dts )
604 i_dts = p_data->i_dts;
608 *pi_stream = i_stream;
614 /****************************************************************************
615 * Asf header construction
616 ****************************************************************************/
618 /****************************************************************************
620 ****************************************************************************/
621 static void bo_init( bo_t *p_bo, uint8_t *p_buffer, int i_size )
623 p_bo->i_buffer_size = i_size;
625 p_bo->p_buffer = p_buffer;
627 static void bo_add_u8( bo_t *p_bo, uint8_t i )
629 if( p_bo->i_buffer < p_bo->i_buffer_size )
631 p_bo->p_buffer[p_bo->i_buffer] = i;
635 static void bo_addle_u16( bo_t *p_bo, uint16_t i )
637 bo_add_u8( p_bo, i &0xff );
638 bo_add_u8( p_bo, ( ( i >> 8) &0xff ) );
640 static void bo_addle_u32( bo_t *p_bo, uint32_t i )
642 bo_addle_u16( p_bo, i &0xffff );
643 bo_addle_u16( p_bo, ( ( i >> 16) &0xffff ) );
645 static void bo_addle_u64( bo_t *p_bo, uint64_t i )
647 bo_addle_u32( p_bo, i &0xffffffff );
648 bo_addle_u32( p_bo, ( ( i >> 32) &0xffffffff ) );
651 static void bo_add_mem( bo_t *p_bo, uint8_t *p_mem, int i_size )
653 int i_copy = __MIN( i_size, p_bo->i_buffer_size - p_bo->i_buffer );
657 memcpy( &p_bo->p_buffer[p_bo->i_buffer],
661 p_bo->i_buffer += i_size;
664 static void bo_addle_str16( bo_t *bo, char *str )
666 bo_addle_u16( bo, strlen( str ) + 1 );
672 bo_addle_u16( bo, c );
680 static void bo_addle_str16_nosize( bo_t *bo, char *str )
687 bo_addle_u16( bo, c );
695 /****************************************************************************
697 ****************************************************************************/
698 static void bo_add_guid( bo_t *p_bo, const guid_t *id )
701 bo_addle_u32( p_bo, id->v1 );
702 bo_addle_u16( p_bo, id->v2 );
703 bo_addle_u16( p_bo, id->v3 );
704 for( i = 0; i < 8; i++ )
706 bo_add_u8( p_bo, id->v4[i] );
710 static const guid_t asf_object_header_guid =
715 { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
717 static const guid_t asf_object_data_guid =
722 { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
725 static const guid_t asf_object_file_properties_guid =
730 { 0x8e,0xe4, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
733 static const guid_t asf_object_stream_properties_guid =
738 { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
741 static const guid_t asf_object_header_extention_guid =
746 { 0x8E,0xE3, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
749 static const guid_t asf_object_stream_type_audio =
754 { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
757 static const guid_t asf_object_stream_type_video =
762 { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
765 static const guid_t asf_guid_audio_conceal_none =
770 { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
772 static const guid_t asf_guid_video_conceal_none =
777 { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
779 static const guid_t asf_guid_reserved_1 =
784 { 0x8E, 0xE6,0x00, 0xC0, 0x0C ,0x20, 0x53, 0x65 }
786 static const guid_t asf_object_codec_comment_guid =
791 { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }
793 static const guid_t asf_object_codec_comment_reserved_guid =
798 { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }
800 static const guid_t asf_object_content_description_guid =
805 { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }
808 static void asf_chunk_add( bo_t *bo,
809 int i_type, int i_len, int i_flags, int i_seq )
811 bo_addle_u16( bo, i_type );
812 bo_addle_u16( bo, i_len + 8 );
813 bo_addle_u32( bo, i_seq );
814 bo_addle_u16( bo, i_flags );
815 bo_addle_u16( bo, i_len + 8 );
818 static block_t *asf_header_create( sout_mux_t *p_mux,
819 vlc_bool_t b_broadcast )
821 sout_mux_sys_t *p_sys = p_mux->p_sys;
824 mtime_t i_duration = 0;
832 if( p_sys->i_dts_first > 0 )
834 i_duration = p_sys->i_dts_last - p_sys->i_dts_first;
841 /* calculate header size */
842 i_size = 30 + 104 + 46;
844 for( i = 1; i < p_sys->i_track; i++ )
846 i_size += 78 + p_sys->track[i].i_extra;
847 i_ci_size += 8 + 2 * strlen( p_sys->track[i].psz_name );
848 if( p_sys->track[i].i_cat == AUDIO_ES )
852 else if( p_sys->track[i].i_cat == VIDEO_ES )
857 if( *p_sys->psz_title || *p_sys->psz_author || *p_sys->psz_copyright ||
858 *p_sys->psz_comment || *p_sys->psz_rating )
860 i_cd_size = 34 + 2 * ( strlen( p_sys->psz_title ) + 1 +
861 strlen( p_sys->psz_author ) + 1 +
862 strlen( p_sys->psz_copyright ) + 1 +
863 strlen( p_sys->psz_comment ) + 1 +
864 strlen( p_sys->psz_rating ) + 1 );
867 i_size += i_ci_size + i_cd_size;
869 if( p_sys->b_asf_http )
871 out = block_New( p_mux, i_size + 50 + 12 );
872 bo_init( &bo, out->p_buffer, i_size + 50 + 12 );
873 asf_chunk_add( &bo, 0x4824, i_size + 50, 0xc00, p_sys->i_seq++ );
877 out = block_New( p_mux, i_size + 50 );
878 bo_init( &bo, out->p_buffer, i_size + 50 );
881 bo_add_guid ( &bo, &asf_object_header_guid );
882 bo_addle_u64( &bo, i_size );
883 bo_addle_u32( &bo, 2 + p_sys->i_track - 1 );
884 bo_add_u8 ( &bo, 1 );
885 bo_add_u8 ( &bo, 2 );
889 /* file properties */
890 bo_add_guid ( &bo, &asf_object_file_properties_guid );
891 bo_addle_u64( &bo, 104 );
892 bo_add_guid ( &bo, &p_sys->fid );
893 bo_addle_u64( &bo, i_size + 50 + p_sys->i_packet_count *
894 p_sys->i_packet_size ); /* file size */
895 bo_addle_u64( &bo, 0 ); /* creation date */
896 bo_addle_u64( &bo, b_broadcast ? 0xffffffffLL : p_sys->i_packet_count );
897 bo_addle_u64( &bo, i_duration * 10 ); /* play duration (100ns) */
898 bo_addle_u64( &bo, i_duration * 10 ); /* send duration (100ns) */
899 bo_addle_u64( &bo, 3000 ); /* preroll duration (ms) */
900 bo_addle_u32( &bo, b_broadcast ? 0x01 : 0x00); /* flags */
901 bo_addle_u32( &bo, p_sys->i_packet_size ); /* packet size min */
902 bo_addle_u32( &bo, p_sys->i_packet_size ); /* packet size max */
903 bo_addle_u32( &bo, p_sys->i_bitrate ); /* maxbitrate */
905 /* header extention */
906 bo_add_guid ( &bo, &asf_object_header_extention_guid );
907 bo_addle_u64( &bo, 46 );
908 bo_add_guid ( &bo, &asf_guid_reserved_1 );
909 bo_addle_u16( &bo, 6 );
910 bo_addle_u32( &bo, 0 );
912 /* content description header */
915 bo_add_guid ( &bo, &asf_object_content_description_guid );
916 bo_addle_u64( &bo, i_cd_size );
917 bo_addle_u16( &bo, 2 * strlen( p_sys->psz_title ) + 2 );
918 bo_addle_u16( &bo, 2 * strlen( p_sys->psz_author ) + 2 );
919 bo_addle_u16( &bo, 2 * strlen( p_sys->psz_copyright ) + 2 );
920 bo_addle_u16( &bo, 2 * strlen( p_sys->psz_comment ) + 2 );
921 bo_addle_u16( &bo, 2 * strlen( p_sys->psz_rating ) + 2 );
923 bo_addle_str16_nosize( &bo, p_sys->psz_title );
924 bo_addle_str16_nosize( &bo, p_sys->psz_author );
925 bo_addle_str16_nosize( &bo, p_sys->psz_copyright );
926 bo_addle_str16_nosize( &bo, p_sys->psz_comment );
927 bo_addle_str16_nosize( &bo, p_sys->psz_rating );
930 /* stream properties */
931 for( i = 1; i < p_sys->i_track; i++ )
933 tk = &p_sys->track[i];
935 bo_add_guid ( &bo, &asf_object_stream_properties_guid );
936 bo_addle_u64( &bo, 78 + tk->i_extra );
937 if( tk->i_cat == AUDIO_ES )
939 bo_add_guid( &bo, &asf_object_stream_type_audio );
940 bo_add_guid( &bo, &asf_guid_audio_conceal_none );
942 else if( tk->i_cat == VIDEO_ES )
944 bo_add_guid( &bo, &asf_object_stream_type_video );
945 bo_add_guid( &bo, &asf_guid_video_conceal_none );
947 bo_addle_u64( &bo, 0 ); /* time offset */
948 bo_addle_u32( &bo, tk->i_extra );
949 bo_addle_u32( &bo, 0 ); /* 0 */
950 bo_addle_u16( &bo, tk->i_id ); /* stream number */
951 bo_addle_u32( &bo, 0 );
952 bo_add_mem ( &bo, tk->p_extra, tk->i_extra );
956 bo_add_guid ( &bo, &asf_object_codec_comment_guid );
957 bo_addle_u64( &bo, i_ci_size );
958 bo_add_guid ( &bo, &asf_object_codec_comment_reserved_guid );
959 bo_addle_u32( &bo, p_sys->i_track - 1 );
960 for( i = 1; i < p_sys->i_track; i++ )
962 tk = &p_sys->track[i];
964 bo_addle_u16( &bo, tk->i_id );
965 bo_addle_str16( &bo, tk->psz_name );
966 bo_addle_u16( &bo, 0 );
967 if( tk->i_cat == AUDIO_ES )
969 bo_addle_u16( &bo, 2 );
970 bo_addle_u16( &bo, tk->i_tag );
972 else if( tk->i_cat == VIDEO_ES )
974 bo_addle_u16( &bo, 4 );
975 bo_add_mem ( &bo, (uint8_t*)&tk->i_fourcc, 4 );
981 bo_add_guid ( &bo, &asf_object_data_guid );
982 bo_addle_u64( &bo, 50 + p_sys->i_packet_count * p_sys->i_packet_size );
983 bo_add_guid ( &bo, &p_sys->fid );
984 bo_addle_u64( &bo, p_sys->i_packet_count );
985 bo_addle_u16( &bo, 0x101 );
990 /****************************************************************************
992 ****************************************************************************/
993 static block_t *asf_packet_create( sout_mux_t *p_mux,
994 asf_track_t *tk, block_t *data )
996 sout_mux_sys_t *p_sys = p_mux->p_sys;
998 int i_data = data->i_buffer;
1000 uint8_t *p_data= data->p_buffer;
1001 block_t *first = NULL, **last = &first;
1002 int i_preheader = p_sys->b_asf_http ? 12 : 0;
1004 while( i_pos < i_data )
1009 if( p_sys->pk == NULL )
1011 p_sys->pk = block_New( p_mux,
1012 p_sys->i_packet_size + i_preheader);
1013 /* reserve 14 bytes for the packet header */
1014 p_sys->i_pk_used = 14 + i_preheader;
1015 p_sys->i_pk_frame = 0;
1016 p_sys->i_pk_dts = data->i_dts;
1020 bo_init( &bo, &p_sys->pk->p_buffer[p_sys->i_pk_used],
1021 p_sys->i_packet_size - p_sys->i_pk_used );
1023 /* add payload (header size = 17) */
1024 i_payload = __MIN( i_data - i_pos,
1025 p_sys->i_packet_size - p_sys->i_pk_used - 17 );
1026 bo_add_u8 ( &bo, 0x80 | tk->i_id );
1027 bo_add_u8 ( &bo, tk->i_sequence );
1028 bo_addle_u32( &bo, i_pos );
1029 bo_add_u8 ( &bo, 0x08 ); /* flags */
1030 bo_addle_u32( &bo, i_data );
1031 bo_addle_u32( &bo, ( data->i_dts - p_sys->i_dts_first )/ 1000 );
1032 bo_addle_u16( &bo, i_payload );
1033 bo_add_mem ( &bo, &p_data[i_pos], i_payload );
1035 p_sys->i_pk_used += 17 + i_payload;
1037 p_sys->i_pk_frame++;
1039 if( p_sys->i_pk_used + 17 >= p_sys->i_packet_size )
1041 /* not enough data for another payload, flush the packet */
1042 int i_pad = p_sys->i_packet_size - p_sys->i_pk_used;
1044 bo_init( &bo, p_sys->pk->p_buffer, 14 + i_preheader );
1046 if( p_sys->b_asf_http )
1048 asf_chunk_add( &bo, 0x4424,
1049 p_sys->i_packet_size, 0x00, p_sys->i_seq++);
1051 bo_add_u8 ( &bo, 0x82 );
1052 bo_addle_u16( &bo, 0 );
1053 bo_add_u8( &bo, 0x11 );
1054 bo_add_u8( &bo, 0x5d );
1055 bo_addle_u16( &bo, i_pad );
1056 bo_addle_u32( &bo, ( p_sys->i_pk_dts - p_sys->i_dts_first )/ 1000 );
1057 bo_addle_u16( &bo, 0 * data->i_length / 1000 );
1058 bo_add_u8( &bo, 0x80 | p_sys->i_pk_frame );
1060 /* append the packet */
1062 last = &p_sys->pk->p_next;
1066 p_sys->i_packet_count++;
1071 block_Release( data );
1076 static block_t *asf_stream_end_create( sout_mux_t *p_mux )
1078 sout_mux_sys_t *p_sys = p_mux->p_sys;
1080 block_t *out = NULL;
1083 if( p_sys->b_asf_http )
1085 out = block_New( p_mux, 12 );
1086 bo_init( &bo, out->p_buffer, 12 );
1087 asf_chunk_add( &bo, 0x4524, 0, 0x00, p_sys->i_seq++ );