mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-23 19:31:44 +00:00
mkvmerge will copy the attachments from Matroska source files. Can be disabled with the --no-attachments option.
This commit is contained in:
parent
b7c1b707c7
commit
0b02af818d
@ -1,3 +1,8 @@
|
||||
2003-09-29 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: new feature: Attachments are kept when reading
|
||||
Matroska files.
|
||||
|
||||
2003-09-28 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mmg: new feature: Added a (nearly) full-featured chapter editor.
|
||||
|
2
debian/rules
vendored
2
debian/rules
vendored
@ -76,7 +76,7 @@ binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
# dh_installdebconf
|
||||
# dh_installdocs doc/matroskatags.dtd doc/matroskachapters.dtd doc/example-tags-1.xml doc/example-chapters-1.xml doc/example-chapters-2.xml
|
||||
dh_installdocs doc/mkvmerge-gui.html
|
||||
dh_installexamples examples/*xml examples/*dtd
|
||||
# dh_installmenu
|
||||
# dh_installlogrotate
|
||||
|
@ -179,6 +179,9 @@ Don't copy any subtitle track from this file.
|
||||
\fB\-\-no\-chapters\fR
|
||||
If the source is a Matroska file then don't copy chapters from it.
|
||||
.TP
|
||||
\fB\-\-no\-attachments\fR
|
||||
If the source is a Matroska file then don't copy attachments from it.
|
||||
.TP
|
||||
\fB\-y\fR, \fB\-\-sync\fR <\fITID\fR:\fId\fR[,\fIo\fR[/\fIp\fR]]>
|
||||
Synchronize manually, delay the audio track with the id \fITID\fR by \fId\fR
|
||||
ms. The track IDs are the same as the ones given with \fB\-\-identify\fR (see
|
||||
|
@ -300,6 +300,7 @@ static void usage() {
|
||||
" -D, --novideo Don't copy any video track from this file.\n"
|
||||
" -S, --nosubs Don't copy any text track from this file.\n"
|
||||
" --no-chapters Don't keep chapters from a Matroska file.\n"
|
||||
" --no-attachments Don't keep attachments from a Matroska file.\n"
|
||||
" -y, --sync <TID:d[,o[/p]]>\n"
|
||||
" Synchronize, delay the audio track with the\n"
|
||||
" id TID by d ms. \n"
|
||||
@ -885,6 +886,7 @@ static void render_headers(mm_io_c *out, bool last_file, bool first_file) {
|
||||
}
|
||||
|
||||
static void render_attachments(IOCallback *out) {
|
||||
KaxAttachments *other_as;
|
||||
KaxAttached *kax_a;
|
||||
KaxFileData *fdata;
|
||||
attachment_t *attch;
|
||||
@ -894,9 +896,21 @@ static void render_attachments(IOCallback *out) {
|
||||
int64_t size;
|
||||
mm_io_c *io;
|
||||
|
||||
if (!(((file_num == 1) && (attachment_sizes_first > 0)) ||
|
||||
(attachment_sizes_others > 0)))
|
||||
other_as = new KaxAttachments;
|
||||
for (i = 0; i < files.size(); i++)
|
||||
files[i]->reader->add_attachments(other_as);
|
||||
for (i = 0, size = 0; i < other_as->ListSize(); i++) {
|
||||
kax_a = static_cast<KaxAttached *>((*other_as)[i]);
|
||||
fdata = FindChild<KaxFileData>(*kax_a);
|
||||
if (fdata != NULL)
|
||||
size += fdata->GetSize();
|
||||
}
|
||||
|
||||
if (!(((file_num == 1) && ((attachment_sizes_first + size) > 0)) ||
|
||||
((attachment_sizes_others + size) > 0))) {
|
||||
delete other_as;
|
||||
return;
|
||||
}
|
||||
|
||||
if (kax_as != NULL)
|
||||
delete kax_as;
|
||||
@ -936,10 +950,7 @@ static void render_attachments(IOCallback *out) {
|
||||
|
||||
try {
|
||||
io = new mm_io_c(attch->name, MODE_READ);
|
||||
io->setFilePointer(0, seek_end);
|
||||
size = io->getFilePointer();
|
||||
io->setFilePointer(0, seek_beginning);
|
||||
|
||||
size = io->get_size();
|
||||
buffer = new binary[size];
|
||||
io->read(buffer, size);
|
||||
delete io;
|
||||
@ -952,6 +963,12 @@ static void render_attachments(IOCallback *out) {
|
||||
}
|
||||
}
|
||||
|
||||
while (other_as->ListSize() > 0) {
|
||||
kax_as->PushElement(*(*other_as)[0]);
|
||||
other_as->Remove(0);
|
||||
}
|
||||
delete other_as;
|
||||
|
||||
kax_as->Render(*out);
|
||||
}
|
||||
|
||||
@ -1417,6 +1434,9 @@ static void parse_args(int argc, char **argv) {
|
||||
} else if (!strcmp(this_arg, "--no-chapters")) {
|
||||
ti.no_chapters = true;
|
||||
|
||||
} else if (!strcmp(this_arg, "--no-attachments")) {
|
||||
ti.no_attachments = true;
|
||||
|
||||
} else if (!strcmp(this_arg, "--dump-packets")) {
|
||||
if (next_arg == NULL)
|
||||
mxerror("'--dump-packets' lacks the output path.\n");
|
||||
|
@ -657,6 +657,10 @@ void mmg_dialog::update_command_line() {
|
||||
cmdline += "--no-chapters ";
|
||||
clargs.Add("--no-chapters");
|
||||
}
|
||||
if (f->no_attachments) {
|
||||
cmdline += "--no-attachments ";
|
||||
clargs.Add("--no-attachments");
|
||||
}
|
||||
if (no_video) {
|
||||
cmdline += "-D ";
|
||||
clargs.Add("-D");
|
||||
|
@ -116,6 +116,7 @@ using namespace libmatroska;
|
||||
#define ID_CB_CHAPTERSELECTLANGUAGECODE 10069
|
||||
#define ID_CB_CHAPTERSELECTCOUNTRYCODE 10070
|
||||
#define ID_B_ADDSUBCHAPTER 10071
|
||||
#define ID_CB_NOATTACHMENTS 10072
|
||||
|
||||
#define ID_M_FILE_LOAD 20000
|
||||
#define ID_M_FILE_SAVE 20001
|
||||
@ -164,7 +165,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
wxString *file_name;
|
||||
vector<mmg_track_t> *tracks;
|
||||
bool no_chapters;
|
||||
bool no_chapters, no_attachments;
|
||||
} mmg_file_t;
|
||||
|
||||
typedef struct {
|
||||
@ -191,7 +192,7 @@ class tab_input: public wxPanel {
|
||||
protected:
|
||||
wxListBox *lb_input_files;
|
||||
wxButton *b_add_file, *b_remove_file, *b_browse_tags;
|
||||
wxCheckBox *cb_no_chapters, *cb_default, *cb_aac_is_sbr;
|
||||
wxCheckBox *cb_no_chapters, *cb_no_attachments, *cb_default, *cb_aac_is_sbr;
|
||||
wxCheckListBox *clb_tracks;
|
||||
wxComboBox *cob_language, *cob_cues, *cob_sub_charset;
|
||||
wxComboBox *cob_aspect_ratio, *cob_fourcc;
|
||||
@ -210,6 +211,7 @@ public:
|
||||
void on_track_selected(wxCommandEvent &evt);
|
||||
void on_track_enabled(wxCommandEvent &evt);
|
||||
void on_nochapters_clicked(wxCommandEvent &evt);
|
||||
void on_noattachments_clicked(wxCommandEvent &evt);
|
||||
void on_default_track_clicked(wxCommandEvent &evt);
|
||||
void on_aac_is_sbr_clicked(wxCommandEvent &evt);
|
||||
void on_language_selected(wxCommandEvent &evt);
|
||||
|
@ -61,11 +61,18 @@ tab_input::tab_input(wxWindow *parent):
|
||||
wxDefaultSize, 0);
|
||||
cb_no_chapters =
|
||||
new wxCheckBox(this, ID_CB_NOCHAPTERS, _("No chapters"), wxPoint(5, 110),
|
||||
wxSize(100, -1), 0);
|
||||
wxDefaultSize, 0);
|
||||
cb_no_chapters->SetValue(false);
|
||||
cb_no_chapters->SetToolTip(_("Do not copy chapters from this file. Only "
|
||||
"applies to Matroska files."));
|
||||
cb_no_chapters->Enable(false);
|
||||
cb_no_attachments =
|
||||
new wxCheckBox(this, ID_CB_NOATTACHMENTS, _("No attachments"),
|
||||
wxPoint(110, 110), wxDefaultSize, 0);
|
||||
cb_no_attachments->SetValue(false);
|
||||
cb_no_attachments->SetToolTip(_("Do not copy attachments from this file. "
|
||||
"Only applies to Matroska files."));
|
||||
cb_no_attachments->Enable(false);
|
||||
new wxStaticText(this, wxID_STATIC, _("Tracks:"), wxPoint(5, 140),
|
||||
wxDefaultSize, 0);
|
||||
clb_tracks =
|
||||
@ -424,6 +431,7 @@ void tab_input::on_remove_file(wxCommandEvent &evt) {
|
||||
lb_input_files->Delete(selected_file);
|
||||
selected_file = -1;
|
||||
cb_no_chapters->Enable(false);
|
||||
cb_no_attachments->Enable(false);
|
||||
b_remove_file->Enable(false);
|
||||
clb_tracks->Enable(false);
|
||||
no_track_mode();
|
||||
@ -438,10 +446,12 @@ void tab_input::on_file_selected(wxCommandEvent &evt) {
|
||||
|
||||
b_remove_file->Enable(true);
|
||||
cb_no_chapters->Enable(true);
|
||||
cb_no_attachments->Enable(true);
|
||||
selected_file = -1;
|
||||
new_sel = lb_input_files->GetSelection();
|
||||
f = &files[new_sel];
|
||||
cb_no_chapters->SetValue(f->no_chapters);
|
||||
cb_no_attachments->SetValue(f->no_attachments);
|
||||
|
||||
clb_tracks->Clear();
|
||||
for (i = 0; i < f->tracks->size(); i++) {
|
||||
@ -468,6 +478,11 @@ void tab_input::on_nochapters_clicked(wxCommandEvent &evt) {
|
||||
files[selected_file].no_chapters = cb_no_chapters->GetValue();
|
||||
}
|
||||
|
||||
void tab_input::on_noattachments_clicked(wxCommandEvent &evt) {
|
||||
if (selected_file -1)
|
||||
files[selected_file].no_attachments = cb_no_attachments->GetValue();
|
||||
}
|
||||
|
||||
void tab_input::on_track_selected(wxCommandEvent &evt) {
|
||||
mmg_file_t *f;
|
||||
mmg_track_t *t;
|
||||
@ -631,6 +646,7 @@ void tab_input::save(wxConfigBase *cfg) {
|
||||
cfg->SetPath(s);
|
||||
cfg->Write("file_name", *f->file_name);
|
||||
cfg->Write("no_chapters", f->no_chapters);
|
||||
cfg->Write("no_attachments", f->no_attachments);
|
||||
|
||||
cfg->Write("number_of_tracks", (int)f->tracks->size());
|
||||
for (tidx = 0; tidx < f->tracks->size(); tidx++) {
|
||||
@ -718,6 +734,7 @@ void tab_input::load(wxConfigBase *cfg) {
|
||||
}
|
||||
fi.file_name = new wxString(s);
|
||||
cfg->Read("no_chapters", &fi.no_chapters);
|
||||
cfg->Read("no_attachments", &fi.no_attachments);
|
||||
fi.tracks = new vector<mmg_track_t>;
|
||||
|
||||
for (tidx = 0; tidx < (uint32_t)num_tracks; tidx++) {
|
||||
@ -905,6 +922,7 @@ BEGIN_EVENT_TABLE(tab_input, wxPanel)
|
||||
EVT_CHECKLISTBOX(ID_CLB_TRACKS, tab_input::on_track_enabled)
|
||||
|
||||
EVT_CHECKBOX(ID_CB_NOCHAPTERS, tab_input::on_nochapters_clicked)
|
||||
EVT_CHECKBOX(ID_CB_NOATTACHMENTS, tab_input::on_noattachments_clicked)
|
||||
EVT_CHECKBOX(ID_CB_MAKEDEFAULT, tab_input::on_default_track_clicked)
|
||||
EVT_CHECKBOX(ID_CB_AACISSBR, tab_input::on_aac_is_sbr_clicked)
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include <matroska/KaxAttachments.h>
|
||||
#include <matroska/KaxBlock.h>
|
||||
#include <matroska/KaxCluster.h>
|
||||
#include <matroska/KaxTracks.h>
|
||||
@ -118,7 +119,7 @@ typedef struct {
|
||||
vector<language_t> *track_names; // As given on the command line
|
||||
char *track_name; // For this very track
|
||||
|
||||
bool no_chapters;
|
||||
bool no_chapters, no_attachments, no_tags;
|
||||
} track_info_t;
|
||||
|
||||
class generic_reader_c;
|
||||
@ -234,6 +235,8 @@ public:
|
||||
virtual void set_headers() = 0;
|
||||
virtual void identify() = 0;
|
||||
|
||||
virtual void add_attachments(KaxAttachments *a) {
|
||||
};
|
||||
// virtual void set_tag_track_uids() = 0;
|
||||
|
||||
protected:
|
||||
|
@ -143,6 +143,9 @@ kax_reader_c::~kax_reader_c() {
|
||||
safefree(tracks[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < attachments.size(); i++)
|
||||
safefree(attachments[i].data);
|
||||
|
||||
if (es != NULL)
|
||||
delete es;
|
||||
if (saved_l1 != NULL)
|
||||
@ -464,10 +467,11 @@ void kax_reader_c::handle_attachments(mm_io_c *io, EbmlStream *es,
|
||||
KaxAttachments *atts;
|
||||
KaxAttached *att;
|
||||
EbmlElement *l1, *l2;
|
||||
UTFstring description, name;
|
||||
int upper_lvl_el, i, k;
|
||||
string name, type;
|
||||
string mime_type;
|
||||
int64_t size, id;
|
||||
char *str;
|
||||
unsigned char *data;
|
||||
bool found;
|
||||
kax_attachment_t matt;
|
||||
|
||||
@ -484,8 +488,9 @@ void kax_reader_c::handle_attachments(mm_io_c *io, EbmlStream *es,
|
||||
for (i = 0; i < atts->ListSize(); i++) {
|
||||
att = (KaxAttached *)(*atts)[i];
|
||||
if (EbmlId(*att) == KaxAttached::ClassInfos.GlobalId) {
|
||||
name = "";
|
||||
type = "";
|
||||
name = L"";
|
||||
mime_type = "";
|
||||
description = L"";
|
||||
size = -1;
|
||||
id = -1;
|
||||
|
||||
@ -494,13 +499,15 @@ void kax_reader_c::handle_attachments(mm_io_c *io, EbmlStream *es,
|
||||
|
||||
if (EbmlId(*l2) == KaxFileName::ClassInfos.GlobalId) {
|
||||
KaxFileName &fname = *static_cast<KaxFileName *>(l2);
|
||||
str = UTFstring_to_cstr(UTFstring(fname));
|
||||
name = str;
|
||||
safefree(str);
|
||||
name = UTFstring(fname);
|
||||
|
||||
} else if (EbmlId(*l2) == KaxFileDescription::ClassInfos.GlobalId) {
|
||||
KaxFileDescription &fdesc = *static_cast<KaxFileDescription *>(l2);
|
||||
description = UTFstring(fdesc);
|
||||
|
||||
} else if (EbmlId(*l2) == KaxMimeType::ClassInfos.GlobalId) {
|
||||
KaxMimeType &mtype = *static_cast<KaxMimeType *>(l2);
|
||||
type = string(mtype);
|
||||
mime_type = string(mtype);
|
||||
|
||||
} else if (EbmlId(*l2) == KaxFileUID::ClassInfos.GlobalId) {
|
||||
KaxFileUID &fuid = *static_cast<KaxFileUID *>(l2);
|
||||
@ -509,11 +516,12 @@ void kax_reader_c::handle_attachments(mm_io_c *io, EbmlStream *es,
|
||||
} else if (EbmlId(*l2) == KaxFileData::ClassInfos.GlobalId) {
|
||||
KaxFileData &fdata = *static_cast<KaxFileData *>(l2);
|
||||
size = fdata.GetSize();
|
||||
|
||||
data = (unsigned char *)fdata.GetBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
if ((id != -1) && (size != -1) && (type.length() != 0)) {
|
||||
if ((id != -1) && (size != -1) && (mime_type.length() > 0) &&
|
||||
(name.length() > 0)) {
|
||||
found = false;
|
||||
|
||||
for (k = 0; k < attachments.size(); k++)
|
||||
@ -524,9 +532,11 @@ void kax_reader_c::handle_attachments(mm_io_c *io, EbmlStream *es,
|
||||
|
||||
if (!found) {
|
||||
matt.name = name;
|
||||
matt.type = type;
|
||||
matt.mime_type = mime_type;
|
||||
matt.description = description;
|
||||
matt.size = size;
|
||||
matt.id = id;
|
||||
matt.data = (unsigned char *)safememdup(data, size);
|
||||
attachments.push_back(matt);
|
||||
}
|
||||
}
|
||||
@ -1487,6 +1497,7 @@ void kax_reader_c::set_headers() {
|
||||
void kax_reader_c::identify() {
|
||||
int i;
|
||||
string info;
|
||||
char *str;
|
||||
|
||||
mxinfo("File '%s': container: Matroska\n", ti->fname);
|
||||
for (i = 0; i < tracks.size(); i++)
|
||||
@ -1511,12 +1522,20 @@ void kax_reader_c::identify() {
|
||||
|
||||
for (i = 0; i < attachments.size(); i++) {
|
||||
mxinfo("Attachment ID %lld: type '%s', size %lld bytes, ",
|
||||
attachments[i].id, attachments[i].type.c_str(),
|
||||
attachments[i].id, attachments[i].mime_type.c_str(),
|
||||
attachments[i].size);
|
||||
if (attachments[i].description.length() > 0) {
|
||||
str = UTFstring_to_cstr(attachments[i].description.c_str());
|
||||
mxinfo("description '%s', ", str);
|
||||
safefree(str);
|
||||
}
|
||||
if (attachments[i].name.length() == 0)
|
||||
mxinfo("no file name given\n");
|
||||
else
|
||||
mxinfo("file name '%s'\n", attachments[i].name.c_str());
|
||||
else {
|
||||
str = UTFstring_to_cstr(attachments[i].name.c_str());
|
||||
mxinfo("file name '%s'\n", str);
|
||||
safefree(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1533,3 +1552,37 @@ int64_t kax_reader_c::get_queued_bytes() {
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void kax_reader_c::add_attachments(KaxAttachments *a) {
|
||||
uint32_t i;
|
||||
KaxAttached *attached;
|
||||
KaxFileData *fdata;
|
||||
binary *buffer;
|
||||
|
||||
if (ti->no_attachments)
|
||||
return;
|
||||
|
||||
for (i = 0; i < attachments.size(); i++) {
|
||||
attached = new KaxAttached;
|
||||
if (attachments[i].description.length() > 0)
|
||||
*static_cast<EbmlUnicodeString *>
|
||||
(&GetChild<KaxFileDescription>(*attached)) =
|
||||
attachments[i].description;
|
||||
|
||||
*static_cast<EbmlString *>(&GetChild<KaxMimeType>(*attached)) =
|
||||
attachments[i].mime_type;
|
||||
|
||||
*static_cast<EbmlUnicodeString *>(&GetChild<KaxFileName>(*attached)) =
|
||||
attachments[i].name;
|
||||
|
||||
*static_cast<EbmlUInteger *>(&GetChild<KaxFileUID>(*attached)) =
|
||||
attachments[i].id;
|
||||
|
||||
fdata = &GetChild<KaxFileData>(*attached);
|
||||
buffer = new binary[attachments[i].size];
|
||||
memcpy(buffer, attachments[i].data, attachments[i].size);
|
||||
fdata->SetBuffer(buffer, attachments[i].size);
|
||||
|
||||
a->PushElement(*attached);
|
||||
}
|
||||
}
|
||||
|
@ -32,14 +32,19 @@
|
||||
#include "pr_generic.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <ebml/EbmlUnicodeString.h>
|
||||
|
||||
#include <matroska/KaxBlock.h>
|
||||
#include <matroska/KaxCluster.h>
|
||||
|
||||
using namespace libebml;
|
||||
using namespace libmatroska;
|
||||
using namespace std;
|
||||
|
||||
typedef struct {
|
||||
string name, type;
|
||||
string mime_type;
|
||||
UTFstring name, description;
|
||||
unsigned char *data;
|
||||
int64 size, id;
|
||||
} kax_attachment_t;
|
||||
|
||||
@ -118,6 +123,7 @@ public:
|
||||
virtual void display_progress(bool final = false);
|
||||
virtual void set_headers();
|
||||
virtual void identify();
|
||||
virtual void add_attachments(KaxAttachments *a);
|
||||
|
||||
static int probe_file(mm_io_c *mm_io, int64_t size);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user