mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 11:54:01 +00:00
Chapters are re-timecoded correctly in both cases (with and without file linking). Updated documentation about chapters.
This commit is contained in:
parent
b705914778
commit
5742bca3dc
@ -1,5 +1,7 @@
|
||||
2003-07-29 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvextract: Support for extracting chapter information.
|
||||
|
||||
* mkvmerge: Added support for simple chapter files (CHAPTER01=...,
|
||||
CHAPTER01NAME=Hello World etc).
|
||||
|
||||
|
128
doc/mkvmerge.1
128
doc/mkvmerge.1
@ -32,6 +32,10 @@ Write to the file '\fIout\fR'.
|
||||
.TP
|
||||
\fB\-\-title\fR <\fItitle\fR>
|
||||
Sets the general title for the output file, e.g. the movie name.
|
||||
.TP
|
||||
\fB\-\-chapters <\fIfile\fR>
|
||||
Read chapter information from the \fIfile\fR. See the section about chapters
|
||||
below for details.
|
||||
|
||||
.LP
|
||||
General output control (still global, advanced options):
|
||||
@ -407,6 +411,36 @@ in \fBmkvinfo\fR's output then please read the section about \fBDEFAULT
|
||||
VALUES\fR.
|
||||
|
||||
|
||||
.SH TRACK IDS
|
||||
.LP
|
||||
Some of the options for \fBmkvmerge\fR need a track ID to specify which track
|
||||
they should be applied to. Those track IDs are printed by the readers when
|
||||
demuxing the current input file, or if \fBmkvmerge\fR is called with the
|
||||
\fB\-\-identify\fR option. Track IDs are assigned like this:
|
||||
.TP
|
||||
*
|
||||
AVI files: The video track has the ID 0. All audio tracks get the ID 1, 2...
|
||||
.TP
|
||||
*
|
||||
AAC, AC3, MP3, SRT and WAV files: The one 'track' in that file gets the ID 0.
|
||||
.TP
|
||||
*
|
||||
Ogg/OGM files: The track's ID is its serial number as given in the Ogg stream
|
||||
header page.
|
||||
.TP
|
||||
*
|
||||
Matroska files: The track's ID is the track number as reported by \fBmkvinfo\fR
|
||||
or \fBmkvmerge \-\-identify\fR. It is \fBnot\fR the track UID.
|
||||
.LP
|
||||
The special track ID '-1' is a wildcard and applies the given switch to all
|
||||
tracks that are read from an input file. This was the bahviour of these
|
||||
switches prior to version 0.4.4.
|
||||
.LP
|
||||
The options that use the track IDs are: \fB\-\-atracks\fR, \fB\-\-vtracks\fR,
|
||||
\fB\-\-stracks\fR, \fB\-\-sync\fR, \fB\-\-default-track\fR, \fB\-\-cues\fR
|
||||
and \fB\-\-language\fR.
|
||||
|
||||
|
||||
.SH SUBTITLES
|
||||
.LP
|
||||
There are several text subtitle formats that can be embedded into Matroska.
|
||||
@ -437,10 +471,10 @@ markup is not supported correctly.
|
||||
Matroska supports file linking which simply says that a specific file is the
|
||||
predecessor or successsor of the current file. To be precise, it's not really
|
||||
the files that are linked but the Matroska segments. As most files will
|
||||
probably only put one Matroska segment into a file I simply say 'file linking'
|
||||
probably only contain one Matroska segment I simply say 'file linking'
|
||||
although 'segment linking' would be more appropriate.
|
||||
.LP
|
||||
Each segment is identified by a unique 128 bit wide segmend UID. This UID
|
||||
Each segment is identified by a unique 128 bit wide segment UID. This UID
|
||||
is automatically generated by \fBmkvmerge\fR. The linking is done primarily
|
||||
via putting the segment UIDs of the previous/next file into the segment
|
||||
header information. \fBmkvinfo(1)\fR prints these UIDs if it finds them.
|
||||
@ -470,36 +504,6 @@ with \'\fB\-\-link\-to\-next\fR\'. If splitting is not used then the one
|
||||
output file will be linked to both of the two UIDs.
|
||||
|
||||
|
||||
.SH TRACK IDS
|
||||
.LP
|
||||
Some of the options for \fBmkvmerge\fR need a track ID to specify which track
|
||||
they should be applied to. Those track IDs are printed by the readers when
|
||||
demuxing the current input file, or if \fBmkvmerge\fR is called with the
|
||||
\fB\-\-identify\fR option. Track IDs are assigned like this:
|
||||
.TP
|
||||
*
|
||||
AVI files: The video track has the ID 0. All audio tracks get the ID 1, 2...
|
||||
.TP
|
||||
*
|
||||
AAC, AC3, MP3, SRT and WAV files: The one 'track' in that file gets the ID 0.
|
||||
.TP
|
||||
*
|
||||
Ogg/OGM files: The track's ID is its serial number as given in the Ogg stream
|
||||
header page.
|
||||
.TP
|
||||
*
|
||||
Matroska files: The track's ID is the track number as reported by \fBmkvinfo\fR
|
||||
or \fBmkvmerge \-\-identify\fR. It is \fBnot\fR the track UID.
|
||||
.LP
|
||||
The special track ID '-1' is a wildcard and applies the given switch to all
|
||||
tracks that are read from an input file. This was the bahviour of these
|
||||
switches prior to version 0.4.4.
|
||||
.LP
|
||||
The options that use the track IDs are: \fB\-\-atracks\fR, \fB\-\-vtracks\fR,
|
||||
\fB\-\-stracks\fR, \fB\-\-sync\fR, \fB\-\-default-track\fR, \fB\-\-cues\fR
|
||||
and \fB\-\-language\fR.
|
||||
|
||||
|
||||
.SH DEFAULT VALUES
|
||||
.LP
|
||||
The Matroska specs say that some elements have a default value. Usually an
|
||||
@ -532,6 +536,47 @@ $ \fBmkvmerge -o output.mkv -A video.avi sound.ogg \-\-attachment\-description
|
||||
\-\-attach\-file really_cool_font.ttf
|
||||
|
||||
|
||||
.SH CHAPTERS
|
||||
.LP
|
||||
The Matroska chapter system is more powerful than the old known system used
|
||||
by OGMs. The full specs can be found at
|
||||
.URL http://cvs.corecodec.org/cgi-bin/viewcvs.cgi/*checkout*/matroska/doc/website/technical/specs/chapters/index.html
|
||||
.LP
|
||||
\fBmkvmerge\fR's chapter support is still a bit limited, though. At the moment
|
||||
it only supports reading chapter data in the same format that the OGM tools
|
||||
expect. It looks basically like this:
|
||||
.LP
|
||||
CHAPTER01=00:00:00.000
|
||||
.br
|
||||
CHAPTER01NAME=Intro
|
||||
.br
|
||||
CHAPTER02=00:02:30.000
|
||||
.br
|
||||
CHAPTER02NAME=Baby prepares to rock
|
||||
.br
|
||||
CHAPTER03=00:02:42.300
|
||||
.br
|
||||
CHAPTER03NAME=Baby rocks the house
|
||||
.LP
|
||||
\fBmkvmerge\fR will transform every pair or lines (CHAPTERxx and CHAPTERxxNAME)
|
||||
into one Matroska \fIChapterAtom\fR. It does not set any
|
||||
\fIChapterTrackNumber\fR which means that the chapters all apply to all
|
||||
tracks in the file.
|
||||
.LP
|
||||
When splitting files \fBmkvmerge\fR will correctly adjust the chapters as
|
||||
well. This means that each file only includes the chapter entries that
|
||||
apply to it, and that the timecodes will be offset to match the new timecodes
|
||||
of each output file.
|
||||
.LP
|
||||
Another shortcoming is that \fBmkvmerge\fR will silently discards chapters
|
||||
found in source files - e.g. when reading them from an OGM file or another
|
||||
Matroska file. You can use \fBmkvextract\fR to export chapters from another
|
||||
Matroska file and use the result with \fBmkvmerge\fR.
|
||||
.LP
|
||||
The upcoming version of \fBmkvmerge\fR will address most of the shortcomings
|
||||
mentioned above.
|
||||
|
||||
|
||||
.SH NOTES
|
||||
.LP
|
||||
What works:
|
||||
@ -579,22 +624,19 @@ taken from other OGM files.
|
||||
.TP
|
||||
*
|
||||
SSA/ASS subtitles from SSA/ASS files
|
||||
.TP
|
||||
*
|
||||
Simple chapters.
|
||||
.TP
|
||||
*
|
||||
Full tags support.
|
||||
.LP
|
||||
What not works:
|
||||
.TP
|
||||
*
|
||||
Manual audio synchronization for PCM sound (who needs it anyway?)
|
||||
.LP
|
||||
Planned functionality:
|
||||
.TP
|
||||
*
|
||||
support for other subtitle formats
|
||||
.TP
|
||||
*
|
||||
chapter information
|
||||
.TP
|
||||
*
|
||||
a lot of other stuff, like tags, user information etc.
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
.I mkvmerge
|
||||
was written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
|
@ -103,7 +103,7 @@ static bool probe_simple_chapters(mm_text_io_c *in) {
|
||||
// CHAPTER01NAME=Hallo Welt
|
||||
|
||||
static KaxChapters *parse_simple_chapters(mm_text_io_c *in, int64_t min_tc,
|
||||
int64_t max_tc) {
|
||||
int64_t max_tc, int64_t offset) {
|
||||
KaxChapters *chaps;
|
||||
KaxEditionEntry *edition;
|
||||
KaxChapterAtom *atom;
|
||||
@ -119,6 +119,8 @@ static KaxChapters *parse_simple_chapters(mm_text_io_c *in, int64_t min_tc,
|
||||
atom = NULL;
|
||||
edition = NULL;
|
||||
|
||||
printf("off: %lld\n", offset);
|
||||
|
||||
while (in->getline2(line)) {
|
||||
strip(line);
|
||||
if (line.length() == 0)
|
||||
@ -158,7 +160,7 @@ static KaxChapters *parse_simple_chapters(mm_text_io_c *in, int64_t min_tc,
|
||||
*static_cast<EbmlUInteger *>(&GetChild<KaxChapterUID>(*atom)) =
|
||||
create_unique_uint32();
|
||||
*static_cast<EbmlUInteger *>(&GetChild<KaxChapterTimeStart>(*atom)) =
|
||||
(start - min_tc) * 1000000;
|
||||
(start - offset) * 1000000;
|
||||
display = &GetChild<KaxChapterDisplay>(*atom);
|
||||
*static_cast<EbmlUnicodeString *>
|
||||
(&GetChild<KaxChapterString>(*display)) =
|
||||
@ -178,12 +180,13 @@ static bool probe_xml_chapters(mm_text_io_c *) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static KaxChapters *parse_xml_chapters(mm_text_io_c *, int64_t, int64_t) {
|
||||
static KaxChapters *parse_xml_chapters(mm_text_io_c *, int64_t, int64_t,
|
||||
int64_t) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
KaxChapters *parse_chapters(const char *file_name, int64_t min_tc,
|
||||
int64_t max_tc) {
|
||||
int64_t max_tc, int64_t offset) {
|
||||
mm_text_io_c *in;
|
||||
|
||||
try {
|
||||
@ -194,10 +197,10 @@ KaxChapters *parse_chapters(const char *file_name, int64_t min_tc,
|
||||
}
|
||||
|
||||
if (probe_simple_chapters(in))
|
||||
return parse_simple_chapters(in, min_tc, max_tc);
|
||||
return parse_simple_chapters(in, min_tc, max_tc, offset);
|
||||
|
||||
if (probe_xml_chapters(in))
|
||||
return parse_xml_chapters(in, min_tc, max_tc);
|
||||
return parse_xml_chapters(in, min_tc, max_tc, offset);
|
||||
|
||||
mxprint(stderr, "Error: Unknown file format for '%s'. It does not contain "
|
||||
"a supported chapter format.\n", file_name);
|
||||
|
@ -28,7 +28,7 @@
|
||||
using namespace libmatroska;
|
||||
|
||||
KaxChapters *parse_chapters(const char *file_name, int64_t min_tc = 0,
|
||||
int64_t max_tc = -1);
|
||||
int64_t max_tc = -1, int64_t offset = 0);
|
||||
|
||||
void write_chapters_xml(KaxChapters *chapters, FILE *out);
|
||||
|
||||
|
@ -666,3 +666,7 @@ int64_t cluster_helper_c::get_max_timecode() {
|
||||
int64_t cluster_helper_c::get_first_timecode() {
|
||||
return first_timecode;
|
||||
}
|
||||
|
||||
int64_t cluster_helper_c::get_timecode_offset() {
|
||||
return timecode_offset;
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
int get_cluster_content_size();
|
||||
int64_t get_max_timecode();
|
||||
int64_t get_first_timecode();
|
||||
int64_t get_timecode_offset();
|
||||
void find_next_splitpoint();
|
||||
int get_next_splitpoint();
|
||||
|
||||
|
@ -1799,6 +1799,7 @@ void create_next_output_file(bool last_file, bool first_file) {
|
||||
void finish_file() {
|
||||
int i;
|
||||
KaxChapters *chapters_here;
|
||||
int64_t start, end, offset;
|
||||
|
||||
// Render the cues.
|
||||
if (write_cues && cue_writing_requested) {
|
||||
@ -1819,9 +1820,14 @@ void finish_file() {
|
||||
out->restore_pos();
|
||||
|
||||
if ((kax_chapters != NULL) && (pass > 0)) {
|
||||
chapters_here = parse_chapters(chapter_file_name,
|
||||
cluster_helper->get_first_timecode(),
|
||||
cluster_helper->get_max_timecode());
|
||||
if (no_linking)
|
||||
offset = cluster_helper->get_timecode_offset();
|
||||
else
|
||||
offset = 0;
|
||||
start = cluster_helper->get_first_timecode() + offset;
|
||||
end = cluster_helper->get_max_timecode() + offset;
|
||||
|
||||
chapters_here = parse_chapters(chapter_file_name, start, end, offset);
|
||||
kax_chapters_void->ReplaceWith(*chapters_here, *out, true);
|
||||
delete kax_chapters_void;
|
||||
kax_chapters_void = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user