Subtitle Resynchronizer (I)-程序员宅基地

I found some of the movies I downloaded failed to have any perfectly matching subtitles that can be easily found online, so I have to use some of the closest. But using resync function of vobsub or so is obviously not a way round. With this tool and not too much tuning on it, I guess I may even use those most diverse ones. Complete code of the latest version with some inefficient commentary is provided here:

#include <cstdio>
#include <cstring>
#include <cstdlib>

typedef unsigned long movtime_t;

static void fgetline (char *buf, int size, FILE *f)
{
fgets(buf, size, f);
int len = strlen(buf);
buf[len - 1] = 0;
}

static bool isnumber (char *p)
{
int len = 0;
for ( ; *p != '/0'; ++p, ++len)
{
if (*p < '0' || *p > '9')
{
return false;
}
}
return (len > 0);
}

static bool parse_timestamp (char *p, movtime_t &t)
{
#define ISDIGIT(c) ((c)>='0'&&(c)<='9')
#define ASSERTC(c, ca) if (c!=ca) return false;
#define DIGIT2(v,p) /
if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) return false; /
v = ((p)[0]-'0')*10+((p)[1]-'0');
#define DIGIT3(v,p) /
if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1]) || !ISDIGIT((p)[2])) return false; /
v = ((p)[0]-'0')*100+((p)[1]-'0')*10+((p)[2]-'0');

int h, m, s, ms;
DIGIT2(h,p);
ASSERTC(p[2],':');
DIGIT2(m,p+3);
ASSERTC(p[5],':');
DIGIT2(s,p+6);
ASSERTC(p[8],',');
DIGIT3(ms,p+9);
t = (h*3600+m*60+s)*1000+ms;
return true;
}

static bool istimestamp (char *p, movtime_t &begin, movtime_t &end)
{
// form 00:00:46,430
if (strlen(p) < 29) { return false; }

if (!parse_timestamp(p, begin))
{
return false;
}

// no assertion on the arrow, for it's already very certain

if (!parse_timestamp(p + 17, end))
{
return false;
}

return true;
}

static void analyse_time (movtime_t t, int &h, int &m, int &s, int &ms)
{
ms = t % 1000;
t /= 1000;
s = t % 60;
t /= 60;
m = t % 60;
t /= 60;
h = t;
}

/* it should be big enough to avoid line segmentation */
#define sizebuf 2048


static void rectify (
FILE **ssfpins, // ssfnum
FILE **ssfpouts, // movnum
int ssfnum,
int movnum,
movtime_t *ssfdurs, // in msec, 120min --> 7200000
movtime_t *movdurs // in msec
)
{

// the initial offset of both items are provided at the tail
// the following are the absolute time of them
movtime_t ssfabs = ssfdurs[ssfnum];
movtime_t movabs = movdurs[movnum];

char buf[sizebuf];
char outbuf[sizebuf*2] = {0, };
char oldbuf[sizebuf*2] = {0, };

char tempbuf[sizebuf];

int ssfi = 0;
int movi = 0;
FILE *ssfpin = ssfpins[ssfi];
FILE *ssfpout = ssfpouts[movi];
int outcount = 0;
int oldcount;
bool someinold = false;

while (1)
{
if (feof(ssfpin))
{
__fileend:
ssfabs += ssfdurs[ssfi];
ssfi++;
if (ssfi >= ssfnum )
{
break;
}
ssfpin = ssfpins[ssfi];
}

fgetline(buf, sizebuf, ssfpin);

movtime_t begin, end;
if (isnumber(buf))
{
// print last
if (someinold)
{
fprintf(ssfpout-1, "%d/n", oldcount);
fprintf(ssfpout-1, "%s", oldbuf);
someinold = false;
}
if (outcount > 0)
{
fprintf(ssfpout, "%d/n", outcount);
fprintf(ssfpout, "%s", outbuf);
}

outbuf[0] = 0;
outcount++;
}
else if (istimestamp(buf, begin, end))
{
if (begin == 0 && end == 0)
{
// sign of end
goto __fileend;
}

movtime_t absbegin, absend;
movtime_t corrbegin, corrend;

absbegin = ssfabs + begin;
absend = ssfabs + end;

// check if it's the next output file's turn
if (absend >= movabs + movdurs[movi])
{
if (absbegin < movabs + movdurs[movi])
{
// absbegin to movabs + movdurs[movi] -> cur
corrbegin = absbegin - movabs;
corrend = movdurs[movi];

int h, m, s, ms;
analyse_time(corrbegin, h, m, s, ms);
sprintf(tempbuf, "%02d:%02d:%02d,%03d", h, m, s, ms);
strcat(outbuf, tempbuf);
analyse_time(corrend, h, m, s, ms);
sprintf(tempbuf, " --> %02d:%02d:%02d,%03d/n", h, m, s, ms);
strcat(outbuf, tempbuf);
strcpy(oldbuf, outbuf); outbuf[0] = 0;
oldcount = outcount;
someinold = true;

// movabs + movdurs[movi] to absend -> next
absbegin = movabs + movdurs[movi];

}
else
{ // totally in a new one

}

movabs += movdurs[movi];
movi++;
if (movi >= movnum)
{
break;
}
ssfpout = ssfpouts[movi];

outcount = 1;
}

corrbegin = absbegin - movabs;
corrend = absend - movabs;

int h, m, s, ms;
analyse_time(corrbegin, h, m, s, ms);
sprintf(tempbuf, "%02d:%02d:%02d,%03d", h, m, s, ms);
strcat(outbuf, tempbuf);
analyse_time(corrend, h, m, s, ms);
sprintf(tempbuf, " --> %02d:%02d:%02d,%03d/n", h, m, s, ms);
strcat(outbuf, tempbuf);
}
else
{
sprintf(tempbuf, "%s/n", buf);
strcat(outbuf, tempbuf);
if (someinold)
{
strcat(oldbuf, tempbuf);
}
}
}
}

