/* * VFR translation functions for OverLua * Copyright 2007 Niels Martin Hansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Contact: E-mail: IRC: jfs in #aegisub on irc.rizon.net */ #include "vfr.h" #include #include #include // Work with seconds per frame (spf) here instead of fps since that's more natural for the translation we're doing class TimecodesV1 : public VFRTranslator { private: // Used when sections run out double default_spf; double first_non_section_timestamp; int first_non_section_frame; // Also generate sections for unspecified ones // (use the default framerate then) struct FrameRateSection { double start_time; double spf; int start_frame; int end_frame; }; std::vector sections; public: virtual double TimeStampFromFrameNumber(int n) { // Find correct section for (size_t i = 0; i < sections.size(); i++) { FrameRateSection § = sections[i]; if (n >= sect.start_frame && n <= sect.end_frame) { return sect.start_time + (n - sect.start_frame) * sect.spf; } } // Not in a section if (n < 0) return 0.0; return first_non_section_timestamp + (n - first_non_section_frame) * default_spf; } TimecodesV1(FILE *vfrfile) { char buf[100]; default_spf = -1; double cur_time = 0.0; FrameRateSection temp_section; temp_section.start_time = 0.0; temp_section.spf = -1; temp_section.start_frame = 0; temp_section.end_frame = 0; while (fgets(buf, 100, vfrfile)) { // Comment? if (buf[0] == '#') continue; if (strncmp(buf, "Assume ", 7) == 0 && default_spf < 0) { char *num = buf+7; default_spf = atof(num); if (default_spf > 0) default_spf = 1 / default_spf; else default_spf = -1; temp_section.spf = default_spf; continue; } int start_frame, end_frame; double fps; if (scanf("%d,%d,%f", &start_frame, &end_frame, &fps) == 3) { // Finish the current temp section temp_section.end_frame = start_frame - 1; if (temp_section.end_frame >= temp_section.start_frame) { cur_time += (temp_section.end_frame - temp_section.start_frame + 1) * temp_section.spf; sections.push_back(temp_section); } // Insert the section corresponding to this line temp_section.spf = 1/fps; temp_section.start_frame = start_frame; temp_section.end_frame = end_frame; temp_section.start_time = cur_time; cur_time += (end_frame - start_frame + 1) / fps; sections.push_back(temp_section); // Begin new temp section temp_section.spf = default_spf; temp_section.start_frame = end_frame + 1; temp_section.end_frame = end_frame; // yes, negative duration temp_section.start_time = cur_time; } } first_non_section_timestamp = cur_time; first_non_section_frame = temp_section.start_frame; } }; class TimecodesV2 : public VFRTranslator { private: // Main data std::vector timestamps; // For when data are exhausted (well, they shouldn't, then the vfr file is bad) int last_known_frame; double last_known_timestamp; double assumed_spf; public: virtual double TimeStampFromFrameNumber(int n) { if (n < (int)timestamps.size() && n >= 0) { return timestamps[n]; } if (n < 0) return 0.0; return last_known_timestamp + (n - last_known_frame) * assumed_spf; } TimecodesV2(FILE *vfrfile) { char buf[50]; timestamps.reserve(8192); // should be enough for most cases while (fgets(buf, 50, vfrfile)) { // Comment? if (buf[0] == '#') continue; // Otherwise assume it's a good timestamp timestamps.push_back(atof(buf)); } last_known_frame = (int)timestamps.size()-1; last_known_timestamp = timestamps[last_known_frame]; assumed_spf = 1/25.0; // yes, this is stupid - anyone got a better idea? } }; VFRTranslator *GetVFRTranslator(const char *vfrfile) { char buf[32]; buf[19] = 0; // In "# timecode format v1" the version number is character index 19 FILE *f = fopen(vfrfile, "r"); VFRTranslator *res = 0; if (fgets(buf, 32, f) && buf[0] == '#') { // So do some really shoddy parsing here, assume the file is good if (buf[19] == '1') { res = new TimecodesV1(f); } else if (buf[19] == '2') { res = new TimecodesV2(f); } } fclose(f); return res; }