]> granicus.if.org Git - handbrake/commitdiff
Fix PGS subtitle decoding...
authorJohn Stebbins <jstebbins.hb@gmail.com>
Wed, 13 Jun 2018 22:07:25 +0000 (15:07 -0700)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Wed, 13 Jun 2018 22:07:25 +0000 (15:07 -0700)
...And add a timebase to every stream.

ffmpeg's subtitle decoder internally converts the packet pts to
AV_TIME_BASE units based on AVCodecContext.pkt_timebase.  If
pkt_timebase is not set, the PGS subtitle decoder only returns
AV_NOPTS_VALUE for timestamps.  So setting pkt_timebase in decpgssub.c
fixes PGS subtitle decoding.

Confusingly, the subtitle decoder does not convert the pts *back* to the
input timebase, but instead leaves them in AV_TIME_BASE units upon
returning a decoded subtitle.

To get a head start on fixing any other such issues that might arrise, I
have also set pkt_timebase in all other avcodec decoders.

libhb/bd.c
libhb/common.c
libhb/common.h
libhb/decavcodec.c
libhb/decpgssub.c
libhb/dvd.c
libhb/dvdnav.c
libhb/stream.c

index 4517d2075352bf3883c43d5c24ae6cb68485f218..b8fc6fc0aa6b5dab84cd62aaed3b30ada6a7d755 100644 (file)
@@ -115,9 +115,11 @@ static void add_subtitle(int track, hb_list_t *list_subtitle, BLURAY_STREAM_INFO
     snprintf(subtitle->iso639_2, sizeof( subtitle->iso639_2 ), "%s",
              lang->iso639_2);
 
-    subtitle->reg_desc = STR4_TO_UINT32("HDMV");
-    subtitle->stream_type = bdsub->coding_type;
-    subtitle->codec = codec;
+    subtitle->reg_desc     = STR4_TO_UINT32("HDMV");
+    subtitle->stream_type  = bdsub->coding_type;
+    subtitle->codec        = codec;
+    subtitle->timebase.num = 1;
+    subtitle->timebase.den = 90000;
 
     hb_log( "bd: subtitle id=0x%x, lang=%s, 3cc=%s", subtitle->id,
             subtitle->lang, subtitle->iso639_2 );
@@ -202,7 +204,10 @@ static void add_audio(int track, hb_list_t *list_audio, BLURAY_STREAM_INFO *bdau
     hb_log("bd: audio id=0x%x, lang=%s (%s), 3cc=%s", audio->id,
            audio->config.lang.simple, codec_name, audio->config.lang.iso639_2);
 
-    audio->config.in.track = track;
+    audio->config.in.track        = track;
+    audio->config.in.timebase.num = 1;
+    audio->config.in.timebase.den = 90000;
+
     hb_list_add( list_audio, audio );
     return;
 }
index bb5de65fb74cb59ae6ff80a2760725b97e1dc356..4037414102a7f73a2240a86a937bb11c6ff96489 100644 (file)
@@ -3604,21 +3604,23 @@ hb_title_t * hb_title_init( char * path, int index )
 
     t = calloc( sizeof( hb_title_t ), 1 );
 
-    t->index         = index;
-    t->playlist      = -1;
-    t->list_audio    = hb_list_init();
-    t->list_chapter  = hb_list_init();
-    t->list_subtitle = hb_list_init();
-    t->list_attachment = hb_list_init();
-    t->metadata      = hb_metadata_init();
+    t->index              = index;
+    t->playlist           = -1;
+    t->list_audio         = hb_list_init();
+    t->list_chapter       = hb_list_init();
+    t->list_subtitle      = hb_list_init();
+    t->list_attachment    = hb_list_init();
+    t->metadata           = hb_metadata_init();
     strncat(t->path, path, sizeof(t->path) - 1);
     // default to decoding mpeg2
-    t->video_id      = 0xE0;
-    t->video_codec   = WORK_DECAVCODECV;
-    t->video_codec_param = AV_CODEC_ID_MPEG2VIDEO;
-    t->angle_count   = 1;
-    t->geometry.par.num = 1;
-    t->geometry.par.den = 1;
+    t->video_id           = 0xE0;
+    t->video_codec        = WORK_DECAVCODECV;
+    t->video_codec_param  = AV_CODEC_ID_MPEG2VIDEO;
+    t->video_timebase.num = 1;
+    t->video_timebase.den = 90000;
+    t->angle_count        = 1;
+    t->geometry.par.num   = 1;
+    t->geometry.par.den   = 1;
 
     return t;
 }