struct CorrStruct
{
#define MAXFNUM 16
FILE *ssfpins[MAXFNUM]; // ssfnum in count
FILE *ssfpouts[MAXFNUM]; // movnum in count

int ssfnum;
int movnum;

// one more than ssfnum in count
movtime_t ssfdurs[MAXFNUM]; // in msec, 120min --> 7200000
movtime_t movdurs[MAXFNUM]; // in msec
};

static int ParseConfig (CorrStruct *corr, FILE *fConfig)
{
int i;
char buf[sizebuf];
fgetline(buf, sizebuf, fConfig);
corr->ssfnum = atoi(buf);
if (corr->ssfnum + 1 > MAXFNUM)
{
return -1; /* too many files */
}

fgetline(buf, sizebuf, fConfig);
if (!parse_timestamp(buf, corr->ssfdurs[corr->ssfnum]))
{
return -2; /* timestamp error */
}
for (i = 0; i < corr->ssfnum; i++)
{
fgetline(buf, sizebuf, fConfig);
corr->ssfpins[i] = fopen(buf, "r");
fgetline(buf, sizebuf, fConfig);
if (!parse_timestamp(buf, corr->ssfdurs[i]))
{
return -2;
}
}

fgetline(buf, sizebuf, fConfig);
corr->movnum = atoi(buf);
if (corr->movnum + 1 > MAXFNUM)
{
return -1; /* too many files */
}

fgetline(buf, sizebuf, fConfig);
if (!parse_timestamp(buf, corr->movdurs[corr->movnum]))
{
return -2;
}

for (i = 0; i < corr->movnum; i++)
{
fgetline(buf, sizebuf, fConfig);
corr->ssfpouts[i] = fopen(buf, "w");
fgetline(buf, sizebuf, fConfig);
if (!parse_timestamp(buf, corr->movdurs[i]))
{
return -2;
}
}
return 0;
}

static void Finalize (CorrStruct *corr)
{
for (int i = 0; i < corr->ssfnum; i++)
{
fclose(corr->ssfpins[i]);
}
for (int i = 0; i < corr->movnum; i++)
{
fclose(corr->ssfpouts[i]);
}
}

int main (void)
{
FILE *fConfig = fopen("ssresync_config.txt", "r");
CorrStruct corr;
ParseConfig(&corr, fConfig);
rectify(corr.ssfpins, corr.ssfpouts, corr.ssfnum, corr.movnum, corr.ssfdurs, corr.movdurs);
Finalize(&corr);

fclose(fConfig);

return 0;
}

// An example of config file
// It is applied on the subtitles downloaded from shooter.cn for the movie Amadeus with both the
// movie and the script divided into 3 parts with some time deviation between them.
/*
== BEGIN ==
3
00:00:00,000
inNewMov-Amadeus-CD1.eng.srt
00:58:03,160
inNewMov-Amadeus-CD2.eng.srt
00:58:12,500
inNewMov-Amadeus-CD3.eng.srt
00:58:23,240
3
00:00:00,000
NewMov-Amadeus-CD1.eng.srt
00:57:09,000
NewMov-Amadeus-CD2.eng.srt
00:57:40,000
NewMov-Amadeus-CD3.eng.srt
01:05:32,000
== END ==
*/



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/iteye_18591/article/details/81580845

智能推荐

13. HTTP1.0 HTTP 1.1 HTTP 2.0主要区别_http 0.13.1-程序员宅基地

文章浏览阅读175次。HTTP1.0 HTTP 1.1 HTTP 2.0主要区别HTTP1.0 HTTP 1.1主要区别长连接节约带宽HOST域HTTP1.1 HTTP 2.0主要区别多路复用数据压缩服务器推送HTTP1.0 HTTP 1.1主要区别长连接HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支..._http 0.13.1

Webdynpro ABAP 简单剖析_abap webdynpro-程序员宅基地

文章浏览阅读1.7k次。众所周知,WEBDYNPRO是今天来SAP主推的一个面向WEB的MVC编程框架,接触过J2EE的朋友都不会对MVC这种设计模式陌生,WEBDYNPRO ABAP的基本设计思路和很多著名的面向互联网的MVC框架很相似(比如STRUCTS)SAPNETWEAVER 平台上也有WEBDYNPRO的一些标准应用,譬如PI RWB上面的ALERT CONFIGRATION功能,理解WEBDYNPRO的工作..._abap webdynpro

