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

j at svn.xiph.org j at svn.xiph.org
Fri Apr 24 04:46:40 PDT 2009


Author: j
Date: 2009-04-24 04:46:40 -0700 (Fri, 24 Apr 2009)
New Revision: 15952

Added:
   trunk/ffmpeg2theora/src/iso639.c
   trunk/ffmpeg2theora/src/iso639.h
Modified:
   trunk/ffmpeg2theora/ffmpeg2theora.1
   trunk/ffmpeg2theora/get_libkate.sh
   trunk/ffmpeg2theora/src/ffmpeg2theora.c
   trunk/ffmpeg2theora/src/ffmpeg2theora.h
   trunk/ffmpeg2theora/src/subtitles.c
   trunk/ffmpeg2theora/src/subtitles.h
   trunk/ffmpeg2theora/subtitles.txt
Log:
* transcode text subtitles found in the video.
  Only text (raw UTF-8 and SSA) is supported.
  SSA tags are not properly removed yet.
* update libkate to 0.3.1



Modified: trunk/ffmpeg2theora/ffmpeg2theora.1
===================================================================
--- trunk/ffmpeg2theora/ffmpeg2theora.1	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/ffmpeg2theora.1	2009-04-24 11:46:40 UTC (rev 15952)
@@ -1,5 +1,5 @@
 .\"                                      Hey, EMACS: -*- nroff -*-
-.TH FFMPEG2THEORA 1 "August 31, 2008"
+.TH FFMPEG2THEORA 1 "April 9, 2009"
 .\" Please adjust this date whenever revising the manpage.
 .\"
 .\" Some roff macros, for reference:
@@ -179,6 +179,11 @@
 an otherwise UTF-8 file. Note that, since those invalid sequences
 will be removed from the output, this option is not a substitute to
 converting a non UTF-8 file to UTF-8.
+.TP
+.B \-\-nosubtitles
+Disables subtitles from input.
+Note that subtitles explicitely loaded from external files will still
+be used.
 .SS Metadata options:
 .TP
 .B \-\-artist

Modified: trunk/ffmpeg2theora/get_libkate.sh
===================================================================
--- trunk/ffmpeg2theora/get_libkate.sh	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/get_libkate.sh	2009-04-24 11:46:40 UTC (rev 15952)
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-version=0.3.0
+version=0.3.1
 baseurl="http://libkate.googlecode.com/files/libkate-$version.tar.gz"
 
 which wget >& /dev/null

Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.c	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.c	2009-04-24 11:46:40 UTC (rev 15952)
@@ -44,6 +44,7 @@
 #endif
 
 #include "theorautils.h"
+#include "iso639.h"
 #include "subtitles.h"
 #include "ffmpeg2theora.h"
 
@@ -54,6 +55,7 @@
     SYNC_FLAG,
     NOAUDIO_FLAG,
     NOVIDEO_FLAG,
+    NOSUBTITLES_FLAG,
     NOUPSCALING_FLAG,
     CROPTOP_FLAG,
     CROPBOTTOM_FLAG,
@@ -146,6 +148,7 @@
     if (this != NULL) {
         this->disable_audio=0;
         this->disable_video=0;
+        this->disable_subtitles=0;
         this->no_upscaling=0;
         this->video_index = -1;
         this->audio_index = -1;
@@ -300,6 +303,73 @@
     }
 }
 
