[FFmpeg-devel] [PATCH] Add SUP/PGS subtitle demuxer

wm4 nfxjfg at googlemail.com
Sat Aug 30 15:38:45 CEST 2014


---
Reverse engineered by looking at Petri Hintukainen's muxer patch, and
also the mkvmerge sources. Tested with files extracted by mkvextract
only (does someone have better samples?). No idea if a parser would be
required for correct remuxing, but at least for decoding with lavc it
probably isn't be needed, going by how pgssubdec.c is structured.

At least files produced by mkvextract have the DTS always set to 0.
I don't know whether 0 means "invalid value", or whether DTS should
just always be discarded. (Actually setting the 0 DTS breaks seeking.)
---
 libavformat/Makefile     |  1 +
 libavformat/allformats.c |  1 +
 libavformat/supdec.c     | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
 create mode 100644 libavformat/supdec.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 3d124fb..b4965fe 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -405,6 +405,7 @@ OBJS-$(CONFIG_SRT_MUXER)                 += srtenc.o
 OBJS-$(CONFIG_STR_DEMUXER)               += psxstr.o
 OBJS-$(CONFIG_SUBVIEWER1_DEMUXER)        += subviewer1dec.o subtitles.o
 OBJS-$(CONFIG_SUBVIEWER_DEMUXER)         += subviewerdec.o subtitles.o
+OBJS-$(CONFIG_SUP_DEMUXER)               += supdec.o
 OBJS-$(CONFIG_SWF_DEMUXER)               += swfdec.o swf.o
 OBJS-$(CONFIG_SWF_MUXER)                 += swfenc.o swf.o
 OBJS-$(CONFIG_TAK_DEMUXER)               += takdec.o apetag.o img2.o rawdec.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 8f70c4b..e6c0e5f 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -280,6 +280,7 @@ void av_register_all(void)
     REGISTER_DEMUXER (STR,              str);
     REGISTER_DEMUXER (SUBVIEWER1,       subviewer1);
     REGISTER_DEMUXER (SUBVIEWER,        subviewer);
+    REGISTER_DEMUXER (SUP,              sup);
     REGISTER_MUXDEMUX(SWF,              swf);
     REGISTER_DEMUXER (TAK,              tak);
     REGISTER_MUXER   (TEE,              tee);
diff --git a/libavformat/supdec.c b/libavformat/supdec.c
new file mode 100644
index 0000000..1938b06
--- /dev/null
+++ b/libavformat/supdec.c
@@ -0,0 +1,92 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+#define SUP_PGS_MAGIC 0x5047 /* "PG", big endian */
+
+static int sup_read_header(AVFormatContext *s)
+{
+    AVStream *st = avformat_new_stream(s, NULL);
+    if (!st)
+        return AVERROR(ENOMEM);
+    st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+    st->codec->codec_id = AV_CODEC_ID_HDMV_PGS_SUBTITLE;
+    avpriv_set_pts_info(st, 32, 1, 90000);
+
+    return 0;
+}
+
+static int sup_read_packet(struct AVFormatContext *s, AVPacket *pkt)
+{
+    char tmp[3];
+    size_t len;
+    int64_t pts, pos;
+    int ret;
+
+    pos = avio_tell(s->pb);
+
+    if (avio_rb16(s->pb) != SUP_PGS_MAGIC)
+        return avio_feof(s->pb) ? AVERROR_EOF : AVERROR_INVALIDDATA;
+
+    pts = avio_rb32(s->pb);
+    avio_rb32(s->pb); /* discard DTS (usually 0, and useless) */
+
+    // The packet-size is stored as part of the packet.
+    if ((ret = avio_read(s->pb, tmp, 3)) < 0)
+        return ret;
+
+    len = AV_RB16(tmp + 1);
+
+    if ((ret = av_new_packet(pkt, len + 3)) < 0)
+        return ret;
+
+    memcpy(pkt->data, tmp, 3);
+
+    if ((ret = avio_read(s->pb, pkt->data + 3, len)) < 0) {
+        av_free_packet(pkt);
+        return ret;
+    }
+
+    pkt->stream_index = 0;
+    pkt->flags |= AV_PKT_FLAG_KEY;
+    pkt->pos = pos;
+    pkt->pts = pts;
+
+    return 0;
+}
+
+static int sup_probe(AVProbeData *p)
+{
+    if (p->buf_size < 2 || memcmp(p->buf, "PG", 2))
+        return 0;
+    return AVPROBE_SCORE_EXTENSION;
+}
+
+AVInputFormat ff_sup_demuxer = {
+    .name           = "sup",
+    .long_name      = NULL_IF_CONFIG_SMALL("raw HDMV Presentation Graphic Stream subtitles"),
+    .extensions     = "sup",
+    .mime_type      = "application/x-pgs",
+    .read_probe     = sup_probe,
+    .read_header    = sup_read_header,
+    .read_packet    = sup_read_packet,
+    .flags          = AVFMT_GENERIC_INDEX,
+};
-- 
2.1.0.rc1



More information about the ffmpeg-devel mailing list