【spring cloud】spring cloud2.X spring boot2.0.4调用feign配置Hystrix Dashboard 和 集成Turbine 【解决:Hystrix仪表盘...-程序员宅基地

文章浏览阅读311次。环境:&lt;java.version&gt;1.8&lt;/java.version&gt;&lt;spring-boot.version&gt;2.0.4.RELEASE&lt;/spring-boot.version&gt;&lt;spring-cloud.version&gt;Finchley.SR1&lt;/spring-cloud.version&gt;&lt;lcn.last.v..._springboot 2.4 可以使用feign调用吗

Win7/Win10移动用户文件夹(C:\Users)移到非系统盘(如D:)_该应用程序位于未经授权的位置 请移至非系统文件夹-程序员宅基地

文章浏览阅读8.8w次,点赞48次,收藏252次。Windows的用户文件夹默认所在位置是系统盘(通常是C盘)下的“\Users”目录之内。该文件夹中保存着所有的用户个人数据,比如你保存在“桌面”上的文件(实际上是保存在C:\Users\你的用户名\Desktop\目录之中),再比如你保存在“我的文档”里的文件(实际上是保存在C:\Users\用户名\Documents目录之中)。用户文件夹处于系统盘的坏处在于,如若系统盘一旦坏掉,就可能连带用..._该应用程序位于未经授权的位置 请移至非系统文件夹

约瑟夫环的数学公式推导_约瑟夫出圈问题公式-程序员宅基地

文章浏览阅读6.7k次,点赞7次,收藏35次。约瑟夫环的数学方法解决 编写约瑟夫环程序时会发现,当我们把整个报数过程的人数N变的很大,例如到几百万,虽然在最后还是只剩下两个人报数,但也要循环几百万次才能确定最后留下来的那个人。这样程序执行的效率不高,会占用大量时间去执行循环的过程。有时会发生输出一直等待很长时间才能出来结果。经过查询资料,找到了约瑟夫环的数学解决方法,以及它的算法具体执行的过程来做分享。我们假设..._约瑟夫出圈问题公式

软件测试|Pytest必会使用autouse实现自动传参-程序员宅基地

文章浏览阅读120次。1.薪资丰厚: 基本薪资+绩效+项目奖金+年终奖2.福利: 和正式员工福利基本看齐,共享工位,免费夜宵,班车,一流办公环境,月末周六双倍工资3.技术栈:C/C+当用例很多的时候,每次。不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦。不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦虑不焦。

随便推点

Linux命令_禅道的运行日志放在哪-程序员宅基地

文章浏览阅读309次。笔记_禅道的运行日志放在哪

Web实训项目--网页设计(附源码)_web前端网页设计代码-程序员宅基地

文章浏览阅读4.3w次,点赞79次,收藏882次。我们要使用这些知识实现一个简单的网页设计,利用HTML的a标签做文本内容跳转以及超链接的应用,CSS设计内容样式和图片、动画、视频的大小位置格式,JavaScript实现轮播图效果等。学习如何设计网页中的轮播图和动画效果,并掌握a标签文本内容跳转、超链接的应用、播放音乐与视频等操作。通过对Web知识内容的了解,我们掌握了HTML、CSS和JavaScript的基本知识以及利用它们实现一些简单的应用。1、使用Web知识实现一个简单的网页设计,利用HTML的a标签做文本内容跳转以及超链接的应用。_web前端网页设计代码

Matlab:非负 ODE 解_matlab銝要onnegative-程序员宅基地

Matlab中讲解了如何约束ODE解为非负解的示例,并以绝对值函数和膝盖问题为例进行了说明。文章指出在某些情况下,由于方程的物理解释或解性质的原因,施加非负约束是必要的。

关于g2o_viewer data/result_after.g2o使用过程中coredump、与lsd_slam依赖包libg2o冲突问题_libg2o_-程序员宅基地

文章浏览阅读1.1k次。电脑上装的东西多了就很容引起版本或者依赖问题。。。这不,按照高博教程做octomap实验时候运行g2o_viewer data/result_after.g2o时候就直接coredump。。。。回想起来自己ROS系统中装了libg2o,于是卸载之:sudo apt-get remove ros-indigo-libg2o然后重新执行g2o_viewer data/result_after.g2o注..._libg2o_

学习通选修刷课使用过程(懂得都懂)_学习通脚本-程序员宅基地

文章浏览阅读2w次,点赞58次,收藏268次。学习通不想好好上课系列_学习通脚本

将Total Commander设置为“默认”文件管理器?_total commander默认文件管理器-程序员宅基地

文章浏览阅读1.6k次。将Total Commander设置为“默认”文件管理器?法一:开始,运行,输入regedit ,回车: 定位到HKEY_LOCAL_MACHINE_total commander默认文件管理器

推荐文章

热门文章

相关标签