Documentation update.

This commit is contained in:
Moritz Bunkus 2004-11-13 20:56:19 +00:00
parent de3b877a8c
commit 6c16414ff9
3 changed files with 232 additions and 30 deletions

View File

@ -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;

View File

@ -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"

View File

@ -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"