Browse Source

Initial commit. Version 1.0

master
commit
4055c49a5a
1 changed files with 286 additions and 0 deletions
  1. +286
    -0
      srt2ass3D.c

+ 286
- 0
srt2ass3D.c View 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…
Cancel
Save