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.fr/>.
5 It may be used under the terms of the GNU General Public License. */
10 #define AVIF_HASINDEX 0x10
11 #define AVIIF_KEYFRAME 0x10
12 #define FOURCC(a) ((a[3]<<24)|(a[2]<<16)|(a[1]<<8)|a[0])
14 /* Structures definitions */
15 typedef struct __attribute__((__packed__))
19 uint32_t MicroSecPerFrame;
20 uint32_t MaxBytesPerSec;
21 uint32_t PaddingGranularity;
24 uint32_t InitialFrames;
26 uint32_t SuggestedBufferSize;
31 } hb_avi_main_header_t;
33 typedef struct __attribute__((__packed__))
42 uint32_t InitialFrames;
47 uint32_t SuggestedBufferSize;
55 } hb_avi_stream_header_t;
57 typedef struct __attribute__((__packed__))
61 uint32_t VideoFormatToken;
62 uint32_t VideoStandard;
63 uint32_t dwVerticalRefreshRate;
65 uint32_t dwVTotalInLines;
66 uint16_t dwFrameAspectRatioDen;
67 uint16_t dwFrameAspectRatioNum;
68 uint32_t dwFrameWidthInPixels;
69 uint32_t dwFrameHeightInLines;
70 uint32_t nbFieldPerFrame;
71 uint32_t CompressedBMHeight;
72 uint32_t CompressedBMWidth;
73 uint32_t ValidBMHeight;
74 uint32_t ValidBMWidth;
75 uint32_t ValidBMXOffset;
76 uint32_t ValidBMYOffset;
77 uint32_t VideoXOffsetInT;
78 uint32_t VideoYValidStartLine;
82 typedef struct __attribute__((__packed__))
93 uint32_t XPelsPerMeter;
94 uint32_t YPelsPerMeter;
96 uint32_t ClrImportant;
100 typedef struct __attribute__((__packed__))
106 uint32_t SamplesPerSec;
107 uint32_t AvgBytesPerSec;
109 uint16_t BitsPerSample;
112 } hb_wave_formatex_t;
114 typedef struct __attribute__((__packed__))
119 uint16_t FramesPerBlock;
124 static void WriteBuffer( FILE * file, hb_buffer_t * buf )
126 fwrite( buf->data, buf->size, 1, file );
129 /* Little-endian write routines */
131 static void WriteInt8( FILE * file, uint8_t val )
136 static void WriteInt16( FILE * file, uint16_t val )
138 fputc( val & 0xFF, file );
139 fputc( val >> 8, file );
142 static void WriteInt32( FILE * file, uint32_t val )
144 fputc( val & 0xFF, file );
145 fputc( ( val >> 8 ) & 0xFF, file );
146 fputc( ( val >> 16 ) & 0xFF, file );
147 fputc( val >> 24, file );
150 static void WriteBitmapInfo( FILE * file, hb_bitmap_info_t * info )
152 WriteInt32( file, info->FourCC );
153 WriteInt32( file, info->BytesCount );
154 WriteInt32( file, info->Size );
155 WriteInt32( file, info->Width );
156 WriteInt32( file, info->Height );
157 WriteInt16( file, info->Planes );
158 WriteInt16( file, info->BitCount );
159 WriteInt32( file, info->Compression );
160 WriteInt32( file, info->SizeImage );
161 WriteInt32( file, info->XPelsPerMeter );
162 WriteInt32( file, info->YPelsPerMeter );
163 WriteInt32( file, info->ClrUsed );
164 WriteInt32( file, info->ClrImportant );
167 static void WriteWaveFormatEx( FILE * file, hb_wave_formatex_t * format )
169 WriteInt32( file, format->FourCC );
170 WriteInt32( file, format->BytesCount );
171 WriteInt16( file, format->FormatTag );
172 WriteInt16( file, format->Channels );
173 WriteInt32( file, format->SamplesPerSec );
174 WriteInt32( file, format->AvgBytesPerSec );
175 WriteInt16( file, format->BlockAlign );
176 WriteInt16( file, format->BitsPerSample );
177 WriteInt16( file, format->Size );
180 static void WriteWaveMp3( FILE * file, hb_wave_mp3_t * mp3 )
182 WriteInt16( file, mp3->Id );
183 WriteInt32( file, mp3->Flags );
184 WriteInt16( file, mp3->BlockSize );
185 WriteInt16( file, mp3->FramesPerBlock );
186 WriteInt16( file, mp3->CodecDelay );
189 static void WriteMainHeader( FILE * file, hb_avi_main_header_t * header )
191 WriteInt32( file, header->FourCC );
192 WriteInt32( file, header->BytesCount );
193 WriteInt32( file, header->MicroSecPerFrame );
194 WriteInt32( file, header->MaxBytesPerSec );
195 WriteInt32( file, header->PaddingGranularity );
196 WriteInt32( file, header->Flags );
197 WriteInt32( file, header->TotalFrames );
198 WriteInt32( file, header->InitialFrames );
199 WriteInt32( file, header->Streams );
200 WriteInt32( file, header->SuggestedBufferSize );
201 WriteInt32( file, header->Width );
202 WriteInt32( file, header->Height );
203 WriteInt32( file, header->Reserved[0] );
204 WriteInt32( file, header->Reserved[1] );
205 WriteInt32( file, header->Reserved[2] );
206 WriteInt32( file, header->Reserved[3] );
209 static void WriteStreamHeader( FILE * file, hb_avi_stream_header_t * header )
211 WriteInt32( file, header->FourCC );
212 WriteInt32( file, header->BytesCount );
213 WriteInt32( file, header->Type );
214 WriteInt32( file, header->Handler );
215 WriteInt32( file, header->Flags );
216 WriteInt16( file, header->Priority );
217 WriteInt16( file, header->Language );
218 WriteInt32( file, header->InitialFrames );
219 WriteInt32( file, header->Scale );
220 WriteInt32( file, header->Rate );
221 WriteInt32( file, header->Start );
222 WriteInt32( file, header->Length );
223 WriteInt32( file, header->SuggestedBufferSize );
224 WriteInt32( file, header->Quality );
225 WriteInt32( file, header->SampleSize );
226 WriteInt16( file, header->Left );
227 WriteInt16( file, header->Top );
228 WriteInt16( file, header->Right );
229 WriteInt16( file, header->Bottom );
232 static void WriteVprpInfo( FILE * file, hb_avi_vprp_info_t * info )
234 WriteInt32( file, info->FourCC );
235 WriteInt32( file, info->BytesCount );
236 WriteInt32( file, info->VideoFormatToken );
237 WriteInt32( file, info->VideoStandard );
238 WriteInt32( file, info->dwVerticalRefreshRate );
239 WriteInt32( file, info->dwHTotalInT );
240 WriteInt32( file, info->dwVTotalInLines );
241 WriteInt16( file, info->dwFrameAspectRatioDen );
242 WriteInt16( file, info->dwFrameAspectRatioNum );
243 WriteInt32( file, info->dwFrameWidthInPixels );
244 WriteInt32( file, info->dwFrameHeightInLines );
245 WriteInt32( file, info->nbFieldPerFrame );
246 WriteInt32( file, info->CompressedBMHeight );
247 WriteInt32( file, info->CompressedBMWidth );
248 WriteInt32( file, info->ValidBMHeight );
249 WriteInt32( file, info->ValidBMWidth );
250 WriteInt32( file, info->ValidBMXOffset );
251 WriteInt32( file, info->ValidBMYOffset );
252 WriteInt32( file, info->VideoXOffsetInT );
253 WriteInt32( file, info->VideoYValidStartLine );
256 static void IndexAddInt32( hb_buffer_t * b, uint32_t val )
258 if( b->size + 16 > b->alloc )
260 hb_log( "muxavi: reallocing index (%d MB)",
261 1 + b->alloc / 1024 / 1024 );
262 hb_buffer_realloc( b, b->alloc + 1024 * 1024 );
265 b->data[b->size++] = val & 0xFF;
266 b->data[b->size++] = ( val >> 8 ) & 0xFF;
267 b->data[b->size++] = ( val >> 16 ) & 0xFF;
268 b->data[b->size++] = val >> 24;
271 struct hb_mux_object_s
277 /* Data size in bytes, not including headers */
281 hb_avi_main_header_t main_header;
287 hb_avi_stream_header_t header;
288 hb_avi_vprp_info_t vprp_header;
294 hb_wave_formatex_t f;
300 static void AddIndex( hb_mux_object_t * m )
302 fseek( m->file, 0, SEEK_END );
304 /* Write the index at the end of the file */
305 WriteInt32( m->file, FOURCC( "idx1" ) );
306 WriteInt32( m->file, m->index->size );
307 WriteBuffer( m->file, m->index );
309 /* Update file size */
310 m->size += 8 + m->index->size;
311 fseek( m->file, 4, SEEK_SET );
312 WriteInt32( m->file, 2040 + m->size );
314 /* Update HASINDEX flag */
315 m->main_header.Flags |= AVIF_HASINDEX;
316 fseek( m->file, 24, SEEK_SET );
317 WriteMainHeader( m->file, &m->main_header );
321 /**********************************************************************
323 **********************************************************************
324 * Allocates things, create file, initialize and write headers
325 *********************************************************************/
326 static int AVIInit( hb_mux_object_t * m )
328 hb_job_t * job = m->job;
329 hb_title_t * title = job->title;
332 hb_mux_data_t * mux_data;
334 int audio_count = hb_list_count( title->list_audio );
341 m->index = hb_buffer_init( 1024 * 1024 );
344 /* Open destination file */
345 hb_log( "muxavi: opening %s", job->file );
346 m->file = fopen( job->file, "wb" );
348 #define m m->main_header
349 /* AVI main header */
350 m.FourCC = FOURCC( "avih" );
351 m.BytesCount = sizeof( hb_avi_main_header_t ) - 8;
352 m.MicroSecPerFrame = (uint64_t) 1000000 * job->vrate_base / job->vrate;
353 m.Streams = 1 + audio_count;
354 m.Width = job->width;
355 m.Height = job->height;
359 mux_data = calloc( sizeof( hb_mux_data_t ), 1 );
360 job->mux_data = mux_data;
362 #define h mux_data->header
363 /* Video stream header */
364 h.FourCC = FOURCC( "strh" );
365 h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8;
366 h.Type = FOURCC( "vids" );
368 if( job->vcodec == HB_VCODEC_FFMPEG )
369 h.Handler = FOURCC( "divx" );
370 else if( job->vcodec == HB_VCODEC_X264 )
371 h.Handler = FOURCC( "h264" );
373 h.Scale = job->vrate_base;
377 #define f mux_data->format.v
378 /* Video stream format */
379 f.FourCC = FOURCC( "strf" );
380 f.BytesCount = sizeof( hb_bitmap_info_t ) - 8;
381 f.Size = f.BytesCount;
382 f.Width = job->width;
383 f.Height = job->height;
386 if( job->vcodec == HB_VCODEC_FFMPEG )
387 f.Compression = FOURCC( "DX50" );
388 else if( job->vcodec == HB_VCODEC_X264 )
389 f.Compression = FOURCC( "H264" );
392 #define g mux_data->vprp_header
393 /* Vprp video stream header */
394 AVRational sample_aspect_ratio = ( AVRational ){ job->anamorphic.par_width, job->anamorphic.par_height };
395 AVRational dar = av_mul_q( sample_aspect_ratio, ( AVRational ){ job->width, job->height } );
397 av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);
399 g.FourCC = FOURCC( "vprp" );
400 g.BytesCount = sizeof( hb_avi_vprp_info_t ) - 8;
401 g.VideoFormatToken = 0;
403 g.dwVerticalRefreshRate = job->vrate / job->vrate_base;
404 g.dwHTotalInT = job->width;
405 g.dwVTotalInLines = job->height;
406 g.dwFrameAspectRatioDen = den;
407 g.dwFrameAspectRatioNum = num;
408 g.dwFrameWidthInPixels = job->width;
409 g.dwFrameHeightInLines = job->height;
410 g.nbFieldPerFrame = 1;
411 g.CompressedBMHeight = job->height;
412 g.CompressedBMWidth = job->width;
413 g.ValidBMHeight = job->height;
414 g.ValidBMWidth = job->width;
415 g.ValidBMXOffset = 0;
416 g.ValidBMYOffset = 0;
417 g.VideoXOffsetInT = 0;
418 g.VideoYValidStartLine = 0;
422 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
424 audio = hb_list_item( title->list_audio, i );
426 is_ac3 = (audio->config.out.codec == HB_ACODEC_AC3);
427 is_passthru = (audio->config.out.codec == HB_ACODEC_AC3) ||
428 (audio->config.out.codec == HB_ACODEC_DCA);
430 mux_data = calloc( sizeof( hb_mux_data_t ), 1 );
431 audio->priv.mux_data = mux_data;
433 #define h mux_data->header
434 #define f mux_data->format.a.f
435 #define m mux_data->format.a.m
436 /* Audio stream header */
437 h.FourCC = FOURCC( "strh" );
438 h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8;
439 h.Type = FOURCC( "auds" );
442 h.Rate = is_passthru ? ( audio->config.in.bitrate / 8 ) :
443 ( audio->config.out.bitrate * 1000 / 8 );
444 h.Quality = 0xFFFFFFFF;
447 /* Audio stream format */
448 f.FourCC = FOURCC( "strf" );
451 f.BytesCount = sizeof( hb_wave_formatex_t ) - 8;
452 f.FormatTag = is_ac3 ? 0x2000 : 0x2001;
453 f.Channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout);
454 f.SamplesPerSec = audio->config.in.samplerate;
458 f.BytesCount = sizeof( hb_wave_formatex_t ) +
459 sizeof( hb_wave_mp3_t ) - 8;
461 f.Channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
462 f.SamplesPerSec = audio->config.out.samplerate;
464 f.AvgBytesPerSec = h.Rate;
472 f.Size = sizeof( hb_wave_mp3_t );
475 m.BlockSize = 1152 * f.AvgBytesPerSec / audio->config.out.samplerate;
476 m.FramesPerBlock = 1;
486 4 + sizeof( hb_avi_main_header_t ) +
487 /* strh for video + audios */
488 ( 1 + audio_count ) * ( 12 + sizeof( hb_avi_stream_header_t ) ) +
490 sizeof( hb_bitmap_info_t ) +
492 ( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) +
494 audio_count * ( sizeof( hb_wave_formatex_t ) +
495 ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) );
497 /* Here we really start to write into the file */
500 WriteInt32( m->file, FOURCC( "RIFF" ) );
501 WriteInt32( m->file, 2040 );
502 WriteInt32( m->file, FOURCC( "AVI " ) );
503 WriteInt32( m->file, FOURCC( "LIST" ) );
504 WriteInt32( m->file, hdrl_bytes );
505 WriteInt32( m->file, FOURCC( "hdrl" ) );
506 WriteMainHeader( m->file, &m->main_header );
509 mux_data = job->mux_data;
510 mux_data->fourcc = FOURCC( "00dc" );
512 WriteInt32( m->file, FOURCC( "LIST" ) );
513 WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
514 sizeof( hb_bitmap_info_t ) +
515 ( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) );
516 WriteInt32( m->file, FOURCC( "strl" ) );
517 WriteStreamHeader( m->file, &mux_data->header );
518 WriteBitmapInfo( m->file, &mux_data->format.v );
519 if( job->anamorphic.mode )
521 WriteVprpInfo( m->file, &mux_data->vprp_header );
525 for( i = 0; i < audio_count; i++ )
527 char fourcc[4] = "00wb";
529 audio = hb_list_item( title->list_audio, i );
530 mux_data = audio->priv.mux_data;
532 fourcc[1] = '1' + i; /* This is fine as we don't allow more
534 mux_data->fourcc = FOURCC( fourcc );
536 WriteInt32( m->file, FOURCC( "LIST" ) );
537 WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
538 sizeof( hb_wave_formatex_t ) +
539 ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) );
540 WriteInt32( m->file, FOURCC( "strl" ) );
541 WriteStreamHeader( m->file, &mux_data->header );
542 WriteWaveFormatEx( m->file, &mux_data->format.a.f );
545 WriteWaveMp3( m->file, &mux_data->format.a.m );
549 WriteInt32( m->file, FOURCC( "JUNK" ) );
550 WriteInt32( m->file, 2020 - hdrl_bytes );
551 for( i = 0; i < 2020 - hdrl_bytes; i++ )
553 WriteInt8( m->file, 0 );
555 WriteInt32( m->file, FOURCC( "LIST" ) );
556 WriteInt32( m->file, 4 );
557 WriteInt32( m->file, FOURCC( "movi" ) );
562 static int AVIMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
565 hb_job_t * job = m->job;
566 hb_title_t * title = job->title;
572 IndexAddInt32( m->index, mux_data->fourcc );
573 IndexAddInt32( m->index, (buf->frametype & HB_FRAME_KEY) ? AVIIF_KEYFRAME : 0 );
574 IndexAddInt32( m->index, 4 + m->size );
575 IndexAddInt32( m->index, buf->size );
577 /* Write the chunk to the file */
578 fseek( m->file, 0, SEEK_END );
579 WriteInt32( m->file, mux_data->fourcc );
580 WriteInt32( m->file, buf->size );
581 WriteBuffer( m->file, buf );
583 /* Chunks must be 2-bytes aligned */
586 WriteInt8( m->file, 0 );
590 m->size += 8 + EVEN( buf->size );
591 mux_data->header.Length++;
594 fseek( m->file, 4, SEEK_SET );
595 WriteInt32( m->file, 2052 + m->size );
597 /* Mmmmh that's not nice */
598 fseek( m->file, 140, SEEK_SET );
599 WriteInt32( m->file, job->mux_data->header.Length );
600 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
603 audio = hb_list_item( title->list_audio, i );
604 is_passthru = (audio->config.out.codec == HB_ACODEC_AC3) ||
605 (audio->config.out.codec == HB_ACODEC_DCA);
606 fseek( m->file, 264 + i *
607 ( 102 + ( is_passthru ? 0 :
608 sizeof( hb_wave_mp3_t ) ) ), SEEK_SET );
609 WriteInt32( m->file, audio->priv.mux_data->header.Length );
613 fseek( m->file, 2052, SEEK_SET );
614 WriteInt32( m->file, 4 + m->size );
618 static int AVIEnd( hb_mux_object_t * m )
620 hb_job_t * job = m->job;
622 hb_log( "muxavi: writing index" );
625 hb_log( "muxavi: closing %s", job->file );
628 hb_buffer_close( &m->index );
633 hb_mux_object_t * hb_mux_avi_init( hb_job_t * job )
635 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );