diff options
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/common.c | 8 | ||||
-rw-r--r-- | libhb/decmetadata.c | 206 | ||||
-rw-r--r-- | libhb/internal.h | 5 | ||||
-rw-r--r-- | libhb/module.defs | 21 | ||||
-rw-r--r-- | libhb/muxavformat.c | 4 | ||||
-rw-r--r-- | libhb/muxcommon.c | 12 | ||||
-rw-r--r-- | libhb/muxmkv.c | 710 | ||||
-rw-r--r-- | libhb/muxmp4.c | 1249 | ||||
-rw-r--r-- | libhb/stream.c | 6 |
9 files changed, 3 insertions, 2218 deletions
diff --git a/libhb/common.c b/libhb/common.c index 7015ae17a..f6e773777 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -339,16 +339,8 @@ static int hb_container_is_enabled(int format) { switch (format) { -#ifdef USE_MP4V2 - case HB_MUX_MP4V2: -#endif -#ifdef USE_LIBMKV - case HB_MUX_LIBMKV: -#endif -#ifdef USE_AVFORMAT case HB_MUX_AV_MP4: case HB_MUX_AV_MKV: -#endif return 1; default: diff --git a/libhb/decmetadata.c b/libhb/decmetadata.c deleted file mode 100644 index 85d27ca7f..000000000 --- a/libhb/decmetadata.c +++ /dev/null @@ -1,206 +0,0 @@ -/* decmetadata.c - - Copyright (c) 2003-2014 HandBrake Team - This file is part of the HandBrake source code - Homepage: <http://handbrake.fr/>. - It may be used under the terms of the GNU General Public License v2. - For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html - */ - - -#include "common.h" - -#if defined(USE_MP4V2) -#include <mp4v2/mp4v2.h> - -static int decmp4metadata( hb_title_t *title ) -{ - MP4FileHandle input_file; - int result = 0; - hb_deep_log( 2, "Got an MP4 input, read the metadata"); - - input_file = MP4Read( title->path, 0 ); - - if( input_file != MP4_INVALID_FILE_HANDLE ) - { - /* - * Store iTunes MetaData - */ - const MP4Tags* tags; - - /* alloc,fetch tags */ - tags = MP4TagsAlloc(); - MP4TagsFetch( tags, input_file ); - - if( tags->name ) { - hb_deep_log( 2, "Metadata Name in input file is '%s'", tags->name ); - hb_metadata_set_name(title->metadata, tags->name); - result = 1; - } - - if( tags->artist ) - { - hb_metadata_set_artist(title->metadata, tags->artist); - result = 1; - } - - if( tags->composer ) - { - hb_metadata_set_composer(title->metadata, tags->composer); - result = 1; - } - - if( tags->comments ) - { - hb_metadata_set_comment(title->metadata, tags->comments); - result = 1; - } - - if( tags->releaseDate ) - { - hb_metadata_set_release_date(title->metadata, tags->releaseDate); - result = 1; - } - - if( tags->album ) - { - hb_metadata_set_album(title->metadata, tags->album); - result = 1; - } - - if( tags->albumArtist ) - { - hb_metadata_set_album_artist(title->metadata, tags->albumArtist); - result = 1; - } - - if( tags->genre ) - { - hb_metadata_set_genre(title->metadata, tags->genre); - result = 1; - } - - if( tags->description ) - { - hb_metadata_set_description(title->metadata, tags->description); - result = 1; - } - - if( tags->longDescription ) - { - hb_metadata_set_long_description(title->metadata, tags->longDescription); - result = 1; - } - - int ii; - for ( ii = 0; ii < tags->artworkCount; ii++ ) - { - const MP4TagArtwork* art = tags->artwork + ii; - int type; - switch ( art->type ) - { - case MP4_ART_BMP: - type = HB_ART_BMP; - break; - case MP4_ART_GIF: - type = HB_ART_GIF; - break; - case MP4_ART_JPEG: - type = HB_ART_JPEG; - break; - case MP4_ART_PNG: - type = HB_ART_PNG; - break; - default: - type = HB_ART_UNDEFINED; - break; - } - hb_metadata_add_coverart( - title->metadata, art->data, art->size, type); - hb_deep_log( 2, "Got some cover art of type %d, size %d", - art->type, - art->size ); - result = 1; - } - - /* store,free tags */ - MP4TagsStore( tags, input_file ); - MP4TagsFree( tags ); - - /* - * Handle the chapters. - */ - MP4Chapter_t *chapter_list = NULL; - uint32_t chapter_count; - - MP4GetChapters( input_file, &chapter_list, &chapter_count, - MP4ChapterTypeQt ); - - if( chapter_list && ( hb_list_count( title->list_chapter ) == 0 ) ) { - uint32_t i = 1; - while( i <= chapter_count ) - { - hb_chapter_t * chapter; - chapter = calloc( sizeof( hb_chapter_t ), 1 ); - chapter->index = i; - chapter->duration = chapter_list[i-1].duration * 90; - - int seconds = ( chapter->duration + 45000 ) / 90000; - chapter->hours = ( seconds / 3600 ); - chapter->minutes = ( seconds % 3600 ) / 60; - chapter->seconds = ( seconds % 60 ); - - if( chapter_list[i-1].title ) - { - hb_chapter_set_title( chapter, chapter_list[i-1].title ); - } - else - { - char chapter_title[80]; - sprintf( chapter_title, "Chapter %d", chapter->index ); - hb_chapter_set_title( chapter, chapter_title ); - } - - hb_deep_log( 2, "Added chapter %i, name='%s', dur=%"PRId64", (%02i:%02i:%02i)", - chapter->index, chapter->title, chapter->duration, - chapter->hours, chapter->minutes, chapter->seconds); - - hb_list_add( title->list_chapter, chapter ); - i++; - } - } - - MP4Close( input_file ); - } - return result; -} -#endif // USE_MP4V2 - -/* - * decmetadata() - * - * Look at the title and extract whatever metadata we can from that title. - */ -int decmetadata( hb_title_t *title ) -{ - if( !title ) - { - return 0; - } - - if( !title->metadata ) - { - return 0; - } - -#if defined(USE_MP4V2) - /* - * Hacky way of figuring out if this is an MP4, in which case read the data using libmp4v2 - */ - if( title->container_name && strcmp(title->container_name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) - { - return decmp4metadata( title ); - } -#endif - return 0; -} diff --git a/libhb/internal.h b/libhb/internal.h index c71b23ecd..f32c3d3ff 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -284,11 +284,6 @@ void hb_demux_null( hb_buffer_t * ps_buf, hb_list_t * es_list, hb_psdemux_t * ); extern const hb_muxer_t hb_demux[]; /*********************************************************************** - * decmetadata.c - **********************************************************************/ -extern int decmetadata( hb_title_t *title ); - -/*********************************************************************** * batch.c **********************************************************************/ typedef struct hb_batch_s hb_batch_t; diff --git a/libhb/module.defs b/libhb/module.defs index d0a2da131..b1920fdbd 100644 --- a/libhb/module.defs +++ b/libhb/module.defs @@ -1,6 +1,6 @@ __deps__ := A52DEC BZIP2 LIBVPX FFMPEG FONTCONFIG FREETYPE LAME LIBASS LIBDCA \ - LIBDVDREAD LIBDVDNAV LIBICONV LIBMKV LIBOGG LIBSAMPLERATE LIBTHEORA LIBVORBIS LIBXML2 \ - MP4V2 PTHREADW32 X264 X265 ZLIB LIBBLURAY FDKAAC LIBMFX + LIBDVDREAD LIBDVDNAV LIBICONV LIBOGG LIBSAMPLERATE LIBTHEORA LIBVORBIS LIBXML2 \ + PTHREADW32 X264 X265 ZLIB LIBBLURAY FDKAAC LIBMFX $(eval $(call import.MODULE.defs,LIBHB,libhb,$(__deps__))) $(eval $(call import.GCC,LIBHB)) @@ -42,15 +42,6 @@ endif ifeq (1,$(FEATURE.libav_aac)) LIBHB.GCC.D += USE_LIBAV_AAC endif -ifeq (1,$(FEATURE.mp4v2)) -LIBHB.GCC.D += USE_MP4V2 -endif -ifeq (1,$(FEATURE.libmkv)) -LIBHB.GCC.D += USE_LIBMKV -endif -ifeq (1,$(FEATURE.avformat)) -LIBHB.GCC.D += USE_AVFORMAT -endif LIBHB.GCC.D += __LIBHB__ USE_PTHREAD LIBHB.GCC.I += $(LIBHB.build/) $(CONTRIB.build/)include @@ -131,14 +122,6 @@ ifeq (1,$(FEATURE.x265)) LIBHB.dll.libs += $(CONTRIB.build/)lib/libx265.a endif -ifeq (1,$(FEATURE.mp4v2)) -LIBHB.dll.libs += $(CONTRIB.build/)lib/libmp4v2.a -endif - -ifeq (1,$(FEATURE.libmkv)) -LIBHB.dll.libs += $(CONTRIB.build/)lib/libmkv.a -endif - ifneq ($(HAS.iconv),1) LIBHB.dll.libs += $(CONTRIB.build/)lib/libiconv.a else diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c index d39cbdd8f..67d1fff69 100644 --- a/libhb/muxavformat.c +++ b/libhb/muxavformat.c @@ -7,8 +7,6 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ -#if defined(USE_AVFORMAT) - #include <ogg/ogg.h> #include "libavformat/avformat.h" #include "libavutil/avstring.h" @@ -1323,5 +1321,3 @@ hb_mux_object_t * hb_mux_avformat_init( hb_job_t * job ) m->job = job; return m; } - -#endif // USE_AVFORMAT diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c index f06651734..d1646e7fb 100644 --- a/libhb/muxcommon.c +++ b/libhb/muxcommon.c @@ -614,22 +614,10 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job ) { switch( job->mux ) { -#ifdef USE_MP4V2 - case HB_MUX_MP4V2: - mux->m = hb_mux_mp4_init( job ); - break; -#endif -#ifdef USE_LIBMKV - case HB_MUX_LIBMKV: - mux->m = hb_mux_mkv_init( job ); - break; -#endif -#ifdef USE_AVFORMAT case HB_MUX_AV_MP4: case HB_MUX_AV_MKV: mux->m = hb_mux_avformat_init( job ); break; -#endif default: hb_error( "No muxer selected, exiting" ); *job->done_error = HB_ERROR_INIT; diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c deleted file mode 100644 index 4a8de8a37..000000000 --- a/libhb/muxmkv.c +++ /dev/null @@ -1,710 +0,0 @@ -/* muxmkv.c - - Copyright (c) 2003-2014 HandBrake Team - This file is part of the HandBrake source code - Homepage: <http://handbrake.fr/>. - It may be used under the terms of the GNU General Public License v2. - For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html - */ - -/* libmkv header */ - -#if defined(USE_LIBMKV) - -#include "libmkv.h" - -#include <ogg/ogg.h> - -#include "hb.h" -#include "lang.h" - -/* Scale factor to apply to timecodes to convert from HandBrake's - * 1/90000s to nanoseconds as expected by libmkv */ -#define NANOSECOND_SCALE 1000000000L -#define TIMECODE_SCALE 1000000000L / 90000 - -struct hb_mux_object_s -{ - HB_MUX_COMMON; - - hb_job_t * job; - mk_Writer * file; - int delay; -}; - -struct hb_mux_data_s -{ - mk_Track * track; - uint64_t prev_chapter_tc; - uint16_t current_chapter; - int codec; - int subtitle; - int sub_format; -}; - -static uint8_t * create_flac_header( uint8_t *data, int size ) -{ - uint8_t * out; - uint8_t header[8] = { - 0x66, 0x4C, 0x61, 0x43, 0x80, 0x00, 0x00, 0x22 - }; - - out = malloc( size + 8 ); - memcpy( out, header, 8 ); - memcpy( out + 8, data, size ); - return out; -} - -static uint8_t* create_h264_header(hb_job_t *job, int *size) -{ - /* Taken from x264's muxers.c */ - int avcC_len = (5 + - 1 + 2 + job->config.h264.sps_length + - 1 + 2 + job->config.h264.pps_length); -#define MAX_AVCC_LEN 5 + 1 + 2 + 1024 + 1 + 2 + 1024 // FIXME - if (avcC_len > MAX_AVCC_LEN) - { - hb_log("create_h264_header: H.264 header too long (%d, max: %d)", - avcC_len, MAX_AVCC_LEN); - return NULL; - } - uint8_t *avcC = malloc(avcC_len); - if (avcC == NULL) - { - return NULL; - } - - avcC[0] = 1; - avcC[1] = job->config.h264.sps[1]; /* AVCProfileIndication */ - avcC[2] = job->config.h264.sps[2]; /* profile_compat */ - avcC[3] = job->config.h264.sps[3]; /* AVCLevelIndication */ - avcC[4] = 0xff; // nalu size length is four bytes - avcC[5] = 0xe1; // one sps - - avcC[6] = job->config.h264.sps_length >> 8; - avcC[7] = job->config.h264.sps_length; - memcpy(avcC + 8, job->config.h264.sps, job->config.h264.sps_length); - - avcC[8 + job->config.h264.sps_length] = 1; // one pps - avcC[9 + job->config.h264.sps_length] = job->config.h264.pps_length >> 8; - avcC[10 + job->config.h264.sps_length] = job->config.h264.pps_length; - memcpy(avcC + 11 + job->config.h264.sps_length, - job->config.h264.pps, job->config.h264.pps_length); - - if (size != NULL) - { - *size = avcC_len; - } - return avcC; -} - -/********************************************************************** - * MKVInit - ********************************************************************** - * Allocates hb_mux_data_t structures, create file and write headers - *********************************************************************/ -static int MKVInit( hb_mux_object_t * m ) -{ - hb_job_t * job = m->job; - hb_audio_t * audio; - hb_mux_data_t * mux_data; - - uint8_t *avcC = NULL; - uint8_t default_track_flag = 1; - uint8_t need_fonts = 0; - int avcC_len, i, j; - ogg_packet *ogg_headers[3]; - mk_TrackConfig *track; - iso639_lang_t *lang; - - track = calloc(1, sizeof(mk_TrackConfig)); - - // convert file name to current code page - char *path = hb_utf8_to_cp(job->file); - if (path == NULL) - { - hb_error("Could not convert string, out of memory?"); - job->mux_data = NULL; - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - - m->file = mk_createWriter(path, 1000000, 1); - free(path); - - if( !m->file ) - { - hb_error( "Could not create output file, Disk Full?" ); - job->mux_data = NULL; - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - free(track); - return 0; - } - - /* Video track */ - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - job->mux_data = mux_data; - - track->trackType = MK_TRACK_VIDEO; - track->flagDefault = 1; - track->flagEnabled = 1; - switch (job->vcodec) - { - case HB_VCODEC_X264: - case HB_VCODEC_QSV_H264: - avcC = create_h264_header(job, &avcC_len); - if (avcC == NULL) - { - free(track); - return -1; - } - track->codecID = MK_VCODEC_MP4AVC; - track->codecPrivate = avcC; - track->codecPrivateSize = avcC_len; - if (job->areBframes) - track->minCache = 1; - break; - case HB_VCODEC_FFMPEG_MPEG4: - track->codecID = MK_VCODEC_MP4ASP; - track->codecPrivate = job->config.mpeg4.bytes; - track->codecPrivateSize = job->config.mpeg4.length; - if (job->areBframes) - track->minCache = 1; - break; - case HB_VCODEC_FFMPEG_MPEG2: - track->codecID = MK_VCODEC_MPEG2; - track->codecPrivate = job->config.mpeg4.bytes; - track->codecPrivateSize = job->config.mpeg4.length; - if (job->areBframes) - track->minCache = 1; - break; - case HB_VCODEC_FFMPEG_VP8: - track->codecID = "V_VP8"; - track->codecPrivate = NULL; - track->codecPrivateSize = 0; - break; - case HB_VCODEC_THEORA: - { - int i; - uint64_t cp_size = 0; - track->codecID = MK_VCODEC_THEORA; - uint64_t header_sizes[3]; - for (i = 0; i < 3; ++i) - { - ogg_headers[i] = (ogg_packet *)job->config.theora.headers[i]; - ogg_headers[i]->packet = (unsigned char *)&job->config.theora.headers[i] + sizeof( ogg_packet ); - header_sizes[i] = ogg_headers[i]->bytes; - } - track->codecPrivate = mk_laceXiph(header_sizes, 2, &cp_size); - track->codecPrivate = realloc(track->codecPrivate, cp_size + ogg_headers[0]->bytes + ogg_headers[1]->bytes + ogg_headers[2]->bytes); - for(i = 0; i < 3; ++i) - { - memcpy(track->codecPrivate + cp_size, ogg_headers[i]->packet, ogg_headers[i]->bytes); - cp_size += ogg_headers[i]->bytes; - } - track->codecPrivateSize = cp_size; - } - break; - default: - *job->done_error = HB_ERROR_WRONG_INPUT; - *job->die = 1; - hb_error("muxmkv: Unknown video codec: %x", job->vcodec); - free(track); - return 0; - } - - track->extra.video.pixelWidth = job->width; - track->extra.video.pixelHeight = job->height; - track->extra.video.displayHeight = job->height; - if( job->anamorphic.mode ) - { - track->extra.video.displayWidth = job->width * ((double)job->anamorphic.par_width / (double)job->anamorphic.par_height); - } - else - { - track->extra.video.displayWidth = job->width; - } - - int vrate_base, vrate; - if( job->pass == 2 ) - { - hb_interjob_t * interjob = hb_interjob_get( job->h ); - vrate_base = interjob->vrate_base; - vrate = interjob->vrate; - } - else - { - vrate_base = job->vrate_base; - vrate = job->vrate; - } - track->defaultDuration = (int64_t)(((float)vrate_base / (float)vrate) * 1000000000); - - mux_data->track = mk_createTrack(m->file, track); - - /* add the audio tracks */ - for( i = 0; i < hb_list_count( job->list_audio ); i++ ) - { - audio = hb_list_item( job->list_audio, i ); - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - audio->priv.mux_data = mux_data; - - if (audio->config.out.delay > m->delay) - m->delay = audio->config.out.delay; - - mux_data->codec = audio->config.out.codec; - - memset(track, 0, sizeof(mk_TrackConfig)); - switch (audio->config.out.codec & HB_ACODEC_MASK) - { - case HB_ACODEC_DCA: - case HB_ACODEC_DCA_HD: - track->codecPrivate = NULL; - track->codecPrivateSize = 0; - track->codecID = MK_ACODEC_DTS; - break; - case HB_ACODEC_AC3: - track->codecPrivate = NULL; - track->codecPrivateSize = 0; - track->codecID = MK_ACODEC_AC3; - break; - case HB_ACODEC_LAME: - case HB_ACODEC_MP3: - track->codecPrivate = NULL; - track->codecPrivateSize = 0; - track->codecID = MK_ACODEC_MP3; - break; - case HB_ACODEC_VORBIS: - { - int i; - uint64_t cp_size = 0; - track->codecID = MK_ACODEC_VORBIS; - uint64_t header_sizes[3]; - for (i = 0; i < 3; ++i) - { - ogg_headers[i] = (ogg_packet *)audio->priv.config.vorbis.headers[i]; - ogg_headers[i]->packet = (unsigned char *)&audio->priv.config.vorbis.headers[i] + sizeof( ogg_packet ); - header_sizes[i] = ogg_headers[i]->bytes; - } - track->codecPrivate = mk_laceXiph(header_sizes, 2, &cp_size); - track->codecPrivate = realloc(track->codecPrivate, cp_size + ogg_headers[0]->bytes + ogg_headers[1]->bytes + ogg_headers[2]->bytes); - for(i = 0; i < 3; ++i) - { - memcpy(track->codecPrivate + cp_size, ogg_headers[i]->packet, ogg_headers[i]->bytes); - cp_size += ogg_headers[i]->bytes; - } - track->codecPrivateSize = cp_size; - } - break; - case HB_ACODEC_FFFLAC: - case HB_ACODEC_FFFLAC24: - if (audio->priv.config.extradata.bytes) - { - track->codecPrivate = create_flac_header(audio->priv.config.extradata.bytes, - audio->priv.config.extradata.length); - track->codecPrivateSize = audio->priv.config.extradata.length + 8; - } - track->codecID = MK_ACODEC_FLAC; - break; - case HB_ACODEC_FFAAC: - case HB_ACODEC_CA_AAC: - case HB_ACODEC_CA_HAAC: - case HB_ACODEC_FDK_AAC: - case HB_ACODEC_FDK_HAAC: - track->codecPrivate = audio->priv.config.extradata.bytes; - track->codecPrivateSize = audio->priv.config.extradata.length; - track->codecID = MK_ACODEC_AAC; - break; - default: - *job->done_error = HB_ERROR_WRONG_INPUT; - *job->die = 1; - hb_error("muxmkv: Unknown audio codec: %x", audio->config.out.codec); - return 0; - } - - if( default_track_flag ) - { - track->flagDefault = 1; - default_track_flag = 0; - } - else - { - track->flagDefault = 0; - } - track->flagEnabled = 1; - track->trackType = MK_TRACK_AUDIO; - // MKV lang codes should be ISO-639-2/B - lang = lang_for_code2( audio->config.lang.iso639_2 ); - track->language = lang->iso639_2b ? lang->iso639_2b : lang->iso639_2; - // sample rate - if ((audio->config.out.codec == HB_ACODEC_CA_HAAC) || - (audio->config.out.codec == HB_ACODEC_FDK_HAAC) || - (audio->config.out.codec == HB_ACODEC_AAC_PASS && - audio->config.in.samples_per_frame > 1024)) - { - // For HE-AAC, write outputSamplingFreq too - // samplingFreq is half of outputSamplingFreq - track->extra.audio.outputSamplingFreq = (float)audio->config.out.samplerate; - track->extra.audio.samplingFreq = track->extra.audio.outputSamplingFreq / 2.; - } - else - { - track->extra.audio.samplingFreq = (float)audio->config.out.samplerate; - } - if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) - { - track->extra.audio.channels = av_get_channel_layout_nb_channels(audio->config.in.channel_layout); - } - else - { - track->extra.audio.channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); - } - mux_data->track = mk_createTrack(m->file, track); - if (audio->config.out.codec == HB_ACODEC_VORBIS || - audio->config.out.codec == HB_ACODEC_FFFLAC || - audio->config.out.codec == HB_ACODEC_FFFLAC24) - free(track->codecPrivate); - } - - char * subidx_fmt = - "size: %dx%d\n" - "org: %d, %d\n" - "scale: 100%%, 100%%\n" - "alpha: 100%%\n" - "smooth: OFF\n" - "fadein/out: 50, 50\n" - "align: OFF at LEFT TOP\n" - "time offset: 0\n" - "forced subs: %s\n" - "palette: %06x, %06x, %06x, %06x, %06x, %06x, " - "%06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n" - "custom colors: OFF, tridx: 0000, " - "colors: 000000, 000000, 000000, 000000\n"; - - for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) - { - hb_subtitle_t * subtitle; - uint32_t rgb[16]; - char subidx[2048]; - int len; - - subtitle = hb_list_item( job->list_subtitle, i ); - if (subtitle->config.dest != PASSTHRUSUB) - continue; - - memset(track, 0, sizeof(mk_TrackConfig)); - switch (subtitle->source) - { - case VOBSUB: - track->codecID = MK_SUBTITLE_VOBSUB; - for (j = 0; j < 16; j++) - rgb[j] = hb_yuv2rgb(subtitle->palette[j]); - len = snprintf(subidx, 2048, subidx_fmt, - subtitle->width, subtitle->height, - 0, 0, "OFF", - rgb[0], rgb[1], rgb[2], rgb[3], - rgb[4], rgb[5], rgb[6], rgb[7], - rgb[8], rgb[9], rgb[10], rgb[11], - rgb[12], rgb[13], rgb[14], rgb[15]); - track->codecPrivate = subidx; - track->codecPrivateSize = len + 1; - break; - case PGSSUB: - track->codecPrivate = NULL; - track->codecPrivateSize = 0; - track->codecID = MK_SUBTITLE_PGS; - break; - case CC608SUB: - case CC708SUB: - case TX3GSUB: - case UTF8SUB: - case SRTSUB: - case SSASUB: - track->codecID = MK_SUBTITLE_SSA; - need_fonts = 1; - track->codecPrivate = subtitle->extradata; - track->codecPrivateSize = subtitle->extradata_size; - break; - default: - continue; - } - if ( subtitle->config.default_track ) - { - track->flagDefault = 1; - } - - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - subtitle->mux_data = mux_data; - mux_data->subtitle = 1; - mux_data->sub_format = subtitle->format; - - track->flagEnabled = 1; - track->trackType = MK_TRACK_SUBTITLE; - // MKV lang codes should be ISO-639-2/B - lang = lang_for_code2( subtitle->iso639_2 ); - track->language = lang->iso639_2b ? lang->iso639_2b : lang->iso639_2; - - mux_data->track = mk_createTrack(m->file, track); - } - - if (need_fonts) - { - hb_list_t * list_attachment = job->list_attachment; - int i; - for ( i = 0; i < hb_list_count(list_attachment); i++ ) - { - hb_attachment_t * attachment = hb_list_item( list_attachment, i ); - - if ( attachment->type == FONT_TTF_ATTACH ) - { - mk_createAttachment( - m->file, - attachment->name, - NULL, - "application/x-truetype-font", - attachment->data, - attachment->size); - } - } - } - - if( mk_writeHeader( m->file, "HandBrake " HB_PROJECT_VERSION) < 0 ) - { - hb_error( "Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - } - if (track != NULL) - free(track); - if (avcC != NULL) - free(avcC); - - return 0; -} - -static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf) -{ - char chapter_name[1024]; - hb_chapter_t *chapter_data; - uint64_t timecode = 0; - hb_job_t *job = m->job; - - // Adjust for audio preroll and scale units - timecode = (buf->s.start + m->delay) * TIMECODE_SCALE; - if (mux_data == job->mux_data) - { - /* Video */ - if (job->chapter_markers && buf->s.new_chap) - { - // reached chapter N, write marker for chapter N-1 - mux_data->current_chapter = buf->s.new_chap - 1; - - // chapter numbers start at 1, but the list starts at 0 - chapter_data = hb_list_item(job->list_chapter, - mux_data->current_chapter - 1); - - // make sure we're not writing a chapter that has 0 length - if (chapter_data != NULL && mux_data->prev_chapter_tc < timecode) - { - if (chapter_data->title != NULL) - { - snprintf(chapter_name, 1023, "%s", chapter_data->title); - } - else - { - snprintf(chapter_name, 1023, "Chapter %d", - mux_data->current_chapter); - } - mk_createChapterSimple(m->file, - mux_data->prev_chapter_tc, - mux_data->prev_chapter_tc, chapter_name); - } - mux_data->prev_chapter_tc = timecode; - } - } - else if (mux_data->subtitle) - { - if( mk_startFrame(m->file, mux_data->track) < 0) - { - hb_error("Failed to write frame to output file, Disk Full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - uint64_t duration; - if (buf->s.duration < 0) - { - duration = 10 * NANOSECOND_SCALE; - } - else - { - duration = buf->s.duration * TIMECODE_SCALE; - } - mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); - mk_setFrameFlags(m->file, mux_data->track, timecode, 1, duration); - mk_flushFrame(m->file, mux_data->track); - hb_buffer_close(&buf); - return 0; - } - else - { - /* Audio */ - } - - if( mk_startFrame(m->file, mux_data->track) < 0) - { - hb_error( "Failed to write frame to output file, Disk Full?" ); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); - mk_setFrameFlags(m->file, mux_data->track, timecode, - ((mux_data == job->mux_data && - ((job->vcodec & HB_VCODEC_H264_MASK) || - (job->vcodec & HB_VCODEC_FFMPEG_MASK))) ? - (buf->s.frametype == HB_FRAME_IDR) : - (buf->s.frametype & HB_FRAME_KEY) != 0), 0); - hb_buffer_close(&buf); - return 0; -} - -static int MKVEnd(hb_mux_object_t *m) -{ - char chapter_name[1024]; - hb_chapter_t *chapter_data; - hb_job_t *job = m->job; - hb_mux_data_t *mux_data = job->mux_data; - - if( !job->mux_data ) - { - /* - * We must have failed to create the file in the first place. - */ - return 0; - } - - if (job->chapter_markers) - { - // get the last chapter - chapter_data = hb_list_item(job->list_chapter, - mux_data->current_chapter++); - - // only write the last chapter marker if it lasts at least 1.5 second - if (chapter_data != NULL && chapter_data->duration > 135000LL) - { - if (chapter_data->title != NULL) - { - snprintf(chapter_name, 1023, "%s", chapter_data->title); - } - else - { - snprintf(chapter_name, 1023, "Chapter %d", - mux_data->current_chapter); - } - mk_createChapterSimple(m->file, - mux_data->prev_chapter_tc, - mux_data->prev_chapter_tc, chapter_name); - } - } - - if( job->metadata ) - { - hb_metadata_t *md = job->metadata; - - hb_deep_log( 2, "Writing Metadata to output file..."); - if ( md->name ) - { - mk_createTagSimple( m->file, MK_TAG_TITLE, md->name ); - } - if ( md->artist ) - { - mk_createTagSimple( m->file, "ARTIST", md->artist ); - } - if ( md->album_artist ) - { - mk_createTagSimple( m->file, "DIRECTOR", md->album_artist ); - } - if ( md->composer ) - { - mk_createTagSimple( m->file, "COMPOSER", md->composer ); - } - if ( md->release_date ) - { - mk_createTagSimple( m->file, "DATE_RELEASED", md->release_date ); - } - if ( md->comment ) - { - mk_createTagSimple( m->file, "SUMMARY", md->comment ); - } - if ( !md->name && md->album ) - { - mk_createTagSimple( m->file, MK_TAG_TITLE, md->album ); - } - if ( md->genre ) - { - mk_createTagSimple( m->file, MK_TAG_GENRE, md->genre ); - } - if ( md->description ) - { - mk_createTagSimple( m->file, "DESCRIPTION", md->description ); - } - if ( md->long_description ) - { - mk_createTagSimple( m->file, "SYNOPSIS", md->long_description ); - } - } - - // Update and track private data that can change during - // encode. - int i; - for( i = 0; i < hb_list_count( job->list_audio ); i++ ) - { - mk_Track * track; - hb_audio_t * audio; - - audio = hb_list_item( job->list_audio, i ); - track = audio->priv.mux_data->track; - - switch (audio->config.out.codec & HB_ACODEC_MASK) - { - case HB_ACODEC_FFFLAC: - case HB_ACODEC_FFFLAC24: - if( audio->priv.config.extradata.bytes ) - { - uint8_t *header; - header = create_flac_header( - audio->priv.config.extradata.bytes, - audio->priv.config.extradata.length ); - mk_updateTrackPrivateData( m->file, track, - header, - audio->priv.config.extradata.length + 8 ); - free( header ); - } - break; - default: - break; - } - } - - if( mk_close(m->file) < 0 ) - { - hb_error( "Failed to flush the last frame and close the output file, Disk Full?" ); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - - // TODO: Free what we alloc'd - - return 0; -} - -hb_mux_object_t * hb_mux_mkv_init( hb_job_t * job ) -{ - hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); - m->init = MKVInit; - m->mux = MKVMux; - m->end = MKVEnd; - m->job = job; - return m; -} -#endif // USE_LIBMKV diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c deleted file mode 100644 index 946277574..000000000 --- a/libhb/muxmp4.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* muxmp4.c - - Copyright (c) 2003-2014 HandBrake Team - This file is part of the HandBrake source code - Homepage: <http://handbrake.fr/>. - It may be used under the terms of the GNU General Public License v2. - For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html - */ - -#include "hb.h" - -#if defined(USE_MP4V2) - -#include "mp4v2/mp4v2.h" - -struct hb_mux_object_s -{ - HB_MUX_COMMON; - - hb_job_t * job; - - /* output file name in current code page */ - char * path; - /* libmp4v2 handle */ - MP4FileHandle file; - - int64_t sum_dur; // sum of video frame durations so far - - hb_buffer_t *delay_buf; - - /* Chapter state information for muxing */ - MP4TrackId chapter_track; - int current_chapter; - uint64_t chapter_duration; -}; - -struct hb_mux_data_s -{ - MP4TrackId track; - uint8_t subtitle; - int sub_format; - - uint64_t sum_dur; // sum of the frame durations so far - - // audio frame duration info - int sample_rate; - int samples_per_frame; -}; - -/* Tune video track chunk duration. - * libmp4v2 default duration == dusamplerate == 1 second. - * Per van's suggestion we desire duration == 4 frames. - * Should be invoked immediately after track creation. - * - * return true on fail, false on success. - */ -static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId ) -{ - uint32_t tscale; - MP4Duration dur; - - tscale = MP4GetTrackTimeScale( m->file, trackId ); - dur = (MP4Duration)ceil( (double)tscale * (double)m->job->vrate_base / (double)m->job->vrate * 4.0 ); - - if( !MP4SetTrackDurationPerChunk( m->file, trackId, dur )) - { - hb_error( "muxmp4.c: MP4SetTrackDurationPerChunk failed!" ); - *m->job->done_error = HB_ERROR_UNKNOWN; - *m->job->die = 1; - return 0; - } - - hb_deep_log( 2, "muxmp4: track %u, chunk duration %"PRIu64, MP4FindTrackIndex( m->file, trackId ), dur ); - return 1; -} - -static const uint16_t ac3_sample_rate_tab[3] = { 48000, 44100, 32000 }; -/* possible bitrates */ -static const uint16_t ac3_bitrate_tab[19] = { - 32, 40, 48, 56, 64, 80, 96, 112, 128, - 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 -}; - - -/********************************************************************** - * MP4Init - ********************************************************************** - * Allocates hb_mux_data_t structures, create file and write headers - *********************************************************************/ -static int MP4Init( 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 i; - int subtitle_default; - - /* Flags for enabling/disabling tracks in an MP4. */ - enum - { - TRACK_DISABLED = 0x0, - TRACK_ENABLED = 0x1, - TRACK_IN_MOVIE = 0x2, - TRACK_IN_PREVIEW = 0x4, - TRACK_IN_POSTER = 0x8 - }; - - m->path = hb_utf8_to_cp(job->file); - if (m->path == NULL) - { - hb_error("Could not convert string, out of memory?"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - - /* Create an empty mp4 file */ - if (job->largeFileSize) - /* Use 64-bit MP4 file */ - { - m->file = MP4Create(m->path, MP4_DETAILS_ERROR, MP4_CREATE_64BIT_DATA); - hb_deep_log( 2, "muxmp4: using 64-bit MP4 formatting."); - } - else - /* Limit MP4s to less than 4 GB */ - { - m->file = MP4Create(m->path, MP4_DETAILS_ERROR, 0); - } - - if (m->file == MP4_INVALID_FILE_HANDLE) - { - hb_error("muxmp4.c: MP4Create failed!"); - *job->done_error = HB_ERROR_WRONG_INPUT; - *job->die = 1; - return 0; - } - - /* Video track */ - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - job->mux_data = mux_data; - - if (!(MP4SetTimeScale( m->file, 90000 ))) - { - hb_error("muxmp4.c: MP4SetTimeScale failed!"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - - if (job->vcodec & HB_VCODEC_H264_MASK) - { - /* Stolen from mp4creator */ - MP4SetVideoProfileLevel( m->file, 0x7F ); - mux_data->track = MP4AddH264VideoTrack( m->file, 90000, - 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 */ - if ( mux_data->track == MP4_INVALID_TRACK_ID ) - { - hb_error( "muxmp4.c: MP4AddH264VideoTrack failed!" ); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - - /* Tune track chunk duration */ - if( !MP4TuneTrackDurationPerChunk( m, mux_data->track )) - { - return 0; - } - - 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 ); - - if( job->ipod_atom ) - { - hb_deep_log( 2, "muxmp4: adding iPod atom"); - MP4AddIPodUUID(m->file, mux_data->track); - } - } - else if ( job->vcodec == HB_VCODEC_FFMPEG_MPEG4 ) /* FFmpeg MPEG-4 */ - { - MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 ); - mux_data->track = MP4AddVideoTrack( m->file, 90000, - MP4_INVALID_DURATION, job->width, job->height, - MP4_MPEG4_VIDEO_TYPE ); - if (mux_data->track == MP4_INVALID_TRACK_ID) - { - hb_error("muxmp4.c: MP4AddVideoTrack failed!"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - - /* Tune track chunk duration */ - if( !MP4TuneTrackDurationPerChunk( m, mux_data->track )) - { - return 0; - } - - /* VOL from FFmpeg or XviD */ - if (!(MP4SetTrackESConfiguration( m->file, mux_data->track, - job->config.mpeg4.bytes, job->config.mpeg4.length ))) - { - hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - } - else if ( job->vcodec == HB_VCODEC_FFMPEG_MPEG2 ) /* FFmpeg MPEG-2 */ - { - mux_data->track = MP4AddVideoTrack( m->file, 90000, - MP4_INVALID_DURATION, job->width, job->height, - MP4_MPEG2_VIDEO_TYPE ); - if (mux_data->track == MP4_INVALID_TRACK_ID) - { - hb_error("muxmp4.c: MP4AddVideoTrack failed!"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - - /* Tune track chunk duration */ - if( !MP4TuneTrackDurationPerChunk( m, mux_data->track )) - { - return 0; - } - - /* VOL from FFmpeg */ - if (!(MP4SetTrackESConfiguration( m->file, mux_data->track, - job->config.mpeg4.bytes, job->config.mpeg4.length ))) - { - hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - } - else - { - hb_error("muxmp4.c: Unsupported video encoder!"); - } - - /* COLR atom for color and gamma correction. Per the notes at: - * http://developer.apple.com/quicktime/icefloe/dispatch019.html#colr - * http://forum.doom9.org/showthread.php?t=133982#post1090068 - * The user can set it from job->color_matrix_code. */ - if( job->color_matrix_code == 4 ) - { - // Custom - MP4AddColr(m->file, mux_data->track, job->color_prim, job->color_transfer, job->color_matrix); - } - else if( job->color_matrix_code == 3 ) - { - // ITU BT.709 HD content - MP4AddColr(m->file, mux_data->track, HB_COLR_PRI_BT709, HB_COLR_TRA_BT709, HB_COLR_MAT_BT709); - } - else if( job->color_matrix_code == 2 ) - { - // ITU BT.601 DVD or SD TV content (PAL) - MP4AddColr(m->file, mux_data->track, HB_COLR_PRI_EBUTECH, HB_COLR_TRA_BT709, HB_COLR_MAT_SMPTE170M); - } - else if( job->color_matrix_code == 1 ) - { - // ITU BT.601 DVD or SD TV content (NTSC) - MP4AddColr(m->file, mux_data->track, HB_COLR_PRI_SMPTEC, HB_COLR_TRA_BT709, HB_COLR_MAT_SMPTE170M); - } - else - { - // detected during scan - MP4AddColr(m->file, mux_data->track, title->color_prim, title->color_transfer, title->color_matrix); - } - - if( job->anamorphic.mode ) - { - /* PASP atom for anamorphic video */ - float width, height; - - width = job->anamorphic.par_width; - - height = job->anamorphic.par_height; - - MP4AddPixelAspectRatio(m->file, mux_data->track, (uint32_t)width, (uint32_t)height); - - MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height)); - } - - /* add the audio tracks */ - for( i = 0; i < hb_list_count( job->list_audio ); i++ ) - { - audio = hb_list_item( job->list_audio, i ); - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - audio->priv.mux_data = mux_data; - - switch ( audio->config.out.codec & HB_ACODEC_MASK ) - { - case HB_ACODEC_AC3: - { - int ii, jj; - int bitrate; - int sr_shift, sr_code; - uint8_t bsid; - uint8_t bsmod; - uint8_t acmod; - uint8_t lfeon; - uint8_t br_code = 0; - - if ( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) - { - bsmod = audio->config.in.mode; - switch (audio->config.in.channel_layout & ~AV_CH_LOW_FREQUENCY) - { - case AV_CH_LAYOUT_MONO: - acmod = 1; - break; - - case AV_CH_LAYOUT_STEREO: - acmod = 2; - break; - - case AV_CH_LAYOUT_SURROUND: - acmod = 3; - break; - - case AV_CH_LAYOUT_2_1: - acmod = 4; - break; - - case AV_CH_LAYOUT_4POINT0: - acmod = 5; - break; - - case AV_CH_LAYOUT_2_2: - acmod = 6; - break; - - case AV_CH_LAYOUT_5POINT0: - acmod = 7; - break; - - default: - hb_error("MP4Init: bad mixdown"); - acmod = 2; - break; - } - lfeon = !!(audio->config.in.channel_layout & AV_CH_LOW_FREQUENCY); - bitrate = audio->config.in.bitrate; - mux_data->sample_rate = audio->config.in.samplerate; - mux_data->samples_per_frame = audio->config.in.samples_per_frame; - } - else - { - bsmod = 0; - bitrate = audio->config.out.bitrate * 1000; - mux_data->sample_rate = audio->config.out.samplerate; - mux_data->samples_per_frame = audio->config.out.samples_per_frame; - switch (audio->config.out.mixdown) - { - case HB_AMIXDOWN_MONO: - acmod = 1; - lfeon = 0; - break; - - case HB_AMIXDOWN_STEREO: - case HB_AMIXDOWN_DOLBY: - case HB_AMIXDOWN_DOLBYPLII: - acmod = 2; - lfeon = 0; - break; - - case HB_AMIXDOWN_5POINT1: - acmod = 7; - lfeon = 1; - break; - - default: - hb_log("MP4Init: bad mixdown"); - acmod = 2; - lfeon = 0; - break; - } - } - - for (ii = 0; ii < 3; ii++) - { - for (jj = 0; jj < 3; jj++) - { - if ((ac3_sample_rate_tab[jj] >> ii) == mux_data->sample_rate) - { - goto rate_found1; - } - } - } - hb_error("Unknown AC3 samplerate"); - ii = jj = 0; - rate_found1: - sr_shift = ii; - sr_code = jj; - bsid = 8 + ii; - for (ii = 0; ii < 19; ii++) - { - if ((ac3_bitrate_tab[ii] >> sr_shift)*1000 == bitrate) - break; - } - if ( ii >= 19 ) - { - hb_error("Unknown AC3 bitrate"); - ii = 0; - } - br_code = ii; - - mux_data->track = MP4AddAC3AudioTrack(m->file, - mux_data->sample_rate, - sr_code, bsid, bsmod, - acmod, lfeon, br_code); - - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - - if (audio->config.out.name == NULL) { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)"Surround", strlen("Surround")); - } - else { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)(audio->config.out.name), - strlen(audio->config.out.name)); - } - } break; - - case HB_ACODEC_FFAAC: - case HB_ACODEC_CA_AAC: - case HB_ACODEC_CA_HAAC: - case HB_ACODEC_FDK_AAC: - case HB_ACODEC_FDK_HAAC: - case HB_ACODEC_LAME: - case HB_ACODEC_MP3: - case HB_ACODEC_DCA_HD: - case HB_ACODEC_DCA: - { - uint8_t audio_type = MP4_MPEG4_AUDIO_TYPE; - int channels, config_len = 0; - uint8_t *config_bytes = NULL; - - switch ( audio->config.out.codec & HB_ACODEC_MASK ) - { - case HB_ACODEC_FFAAC: - case HB_ACODEC_CA_AAC: - case HB_ACODEC_CA_HAAC: - case HB_ACODEC_FDK_AAC: - case HB_ACODEC_FDK_HAAC: - { - audio_type = MP4_MPEG4_AUDIO_TYPE; - config_bytes = audio->priv.config.extradata.bytes; - config_len = audio->priv.config.extradata.length; - } break; - case HB_ACODEC_LAME: - case HB_ACODEC_MP3: - { - audio_type = MP4_MPEG2_AUDIO_TYPE; - } break; - case HB_ACODEC_DCA: - case HB_ACODEC_DCA_HD: - { - audio_type = 0xA9; - } break; - } - if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) - { - mux_data->sample_rate = audio->config.in.samplerate; - mux_data->samples_per_frame = audio->config.in.samples_per_frame; - channels = av_get_channel_layout_nb_channels(audio->config.in.channel_layout); - } - else - { - mux_data->sample_rate = audio->config.out.samplerate; - mux_data->samples_per_frame = audio->config.out.samples_per_frame; - channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); - } - mux_data->track = MP4AddAudioTrack(m->file, - mux_data->sample_rate, - // fixed frame duration, if applicable - mux_data->samples_per_frame > 0 ? - mux_data->samples_per_frame : MP4_INVALID_DURATION, - audio_type); - - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - - if (audio->config.out.name == NULL) { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)"Stereo", strlen("Stereo")); - } - else { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)(audio->config.out.name), - strlen(audio->config.out.name)); - } - - MP4SetAudioProfileLevel( m->file, 0x0F ); - if ( config_bytes ) - { - MP4SetTrackESConfiguration( m->file, mux_data->track, - config_bytes, config_len ); - } - /* Set the correct number of channels for this track */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.*.channels", channels); - } break; - - default: - { - hb_log("MP4Mux: Unsupported audio codec %x", audio->config.out.codec); - } break; - } - - /* Set the language for this track */ - MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2); - - if( hb_list_count( job->list_audio ) > 1 ) - { - /* Set the audio track alternate group */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1); - } - - if (i == 0) { - /* Enable the first audio track */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE)); - } - else - /* Disable the other audio tracks so QuickTime doesn't play - them all at once. */ - { - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE)); - hb_deep_log( 2, "muxmp4: disabled extra audio track %u", MP4FindTrackIndex( m->file, mux_data->track )); - } - - } - - // Quicktime requires that at least one subtitle is enabled, - // else it doesn't show any of the subtitles. - // So check to see if any of the subtitles are flagged to be - // the defualt. The default will the the enabled track, else - // enable the first track. - subtitle_default = 0; - for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) - { - hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i ); - - if( subtitle && subtitle->format == TEXTSUB && - subtitle->config.dest == PASSTHRUSUB ) - { - if ( subtitle->config.default_track ) - subtitle_default = 1; - } - } - for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) - { - hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i ); - - if( subtitle && subtitle->format == TEXTSUB && - subtitle->config.dest == PASSTHRUSUB ) - { - uint64_t width, height = 60; - if( job->anamorphic.mode ) - width = job->width * ( (float) job->anamorphic.par_width / job->anamorphic.par_height ); - else - width = job->width; - - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - subtitle->mux_data = mux_data; - mux_data->subtitle = 1; - mux_data->sub_format = subtitle->format; - mux_data->track = MP4AddSubtitleTrack( m->file, 90000, width, height ); - - MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2); - - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - - const uint8_t textColor[4] = { 255,255,255,255 }; - - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 2); - - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.dataReferenceIndex", 1); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.horizontalJustification", 1); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.verticalJustification", 255); - - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.bgColorAlpha", 255); - - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxBottom", height); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.defTextBoxRight", width); - - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontID", 1); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontSize", 24); - - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorRed", textColor[0]); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorGreen", textColor[1]); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorBlue", textColor[2]); - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.tx3g.fontColorAlpha", textColor[3]); - - /* translate the track */ - uint8_t* val; - uint8_t nval[36]; - uint32_t *ptr32 = (uint32_t*) nval; - uint32_t size; - - MP4GetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", &val, &size); - memcpy(nval, val, size); - - const uint32_t ytranslation = (job->height - height) * 0x10000; - -#ifdef WORDS_BIGENDIAN - ptr32[7] = ytranslation; -#else - /* we need to switch the endianness, as the file format expects big endian */ - ptr32[7] = ((ytranslation & 0x000000FF) << 24) + ((ytranslation & 0x0000FF00) << 8) + - ((ytranslation & 0x00FF0000) >> 8) + ((ytranslation & 0xFF000000) >> 24); -#endif - - MP4SetTrackBytesProperty(m->file, mux_data->track, "tkhd.matrix", nval, size); - if ( !subtitle_default || subtitle->config.default_track ) { - /* Enable the default subtitle track */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE)); - subtitle_default = 1; - } - else - { - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE)); - } - } - else if( subtitle && subtitle->format == PICTURESUB && - subtitle->config.dest == PASSTHRUSUB ) - { - mux_data = calloc(1, sizeof( hb_mux_data_t ) ); - subtitle->mux_data = mux_data; - mux_data->subtitle = 1; - mux_data->sub_format = subtitle->format; - - mux_data->track = MP4AddSubpicTrack( m->file, 90000, subtitle->width, subtitle->height ); - - MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2); - - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - uint8_t palette[16][4]; - int ii; - for ( ii = 0; ii < 16; ii++ ) - { - palette[ii][0] = 0; - palette[ii][1] = (subtitle->palette[ii] >> 16) & 0xff; - palette[ii][2] = (subtitle->palette[ii] >> 8) & 0xff; - palette[ii][3] = (subtitle->palette[ii]) & 0xff; - } - if (!(MP4SetTrackESConfiguration( m->file, mux_data->track, - (uint8_t*)palette, 16 * 4 ))) - { - hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!"); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return 0; - } - if ( !subtitle_default || subtitle->config.default_track ) { - /* Enable the default subtitle track */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE)); - subtitle_default = 1; - } - else - { - MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE)); - } - } - } - - if (job->chapter_markers) - { - /* add a text track for the chapters. We add the 'chap' atom to track - one which is usually the video track & should never be disabled. - The Quicktime spec says it doesn't matter which media track the - chap atom is on but it has to be an enabled track. */ - MP4TrackId textTrack; - textTrack = MP4AddChapterTextTrack(m->file, 1, 0); - - m->chapter_track = textTrack; - m->chapter_duration = 0; - m->current_chapter = job->chapter_start; - } - - /* Add encoded-by metadata listing version and build date */ - char *tool_string; - tool_string = (char *)malloc(80); - snprintf( tool_string, 80, "HandBrake %s %i", HB_PROJECT_VERSION, HB_PROJECT_BUILD); - - /* allocate,fetch,populate,store,free tags structure */ - const MP4Tags* tags; - tags = MP4TagsAlloc(); - MP4TagsFetch( tags, m->file ); - MP4TagsSetEncodingTool( tags, tool_string ); - MP4TagsStore( tags, m->file ); - MP4TagsFree( tags ); - - free(tool_string); - - 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; - int64_t duration, stop = AV_NOPTS_VALUE; - int64_t offset = 0; - hb_buffer_t *tmp; - - if (buf != NULL) - { - if (buf->s.duration >= 0) - { - stop = buf->s.start + buf->s.duration; - } - else if (mux_data->subtitle) - { - buf->s.duration = 10 * 90000; - stop = buf->s.start + buf->s.duration; - } - } - - if( mux_data == job->mux_data ) - { - /* Video */ - if ((job->vcodec & HB_VCODEC_H264_MASK) || - (job->vcodec & HB_VCODEC_FFMPEG_MASK)) - { - if ( buf && buf->s.start < buf->s.renderOffset ) - { - hb_log("MP4Mux: PTS %"PRId64" < DTS %"PRId64, - buf->s.start, buf->s.renderOffset ); - buf->s.renderOffset = buf->s.start; - } - } - - // We delay muxing video by one frame so that we can calculate - // the dts to dts duration of the frames. - tmp = buf; - buf = m->delay_buf; - m->delay_buf = tmp; - - if ( !buf ) - return 0; - - stop = buf->s.start + buf->s.duration; - - if ((job->vcodec & HB_VCODEC_H264_MASK) || - (job->vcodec & HB_VCODEC_FFMPEG_MASK)) - { - // x264 supplies us with DTS, so offset is PTS - DTS - offset = buf->s.start - buf->s.renderOffset; - } - - /* Add the sample before the new frame. - It is important that this be calculated prior to the duration - of the new video sample, as we want to sync to right after it. - (This is because of how durations for text tracks work in QT) */ - if( job->chapter_markers && buf->s.new_chap ) - { - hb_chapter_t *chapter = NULL; - - // this chapter is postioned by writing out the previous chapter. - // the duration of the previous chapter is the duration up to but - // not including the current frame minus the duration of all - // chapters up to the previous. - // The initial and final chapters can be very short (a second or - // less) since they're not really chapters but just a placeholder to - // insert a cell command. We don't write chapters shorter than 1.5 sec. - duration = m->sum_dur - m->chapter_duration + offset; - if ( duration >= (90000*3)/2 ) - { - chapter = hb_list_item( m->job->list_chapter, - buf->s.new_chap - 2 ); - - MP4AddChapter( m->file, - m->chapter_track, - duration, - (chapter != NULL) ? chapter->title : NULL); - - m->current_chapter = buf->s.new_chap; - m->chapter_duration += duration; - } - } - - if ((job->vcodec & HB_VCODEC_H264_MASK) || - (job->vcodec & HB_VCODEC_FFMPEG_MASK)) - { - // x264 supplies us with DTS - if ( m->delay_buf ) - { - duration = m->delay_buf->s.renderOffset - buf->s.renderOffset; - } - else - { - duration = stop - m->sum_dur; - // Due to how libx264 generates DTS, it's possible for the - // above calculation to be negative. - // - // x264 generates DTS by rearranging PTS in this sequence: - // pts0 - delay, pts1 - delay, pts2 - delay, pts1, pts2, pts3... - // - // where delay == pts2. This guarantees that DTS <= PTS for - // any frame, but also generates this sequence of durations: - // d0 + d1 + d0 + d1 + d2 + d3 ... + d(N-2) - // - // so the sum up to the last frame is: - // sum_dur = d0 + d1 + d0 + d1 + d2 + d3 ... + d(N-3) - // - // while the original total duration of the video was: - // duration = d0 + d1 + d2 + d3 ... + d(N) - // - // Note that if d0 + d1 != d(N-1) + d(N), the total - // length of the video changes since d(N-1) and d(N) are - // replaced by d0 and d1 in the final duration sum. - // - // To keep the total length of the video the same as the source - // we try to make - // d(N-2) = duration - sum_dur - // - // But if d0 + d1 >= d(N-1) + d(N), the above calculation - // results in a nagative value and we need to fix it. - if ( duration <= 0 ) - duration = 90000. / ((double)job->vrate / (double)job->vrate_base); - } - } - else - { - // We're getting the frames in decode order but the timestamps are - // for presentation so we have to use durations and effectively - // compute a DTS. - duration = buf->s.duration; - } - - if ( duration <= 0 ) - { - /* We got an illegal mp4/h264 duration. This shouldn't - be possible and usually indicates a bug in the upstream code. - Complain in the hope that someone will go find the bug but - try to fix the error so that the file will still be playable. */ - hb_log("MP4Mux: illegal duration %"PRId64", start %"PRId64"," - "stop %"PRId64", sum_dur %"PRId64, - duration, buf->s.start, stop, m->sum_dur ); - /* we don't know when the next frame starts so we can't pick a - valid duration for this one. we pick something "short" - (roughly 1/3 of an NTSC frame time) to take time from - the next frame. */ - duration = 1000; - } - m->sum_dur += duration; - } - else - { - /* Audio */ - if (mux_data->samples_per_frame > 0) - // frame size is fixed and known - duration = MP4_INVALID_DURATION; - else - // frame size has to be computed - duration = buf->s.duration * mux_data->sample_rate / 90000; - } - - /* Here's where the sample actually gets muxed. */ - if (mux_data == job->mux_data && ((job->vcodec & HB_VCODEC_H264_MASK) || - (job->vcodec & HB_VCODEC_FFMPEG_MASK))) - { - /* Compute dependency flags. - * - * This mechanism is (optionally) used by media players such as QuickTime - * to offer better scrubbing performance. The most influential bits are - * MP4_SDT_HAS_NO_DEPENDENTS and MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED. - * - * Other bits are possible but no example media using such bits have been - * found. - * - * It is acceptable to supply 0-bits for any samples which characteristics - * cannot be positively guaranteed. - */ - int sync = 0; - uint32_t dflags = 0; - - /* encoding layer signals if frame is referenced by other frames */ - if( buf->s.flags & HB_FRAME_REF ) - dflags |= MP4_SDT_HAS_DEPENDENTS; - else - dflags |= MP4_SDT_HAS_NO_DEPENDENTS; /* disposable */ - - switch( buf->s.frametype ) - { - case HB_FRAME_IDR: - sync = 1; - break; - case HB_FRAME_I: - dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED; - break; - case HB_FRAME_P: - dflags |= MP4_SDT_EARLIER_DISPLAY_TIMES_ALLOWED; - break; - case HB_FRAME_BREF: - case HB_FRAME_B: - default: - break; /* nothing to mark */ - } - - if( !MP4WriteSampleDependency( m->file, - mux_data->track, - buf->data, - buf->size, - duration, - offset, - sync, - dflags )) - { - hb_error("Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - } - else if (mux_data->subtitle) - { - if( mux_data->sub_format == TEXTSUB ) - { - /* MPEG4 timed text does not allow overlapping samples; upstream - code should coalesce overlapping subtitle lines. */ - if( buf->s.start < mux_data->sum_dur ) - { - if ( stop - mux_data->sum_dur > 90*500 ) - { - hb_log("MP4Mux: shortening overlapping subtitle, " - "start %"PRId64", stop %"PRId64", sum_dur %"PRId64, - buf->s.start, stop, m->sum_dur); - buf->s.start = mux_data->sum_dur; - } - } - if( buf->s.start < mux_data->sum_dur ) - { - hb_log("MP4Mux: skipping overlapping subtitle, " - "start %"PRId64", stop %"PRId64", sum_dur %"PRId64, - buf->s.start, stop, m->sum_dur); - } - else - { - /* Write an empty sample */ - if ( mux_data->sum_dur < buf->s.start ) - { - uint8_t empty[2] = {0,0}; - if( !MP4WriteSample( m->file, - mux_data->track, - empty, - 2, - buf->s.start - mux_data->sum_dur, - 0, - 1 )) - { - hb_error("Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - mux_data->sum_dur += buf->s.start - mux_data->sum_dur; - } - uint8_t styleatom[2048];; - uint16_t stylesize = 0; - uint8_t buffer[2048]; - uint16_t buffersize = 0; - uint8_t output[2048]; - - *buffer = '\0'; - - /* - * Copy the subtitle into buffer stripping markup and creating - * style atoms for them. - */ - hb_muxmp4_process_subtitle_style( buf->data, - buffer, - styleatom, &stylesize ); - - buffersize = strlen((char*)buffer); - - hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%f: %s", - (float)buf->s.start / 90000, buf->s.start, stop, - buf->s.duration, buffer); - - /* Write the subtitle sample */ - memcpy( output + 2, buffer, buffersize ); - memcpy( output + 2 + buffersize, styleatom, stylesize); - output[0] = ( buffersize >> 8 ) & 0xff; - output[1] = buffersize & 0xff; - - if( !MP4WriteSample( m->file, - mux_data->track, - output, - buffersize + stylesize + 2, - buf->s.duration, - 0, - 1 )) - { - hb_error("Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - - mux_data->sum_dur += buf->s.duration; - } - } - else if( mux_data->sub_format == PICTURESUB ) - { - /* Write an empty sample */ - if ( mux_data->sum_dur < buf->s.start ) - { - uint8_t empty[2] = {0,0}; - if( !MP4WriteSample( m->file, - mux_data->track, - empty, - 2, - buf->s.start - mux_data->sum_dur, - 0, - 1 )) - { - hb_error("Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - mux_data->sum_dur += buf->s.start - mux_data->sum_dur; - } - if( !MP4WriteSample( m->file, - mux_data->track, - buf->data, - buf->size, - buf->s.duration, - 0, - 1 )) - { - hb_error("Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - - mux_data->sum_dur += buf->s.duration; - } - } - else - { - /* - * Audio - */ - if( !MP4WriteSample( m->file, - mux_data->track, - buf->data, - buf->size, - duration, - offset, - ( buf->s.frametype & HB_FRAME_KEY ) != 0 )) - { - hb_error("Failed to write to output file, disk full?"); - *job->done_error = HB_ERROR_UNKNOWN; - *job->die = 1; - } - } - hb_buffer_close( &buf ); - - return 0; -} - -static int MP4End( hb_mux_object_t * m ) -{ - hb_job_t * job = m->job; - int i; - - if (m->file != MP4_INVALID_FILE_HANDLE) - { - // Flush the delayed frame - if ( m->delay_buf ) - MP4Mux( m, job->mux_data, NULL ); - - /* Write our final chapter marker */ - if( m->job->chapter_markers ) - { - hb_chapter_t *chapter = NULL; - int64_t duration = m->sum_dur - m->chapter_duration; - /* The final chapter can have a very short duration - if it's less - * than 1.5 seconds just skip it. */ - if ( duration >= (90000*3)/2 ) - { - - chapter = hb_list_item( m->job->list_chapter, - m->current_chapter - 1 ); - - MP4AddChapter( m->file, - m->chapter_track, - duration, - (chapter != NULL) ? chapter->title : NULL); - } - } - - if ( job->config.h264.init_delay ) - { - // Insert track edit to get A/V back in sync. The edit amount is - // the init_delay. - int64_t edit_amt = job->config.h264.init_delay; - MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt, - MP4GetTrackDuration(m->file, 1), 0); - if ( m->job->chapter_markers ) - { - // apply same edit to chapter track to keep it in sync with video - MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID, - edit_amt, - MP4GetTrackDuration(m->file, m->chapter_track), 0); - } - } - - // Check for audio preroll and add edit entries for audio - for( i = 0; i < hb_list_count( job->list_audio ); i++ ) - { - hb_audio_t *audio = hb_list_item( job->list_audio, i ); - hb_mux_data_t *mux_data = audio->priv.mux_data; - if (audio->config.out.delay > 0) - { - int64_t edit_amt = audio->config.out.delay; - MP4AddTrackEdit(m->file, mux_data->track, MP4_INVALID_EDIT_ID, - edit_amt, MP4GetTrackDuration(m->file, 1), 0); - } - } - - /* - * Write the MP4 iTunes metadata if we have any metadata - */ - if( job->metadata ) - { - hb_metadata_t *md = job->metadata; - const MP4Tags* tags; - - hb_deep_log( 2, "Writing Metadata to output file..."); - - /* allocate tags structure */ - tags = MP4TagsAlloc(); - /* fetch data from MP4 file (in case it already has some data) */ - MP4TagsFetch( tags, m->file ); - - /* populate */ - if( md->name ) - MP4TagsSetName( tags, md->name ); - if( md->artist ) - MP4TagsSetArtist( tags, md->artist ); - if( md->composer ) - MP4TagsSetComposer( tags, md->composer ); - if( md->comment ) - MP4TagsSetComments( tags, md->comment ); - if( md->release_date ) - MP4TagsSetReleaseDate( tags, md->release_date ); - if( md->album ) - MP4TagsSetAlbum( tags, md->album ); - if( md->album_artist ) - MP4TagsSetAlbumArtist( tags, md->album_artist ); - if( md->genre ) - MP4TagsSetGenre( tags, md->genre ); - if( md->description ) - MP4TagsSetDescription( tags, md->description ); - if( md->long_description ) - MP4TagsSetLongDescription( tags, md->long_description ); - - if( md->list_coverart ) - { - hb_coverart_t * coverart; - int ii; - - for ( ii = 0; ii < hb_list_count( md->list_coverart ); ii++ ) - { - coverart = hb_list_item( md->list_coverart, ii ); - MP4TagArtwork art; - int type; - switch ( coverart->type ) - { - case HB_ART_BMP: - type = MP4_ART_BMP; - break; - case HB_ART_GIF: - type = MP4_ART_GIF; - break; - case HB_ART_JPEG: - type = MP4_ART_JPEG; - break; - case HB_ART_PNG: - type = MP4_ART_PNG; - break; - default: - type = MP4_ART_UNDEFINED; - break; - } - art.data = coverart->data; - art.size = coverart->size; - art.type = type; - MP4TagsAddArtwork( tags, &art ); - } - } - - /* push data to MP4 file */ - MP4TagsStore( tags, m->file ); - /* free memory associated with structure */ - MP4TagsFree( tags ); - } - - MP4Close( m->file ); - - if ( job->mp4_optimize ) - { - hb_log( "muxmp4: optimizing file" ); - char filename[1024]; memset( filename, 0, 1024 ); - snprintf(filename, 1024, "%s.tmp", m->path); - MP4Optimize(m->path, filename, MP4_DETAILS_ERROR); - remove(m->path); - rename(filename, m->path); - } - - } - free(m->path); - - return 0; -} - -hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job ) -{ - hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); - m->init = MP4Init; - m->mux = MP4Mux; - m->end = MP4End; - m->job = job; - return m; -} - -#endif // USE_MP4V2 diff --git a/libhb/stream.c b/libhb/stream.c index 5ebdc3639..05f1e9fc9 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -5523,11 +5523,7 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) /* * Fill the metadata. */ - // JJJ: is this necessary? can we just get this metadata from libav api's? - if (!decmetadata( title )) - { - ffmpeg_decmetadata( ic->metadata, title ); - } + ffmpeg_decmetadata( ic->metadata, title ); if( hb_list_count( title->list_chapter ) == 0 ) { |