diff --git a/ChangeLog b/ChangeLog index a3b48e6ee..fd8ce0890 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2004-09-30 Moritz Bunkus + + * mkvmerge: new feature: The CUE sheet parser now accepts INDEX + lines with indices from 00 up to 99 and implements the Red Book + specification for audio CDs that way. Patch by Vegard Pettersen + . + 2004-09-28 Moritz Bunkus * mkvmerge, mkvextract: bug fix: ASS was handled like SSA which is diff --git a/src/common/chapter_parser_cue.cpp b/src/common/chapter_parser_cue.cpp index 4ae70170b..32efbf0a9 100644 --- a/src/common/chapter_parser_cue.cpp +++ b/src/common/chapter_parser_cue.cpp @@ -104,8 +104,9 @@ cue_entries_to_chapter_name(string &performer, typedef struct { int num; - int64_t start_00; - int64_t start_01; + int64_t start_of_track; + vector start_indices; + bool index00_missing; int64_t end; int64_t min_tc; int64_t max_tc; @@ -245,28 +246,18 @@ static void add_subchapters_for_index_entries(cue_parser_args_t &a) { KaxChapterAtom *atom; KaxChapterDisplay *display; + int i, offset; - if ((a.start_00 == -1) && (a.start_01 == -1)) + if (a.start_indices.empty()) return; + if (a.index00_missing) + offset = 1; + else + offset = 0; + atom = NULL; - if (a.start_00 != -1) { - atom = &GetChild(*a.atom); - *static_cast(&GetChild(*atom)) = - create_unique_uint32(UNIQUE_CHAPTER_IDS); - *static_cast(&GetChild(*atom)) = - a.start_00 - a.offset; - - display = &GetChild(*atom); - *static_cast(&GetChild(*display)) = - cstrutf8_to_UTFstring("INDEX 00"); - *static_cast(&GetChild(*display)) = - "eng"; - - *static_cast(&GetChild(*atom)) = 1; - } - - if (a.start_01 != -1) { + for (i = 0; i < a.start_indices.size(); i++) { if (atom == NULL) atom = &GetChild(*a.atom); else @@ -275,11 +266,11 @@ add_subchapters_for_index_entries(cue_parser_args_t &a) { *static_cast(&GetChild(*atom)) = create_unique_uint32(UNIQUE_CHAPTER_IDS); *static_cast(&GetChild(*atom)) = - a.start_01 - a.offset; + a.start_indices[i] - a.offset; display = &GetChild(*atom); *static_cast(&GetChild(*display)) = - cstrutf8_to_UTFstring("INDEX 01"); + cstrutf8_to_UTFstring(mxsprintf("INDEX %02d", i + offset).c_str()); *static_cast(&GetChild(*display)) = "eng"; @@ -293,17 +284,12 @@ add_elements_for_cue_entry(cue_parser_args_t &a, KaxChapterDisplay *display; UTFstring wchar_string; uint32_t cuid; - int64_t start; - if ((a.start_00 == -1) && (a.start_01 == -1)) + if (a.start_indices.empty()) mxerror("Cue sheet parser: No INDEX entry found for the previous " "TRACK entry (current line: %d)\n", a.line_num); - if (a.start_01 != -1) - start = a.start_01; - else - start = a.start_00; - - if (!((start >= a.min_tc) && ((start <= a.max_tc) || (a.max_tc == -1)))) + if (!((a.start_indices[0] >= a.min_tc) && + ((a.start_indices[0] <= a.max_tc) || (a.max_tc == -1)))) return; if (a.edition == NULL) { @@ -320,7 +306,7 @@ add_elements_for_cue_entry(cue_parser_args_t &a, *static_cast(&GetChild(*a.atom)) = cuid; *static_cast(&GetChild(*a.atom)) = - start - a.offset; + a.start_of_track - a.offset; display = &GetChild(*a.atom); @@ -378,7 +364,6 @@ parse_cue_chapters(mm_text_io_c *in, const char *charset, bool exception_on_error, KaxTags **tags) { - int index, min, sec, frames; cue_parser_args_t a; string line; @@ -407,8 +392,7 @@ parse_cue_chapters(mm_text_io_c *in, a.edition = NULL; a.num = 0; a.line_num = 0; - a.start_00 = -1; - a.start_01 = -1; + a.start_of_track = -1; a.edition_uid = create_unique_uint32(UNIQUE_EDITION_IDS); try { while (in->getline2(line)) { @@ -433,22 +417,39 @@ parse_cue_chapters(mm_text_io_c *in, a.title = get_quoted(line, 6); } else if (starts_with_case(line, "index ")) { + int index, min, sec, frames; + bool index_ok; + line.erase(0, 6); strip(line); if (sscanf(line.c_str(), "%d %d:%d:%d", &index, &min, &sec, &frames) < 4) mxerror("Cue sheet parser: Invalid INDEX entry in line %d.\n", a.line_num); - if ((a.start_00 == -1) && (index == 0)) - a.start_00 = min * 60 * 1000000000ll + sec * 1000000000ll + frames * - 1000000000ll / 75; - else if ((a.start_01 == -1) && (index == 1)) - a.start_01 = min * 60 * 1000000000ll + sec * 1000000000ll + frames * - 1000000000ll / 75; + + index_ok = false; + if ((index >= 0) && (index <= 99)) { + if ((a.start_indices.size() == 0) && (index == 1)) + a.index00_missing = true; + if ((a.start_indices.size() == index) || + ((a.start_indices.size() == (index - 1)) && a.index00_missing)) { + int64_t timestamp = min * 60 * 1000000000ll + sec * 1000000000ll + + frames * 1000000000ll / 75; + a.start_indices.push_back(timestamp); + if ((index == 1) || (index == 0)) + a.start_of_track = timestamp; + index_ok = true; + } + } + + if (!index_ok) + mxerror("Cue sheet parser: Invalid INDEX number (got %d, " + "expected %d) in line %d,\n", + index, a.start_indices.size(), a.line_num); } else if (starts_with_case(line, "track ")) { - if ((line.length() < 5) || strcasecmp(&line[line.length() - 5], - "audio")) + if ((line.length() < 5) || + strcasecmp(&line[line.length() - 5], "audio")) continue; if (a.num >= 1) @@ -457,9 +458,9 @@ parse_cue_chapters(mm_text_io_c *in, add_tag_for_global_cue_settings(a, tags); a.num++; - - a.start_00 = -1; - a.start_01 = -1; + a.start_of_track = -1; + a.start_indices.clear(); + a.index00_missing = false; a.performer = ""; a.title = ""; a.isrc = ""; diff --git a/src/extract/cuesheets.cpp b/src/extract/cuesheets.cpp index 7bd413bf8..90dea49e3 100644 --- a/src/extract/cuesheets.cpp +++ b/src/extract/cuesheets.cpp @@ -182,7 +182,7 @@ get_chapter_index(int idx, int i; string sidx; - sidx = mxsprintf("INDEX 0%d", idx); + sidx = mxsprintf("INDEX %02d", idx); for (i = 0; i < atom.ListSize(); i++) if ((EbmlId(*atom[i]) == KaxChapterAtom::ClassInfos.GlobalId) && (get_chapter_name(*static_cast(atom[i])) == sidx)) @@ -281,9 +281,10 @@ write_cuesheet(const char *file_name, mm_io_c &out) { KaxTag *tag; string s; - int i; - int64_t index_00, index_01; - + int i, j; + int64_t temp_index; + vector indices; + if (chapters.ListSize() == 0) return; @@ -311,37 +312,28 @@ write_cuesheet(const char *file_name, print_if_available("ARTIST", " PERFORMER \"%s\"\n"); print_if_available("ISRC", " ISRC %s\n"); print_if_available("CDAUDIO_TRACK_FLAGS", " FLAGS %s\n"); - index_00 = get_chapter_index(0, atom); - index_01 = get_chapter_index(1, atom); - if (index_01 == -1) { - index_01 = get_chapter_start(atom); - if (index_01 == -1) - index_01 = 0; - } - if (index_00 != -1) - out.printf(" INDEX 00 %02lld:%02lld:%02lld\n", - index_00 / 1000000 / 1000 / 60, - (index_00 / 1000000 / 1000) % 60, - irnd((double)(index_00 % 1000000000ll) * 75.0 / + + j = 0; + do { + if ((temp_index = get_chapter_index(j, atom)) != -1) + indices.push_back(temp_index); + j++; + } while ((temp_index != -1) && (j <= 99)); + + for (j = 0; j < indices.size(); j++) { + out.printf(" INDEX %02d %02lld:%02lld:%02lld\n", + j, + indices[j] / 1000000 / 1000 / 60, + (indices[j] / 1000000 / 1000) % 60, + irnd((double)(indices[j] % 1000000000ll) * 75.0 / 1000000000.0)); - out.printf(" INDEX 01 %02lld:%02lld:%02lld\n", - index_01 / 1000000 / 1000 / 60, - (index_01 / 1000000 / 1000) % 60, - irnd((double)(index_01 % 1000000000ll) * 75.0 / - 1000000000.0)); + } + indices.clear(); + print_if_available("DATE", " REM DATE \"%s\"\n"); print_if_available("GENRE", " REM GENRE \"%s\"\n"); print_comments(" ", *tag, out); - } else { - index_01 = get_chapter_start(atom); - out.printf(" TITLE \"%s\"\n", - get_chapter_name(atom).c_str()); - out.printf(" INDEX 01 %02lld:%02lld:%02lld\n", - index_01 / 1000000 / 1000 / 60, - (index_01 / 1000000 / 1000) % 60, - irnd((double)(index_01 % 1000000000ll) * 75.0 / - 1000000000.0)); - } + } } }