X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fmuxmp4.c;h=e8e52751c282dc0cd0c5f8c5cb89bdce8069d2b6;hb=2f0858a91e2c736a5541d14318357efebfe89556;hp=bdeea8c423c160de794829991ca67bc3226809c7;hpb=0a9f73dcc79b7df7d0b86ad06bff4eac5f81eafd;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index bdeea8c4..e8e52751 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -31,7 +31,11 @@ struct hb_mux_object_s struct hb_mux_data_s { - MP4TrackId track; + MP4TrackId track; + uint8_t subtitle; + int sub_format; + + uint64_t sum_dur; // sum of the frame durations so far }; /* Tune video track chunk duration. @@ -56,7 +60,7 @@ static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId return 0; } - hb_deep_log( 2, "muxmp4: track %u, chunk duration %llu", MP4FindTrackIndex( m->file, trackId ), dur ); + hb_deep_log( 2, "muxmp4: track %u, chunk duration %"PRIu64, MP4FindTrackIndex( m->file, trackId ), dur ); return 1; } @@ -73,6 +77,7 @@ static int MP4Init( hb_mux_object_t * m ) hb_audio_t * audio; hb_mux_data_t * mux_data; int i; + int subtitle_default; /* Flags for enabling/disabling tracks in an MP4. */ typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags; @@ -98,7 +103,7 @@ static int MP4Init( hb_mux_object_t * m ) } /* Video track */ - mux_data = malloc( sizeof( hb_mux_data_t ) ); + mux_data = calloc(1, sizeof( hb_mux_data_t ) ); job->mux_data = mux_data; if (!(MP4SetTimeScale( m->file, 90000 ))) @@ -220,7 +225,7 @@ static int MP4Init( hb_mux_object_t * m ) 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 ) ); + mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; if( audio->config.out.codec == HB_ACODEC_AC3 ) @@ -399,6 +404,100 @@ static int MP4Init( hb_mux_object_t * m ) } + // 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", 0); + + 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)); + } + } + } + if (job->chapter_markers) { /* add a text track for the chapters. We add the 'chap' atom to track @@ -437,7 +536,6 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, hb_job_t * job = m->job; int64_t duration; int64_t offset = 0; - int i; if( mux_data == job->mux_data ) { @@ -450,8 +548,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, offset = buf->start + m->init_delay - m->sum_dur; if ( offset < 0 ) { - hb_log("MP4Mux: illegal render offset %lld, start %lld," - "stop %lld, sum_dur %lld", + hb_log("MP4Mux: illegal render offset %"PRId64", start %"PRId64"," + "stop %"PRId64", sum_dur %"PRId64, offset, buf->start, buf->stop, m->sum_dur ); offset = 0; } @@ -498,8 +596,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, 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 %lld, start %lld," - "stop %lld, sum_dur %lld", + hb_log("MP4Mux: illegal duration %"PRId64", start %"PRId64"," + "stop %"PRId64", sum_dur %"PRId64, duration, buf->start, buf->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" @@ -569,8 +667,57 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, *job->die = 1; } } + else if (mux_data->subtitle) + { + if( mux_data->sub_format == TEXTSUB ) + { + /* Write an empty sample */ + if ( mux_data->sum_dur < buf->start ) + { + uint8_t empty[2] = {0,0}; + if( !MP4WriteSample( m->file, + mux_data->track, + empty, + 2, + buf->start - mux_data->sum_dur, + 0, + 1 )) + { + hb_error("Failed to write to output file, disk full?"); + *job->die = 1; + } + mux_data->sum_dur += buf->start - mux_data->sum_dur; + } + + /* Write the subtitle sample */ + uint8_t buffer[2048]; + memcpy( buffer + 2, buf->data, buf->size ); + buffer[0] = ( buf->size >> 8 ) & 0xff; + buffer[1] = buf->size & 0xff; + + if( !MP4WriteSample( m->file, + mux_data->track, + buffer, + buf->size + 2, + buf->stop - buf->start, + 0, + 1 )) + { + hb_error("Failed to write to output file, disk full?"); + *job->die = 1; + } + + mux_data->sum_dur += (buf->stop - buf->start); + hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%"PRId64": %s", (float)buf->start / 90000, buf->start, buf->stop, + (buf->stop - buf->start), buf->data); + hb_deep_log(3, "MuxMP4:Total time elapsed:%"PRId64, mux_data->sum_dur); + } + } else { + /* + * Audio + */ if( !MP4WriteSample( m->file, mux_data->track, buf->data, @@ -584,33 +731,6 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } } - 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->dest == PASSTHRUSUB ) - { - /* - * Should be adding this one if the timestamp is right. - */ - hb_buffer_t *sub; - - while( ( sub = hb_fifo_see( subtitle->fifo_out )) != NULL ) - { - if (sub->start < buf->start ) { - sub = hb_fifo_get( subtitle->fifo_out ); - hb_log("MuxMP4: Text Sub:%lld: %s", sub->start, sub->data); - hb_buffer_close( &sub ); - } else { - /* - * Not time yet - */ - break; - } - } - } - } return 0; } @@ -672,13 +792,20 @@ static int MP4End( hb_mux_object_t * m ) MP4TagsFetch( tags, m->file ); /* populate */ - MP4TagsSetName( tags, md->name ); - MP4TagsSetArtist( tags, md->artist ); - MP4TagsSetComposer( tags, md->composer ); - MP4TagsSetComments( tags, md->comment ); - MP4TagsSetReleaseDate( tags, md->release_date ); - MP4TagsSetAlbum( tags, md->album ); - MP4TagsSetGenre( tags, md->genre ); + if( strlen( md->name )) + MP4TagsSetName( tags, md->name ); + if( strlen( md->artist )) + MP4TagsSetArtist( tags, md->artist ); + if( strlen( md->composer )) + MP4TagsSetComposer( tags, md->composer ); + if( strlen( md->comment )) + MP4TagsSetComments( tags, md->comment ); + if( strlen( md->release_date )) + MP4TagsSetReleaseDate( tags, md->release_date ); + if( strlen( md->album )) + MP4TagsSetAlbum( tags, md->album ); + if( strlen( md->genre )) + MP4TagsSetGenre( tags, md->genre ); if( md->coverart ) {