OSDN Git Service

import original 0.9.5 release
[handbrake-jp/handbrake-jp.git] / libhb / muxmp4.c
index 1264f9b..7cd4e0f 100644 (file)
@@ -20,8 +20,7 @@ struct hb_mux_object_s
 
     int64_t sum_dur;    // sum of video frame durations so far
 
-    // bias to keep render offsets in ctts atom positive (set up by encx264)
-    int64_t init_delay;
+    hb_buffer_t *delay_buf;
 
     /* Chapter state information for muxing */
     MP4TrackId chapter_track;
@@ -64,6 +63,14 @@ static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId
     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
  **********************************************************************
@@ -141,13 +148,11 @@ static int MP4Init( hb_mux_object_t * m )
         MP4AddH264PictureParameterSet( m->file, mux_data->track,
                 job->config.h264.pps, job->config.h264.pps_length );
 
-               if( job->h264_level == 30 || job->ipod_atom)
+               if( job->ipod_atom )
                {
                        hb_deep_log( 2, "muxmp4: adding iPod atom");
                        MP4AddIPodUUID(m->file, mux_data->track);
                }
-
-        m->init_delay = job->config.h264.init_delay;
     }
     else /* FFmpeg or XviD */
     {
@@ -228,106 +233,138 @@ static int MP4Init( hb_mux_object_t * m )
         mux_data = calloc(1, sizeof( hb_mux_data_t ) );
         audio->priv.mux_data = mux_data;
 
-        if( audio->config.out.codec == HB_ACODEC_AC3 )
+        if( audio->config.out.codec == HB_ACODEC_AC3_PASS )
         {
-            uint8_t fscod = 0;
             uint8_t bsid = audio->config.in.version;
             uint8_t bsmod = audio->config.in.mode;
             uint8_t acmod = audio->config.flags.ac3 & 0x7;
             uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
             uint8_t bit_rate_code = 0;
+            int ii, jj;
+            int freq = audio->config.in.samplerate;
+            int bitrate = audio->config.in.bitrate;
+            int sr_shift, sr_code;
 
-            /*
-             * Rewrite AC3 information into correct format for dac3 atom
-             */
-            switch( audio->config.in.samplerate )
+            for (ii = 0; ii < 3; ii++)
             {
-            case 48000:
-                fscod = 0;
-                break;
-            case 44100:
-                fscod = 1;
-                break;
-            case 32000:
-                fscod = 2;
-                break;
-            default:
-                /*
-                 * Error value, tells decoder to not decode this audio.
-                 */
-                fscod = 3;
-                break;
+                for (jj = 0; jj < 3; jj++)
+                {
+                    if ((ac3_sample_rate_tab[jj] >> ii) == freq)
+                    {
+                        goto rate_found1;
+                    }
+                }
+            }
+            hb_error("Unknown AC3 samplerate");
+            ii = jj = 0;
+rate_found1:
+            sr_shift = ii;
+            sr_code = jj;
+            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;
+            }
+            bit_rate_code = ii;
+
+            mux_data->track = MP4AddAC3AudioTrack(
+                m->file,
+                audio->config.in.samplerate, 
+                sr_code,
+                bsid,
+                bsmod,
+                acmod,
+                lfeon,
+                bit_rate_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));
             }
+        }
+        else if( audio->config.out.codec == HB_ACODEC_AC3 )
+        {
+            uint8_t bsid = 8;
+            uint8_t bsmod = 0;
+            uint8_t acmod = 2;
+            uint8_t lfeon = 0;
+            uint8_t bit_rate_code = 0;
+            int ii, jj;
+            int freq = audio->config.out.samplerate;
+            int bitrate = audio->config.out.bitrate;
+            int sr_shift, sr_code;
 
-            switch( audio->config.in.bitrate )
+            for (ii = 0; ii < 3; ii++)
+            {
+                for (jj = 0; jj < 3; jj++)
+                {
+                    if ((ac3_sample_rate_tab[jj] >> ii) == freq)
+                    {
+                        goto rate_found2;
+                    }
+                }
+            }
+            hb_error("Unknown AC3 samplerate");
+            ii = jj = 0;
+rate_found2:
+            sr_shift = ii;
+            sr_code = jj;
+            bsid = 8 + ii;
+            for (ii = 0; ii < 19; ii++)
+            {
+                if ((ac3_bitrate_tab[ii] >> sr_shift) == bitrate)
+                    break;
+            }
+            if ( ii >= 19 )
             {
-            case 32000:
-                bit_rate_code = 0;
-                break;
-            case 40000:
-                bit_rate_code = 1;
-                break;
-            case 48000:
-                bit_rate_code = 2;
-                break;
-            case 56000:
-                bit_rate_code = 3;
-                break;
-            case 64000:
-                bit_rate_code = 4;
-                break;
-            case 80000:
-                bit_rate_code = 5;
-                break;
-            case 96000:
-                bit_rate_code = 6;
-                break;
-            case 112000:
-                bit_rate_code = 7;
-                break;
-            case 128000:
-                bit_rate_code = 8;
-                break;
-            case 160000:
-                bit_rate_code = 9;
-                break;
-            case 192000:
-                bit_rate_code = 10;
-                break;
-            case 224000:
-                bit_rate_code = 11;
-                break;
-            case 256000:
-                bit_rate_code = 12;
-                break;
-            case 320000:
-                bit_rate_code = 13;
-                break;
-            case 384000:
-                bit_rate_code = 14;
-                break;
-            case 448000:
-                bit_rate_code = 15;
-                break;
-            case 512000:
-                bit_rate_code = 16;
-                break;
-            case 576000:
-                bit_rate_code = 17;
-                break;
-            case 640000:
-                bit_rate_code = 18;
-                break;
-            default:
                 hb_error("Unknown AC3 bitrate");
-                bit_rate_code = 0;
-                break;
+                ii = 0;
+            }
+            bit_rate_code = ii;
+
+            switch( audio->config.out.mixdown )
+            {
+                case HB_AMIXDOWN_MONO:
+                    acmod = 1;
+                    break;
+
+                case HB_AMIXDOWN_STEREO:
+                case HB_AMIXDOWN_DOLBY:
+                case HB_AMIXDOWN_DOLBYPLII:
+                    acmod = 2;
+                    break;
+
+                case HB_AMIXDOWN_6CH:
+                    acmod = 7;
+                    lfeon = 1;
+                    break;
+
+                default:
+                    hb_log(" MP4Init: bad mixdown" );
+                    break;
             }
 
             mux_data->track = MP4AddAC3AudioTrack(
                 m->file,
                 audio->config.out.samplerate, 
-                fscod,
+                sr_code,
                 bsid,
                 bsmod,
                 acmod,
@@ -350,7 +387,10 @@ static int MP4Init( hb_mux_object_t * m )
                     (const uint8_t*)(audio->config.out.name),
                     strlen(audio->config.out.name));
             }
