Initial commit. Version 1.0
This commit is contained in:
commit
4055c49a5a
1 changed files with 286 additions and 0 deletions
286
srt2ass3D.c
Normal file
286
srt2ass3D.c
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define SBS_MIDDLE_LEFT_1920 480
|
||||||
|
#define SBS_MIDDLE_LEFT_3840 SBS_MIDDLE_LEFT_1920 * 2
|
||||||
|
#define SBS_MIDDLE_RIGHT_1920 1440
|
||||||
|
#define SBS_MIDDLE_RIGHT_3840 SBS_MIDDLE_RIGHT_1920 * 2
|
||||||
|
#define TB_MIDDLE_1920 960
|
||||||
|
#define TB_MIDDLE_3840 TB_MIDDLE_1920 * 2
|
||||||
|
|
||||||
|
static int fullres = 0;
|
||||||
|
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{ "input", required_argument, 0, 'i' },
|
||||||
|
{ "output", required_argument, 0, 'o' },
|
||||||
|
{ "3dmode", required_argument, 0, '3' },
|
||||||
|
{ "3ddepth", required_argument, 0, 'd' },
|
||||||
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ "fullres", no_argument, &fullres, 1 },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
void show_help() {
|
||||||
|
printf("srt2ass3D converts a SRT subtitle file to a ASS subtitle file for 3d viewing. Options are:\n");
|
||||||
|
printf("\t--input,-i\t(required) Input file name\n");
|
||||||
|
printf("\t--output,-o\t(required) Output file name\n");
|
||||||
|
printf("\t--3dmode,-3\t(required) 3D Mode (SBS, TB)\n");
|
||||||
|
printf("\t--3ddepth,-d\t(required) 3D Depth for the subtitles [-3, 3]\n");
|
||||||
|
printf("\t--fullres\tSpecifies that the movie is a full resolution 3D movie (3840x1080 or 1920x2160)\n");
|
||||||
|
printf("\t--help,-h\tThis help screen\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strreplace(const char *string, const char *substr, const char *replacement){
|
||||||
|
char *tok = NULL;
|
||||||
|
char *newstr = NULL;
|
||||||
|
char *oldstr = NULL;
|
||||||
|
char *head = NULL;
|
||||||
|
|
||||||
|
/* if either substr or replacement is NULL, duplicate string a let caller handle it */
|
||||||
|
if (substr == NULL || replacement == NULL)
|
||||||
|
return strdup (string);
|
||||||
|
|
||||||
|
newstr = strdup(string);
|
||||||
|
head = newstr;
|
||||||
|
while ((tok = strstr(head, substr))) {
|
||||||
|
oldstr = newstr;
|
||||||
|
newstr = malloc(strlen(oldstr) - strlen(substr) + strlen(replacement) + 1 );
|
||||||
|
/*failed to alloc mem, free old string and return NULL */
|
||||||
|
if (newstr == NULL) {
|
||||||
|
free (oldstr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(newstr, oldstr, tok - oldstr);
|
||||||
|
memcpy(newstr + (tok - oldstr), replacement, strlen(replacement));
|
||||||
|
memcpy(newstr + (tok - oldstr) + strlen(replacement), tok + strlen(substr), strlen(oldstr) - strlen(substr) - (tok - oldstr));
|
||||||
|
memset(newstr + strlen(oldstr) - strlen(substr) + strlen(replacement), 0, 1 );
|
||||||
|
|
||||||
|
/* move back head right after the last replacement */
|
||||||
|
head = newstr + (tok - oldstr) + strlen(replacement);
|
||||||
|
free (oldstr);
|
||||||
|
}
|
||||||
|
return newstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* replace_tags(char *text) {
|
||||||
|
char *tmp1, *tmp2;
|
||||||
|
|
||||||
|
tmp1 = strreplace(strreplace(text, "<i>", "{\\i1}"), "</i>", "{\\i0}");
|
||||||
|
tmp2 = strreplace(strreplace(tmp1, "<b>", "{\\b1}"), "</b>", "{\\b0}");
|
||||||
|
free(tmp1);
|
||||||
|
return tmp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int option_index;
|
||||||
|
unsigned int c;
|
||||||
|
char *input_name = NULL;
|
||||||
|
char *output_name = NULL;
|
||||||
|
int tb;
|
||||||
|
short depth = 0;
|
||||||
|
short valid_args = 0;
|
||||||
|
|
||||||
|
while ((c = getopt_long(argc, argv, "i:o:3:d:h", long_options, &option_index)) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 0: {
|
||||||
|
if (long_options[option_index].flag != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'i': {
|
||||||
|
input_name = malloc(sizeof(char) * strlen(optarg) + 1);
|
||||||
|
strcpy(input_name, optarg);
|
||||||
|
valid_args++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'o': {
|
||||||
|
output_name = malloc(sizeof(unsigned char) * strlen(optarg) + 1);
|
||||||
|
strcpy(output_name, optarg);
|
||||||
|
valid_args++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '3': {
|
||||||
|
// If the argument is SBS then the result will be 0, and 0 == false, so TB = false.
|
||||||
|
tb = strcasecmp("SBS", optarg);
|
||||||
|
valid_args++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
depth = atoi(optarg);
|
||||||
|
valid_args++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'h': {
|
||||||
|
show_help();
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_args != 4) {
|
||||||
|
if (input_name != NULL)
|
||||||
|
free(input_name);
|
||||||
|
if (output_name != NULL)
|
||||||
|
free(output_name);
|
||||||
|
show_help();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth < -3 || depth > 3) {
|
||||||
|
printf("Values of depth should be between -3 and 3\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *inputf;
|
||||||
|
FILE *outputf;
|
||||||
|
inputf = fopen(input_name, "r");
|
||||||
|
if (inputf == NULL) {
|
||||||
|
printf("Error opening %s for reading: %s\n", input_name, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
outputf = fopen(output_name, "w");
|
||||||
|
if (outputf == NULL) {
|
||||||
|
printf("Error opening %s for writing: %s\n", output_name, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Input file: %s\nOutput file: %s\n3D type: %s\nDepth: %i\n\n",
|
||||||
|
input_name, output_name, (tb ? "TB" : "SBS"), depth);
|
||||||
|
|
||||||
|
// ASS headers
|
||||||
|
fprintf(outputf, "[Script Info]\n");
|
||||||
|
fprintf(outputf, "; Script generated by srt2ass3D 1.0\n");
|
||||||
|
fprintf(outputf, "Title: %s\n", output_name);
|
||||||
|
fprintf(outputf, "ScriptType: v4.00+\n");
|
||||||
|
fprintf(outputf, "WrapStyle: 0\n");
|
||||||
|
if (!fullres) {
|
||||||
|
fprintf(outputf, "PlayResX: 1920\n");
|
||||||
|
fprintf(outputf, "PlayResY: 1080\n");
|
||||||
|
} else {
|
||||||
|
if (!tb) {
|
||||||
|
fprintf(outputf, "PlayResX: 3840\n");
|
||||||
|
fprintf(outputf, "PlayResY: 1080\n");
|
||||||
|
} else {
|
||||||
|
fprintf(outputf, "PlayResX: 1920\n");
|
||||||
|
fprintf(outputf, "PlayResY: 2160\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(outputf, "ScaledBorderAndShadow: yes\n\n");
|
||||||
|
fprintf(outputf, "[V4+ Styles]\n");
|
||||||
|
fprintf(outputf, "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n");
|
||||||
|
if (!tb)
|
||||||
|
fprintf(outputf, "Style: 3D,Cube Modern Rounded Thin,60,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,6,0,2,0,0,0,1\n\n");
|
||||||
|
else
|
||||||
|
fprintf(outputf, "Style: 3D,Cube Modern Rounded Short,60,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,6,0,2,0,0,0,1\n\n");
|
||||||
|
fprintf(outputf, "[Events]\n");
|
||||||
|
fprintf(outputf, "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n\n");
|
||||||
|
|
||||||
|
short state = 0;
|
||||||
|
char *line = malloc(sizeof(unsigned char) * 50);
|
||||||
|
char *subtitle1 = malloc(sizeof(unsigned char) * 256);
|
||||||
|
char *subtitle2 = malloc(sizeof(unsigned char) * 256);
|
||||||
|
// read the input file and convert it
|
||||||
|
while (fgets(line, 50, inputf) != NULL) {
|
||||||
|
switch (state) {
|
||||||
|
case 0: {
|
||||||
|
// subtitle index expected
|
||||||
|
strtol(line, (char **) NULL, 10);
|
||||||
|
if (errno == EINVAL) {
|
||||||
|
// Maybe the input format is wrong
|
||||||
|
printf("Input file format is wrong\n");
|
||||||
|
fclose(inputf);
|
||||||
|
fclose(outputf);
|
||||||
|
free(input_name);
|
||||||
|
free(output_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
// start/end time expected
|
||||||
|
unsigned short sh, sm, ss, sms;
|
||||||
|
unsigned short eh, em, es, ems;
|
||||||
|
int r = sscanf(line, "%hd:%hd:%hd,%hd --> %hd:%hd:%hd,%hd", &sh, &sm, &ss, &sms, &eh, &em, &es, &ems);
|
||||||
|
if (r == 0) {
|
||||||
|
// Maybe the input format is wrong
|
||||||
|
printf("Input file format is wrong\n");
|
||||||
|
fclose(inputf);
|
||||||
|
fclose(outputf);
|
||||||
|
free(input_name);
|
||||||
|
free(output_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(subtitle1, "Dialogue: 0,%hd:%02hd:%02hd.%03hd,%hd:%02hd:%02hd.%03hd,3D,,0000,0000,0000,,",
|
||||||
|
sh, sm, ss, sms, eh, em, es, ems);
|
||||||
|
sprintf(subtitle2, "Dialogue: 0,%hd:%02hd:%02hd.%03hd,%hd:%02hd:%02hd.%03hd,3D,,0000,0000,0000,,",
|
||||||
|
sh, sm, ss, sms, eh, em, es, ems);
|
||||||
|
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
// 1st line of the subtitle expected
|
||||||
|
if (strlen(line) == 0) {
|
||||||
|
// Maybe the input format is wrong
|
||||||
|
printf("Input file format is wrong\n");
|
||||||
|
fclose(inputf);
|
||||||
|
fclose(outputf);
|
||||||
|
free(input_name);
|
||||||
|
free(output_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tb) {
|
||||||
|
sprintf(subtitle1 + strlen(subtitle1), "{\\pos(%d,1060)}%s", (fullres == 0 ? SBS_MIDDLE_LEFT_1920 : SBS_MIDDLE_LEFT_3840) - depth, line);
|
||||||
|
sprintf(subtitle2 + strlen(subtitle2), "{\\pos(%d,1060)}%s", (fullres == 0 ? SBS_MIDDLE_RIGHT_1920 : SBS_MIDDLE_RIGHT_3840) + depth, line);
|
||||||
|
} else {
|
||||||
|
sprintf(subtitle1 + strlen(subtitle1), "{\\pos(%d,1070)}%s", (fullres == 0 ? TB_MIDDLE_1920 : TB_MIDDLE_3840) - depth, line);
|
||||||
|
sprintf(subtitle2 + strlen(subtitle2), "{\\pos(%d,530)}%s", (fullres == 0 ? TB_MIDDLE_1920 : TB_MIDDLE_3840) + depth, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
// In this case, we can have a 2nd subtitle, or an empty line
|
||||||
|
if (!isspace(*line)) {
|
||||||
|
sprintf(subtitle1 + strlen(subtitle1) - 2, "\\N%s", line);
|
||||||
|
sprintf(subtitle2 + strlen(subtitle2) - 2, "\\N%s", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(outputf, "%s", replace_tags(subtitle1));
|
||||||
|
fprintf(outputf, "%s", replace_tags(subtitle2));
|
||||||
|
|
||||||
|
state = (!isspace(*line) ? 4 : 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
// empty line expected
|
||||||
|
if (!isspace(*line)) {
|
||||||
|
// Maybe the input format is wrong
|
||||||
|
printf("Input file format is wrong\n");
|
||||||
|
fclose(inputf);
|
||||||
|
fclose(outputf);
|
||||||
|
free(input_name);
|
||||||
|
free(output_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Done\n");
|
||||||
|
|
||||||
|
fclose(inputf);
|
||||||
|
fclose(outputf);
|
||||||
|
free(input_name);
|
||||||
|
free(output_name);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue