...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.
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 );
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;
}
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;
}
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)
PRIVATE int encoder_delay; /* Encoder delay in samples.
* These samples should be dropped
* when decoding */
+ PRIVATE hb_rational_t timebase;
} in;
struct
#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
};
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;
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)
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;
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;
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;
}
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;
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;
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;
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 );
}
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;
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 );
}
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)
{
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 )
{
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));
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)
{
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 )
{
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 ) )
{
}
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:
}
}
- 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 );
}