+static int is_supported_subtitle_stream(ff2theora this, int idx)
+{
+  AVCodecContext *enc = this->context->streams[idx]->codec;
+  if (enc->codec_type != CODEC_TYPE_SUBTITLE) return 0;
+  switch (enc->codec_id) {
+    case CODEC_ID_TEXT:
+    case CODEC_ID_SSA:
+      return 1;
+    default:
+      return 0;
+  }
+  return 0;
+}
+
+static const char *get_raw_text_from_ssa(const char *ssa)
+{
+  int n;
+  const char *ptr=ssa;
+  for (n=0;n<9;++n) {
+    ptr=strchr(ptr,',');
+    if (!ptr) return NULL;
+    ++ptr;
+  }
+  return ptr;
+}
+
+static const float get_ssa_time(const char *p)
+{
+    int hour, min, sec, hsec;
+    int r;
+
+    if(sscanf(p, "%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4)
+        return 0;
+
+    min+= 60*hour;
+    sec+= 60*min;
+    return (float)(sec*100+hsec)/100;
+}
+
+static const float get_duration_from_ssa(const char *ssa)
+{
+  int n;
+  float d = 2.0f;
+  double start, end;
+  const char *ptr=ssa;
+
+  ptr=strchr(ptr,',');
+  if (!ptr) return d;
+  ptr++;
+  start = get_ssa_time(ptr);
+  ptr=strchr(ptr,',');
+  if (!ptr) return d;
+  ptr++;
+  end = get_ssa_time(ptr);
+
+  return end-start;
+}
+
+static const char *find_language_for_subtitle_stream(const AVStream *s)
+{
+  const char *lang=find_iso639_1(s->language);
+  if (!lang) {
+    fprintf(stderr,"WARNING - unrecognized ISO 639-2 language code: %s\n",s->language);
+  }
+  return lang;
+}
+
 void ff2theora_output(ff2theora this) {
     unsigned int i;
     AVCodecContext *aenc = NULL;
@@ -314,6 +384,8 @@
     double fps = 0.0;
     AVRational vstream_fps;
     int display_width, display_height;
+    char *subtitles_enabled = (char*)alloca(this->context->nb_streams);
+    char *subtitles_opened = (char*)alloca(this->context->nb_streams);
 
     if (this->audiostream >= 0 && this->context->nb_streams > this->audiostream) {
         AVCodecContext *enc = this->context->streams[this->audiostream]->codec;
@@ -651,6 +723,54 @@
         }
     }
 
+    for (i = 0; i < this->context->nb_streams; i++) {
+      subtitles_enabled[i] = 0;
+      subtitles_opened[i] = 0;
+      if (!this->disable_subtitles) {
+        AVStream *stream = this->context->streams[i];
+        AVCodecContext *enc = stream->codec;
+        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 (enc->codec_id == CODEC_ID_TEXT || enc->codec_id == CODEC_ID_SSA || subtitles_opened[i]) {
+            subtitles_enabled[i] = 1;
+            add_subtitles_stream(this, i, find_language_for_subtitle_stream(stream), NULL);
+          }
+          else {
+            fprintf(stderr,"Subtitle stream %d codec not supported, ignored\n", i);
+          }
+        }
+      }
+    }
+
+    for (i=0; i<this->n_kate_streams; ++i) {
+        ff2theora_kate_stream *ks=this->kate_streams+i;
+        if (ks->stream_index >= 0) {
+            printf("Muxing Kate stream %d from input stream %d\n",
+                i,ks->stream_index);
+            if (!this->disable_subtitles) {
+              info.with_kate=1;
+            }
+        }
+        else if (load_subtitles(ks,this->ignore_non_utf8)>0) {
+            printf("Muxing Kate stream %d from %s as %s %s\n",
+                i,ks->filename,
+                ks->subtitles_language[0]?ks->subtitles_language:"<unknown language>",
+                ks->subtitles_category[0]?ks->subtitles_category:"SUB");
+        }
+        else {
+            if (i!=this->n_kate_streams) {
+            memmove(this->kate_streams+i,this->kate_streams+i+1,(this->n_kate_streams-i-1)*sizeof(ff2theora_kate_stream));
+            --this->n_kate_streams;
+            --i;
+          }
+        }
+    }
+
+    oggmux_setup_kate_streams(&info, this->n_kate_streams);
+
     if (this->video_index >= 0 || this->audio_index >= 0) {
         AVFrame *frame=NULL;
         AVFrame *frame_p=NULL;
@@ -769,7 +889,7 @@
             ff2theora_kate_stream *ks = this->kate_streams+i;
             kate_info *ki = &info.kate_streams[i].ki;
             kate_info_init(ki);
-            if (ks->num_subtitles > 0) {
+            if (ks->stream_index >= 0 || ks->num_subtitles > 0) {
                 if (!ks->subtitles_language[0]) {
                     fprintf(stderr, "WARNING - Subtitles language not set for input file %d\n",i);
                 }
@@ -1019,6 +1139,44 @@
                 }
             }
 
+            if (!this->disable_subtitles && subtitles_enabled[pkt.stream_index] && is_supported_subtitle_stream(this, pkt.stream_index)) {
+              AVStream *stream=this->context->streams[pkt.stream_index];
+              AVCodecContext *enc = stream->codec;
+              if (enc) {
+                if (enc->codec_id == CODEC_ID_TEXT || enc->codec_id == CODEC_ID_SSA) {
+                  const char *utf8 = pkt.data;
+                  size_t utf8len = pkt.size;
+                  float t = (float)pkt.pts * 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;
+                  if (pkt.duration <= 0) {
+                    duration = 2.0f;
+                  }
+                  else {
+                    duration  = (float)pkt.duration * stream->time_base.num / stream->time_base.den;
+                  }
+                  // SSA has control stuff in there, extract raw text
+                  if (enc->codec_id == CODEC_ID_SSA) {
+                    duration = get_duration_from_ssa(utf8);
+                    utf8 = get_raw_text_from_ssa(utf8);
+                    if (utf8) {
+                      utf8len = strlen(utf8);
+                    }
+                  }
+                  if (t < 0 && t + duration > 0) {
+                    duration += t;
+                    t = 0;
+                  }
+                  if (utf8 && t >= 0)
+                    add_subtitle_for_stream(this->kate_streams, this->n_kate_streams, pkt.stream_index, t, duration, utf8, utf8len);
+                }
+                else {
+                  /* TODO: other types */
+                }
+              }
+            }
+
             /* if we have subtitles starting before then, add it */
             if (info.with_kate) {
                 double avtime = info.audio_only ? info.audiotime :
@@ -1054,6 +1212,15 @@
             }
         }
 
+        if (!this->disable_subtitles) {
+          for (i = 0; i < this->context->nb_streams; i++) {
+            if (subtitles_opened[i]) {
+              AVCodecContext *enc = this->context->streams[i]->codec;
+              if (enc) avcodec_close(enc);
+            }
+          }
+        }
+
         if (this->video_index >= 0) {
             avcodec_close(venc);
         }
@@ -1290,6 +1457,7 @@
         "      --subtitles-language language    set subtitles language (de, en_GB, etc)\n"
         "      --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"
         "\n"
 #endif
         "Metadata options:\n"
@@ -1376,6 +1544,7 @@
         {"nosound",0,&flag,NOAUDIO_FLAG},
         {"noaudio",0,&flag,NOAUDIO_FLAG},
         {"novideo",0,&flag,NOVIDEO_FLAG},
+        {"nosubtitles",0,&flag,NOSUBTITLES_FLAG},
         {"no-upscaling",0,&flag,NOUPSCALING_FLAG},
 #ifdef HAVE_FRAMEHOOK
         {"vhook",required_argument,&flag,VHOOK_FLAG},
@@ -1469,6 +1638,10 @@
                             convert->disable_video = 1;
                             flag = -1;
                             break;
+                        case NOSUBTITLES_FLAG:
+                            convert->disable_subtitles = 1;
+                            flag = -1;
+                            break;
                         case NOUPSCALING_FLAG:
                             convert->no_upscaling = 1;
                             flag = -1;
@@ -1815,25 +1988,6 @@
         }
     }
 
