summaryrefslogtreecommitdiff
authorNicolas George <nicolas.george@normalesup.org>2012-08-09 09:44:17 (GMT)
committer Nicolas George <nicolas.george@normalesup.org>2012-08-14 09:17:45 (GMT)
commit0cad101ea10d01cb9f4780ebd915fb16dad19997 (patch)
tree7a4f655f210ebbded5acaa703163d4b108bf804c
parent1bfa349a8d706424b5f2f379c439c11be21f4316 (diff)
downloadffmpeg-0cad101ea10d01cb9f4780ebd915fb16dad19997.zip
ffmpeg-0cad101ea10d01cb9f4780ebd915fb16dad19997.tar.gz
ffmpeg-0cad101ea10d01cb9f4780ebd915fb16dad19997.tar.bz2
ffmpeg: add an option to fix subtitles durations.
With this option, transcoding DVB subtitles becomes possible.
Diffstat
-rw-r--r--doc/ffmpeg.texi19
-rw-r--r--ffmpeg.c23
-rw-r--r--ffmpeg.h10
-rw-r--r--ffmpeg_opt.c2
4 files changed, 53 insertions, 1 deletions
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 2908ad8..ab7697a 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -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
diff --git a/ffmpeg.c b/ffmpeg.c
index 411cad1..5aeaba2 100644
--- a/ffmpeg.c
+++ b/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);
diff --git a/ffmpeg.h b/ffmpeg.h
index 9b26103..4539ad9 100644
--- a/ffmpeg.h
+++ b/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;
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 99670bb..ac72b45 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -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" },