diff options
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/common.c | 1 | ||||
-rw-r--r-- | libhb/common.h | 5 | ||||
-rw-r--r-- | libhb/encavcodec.c | 14 | ||||
-rw-r--r-- | libhb/encfaac.c | 8 | ||||
-rw-r--r-- | libhb/encx264.c | 60 | ||||
-rw-r--r-- | libhb/hb.c | 23 | ||||
-rw-r--r-- | libhb/internal.h | 8 | ||||
-rw-r--r-- | libhb/muxcommon.c | 1 | ||||
-rw-r--r-- | libhb/muxmp4.c | 196 | ||||
-rw-r--r-- | libhb/work.c | 3 |
10 files changed, 173 insertions, 146 deletions
diff --git a/libhb/common.c b/libhb/common.c index 7bd125c84..c9650ab4b 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -115,6 +115,7 @@ int hb_calc_bitrate( hb_job_t * job, int size ) switch( job->mux ) { case HB_MUX_MP4: + case HB_MUX_PSP: overhead = 6; break; case HB_MUX_AVI: diff --git a/libhb/common.h b/libhb/common.h index dea4a4800..a0c22ff27 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -155,8 +155,9 @@ struct hb_job_s file: file path */ #define HB_MUX_MASK 0xFF0000 #define HB_MUX_MP4 0x010000 -#define HB_MUX_AVI 0x020000 -#define HB_MUX_OGM 0x040000 +#define HB_MUX_PSP 0x020000 +#define HB_MUX_AVI 0x040000 +#define HB_MUX_OGM 0x080000 int mux; char * file; diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index 155ff9b3e..f04606906 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -65,10 +65,14 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) context->gop_size = 10 * job->vrate / job->vrate_base; context->pix_fmt = PIX_FMT_YUV420P; - if( job->mux & HB_MUX_MP4 ) + if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) { context->flags |= CODEC_FLAG_GLOBAL_HEADER; } + if( job->mux & HB_MUX_PSP ) + { + context->flags |= CODEC_FLAG_BITEXACT; + } if( job->grayscale ) { context->flags |= CODEC_FLAG_GRAY; @@ -110,11 +114,17 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) } pv->context = context; - if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 ) + if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 ) { +#if 0 /* Hem hem */ w->config->mpeg4.length = 15; memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 ); +#else + w->config->mpeg4.length = context->extradata_size; + memcpy( w->config->mpeg4.bytes, context->extradata, + context->extradata_size ); +#endif } return 0; diff --git a/libhb/encfaac.c b/libhb/encfaac.c index 4c0d19e72..8e2bd4355 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -42,9 +42,11 @@ hb_work_object_t hb_encfaac = int encfaacInit( hb_work_object_t * w, hb_job_t * job ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); - w->private_data = pv; - faacEncConfigurationPtr cfg; + uint8_t * bytes; + unsigned long length; + + w->private_data = pv; pv->job = job; @@ -67,8 +69,6 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) hb_log( "faacEncSetConfiguration failed" ); } - uint8_t * bytes; - unsigned long length; if( faacEncGetDecoderSpecificInfo( pv->faac, &bytes, &length ) < 0 ) { hb_log( "faacEncGetDecoderSpecificInfo failed" ); diff --git a/libhb/encx264.c b/libhb/encx264.c index 806fc4c88..13faadc39 100644 --- a/libhb/encx264.c +++ b/libhb/encx264.c @@ -43,6 +43,7 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job ) x264_param_t param; x264_nal_t * nal; int nal_count; + int i, size; hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; @@ -63,6 +64,7 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job ) param.i_log_level = X264_LOG_NONE; if( job->h264_13 ) { + param.i_threads = 1; param.b_cabac = 0; param.i_level_idc = 13; } @@ -98,17 +100,17 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job ) hb_log( "encx264: opening libx264 (pass %d)", job->pass ); pv->x264 = x264_encoder_open( ¶m ); - x264_encoder_headers( pv->x264, &nal, &nal_count ); + w->config->mpeg4.length = 0; - /* Sequence Parameter Set */ - w->config->h264.sps_length = 1 + nal[1].i_payload; - w->config->h264.sps[0] = 0x67; - memcpy( &w->config->h264.sps[1], nal[1].p_payload, nal[1].i_payload ); + x264_encoder_headers( pv->x264, &nal, &nal_count ); - /* Picture Parameter Set */ - w->config->h264.pps_length = 1 + nal[2].i_payload; - w->config->h264.pps[0] = 0x68; - memcpy( &w->config->h264.pps[1], nal[2].p_payload, nal[2].i_payload ); + for( i = 0; i < nal_count; i++ ) + { + size = sizeof( w->config->mpeg4.bytes ) - w->config->mpeg4.length; + x264_nal_encode( &w->config->mpeg4.bytes[w->config->mpeg4.length], + &size, 1, &nal[i] ); + w->config->mpeg4.length += size; + } x264_picture_alloc( &pv->pic_in, X264_CSP_I420, job->width, job->height ); @@ -158,51 +160,19 @@ int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in, /* Should be way too large */ buf = hb_buffer_init( 3 * job->width * job->height / 2 ); - buf->size = 0; buf->start = in->start; buf->stop = in->stop; - buf->key = 0; + buf->key = ( pv->pic_out.i_type == X264_TYPE_IDR ); + buf->size = 0; for( i = 0; i < i_nal; i++ ) { int size, data; - data = buf->alloc - buf->size; - if( ( size = x264_nal_encode( buf->data + buf->size, &data, - 1, &nal[i] ) ) < 1 ) + if( ( size = x264_nal_encode( &buf->data[buf->size], &data, + 1, &nal[i] ) ) > 0 ) { - continue; - } - - if( job->mux & HB_MUX_AVI ) - { - if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) - { - buf->key = 1; - } buf->size += size; - continue; - } - - /* H.264 in .mp4 */ - switch( buf->data[buf->size+4] & 0x1f ) - { - case 0x7: - case 0x8: - /* SPS, PPS */ - break; - - default: - /* H.264 in mp4 (stolen from mp4creator) */ - buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF; - buf->data[buf->size+1] = ( ( size - 4 ) >> 16 ) & 0xFF; - buf->data[buf->size+2] = ( ( size - 4 ) >> 8 ) & 0xFF; - buf->data[buf->size+3] = ( ( size - 4 ) >> 0 ) & 0xFF; - if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) - { - buf->key = 1; - } - buf->size += size; } } diff --git a/libhb/hb.c b/libhb/hb.c index 7bc41be8e..d44c05de6 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -260,6 +260,7 @@ void hb_set_size( hb_job_t * job, int aspect, int pixels ) int croppedAspect = title->aspect * title->height * croppedWidth / croppedHeight / title->width; int addCrop; + int i, w, h; if( aspect <= 0 ) { @@ -296,11 +297,29 @@ void hb_set_size( hb_job_t * job, int aspect, int pixels ) else if( aspect > croppedAspect ) { /* Need to crop on the top and bottom */ - /* TODO */ + addCrop = croppedHeight - croppedWidth * title->aspect * + title->height / aspect / title->width; + if( addCrop & 3 ) + { + addCrop = ( addCrop + 1 ) / 2; + job->crop[0] += addCrop; + job->crop[1] += addCrop; + } + else if( addCrop & 2 ) + { + addCrop /= 2; + job->crop[0] += addCrop - 1; + job->crop[1] += addCrop + 1; + } + else + { + addCrop /= 2; + job->crop[0] += addCrop; + job->crop[1] += addCrop; + } } /* Compute a resolution from the number of pixels and aspect */ - int i, w, h; for( i = 0;; i++ ) { w = 16 * i; diff --git a/libhb/internal.h b/libhb/internal.h index 7a6caad4a..e13008f9b 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -123,14 +123,6 @@ union hb_esconfig_u struct { - uint8_t sps[HB_CONFIG_MAX_SIZE]; - int sps_length; - uint8_t pps[HB_CONFIG_MAX_SIZE]; - int pps_length; - } h264; - - struct - { uint8_t bytes[HB_CONFIG_MAX_SIZE]; int length; } aac; diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c index 090f332b2..8deba08e3 100644 --- a/libhb/muxcommon.c +++ b/libhb/muxcommon.c @@ -70,6 +70,7 @@ static void MuxerFunc( void * _mux ) switch( job->mux ) { case HB_MUX_MP4: + case HB_MUX_PSP: m = hb_mux_mp4_init( job ); break; case HB_MUX_AVI: diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index d5002fa4a..21aea7a53 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -4,27 +4,28 @@ Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -/* libmp4v2 header */ -#include "mp4.h" +#include <ffmpeg/avformat.h> #include "hb.h" +int64_t ff_gcd(int64_t a, int64_t b); +static inline int ff_get_fourcc(const char *s) +{ + return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24); +} + struct hb_mux_object_s { HB_MUX_COMMON; hb_job_t * job; - /* libmp4v2 handle */ - MP4FileHandle file; - - /* Cumulated durations so far, in timescale units (see MP4Mux) */ - uint64_t sum_dur; + AVFormatContext * format; }; struct hb_mux_data_s { - MP4TrackId track; + int track; }; /********************************************************************** @@ -38,110 +39,141 @@ static int MP4Init( hb_mux_object_t * m ) hb_title_t * title = job->title; hb_audio_t * audio; - hb_mux_data_t * mux_data; int i; + AVFormatContext * oc; + AVStream *st; + AVFormatParameters params; - /* Create an empty mp4 file */ - m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 ); + register_protocol(&file_protocol); + movenc_init(); - /* Video track */ - mux_data = malloc( sizeof( hb_mux_data_t ) ); - job->mux_data = mux_data; + oc = av_alloc_format_context(); - /* When using the standard 90000 timescale, QuickTime tends to have - synchronization issues (audio not playing at the correct speed). - To workaround this, we use the audio samplerate as the - timescale */ - MP4SetTimeScale( m->file, job->arate ); - - if( job->vcodec == HB_VCODEC_X264 ) + if( job->mux & HB_MUX_PSP ) + { + oc->oformat = guess_format( "psp", NULL, NULL ); + } + else + { + oc->oformat = guess_format( "mp4", NULL, NULL ); + } + if( !oc->oformat ) { - /* Stolen from mp4creator */ - MP4SetVideoProfileLevel( m->file, 0x7F ); - - mux_data->track = MP4AddH264VideoTrack( m->file, job->arate, - MP4_INVALID_DURATION, job->width, job->height, - job->config.h264.sps[1], /* AVCProfileIndication */ - job->config.h264.sps[2], /* profile_compat */ - job->config.h264.sps[3], /* AVCLevelIndication */ - 3 ); /* 4 bytes length before each NAL unit */ - - MP4AddH264SequenceParameterSet( m->file, mux_data->track, - job->config.h264.sps, job->config.h264.sps_length ); - MP4AddH264PictureParameterSet( m->file, mux_data->track, - job->config.h264.pps, job->config.h264.pps_length ); + hb_log( "guess_format failed" ); + return 1; } - else /* FFmpeg or XviD */ + snprintf( oc->filename, sizeof( oc->filename ), + "%s", job->file ); + + st = av_new_stream( oc, oc->nb_streams ); + if( !st ) { - MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 ); - mux_data->track = MP4AddVideoTrack( m->file, job->arate, - MP4_INVALID_DURATION, job->width, job->height, - MP4_MPEG4_VIDEO_TYPE ); - - /* VOL from FFmpeg or XviD */ - MP4SetTrackESConfiguration( m->file, mux_data->track, - job->config.mpeg4.bytes, job->config.mpeg4.length ); + hb_log( "av_new_stream failed" ); + return 1; } + st->stream_copy = 1; + st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = ( job->vcodec == HB_VCODEC_X264 ) ? + CODEC_ID_H264 : CODEC_ID_MPEG4; + st->codec->extradata= job->config.mpeg4.bytes; + st->codec->extradata_size= job->config.mpeg4.length; + st->codec->bit_rate = 1000 * job->vbitrate; + i = ff_gcd( job->vrate_base, job->vrate ); + st->codec->time_base = (AVRational){ job->vrate_base / i, job->vrate / i }; + + st->codec->pix_fmt = PIX_FMT_YUV420P; + st->codec->width = job->width; + st->codec->height = job->height; + st->codec->has_b_frames = 0; + + job->mux_data = malloc( sizeof( hb_mux_data_t ) ); + job->mux_data->track = 0; for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { audio = hb_list_item( title->list_audio, i ); - mux_data = malloc( sizeof( hb_mux_data_t ) ); - audio->mux_data = mux_data; - - mux_data->track = MP4AddAudioTrack( m->file, - job->arate, 1024, MP4_MPEG4_AUDIO_TYPE ); - MP4SetAudioProfileLevel( m->file, 0x0F ); - MP4SetTrackESConfiguration( m->file, mux_data->track, - audio->config.aac.bytes, audio->config.aac.length ); + + audio->mux_data = malloc( sizeof( hb_mux_data_t ) ); + audio->mux_data->track = i + 1; + + st = av_new_stream( oc, oc->nb_streams ); + if( !st ) + { + hb_log( "av_new_stream failed" ); + return 1; + } + st->stream_copy = 1; + st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_AAC; + st->codec->bit_rate = 1000 * job->abitrate; + st->codec->extradata= audio->config.aac.bytes; + st->codec->extradata_size= audio->config.aac.length; + st->codec->time_base = (AVRational){ 1, job->arate }; + st->codec->channels = 2; + st->codec->sample_rate = job->arate; + st->codec->frame_size = 1024; + st->codec->block_align = 0; } + oc->timestamp = 0; + if( url_fopen( &oc->pb, job->file, URL_WRONLY ) < 0 ) + { + hb_log( "url_fopen failed (%s)", job->file ); + return 1; + } + + memset( ¶ms, 0, sizeof( params ) ); + if( av_set_parameters( oc, ¶ms ) < 0 ) + { + hb_log( "av_set_parameters failed" ); + return 1; + } + + oc->packet_size= 0; + oc->mux_rate= 0; + oc->preload= (int)(0.5*AV_TIME_BASE); + oc->max_delay= (int)(0.7*AV_TIME_BASE); + oc->loop_output = AVFMT_NOOUTPUTLOOP; + + if( av_write_header( oc ) < 0 ) + { + hb_log( "av_write_header failed" ); + return 1; + } + + m->format = oc; + return 0; } static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, hb_buffer_t * buf ) { - hb_job_t * job = m->job; + AVPacket pkt; + av_init_packet(&pkt); - uint64_t duration; + pkt.stream_index = mux_data->track; + pkt.data = buf->data; + pkt.size = buf->size; + pkt.pts = buf->start; - if( mux_data == job->mux_data ) - { - /* Video */ - /* Because we use the audio samplerate as the timescale, - we have to use potentially variable durations so the video - doesn't go out of sync */ - duration = ( buf->stop * job->arate / 90000 ) - m->sum_dur; - m->sum_dur += duration; - } - else + if( buf->key ) { - /* Audio */ - duration = MP4_INVALID_DURATION; + pkt.flags |= PKT_FLAG_KEY; } - MP4WriteSample( m->file, mux_data->track, buf->data, buf->size, - duration, 0, buf->key ); + av_interleaved_write_frame( m->format, &pkt ); + return 0; } static int MP4End( hb_mux_object_t * m ) { -#if 0 - hb_job_t * job = m->job; -#endif - char filename[1024]; memset( filename, 0, 1024 ); - - MP4Close( m->file ); - -#if 0 - hb_log( "muxmp4: optimizing file" ); - snprintf( filename, 1024, "%s.tmp", job->file ); - MP4Optimize( job->file, filename, MP4_DETAILS_ERROR ); - remove( job->file ); - rename( filename, job->file ); -#endif + av_write_trailer( m->format ); + url_fclose( &m->format->pb ); + av_free( m->format ); return 0; } diff --git a/libhb/work.c b/libhb/work.c index 2ad4f65f7..349a630e3 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -71,6 +71,7 @@ static void do_job( hb_job_t * job, int cpu_count ) hb_work_object_t * w; hb_audio_t * audio; hb_subtitle_t * subtitle; + int done; title = job->title; @@ -229,7 +230,7 @@ static void do_job( hb_job_t * job, int cpu_count ) HB_LOW_PRIORITY ); } - int done = 0; + done = 0; w = hb_list_item( job->list_work, 0 ); w->init( w, job ); while( !*job->die ) |