Added an option for setting the track name. Track names and the segment title are kept when reading a Matroska file.

This commit is contained in:
Moritz Bunkus 2003-09-12 19:37:51 +00:00
parent 5bffe14d93
commit e48c6bc73a
8 changed files with 114 additions and 18 deletions

View File

@ -1,5 +1,7 @@
2003-09-12 Moritz Bunkus <moritz@bunkus.org> 2003-09-12 Moritz Bunkus <moritz@bunkus.org>
* mkvmerge: Support for setting the track names.
* mkvmerge: For Matroska source files: If the source contains * mkvmerge: For Matroska source files: If the source contains
chapters then these are kept unless the user specified chapters chapters then these are kept unless the user specified chapters
with --chapters. with --chapters.

View File

@ -222,6 +222,10 @@ prefer the track that has his 'default' flag set. Only one track of each kind
This option can be used multiple times for an input file applying to several This option can be used multiple times for an input file applying to several
tracks by selecting different track IDs each time. tracks by selecting different track IDs each time.
.TP .TP
\fB\-\-track\-name\fR <\fITID\fR:\fIname\fR>
Sets the track name for the given track (see section \fBTRACK IDS\fR) to
\fIname\fR.
.TP
\fB\-\-language\fR <\fITID\fR:\fIlanguage\fR> \fB\-\-language\fR <\fITID\fR:\fIlanguage\fR>
Sets the language for the given track (see section \fBTRACK IDS\fR). Only Sets the language for the given track (see section \fBTRACK IDS\fR). Only
ISO639-2 codes are allowed. All languages including their ISO639-2 codes can be ISO639-2 codes are allowed. All languages including their ISO639-2 codes can be

View File

