正在处理中的导入字幕

Posted

技术标签:

【中文标题】正在处理中的导入字幕【英文标题】:Import Subtitles in Processing 【发布时间】:2013-11-20 22:45:09 【问题描述】:

我正在处理这个草图,它从我的网络摄像头/智能手机获取视频源并在运行时显示它。我想从电影中导入一个转换为 txt 字幕文件的 .srt 文件。我可以看到文本文件中的所有这些数字都代表实际文本之前的开始和结束字幕框。

这是一个例子:

92329331Those swings are dangerous.|Stay off there. I haven't fixed them yet.
93339374I think you're gonna live.

我想做的是找出一个代码

    使用这些数字并将它们设置为开始/结束帧,以便在电影中的正确时间运行 显示字幕 弄清楚如何使用“|”符号作为符号在脚本中触发换行。

我想这可能已经很复杂了,但我只是想检查过去是否有人做过类似的事情..

我想我想做的是让我免于做整个事情

if ((current_frame > 9232) && ((current_frame < 9331)) 
    text("Those swings are dangerous.", 200, 500/2);
    text("Stay off there. I haven't fixed them yet..", 200, (500/2 + 35));
 

每个字幕的东西...

我对处理很陌生,所以除了'for'和'if'之外的许多命令都不熟悉,导入.txt文件的新手和处理数组的无知。但是我真的很想在最后两位找到一个好方法..

任何形式的帮助将不胜感激:)

干杯, 乔治

【问题讨论】:

【参考方案1】:

为了显示适当的字幕,您可以执行以下操作(解释如下,对于文字墙提前抱歉):

String[] subtitles = loadStrings("subtitles.txt");
int currentFrame = 0;
int subtitleIndex = -1;
int startFrame = -1, endFrame = -1;
int fontSize = 10; //change to suit your taste
String[] currentSubtitle;
...

//draw loop start:
//video drawing code goes here

if(currentFrame > endFrame) //update which subtitle is now/next
  subtitleIndex++;
  startFrame = int(subtitles[subtitleIndex].split("\\\\")[0].substring(1));
  endFrame = int(subtitles[subtitleIndex].split("\\\\")[1].split("\\")[0]);
  currentSubtitle = subtitles[subtitleIndex].split("\\")[2].split("\\|");

if(currentFrame >= startFrame && currentFrame <= endFrame)
  for(int i = 0; i < currentSubtitle.length; i++)
    text(currentSubtitle[i], width/2, height - fontSize * (currentSubtitle.length - i));
  

currentFrame++;
//draw loop end

这对你来说可能看起来很吓人,所以这里有一些演练的评论。您的程序将是state machine 的类型。它要么处于显示字幕的状态,要么不处于显示字幕的状态。我们稍后在设计代码时会记住这一点。首先,您需要声明和初始化变量。

第一行使用loadStrings() 函数,它读取一个文本文件并返回一个String 数组,其中数组中的每个元素都是文件中的一行。当然,您需要更改文件名以适合您的文件。

您的代码使用了一个名为current_frame 的变量,这是一个非常好的主意,但我已将其重命名为currentFrame 以符合Java 编码约定。我们将从零开始,稍后我们的代码将在每帧显示时递增它。这个变量将告诉我们我们在字幕序列中的位置以及应该显示哪条消息(如果有的话)。

因为每个字幕开始和结束的帧的信息被编码在一个字符串中,所以将其合并到代码中有点棘手。现在,让我们创建一些变量来表示“当前”字幕——我们当前正在显示或将要显示的下一个字幕——开始和结束的时间。我们还将创建一个索引来跟踪subtitles 数组中的哪个元素是“当前”字幕。这些变量都以-1 开头,这看起来有点奇怪。虽然我们将currentFrame 初始化为0,但它们并没有真正的“初始”值,至少现在没有。如果我们选择0,那么这不是真的,因为第一个字幕可能不会(可能不会)在帧0 开始和结束,并且任何其他正数都没有多大意义。 -1 通常用作虚拟索引,在变量实际使用之前将被替换,因此我们也将在这里这样做。

现在是最后一个变量:currentSubtitle。直接的想法是让它成为一个普通的String,而不是String 数组。但是,由于每个字幕可能需要在管道 (|) 符号上进行拆分,因此每个字幕实际上可能代表几行文本,因此为了安全起见,我们将创建一个数组。有些字幕可能是单元素数组,但这没关系。

现在是最难的部分!

大概,您的代码中会有某种循环,在每次迭代中,相关的视频帧都会被绘制到屏幕上,并且(如果满足条件),字幕会被绘制在它的顶部。我省略了视频部分,因为这不是你问题的一部分。

