summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-06-24 02:06:55 +0200
committerwm4 <wm4@nowhere>2013-06-25 00:11:57 +0200
commit709389ce653d5ab11abf8de067cfb5932e642898 (patch)
treee64d81075ed809c03a26ec321d096c8b2ef56099 /sub
parent0b2e073853beff170e8a9f8a5898e636cf636cf0 (diff)
downloadmpv-709389ce653d5ab11abf8de067cfb5932e642898.tar.bz2
mpv-709389ce653d5ab11abf8de067cfb5932e642898.tar.xz
sub: add hack for Libav SRT demuxer
Before this commit, SRT demuxing and display actually happened to work on Libav. But it was using the libavcodec srt converter (which is essentially unmaintained in Libav), and timing postprocessing didn't work. For some background explanations see sd_lavf_srt.c.
Diffstat (limited to 'sub')
-rw-r--r--sub/dec_sub.c8
-rw-r--r--sub/sd_lavf_srt.c94
2 files changed, 101 insertions, 1 deletions
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index 01ba109ad0..56ed2a3d6f 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -36,6 +36,7 @@ extern const struct sd_functions sd_spu;
extern const struct sd_functions sd_movtext;
extern const struct sd_functions sd_srt;
extern const struct sd_functions sd_microdvd;
+extern const struct sd_functions sd_lavf_srt;
extern const struct sd_functions sd_lavc_conv;
static const struct sd_functions *sd_list[] = {
@@ -47,6 +48,7 @@ static const struct sd_functions *sd_list[] = {
&sd_movtext,
&sd_srt,
&sd_microdvd,
+ &sd_lavf_srt,
&sd_lavc_conv,
NULL
};
@@ -134,7 +136,7 @@ static void print_chain(struct dec_sub *sub)
mp_msg(MSGT_OSD, MSGL_V, "Subtitle filter chain: ");
for (int n = 0; n < sub->num_sd; n++) {
struct sd *sd = sub->sd[n];
- mp_msg(MSGT_OSD, MSGL_V, "%s%s (%s)", n > 0 ? " -> " : "",
+ mp_msg(MSGT_OSD, MSGL_V, "%s%s (%s)", n > 0 ? " -> " : "",
sd->driver->name, sd->codec);
}
mp_msg(MSGT_OSD, MSGL_V, "\n");
@@ -371,6 +373,10 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
if (sub->sd[0]->driver == &sd_movtext)
preprocess = 1;
+ // Broken Libav libavformat srt packet format (fix timestamps first).
+ if (sub->sd[0]->driver == &sd_lavf_srt)
+ preprocess = 1;
+
for (;;) {
ds_get_next_pts(sh->ds);
struct demux_packet *pkt = ds_get_packet_sub(sh->ds);
diff --git a/sub/sd_lavf_srt.c b/sub/sd_lavf_srt.c
new file mode 100644
index 0000000000..0d34b489c7
--- /dev/null
+++ b/sub/sd_lavf_srt.c
@@ -0,0 +1,94 @@
+/*
+ * This file is part of mpv.
+ *
+ * SRT timestamp parsing code lifted from FFmpeg srtdec.c (LGPL).
+ *
+ * mpv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "core/bstr.h"
+#include "sd.h"
+
+/*
+ * Background:
+ *
+ * Libav's .srt demuxer outputs packets that contain parts of the subtitle
+ * event header. Also, the packet duration is not set (they don't parse it
+ * on the demuxer side). As a result, the srt demuxer is useless.
+ *
+ * However, we can fix it by parsing the header, which spares us from writing
+ * a full SRT demuxer.
+ *
+ * Newer versions of FFmpeg do not have this problem. To avoid compatibility
+ * problems, they changed the codec name from "srt" to "subrip".
+ *
+ * Summary: this is a hack for broken SRT stuff in Libav.
+ *
+ */
+
+static bool supports_format(const char *format)
+{
+ return format && strcmp(format, "srt") == 0;
+}
+
+static int init(struct sd *sd)
+{
+ sd->output_codec = "subrip";
+ return 0;
+}
+
+static bool parse_pts(bstr header, double *duration)
+{
+ char buf[200];
+ snprintf(buf, sizeof(buf), "%.*s", BSTR_P(header));
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+ if (sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d",
+ &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2) >= 8)
+ {
+ int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
+ int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
+ *duration = (end - start) / 1000.0;
+ return true;
+ }
+ return false;
+}
+
+static void decode(struct sd *sd, struct demux_packet *packet)
+{
+ bstr data = {packet->buffer, packet->len};
+ // Remove the broken header. It's usually on the second or first line.
+ bstr left = data;
+ while (left.len) {
+ bstr line = bstr_getline(left, &left);
+ if (parse_pts(line, &packet->duration)) {
+ data = left;
+ break;
+ }
+ }
+ sd_conv_add_packet(sd, data.start, data.len, packet->pts, packet->duration);
+}
+
+const struct sd_functions sd_lavf_srt = {
+ .name = "lavf_srt",
+ .supports_format = supports_format,
+ .init = init,
+ .decode = decode,
+ .get_converted = sd_conv_def_get_converted,
+ .reset = sd_conv_def_reset,
+};