@ -168,7 +168,7 @@ char *chapter_file_name = NULL;
char *chapter_language = NULL; char *chapter_language = NULL;
char *chapter_charset = NULL; char *chapter_charset = NULL;
string title; string segment_title;
int64_t tags_size = 0; int64_t tags_size = 0;
bool accept_tags = true; bool accept_tags = true;
@ -283,6 +283,7 @@ static void usage() {
" omitted. Both o and p can be floating point\n" " omitted. Both o and p can be floating point\n"
" numbers.\n" " numbers.\n"
" --default-track <TID> Sets the 'default' flag for this track.\n" " --default-track <TID> Sets the 'default' flag for this track.\n"
" --track-name <TID:name> Sets the name for a track.\n"
" --cues <TID:none|iframes|all>\n" " --cues <TID:none|iframes|all>\n"
" Create cue (index) entries for this track:\n" " Create cue (index) entries for this track:\n"
" None at all, only for I frames, for all.\n" " None at all, only for I frames, for all.\n"
@ -691,24 +692,24 @@ static void parse_compression(char *s, cue_creation_t &compression) {
orig.c_str()); orig.c_str());
} }
static void parse_language(char *s, language_t &lang) { static void parse_language(char *s, language_t &lang, const char *opt,
const char *topic, bool check) {
char *colon; char *colon;
string orig = s; string orig = s;
// Extract the track number. // Extract the track number.
if ((colon = strchr(s, ':')) == NULL) if ((colon = strchr(s, ':')) == NULL)
mxerror("Invalid language option. No track ID specified in " mxerror("No track ID specified in '--%s' %s'.\n", opt, orig.c_str());
"'--language %s'.\n", orig.c_str());
*colon = 0; *colon = 0;
if (!parse_int(s, lang.id)) if (!parse_int(s, lang.id))
mxerror("Invalid track ID specified in '--language %s'.\n", orig.c_str()); mxerror("Invalid track ID specified in '--%s %s'.\n", opt, orig.c_str());
s = &colon[1]; s = &colon[1];
if (*s == 0) if (*s == 0)
mxerror("Invalid language specified in '--language %s'.\n", orig.c_str()); mxerror("Invalid %s specified in '--%s %s'.\n", topic, opt, orig.c_str());
if (!is_valid_iso639_2_code(s)) if (check && !is_valid_iso639_2_code(s))
mxerror("'%s' is not a valid ISO639-2 code. See " mxerror("'%s' is not a valid ISO639-2 code. See "
"'mkvmerge --list-languages'.\n", s); "'mkvmerge --list-languages'.\n", s);
@ -791,9 +792,9 @@ static void render_headers(mm_io_c *out, bool last_file, bool first_file) {
cstr_to_UTFstring(VERSIONINFO); cstr_to_UTFstring(VERSIONINFO);
GetChild<KaxDateUTC>(*kax_infos).SetEpochDate(time(NULL)); GetChild<KaxDateUTC>(*kax_infos).SetEpochDate(time(NULL));
if (title.length() > 0) if (segment_title.length() > 0)
*((EbmlUnicodeString *)&GetChild<KaxTitle>(*kax_infos)) = *((EbmlUnicodeString *)&GetChild<KaxTitle>(*kax_infos)) =
cstr_to_UTFstring(title.c_str()); cstrutf8_to_UTFstring(segment_title.c_str());
// Generate the segment UIDs. // Generate the segment UIDs.
if (first_file) { if (first_file) {
@ -1007,6 +1008,7 @@ static void identify(const char *filename) {
ti.stracks = new vector<int64_t>; ti.stracks = new vector<int64_t>;
ti.aac_is_sbr = new vector<int64_t>; ti.aac_is_sbr = new vector<int64_t>;
ti.compression_list = new vector<cue_creation_t>; ti.compression_list = new vector<cue_creation_t>;
ti.track_names = new vector<language_t>;
file = (filelist_t *)safemalloc(sizeof(filelist_t)); file = (filelist_t *)safemalloc(sizeof(filelist_t));
@ -1064,6 +1066,7 @@ static void parse_args(int argc, char **argv) {
ti.vtracks = new vector<int64_t>; ti.vtracks = new vector<int64_t>;
ti.stracks = new vector<int64_t>; ti.stracks = new vector<int64_t>;
ti.compression_list = new vector<cue_creation_t>; ti.compression_list = new vector<cue_creation_t>;
ti.track_names = new vector<language_t>;
attachment = (attachment_t *)safemalloc(sizeof(attachment_t)); attachment = (attachment_t *)safemalloc(sizeof(attachment_t));
memset(attachment, 0, sizeof(attachment_t)); memset(attachment, 0, sizeof(attachment_t));
memset(&tags, 0, sizeof(tags_t)); memset(&tags, 0, sizeof(tags_t));
@ -1147,10 +1150,13 @@ static void parse_args(int argc, char **argv) {
verbose = 2; verbose = 2;
else if (!strcmp(this_arg, "--title")) { else if (!strcmp(this_arg, "--title")) {
char *tmp;
if ((next_arg == NULL) || (next_arg[0] == 0)) if ((next_arg == NULL) || (next_arg[0] == 0))
mxerror("'--title' lacks the title.\n"); mxerror("'--title' lacks the title.\n");
title = next_arg; tmp = to_utf8(cc_local_utf8, next_arg);
segment_title = tmp;
safefree(tmp);
i++; i++;
} else if (!strcmp(this_arg, "--split")) { } else if (!strcmp(this_arg, "--split")) {
@ -1452,7 +1458,7 @@ static void parse_args(int argc, char **argv) {
if (next_arg == NULL) if (next_arg == NULL)
mxerror("'--language' lacks its argument.\n"); mxerror("'--language' lacks its argument.\n");
parse_language(next_arg, lang); parse_language(next_arg, lang, "language", "language", true);
ti.languages->push_back(lang); ti.languages->push_back(lang);
i++; i++;
@ -1491,6 +1497,15 @@ static void parse_args(int argc, char **argv) {
ti.compression_list->push_back(cues); ti.compression_list->push_back(cues);
i++; i++;
} else if (!strcmp(this_arg, "--track-name")) {
if (next_arg == NULL)
mxerror("'--track-name' lacks its argument.\n");
parse_language(next_arg, lang, "track-name", "track name", false);
lang.language = to_utf8(cc_local_utf8, lang.language);
ti.track_names->push_back(lang);
i++;
} }
// The argument is an input file. // The argument is an input file.
@ -1537,6 +1552,9 @@ static void parse_args(int argc, char **argv) {
delete ti.all_tags; delete ti.all_tags;
delete ti.aac_is_sbr; delete ti.aac_is_sbr;
delete ti.compression_list; delete ti.compression_list;
for (j = 0; j < ti.track_names->size(); j++)
safefree((*ti.track_names)[j].language);
delete ti.track_names;
memset(&ti, 0, sizeof(track_info_t)); memset(&ti, 0, sizeof(track_info_t));
ti.audio_syncs = new vector<audio_sync_t>; ti.audio_syncs = new vector<audio_sync_t>;
ti.cue_creations = new vector<cue_creation_t>; ti.cue_creations = new vector<cue_creation_t>;
@ -1550,6 +1568,7 @@ static void parse_args(int argc, char **argv) {
ti.vtracks = new vector<int64_t>; ti.vtracks = new vector<int64_t>;
ti.stracks = new vector<int64_t>; ti.stracks = new vector<int64_t>;
ti.compression_list = new vector<cue_creation_t>; ti.compression_list = new vector<cue_creation_t>;
ti.track_names = new vector<language_t>;
} }
} }
@ -1584,6 +1603,9 @@ static void parse_args(int argc, char **argv) {
delete ti.vtracks; delete ti.vtracks;
delete ti.stracks; delete ti.stracks;
delete ti.compression_list; delete ti.compression_list;
for (j = 0; j < ti.track_names->size(); j++)
safefree((*ti.track_names)[j].language);
delete ti.track_names;
safefree(attachment); safefree(attachment);
} }

View File

@ -46,6 +46,7 @@ extern KaxSeekHead *kax_sh_main, *kax_sh_cues;
extern KaxChapters *kax_chapters; extern KaxChapters *kax_chapters;
extern int track_number; extern int track_number;
extern int64_t tags_size; extern int64_t tags_size;
extern string segment_title;
extern float video_fps; extern float video_fps;

View File

@ -125,6 +125,16 @@ generic_packetizer_c::generic_packetizer_c(generic_reader_c *nreader,
} }
} }
// Let's see if the user has specified a name for this track.
for (i = 0; i < ti->track_names->size(); i++) {
lang = &(*ti->track_names)[i];
if ((lang->id == ti->id) || (lang->id == -1)) { // -1 == all tracks
safefree(ti->track_name);
ti->track_name = safestrdup(lang->language);
break;
}
}
// Set default header values to 'unset'. // Set default header values to 'unset'.
hserialno = track_number++; hserialno = track_number++;
huid = 0; huid = 0;
@ -246,6 +256,11 @@ int generic_packetizer_c::get_track_num() {
return hserialno; return hserialno;
} }
void generic_packetizer_c::set_track_name(const char *name) {
safefree(ti->track_name);
ti->track_name = safestrdup(name);
}
void generic_packetizer_c::set_codec_id(const char *id) { void generic_packetizer_c::set_codec_id(const char *id) {
safefree(hcodec_id); safefree(hcodec_id);
if (id == NULL) { if (id == NULL) {
@ -426,11 +441,15 @@ void generic_packetizer_c::set_headers() {
*(static_cast<EbmlUInteger *> *(static_cast<EbmlUInteger *>
(&GetChild<KaxTrackFlagDefault>(*track_entry))) = 0; (&GetChild<KaxTrackFlagDefault>(*track_entry))) = 0;
if (ti->language != NULL) { if (ti->language != NULL)
*(static_cast<EbmlString *> *(static_cast<EbmlString *>
(&GetChild<KaxTrackLanguage>(*track_entry))) = ti->language; (&GetChild<KaxTrackLanguage>(*track_entry))) = ti->language;
}
if (ti->track_name != NULL)
*(static_cast<EbmlUnicodeString *>
(&GetChild<KaxTrackName>(*track_entry))) =
cstrutf8_to_UTFstring(ti->track_name);
if (htrack_type == track_video) { if (htrack_type == track_video) {
KaxTrackVideo &video = KaxTrackVideo &video =
GetChild<KaxTrackVideo>(*track_entry); GetChild<KaxTrackVideo>(*track_entry);
@ -662,19 +681,24 @@ track_info_t *duplicate_track_info(track_info_t *src) {
dst->languages = new vector<language_t>(*src->languages); dst->languages = new vector<language_t>(*src->languages);
for (i = 0; i < src->languages->size(); i++) for (i = 0; i < src->languages->size(); i++)
(*dst->languages)[i].language = safestrdup((*src->languages)[i].language); (*dst->languages)[i].language = safestrdup((*src->languages)[i].language);
dst->language = safestrdup(src->language);
dst->sub_charsets = new vector<language_t>(*src->sub_charsets); dst->sub_charsets = new vector<language_t>(*src->sub_charsets);
for (i = 0; i < src->sub_charsets->size(); i++) for (i = 0; i < src->sub_charsets->size(); i++)
(*dst->sub_charsets)[i].language = (*dst->sub_charsets)[i].language =
safestrdup((*src->sub_charsets)[i].language); safestrdup((*src->sub_charsets)[i].language);
dst->sub_charset = safestrdup(src->sub_charset);
dst->all_tags = new vector<tags_t>(*src->all_tags); dst->all_tags = new vector<tags_t>(*src->all_tags);
for (i = 0; i < src->all_tags->size(); i++) for (i = 0; i < src->all_tags->size(); i++)
(*dst->all_tags)[i].file_name = safestrdup((*src->all_tags)[i].file_name); (*dst->all_tags)[i].file_name = safestrdup((*src->all_tags)[i].file_name);
dst->aac_is_sbr = new vector<int64_t>(*src->aac_is_sbr); dst->aac_is_sbr = new vector<int64_t>(*src->aac_is_sbr);
dst->private_data = (unsigned char *)safememdup(src->private_data, dst->private_data = (unsigned char *)safememdup(src->private_data,
src->private_size); src->private_size);
dst->language = safestrdup(src->language);
dst->sub_charset = safestrdup(src->sub_charset);
dst->compression_list = new vector<cue_creation_t>(*src->compression_list); dst->compression_list = new vector<cue_creation_t>(*src->compression_list);
dst->track_names = new vector<language_t>(*src->track_names);
for (i = 0; i < src->track_names->size(); i++)
(*dst->track_names)[i].language =
safestrdup((*src->track_names)[i].language);
dst->track_name = safestrdup(src->track_name);
dst->tags = NULL; dst->tags = NULL;
return dst; return dst;
@ -696,17 +720,21 @@ void free_track_info(track_info_t *ti) {
for (i = 0; i < ti->languages->size(); i++) for (i = 0; i < ti->languages->size(); i++)
safefree((*ti->languages)[i].language); safefree((*ti->languages)[i].language);
delete ti->languages; delete ti->languages;
safefree(ti->language);
for (i = 0; i < ti->sub_charsets->size(); i++) for (i = 0; i < ti->sub_charsets->size(); i++)
safefree((*ti->sub_charsets)[i].language); safefree((*ti->sub_charsets)[i].language);
delete ti->sub_charsets; delete ti->sub_charsets;
safefree(ti->sub_charset);
for (i = 0; i < ti->all_tags->size(); i++) for (i = 0; i < ti->all_tags->size(); i++)
safefree((*ti->all_tags)[i].file_name); safefree((*ti->all_tags)[i].file_name);
delete ti->all_tags; delete ti->all_tags;
delete ti->aac_is_sbr; delete ti->aac_is_sbr;
delete ti->compression_list; delete ti->compression_list;
safefree(ti->language); for (i = 0; i < ti->track_names->size(); i++)
safefree((*ti->track_names)[i].language);
delete ti->track_names;
safefree(ti->track_name);
safefree(ti->private_data); safefree(ti->private_data);
safefree(ti->sub_charset);
if (ti->tags != NULL) if (ti->tags != NULL)
delete ti->tags; delete ti->tags;
safefree(ti); safefree(ti);

View File

@ -115,6 +115,9 @@ typedef struct {
vector<cue_creation_t> *compression_list; // As given on the command line vector<cue_creation_t> *compression_list; // As given on the command line
int compression; // For this very track int compression; // For this very track
vector<language_t> *track_names; // As given on the command line
char *track_name; // For this very track
bool no_chapters; bool no_chapters;
} track_info_t; } track_info_t;
@ -213,6 +216,8 @@ public:
virtual void set_tag_track_uid(); virtual void set_tag_track_uid();
virtual void set_track_name(const char *name);
protected: protected:
virtual void dump_packet(const void *buffer, int size); virtual void dump_packet(const void *buffer, int size);
}; };

View File

@ -136,6 +136,8 @@ kax_reader_c::~kax_reader_c() {
delete tracks[i]->packetizer; delete tracks[i]->packetizer;
safefree(tracks[i]->private_data); safefree(tracks[i]->private_data);
safefree(tracks[i]->codec_id); safefree(tracks[i]->codec_id);
safefree(tracks[i]->language);
safefree(tracks[i]->track_name);
safefree(tracks[i]); safefree(tracks[i]);
} }
@ -664,6 +666,7 @@ int kax_reader_c::read_headers() {
if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) { if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) {
KaxTimecodeScale *ktc_scale; KaxTimecodeScale *ktc_scale;
KaxDuration *kduration; KaxDuration *kduration;
KaxTitle *ktitle;
// General info about this Matroska file // General info about this Matroska file
if (verbose > 1) if (verbose > 1)
@ -687,6 +690,20 @@ int kax_reader_c::read_headers() {
mxinfo(PFX "| + duration: %.3fs\n", segment_duration); mxinfo(PFX "| + duration: %.3fs\n", segment_duration);
} }
ktitle = FINDFIRST(l1, KaxTitle);
if (ktitle != NULL) {
char *tmp;
tmp = UTFstring_to_cstr(UTFstring(*ktitle));
if (verbose > 1)
mxinfo(PFX "| + title: %s\n", tmp);
safefree(tmp);
if (segment_title.length() == 0) {
tmp = UTFstring_to_cstrutf8(UTFstring(*ktitle));
segment_title = tmp;
safefree(tmp);
}
}
} else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) { } else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) {
KaxTrackEntry *ktentry; KaxTrackEntry *ktentry;
@ -712,6 +729,7 @@ int kax_reader_c::read_headers() {
KaxTrackFlagDefault *ktfdefault; KaxTrackFlagDefault *ktfdefault;
KaxTrackLanguage *ktlanguage; KaxTrackLanguage *ktlanguage;
KaxTrackMinCache *ktmincache; KaxTrackMinCache *ktmincache;
KaxTrackName *ktname;
if (verbose > 1) if (verbose > 1)
mxinfo(PFX "| + a track...\n"); mxinfo(PFX "| + a track...\n");
@ -909,6 +927,18 @@ int kax_reader_c::read_headers() {
track->language = safestrdup(string(*ktlanguage).c_str()); track->language = safestrdup(string(*ktlanguage).c_str());
} }
ktname = FINDFIRST(ktentry, KaxTrackName);
if (ktname != NULL) {
char *tmp;
safefree(track->track_name);
track->track_name =
UTFstring_to_cstrutf8(UTFstring(*ktname));
tmp = UTFstring_to_cstr(UTFstring(*ktname));
if (verbose > 1)
mxinfo(PFX "| + Name: %s\n", tmp);
safefree(tmp);
}
ktentry = FINDNEXT(l1, KaxTrackEntry, ktentry); ktentry = FINDNEXT(l1, KaxTrackEntry, ktentry);
} // while (ktentry != NULL) } // while (ktentry != NULL)
@ -1029,8 +1059,10 @@ void kax_reader_c::create_packetizers() {
memcpy(nti.fourcc, t->v_fourcc, 5); memcpy(nti.fourcc, t->v_fourcc, 5);
if (nti.default_track == 0) if (nti.default_track == 0)
nti.default_track = t->default_track; nti.default_track = t->default_track;
if (nti.language == 0) if (nti.language == NULL)
nti.language = t->language; nti.language = t->language;
if (nti.track_name == NULL)
nti.track_name = t->track_name;
if (t->ok && demuxing_requested(t->type, t->tnum)) { if (t->ok && demuxing_requested(t->type, t->tnum)) {
nti.id = t->tnum; // ID for this track. nti.id = t->tnum; // ID for this track.

View File

@ -73,6 +73,8 @@ typedef struct {
int64_t units_processed; int64_t units_processed;
char *track_name;
int ok; int ok;
generic_packetizer_c *packetizer; generic_packetizer_c *packetizer;