commit
4055c49a5a
@ -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 new issue