@@ -4809,6 +4811,8 @@ int hb_srt_add( const hb_job_t * job,
     subtitle->format = TEXTSUB;
     subtitle->source = SRTSUB;
     subtitle->codec = WORK_DECSRTSUB;
+    subtitle->timebase.num = 1;
+    subtitle->timebase.den = 90000;
 
     lang = lang_for_code2(lang_code);
     if (lang == NULL)
index b1f457d05e7aef9716c17136887e3ae4eb112996..a91d608c97b1ea617f0280a04de0a075932fc5cf 100644 (file)
@@ -813,6 +813,7 @@ struct hb_audio_config_s
         PRIVATE int encoder_delay; /* Encoder delay in samples.
                                     * These samples should be dropped
                                     * when decoding */
+        PRIVATE hb_rational_t timebase;
     } in;
 
     struct
@@ -943,14 +944,15 @@ struct hb_subtitle_s
 
 #ifdef __LIBHB__
     /* Internal data */
-    PRIVATE uint32_t codec;         /* Input "codec" */
-    PRIVATE uint32_t reg_desc;      /* registration descriptor of source */
-    PRIVATE uint32_t stream_type;   /* stream type from source stream */
-    PRIVATE uint32_t substream_type;/* substream for multiplexed streams */
-
-    hb_fifo_t * fifo_in;  /* SPU ES */
-    hb_fifo_t * fifo_raw; /* Decoded SPU */
-    hb_fifo_t * fifo_out; /* Correct Timestamps, ready to be muxed */
+    uint32_t        codec;          /* Input "codec" */
+    uint32_t        reg_desc;       /* registration descriptor of source */
+    uint32_t        stream_type;    /* stream type from source stream */
+    uint32_t        substream_type; /* substream for multiplexed streams */
+    hb_rational_t   timebase;
+
+    hb_fifo_t     * fifo_in;        /* SPU ES */
+    hb_fifo_t     * fifo_raw;       /* Decoded SPU */
+    hb_fifo_t     * fifo_out;       /* Correct Timestamps, ready to be muxed */
     hb_mux_data_t * mux_data;
 #endif
 };
