diff --git a/ChangeLog b/ChangeLog index 62abaca81..933ea389c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2003-09-12 Moritz Bunkus + * mkvmerge: Support for setting the track names. + * mkvmerge: For Matroska source files: If the source contains chapters then these are kept unless the user specified chapters with --chapters. diff --git a/doc/mkvmerge.1 b/doc/mkvmerge.1 index d0b18e57f..03871454d 100644 --- a/doc/mkvmerge.1 +++ b/doc/mkvmerge.1 @@ -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 tracks by selecting different track IDs each time. .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> 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 diff --git a/src/mkvmerge.cpp b/src/mkvmerge.cpp index 647d8256f..0305fe3a6 100644 --- a/src/mkvmerge.cpp +++ b/src/mkvmerge.cpp @@ -168,7 +168,7 @@ char *chapter_file_name = NULL; char *chapter_language = NULL; char *chapter_charset = NULL; -string title; +string segment_title; int64_t tags_size = 0; bool accept_tags = true; @@ -283,6 +283,7 @@ static void usage() { " omitted. Both o and p can be floating point\n" " numbers.\n" " --default-track Sets the 'default' flag for this track.\n" + " --track-name Sets the name for a track.\n" " --cues \n" " Create cue (index) entries for this track:\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()); } -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; string orig = s; // Extract the track number. if ((colon = strchr(s, ':')) == NULL) - mxerror("Invalid language option. No track ID specified in " - "'--language %s'.\n", orig.c_str()); + mxerror("No track ID specified in '--%s' %s'.\n", opt, orig.c_str()); *colon = 0; 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]; 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 " "'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); GetChild(*kax_infos).SetEpochDate(time(NULL)); - if (title.length() > 0) + if (segment_title.length() > 0) *((EbmlUnicodeString *)&GetChild(*kax_infos)) = - cstr_to_UTFstring(title.c_str()); + cstrutf8_to_UTFstring(segment_title.c_str()); // Generate the segment UIDs. if (first_file) { @@ -1007,6 +1008,7 @@ static void identify(const char *filename) { ti.stracks = new vector; ti.aac_is_sbr = new vector; ti.compression_list = new vector; + ti.track_names = new vector; file = (filelist_t *)safemalloc(sizeof(filelist_t)); @@ -1064,6 +1066,7 @@ static void parse_args(int argc, char **argv) { ti.vtracks = new vector; ti.stracks = new vector; ti.compression_list = new vector; + ti.track_names = new vector; attachment = (attachment_t *)safemalloc(sizeof(attachment_t)); memset(attachment, 0, sizeof(attachment_t)); memset(&tags, 0, sizeof(tags_t)); @@ -1147,10 +1150,13 @@ static void parse_args(int argc, char **argv) { verbose = 2; else if (!strcmp(this_arg, "--title")) { + char *tmp; if ((next_arg == NULL) || (next_arg[0] == 0)) mxerror("'--title' lacks the title.\n"); - title = next_arg; + tmp = to_utf8(cc_local_utf8, next_arg); + segment_title = tmp; + safefree(tmp); i++; } else if (!strcmp(this_arg, "--split")) { @@ -1452,7 +1458,7 @@ static void parse_args(int argc, char **argv) { if (next_arg == NULL) mxerror("'--language' lacks its argument.\n"); - parse_language(next_arg, lang); + parse_language(next_arg, lang, "language", "language", true); ti.languages->push_back(lang); i++; @@ -1491,6 +1497,15 @@ static void parse_args(int argc, char **argv) { ti.compression_list->push_back(cues); 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. @@ -1537,6 +1552,9 @@ static void parse_args(int argc, char **argv) { delete ti.all_tags; delete ti.aac_is_sbr; 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)); ti.audio_syncs = new vector; ti.cue_creations = new vector; @@ -1550,6 +1568,7 @@ static void parse_args(int argc, char **argv) { ti.vtracks = new vector; ti.stracks = new vector; ti.compression_list = new vector; + ti.track_names = new vector; } } @@ -1584,6 +1603,9 @@ static void parse_args(int argc, char **argv) { delete ti.vtracks; delete ti.stracks; 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); } diff --git a/src/mkvmerge.h b/src/mkvmerge.h index 1ea2ea770..08a5154fa 100644 --- a/src/mkvmerge.h +++ b/src/mkvmerge.h @@ -46,6 +46,7 @@ extern KaxSeekHead *kax_sh_main, *kax_sh_cues; extern KaxChapters *kax_chapters; extern int track_number; extern int64_t tags_size; +extern string segment_title; extern float video_fps; diff --git a/src/pr_generic.cpp b/src/pr_generic.cpp index 67a94687a..670951ee7 100644 --- a/src/pr_generic.cpp +++ b/src/pr_generic.cpp @@ -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'. hserialno = track_number++; huid = 0; @@ -246,6 +256,11 @@ int generic_packetizer_c::get_track_num() { 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) { safefree(hcodec_id); if (id == NULL) { @@ -426,11 +441,15 @@ void generic_packetizer_c::set_headers() { *(static_cast (&GetChild(*track_entry))) = 0; - if (ti->language != NULL) { + if (ti->language != NULL) *(static_cast (&GetChild(*track_entry))) = ti->language; - } + if (ti->track_name != NULL) + *(static_cast + (&GetChild(*track_entry))) = + cstrutf8_to_UTFstring(ti->track_name); + if (htrack_type == track_video) { KaxTrackVideo &video = GetChild(*track_entry); @@ -662,19 +681,24 @@ track_info_t *duplicate_track_info(track_info_t *src) { dst->languages = new vector(*src->languages); for (i = 0; i < src->languages->size(); i++) (*dst->languages)[i].language = safestrdup((*src->languages)[i].language); + dst->language = safestrdup(src->language); dst->sub_charsets = new vector(*src->sub_charsets); for (i = 0; i < src->sub_charsets->size(); i++) (*dst->sub_charsets)[i].language = safestrdup((*src->sub_charsets)[i].language); + dst->sub_charset = safestrdup(src->sub_charset); dst->all_tags = new vector(*src->all_tags); for (i = 0; i < src->all_tags->size(); i++) (*dst->all_tags)[i].file_name = safestrdup((*src->all_tags)[i].file_name); dst->aac_is_sbr = new vector(*src->aac_is_sbr); dst->private_data = (unsigned char *)safememdup(src->private_data, src->private_size); - dst->language = safestrdup(src->language); - dst->sub_charset = safestrdup(src->sub_charset); dst->compression_list = new vector(*src->compression_list); + dst->track_names = new vector(*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; return dst; @@ -696,17 +720,21 @@ void free_track_info(track_info_t *ti) { for (i = 0; i < ti->languages->size(); i++) safefree((*ti->languages)[i].language); delete ti->languages; + safefree(ti->language); for (i = 0; i < ti->sub_charsets->size(); i++) safefree((*ti->sub_charsets)[i].language); delete ti->sub_charsets; + safefree(ti->sub_charset); for (i = 0; i < ti->all_tags->size(); i++) safefree((*ti->all_tags)[i].file_name); delete ti->all_tags; delete ti->aac_is_sbr; 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->sub_charset); if (ti->tags != NULL) delete ti->tags; safefree(ti); diff --git a/src/pr_generic.h b/src/pr_generic.h index 4799a0de0..4e244b9ec 100644 --- a/src/pr_generic.h +++ b/src/pr_generic.h @@ -115,6 +115,9 @@ typedef struct { vector *compression_list; // As given on the command line int compression; // For this very track + vector *track_names; // As given on the command line + char *track_name; // For this very track + bool no_chapters; } track_info_t; @@ -213,6 +216,8 @@ public: virtual void set_tag_track_uid(); + virtual void set_track_name(const char *name); + protected: virtual void dump_packet(const void *buffer, int size); }; diff --git a/src/r_matroska.cpp b/src/r_matroska.cpp index 8cf99e7ca..aced3d460 100644 --- a/src/r_matroska.cpp +++ b/src/r_matroska.cpp @@ -136,6 +136,8 @@ kax_reader_c::~kax_reader_c() { delete tracks[i]->packetizer; safefree(tracks[i]->private_data); safefree(tracks[i]->codec_id); + safefree(tracks[i]->language); + safefree(tracks[i]->track_name); safefree(tracks[i]); } @@ -664,6 +666,7 @@ int kax_reader_c::read_headers() { if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) { KaxTimecodeScale *ktc_scale; KaxDuration *kduration; + KaxTitle *ktitle; // General info about this Matroska file if (verbose > 1) @@ -687,6 +690,20 @@ int kax_reader_c::read_headers() { 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) { KaxTrackEntry *ktentry; @@ -712,6 +729,7 @@ int kax_reader_c::read_headers() { KaxTrackFlagDefault *ktfdefault; KaxTrackLanguage *ktlanguage; KaxTrackMinCache *ktmincache; + KaxTrackName *ktname; if (verbose > 1) mxinfo(PFX "| + a track...\n"); @@ -909,6 +927,18 @@ int kax_reader_c::read_headers() { 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); } // while (ktentry != NULL) @@ -1029,8 +1059,10 @@ void kax_reader_c::create_packetizers() { memcpy(nti.fourcc, t->v_fourcc, 5); if (nti.default_track == 0) nti.default_track = t->default_track; - if (nti.language == 0) + if (nti.language == NULL) nti.language = t->language; + if (nti.track_name == NULL) + nti.track_name = t->track_name; if (t->ok && demuxing_requested(t->type, t->tnum)) { nti.id = t->tnum; // ID for this track. diff --git a/src/r_matroska.h b/src/r_matroska.h index 1af3c85ac..96a98fa6f 100644 --- a/src/r_matroska.h +++ b/src/r_matroska.h @@ -73,6 +73,8 @@ typedef struct { int64_t units_processed; + char *track_name; + int ok; generic_packetizer_c *packetizer;