From c9e41ac2fbf6e518372be3057e8e794745190496 Mon Sep 17 00:00:00 2001
From: Shin-ichi Toyama <shin1@wmail.plala.or.jp>
Date: Mon, 10 Nov 2014 22:13:35 +0900
Subject: [PATCH] Enables parsing DVD color palette directly from IFO file via
 -palette option using syntax `-palette ifo:filename'

---
 libavcodec/dvdsubdec.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c
index bb28d9e..b09eb61 100644
--- a/libavcodec/dvdsubdec.c
+++ b/libavcodec/dvdsubdec.c
@@ -28,6 +28,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/avstring.h"
+#include "libavutil/bswap.h"
 
 typedef struct DVDSubContext
 {
@@ -574,13 +575,59 @@ static int dvdsub_decode(AVCodecContext *avctx,
 static void parse_palette(DVDSubContext *ctx, char *p)
 {
     int i;
+    char ifo[_MAX_PATH];
+    FILE *in;
+    uint32_t sp_pgci, pgci, off_pgc, pgc;
+    uint8_t c, Y, Cr, Cb, R, G, B;
 
     ctx->has_palette = 1;
+
+  if (strncmp(p, "ifo:", 4) == 0) {
+    strncpy (ifo, p+4, _MAX_PATH);
+    if((in=fopen(ifo, "r"))==NULL){
+      fprintf(stderr, "[dvdsubdec.c] Warning: Failed to open IFO file\n");
+      ctx->has_palette = 0;
+      return;
+    }
+    /* Obtain Start Point of PGCI */
+    fseek(in, 0xCC, SEEK_SET);
+    fread(&sp_pgci, 4, 1, in);
+    sp_pgci=av_be2ne32(sp_pgci);
+    
+    /* Obtain Offset to VTS_PGCI */
+    pgci = sp_pgci * 2048;
+    fseek(in, pgci + 0x0C, SEEK_SET);
+    fread(&off_pgc, 4, 1, in);
+    off_pgc=av_be2ne32(off_pgc);
+    
+    /* Obtain Color pallet Start Point */
+    pgc = pgci + off_pgc;
+    fseek(in, pgc + 0xA4, SEEK_SET);
+    
+    for(i=0;i<16;i++)
+    {
+      fread(&c,  1, 1, in);
+      fread(&Y,  1, 1, in);
+      fread(&Cr, 1, 1, in);
+      fread(&Cb, 1, 1, in);
+
+      /* YCrCb - RGB conversion */
+      Cr = Cr - 128;
+      Cb = Cb - 128;
+      R = Y + Cr + (Cr>>2) + (Cr>>3) + (Cr>>5);
+      G = Y - ((Cb>>2) + (Cb>>4) + (Cb>>5)) - ((Cr>>1) + (Cr>>3) + (Cr>>4) + (Cr>>5));
+      B = Y + Cb + (Cb>>1) + (Cb>>2) + (Cb>>6);
+
+      ctx->palette[i] = (R<<16) + (G<<8) + B;
+    }
+    fclose(in);
+  } else {
     for(i=0;i<16;i++) {
         ctx->palette[i] = strtoul(p, &p, 16);
         while(*p == ',' || av_isspace(*p))
             p++;
     }
+  }
 }
 
 static int dvdsub_parse_extradata(AVCodecContext *avctx)
-- 
2.1.1