@@ -1000,51 +1002,52 @@ struct hb_metadata_s
 struct hb_title_s
 {
     enum { HB_DVD_TYPE, HB_BD_TYPE, HB_STREAM_TYPE, HB_FF_STREAM_TYPE } type;
-    uint32_t      reg_desc;
-    char          path[1024];
-    char          name[1024];
-    int           index;
-    int           playlist;
-    int           vts;
-    int           ttn;
-    int           cell_start;
-    int           cell_end;
-    uint64_t      block_start;
-    uint64_t      block_end;
-    uint64_t      block_count;
-    int           angle_count;
-    void        * opaque_priv;
+    uint32_t        reg_desc;
+    char            path[1024];
+    char            name[1024];
+    int             index;
+    int             playlist;
+    int             vts;
+    int             ttn;
+    int             cell_start;
+    int             cell_end;
+    uint64_t        block_start;
+    uint64_t        block_end;
+    uint64_t        block_count;
+    int             angle_count;
+    void          * opaque_priv;
 
     /* Visual-friendly duration */
-    int           hours;
-    int           minutes;
-    int           seconds;
+    int             hours;
+    int             minutes;
+    int             seconds;
 
     /* Exact duration (in 1/90000s) */
-    uint64_t      duration;
+    uint64_t        duration;
 
-    int           preview_count;
-    int           has_resolution_change;
+    int             preview_count;
+    int             has_resolution_change;
     enum { HB_ROTATION_0, HB_ROTATION_90, HB_ROTATION_180, HB_ROTATION_270 } rotation;
-    hb_geometry_t geometry;
-    hb_rational_t dar;             // aspect ratio for the title's video
-    hb_rational_t container_dar;   // aspect ratio from container (0 if none)
-    int           color_prim;
-    int           color_transfer;
-    int           color_matrix;
-    hb_rational_t vrate;
-    int           crop[4];
+    hb_geometry_t   geometry;
+    hb_rational_t   dar;             // aspect ratio for the title's video
+    hb_rational_t   container_dar;   // aspect ratio from container (0 if none)
+    int             color_prim;
+    int             color_transfer;
+    int             color_matrix;
+    hb_rational_t   vrate;
+    int             crop[4];
     enum {HB_DVD_DEMUXER, HB_TS_DEMUXER, HB_PS_DEMUXER, HB_NULL_DEMUXER} demuxer;
-    int           detected_interlacing;
-    int           pcr_pid;                /* PCR PID for TS streams */
-    int           video_id;               /* demuxer stream id for video */
-    int           video_codec;            /* worker object id of video codec */
-    uint32_t      video_stream_type;      /* stream type from source stream */
-    int           video_codec_param;      /* codec specific config */
-    char        * video_codec_name;
-    int           video_bitrate;
-    char        * container_name;
-    int           data_rate;
+    int             detected_interlacing;
+    int             pcr_pid;                /* PCR PID for TS streams */
+    int             video_id;               /* demuxer stream id for video */
+    int             video_codec;            /* worker object id of video codec */
+    uint32_t        video_stream_type;      /* stream type from source stream */
+    int             video_codec_param;      /* codec specific config */
+    char          * video_codec_name;
+    int             video_bitrate;
+    hb_rational_t   video_timebase;
+    char          * container_name;
+    int             data_rate;
 
     // additional supported video decoders (e.g. HW-accelerated implementations)
     int           video_decode_support;
index db677db1c83243d5e3faab6c3a5bcc3ba0ef617b..8daca6604b2930a845ecfdb9ce1279b2aaa60687 100644 (file)
@@ -310,6 +310,9 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
         hb_log("decavcodecaInit: avcodec_open failed");
         return 1;
     }
+    pv->context->pkt_timebase.num = pv->audio->config.in.timebase.num;
+    pv->context->pkt_timebase.den = pv->audio->config.in.timebase.den;
+
     // avcodec_open populates av_opts with the things it didn't recognize.
     AVDictionaryEntry *t = NULL;
     while ((t = av_dict_get(av_opts, "", t, AV_DICT_IGNORE_SUFFIX)) != NULL)
@@ -657,6 +660,9 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
         av_dict_free( &av_opts );
         return -1;
     }
+    context->pkt_timebase.num = audio->config.in.timebase.num;
+    context->pkt_timebase.den = audio->config.in.timebase.den;
+
     av_dict_free( &av_opts );
     unsigned char *parse_buffer;
     int parse_pos, parse_buffer_size;
@@ -1668,6 +1674,8 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
             hb_log( "decavcodecvInit: avcodec_open failed" );
             return 1;
         }
+        pv->context->pkt_timebase.num = pv->title->video_timebase.num;
+        pv->context->pkt_timebase.den = pv->title->video_timebase.den;
         av_dict_free( &av_opts );
 
         pv->video_codec_opened = 1;
@@ -1843,6 +1851,8 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
             hb_buffer_close( &in );
             return HB_WORK_OK;
         }
+        pv->context->pkt_timebase.num = pv->title->video_timebase.num;
+        pv->context->pkt_timebase.den = pv->title->video_timebase.den;
         av_dict_free( &av_opts );
         pv->video_codec_opened = 1;
     }
index 8e6532532f7867a98368a518066ae1587550f58b..716231d3968b49cb5aa632d2a80b2d2da9a57d92 100644 (file)
@@ -50,11 +50,13 @@ static int decsubInit( hb_work_object_t * w, hb_job_t * job )
 
     hb_buffer_list_clear(&pv->list);
     hb_buffer_list_clear(&pv->list_pass);
-    pv->discard_subtitle = 1;
-    pv->seen_forced_sub  = 0;
-    pv->last_pts         = AV_NOPTS_VALUE;
-    pv->context          = context;
-    pv->job              = job;
+    pv->discard_subtitle      = 1;
+    pv->seen_forced_sub       = 0;
+    pv->last_pts              = AV_NOPTS_VALUE;
+    pv->context               = context;
+    context->pkt_timebase.num = w->subtitle->timebase.num;
+    context->pkt_timebase.den = w->subtitle->timebase.den;
+    pv->job                   = job;
 
     // Set decoder opts...
     AVDictionary * av_opts = NULL;
