mirror of https://git.ffmpeg.org/ffmpeg.git
ffmpeg: add an option to fix subtitles durations.
With this option, transcoding DVB subtitles becomes possible.
This commit is contained in:
parent
1bfa349a8d
commit
0cad101ea1
|
@ -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
|
||||
|
|
23
ffmpeg.c
23
ffmpeg.c
|
@ -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);
|
||||
|
|
10
ffmpeg.h
10
ffmpeg.h
|
@ -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" },
|
||||
|
|
Loading…
Reference in New Issue