[xiph-commits] r17294 - in trunk/ffmpeg2theora: . src

oggk at svn.xiph.org oggk at svn.xiph.org
Thu Jun 17 08:06:37 PDT 2010


Author: oggk
Date: 2010-06-17 08:06:37 -0700 (Thu, 17 Jun 2010)
New Revision: 17294

Modified:
   trunk/ffmpeg2theora/ffmpeg2theora.1
   trunk/ffmpeg2theora/src/ffmpeg2theora.c
   trunk/ffmpeg2theora/src/ffmpeg2theora.h
   trunk/ffmpeg2theora/src/subtitles.c
   trunk/ffmpeg2theora/src/subtitles.h
   trunk/ffmpeg2theora/src/theorautils.c
   trunk/ffmpeg2theora/src/theorautils.h
   trunk/ffmpeg2theora/subtitles.txt
Log:
SPU style subtitles (eg, those found on DVDs) are now supported as well, though not
 enabled by default; OKed by j.



Modified: trunk/ffmpeg2theora/ffmpeg2theora.1
===================================================================
--- trunk/ffmpeg2theora/ffmpeg2theora.1	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/ffmpeg2theora.1	2010-06-17 15:06:37 UTC (rev 17294)
@@ -1,5 +1,5 @@
 .\"                                      Hey, EMACS: -*- nroff -*-
-.TH FFMPEG2THEORA 1 "July 31, 2009"
+.TH FFMPEG2THEORA 1 "May 14, 2010"
 .\" Please adjust this date whenever revising the manpage.
 .\"
 .\" Some roff macros, for reference:
@@ -231,6 +231,14 @@
 Disables subtitles from input.
 Note that subtitles explicitely loaded from external files will still
 be used.
+.TP
+.B \-\-subtitle-types
+Selects which subtitle types to include from the input file.
+Allowed types are: none, all, text, spu (spu being the image based
+subtitles found on DVD).
+By default, only text based subtitles will be included.
+Note that subtitles explicitely loaded from external files will still
+be used.
 .SS Metadata options:
 .TP
 .B \-\-artist

Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.c	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.c	2010-06-17 15:06:37 UTC (rev 17294)
@@ -61,6 +61,7 @@
     NOAUDIO_FLAG,
     NOVIDEO_FLAG,
     NOSUBTITLES_FLAG,
+    SUBTITLETYPES_FLAG,
     NOMETADATA_FLAG,
     NOOSHASH_FLAG,
     NOUPSCALING_FLAG,
@@ -113,6 +114,8 @@
 #define NTSC_FULL_WIDTH 720
 #define NTSC_FULL_HEIGHT 480
 
+#define INCSUB_TEXT 1
+#define INCSUB_SPU 2
 
 oggmux_info info;
 
@@ -167,7 +170,7 @@
     if (this != NULL) {
         this->disable_audio=0;
         this->disable_video=0;
-        this->disable_subtitles=0;
+        this->included_subtitles=INCSUB_TEXT;
         this->disable_metadata=0;
         this->disable_oshash=0;
         this->no_upscaling=0;
@@ -335,7 +338,7 @@
     }
 }
 
-static int is_supported_subtitle_stream(ff2theora this, int idx)
+static const char *find_category_for_subtitle_stream (ff2theora this, int idx, int included_subtitles)
 {
   AVCodecContext *enc = this->context->streams[idx]->codec;
   if (enc->codec_type != CODEC_TYPE_SUBTITLE) return 0;
@@ -343,13 +346,26 @@
     case CODEC_ID_TEXT:
     case CODEC_ID_SSA:
     case CODEC_ID_MOV_TEXT:
-      return 1;
+      if (included_subtitles & INCSUB_TEXT)
+        return "SUB";
+      else
+        return NULL;
+    case CODEC_ID_DVD_SUBTITLE:
+      if (included_subtitles & INCSUB_SPU)
+        return "K-SPU";
+      else
+        return NULL;
     default:
-      return 0;
+      return NULL;
   }