@@ -195,15 +197,7 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
     av_init_packet( &avp );
     avp.data = in->data;
     avp.size = in->size;
-    // libav wants pkt pts in AV_TIME_BASE units
-    if (in->s.start != AV_NOPTS_VALUE)
-    {
-        avp.pts = av_rescale(in->s.start, AV_TIME_BASE, 90000);
-    }
-    else
-    {
-        avp.pts = AV_NOPTS_VALUE;
-    }
+    avp.pts  = in->s.start;
 
     int has_subtitle = 0;
 
index dee82eb3e868e1b344be87396d5c14062be99e43..3fd567c04900f02ff8f3a64925ed40447fab584e 100644 (file)
@@ -204,6 +204,8 @@ static void add_subtitle( hb_list_t * list_subtitle, int position,
     subtitle->stream_type    = 0xbd;
     subtitle->substream_type = 0x20 + position;
     subtitle->codec          = WORK_DECVOBSUB;
+    subtitle->timebase.num   = 1;
+    subtitle->timebase.den   = 90000;
 
     memcpy(subtitle->palette, palette, 16 * sizeof(uint32_t));
     subtitle->palette_set = 1;
@@ -572,7 +574,10 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur
                audio->config.lang.simple, codec_name,
                audio->config.lang.iso639_2, lang_extension);
 
-        audio->config.in.track = i;
+        audio->config.in.track        = i;
+        audio->config.in.timebase.num = 1;
+        audio->config.in.timebase.den = 90000;
+
         hb_list_add( title->list_audio, audio );
     }
 
index b0e7239c8dc91bddfe9cc94080bd87d78c759b71..adbbb34e7b6b912cbfe64b99b9f9c50073cfb4d8 100644 (file)
@@ -348,6 +348,8 @@ static void add_subtitle( hb_list_t * list_subtitle, int position,
     subtitle->stream_type    = 0xbd;
     subtitle->substream_type = 0x20 + position;
     subtitle->codec          = WORK_DECVOBSUB;
+    subtitle->timebase.num   = 1;
+    subtitle->timebase.den   = 90000;
 
     memcpy(subtitle->palette, palette, 16 * sizeof(uint32_t));
     subtitle->palette_set = 1;
@@ -752,7 +754,10 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura
                audio->config.lang.simple, codec_name,
                audio->config.lang.iso639_2, lang_extension);
 
-        audio->config.in.track = i;
+        audio->config.in.track        = i;
+        audio->config.in.timebase.num = 1;
+        audio->config.in.timebase.den = 90000;
+
         hb_list_add( title->list_audio, audio );
     }
 
index b1f67cf1608eb268758df9c621be0b11e893cb58..df7ddc1b620dd97f0a780700b2e35c2edb503432 100644 (file)
@@ -1078,6 +1078,8 @@ hb_title_t * hb_stream_title_scan(hb_stream_t *stream, hb_title_t * title)
     title->video_id = get_id( &stream->pes.list[idx] );
     title->video_codec = stream->pes.list[idx].codec;
     title->video_codec_param = stream->pes.list[idx].codec_param;
