From ed95a453997bee9557f6af852c9b81f9f8c426f8 Mon Sep 17 00:00:00 2001
From: Shin-ichi Toyama <shin1@wmail.plala.or.jp>
Date: Sat, 15 Nov 2014 02:15:57 +0900
Subject: [PATCH] New option for obtaining global palette from .IFO file

---
 doc/decoders.texi      |  3 +++
 libavcodec/dvdsubdec.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/version.h   |  2 +-
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/doc/decoders.texi b/doc/decoders.texi
index ae20cea..d01c4d1 100644
--- a/doc/decoders.texi
+++ b/doc/decoders.texi
@@ -191,6 +191,9 @@ numbers (without 0x prefix) separated by comas, for example @code{0d00ee,
 ee450d, 101010, eaeaea, 0ce60b, ec14ed, ebff0b, 0d617a, 7b7b7b, d1d1d1,
 7b2a0e, 0d950c, 0f007b, cf0dec, cfa80c, 7c127b}.
 
+@item ifo_palette
+Specify the the IFO file from which the global palette is obtained.
+
 @item forced_subs_only
 Only decode subtitle entries marked as forced. Some titles have forced
 and non-forced subtitles in the same track. Setting this flag to @code{1}
diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c
index bb28d9e..b96a5e0 100644
--- a/libavcodec/dvdsubdec.c
+++ b/libavcodec/dvdsubdec.c
@@ -28,12 +28,15 @@
 #include "libavutil/opt.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/avstring.h"
+#include "libavutil/bswap.h"
+#include "libavformat/avio.h"
 
 typedef struct DVDSubContext
 {
   AVClass *class;
   uint32_t palette[16];
   char    *palette_str;
+  char    *ifo_str;
   int      has_palette;
   uint8_t  colormap[4];
   uint8_t  alpha[256];
@@ -583,6 +586,58 @@ static void parse_palette(DVDSubContext *ctx, char *p)
     }
 }
 
+static int parse_ifo_palette(DVDSubContext *ctx, char *p)
+{
+    AVIOContext *ifo = NULL;
+    char ifostr[12];
+    uint32_t sp_pgci, pgci, off_pgc, pgc;
+    uint8_t r, g, b, yuv[65], *buf;
+    int i, y, cb, cr, r_add, g_add, b_add;
+    int ret = 0;
+    const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
+
+    ctx->has_palette = 0;
+    ret = avio_open2(&ifo, p, AVIO_FLAG_READ, NULL, NULL);
+    if (ret < 0) {
+        av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\"\n", p);
+        return ret;
+    }
+    if (avio_read(ifo, ifostr, 12) != 12 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) {
+        av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p);
+        ret = AVERROR_INVALIDDATA;
+        goto end;
+    }
+    avio_seek(ifo, 0xCC, SEEK_SET);
+    if (avio_read(ifo, (char *)&sp_pgci, 4) == 4) {
+        pgci = av_be2ne32(sp_pgci) * 2048;
+        avio_seek(ifo, pgci + 0x0C, SEEK_SET);
+        if (avio_read(ifo, (char *)&off_pgc, 4) == 4) {
+            pgc = pgci + av_be2ne32(off_pgc);
+            avio_seek(ifo, pgc + 0xA4, SEEK_SET);
+            if ((avio_read(ifo, yuv, 64)) == 64) {
+                buf = yuv;
+                for(i=0; i<16; i++) {
+                    y  = *++buf;
+                    cr = *++buf;
+                    cb = *++buf;
+                    YUV_TO_RGB1_CCIR(cb, cr);
+                    YUV_TO_RGB2_CCIR(r, g, b, y);
+                    ctx->palette[i] = (r << 16) + (g << 8) + b;
+                    buf++;
+                }
+                ctx->has_palette = 1;
+            }
+        }
+    }
+    if (ctx->has_palette == 0) {
+        av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p);
+        ret = AVERROR_INVALIDDATA;
+    }
+end:
+    avio_close(ifo);
+    return ret;
+}
+
 static int dvdsub_parse_extradata(AVCodecContext *avctx)
 {
     DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
@@ -631,6 +686,8 @@ static av_cold int dvdsub_init(AVCodecContext *avctx)
     if ((ret = dvdsub_parse_extradata(avctx)) < 0)
         return ret;
 
+    if (ctx->ifo_str)
+        parse_ifo_palette(ctx, ctx->ifo_str);
     if (ctx->palette_str)
         parse_palette(ctx, ctx->palette_str);
     if (ctx->has_palette) {
@@ -656,6 +713,7 @@ static av_cold int dvdsub_close(AVCodecContext *avctx)
 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
 static const AVOption options[] = {
     { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
+    { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
     { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD},
     { NULL }
 };
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 5d2c9a2..ce4af6c 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -30,7 +30,7 @@
 
 #define LIBAVCODEC_VERSION_MAJOR 56
 #define LIBAVCODEC_VERSION_MINOR  12
-#define LIBAVCODEC_VERSION_MICRO 100
+#define LIBAVCODEC_VERSION_MICRO 101
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
-- 
2.1.1