-  return 0;
+  return NULL;
 }
 
+static int is_supported_subtitle_stream(ff2theora this, int idx, int included_subtitles)
+{
+  return find_category_for_subtitle_stream(this, idx, included_subtitles) != NULL;
+}
+
 static char *get_raw_text_from_ssa(const char *ssa)
 {
   int n,intag,inescape;
@@ -960,20 +976,22 @@
         subtitles_enabled[i] = 0;
         subtitles_opened[i] = 0;
 #ifdef HAVE_KATE
-        if (!this->disable_subtitles) {
+        if (this->included_subtitles) {
           AVStream *stream = this->context->streams[i];
           AVCodecContext *enc = stream->codec;
+          const char *category;
           if (enc->codec_type == CODEC_TYPE_SUBTITLE) {
             AVCodec *codec = avcodec_find_decoder (enc->codec_id);
             if (codec && avcodec_open (enc, codec) >= 0) {
               subtitles_opened[i] = 1;
             }
-            if (is_supported_subtitle_stream(this, i)) {
+            category = find_category_for_subtitle_stream(this, i, this->included_subtitles);
+            if (category) {
               subtitles_enabled[i] = 1;
-              add_subtitles_stream(this, i, find_language_for_subtitle_stream(stream), NULL);
+              add_subtitles_stream(this, i, find_language_for_subtitle_stream(stream), category);
             }
             else if(!info.frontend) {
-              fprintf(stderr,"Subtitle stream %d codec not supported, ignored\n", i);
+              fprintf(stderr,"Subtitle stream %d, ignored\n", i);
             }
           }
         }
@@ -990,7 +1008,7 @@
             printf("Muxing Kate stream %d from input stream %d\n",
                 i,ks->stream_index);
 #endif
-            if (!this->disable_subtitles) {
+            if (this->included_subtitles) {
               info.with_kate=1;
             }
         }
@@ -1265,6 +1283,8 @@
                     ki->gps_denominator = 1;
                 }
                 ki->granule_shift = 32;
+                ki->original_canvas_width = display_width;
+                ki->original_canvas_height = display_height;
             }
           }
         }
@@ -1536,7 +1556,7 @@
             }
 
             if (info.passno!=1)
