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 );
340 m->index = hb_buffer_init( 1024 * 1024 );
343 /* Open destination file */
344 hb_log( "muxavi: opening %s", job->file );
345 m->file = fopen( job->file, "wb" );
347 #define m m->main_header
348 /* AVI main header */
349 m.FourCC = FOURCC( "avih" );
350 m.BytesCount = sizeof( hb_avi_main_header_t ) - 8;
351 m.MicroSecPerFrame = (uint64_t) 1000000 * job->vrate_base / job->vrate;
352 m.Streams = 1 + audio_count;
353 m.Width = job->width;
354 m.Height = job->height;
358 mux_data = calloc( sizeof( hb_mux_data_t ), 1 );
359 job->mux_data = mux_data;
361 #define h mux_data->header
362 /* Video stream header */
363 h.FourCC = FOURCC( "strh" );
364 h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8;
365 h.Type = FOURCC( "vids" );
367 if( job->vcodec == HB_VCODEC_FFMPEG )
368 h.Handler = FOURCC( "divx" );
369 else if( job->vcodec == HB_VCODEC_XVID )
370 h.Handler = FOURCC( "xvid" );
371 else if( job->vcodec == HB_VCODEC_X264 )
372 h.Handler = FOURCC( "h264" );
374 h.Scale = job->vrate_base;
378 #define f mux_data->format.v
379 /* Video stream format */
380 f.FourCC = FOURCC( "strf" );
381 f.BytesCount = sizeof( hb_bitmap_info_t ) - 8;
382 f.Size = f.BytesCount;
383 f.Width = job->width;
384 f.Height = job->height;
387 if( job->vcodec == HB_VCODEC_FFMPEG )
388 f.Compression = FOURCC( "DX50" );
389 else if( job->vcodec == HB_VCODEC_XVID )
390 f.Compression = FOURCC( "XVID" );
391 else if( job->vcodec == HB_VCODEC_X264 )
392 f.Compression = FOURCC( "H264" );
395 #define g mux_data->vprp_header
396 /* Vprp video stream header */
397 AVRational sample_aspect_ratio = ( AVRational ){ job->anamorphic.par_width, job->anamorphic.par_height };
398 AVRational dar = av_mul_q( sample_aspect_ratio, ( AVRational ){ job->width, job->height } );
400 av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);
402 g.FourCC = FOURCC( "vprp" );
403 g.BytesCount = sizeof( hb_avi_vprp_info_t ) - 8;
404 g.VideoFormatToken = 0;
406 g.dwVerticalRefreshRate = job->vrate / job->vrate_base;
407 g.dwHTotalInT = job->width;
408 g.dwVTotalInLines = job->height;
409 g.dwFrameAspectRatioDen = den;
410 g.dwFrameAspectRatioNum = num;
411 g.dwFrameWidthInPixels = job->width;
412 g.dwFrameHeightInLines = job->height;
413 g.nbFieldPerFrame = 1;
414 g.CompressedBMHeight = job->height;
415 g.CompressedBMWidth = job->width;
416 g.ValidBMHeight = job->height;
417 g.ValidBMWidth = job->width;
418 g.ValidBMXOffset = 0;
419 g.ValidBMYOffset = 0;
420 g.VideoXOffsetInT = 0;
421 g.VideoYValidStartLine = 0;
425 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
427 audio = hb_list_item( title->list_audio, i );
429 is_ac3 = (audio->config.out.codec == HB_ACODEC_AC3);
431 mux_data = calloc( sizeof( hb_mux_data_t ), 1 );
432 audio->priv.mux_data = mux_data;
434 #define h mux_data->header
435 #define f mux_data->format.a.f
436 #define m mux_data->format.a.m
437 /* Audio stream header */
438 h.FourCC = FOURCC( "strh" );
439 h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8;
440 h.Type = FOURCC( "auds" );
443 h.Rate = is_ac3 ? ( audio->config.in.bitrate / 8 ) :
444 ( audio->config.out.bitrate * 1000 / 8 );
445 h.Quality = 0xFFFFFFFF;
448 /* Audio stream format */
449 f.FourCC = FOURCC( "strf" );
452 f.BytesCount = sizeof( hb_wave_formatex_t ) - 8;
453 f.FormatTag = 0x2000;
454 f.Channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout);
455 f.SamplesPerSec = audio->config.in.samplerate;
459 f.BytesCount = sizeof( hb_wave_formatex_t ) +
460 sizeof( hb_wave_mp3_t ) - 8;
462 f.Channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
463 f.SamplesPerSec = audio->config.out.samplerate;
465 f.AvgBytesPerSec = h.Rate;
473 f.Size = sizeof( hb_wave_mp3_t );
476 m.BlockSize = 1152 * f.AvgBytesPerSec / audio->config.out.samplerate;
477 m.FramesPerBlock = 1;
487 4 + sizeof( hb_avi_main_header_t ) +
488 /* strh for video + audios */
489 ( 1 + audio_count ) * ( 12 + sizeof( hb_avi_stream_header_t ) ) +
491 sizeof( hb_bitmap_info_t ) +
493 ( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) +
495 audio_count * ( sizeof( hb_wave_formatex_t ) +
496 ( is_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) );
498 /* Here we really start to write into the file */
501 WriteInt32( m->file, FOURCC( "RIFF" ) );
502 WriteInt32( m->file, 2040 );
503 WriteInt32( m->file, FOURCC( "AVI " ) );
504 WriteInt32( m->file, FOURCC( "LIST" ) );
505 WriteInt32( m->file, hdrl_bytes );
506 WriteInt32( m->file, FOURCC( "hdrl" ) );
507 WriteMainHeader( m->file, &m->main_header );
510 mux_data = job->mux_data;
511 mux_data->fourcc = FOURCC( "00dc" );
513 WriteInt32( m->file, FOURCC( "LIST" ) );
514 WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
515 sizeof( hb_bitmap_info_t ) +
516 ( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) );
517 WriteInt32( m->file, FOURCC( "strl" ) );
518 WriteStreamHeader( m->file, &mux_data->header );
519 WriteBitmapInfo( m->file, &mux_data->format.v );
520 if( job->anamorphic.mode )
522 WriteVprpInfo( m->file, &mux_data->vprp_header );
526 for( i = 0; i < audio_count; i++ )
528 char fourcc[4] = "00wb";
530 audio = hb_list_item( title->list_audio, i );
531 mux_data = audio->priv.mux_data;
533 fourcc[1] = '1' + i; /* This is fine as we don't allow more
535 mux_data->fourcc = FOURCC( fourcc );
537 WriteInt32( m->file, FOURCC( "LIST" ) );
538 WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
539 sizeof( hb_wave_formatex_t ) +
540 ( is_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) );
541 WriteInt32( m->file, FOURCC( "strl" ) );
542 WriteStreamHeader( m->file, &mux_data->header );
543 WriteWaveFormatEx( m->file, &mux_data->format.a.f );
546 WriteWaveMp3( m->file, &mux_data->format.a.m );
550 WriteInt32( m->file, FOURCC( "JUNK" ) );
551 WriteInt32( m->file, 2020 - hdrl_bytes );
552 for( i = 0; i < 2020 - hdrl_bytes; i++ )
554 WriteInt8( m->file, 0 );
556 WriteInt32( m->file, FOURCC( "LIST" ) );
557 WriteInt32( m->file, 4 );
558 WriteInt32( m->file, FOURCC( "movi" ) );
563 static int AVIMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
566 hb_job_t * job = m->job;
567 hb_title_t * title = job->title;
573 IndexAddInt32( m->index, mux_data->fourcc );
574 IndexAddInt32( m->index, (buf->frametype & HB_FRAME_KEY) ? AVIIF_KEYFRAME : 0 );
575 IndexAddInt32( m->index, 4 + m->size );
576 IndexAddInt32( m->index, buf->size );
578 /* Write the chunk to the file */
579 fseek( m->file, 0, SEEK_END );
580 WriteInt32( m->file, mux_data->fourcc );
581 WriteInt32( m->file, buf->size );
582 WriteBuffer( m->file, buf );
584 /* Chunks must be 2-bytes aligned */
587 WriteInt8( m->file, 0 );
591 m->size += 8 + EVEN( buf->size );
592 mux_data->header.Length++;
595 fseek( m->file, 4, SEEK_SET );
596 WriteInt32( m->file, 2052 + m->size );
598 /* Mmmmh that's not nice */
599 fseek( m->file, 140, SEEK_SET );
600 WriteInt32( m->file, job->mux_data->header.Length );
601 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
603 audio = hb_list_item( title->list_audio, i );
604 fseek( m->file, 264 + i *
605 ( 102 + ( ( audio->config.out.codec == HB_ACODEC_AC3 ) ? 0 :
606 sizeof( hb_wave_mp3_t ) ) ), SEEK_SET );
607 WriteInt32( m->file, audio->priv.mux_data->header.Length );
611 fseek( m->file, 2052, SEEK_SET );
612 WriteInt32( m->file, 4 + m->size );
616 static int AVIEnd( hb_mux_object_t * m )
618 hb_job_t * job = m->job;
620 hb_log( "muxavi: writing index" );
623 hb_log( "muxavi: closing %s", job->file );
626 hb_buffer_close( &m->index );
631 hb_mux_object_t * hb_mux_avi_init( hb_job_t * job )
633 hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 );