1 /* $Id: muxavi.c,v 1.10 2005/03/30 18:17:29 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
9 #define AVIF_HASINDEX 0x10
10 #define AVIIF_KEYFRAME 0x10
11 #define FOURCC(a) ((a[3]<<24)|(a[2]<<16)|(a[1]<<8)|a[0])
13 /* Structures definitions */
14 typedef struct __attribute__((__packed__
))
18 uint32_t MicroSecPerFrame
;
19 uint32_t MaxBytesPerSec
;
20 uint32_t PaddingGranularity
;
23 uint32_t InitialFrames
;
25 uint32_t SuggestedBufferSize
;
30 } hb_avi_main_header_t
;
32 typedef struct __attribute__((__packed__
))
41 uint32_t InitialFrames
;
46 uint32_t SuggestedBufferSize
;
54 } hb_avi_stream_header_t
;
56 typedef struct __attribute__((__packed__
))
67 uint32_t XPelsPerMeter
;
68 uint32_t YPelsPerMeter
;
70 uint32_t ClrImportant
;
74 typedef struct __attribute__((__packed__
))
80 uint32_t SamplesPerSec
;
81 uint32_t AvgBytesPerSec
;
83 uint16_t BitsPerSample
;
88 typedef struct __attribute__((__packed__
))
93 uint16_t FramesPerBlock
;
98 static void WriteBuffer( FILE * file
, hb_buffer_t
* buf
)
100 fwrite( buf
->data
, buf
->size
, 1, file
);
103 /* Little-endian write routines */
105 static void WriteInt8( FILE * file
, uint8_t val
)
110 static void WriteInt16( FILE * file
, uint16_t val
)
112 fputc( val
& 0xFF, file
);
113 fputc( val
>> 8, file
);
116 static void WriteInt32( FILE * file
, uint32_t val
)
118 fputc( val
& 0xFF, file
);
119 fputc( ( val
>> 8 ) & 0xFF, file
);
120 fputc( ( val
>> 16 ) & 0xFF, file
);
121 fputc( val
>> 24, file
);
124 static void WriteBitmapInfo( FILE * file
, hb_bitmap_info_t
* info
)
126 WriteInt32( file
, info
->FourCC
);
127 WriteInt32( file
, info
->BytesCount
);
128 WriteInt32( file
, info
->Size
);
129 WriteInt32( file
, info
->Width
);
130 WriteInt32( file
, info
->Height
);
131 WriteInt16( file
, info
->Planes
);
132 WriteInt16( file
, info
->BitCount
);
133 WriteInt32( file
, info
->Compression
);
134 WriteInt32( file
, info
->SizeImage
);
135 WriteInt32( file
, info
->XPelsPerMeter
);
136 WriteInt32( file
, info
->YPelsPerMeter
);
137 WriteInt32( file
, info
->ClrUsed
);
138 WriteInt32( file
, info
->ClrImportant
);
141 static void WriteWaveFormatEx( FILE * file
, hb_wave_formatex_t
* format
)
143 WriteInt32( file
, format
->FourCC
);
144 WriteInt32( file
, format
->BytesCount
);
145 WriteInt16( file
, format
->FormatTag
);
146 WriteInt16( file
, format
->Channels
);
147 WriteInt32( file
, format
->SamplesPerSec
);
148 WriteInt32( file
, format
->AvgBytesPerSec
);
149 WriteInt16( file
, format
->BlockAlign
);
150 WriteInt16( file
, format
->BitsPerSample
);
151 WriteInt16( file
, format
->Size
);
154 static void WriteWaveMp3( FILE * file
, hb_wave_mp3_t
* mp3
)
156 WriteInt16( file
, mp3
->Id
);
157 WriteInt32( file
, mp3
->Flags
);
158 WriteInt16( file
, mp3
->BlockSize
);
159 WriteInt16( file
, mp3
->FramesPerBlock
);
160 WriteInt16( file
, mp3
->CodecDelay
);
163 static void WriteMainHeader( FILE * file
, hb_avi_main_header_t
* header
)
165 WriteInt32( file
, header
->FourCC
);
166 WriteInt32( file
, header
->BytesCount
);
167 WriteInt32( file
, header
->MicroSecPerFrame
);
168 WriteInt32( file
, header
->MaxBytesPerSec
);
169 WriteInt32( file
, header
->PaddingGranularity
);
170 WriteInt32( file
, header
->Flags
);
171 WriteInt32( file
, header
->TotalFrames
);
172 WriteInt32( file
, header
->InitialFrames
);
173 WriteInt32( file
, header
->Streams
);
174 WriteInt32( file
, header
->SuggestedBufferSize
);
175 WriteInt32( file
, header
->Width
);
176 WriteInt32( file
, header
->Height
);
177 WriteInt32( file
, header
->Reserved
[0] );
178 WriteInt32( file
, header
->Reserved
[1] );
179 WriteInt32( file
, header
->Reserved
[2] );
180 WriteInt32( file
, header
->Reserved
[3] );
183 static void WriteStreamHeader( FILE * file
, hb_avi_stream_header_t
* header
)
185 WriteInt32( file
, header
->FourCC
);
186 WriteInt32( file
, header
->BytesCount
);
187 WriteInt32( file
, header
->Type
);
188 WriteInt32( file
, header
->Handler
);
189 WriteInt32( file
, header
->Flags
);
190 WriteInt16( file
, header
->Priority
);
191 WriteInt16( file
, header
->Language
);
192 WriteInt32( file
, header
->InitialFrames
);
193 WriteInt32( file
, header
->Scale
);
194 WriteInt32( file
, header
->Rate
);
195 WriteInt32( file
, header
->Start
);
196 WriteInt32( file
, header
->Length
);
197 WriteInt32( file
, header
->SuggestedBufferSize
);
198 WriteInt32( file
, header
->Quality
);
199 WriteInt32( file
, header
->SampleSize
);
200 WriteInt16( file
, header
->Left
);
201 WriteInt16( file
, header
->Top
);
202 WriteInt16( file
, header
->Right
);
203 WriteInt16( file
, header
->Bottom
);
206 static void IndexAddInt32( hb_buffer_t
* b
, uint32_t val
)
208 if( b
->size
+ 16 > b
->alloc
)
210 hb_log( "muxavi: reallocing index (%d MB)",
211 1 + b
->alloc
/ 1024 / 1024 );
212 hb_buffer_realloc( b
, b
->alloc
+ 1024 * 1024 );
215 b
->data
[b
->size
++] = val
& 0xFF;
216 b
->data
[b
->size
++] = ( val
>> 8 ) & 0xFF;
217 b
->data
[b
->size
++] = ( val
>> 16 ) & 0xFF;
218 b
->data
[b
->size
++] = val
>> 24;
221 struct hb_mux_object_s
227 /* Data size in bytes, not including headers */
231 hb_avi_main_header_t main_header
;
237 hb_avi_stream_header_t header
;
243 hb_wave_formatex_t f
;
249 static void AddIndex( hb_mux_object_t
* m
)
251 fseek( m
->file
, 0, SEEK_END
);
253 /* Write the index at the end of the file */
254 WriteInt32( m
->file
, FOURCC( "idx1" ) );
255 WriteInt32( m
->file
, m
->index
->size
);
256 WriteBuffer( m
->file
, m
->index
);
258 /* Update file size */
259 m
->size
+= 8 + m
->index
->size
;
260 fseek( m
->file
, 4, SEEK_SET
);
261 WriteInt32( m
->file
, 2040 + m
->size
);
263 /* Update HASINDEX flag */
264 m
->main_header
.Flags
|= AVIF_HASINDEX
;
265 fseek( m
->file
, 24, SEEK_SET
);
266 WriteMainHeader( m
->file
, &m
->main_header
);
270 /**********************************************************************
272 **********************************************************************
273 * Allocates things, create file, initialize and write headers
274 *********************************************************************/
275 static int AVIInit( hb_mux_object_t
* m
)
277 hb_job_t
* job
= m
->job
;
278 hb_title_t
* title
= job
->title
;
281 hb_mux_data_t
* mux_data
;
283 int audio_count
= hb_list_count( title
->list_audio
);
284 int is_ac3
= ( job
->acodec
& HB_ACODEC_AC3
);
289 m
->index
= hb_buffer_init( 1024 * 1024 );
292 /* Open destination file */
293 hb_log( "muxavi: opening %s", job
->file
);
294 m
->file
= fopen( job
->file
, "wb" );
296 #define m m->main_header
297 /* AVI main header */
298 m
.FourCC
= FOURCC( "avih" );
299 m
.BytesCount
= sizeof( hb_avi_main_header_t
) - 8;
300 m
.MicroSecPerFrame
= (uint64_t) 1000000 * job
->vrate_base
/ job
->vrate
;
301 m
.Streams
= 1 + audio_count
;
302 m
.Width
= job
->width
;
303 m
.Height
= job
->height
;
307 mux_data
= calloc( sizeof( hb_mux_data_t
), 1 );
308 job
->mux_data
= mux_data
;
310 #define h mux_data->header
311 /* Video stream header */
312 h
.FourCC
= FOURCC( "strh" );
313 h
.BytesCount
= sizeof( hb_avi_stream_header_t
) - 8;
314 h
.Type
= FOURCC( "vids" );
316 if( job
->vcodec
== HB_VCODEC_FFMPEG
)
317 h
.Handler
= FOURCC( "divx" );
318 else if( job
->vcodec
== HB_VCODEC_XVID
)
319 h
.Handler
= FOURCC( "xvid" );
320 else if( job
->vcodec
== HB_VCODEC_X264
)
321 h
.Handler
= FOURCC( "h264" );
323 h
.Scale
= job
->vrate_base
;
327 #define f mux_data->format.v
328 /* Video stream format */
329 f
.FourCC
= FOURCC( "strf" );
330 f
.BytesCount
= sizeof( hb_bitmap_info_t
) - 8;
331 f
.Size
= f
.BytesCount
;
332 f
.Width
= job
->width
;
333 f
.Height
= job
->height
;
336 if( job
->vcodec
== HB_VCODEC_FFMPEG
)
337 f
.Compression
= FOURCC( "DX50" );
338 else if( job
->vcodec
== HB_VCODEC_XVID
)
339 f
.Compression
= FOURCC( "XVID" );
340 else if( job
->vcodec
== HB_VCODEC_X264
)
341 f
.Compression
= FOURCC( "H264" );
345 for( i
= 0; i
< hb_list_count( title
->list_audio
); i
++ )
347 audio
= hb_list_item( title
->list_audio
, i
);
349 mux_data
= calloc( sizeof( hb_mux_data_t
), 1 );
350 audio
->mux_data
= mux_data
;
352 #define h mux_data->header
353 #define f mux_data->format.a.f
354 #define m mux_data->format.a.m
355 /* Audio stream header */
356 h
.FourCC
= FOURCC( "strh" );
357 h
.BytesCount
= sizeof( hb_avi_stream_header_t
) - 8;
358 h
.Type
= FOURCC( "auds" );
361 h
.Rate
= is_ac3
? ( audio
->bitrate
/ 8 ) :
362 ( job
->abitrate
* 1000 / 8 );
363 h
.Quality
= 0xFFFFFFFF;
366 /* Audio stream format */
367 f
.FourCC
= FOURCC( "strf" );
370 f
.BytesCount
= sizeof( hb_wave_formatex_t
) - 8;
371 f
.FormatTag
= 0x2000;
372 f
.Channels
= HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio
->input_channel_layout
);
373 f
.SamplesPerSec
= audio
->rate
;
377 f
.BytesCount
= sizeof( hb_wave_formatex_t
) +
378 sizeof( hb_wave_mp3_t
) - 8;
380 f
.Channels
= HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(job
->audio_mixdowns
[i
]);
381 f
.SamplesPerSec
= job
->arate
;
383 f
.AvgBytesPerSec
= h
.Rate
;
391 f
.Size
= sizeof( hb_wave_mp3_t
);
394 m
.BlockSize
= 1152 * f
.AvgBytesPerSec
/ job
->arate
;
395 m
.FramesPerBlock
= 1;
405 4 + sizeof( hb_avi_main_header_t
) +
406 /* strh for video + audios */
407 ( 1 + audio_count
) * ( 12 + sizeof( hb_avi_stream_header_t
) ) +
409 sizeof( hb_bitmap_info_t
) +
411 audio_count
* ( sizeof( hb_wave_formatex_t
) +
412 ( is_ac3
? 0 : sizeof( hb_wave_mp3_t
) ) );
414 /* Here we really start to write into the file */
417 WriteInt32( m
->file
, FOURCC( "RIFF" ) );
418 WriteInt32( m
->file
, 2040 );
419 WriteInt32( m
->file
, FOURCC( "AVI " ) );
420 WriteInt32( m
->file
, FOURCC( "LIST" ) );
421 WriteInt32( m
->file
, hdrl_bytes
);
422 WriteInt32( m
->file
, FOURCC( "hdrl" ) );
423 WriteMainHeader( m
->file
, &m
->main_header
);
426 mux_data
= job
->mux_data
;
427 mux_data
->fourcc
= FOURCC( "00dc" );
429 WriteInt32( m
->file
, FOURCC( "LIST" ) );
430 WriteInt32( m
->file
, 4 + sizeof( hb_avi_stream_header_t
) +
431 sizeof( hb_bitmap_info_t
) );
432 WriteInt32( m
->file
, FOURCC( "strl" ) );
433 WriteStreamHeader( m
->file
, &mux_data
->header
);
434 WriteBitmapInfo( m
->file
, &mux_data
->format
.v
);
437 for( i
= 0; i
< audio_count
; i
++ )
439 char fourcc
[4] = "00wb";
441 audio
= hb_list_item( title
->list_audio
, i
);
442 mux_data
= audio
->mux_data
;
444 fourcc
[1] = '1' + i
; /* This is fine as we don't allow more
446 mux_data
->fourcc
= FOURCC( fourcc
);
448 WriteInt32( m
->file
, FOURCC( "LIST" ) );
449 WriteInt32( m
->file
, 4 + sizeof( hb_avi_stream_header_t
) +
450 sizeof( hb_wave_formatex_t
) +
451 ( is_ac3
? 0 : sizeof( hb_wave_mp3_t
) ) );
452 WriteInt32( m
->file
, FOURCC( "strl" ) );
453 WriteStreamHeader( m
->file
, &mux_data
->header
);
454 WriteWaveFormatEx( m
->file
, &mux_data
->format
.a
.f
);
457 WriteWaveMp3( m
->file
, &mux_data
->format
.a
.m
);
461 WriteInt32( m
->file
, FOURCC( "JUNK" ) );
462 WriteInt32( m
->file
, 2020 - hdrl_bytes
);
463 for( i
= 0; i
< 2020 - hdrl_bytes
; i
++ )
465 WriteInt8( m
->file
, 0 );
467 WriteInt32( m
->file
, FOURCC( "LIST" ) );
468 WriteInt32( m
->file
, 4 );
469 WriteInt32( m
->file
, FOURCC( "movi" ) );
474 static int AVIMux( hb_mux_object_t
* m
, hb_mux_data_t
* mux_data
,
477 hb_job_t
* job
= m
->job
;
478 hb_title_t
* title
= job
->title
;
484 IndexAddInt32( m
->index
, mux_data
->fourcc
);
485 IndexAddInt32( m
->index
, (buf
->frametype
& HB_FRAME_KEY
) ? AVIIF_KEYFRAME
: 0 );
486 IndexAddInt32( m
->index
, 4 + m
->size
);
487 IndexAddInt32( m
->index
, buf
->size
);
489 /* Write the chunk to the file */
490 fseek( m
->file
, 0, SEEK_END
);
491 WriteInt32( m
->file
, mux_data
->fourcc
);
492 WriteInt32( m
->file
, buf
->size
);
493 WriteBuffer( m
->file
, buf
);
495 /* Chunks must be 2-bytes aligned */
498 WriteInt8( m
->file
, 0 );
502 m
->size
+= 8 + EVEN( buf
->size
);
503 mux_data
->header
.Length
++;
506 fseek( m
->file
, 4, SEEK_SET
);
507 WriteInt32( m
->file
, 2052 + m
->size
);
509 /* Mmmmh that's not nice */
510 fseek( m
->file
, 140, SEEK_SET
);
511 WriteInt32( m
->file
, job
->mux_data
->header
.Length
);
512 for( i
= 0; i
< hb_list_count( title
->list_audio
); i
++ )
514 audio
= hb_list_item( title
->list_audio
, i
);
515 fseek( m
->file
, 264 + i
*
516 ( 102 + ( ( job
->acodec
& HB_ACODEC_AC3
) ? 0 :
517 sizeof( hb_wave_mp3_t
) ) ), SEEK_SET
);
518 WriteInt32( m
->file
, audio
->mux_data
->header
.Length
);
522 fseek( m
->file
, 2052, SEEK_SET
);
523 WriteInt32( m
->file
, 4 + m
->size
);
527 static int AVIEnd( hb_mux_object_t
* m
)
529 hb_job_t
* job
= m
->job
;
531 hb_log( "muxavi: writing index" );
534 hb_log( "muxavi: closing %s", job
->file
);
537 hb_buffer_close( &m
->index
);
542 hb_mux_object_t
* hb_mux_avi_init( hb_job_t
* job
)
544 hb_mux_object_t
* m
= calloc( sizeof( hb_mux_object_t
), 1 );