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

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search