在我们做任何其他事情之前,我们需要记住我们的一些变量还没有真正的值——之前的所有-1s 都需要设置为某个值。绘制循环的基本逻辑是 1) 判断是否需要绘制字幕,如果需要,则绘制它,以及 2) 判断“当前”字幕是否需要移动到数组中的下一个字幕。让我们先做#2,因为在第一次通过循环时,我们还不知道任何事情!移动到下一个字幕的标准(通常)是我们是否超过了当前字幕的结尾:currentFrame &gt; endFrame。如果这是真的,那么我们需要将所有变量转移到下一个字幕。 subtitleIndex 很简单,我们只需添加一个即可。其余的……没那么容易。我知道这看起来很恶心,但我会在最后讨论这个,以免破坏流程。如果您等不及,请直接跳到底部:)

在(如有必要)更改所有变量以使它们与当前字幕相关之后,我们需要进行一些实际显示。第二个if 语句检查我们是否“在”当前字幕的帧边界内。因为currentSubtitle 变量可以引用需要立即显示的字幕,或者只是序列中的下一个,所以我们需要进行一些检查以确定它是用于这一帧的哪一个。那是第二条if 声明——如果我们已经过了开始并且在结束之前,那么我们应该显示字幕!回想一下我们的currentSubtitle 变量是一个数组,所以我们不能直接显示它。我们需要遍历它并在单独的行上显示每个元素。您提到了text() 命令,所以这里不再深入。棘手的一点是文本的 y 坐标,因为它应该在多行上。我们希望第一个元素在第二个元素之上,第三个元素之上,等等。为此,我们将 y 坐标取决于我们所在的元素,标记为i。我们可以通过改变fontSize的值来缩放行间的差异;这将取决于你的口味。知道您设置的数字将等于行的高度(以像素为单位)。

现在是我不想在上面解释的混乱部分。此代码取决于String 的split() 方法,该方法在您要拆分的字符串上执行,并将字符串作为指示它如何拆分字符串的参数——regex。要从文件中的字幕行中取出 startFrame,我们需要将它沿花括号分开,因为它们是数字之间的分隔符。首先,我们将在出现“”的任何地方拆分字符串——就在第一个数字之后(第二个数字之前)。因为split() 返回一个数组,我们可以使用方括号之间的索引从中引用单个字符串。我们知道第一个数字将在第一个字符串中通过拆分“”返回,所以我们将使用索引0。这将返回(例如)“1234”,因为split() 删除了您要拆分的内容。现在我们只需要获取出现在第一个字符之后的substring,使用int() 将其转换为int,我们就完成了!

对于第二个数字,我们可以采取类似的方法。让我们再次拆分“”,这次我们只取返回数组中的 second(索引 1)元素。现在,我们有类似“9331Those swings are dang...”的内容,我们可以在“”上拆分再次,选择该数组的第一个字符串,转换为 int,然后我们'重做!在这两种情况下,我们都使用subtitles[subtitleIndex] 作为原始字符串,它表示我们在开头使用loadStrings() 加载的文件的原始输入。请注意,在所有这些拆分过程中,subtitles 中的原始字符串永远不会更改——split()substring() 等仅返回新序列,而不会修改您调用它的字符串。

我会让你弄清楚该序列中的最后一行是如何工作的:)

最后,您会看到split() 调用中有一堆反斜杠。这是因为split() 接受一个正则表达式,而不是一个简单的字符串。正则表达式使用很多特殊符号,我不会在这里介绍,但如果你刚刚传递了 split() 类似 "" 的东西,它会尝试解释它并且它不会像预期的那样运行。你需要escape 字符,告诉split() 你不希望它们被解释为特殊的,你只想要字符本身。为此,您需要在任何需要转义的字符之前使用反冲。然而,反斜杠本身是另一个特殊字符,所以你也需要转义它!这会导致像"\\" 这样的东西——第一个反斜杠转义第二个反斜杠,它转义第三个字符。请注意,| 字符也需要转义。

对不起,文字墙!很高兴看到问题被聪明而礼貌地提出,所以我想我会给出一个好的答案作为回报。

【讨论】:

绝妙的答案!

以上是关于正在处理中的导入字幕的主要内容,如果未能解决你的问题,请参考以下文章

Pr制作中英文双语字幕教程

pr怎么快速添加字幕

如何把字幕和视频合成到一个文件?

剪映的字幕加到pr里很糊

请问如何在视频编辑中插入动态文字?

导入工程后,在IDE中显示中文为乱码,请问如何解决