ffmpeg: add an option to fix subtitles durations.

With this option, transcoding DVB subtitles becomes possible.
This commit is contained in:
Nicolas George 2012-08-09 11:44:17 +02:00
parent 1bfa349a8d
commit 0cad101ea1
4 changed files with 53 additions and 1 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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" },