summaryrefslogtreecommitdiffstats
path: root/libhb/muxmp4.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/muxmp4.c')
-rw-r--r--libhb/muxmp4.c196
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( &params, 0, sizeof( params ) );
+ if( av_set_parameters( oc, &params ) < 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;
}