mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 11:54:01 +00:00
Added support for attaching files to the output file(s).
This commit is contained in:
parent
bf83058489
commit
666a004d22
@ -1,5 +1,8 @@
|
||||
2003-07-14 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: Added support for attaching files to the output
|
||||
file(s).
|
||||
|
||||
* mkvinfo: Support for the elements dealing with attachments
|
||||
(KaxAttachments, KaxAttached, KaxFileDescription, KaxFileName,
|
||||
KaxMimeType, KaxFileData).
|
||||
|
@ -1,18 +1,23 @@
|
||||
.TH MKVMERGE "1" "June 2003" "mkvmerge v0.5.0" "User Commands"
|
||||
|
||||
|
||||
.SH NAME
|
||||
mkvmerge \- Merge multimedia streams into a Matroska file
|
||||
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B mkvmerge
|
||||
[\fIglobal options\fR] \-o \fIout\fR [\fIoptions\fR] <file1> [[\fIoptions\fR] <file2> ...] [@optionsfile]
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
This program takes the input from several media files and joins
|
||||
their streams (all of them or just a selection) into a Matroska file.
|
||||
.UR http://www.matroska.org/
|
||||
.UE
|
||||
|
||||
|
||||
.LP
|
||||
Global options:
|
||||
.TP
|
||||
@ -87,6 +92,35 @@ section \fBFILE LINKING\fR below for details.
|
||||
\fB\-\-link\-to\-next\fR <\fIUID\fR>
|
||||
Links the last output file to the segment with the given \fIUID\fR. See the
|
||||
section \fBFILE LINKING\fR below for details.
|
||||
.TP
|
||||
\fB\-\-attachment\-description\fR <\fIdescription\fR>
|
||||
Plain text description of the following attachment. Applies to the next
|
||||
\fB\-\-attach\-file\fR or \fB\-\-attach\-file\-once\fR command.
|
||||
.TP
|
||||
\fB\-\-attachment\-mime\-type\fR <\fIMIME type\fR>
|
||||
MIME type of the following attachment. Applies to the next
|
||||
\fB\-\-attach\-file\fR or \fB\-\-attach\-file\-once\fR command.
|
||||
A list of officially recognized MIME types can be found e.g. at
|
||||
.URL
|
||||
ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/media-types
|
||||
The MIME type is mandatory for an attachment.
|
||||
.TP
|
||||
\fB\-\-attach\-file\fR <\fIfile name\fR>
|
||||
.TP
|
||||
\fB\-\-attach\-file\-once\fR <\fIfile name\fR>
|
||||
Creates a file attachment inside the Matroska file. The MIME type must have
|
||||
been set before this option can used. The difference between the two forms
|
||||
is that during splitting the files attached with \fB\-\-attach\-file\fR are
|
||||
attached to all output files while the ones attached with
|
||||
\fB\-\-attach\-file\-once\fR are only attached to the first file created.
|
||||
If splitting is not used then both do the same.
|
||||
.br
|
||||
\fBmkvextract\fR can be used to extract attached files from a Matroska file.
|
||||
.br
|
||||
\fBNote:\fR If an input file is a Matroska file then the attached files will
|
||||
not be copied to the output file(s). This may change in the future.
|
||||
|
||||
|
||||
.LP
|
||||
Options that can be used for each input file:
|
||||
.TP
|
||||
@ -167,6 +201,8 @@ listed with the \fB\-\-list\-languages\fR option.
|
||||
.br
|
||||
This option can be used multiple times for an input file applying to several
|
||||
tracks by selecting different track IDs each time.
|
||||
|
||||
|
||||
.LP
|
||||
Options that only apply to video tracks:
|
||||
.TP
|
||||
@ -358,6 +394,7 @@ If you do not see the language or default track flags that you've specified
|
||||
in \fBmkvinfo\fR's output then please read the section about \fBDEFAULT
|
||||
VALUES\fR.
|
||||
|
||||
|
||||
.SH SUBTITLES
|
||||
.LP
|
||||
There are several text subtitle formats that can be embedded into Matroska.
|
||||
@ -382,6 +419,7 @@ limitations: 1) Files saved with more than one byte per character (e.g.
|
||||
all UTF-16 formats) are not supported, UTF-8/ASCII only; 2) The \fB\\fe\fR
|
||||
markup is not supported correctly.
|
||||
|
||||
|
||||
.SH FILE LINKING
|
||||
.LP
|
||||
Matroska supports file linking which simply says that a specific file is the
|
||||
@ -419,6 +457,7 @@ If splitting is used then the first file is linked to the UID given with
|
||||
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
|
||||
@ -448,6 +487,7 @@ 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
|
||||
@ -459,6 +499,27 @@ and the default value for the \fIdefault track flag\fR is \fItrue\fR. Therefore
|
||||
if you used \fB--language 0:eng\fR for a track then it will not show up
|
||||
in \fBmkvinfo\fR's output.
|
||||
|
||||
|
||||
.SH ATTACHMENTS
|
||||
.LP
|
||||
Maybe you also want to keep some photos along with your Matroska file, or
|
||||
you're using SSA subtitles and need a special TrueType font that's really
|
||||
rare. In these cases you can attach those files to the Matroska file. They
|
||||
will not be just appended to the file but embedded in it. A player can then
|
||||
show those files (the 'photos' case) or use them to render the subtitles
|
||||
(the 'TrueType fonts' case).
|
||||
.LP
|
||||
Here's an example how to attach a photo and a TrueType font to the output
|
||||
file:
|
||||
.br
|
||||
$ \fBmkvmerge -o output.mkv -A video.avi sound.ogg \-\-attachment\-description
|
||||
"Me and the band behind the stage in a small get-together"
|
||||
\-\-attachment\-mime\-type image/jpeg \-\-attach\-file me_and_the_band.jpg
|
||||
\-\-attachment\-description "The real rare and unbelievably good looking font"
|
||||
\-\-attachment\-type application/octet\-stream
|
||||
\-\-attach\-file really_cool_font.ttf
|
||||
|
||||
|
||||
.SH NOTES
|
||||
.LP
|
||||
What works:
|
||||
@ -487,6 +548,9 @@ DTS audio files
|
||||
MP3 audio files
|
||||
.TP
|
||||
*
|
||||
RealVideo and RealAudio from RealMedia files
|
||||
.TP
|
||||
*
|
||||
Track selection
|
||||
.TP
|
||||
*
|
||||
|
159
src/mkvmerge.cpp
159
src/mkvmerge.cpp
@ -45,6 +45,8 @@
|
||||
#include <ebml/EbmlVoid.h>
|
||||
|
||||
#include <matroska/FileKax.h>
|
||||
#include <matroska/KaxAttached.h>
|
||||
#include <matroska/KaxAttachements.h>
|
||||
#include <matroska/KaxBlock.h>
|
||||
#include <matroska/KaxCluster.h>
|
||||
#include <matroska/KaxClusterData.h>
|
||||
@ -110,8 +112,16 @@ typedef struct {
|
||||
generic_packetizer_c *packetizer;
|
||||
} packetizer_t;
|
||||
|
||||
typedef struct {
|
||||
char *name, *mime_type, *description;
|
||||
int64_t size;
|
||||
bool to_all_files;
|
||||
} attachment_t;
|
||||
|
||||
vector<packetizer_t *> packetizers;
|
||||
vector<filelist_t *> files;
|
||||
vector<attachment_t *> attachments;
|
||||
int64_t attachment_sizes_first = 0, attachment_sizes_others = 0;
|
||||
|
||||
// Variables set by the command line parser.
|
||||
char *outfile = NULL;
|
||||
@ -207,6 +217,15 @@ static void usage(void) {
|
||||
" --dont-link Don't link splitted files.\n"
|
||||
" --link-to-previous <UID> Link the first file to the given UID.\n"
|
||||
" --link-to-next <UID> Link the last file to the given UID.\n"
|
||||
" --attachment-description <desc>\n"
|
||||
" Description for the following attachment.\n"
|
||||
" --attachment-mime-type <mime type>\n"
|
||||
" Mime type for the following attachment.\n"
|
||||
" --attach-file <file> Creates a file attachment inside the\n"
|
||||
" Matroska file.\n"
|
||||
" --attach-file-once <file>\n"
|
||||
" Creates a file attachment inside the\n"
|
||||
" firsts Matroska file written.\n"
|
||||
"\n Options for each input file:\n"
|
||||
" -a, --atracks <n,m,...> Copy audio tracks n,m etc. Default: copy all\n"
|
||||
" audio tracks.\n"
|
||||
@ -426,6 +445,8 @@ static float parse_aspect_ratio(char *s) {
|
||||
float w, h;
|
||||
|
||||
div = strchr(s, '/');
|
||||
if (div == NULL)
|
||||
div = strchr(s, ':');
|
||||
if (div == NULL)
|
||||
return strtod(s, NULL);
|
||||
|
||||
@ -703,6 +724,76 @@ static void render_headers(mm_io_c *out, bool last_file, bool first_file) {
|
||||
}
|
||||
}
|
||||
|
||||
static void render_attachments(IOCallback *out) {
|
||||
KaxAttachements *kax_as;
|
||||
KaxAttached *kax_a;
|
||||
KaxFileData *fdata;
|
||||
attachment_t *attch;
|
||||
int i;
|
||||
char *name;
|
||||
binary *buffer;
|
||||
int64_t size;
|
||||
mm_io_c *io;
|
||||
|
||||
if (!(((file_num == 1) && (attachment_sizes_first > 0)) ||
|
||||
(attachment_sizes_others > 0)))
|
||||
return;
|
||||
|
||||
kax_as = new KaxAttachements();
|
||||
kax_a = NULL;
|
||||
for (i = 0; i < attachments.size(); i++) {
|
||||
attch = attachments[i];
|
||||
|
||||
if ((file_num == 1) || attch->to_all_files) {
|
||||
if (kax_a == NULL)
|
||||
kax_a = &GetChild<KaxAttached>(*kax_as);
|
||||
else
|
||||
kax_a = &GetNextChild<KaxAttached>(*kax_as, *kax_a);
|
||||
|
||||
if (attch->description != NULL)
|
||||
*static_cast<EbmlUnicodeString *>
|
||||
(&GetChild<KaxFileDescription>(*kax_a)) =
|
||||
cstr_to_UTFstring(attch->mime_type);;
|
||||
|
||||
if (attch->mime_type != NULL)
|
||||
*static_cast<EbmlString *>(&GetChild<KaxMimeType>(*kax_a)) =
|
||||
attch->mime_type;
|
||||
|
||||
name = &attch->name[strlen(attch->name) - 1];
|
||||
while ((name != attch->name) && (*name != '/'))
|
||||
name--;
|
||||
if (*name == '/')
|
||||
name++;
|
||||
if (*name == 0)
|
||||
die("Internal error: *name == 0 on %d.", __LINE__);
|
||||
|
||||
*static_cast<EbmlUnicodeString *>
|
||||
(&GetChild<KaxFileName>(*kax_a)) =
|
||||
cstr_to_UTFstring(name);
|
||||
|
||||
try {
|
||||
io = new mm_io_c(attch->name, MODE_READ);
|
||||
io->setFilePointer(0, seek_end);
|
||||
size = io->getFilePointer();
|
||||
io->setFilePointer(0, seek_beginning);
|
||||
|
||||
buffer = new binary[size];
|
||||
io->read(buffer, size);
|
||||
delete io;
|
||||
|
||||
fdata = &GetChild<KaxFileData>(*kax_a);
|
||||
fdata->SetBuffer(buffer, size);
|
||||
} catch (...) {
|
||||
mxprint(stderr, "Error: Could not open the attachment '%s'.\n",
|
||||
attch->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kax_as->Render(*out);
|
||||
delete kax_as;
|
||||
}
|
||||
|
||||
static void create_readers() {
|
||||
filelist_t *file;
|
||||
int i;
|
||||
@ -851,6 +942,8 @@ static void parse_args(int argc, char **argv) {
|
||||
cue_creation_t cues;
|
||||
int64_t id;
|
||||
language_t lang;
|
||||
attachment_t *attachment;
|
||||
mm_io_c *io;
|
||||
|
||||
memset(&ti, 0, sizeof(track_info_t));
|
||||
ti.audio_syncs = new vector<audio_sync_t>;
|
||||
@ -862,6 +955,8 @@ static void parse_args(int argc, char **argv) {
|
||||
ti.atracks = new vector<int64_t>;
|
||||
ti.vtracks = new vector<int64_t>;
|
||||
ti.stracks = new vector<int64_t>;
|
||||
attachment = (attachment_t *)safemalloc(sizeof(attachment_t));
|
||||
memset(attachment, 0, sizeof(attachment_t));
|
||||
|
||||
// Check if only information about the file is wanted. In this mode only
|
||||
// two parameters are allowed: the --identify switch and the file.
|
||||
@ -1034,6 +1129,62 @@ static void parse_args(int argc, char **argv) {
|
||||
else if (!strcmp(argv[i], "--no-lacing"))
|
||||
no_lacing = true;
|
||||
|
||||
else if (!strcmp(argv[i], "--attachment-description")) {
|
||||
if ((i + 1) >= argc) {
|
||||
mxprint(stderr, "Error: --attachment-description lacks the "
|
||||
"description.\n");
|
||||
exit(1);
|
||||
}
|
||||
safefree(attachment->description);
|
||||
attachment->description = safestrdup(argv[i + 1]);
|
||||
i++;
|
||||
|
||||
} else if (!strcmp(argv[i], "--attachment-mime-type")) {
|
||||
if ((i + 1) >= argc) {
|
||||
mxprint(stderr, "Error: --attachment-mime-type lacks the "
|
||||
"MIME type.\n");
|
||||
exit(1);
|
||||
}
|
||||
safefree(attachment->mime_type);
|
||||
attachment->mime_type = safestrdup(argv[i + 1]);
|
||||
i++;
|
||||
|
||||
} else if (!strcmp(argv[i], "--attach-file") ||
|
||||
!strcmp(argv[i], "--attach-file-once")) {
|
||||
if ((i + 1) >= argc) {
|
||||
mxprint(stderr, "Error: %s lacks the file name.\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (attachment->mime_type == NULL) {
|
||||
mxprint(stderr, "Error: No MIME type was set for the attachment '%s'."
|
||||
"\n", argv[i + 1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
attachment->name = safestrdup(argv[i + 1]);
|
||||
if (!strcmp(argv[i], "--attach-file"))
|
||||
attachment->to_all_files = true;
|
||||
try {
|
||||
io = new mm_io_c(attachment->name, MODE_READ);
|
||||
io->setFilePointer(0, seek_end);
|
||||
attachment->size = io->getFilePointer();
|
||||
delete io;
|
||||
if (attachment->size == 0)
|
||||
throw exception();
|
||||
} catch (...) {
|
||||
mxprint(stderr, "Error: Could not open the attachment '%s', or its "
|
||||
"size is 0.\n", attachment->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
attachments.push_back(attachment);
|
||||
attachment = (attachment_t *)safemalloc(sizeof(attachment_t));
|
||||
memset(attachment, 0, sizeof(attachment_t));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// Options that apply to the next input file only.
|
||||
else if (!strcmp(argv[i], "-A") || !strcmp(argv[i], "--noaudio"))
|
||||
ti.no_audio = true;
|
||||
@ -1213,6 +1364,12 @@ static void parse_args(int argc, char **argv) {
|
||||
mxprint(stderr, "Warning: '--dont-link' is only useful in combination "
|
||||
"with '--split'.\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < attachments.size(); i++) {
|
||||
attachment_sizes_first += attachments[i]->size;
|
||||
if (attachments[i]->to_all_files)
|
||||
attachment_sizes_others += attachments[i]->size;
|
||||
}
|
||||
}
|
||||
|
||||
static char **add_string(int &num, char **values, char *new_string) {
|
||||
@ -1442,6 +1599,7 @@ void create_next_output_file(bool last_file, bool first_file) {
|
||||
|
||||
cluster_helper->set_output(out);
|
||||
render_headers(out, last_file, first_file);
|
||||
render_attachments(out);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1464,6 +1622,7 @@ void create_next_output_file(bool last_file, bool first_file) {
|
||||
|
||||
cluster_helper->set_output(out);
|
||||
render_headers(out, last_file, first_file);
|
||||
render_attachments(out);
|
||||
|
||||
file_num++;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user