+    title->video_timebase.num = 1;
+    title->video_timebase.den = 90000;
 
     if (stream->hb_stream_type == transport)
     {
@@ -1967,8 +1969,10 @@ static void pes_add_subtitle_to_title(
     hb_subtitle_t *subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
     iso639_lang_t * lang;
 
-    subtitle->track = idx;
-    subtitle->id = id;
+    subtitle->track        = idx;
+    subtitle->id           = id;
+    subtitle->timebase.num = 1;
+    subtitle->timebase.den = 90000;
 
     switch ( pes->codec )
     {
@@ -2087,6 +2091,8 @@ static void pes_add_audio_to_title(
 
     audio->config.in.codec = pes->codec;
     audio->config.in.codec_param = pes->codec_param;
+    audio->config.in.timebase.num = 1;
+    audio->config.in.timebase.den = 90000;
 
     set_audio_description(audio, lang_for_code(pes->lang_code));
 
@@ -5098,6 +5104,12 @@ static void add_ffmpeg_audio(hb_title_t *title, hb_stream_t *stream, int id)
     audio->config.in.bitrate       = 0;
     audio->config.in.encoder_delay = codecpar->initial_padding;
 
+    // If we ever improve our pipeline to allow other time bases...
+    // audio->config.in.timebase.num  = st->time_base.num;
+    // audio->config.in.timebase.den  = st->time_base.den;
+    audio->config.in.timebase.num  = 1;
+    audio->config.in.timebase.den  = 90000;
+
     // set the input codec and extradata for Passthru
     switch (codecpar->codec_id)
     {
@@ -5302,6 +5314,11 @@ static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id
     hb_subtitle_t *subtitle = calloc( 1, sizeof(*subtitle) );
 
     subtitle->id = id;
+    // If we ever improve our pipeline to allow other time bases...
+    // subtitle->timebase.num = st->time_base.num;
+    // subtitle->timebase.den = st->time_base.den;
+    subtitle->timebase.num = 1;
+    subtitle->timebase.den = 90000;
 
     switch ( codecpar->codec_id )
     {
@@ -5528,12 +5545,14 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title )
     int i;
     for (i = 0; i < ic->nb_streams; ++i )
     {
-        if ( ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
-           !(ic->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) &&
-             avcodec_find_decoder( ic->streams[i]->codecpar->codec_id ) &&
+        AVStream * st = ic->streams[i];
+
+        if ( st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+           !(st->disposition & AV_DISPOSITION_ATTACHED_PIC) &&
+             avcodec_find_decoder( st->codecpar->codec_id ) &&
              title->video_codec == 0 )
         {
-            AVCodecParameters *codecpar = ic->streams[i]->codecpar;
+            AVCodecParameters *codecpar = st->codecpar;
             if ( codecpar->format != AV_PIX_FMT_YUV420P &&
                  !sws_isSupportedInput( codecpar->format ) )
             {
@@ -5542,17 +5561,17 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title )
             }
             title->video_id = i;
             stream->ffmpeg_video_id = i;
-            if ( ic->streams[i]->sample_aspect_ratio.num &&
-                 ic->streams[i]->sample_aspect_ratio.den )
+            if ( st->sample_aspect_ratio.num &&
+                 st->sample_aspect_ratio.den )
             {
-                title->geometry.par.num = ic->streams[i]->sample_aspect_ratio.num;
-                title->geometry.par.den = ic->streams[i]->sample_aspect_ratio.den;
+                title->geometry.par.num = st->sample_aspect_ratio.num;
+                title->geometry.par.den = st->sample_aspect_ratio.den;
             }
 
             int j;
-            for (j = 0; j < ic->streams[i]->nb_side_data; j++)
+            for (j = 0; j < st->nb_side_data; j++)
             {
-                AVPacketSideData sd = ic->streams[i]->side_data[j];
+                AVPacketSideData sd = st->side_data[j];
                 switch (sd.type)
                 {
                     case AV_PKT_DATA_DISPLAYMATRIX:
@@ -5582,23 +5601,28 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title )
                 }
             }
 
-            title->video_codec = WORK_DECAVCODECV;
-            title->video_codec_param = codecpar->codec_id;
+            title->video_codec        = WORK_DECAVCODECV;
+            title->video_codec_param  = codecpar->codec_id;
+            // If we ever improve our pipeline to allow other time bases...
+            // title->video_timebase.num = st->time_base.num;
+            // title->video_timebase.den = st->time_base.den;
+            title->video_timebase.num = 1;
+            title->video_timebase.den = 90000;
             if (ic->iformat->raw_codec_id != AV_CODEC_ID_NONE)
             {
                 title->flags |= HBTF_RAW_VIDEO;
             }
         }
-        else if (ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
-                 avcodec_find_decoder( ic->streams[i]->codecpar->codec_id))
+        else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
+                 avcodec_find_decoder( st->codecpar->codec_id))
         {
             add_ffmpeg_audio( title, stream, i );
         }
-        else if (ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
+        else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
         {
             add_ffmpeg_subtitle( title, stream, i );
         }
-        else if (ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT)
+        else if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT)
         {
             add_ffmpeg_attachment( title, stream, i );
         }