bool TRIFFWriter::InitAVIFile() { // We cannot write out if all elements are not initialized... off_t savePos; bool retVal = true; ssize_t size = 0x4949; // Rewind the file m_File->Seek(0, SEEK_SET); // Write RIFF header WriteRIFFChunk(size); // Write AVIHeader LIST chunk retVal = WriteLISTChunk(size); if (retVal == false) return retVal; // Save position for later calculation. Back over size... off_t listHeaderPos = m_File->Position(); listHeaderPos -= sizeof(uint32); WriteIntMsb(m_File, kRiff_hdrl_Chunk, sizeof(uint32)); // Write AVIHeader chunk retVal = WriteavihChunk(); if (retVal == false) return retVal; // // Write stream data List Chunk // // Make sure we have streams to write if ( (m_StreamCount == 0) || (m_StreamCount > kRiffWriteMaxStreams) ) return false; // // Write out first stream // retVal = WriteLISTChunk(size); if (retVal == false) return retVal; // Save position for later size calculation off_t streamOnePos = m_File->Position(); // Write out 'strl' chunk WriteIntMsb(m_File, kRiff_strl_Chunk, sizeof(uint32)); // First stream header retVal = WriteStreamHeader(&m_StreamHeaderOne); // First stream format retVal = WriteStreamFormat(&m_StreamHeaderOne); // Update streamOne chunk size savePos = m_File->Position(); uint32 streamOneSize = (uint32)(savePos - streamOnePos); // Update list header chunk size B_HOST_TO_LENDIAN_INT32(streamOneSize); streamOnePos -= sizeof(uint32); m_File->WriteAt(streamOnePos, &streamOneSize, sizeof(uint32)); // Return to saved postion m_File->Seek(savePos, SEEK_SET); // // Write out second stream // if (m_StreamCount == 2) { retVal = WriteLISTChunk(size); if (retVal == false) return retVal; // Save position for later size calculation off_t streamTwoPos = m_File->Position(); // Write out 'strl' chunk WriteIntMsb(m_File, kRiff_strl_Chunk, sizeof(uint32)); // Second stream header retVal = WriteStreamHeader(&m_StreamHeaderTwo); // Second stream format retVal = WriteStreamFormat(&m_StreamHeaderTwo); // Update streamTwo chunk size savePos = m_File->Position(); uint32 streamTwoSize = savePos - streamTwoPos; // Update list header chunk size B_HOST_TO_LENDIAN_INT32(streamTwoSize); streamTwoPos -= sizeof(uint32); m_File->WriteAt(streamTwoPos, &streamTwoSize, sizeof(uint32)); // Restore position m_File->Seek(savePos, SEEK_SET); } // Save position and go back and update unitialized chunk sizes savePos = m_File->Position(); uint32 listHeaderSize = savePos - listHeaderPos; // Update list header chunk size B_HOST_TO_LENDIAN_INT32(listHeaderSize); m_File->WriteAt(listHeaderPos, &listHeaderSize, sizeof(uint32)); // Restore position m_File->Seek(savePos, SEEK_SET); // // Write movi Chunk. We don't know the true size yet... // retVal = WriteLISTChunk(size); if (retVal == false) return retVal; WriteIntMsb(m_File, kRiff_movi_Chunk, sizeof(uint32)); // Save offset for later index chunk calculation m_MoviChunkOffset = m_File->Position(); // All done return retVal; }
/********************************************************************** * AVIInit ********************************************************************** * Allocates things, create file, initialize and write headers *********************************************************************/ static int AVIInit( hb_mux_object_t * m ) { hb_job_t * job = m->job; hb_title_t * title = job->title; hb_audio_t * audio; hb_mux_data_t * mux_data; int audio_count = hb_list_count( title->list_audio ); int is_passthru = 0; int is_ac3 = 0; int hdrl_bytes; int i; /* Allocate index */ m->index = hb_buffer_init( 1024 * 1024 ); m->index->size = 0; /* Open destination file */ hb_log( "muxavi: opening %s", job->file ); m->file = fopen( job->file, "wb" ); #define m m->main_header /* AVI main header */ m.FourCC = FOURCC( "avih" ); m.BytesCount = sizeof( hb_avi_main_header_t ) - 8; m.MicroSecPerFrame = (uint64_t) 1000000 * job->vrate_base / job->vrate; m.Streams = 1 + audio_count; m.Width = job->width; m.Height = job->height; #undef m /* Video track */ mux_data = calloc( sizeof( hb_mux_data_t ), 1 ); job->mux_data = mux_data; #define h mux_data->header /* Video stream header */ h.FourCC = FOURCC( "strh" ); h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8; h.Type = FOURCC( "vids" ); if( job->vcodec == HB_VCODEC_FFMPEG ) h.Handler = FOURCC( "divx" ); else if( job->vcodec == HB_VCODEC_X264 ) h.Handler = FOURCC( "h264" ); h.Scale = job->vrate_base; h.Rate = job->vrate; #undef h #define f mux_data->format.v /* Video stream format */ f.FourCC = FOURCC( "strf" ); f.BytesCount = sizeof( hb_bitmap_info_t ) - 8; f.Size = f.BytesCount; f.Width = job->width; f.Height = job->height; f.Planes = 1; f.BitCount = 24; if( job->vcodec == HB_VCODEC_FFMPEG ) f.Compression = FOURCC( "DX50" ); else if( job->vcodec == HB_VCODEC_X264 ) f.Compression = FOURCC( "H264" ); #undef f #define g mux_data->vprp_header /* Vprp video stream header */ AVRational sample_aspect_ratio = ( AVRational ){ job->anamorphic.par_width, job->anamorphic.par_height }; AVRational dar = av_mul_q( sample_aspect_ratio, ( AVRational ){ job->width, job->height } ); int num, den; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); g.FourCC = FOURCC( "vprp" ); g.BytesCount = sizeof( hb_avi_vprp_info_t ) - 8; g.VideoFormatToken = 0; g.VideoStandard = 0; g.dwVerticalRefreshRate = job->vrate / job->vrate_base; g.dwHTotalInT = job->width; g.dwVTotalInLines = job->height; g.dwFrameAspectRatioDen = den; g.dwFrameAspectRatioNum = num; g.dwFrameWidthInPixels = job->width; g.dwFrameHeightInLines = job->height; g.nbFieldPerFrame = 1; g.CompressedBMHeight = job->height; g.CompressedBMWidth = job->width; g.ValidBMHeight = job->height; g.ValidBMWidth = job->width; g.ValidBMXOffset = 0; g.ValidBMYOffset = 0; g.VideoXOffsetInT = 0; g.VideoYValidStartLine = 0; #undef g /* Audio tracks */ for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { audio = hb_list_item( title->list_audio, i ); is_ac3 = (audio->config.out.codec == HB_ACODEC_AC3); is_passthru = (audio->config.out.codec == HB_ACODEC_AC3) || (audio->config.out.codec == HB_ACODEC_DCA); mux_data = calloc( sizeof( hb_mux_data_t ), 1 ); audio->priv.mux_data = mux_data; #define h mux_data->header #define f mux_data->format.a.f #define m mux_data->format.a.m /* Audio stream header */ h.FourCC = FOURCC( "strh" ); h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8; h.Type = FOURCC( "auds" ); h.InitialFrames = 1; h.Scale = 1; h.Rate = is_passthru ? ( audio->config.in.bitrate / 8 ) : ( audio->config.out.bitrate * 1000 / 8 ); h.Quality = 0xFFFFFFFF; h.SampleSize = 1; /* Audio stream format */ f.FourCC = FOURCC( "strf" ); if( is_passthru ) { f.BytesCount = sizeof( hb_wave_formatex_t ) - 8; f.FormatTag = is_ac3 ? 0x2000 : 0x2001; f.Channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout); f.SamplesPerSec = audio->config.in.samplerate; } else { f.BytesCount = sizeof( hb_wave_formatex_t ) + sizeof( hb_wave_mp3_t ) - 8; f.FormatTag = 0x55; f.Channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown); f.SamplesPerSec = audio->config.out.samplerate; } f.AvgBytesPerSec = h.Rate; f.BlockAlign = 1; if( is_passthru ) { f.Size = 0; } else { f.Size = sizeof( hb_wave_mp3_t ); m.Id = 1; m.Flags = 2; m.BlockSize = 1152 * f.AvgBytesPerSec / audio->config.out.samplerate; m.FramesPerBlock = 1; m.CodecDelay = 1393; } #undef h #undef f #undef m } hdrl_bytes = /* Main header */ 4 + sizeof( hb_avi_main_header_t ) + /* strh for video + audios */ ( 1 + audio_count ) * ( 12 + sizeof( hb_avi_stream_header_t ) ) + /* video strf */ sizeof( hb_bitmap_info_t ) + /* video vprp */ ( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) + /* audios strf */ audio_count * ( sizeof( hb_wave_formatex_t ) + ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) ); /* Here we really start to write into the file */ /* Main headers */ WriteInt32( m->file, FOURCC( "RIFF" ) ); WriteInt32( m->file, 2040 ); WriteInt32( m->file, FOURCC( "AVI " ) ); WriteInt32( m->file, FOURCC( "LIST" ) ); WriteInt32( m->file, hdrl_bytes ); WriteInt32( m->file, FOURCC( "hdrl" ) ); WriteMainHeader( m->file, &m->main_header ); /* Video track */ mux_data = job->mux_data; mux_data->fourcc = FOURCC( "00dc" ); WriteInt32( m->file, FOURCC( "LIST" ) ); WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) + sizeof( hb_bitmap_info_t ) + ( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) ); WriteInt32( m->file, FOURCC( "strl" ) ); WriteStreamHeader( m->file, &mux_data->header ); WriteBitmapInfo( m->file, &mux_data->format.v ); if( job->anamorphic.mode ) { WriteVprpInfo( m->file, &mux_data->vprp_header ); } /* Audio tracks */ for( i = 0; i < audio_count; i++ ) { char fourcc[4] = "00wb"; audio = hb_list_item( title->list_audio, i ); mux_data = audio->priv.mux_data; fourcc[1] = '1' + i; /* This is fine as we don't allow more than 8 tracks */ mux_data->fourcc = FOURCC( fourcc ); WriteInt32( m->file, FOURCC( "LIST" ) ); WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) + sizeof( hb_wave_formatex_t ) + ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) ); WriteInt32( m->file, FOURCC( "strl" ) ); WriteStreamHeader( m->file, &mux_data->header ); WriteWaveFormatEx( m->file, &mux_data->format.a.f ); if( !is_passthru ) { WriteWaveMp3( m->file, &mux_data->format.a.m ); } } WriteInt32( m->file, FOURCC( "JUNK" ) ); WriteInt32( m->file, 2020 - hdrl_bytes ); for( i = 0; i < 2020 - hdrl_bytes; i++ ) { WriteInt8( m->file, 0 ); } WriteInt32( m->file, FOURCC( "LIST" ) ); WriteInt32( m->file, 4 ); WriteInt32( m->file, FOURCC( "movi" ) ); return 0; }