Commit 0cad101e authored by Nicolas George's avatar Nicolas George

ffmpeg: add an option to fix subtitles durations.

With this option, transcoding DVB subtitles becomes possible.
parent 1bfa349a
......@@ -620,6 +620,25 @@ Disable subtitle recording.
Deprecated, see -bsf
@end table
@section Advanced Subtitle options:
@table @option
@item -fix_sub_duration
Fix subtitles durations. For each subtitle, wait for the next packet in the
same stream and adjust the duration of the first to avoid overlap. This is
necessary with some subtitles codecs, especially DVB subtitles, because the
duration in the original packet is only a rough estimate and the end is
actually marked by an empty subtitle frame. Failing to use this option when
necessary can result in exaggerated durations or muxing failures due to
non-monotonic timestamps.
Note that this option will delay the output of all data until the next
subtitle packet is decoded: it may increase memory consumption and latency a
lot.
@end table
@section Audio/Video grab options
@table @option
......
......@@ -1649,6 +1649,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
{
AVSubtitle subtitle;
int64_t pts = pkt->pts;
int i, ret = avcodec_decode_subtitle2(ist->st->codec,
&subtitle, got_output, pkt);
if (ret < 0 || !*got_output) {
......@@ -1657,6 +1658,26 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
return ret;
}
if (ist->fix_sub_duration) {
if (ist->prev_sub.got_output) {
int end = av_rescale_q(pts - ist->prev_sub.pts, ist->st->time_base,
(AVRational){ 1, 1000 });
if (end < ist->prev_sub.subtitle.end_display_time) {
av_log(ist->st->codec, AV_LOG_DEBUG,
"Subtitle duration reduced from %d to %d\n",
ist->prev_sub.subtitle.end_display_time, end);
ist->prev_sub.subtitle.end_display_time = end;
}
}
FFSWAP(int64_t, pts, ist->prev_sub.pts);
FFSWAP(int, *got_output, ist->prev_sub.got_output);
FFSWAP(int, ret, ist->prev_sub.ret);
FFSWAP(AVSubtitle, subtitle, ist->prev_sub.subtitle);
}
if (!*got_output || !subtitle.num_rects)
return ret;
rate_emu_sleep(ist);
sub2video_update(ist, &subtitle, pkt->pts);
......@@ -1667,7 +1688,7 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle, pkt->pts);
do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle, pts);
}
avsubtitle_free(&subtitle);
......
......@@ -158,6 +158,8 @@ typedef struct OptionsContext {
int nb_copy_initial_nonkeyframes;
SpecifierOpt *filters;
int nb_filters;
SpecifierOpt *fix_sub_duration;
int nb_fix_sub_duration;
} OptionsContext;
typedef struct InputFilter {
......@@ -223,6 +225,14 @@ typedef struct InputStream {
int resample_channels;
uint64_t resample_channel_layout;
int fix_sub_duration;
struct { /* previous decoded subtitle and related variables */
int64_t pts;
int got_output;
int ret;
AVSubtitle subtitle;
} prev_sub;
struct sub2video {
int64_t last_pts;
AVFilterBufferRef *ref;
......
......@@ -593,6 +593,7 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
case AVMEDIA_TYPE_SUBTITLE:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
break;
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
......@@ -2276,6 +2277,7 @@ const OptionDef options[] = {
{ "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" },
{ "scodec", HAS_ARG | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" },
{ "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_old2new}, "force subtitle tag/fourcc", "fourcc/tag" },
{ "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC, {.off = OFFSET(fix_sub_duration)}, "fix subtitles duration" },
/* grab options */
{ "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "deprecated, use -channel", "channel" },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment