#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; }