mkvmerge will copy the attachments from Matroska source files. Can be disabled with the --no-attachments option.

This commit is contained in:
Moritz Bunkus 2003-09-29 19:26:26 +00:00
parent b7c1b707c7
commit 0b02af818d
10 changed files with 140 additions and 26 deletions

View File

@ -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
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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