/* $Id: muxavi.c,v 1.10 2005/03/30 18:17:29 titer Exp $
This file is part of the HandBrake source code.
- Homepage: <http://handbrake.m0k.org/>.
+ Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
#include "hb.h"
+#include "hbffmpeg.h"
#define AVIF_HASINDEX 0x10
#define AVIIF_KEYFRAME 0x10
{
uint32_t FourCC;
uint32_t BytesCount;
+ uint32_t VideoFormatToken;
+ uint32_t VideoStandard;
+ uint32_t dwVerticalRefreshRate;
+ uint32_t dwHTotalInT;
+ uint32_t dwVTotalInLines;
+ uint16_t dwFrameAspectRatioDen;
+ uint16_t dwFrameAspectRatioNum;
+ uint32_t dwFrameWidthInPixels;
+ uint32_t dwFrameHeightInLines;
+ uint32_t nbFieldPerFrame;
+ uint32_t CompressedBMHeight;
+ uint32_t CompressedBMWidth;
+ uint32_t ValidBMHeight;
+ uint32_t ValidBMWidth;
+ uint32_t ValidBMXOffset;
+ uint32_t ValidBMYOffset;
+ uint32_t VideoXOffsetInT;
+ uint32_t VideoYValidStartLine;
+
+} hb_avi_vprp_info_t;
+
+typedef struct __attribute__((__packed__))
+{
+ uint32_t FourCC;
+ uint32_t BytesCount;
uint32_t Size;
uint32_t Width;
uint32_t Height;
static void WriteInt8( FILE * file, uint8_t val )
{
fputc( val, file );
-}
+}
static void WriteInt16( FILE * file, uint16_t val )
{
WriteInt16( file, header->Bottom );
}
+static void WriteVprpInfo( FILE * file, hb_avi_vprp_info_t * info )
+{
+ WriteInt32( file, info->FourCC );
+ WriteInt32( file, info->BytesCount );
+ WriteInt32( file, info->VideoFormatToken );
+ WriteInt32( file, info->VideoStandard );
+ WriteInt32( file, info->dwVerticalRefreshRate );
+ WriteInt32( file, info->dwHTotalInT );
+ WriteInt32( file, info->dwVTotalInLines );
+ WriteInt16( file, info->dwFrameAspectRatioDen );
+ WriteInt16( file, info->dwFrameAspectRatioNum );
+ WriteInt32( file, info->dwFrameWidthInPixels );
+ WriteInt32( file, info->dwFrameHeightInLines );
+ WriteInt32( file, info->nbFieldPerFrame );
+ WriteInt32( file, info->CompressedBMHeight );
+ WriteInt32( file, info->CompressedBMWidth );
+ WriteInt32( file, info->ValidBMHeight );
+ WriteInt32( file, info->ValidBMWidth );
+ WriteInt32( file, info->ValidBMXOffset );
+ WriteInt32( file, info->ValidBMYOffset );
+ WriteInt32( file, info->VideoXOffsetInT );
+ WriteInt32( file, info->VideoYValidStartLine );
+}
+
static void IndexAddInt32( hb_buffer_t * b, uint32_t val )
{
if( b->size + 16 > b->alloc )
struct hb_mux_data_s
{
- uint32_t fourcc;
- hb_avi_stream_header_t header;
+ uint32_t fourcc;
+ hb_avi_stream_header_t header;
+ hb_avi_vprp_info_t vprp_header;
union
{
hb_bitmap_info_t v;
hb_mux_data_t * mux_data;
int audio_count = hb_list_count( title->list_audio );
- int is_ac3 = ( job->acodec & HB_ACODEC_AC3 );
+ int is_passthru = 0;
+ int is_ac3 = 0;
int hdrl_bytes;
int i;
/* 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" );
if( job->vcodec == HB_VCODEC_FFMPEG )
h.Handler = FOURCC( "divx" );
- else if( job->vcodec == HB_VCODEC_XVID )
- h.Handler = FOURCC( "xvid" );
else if( job->vcodec == HB_VCODEC_X264 )
h.Handler = FOURCC( "h264" );
f.BitCount = 24;
if( job->vcodec == HB_VCODEC_FFMPEG )
f.Compression = FOURCC( "DX50" );
- else if( job->vcodec == HB_VCODEC_XVID )
- f.Compression = FOURCC( "XVID" );
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->mux_data = mux_data;
+ audio->priv.mux_data = mux_data;
#define h mux_data->header
#define f mux_data->format.a.f
h.Type = FOURCC( "auds" );
h.InitialFrames = 1;
h.Scale = 1;
- h.Rate = is_ac3 ? ( audio->bitrate / 8 ) :
- ( job->abitrate * 1000 / 8 );
+ 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_ac3 )
+ if( is_passthru )
{
f.BytesCount = sizeof( hb_wave_formatex_t ) - 8;
- f.FormatTag = 0x2000;
- f.Channels = 2;
- f.SamplesPerSec = audio->rate;
+ 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 = 2;
- f.SamplesPerSec = job->arate;
+ 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_ac3 )
+ if( is_passthru )
{
f.Size = 0;
}
f.Size = sizeof( hb_wave_mp3_t );
m.Id = 1;
m.Flags = 2;
- m.BlockSize = 1152 * f.AvgBytesPerSec / job->arate;
+ m.BlockSize = 1152 * f.AvgBytesPerSec / audio->config.out.samplerate;
m.FramesPerBlock = 1;
m.CodecDelay = 1393;
}
/* strh for video + audios */
( 1 + audio_count ) * ( 12 + sizeof( hb_avi_stream_header_t ) ) +
/* video strf */
- sizeof( hb_bitmap_info_t ) +
+ 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_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) );
+ ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) );
/* Here we really start to write into the file */
WriteInt32( m->file, FOURCC( "LIST" ) );
WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
- sizeof( hb_bitmap_info_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->mux_data;
+ mux_data = audio->priv.mux_data;
fourcc[1] = '1' + i; /* This is fine as we don't allow more
than 8 tracks */
WriteInt32( m->file, FOURCC( "LIST" ) );
WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
sizeof( hb_wave_formatex_t ) +
- ( is_ac3 ? 0 : sizeof( hb_wave_mp3_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_ac3 )
+ if( !is_passthru )
{
WriteWaveMp3( m->file, &mux_data->format.a.m );
}
/* Update index */
IndexAddInt32( m->index, mux_data->fourcc );
- IndexAddInt32( m->index, buf->key ? AVIIF_KEYFRAME : 0 );
+ IndexAddInt32( m->index, (buf->frametype & HB_FRAME_KEY) ? AVIIF_KEYFRAME : 0 );
IndexAddInt32( m->index, 4 + m->size );
IndexAddInt32( m->index, buf->size );
WriteInt8( m->file, 0 );
}
- /* Update headers */
+ /* Update headers */
m->size += 8 + EVEN( buf->size );
mux_data->header.Length++;
- /* RIFF size */
+ /* RIFF size */
fseek( m->file, 4, SEEK_SET );
WriteInt32( m->file, 2052 + m->size );
WriteInt32( m->file, job->mux_data->header.Length );
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
+ int is_passthru;
audio = hb_list_item( title->list_audio, i );
+ is_passthru = (audio->config.out.codec == HB_ACODEC_AC3) ||
+ (audio->config.out.codec == HB_ACODEC_DCA);
fseek( m->file, 264 + i *
- ( 102 + ( ( job->acodec & HB_ACODEC_AC3 ) ? 0 :
+ ( 102 + ( is_passthru ? 0 :
sizeof( hb_wave_mp3_t ) ) ), SEEK_SET );
- WriteInt32( m->file, audio->mux_data->header.Length );
+ WriteInt32( m->file, audio->priv.mux_data->header.Length );
}
/* movi size */