MacGUI: Fix a warning on 10.5
[HandBrake.git] / libhb / muxavi.c
blob92ec80668037fb64df53d988b27d12d97de9282e
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. */
7 #include "hb.h"
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__))
16 uint32_t FourCC;
17 uint32_t BytesCount;
18 uint32_t MicroSecPerFrame;
19 uint32_t MaxBytesPerSec;
20 uint32_t PaddingGranularity;
21 uint32_t Flags;
22 uint32_t TotalFrames;
23 uint32_t InitialFrames;
24 uint32_t Streams;
25 uint32_t SuggestedBufferSize;
26 uint32_t Width;
27 uint32_t Height;
28 uint32_t Reserved[4];
30 } hb_avi_main_header_t;
32 typedef struct __attribute__((__packed__))
34 uint32_t FourCC;
35 uint32_t BytesCount;
36 uint32_t Type;
37 uint32_t Handler;
38 uint32_t Flags;
39 uint16_t Priority;
40 uint16_t Language;
41 uint32_t InitialFrames;
42 uint32_t Scale;
43 uint32_t Rate;
44 uint32_t Start;
45 uint32_t Length;
46 uint32_t SuggestedBufferSize;
47 uint32_t Quality;
48 uint32_t SampleSize;
49 int16_t Left;
50 int16_t Top;
51 int16_t Right;
52 int16_t Bottom;
54 } hb_avi_stream_header_t;
56 typedef struct __attribute__((__packed__))
58 uint32_t FourCC;
59 uint32_t BytesCount;
60 uint32_t Size;
61 uint32_t Width;
62 uint32_t Height;
63 uint16_t Planes;
64 uint16_t BitCount;
65 uint32_t Compression;
66 uint32_t SizeImage;
67 uint32_t XPelsPerMeter;
68 uint32_t YPelsPerMeter;
69 uint32_t ClrUsed;
70 uint32_t ClrImportant;
72 } hb_bitmap_info_t;
74 typedef struct __attribute__((__packed__))
76 uint32_t FourCC;
77 uint32_t BytesCount;
78 uint16_t FormatTag;
79 uint16_t Channels;
80 uint32_t SamplesPerSec;
81 uint32_t AvgBytesPerSec;
82 uint16_t BlockAlign;
83 uint16_t BitsPerSample;
84 uint16_t Size;
86 } hb_wave_formatex_t;
88 typedef struct __attribute__((__packed__))
90 uint16_t Id;
91 uint32_t Flags;
92 uint16_t BlockSize;
93 uint16_t FramesPerBlock;
94 uint16_t CodecDelay;
96 } hb_wave_mp3_t;
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 )
107 fputc( val, file );
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
223 HB_MUX_COMMON;
225 hb_job_t * job;
227 /* Data size in bytes, not including headers */
228 unsigned size;
229 FILE * file;
230 hb_buffer_t * index;
231 hb_avi_main_header_t main_header;
234 struct hb_mux_data_s
236 uint32_t fourcc;
237 hb_avi_stream_header_t header;
238 union
240 hb_bitmap_info_t v;
241 struct
243 hb_wave_formatex_t f;
244 hb_wave_mp3_t m;
245 } a;
246 } format;
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 /**********************************************************************
271 * AVIInit
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;
280 hb_audio_t * audio;
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 );
285 int hdrl_bytes;
286 int i;
288 /* Allocate index */
289 m->index = hb_buffer_init( 1024 * 1024 );
290 m->index->size = 0;
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;
304 #undef m
306 /* Video track */
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;
324 h.Rate = job->vrate;
325 #undef h
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;
334 f.Planes = 1;
335 f.BitCount = 24;
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" );
342 #undef f
344 /* Audio tracks */
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" );
359 h.InitialFrames = 1;
360 h.Scale = 1;
361 h.Rate = is_ac3 ? ( audio->bitrate / 8 ) :
362 ( job->abitrate * 1000 / 8 );
363 h.Quality = 0xFFFFFFFF;
364 h.SampleSize = 1;
366 /* Audio stream format */
367 f.FourCC = FOURCC( "strf" );
368 if( is_ac3 )
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;
375 else
377 f.BytesCount = sizeof( hb_wave_formatex_t ) +
378 sizeof( hb_wave_mp3_t ) - 8;
379 f.FormatTag = 0x55;
380 f.Channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(job->audio_mixdowns[i]);
381 f.SamplesPerSec = job->arate;
383 f.AvgBytesPerSec = h.Rate;
384 f.BlockAlign = 1;
385 if( is_ac3 )
387 f.Size = 0;
389 else
391 f.Size = sizeof( hb_wave_mp3_t );
392 m.Id = 1;
393 m.Flags = 2;
394 m.BlockSize = 1152 * f.AvgBytesPerSec / job->arate;
395 m.FramesPerBlock = 1;
396 m.CodecDelay = 1393;
398 #undef h
399 #undef f
400 #undef m
403 hdrl_bytes =
404 /* Main header */
405 4 + sizeof( hb_avi_main_header_t ) +
406 /* strh for video + audios */
407 ( 1 + audio_count ) * ( 12 + sizeof( hb_avi_stream_header_t ) ) +
408 /* video strf */
409 sizeof( hb_bitmap_info_t ) +
410 /* audios strf */
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 */
416 /* Main headers */
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 );
425 /* Video track */
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 );
436 /* Audio tracks */
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
445 than 8 tracks */
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 );
455 if( !is_ac3 )
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" ) );
471 return 0;
474 static int AVIMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
475 hb_buffer_t * buf )
477 hb_job_t * job = m->job;
478 hb_title_t * title = job->title;
480 hb_audio_t * audio;
481 int i;
483 /* Update index */
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 */
496 if( buf->size & 1 )
498 WriteInt8( m->file, 0 );
501 /* Update headers */
502 m->size += 8 + EVEN( buf->size );
503 mux_data->header.Length++;
505 /* RIFF size */
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 );
521 /* movi size */
522 fseek( m->file, 2052, SEEK_SET );
523 WriteInt32( m->file, 4 + m->size );
524 return 0;
527 static int AVIEnd( hb_mux_object_t * m )
529 hb_job_t * job = m->job;
531 hb_log( "muxavi: writing index" );
532 AddIndex( m );
534 hb_log( "muxavi: closing %s", job->file );
535 fclose( m->file );
537 hb_buffer_close( &m->index );
539 return 0;
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 );
545 m->init = AVIInit;
546 m->mux = AVIMux;
547 m->end = AVIEnd;
548 m->job = job;
549 return m;