mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 11:54:01 +00:00
Documentation update.
This commit is contained in:
parent
de3b877a8c
commit
6c16414ff9
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/** \brief chapter parser and helper functions
|
||||
*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
@ -6,16 +7,16 @@
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
* \file
|
||||
* \version $Id$
|
||||
*
|
||||
* chapter parser/writer functions
|
||||
*
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
* \author Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include <matroska/KaxChapters.h>
|
||||
@ -27,18 +28,26 @@
|
||||
using namespace std;
|
||||
using namespace libmatroska;
|
||||
|
||||
/** The default language for all chapter entries that don't have their own. */
|
||||
string default_chapter_language;
|
||||
/** The default country for all chapter entries that don't have their own. */
|
||||
string default_chapter_country;
|
||||
|
||||
// {{{ defines for chapter line recognition
|
||||
|
||||
/** Is the current char an equal sign? */
|
||||
#define isequal(s) (*(s) == '=')
|
||||
/** Is the current char a colon? */
|
||||
#define iscolon(s) (*(s) == ':')
|
||||
/** Is the current char a dot? */
|
||||
#define isdot(s) (*(s) == '.')
|
||||
/** Do we have two consecutive digits? */
|
||||
#define istwodigits(s) (isdigit(*(s)) && isdigit(*(s + 1)))
|
||||
/** Do we have three consecutive digits? */
|
||||
#define isthreedigits(s) (istwodigits(s) && isdigit(*(s + 2)))
|
||||
/** Does \c s point to the string "CHAPTER"? */
|
||||
#define ischapter(s) (!strncmp("CHAPTER", (s), 7))
|
||||
/** Does \c s point to the string "NAME"? */
|
||||
#define isname(s) (!strncmp("NAME", (s), 4))
|
||||
/** Does \c s point to a valid OGM style chapter timecode entry? */
|
||||
#define ischapterline(s) ((strlen(s) == 22) && \
|
||||
ischapter(s) && \
|
||||
istwodigits(s + 7) && \
|
||||
@ -50,6 +59,7 @@ string default_chapter_country;
|
||||
istwodigits(s + 16) && \
|
||||
isdot(s + 18) && \
|
||||
isthreedigits(s + 19))
|
||||
/** Does \c s point to a valid OGM style chapter name entry? */
|
||||
#define ischapternameline(s) ((strlen(s) >= 15) && \
|
||||
ischapter(s) && \
|
||||
istwodigits(s + 7) && \
|
||||
@ -57,9 +67,16 @@ string default_chapter_country;
|
||||
isequal(s + 13) && \
|
||||
!isblanktab(*(s + 14)))
|
||||
|
||||
// }}}
|
||||
// {{{ helper functions
|
||||
|
||||
/** \brief Format an error message and throw an exception.
|
||||
*
|
||||
* A \c printf like function that throws an ::error_c exception with
|
||||
* the formatted message.
|
||||
*
|
||||
* The parameters are checked for validity.
|
||||
*
|
||||
* \param fmt The \c printf like format.
|
||||
* \param ... Optional arguments for the format.
|
||||
*/
|
||||
static void
|
||||
chapter_error(const char *fmt,
|
||||
...) {
|
||||
@ -68,6 +85,8 @@ chapter_error(const char *fmt,
|
||||
char *new_error;
|
||||
int len;
|
||||
|
||||
assert(fmt != NULL);
|
||||
|
||||
len = strlen("Error: Simple chapter parser: ");
|
||||
va_start(ap, fmt);
|
||||
fix_format(fmt, new_fmt);
|
||||
@ -80,14 +99,25 @@ chapter_error(const char *fmt,
|
||||
throw error_c(new_error, true);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ simple chapter parsing
|
||||
|
||||
/** \brief Reads the start of a file and checks for OGM style comments.
|
||||
*
|
||||
* The first lines are read. OGM style comments are recognized if the first
|
||||
* non-empty line contains <tt>CHAPTER01=...</tt> and the first non-empty
|
||||
* line afterwards contains <tt>CHAPTER01NAME=...</tt>.
|
||||
*
|
||||
* The parameters are checked for validity.
|
||||
*
|
||||
* \param in The file to read from.
|
||||
*
|
||||
* \return \c true if the file contains OGM style comments and \c false
|
||||
* otherwise.
|
||||
*/
|
||||
bool
|
||||
probe_simple_chapters(mm_text_io_c *in) {
|
||||
string line;
|
||||
|
||||
assert(in != NULL);
|
||||
|
||||
in->setFilePointer(0);
|
||||
while (in->getline2(line)) {
|
||||
strip(line);
|
||||
@ -120,6 +150,30 @@ probe_simple_chapters(mm_text_io_c *in) {
|
||||
// CHAPTER01=00:00:00.000
|
||||
// CHAPTER01NAME=Hallo Welt
|
||||
|
||||
/** \brief Parse simple OGM style comments
|
||||
*
|
||||
* The file \a in is read. The content is assumed to be OGM style comments.
|
||||
*
|
||||
* The parameters are checked for validity.
|
||||
*
|
||||
* \param in The text file to read from.
|
||||
* \param min_tc An optional timecode. If both \a min_tc and \a max_tc are
|
||||
* given then only those chapters that lie in the timerange
|
||||
* <tt>[min_tc..max_tc]</tt> are kept.
|
||||
* \param max_tc An optional timecode. If both \a min_tc and \a max_tc are
|
||||
* given then only those chapters that lie in the timerange
|
||||
* <tt>[min_tc..max_tc]</tt> are kept.
|
||||
* \param offset An optional offset that is subtracted from all start and
|
||||
* end timecodes after the timerange check has been made.
|
||||
* \param language This language is added as the \c KaxChapterLanguage
|
||||
* for all entries.
|
||||
* \param country This country is added as the \c KaxChapterCountry for
|
||||
* all entries.
|
||||
* \param exception_on_error If set to \c true then an exception is thrown
|
||||
* if an error occurs. Otherwise \c NULL will be returned.
|
||||
*
|
||||
* \return The chapters parsed from the file or \c NULL if an error occured.
|
||||
*/
|
||||
KaxChapters *
|
||||
parse_simple_chapters(mm_text_io_c *in,
|
||||
int64_t min_tc,
|
||||
@ -138,6 +192,8 @@ parse_simple_chapters(mm_text_io_c *in,
|
||||
bool do_convert;
|
||||
UTFstring wchar_string;
|
||||
|
||||
assert(in != NULL);
|
||||
|
||||
in->setFilePointer(0);
|
||||
chaps = new KaxChapters;
|
||||
|
||||
@ -248,8 +304,17 @@ parse_simple_chapters(mm_text_io_c *in,
|
||||
return chaps;
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
/** \brief Probe a file for different chapter formats and parse the file.
|
||||
*
|
||||
* The file \a file_name is opened and checked for supported chapter formats.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \see ::parse_chapters(mm_text_io_c *in,int64_t min_tc,int64_t max_tc, int64_t offset,const string &language,const string &charset,bool exception_on_error,bool *is_simple_format,KaxTags **tags)
|
||||
* for a full description of its parameters and return values.
|
||||
*
|
||||
* \param file_name The file name that is to be opened.
|
||||
*/
|
||||
KaxChapters *
|
||||
parse_chapters(const string &file_name,
|
||||
int64_t min_tc,
|
||||
@ -283,6 +348,38 @@ parse_chapters(const string &file_name,
|
||||
return result;
|
||||
}
|
||||
|
||||
/** \brief Probe a file for different chapter formats and parse the file.
|
||||
*
|
||||
* The file \a in is checked for supported chapter formats. These include
|
||||
* simple OGM style chapters, CUE sheets and mkvtoolnix' own XML chapter
|
||||
* format.
|
||||
*
|
||||
* The parameters are checked for validity.
|
||||
*
|
||||
* \param in The text file to read from.
|
||||
* \param min_tc An optional timecode. If both \a min_tc and \a max_tc are
|
||||
* given then only those chapters that lie in the timerange
|
||||
* <tt>[min_tc..max_tc]</tt> are kept.
|
||||
* \param max_tc An optional timecode. If both \a min_tc and \a max_tc are
|
||||
* given then only those chapters that lie in the timerange
|
||||
* <tt>[min_tc..max_tc]</tt> are kept.
|
||||
* \param offset An optional offset that is subtracted from all start and
|
||||
* end timecodes after the timerange check has been made.
|
||||
* \param language This language is added as the \c KaxChapterLanguage
|
||||
* for entries that don't specifiy it.
|
||||
* \param country This country is added as the \c KaxChapterCountry for
|
||||
* entries that don't specifiy it.
|
||||
* \param exception_on_error If set to \c true then an exception is thrown
|
||||
* if an error occurs. Otherwise \c NULL will be returned.
|
||||
* \param is_simple_format This boolean will be set to \c true if the chapter
|
||||
* format is either the OGM style format or a CUE sheet.
|
||||
* \param tags When parsing a CUE sheet tags will be created along with the
|
||||
* chapter entries. These tags will be stored in this parameter.
|
||||
*
|
||||
* \return The chapters parsed from the file or \c NULL if an error occured.
|
||||
*
|
||||
* \see ::parse_chapters(const string &file_name,int64_t min_tc,int64_t max_tc, int64_t offset,const string &language,const string &charset,bool exception_on_error,bool *is_simple_format,KaxTags **tags)
|
||||
*/
|
||||
KaxChapters *
|
||||
parse_chapters(mm_text_io_c *in,
|
||||
int64_t min_tc,
|
||||
@ -293,6 +390,8 @@ parse_chapters(mm_text_io_c *in,
|
||||
bool exception_on_error,
|
||||
bool *is_simple_format,
|
||||
KaxTags **tags) {
|
||||
assert(in != NULL);
|
||||
|
||||
try {
|
||||
if (probe_simple_chapters(in)) {
|
||||
if (is_simple_format != NULL)
|
||||
@ -323,8 +422,15 @@ parse_chapters(mm_text_io_c *in,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Some helper functions for easy access to libmatroska's chapter structure.
|
||||
|
||||
/** \brief Get the start timecode for a chapter atom.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param atom The atom for which the start timecode should be returned.
|
||||
*
|
||||
* \return The start timecode or \c -1 if the atom doesn't contain such a
|
||||
* child element.
|
||||
*/
|
||||
int64_t
|
||||
get_chapter_start(KaxChapterAtom &atom) {
|
||||
KaxChapterTimeStart *start;
|
||||
@ -335,6 +441,15 @@ get_chapter_start(KaxChapterAtom &atom) {
|
||||
return uint64(*static_cast<EbmlUInteger *>(start));
|
||||
}
|
||||
|
||||
/** \brief Get the name for a chapter atom.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param atom The atom for which the name should be returned.
|
||||
*
|
||||
* \return The atom's name UTF-8 coded or \c "" if the atom doesn't contain
|
||||
* such a child element.
|
||||
*/
|
||||
string
|
||||
get_chapter_name(KaxChapterAtom &atom) {
|
||||
KaxChapterDisplay *display;
|
||||
@ -349,6 +464,15 @@ get_chapter_name(KaxChapterAtom &atom) {
|
||||
return UTFstring_to_cstrutf8(UTFstring(*name));
|
||||
}
|
||||
|
||||
/** \brief Get the unique ID for a chapter atom.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param atom The atom for which the unique ID should be returned.
|
||||
*
|
||||
* \return The ID or \c -1 if the atom doesn't contain such a
|
||||
* child element.
|
||||
*/
|
||||
int64_t
|
||||
get_chapter_uid(KaxChapterAtom &atom) {
|
||||
KaxChapterUID *uid;
|
||||
@ -359,6 +483,19 @@ get_chapter_uid(KaxChapterAtom &atom) {
|
||||
return uint64(*static_cast<EbmlUInteger *>(uid));
|
||||
}
|
||||
|
||||
/** \brief Add missing mandatory elements
|
||||
*
|
||||
* The Matroska specs and \c libmatroska say that several elements are
|
||||
* mandatory. This function makes sure that they all exist by adding them
|
||||
* with their default values if they're missing. It works recursively. See
|
||||
* \url http://www.matroska.org/technical/specs/chapters/index.html
|
||||
* for a list or mandatory elements.
|
||||
*
|
||||
* The parameters are checked for validity.
|
||||
*
|
||||
* \param e An element that really is an \c EbmlMaster. \a e's children
|
||||
* should be checked.
|
||||
*/
|
||||
void
|
||||
fix_mandatory_chapter_elements(EbmlElement *e) {
|
||||
if (e == NULL)
|
||||
@ -410,6 +547,21 @@ fix_mandatory_chapter_elements(EbmlElement *e) {
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Remove all chapter atoms that are outside of a time range
|
||||
*
|
||||
* All chapter atoms that lie completely outside the timecode range
|
||||
* given with <tt>[min_tc..max_tc]</tt> are deleted. This is the workhorse
|
||||
* for ::select_chapters_in_timeframe
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param min_tc The minimum timecode to accept.
|
||||
* \param max_tc The maximum timecode to accept.
|
||||
* \param offset This value is subtracted from both the start and end timecode
|
||||
* for each chapter after the decision whether or not to keep it has been
|
||||
* made.
|
||||
* \param m The master containing the elements to check.
|
||||
*/
|
||||
static void
|
||||
remove_entries(int64_t min_tc,
|
||||
int64_t max_tc,
|
||||
@ -473,6 +625,22 @@ remove_entries(int64_t min_tc,
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Remove all chapter atoms that are outside of a time range
|
||||
*
|
||||
* All chapter atoms that lie completely outside the timecode range
|
||||
* given with <tt>[min_tc..max_tc]</tt> are deleted.
|
||||
*
|
||||
* The parameters are checked for validity.
|
||||
*
|
||||
* \param chapters The chapters to check.
|
||||
* \param min_tc The minimum timecode to accept.
|
||||
* \param max_tc The maximum timecode to accept.
|
||||
* \param offset This value is subtracted from both the start and end timecode
|
||||
* for each chapter after the decision whether or not to keep it has been
|
||||
* made.
|
||||
*
|
||||
* \return \a chapters if there are entries left and \c NULL otherwise.
|
||||
*/
|
||||
KaxChapters *
|
||||
select_chapters_in_timeframe(KaxChapters *chapters,
|
||||
int64_t min_tc,
|
||||
@ -481,6 +649,12 @@ select_chapters_in_timeframe(KaxChapters *chapters,
|
||||
uint32_t i, k, num_atoms;
|
||||
KaxEditionEntry *eentry;
|
||||
|
||||
// Check the parameters.
|
||||
if (chapters == NULL)
|
||||
return NULL;
|
||||
assert(min_tc < max_tc);
|
||||
|
||||
// Remove the atoms that are outside of the requested range.
|
||||
for (i = 0; i < chapters->ListSize(); i++) {
|
||||
if (dynamic_cast<KaxEditionEntry *>((*chapters)[i]) == NULL)
|
||||
continue;
|
||||
@ -488,6 +662,8 @@ select_chapters_in_timeframe(KaxChapters *chapters,
|
||||
*static_cast<EbmlMaster *>((*chapters)[i]));
|
||||
}
|
||||
|
||||
// Count the number of atoms in each edition. Delete editions without
|
||||
// any atom in them.
|
||||
i = 0;
|
||||
while (i < chapters->ListSize()) {
|
||||
if (dynamic_cast<KaxEditionEntry *>((*chapters)[i]) == NULL) {
|
||||
@ -508,6 +684,7 @@ select_chapters_in_timeframe(KaxChapters *chapters,
|
||||
i++;
|
||||
}
|
||||
|
||||
// If we don't even have one edition then delete the chapters themselves.
|
||||
if (chapters->ListSize() == 0) {
|
||||
delete chapters;
|
||||
chapters = NULL;
|
||||
@ -516,6 +693,16 @@ select_chapters_in_timeframe(KaxChapters *chapters,
|
||||
return chapters;
|
||||
}
|
||||
|
||||
/** \brief Find an edition with a specific UID.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param chapters The chapters in which to look for the edition.
|
||||
* \param uid The requested unique edition ID. The special value \c 0
|
||||
* results in the first edition being returned.
|
||||
*
|
||||
* \return A pointer to the edition or \c NULL if none has been found.
|
||||
*/
|
||||
KaxEditionEntry *
|
||||
find_edition_with_uid(KaxChapters &chapters,
|
||||
uint64_t uid) {
|
||||
@ -538,6 +725,16 @@ find_edition_with_uid(KaxChapters &chapters,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \brief Find a chapter atom with a specific UID.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param chapters The chapters in which to look for the atom.
|
||||
* \param uid The requested unique atom ID. The special value \c 0 results in
|
||||
* the first atom in the first edition being returned.
|
||||
*
|
||||
* \return A pointer to the atom or \c NULL if none has been found.
|
||||
*/
|
||||
KaxChapterAtom *
|
||||
find_chapter_with_uid(KaxChapters &chapters,
|
||||
uint64_t uid) {
|
||||
@ -579,6 +776,8 @@ find_chapter_with_uid(KaxChapters &chapters,
|
||||
*
|
||||
* After processing \a src will be empty.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param dst The container the atoms and editions will be put into.
|
||||
* \param src The container the atoms and editions will be taken from.
|
||||
*/
|
||||
@ -623,18 +822,19 @@ move_chapters_by_edition(KaxChapters &dst,
|
||||
* All start and end timecodes are adjusted by an offset. This is done
|
||||
* recursively.
|
||||
*
|
||||
* Its parameters don't have to be checked for validity.
|
||||
*
|
||||
* \param master A master containint the elements to adjust. This can be
|
||||
* a KaxChapters, KaxEditionEntry or KaxChapterAtom object.
|
||||
* a KaxChapters, KaxEditionEntry or KaxChapterAtom object.
|
||||
* \param offset The offset to add to each timecode. Can be negative. If
|
||||
* the resulting timecode would be smaller than zero then it will be set
|
||||
* to zero.
|
||||
* the resulting timecode would be smaller than zero then it will be set
|
||||
* to zero.
|
||||
*/
|
||||
void
|
||||
adjust_chapter_timecodes(EbmlMaster &master,
|
||||
int64_t offset) {
|
||||
int i;
|
||||
|
||||
|
||||
for (i = 0; i < master.ListSize(); i++) {
|
||||
KaxChapterAtom *atom;
|
||||
KaxChapterTimeStart *start;
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/** \brief command line parsing
|
||||
*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
@ -6,10 +7,10 @@
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
* \file
|
||||
* \version $Id$
|
||||
*
|
||||
* command line parameter parsing
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
* \author Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include "os.h"
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/** \brief output handling
|
||||
*
|
||||
* mkvmerge -- utility for splicing together matroska files
|
||||
* from component media subtypes
|
||||
*
|
||||
@ -6,10 +7,10 @@
|
||||
* see the file COPYING for details
|
||||
* or visit http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* $Id$
|
||||
* \file
|
||||
* \version $Id$
|
||||
*
|
||||
* output handling
|
||||
* Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
* \author Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include "os.h"
|
||||
|
Loading…
Reference in New Issue
Block a user