-            if (!this->disable_subtitles && subtitles_enabled[pkt.stream_index] && is_supported_subtitle_stream(this, pkt.stream_index)) {
+            if (this->included_subtitles && subtitles_enabled[pkt.stream_index] && is_supported_subtitle_stream(this, pkt.stream_index, this->included_subtitles)) {
               AVStream *stream=this->context->streams[pkt.stream_index];
               AVCodecContext *enc = stream->codec;
               if (enc) {
@@ -1546,9 +1566,11 @@
                 float t;
                 AVSubtitle sub;
                 int got_sub=0;
+                int64_t stream_start_time;
 
                 /* work out timing */
-                t = (float)pkt.pts * stream->time_base.num / stream->time_base.den - this->start_time;
+                stream_start_time = stream->start_time == AV_NOPTS_VALUE ? 0 : stream->start_time;
+                t = (float)(pkt.pts - stream_start_time) * stream->time_base.num / stream->time_base.den - this->start_time;
                 // my test case has 0 duration, how clever of that. I assume it's that old 'ends whenever the next
                 // one starts' hack, but it means I don't know in advance what duration it has. Great!
                 float duration;
@@ -1562,13 +1584,40 @@
                 /* generic decoding */
                 if (enc->codec && avcodec_decode_subtitle2(enc,&sub,&got_sub,&pkt) >= 0) {
                   if (got_sub) {
-                    if (sub.rects[0]->ass) {
-                      extra_info_from_ssa(&pkt,&utf8,&utf8len,&allocated_utf8,&duration);
+                    for (i=0; i<sub.num_rects; i++) {
+                      const AVSubtitleRect *rect = sub.rects[i];
+                      if (!rect) continue;
+
+                      switch (rect->type) {
+                        case SUBTITLE_TEXT:
+                            if (!utf8) {
+                              if (rect->text) {
+                                utf8 = rect->text;
+                                utf8len = strlen(utf8);
+                              }
+                            }
+                            break;
+                        case SUBTITLE_ASS:
+                          /* text subtitles, only one for now */
+                          if (!utf8) {
+                            if (rect->ass) {
+                              extra_info_from_ssa(&pkt,&utf8,&utf8len,&allocated_utf8,&duration);
+                            }
+                            else if (rect->text) {
+                              utf8 = rect->text;
+                              utf8len = strlen(utf8);
+                            }
+                          }
+                          break;
+                        case SUBTITLE_BITMAP:
+                          /* image subtitles */
+                          add_image_subtitle_for_stream(this->kate_streams, this->n_kate_streams, pkt.stream_index, t, duration, rect, display_width, display_height, info.frontend);
+                          break;
+
+                        default:
+                          break;
+                      }
                     }
-                    else if (sub.rects[0]->text) {
-                      utf8 = sub.rects[0]->text;
-                      utf8len = strlen(utf8);
-                    }
                   }
                 }
                 else if (enc->codec_id == CODEC_ID_TEXT) {
@@ -1633,7 +1682,14 @@
                            be held till the right time. If we don't do that, we can insert late and
                            oggz-validate moans */
                         while (ks->subtitles_count < ks->num_subtitles && sub->t0-1.0 <= avtime+this->start_time) {
-                            oggmux_add_kate_text(&info, i, sub->t0, sub->t1, sub->text, sub->len);
+#ifdef HAVE_KATE
+                            if (sub->text) {
+                              oggmux_add_kate_text(&info, i, sub->t0, sub->t1, sub->text, sub->len);
+                            }
+                            else {
+                              oggmux_add_kate_image(&info, i, sub->t0, sub->t1, &sub->kr, &sub->kp, &sub->kb);
+                            }
+#endif
                             ks->subtitles_count++;
                             ++sub;
                         }
@@ -1648,6 +1704,7 @@
         } while (ret >= 0 && !(audio_done && video_done));
 
         if (info.passno != 1) {
+#ifdef HAVE_KATE
           for (i=0; i<this->n_kate_streams; ++i) {
             ff2theora_kate_stream *ks = this->kate_streams+i;
             if (ks->num_subtitles > 0) {
@@ -1656,8 +1713,9 @@
                 oggmux_flush (&info, video_eos + audio_eos);
             }
           }
+#endif
 
-          if (!this->disable_subtitles) {
+          if (this->included_subtitles) {
             for (i = 0; i < this->context->nb_streams; i++) {
               if (subtitles_opened[i]) {
                 AVCodecContext *enc = this->context->streams[i]->codec;
@@ -1978,6 +2036,9 @@
         "      --subtitles-category category    set subtitles category (default \"subtitles\")\n"
         "      --subtitles-ignore-non-utf8      ignores any non UTF-8 sequence in UTF-8 text\n"
         "      --nosubtitles                    disables subtitles from input\n"
+        "                                       (equivalent to --subtitles=none)\n"
+        "      --subtitle-types=[all,text,spu,none]   select what subtitle types to include from the\n"
+        "                                             input video (default text)\n"
         "\n"
 #endif
         "Metadata options:\n"
@@ -2089,6 +2150,7 @@
         {"noaudio",0,&flag,NOAUDIO_FLAG},
         {"novideo",0,&flag,NOVIDEO_FLAG},
         {"nosubtitles",0,&flag,NOSUBTITLES_FLAG},
+        {"subtitle-types",required_argument,&flag,SUBTITLETYPES_FLAG},
         {"nometadata",0,&flag,NOMETADATA_FLAG},
         {"no-oshash",0,&flag,NOOSHASH_FLAG},
         {"no-upscaling",0,&flag,NOUPSCALING_FLAG},
@@ -2233,9 +2295,29 @@
                             flag = -1;
                             break;
                         case NOSUBTITLES_FLAG:
-                            convert->disable_subtitles = 1;
+                            convert->included_subtitles = 0;
                             flag = -1;
                             break;
+                        case SUBTITLETYPES_FLAG:
+                            if (!strcmp(optarg, "all")) {
+                              convert->included_subtitles = INCSUB_TEXT | INCSUB_SPU;
+                            }
+                            else if (!strcmp(optarg, "none")) {
+                              convert->included_subtitles = 0;
+                            }
+                            else if (!strcmp(optarg, "text")) {
+                              convert->included_subtitles = INCSUB_TEXT;
+                            }
+                            else if (!strcmp(optarg, "spu")) {
+                              convert->included_subtitles = INCSUB_SPU;
+                            }
+                            else {
+                              fprintf(stderr,
+                                 "Subtitles to include must be all, none, text, or spu.\n");
+                              exit(1);
+                            }
+                            flag = -1;
+                            break;
                         case NOMETADATA_FLAG:
                             convert->disable_metadata = 1;
                             flag = -1;
@@ -2680,13 +2762,13 @@
                         switch (enc->codec_type) {
                             case CODEC_TYPE_VIDEO: has_video = 1; break;
                             case CODEC_TYPE_AUDIO: has_audio = 1; break;
-                            case CODEC_TYPE_SUBTITLE: if (is_supported_subtitle_stream(convert, i)) has_kate = 1; break;
+                            case CODEC_TYPE_SUBTITLE: if (is_supported_subtitle_stream(convert, i, convert->included_subtitles)) has_kate = 1; break;
                             default: break;
                         }
                     }
                     has_video &= !convert->disable_video;
                     has_audio &= !convert->disable_audio;
-                    has_kate &= !convert->disable_subtitles;
+                    has_kate &= !!convert->included_subtitles;
                     has_kate |= convert->n_kate_streams>0; /* may be added via command line */
                     has_skeleton |= info.with_skeleton;
 
@@ -2755,7 +2837,7 @@
                 if (convert->disable_video) {
                     fprintf(stderr, "  [video disabled].\n");
                 }
-                if (convert->disable_subtitles) {
+                if (!convert->included_subtitles) {
                     fprintf(stderr, "  [subtitles disabled].\n");
                 }
                 if (convert->disable_metadata) {

Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.h
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.h	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.h	2010-06-17 15:06:37 UTC (rev 17294)
@@ -8,6 +8,11 @@
     size_t len;
     double t0;
     double t1;
+#ifdef HAVE_KATE
+    kate_region kr;
+    kate_palette kp;
+    kate_bitmap kb;
+#endif
 } ff2theora_subtitle;
 
 typedef struct ff2theora_kate_stream{
@@ -46,7 +51,7 @@
     int audio_bitrate;
     int preset;
 
-    int disable_subtitles;
+    int included_subtitles;
     int disable_metadata;
     int disable_oshash;
 

Modified: trunk/ffmpeg2theora/src/subtitles.c
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.c	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/subtitles.c	2010-06-17 15:06:37 UTC (rev 17294)
@@ -530,6 +530,75 @@
   return 0;
 }
 
+int add_image_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const AVSubtitleRect *sr, int org_width, int org_height, FILE *frontend)
+{
+#ifdef HAVE_KATE
+  int n, c, ret;
+  ff2theora_subtitle *subtitle;
+
+  if (sr->nb_colors <= 0 || sr->nb_colors > 256) {
+    warn(frontend, NULL, 0, "Unsupported number of colors in image subtitle: %d", sr->nb_colors);
+    return -1;
+  }
+
+  for (n=0; n<nstreams; ++n) {
+    ff2theora_kate_stream *ks=streams+n;
+    if (idx == ks->stream_index) {
+      ks->subtitles = (ff2theora_subtitle*)realloc(ks->subtitles, (ks->num_subtitles+1)*sizeof(ff2theora_subtitle));
+      if (!ks->subtitles) {
+        warn(frontend, NULL, 0, "Out of memory");
+        return -1;
+      }
+      subtitle = &ks->subtitles[ks->num_subtitles];
+
+      kate_region_init(&subtitle->kr);
+      subtitle->kr.metric = kate_millionths;
+      subtitle->kr.x = 1000000 * sr->x / org_width;
+      subtitle->kr.y = 1000000 * sr->y / org_height;
+      subtitle->kr.w = 1000000 * sr->w / org_width;
+      subtitle->kr.h = 1000000 * sr->h / org_height;
+
+      kate_palette_init(&subtitle->kp);
+      subtitle->kp.ncolors = sr->nb_colors;
+      subtitle->kp.colors = malloc(sizeof(kate_color) * subtitle->kp.ncolors);
+      if (!subtitle->kp.colors) {
+        warn(frontend, NULL, 0, "Out of memory");
+        return -1;
+      }
+      const uint32_t *pal = (const uint32_t*)sr->pict.data[1];
+      for (c=0; c<subtitle->kp.ncolors; ++c) {
+        subtitle->kp.colors[c].a = (pal[c]>>24)&0xff;
+        subtitle->kp.colors[c].r = (pal[c]>>16)&0xff;
+        subtitle->kp.colors[c].g = (pal[c]>>8)&0xff;
+        subtitle->kp.colors[c].b = pal[c]&0xff;
+      }
+
+      kate_bitmap_init(&subtitle->kb);
+      subtitle->kb.type = kate_bitmap_type_paletted;
+      subtitle->kb.width = sr->w;
+      subtitle->kb.height = sr->h;
+      subtitle->kb.bpp = 0;
+      while ((1<<subtitle->kb.bpp) < sr->nb_colors) ++subtitle->kb.bpp;
+      subtitle->kb.pixels = malloc(sr->w*sr->h);
+      if (!subtitle->kb.pixels) {
+        free(subtitle->kp.colors);
+        warn(frontend, NULL, 0, "Out of memory");
+        return -1;
+      }
+
+      /* Not quite sure if the AVPicture line data is supposed to always be packed */
+      memcpy(subtitle->kb.pixels,sr->pict.data[0],sr->w*sr->h);
+
+      subtitle->text = NULL;
+      subtitle->t0 = t;
+      subtitle->t1 = t+duration;
+      ks->num_subtitles++;
+    }
+  }
+#endif
+  return 0;
+}
+
 void free_subtitles(ff2theora this)
 {
     size_t i,n;

Modified: trunk/ffmpeg2theora/src/subtitles.h
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.h	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/subtitles.h	2010-06-17 15:06:37 UTC (rev 17294)
@@ -22,6 +22,7 @@
 
 extern void add_subtitles_stream(ff2theora this,int stream_index,const char *language,const char *category);
 extern int add_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const char *utf8, size_t utf8len, FILE *frontend);
+extern int add_image_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const AVSubtitleRect *sr, int org_width, int org_height, FILE *frontend);
 extern void set_subtitles_file(ff2theora this,const char *filename);
 extern void set_subtitles_language(ff2theora this,const char *language);
 extern void set_subtitles_category(ff2theora this,const char *category);

Modified: trunk/ffmpeg2theora/src/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.c	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/theorautils.c	2010-06-17 15:06:37 UTC (rev 17294)
@@ -1291,6 +1291,8 @@
     ks->last_end_time = end_time;
 }
 
+#ifdef HAVE_KATE
+
 /**
  * adds a subtitles text to the encoding sink
  * if e_o_s is 1 the end of the logical bitstream will be marked.
@@ -1302,7 +1304,6 @@
  * @param len the number of bytes in the text
  */
 void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len) {
-#ifdef HAVE_KATE
     ogg_packet op;
     oggmux_kate_stream *ks=info->kate_streams+idx;
     int ret;
@@ -1322,17 +1323,51 @@
         fprintf(stderr, "Failed to encode kate data packet (%f --> %f, [%s]): %d\n",
             t0, t1, text, ret);
     }
-#endif
 }
 
 /**
+ * adds a subtitles image to the encoding sink
+ * if e_o_s is 1 the end of the logical bitstream will be marked.
+ * @param info oggmux_info
+ * @param idx which kate stream to output to
+ * @param t0 the show time of the text
+ * @param t1 the hide time of the text
+ * @param kr the region in which to display the subtitle
+ * @param kp the palette to use for the image
+ * @param kb the image itself
+ */
+void oggmux_add_kate_image (oggmux_info *info, int idx, double t0, double t1, const kate_region *kr, const kate_palette *kp, const kate_bitmap *kb) {
+    ogg_packet op;
+    oggmux_kate_stream *ks=info->kate_streams+idx;
+    int ret;
+    ret = kate_encode_set_region(&ks->k, kr);
+    if (ret >= 0) ret = kate_encode_set_palette(&ks->k, kp);
+    if (ret >= 0) ret = kate_encode_set_bitmap(&ks->k, kb);
+    if (ret >= 0) ret = kate_ogg_encode_text(&ks->k, t0, t1, "", 0, &op);
+    if (ret>=0) {
+        if (!info->skeleton_3 && info->passno != 1) {
+            ogg_int64_t start_time = (int)(t0 * 1000.0f + 0.5f);
+            ogg_int64_t end_time = (int)(t1 * 1000.0f + 0.5f);
+            oggmux_record_kate_index(info, ks, &op, start_time, end_time);
+        }
+
+        ogg_stream_packetin (&ks->ko, &op);
+        ogg_packet_clear (&op);
+        info->k_pkg++;
+    }
+    else {
+        fprintf(stderr, "Failed to encode kate data packet (%f --> %f, image): %d\n",
+            t0, t1, ret);
+    }
+}
+
+/**
  * adds a kate end packet to the encoding sink
  * @param info oggmux_info
  * @param idx which kate stream to output to
  * @param t the time of the end packet
  */
 void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t) {
-#ifdef HAVE_KATE
     ogg_packet op;
     oggmux_kate_stream *ks=info->kate_streams+idx;
     int ret;
@@ -1350,9 +1385,10 @@
     else {
         fprintf(stderr, "Failed to encode kate end packet at %f: %d\n", t, ret);
     }
-#endif
 }
 
+#endif
+
 static double get_remaining(oggmux_info *info, double timebase) {
   double remaining = 0;
   double to_encode, time_so_far;

Modified: trunk/ffmpeg2theora/src/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.h	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/theorautils.h	2010-06-17 15:06:37 UTC (rev 17294)
@@ -165,8 +165,11 @@
 extern void oggmux_init (oggmux_info *info);
 extern void oggmux_add_video (oggmux_info *info, th_ycbcr_buffer ycbcr, int e_o_s);
 extern void oggmux_add_audio (oggmux_info *info, int16_t * readbuffer, int bytesread, int samplesread,int e_o_s);
+#ifdef HAVE_KATE
 extern void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len);
+extern void oggmux_add_kate_image (oggmux_info *info, int idx, double t0, double t1, const kate_region *kr, const kate_palette *kp, const kate_bitmap *kb);
 extern void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t);
+#endif
 extern void oggmux_flush (oggmux_info *info, int e_o_s);
 extern void oggmux_close (oggmux_info *info);
 

Modified: trunk/ffmpeg2theora/subtitles.txt
===================================================================
--- trunk/ffmpeg2theora/subtitles.txt	2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/subtitles.txt	2010-06-17 15:06:37 UTC (rev 17294)
@@ -77,8 +77,14 @@
   Subtitle streams from the input file will not be converted. Subtitles
   from any supplied --subtitles option will still be used.
 
+--subtitle-types <types>
+  By default, only text based subtitles found in the input file are
+  included in the output file. This option allows selecting which types
+  are to be included: none, all, text, or spu (spu being the type of
+  image-based subtitles found on DVDs).
 
 
+
  * Converting non-UTF-8 files to UTF-8
 
 If ffmpeg2theora wasn't build with iconv support, only UTF-8 and latin1



More information about the commits mailing list