commit 4055c49a5abcaf36e59610107c5f874aa5e08b18 Author: Carlos Silva Date: Thu Apr 19 23:41:22 2012 +0000 Initial commit. Version 1.0 diff --git a/srt2ass3D.c b/srt2ass3D.c new file mode 100644 index 0000000..9a84db8 --- /dev/null +++ b/srt2ass3D.c @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include + +#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, "", "{\\i1}"), "", "{\\i0}"); + tmp2 = strreplace(strreplace(tmp1, "", "{\\b1}"), "", "{\\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; +}