diff options
Diffstat (limited to 'libhb/muxmp4.c')
-rw-r--r-- | libhb/muxmp4.c | 196 |
1 files changed, 114 insertions, 82 deletions
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; } |