-    for (n=0; n<convert->n_kate_streams; ++n) {
-        ff2theora_kate_stream *ks=convert->kate_streams+n;
-        if (load_subtitles(ks,convert->ignore_non_utf8)>0) {
-            printf("Muxing Kate stream %d from %s as %s %s\n",
-                n,ks->filename,
-                ks->subtitles_language[0]?ks->subtitles_language:"<unknown language>",
-                ks->subtitles_category[0]?ks->subtitles_category:"SUB");
-        }
-        else {
-            if (n!=convert->n_kate_streams) {
-            memmove(convert->kate_streams+n,convert->kate_streams+n+1,(convert->n_kate_streams-n-1)*sizeof(ff2theora_kate_stream));
-            --convert->n_kate_streams;
-            --n;
-          }
-        }
-    }
-
-    oggmux_setup_kate_streams(&info, convert->n_kate_streams);
-
     //detect image sequences and set framerate if provided
     if (av_guess_image2_codec(inputfile_name) != CODEC_ID_NONE || \
         (input_fmt != NULL && strcmp(input_fmt->name, "video4linux") >= 0)) {
@@ -1889,6 +2043,9 @@
                 if (convert->disable_video) {
                     fprintf(stderr, "  [video disabled].\n");
                 }
+                if (convert->disable_subtitles) {
+                    fprintf(stderr, "  [subtitles disabled].\n");
+                }
                 if (convert->sync) {
                     fprintf(stderr, "  Use A/V Sync from input container.\n");
                 }

Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.h
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.h	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.h	2009-04-24 11:46:40 UTC (rev 15952)
@@ -18,9 +18,15 @@
 } ff2theora_subtitle;
 
 typedef struct ff2theora_kate_stream{
+    /* this block valid for subtitles loaded from a file */
     const char *filename;
     size_t num_subtitles;
     ff2theora_subtitle *subtitles;
+
+    /* this block valid for subtitles coming from the source video */
+    int stream_index;
+
+    /* this block valid for all subtitle sources */
     size_t subtitles_count; /* total subtitles output so far */
     F2T_ENCODING subtitles_encoding;
     char subtitles_language[16];
@@ -45,6 +51,8 @@
     int audio_bitrate;
     int preset;
 
+    int disable_subtitles;
+
     int picture_width;
     int picture_height;
     double fps;

Added: trunk/ffmpeg2theora/src/iso639.c
===================================================================
--- trunk/ffmpeg2theora/src/iso639.c	                        (rev 0)
+++ trunk/ffmpeg2theora/src/iso639.c	2009-04-24 11:46:40 UTC (rev 15952)
@@ -0,0 +1,206 @@
+#include <stddef.h>
+#include "iso639.h"
+
+static const struct {
+  const char *iso639_1;
+  const char *iso639_2t;
+  const char *iso639_2b;
+} iso639[] = {
+  {"aa","aar",NULL},
+  {"ab","abk",NULL},
+  {"ae","ave",NULL},
+  {"af","afr",NULL},
+  {"ak","aka",NULL},
+  {"am","amh",NULL},
+  {"an","arg",NULL},
+  {"ar","ara",NULL},
+  {"as","asm",NULL},
+  {"av","ava",NULL},
+  {"ay","aym",NULL},
+  {"az","aze",NULL},
+  {"ba","bak",NULL},
+  {"be","bel",NULL},
+  {"bg","bul",NULL},
+  {"bh","bih",NULL},
+  {"bi","bis",NULL},
+  {"bm","bam",NULL},
+  {"bn","ben",NULL},
+  {"bo","bod","tib"},
+  {"br","bre",NULL},
+  {"bs","bos",NULL},
+  {"ca","cat",NULL},
+  {"ce","che",NULL},
+  {"ch","cha",NULL},
+  {"co","cos",NULL},
+  {"cr","cre",NULL},
+  {"cs","ces","cze"},
+  {"cu","chu",NULL},
+  {"cv","chv",NULL},
+  {"cy","cym","wel"},
+  {"da","dan",NULL},
+  {"de","deu","ger"},
+  {"dv","div",NULL},
+  {"dz","dzo",NULL},
+  {"ee","ewe",NULL},
+  {"el","ell","gre"},
+  {"en","eng",NULL},
+  {"eo","epo",NULL},
+  {"es","spa",NULL},
+  {"et","est",NULL},
+  {"eu","eus","baq"},
+  {"fa","fas","per"},
+  {"ff","ful",NULL},
+  {"fi","fin",NULL},
+  {"fj","fij",NULL},
+  {"fo","fao",NULL},
+  {"fr","fra","fre"},
+  {"fy","fry",NULL},
+  {"ga","gle",NULL},
+  {"gd","gla",NULL},
+  {"gl","glg",NULL},
+  {"gn","grn",NULL},
+  {"gu","guj",NULL},
+  {"gv","glv",NULL},
+  {"ha","hau",NULL},
+  {"he","heb",NULL},
+  {"hi","hin",NULL},
+  {"ho","hmo",NULL},
+  {"hr","hrv","scr"},
+  {"ht","hat",NULL},
+  {"hu","hun",NULL},
+  {"hy","hye","arm"},
+  {"hz","her",NULL},
+  {"ia","ina",NULL},
+  {"id","ind",NULL},
+  {"ie","ile",NULL},
+  {"ig","ibo",NULL},
+  {"ii","iii",NULL},
+  {"ik","ipk",NULL},
+  {"io","ido",NULL},
+  {"is","isl","ice"},
+  {"it","ita",NULL},
+  {"iu","iku",NULL},
+  {"ja","jpn",NULL},
+  {"jv","jav",NULL},
+  {"ka","kat","geo"},
+  {"kg","kon",NULL},
+  {"ki","kik",NULL},
+  {"kj","kua",NULL},
+  {"kk","kaz",NULL},
+  {"kl","kal",NULL},
+  {"km","khm",NULL},
+  {"kn","kan",NULL},
+  {"ko","kor",NULL},
+  {"kr","kau",NULL},
+  {"ks","kas",NULL},
+  {"ku","kur",NULL},
+  {"kv","kom",NULL},
+  {"kw","cor",NULL},
+  {"ky","kir",NULL},
+  {"la","lat",NULL},
+  {"lb","ltz",NULL},
+  {"lg","lug",NULL},
+  {"li","lim",NULL},
+  {"ln","lin",NULL},
+  {"lo","lao",NULL},
+  {"lt","lit",NULL},
+  {"lu","lub",NULL},
+  {"lv","lav",NULL},
+  {"mg","mlg",NULL},
+  {"mh","mah",NULL},
+  {"mi","mri","mao"},
+  {"mk","mkd","mac"},
+  {"ml","mal",NULL},
+  {"mn","mon",NULL},
+  {"mr","mar",NULL},
+  {"ms","msa","may"},
+  {"mt","mlt",NULL},
+  {"my","mya","bur"},
+  {"na","nau",NULL},
+  {"nb","nob",NULL},
+  {"nd","nde",NULL},
+  {"ne","nep",NULL},
+  {"ng","ndo",NULL},
+  {"nl","nld","dut"},
+  {"nn","nno",NULL},
+  {"no","nor",NULL},
+  {"nr","nbl",NULL},
+  {"nv","nav",NULL},
+  {"ny","nya",NULL},
+  {"oc","oci",NULL},
+  {"oj","oji",NULL},
+  {"om","orm",NULL},
+  {"or","ori",NULL},
+  {"os","oss",NULL},
+  {"pa","pan",NULL},
+  {"pi","pli",NULL},
+  {"pl","pol",NULL},
+  {"ps","pus",NULL},
+  {"pt","por",NULL},
+  {"qu","que",NULL},
+  {"rm","roh",NULL},
+  {"rn","run",NULL},
+  {"ro","ron","rum"},
+  {"ru","rus",NULL},
+  {"rw","kin",NULL},
+  {"sa","san",NULL},
+  {"sc","srd",NULL},
+  {"sd","snd",NULL},
+  {"se","sme",NULL},
+  {"sg","sag",NULL},
+  {"si","sin",NULL},
+  {"sk","slk","slo"},
+  {"sl","slv",NULL},
+  {"sm","smo",NULL},
+  {"sn","sna",NULL},
+  {"so","som",NULL},
+  {"sq","sqi","alb"},
+  {"sr","srp","scc"},
+  {"ss","ssw",NULL},
+  {"st","sot",NULL},
+  {"su","sun",NULL},
+  {"sv","swe",NULL},
+  {"sw","swa",NULL},
+  {"ta","tam",NULL},
+  {"te","tel",NULL},
+  {"tg","tgk",NULL},
+  {"th","tha",NULL},
+  {"ti","tir",NULL},
+  {"tk","tuk",NULL},
+  {"tl","tgl",NULL},
+  {"tn","tsn",NULL},
+  {"to","ton",NULL},
+  {"tr","tur",NULL},
+  {"ts","tso",NULL},
+  {"tt","tat",NULL},
+  {"tw","twi",NULL},
+  {"ty","tah",NULL},
+  {"ug","uig",NULL},
+  {"uk","ukr",NULL},
+  {"ur","urd",NULL},
+  {"uz","uzb",NULL},
+  {"ve","ven",NULL},
+  {"vi","vie",NULL},
+  {"vo","vol",NULL},
+  {"wa","wln",NULL},
+  {"wo","wol",NULL},
+  {"xh","xho",NULL},
+  {"yi","yid",NULL},
+  {"yo","yor",NULL},
+  {"za","zha",NULL},
+  {"zh","zho","chi"},
+  {"zu","zul",NULL},
+};
+
+const char *find_iso639_1(const char *iso639_2)
+{
+  size_t n;
+  if (!iso639_2) return NULL;
+  for (n=0; n<sizeof(iso639)/sizeof(iso639[0]); ++n) {
+    if (!strcasecmp(iso639_2,iso639[n].iso639_2t) || (iso639[n].iso639_2b && !strcasecmp(iso639_2,iso639[n].iso639_2b))) {
+      return iso639[n].iso639_1;
+    }
+  }
+  return NULL;
+}
+

Added: trunk/ffmpeg2theora/src/iso639.h
===================================================================
--- trunk/ffmpeg2theora/src/iso639.h	                        (rev 0)
+++ trunk/ffmpeg2theora/src/iso639.h	2009-04-24 11:46:40 UTC (rev 15952)
@@ -0,0 +1,7 @@
+#ifndef _F2T_ISO639_H_
+#define _F2T_ISO639_H_
+
+extern const char *find_iso639_1(const char *iso639_2);
+
+#endif
+

Modified: trunk/ffmpeg2theora/src/subtitles.c
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.c	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/src/subtitles.c	2009-04-24 11:46:40 UTC (rev 15952)
@@ -47,6 +47,7 @@
     ks->filename = NULL;
     ks->num_subtitles = 0;
     ks->subtitles = 0;
+    ks->stream_index = -1;
     ks->subtitles_count = 0; /* denotes not set yet */
     ks->subtitles_encoding = ENC_UNSET;
     strcpy(ks->subtitles_language, "");
@@ -54,12 +55,32 @@
 }
 
 /*
+ * adds a stream for an embedded subtitles stream
+ */
+void add_subtitles_stream(ff2theora this,int stream_index,const char *language,const char *category){
+  ff2theora_kate_stream *ks;
+  add_kate_stream(this);
+
+  ks = &this->kate_streams[this->n_kate_streams-1];
+  ks->stream_index = stream_index;
+
+  if (!category) category="SUB";
+  strncpy(ks->subtitles_category, category, 16);
+  ks->subtitles_category[15] = 0;
+
+  if (language) {
+    strncpy(ks->subtitles_language, language, 16);
+    ks->subtitles_language[15] = 0;
+  }
+}
+
+/*
  * sets the filename of the next subtitles file
  */
 void set_subtitles_file(ff2theora this,const char *filename){
   size_t n;
   for (n=0; n<this->n_kate_streams;++n) {
-    if (!this->kate_streams[n].filename) break;
+    if (this->kate_streams[n].stream_index==-1 && !this->kate_streams[n].filename) break;
   }
   if (n==this->n_kate_streams) add_kate_stream(this);
   this->kate_streams[n].filename = filename;
@@ -71,7 +92,7 @@
 void set_subtitles_language(ff2theora this,const char *language){
   size_t n;
   for (n=0; n<this->n_kate_streams;++n) {
-    if (!this->kate_streams[n].subtitles_language[0]) break;
+    if (this->kate_streams[n].stream_index==-1 && !this->kate_streams[n].subtitles_language[0]) break;
   }
   if (n==this->n_kate_streams) add_kate_stream(this);
   strncpy(this->kate_streams[n].subtitles_language, language, 16);
@@ -84,7 +105,7 @@
 void set_subtitles_category(ff2theora this,const char *category){
   size_t n;
   for (n=0; n<this->n_kate_streams;++n) {
-    if (!this->kate_streams[n].subtitles_category[0]) break;
+    if (this->kate_streams[n].stream_index==-1 && !this->kate_streams[n].subtitles_category[0]) break;
   }
   if (n==this->n_kate_streams) add_kate_stream(this);
   strncpy(this->kate_streams[n].subtitles_category, category, 16);
@@ -97,7 +118,7 @@
 void set_subtitles_encoding(ff2theora this,F2T_ENCODING encoding){
   size_t n;
   for (n=0; n<this->n_kate_streams;++n) {
-    if (this->kate_streams[n].subtitles_encoding==ENC_UNSET) break;
+    if (this->kate_streams[n].stream_index==-1 && !this->kate_streams[n].subtitles_encoding==ENC_UNSET) break;
   }
   if (n==this->n_kate_streams) add_kate_stream(this);
   this->kate_streams[n].subtitles_encoding = encoding;
@@ -382,6 +403,47 @@
 #endif
 }
 
+int add_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const char *utf8, size_t utf8len)
+{
+#ifdef HAVE_KATE
+  int n, ret;
+  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) {
+        fprintf(stderr, "Out of memory\n");
+        return -1;
+      }
+      ret=kate_text_validate(kate_utf8,utf8,utf8len);
+      if (ret<0) {
+        fprintf(stderr,"WARNING - stream %d: subtitle %s is not valid UTF-8\n",idx,utf8);
+      }
+      else {
+        /* make a copy */
+        size_t len = utf8len;
+        char *utf8copy = (char*)malloc(utf8len);
+        if (!utf8copy) {
+	  fprintf(stderr, "Out of memory\n");
+	  return -1;
+        }
+        memcpy(utf8copy, utf8, utf8len);
+        /* kill off trailing \n characters */
+        while (len>0) {
+	  if (utf8copy[len-1]=='\n') utf8copy[--len]=0; else break;
+        }
+        ks->subtitles[ks->num_subtitles].text = utf8copy;
+        ks->subtitles[ks->num_subtitles].len = utf8len;
+        ks->subtitles[ks->num_subtitles].t0 = t;
+        ks->subtitles[ks->num_subtitles].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	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/src/subtitles.h	2009-04-24 11:46:40 UTC (rev 15952)
@@ -19,6 +19,8 @@
 extern int load_subtitles(ff2theora_kate_stream *this, int ignore_non_utf8);
 extern void free_subtitles(ff2theora this);
 
+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);
 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/subtitles.txt
===================================================================
--- trunk/ffmpeg2theora/subtitles.txt	2009-04-24 09:51:08 UTC (rev 15951)
+++ trunk/ffmpeg2theora/subtitles.txt	2009-04-24 11:46:40 UTC (rev 15952)
@@ -28,8 +28,11 @@
 Any number of subtitles streams can be multiplexed, presumably with
 different languages and/or categories. See below for examples of this.
 
+Additionally, text subtitles from the input stream may also be used.
+Use --nosubtitles if those are not to be converted.
 
 
+
  * Subtitles related options
 
 --subtitles <file>
@@ -68,8 +71,12 @@
   a substitute for converting a non utf-8 file to utf-8, however, as the
   non utf-8 sequence will be missing from the output stream.
 
+--nosubtitles
+  Subtitle streams from the input file will not be converted. Subtitles
+  from any supplied --subtitles option will still be used.
 
 
+
  * Converting non-utf-8 files to utf-8
 
 If you have SubRip files in another format than utf-8, you can use the



More information about the commits mailing list