-        } else {
+        } 
+        else if( audio->config.out.codec == HB_ACODEC_FAAC ||
+                 audio->config.out.codec == HB_ACODEC_CA_AAC ) 
+        {
             mux_data->track = MP4AddAudioTrack(
                 m->file,
                 audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
@@ -379,6 +419,32 @@ static int MP4Init( hb_mux_object_t * m )
 
             /* Set the correct number of channels for this track */
              MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
+        } else if( audio->config.out.codec == HB_ACODEC_LAME ) {
+            mux_data->track = MP4AddAudioTrack(
+                m->file,
+                audio->config.out.samplerate, 1152, MP4_MPEG2_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 );
+
+            /* Set the correct number of channels for this track */
+             MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown));
         }
 
         /* Set the language for this track */
@@ -496,6 +562,46 @@ static int MP4Init( hb_mux_object_t * m )
                 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->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)
@@ -774,25 +880,37 @@ 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;
+    hb_buffer_t *tmp;
 
     if( mux_data == job->mux_data )
     {
         /* Video */
 
-        // if there are b-frames compute the render offset
-        // (we'll need it for both the video frame & the chapter track)
-        if ( m->init_delay )
+        if( job->vcodec == HB_VCODEC_X264 )
         {
-            offset = buf->start + m->init_delay - m->sum_dur;
-            if ( offset < 0 )
+            if ( buf && buf->start < buf->renderOffset )
             {
-                hb_log("MP4Mux: illegal render offset %"PRId64", start %"PRId64","
-                       "stop %"PRId64", sum_dur %"PRId64,
-                       offset, buf->start, buf->stop, m->sum_dur );
-                offset = 0;
+                hb_log("MP4Mux: PTS %"PRId64" < DTS %"PRId64,
+                       buf->start, buf->renderOffset );
+                buf->renderOffset = buf->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;
+
+        if( job->vcodec == HB_VCODEC_X264 )
+        {
+            // x264 supplies us with DTS, so offset is PTS - DTS
+            offset = buf->start - buf->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.
@@ -824,10 +942,54 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
             }
         }
 
-        // 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->stop - buf->start;
+        if( job->vcodec == HB_VCODEC_X264 )
+        {
+            // x264 supplies us with DTS
+            if ( m->delay_buf )
+            {
+                duration = m->delay_buf->renderOffset - buf->renderOffset;
+            }
+            else
+            {
+                duration = buf->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->stop - buf->start;
+        }
+
         if ( duration <= 0 )
         {
             /* We got an illegal mp4/h264 duration. This shouldn't
@@ -968,6 +1130,39 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
 
             mux_data->sum_dur += (buf->stop - buf->start);
         }
+        else if( mux_data->sub_format == PICTURESUB )
+        {
+            /* 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;
+            }
+            if( !MP4WriteSample( m->file,
+                                 mux_data->track,
+                                 buf->data,
+                                 buf->size,
+                                 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);
+        }
     }
     else
     {
@@ -986,7 +1181,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
             *job->die = 1;
         }
     }
-
+    hb_buffer_close( &buf );
 
     return 0;
 }
@@ -996,6 +1191,10 @@ static int MP4End( hb_mux_object_t * m )
     hb_job_t   * job   = m->job;
     hb_title_t * title = job->title;
 
+    // Flush the delayed frame
+    if ( m->delay_buf )
+        MP4Mux( m, job->mux_data, NULL );
+
     /* Write our final chapter marker */
     if( m->job->chapter_markers )
     {
@@ -1016,11 +1215,11 @@ static int MP4End( hb_mux_object_t * m )
         }
     }
 
-    if (job->areBframes)
+    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 = m->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 )