From c9e0a7bffb681587478b0f619830c4d0203affa3 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Sun, 8 Jun 2003 19:00:33 +0000 Subject: [PATCH] Implemented support for SegmentUID, PrevUID and NextUID. --- ChangeLog | 8 +++ cluster_helper.cpp | 21 ++++---- cluster_helper.h | 8 ++- mkvinfo.cpp | 32 ++++++++++- mkvmerge.cpp | 131 ++++++++++++++++++++++++++++++++++++++++----- mkvmerge.h | 4 +- 6 files changed, 175 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 941aa210a..ee9b11e9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-06-08 Moritz Bunkus + + * Added support for splitting output files by size or by time and + limiting the number of output files. + + * Added support for the segment UID/next segment UID/previous + segment UID. + 2003-06-06 Moritz Bunkus * A lot of changes to comply with libmatroska/libebml 0.4.4. diff --git a/cluster_helper.cpp b/cluster_helper.cpp index 40fe26cde..3a1f33eab 100644 --- a/cluster_helper.cpp +++ b/cluster_helper.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: cluster_helper.cpp,v 1.24 2003/06/08 16:14:05 mosu Exp $ + \version \$Id: cluster_helper.cpp,v 1.25 2003/06/08 18:59:43 mosu Exp $ \brief cluster helper \author Moritz Bunkus */ @@ -28,7 +28,7 @@ #include "StdIOCallback.h" -vector splitpoints; +vector cluster_helper_c::splitpoints; //#define walk_clusters() check_clusters(__LINE__) #define walk_clusters() @@ -230,6 +230,10 @@ void cluster_helper_c::find_next_splitpoint() { next_splitpoint = i; } +int cluster_helper_c::get_next_splitpoint() { + return next_splitpoint; +} + void cluster_helper_c::set_output(mm_io_c *nout) { out = nout; } @@ -252,12 +256,8 @@ int cluster_helper_c::render() { cluster = clstr->cluster; // Splitpoint stuff - if (header_overhead == -1) { - if (pass != 0) - header_overhead = out->getFilePointer(); - if (pass == 2) - find_next_splitpoint(); - } + if ((header_overhead == -1) && (pass != 0)) + header_overhead = out->getFilePointer(); elements_in_cluster = 0; num_cue_elements_here = 0; @@ -362,13 +362,14 @@ int cluster_helper_c::render() { if (kax_seekhead != NULL) kax_seekhead->IndexThis(*cluster, *kax_segment); } + find_next_splitpoint(); old_max_timecode = max_timecode; max_timecode = pack->timecode; fprintf(stdout, "\n"); finish_file(); - create_next_output_file(); + create_next_output_file(next_splitpoint >= splitpoints.size()); max_timecode = old_max_timecode; @@ -381,8 +382,6 @@ int cluster_helper_c::render() { elements_in_cluster = 0; timecode_offset = pack->timecode; - - find_next_splitpoint(); } } diff --git a/cluster_helper.h b/cluster_helper.h index 07596b07a..8dbff4a8e 100644 --- a/cluster_helper.h +++ b/cluster_helper.h @@ -13,7 +13,7 @@ /*! \file - \version \$Id: cluster_helper.h,v 1.7 2003/06/08 15:38:03 mosu Exp $ + \version \$Id: cluster_helper.h,v 1.8 2003/06/08 18:59:43 mosu Exp $ \brief class definition for the cluster helper \author Moritz Bunkus */ @@ -45,6 +45,9 @@ private: int64_t max_timecode, last_cluster_tc, num_cue_elements, header_overhead; int64_t packet_num, timecode_offset; mm_io_c *out; +public: + static vector splitpoints; + public: cluster_helper_c(); virtual ~cluster_helper_c(); @@ -61,6 +64,8 @@ public: int free_clusters(); int get_cluster_content_size(); int64_t get_max_timecode(); + void find_next_splitpoint(); + int get_next_splitpoint(); private: int find_cluster(KaxCluster *cluster); @@ -68,7 +73,6 @@ private: packet_t *find_packet(int64_t ref_timecode); void free_contents(ch_contents_t *clstr); void check_clusters(int num); - void find_next_splitpoint(); }; extern cluster_helper_c *cluster_helper; diff --git a/mkvinfo.cpp b/mkvinfo.cpp index 9b1c9a9cf..b9ce6bfa4 100644 --- a/mkvinfo.cpp +++ b/mkvinfo.cpp @@ -12,7 +12,7 @@ /*! \file - \version \$Id: mkvinfo.cpp,v 1.57 2003/06/07 14:30:10 mosu Exp $ + \version \$Id: mkvinfo.cpp,v 1.58 2003/06/08 18:59:43 mosu Exp $ \brief retrieves and displays information about a Matroska file \author Moritz Bunkus */ @@ -344,6 +344,36 @@ bool process_file(const char *file_name) { } else show_element(l2, 2, "Date (invalid, value: %d)", temptime); + } else if (EbmlId(*l2) == KaxSegmentUID::ClassInfos.GlobalId) { + KaxSegmentUID &uid = *static_cast(l2); + uid.ReadData(es->I_O()); + char buffer[uid.GetSize() * 5 + 1]; + const unsigned char *b = (const unsigned char *)&binary(uid); + buffer[0] = 0; + for (i = 0; i < uid.GetSize(); i++) + sprintf(&buffer[strlen(buffer)], " 0x%02x", b[i]); + show_element(l2, 2, "Segment UID:%s", buffer); + + } else if (EbmlId(*l2) == KaxPrevUID::ClassInfos.GlobalId) { + KaxPrevUID &uid = *static_cast(l2); + uid.ReadData(es->I_O()); + char buffer[uid.GetSize() * 5 + 1]; + const unsigned char *b = (const unsigned char *)&binary(uid); + buffer[0] = 0; + for (i = 0; i < uid.GetSize(); i++) + sprintf(&buffer[strlen(buffer)], " 0x%02x", b[i]); + show_element(l2, 2, "Previous segment UID:%s", buffer); + + } else if (EbmlId(*l2) == KaxNextUID::ClassInfos.GlobalId) { + KaxNextUID &uid = *static_cast(l2); + uid.ReadData(es->I_O()); + char buffer[uid.GetSize() * 5 + 1]; + const unsigned char *b = (const unsigned char *)&binary(uid); + buffer[0] = 0; + for (i = 0; i < uid.GetSize(); i++) + sprintf(&buffer[strlen(buffer)], " 0x%02x", b[i]); + show_element(l2, 2, "Next segment UID:%s", buffer); + } else if (!is_ebmlvoid(l2, 2)) show_unknown_element(l2, 2); diff --git a/mkvmerge.cpp b/mkvmerge.cpp index c398442e7..959883504 100644 --- a/mkvmerge.cpp +++ b/mkvmerge.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: mkvmerge.cpp,v 1.91 2003/06/08 16:14:05 mosu Exp $ + \version \$Id: mkvmerge.cpp,v 1.92 2003/06/08 18:59:43 mosu Exp $ \brief command line parameter parsing, looping, output handling \author Moritz Bunkus */ @@ -80,6 +80,80 @@ using namespace LIBMATROSKA_NAMESPACE; using namespace std; +class bitvalue_c { +private: + unsigned char *value; + int bitsize; +public: + bitvalue_c(int nsize); + bitvalue_c(const bitvalue_c &src); + virtual ~bitvalue_c(); + + bitvalue_c &operator =(const bitvalue_c &src); + bool operator ==(const bitvalue_c &cmp) const; + unsigned char operator [](int index) const; + + int size() const; + void generate_random(); + unsigned char *data() const; +}; + +bitvalue_c::bitvalue_c(int nbitsize) { + assert(nbitsize > 0); + assert((nbitsize % 8) == 0); + bitsize = nbitsize; + value = (unsigned char *)safemalloc(bitsize / 8); + memset(value, 0, bitsize / 8); +} + +bitvalue_c::bitvalue_c(const bitvalue_c &src) { + value = NULL; + *this = src; +} + +bitvalue_c &bitvalue_c::operator =(const bitvalue_c &src) { + safefree(value); + bitsize = src.bitsize; + value = (unsigned char *)safememdup(src.value, bitsize / 8); + + return *this; +} + +bitvalue_c::~bitvalue_c() { + safefree(value); +} + +bool bitvalue_c::operator ==(const bitvalue_c &cmp) const { + int i; + + if (cmp.bitsize != bitsize) + return false; + for (i = 0; i < bitsize / 8; i++) + if (value[i] != cmp.value[i]) + return false; + return true; +} + +unsigned char bitvalue_c::operator [](int index) const { + assert((index >= 0) && (index < (bitsize / 8))); + return value[index]; +} + +int bitvalue_c::size() const { + return bitsize; +} + +unsigned char *bitvalue_c::data() const { + return value; +} + +void bitvalue_c::generate_random() { + int i; + + for (i = 0; i < bitsize / 8; i++) + value[i] = (unsigned char)(255.0 * rand() / RAND_MAX); +} + typedef struct { char *ext; int type; @@ -146,6 +220,8 @@ int track_number = 1; mm_io_c *out; +bitvalue_c seguid_prev(128), seguid_current(128), seguid_next(128); + file_type_t file_types[] = {{"---", TYPEUNKNOWN, ""}, {"demultiplexers:", -1, ""}, @@ -509,7 +585,7 @@ static void parse_split(const char *arg) { split_by_time = false; } -static void render_headers(mm_io_c *out) { +static void render_headers(mm_io_c *out, bool last_file, bool first_file) { EbmlHead head; int i; @@ -539,6 +615,31 @@ static void render_headers(mm_io_c *out) { cstr_to_UTFstring(VERSIONINFO); GetChild(*kax_infos).SetEpochDate(time(NULL)); + // Generate the segment UIDs. + if (first_file) { + seguid_current.generate_random(); + if (!last_file) + seguid_next.generate_random(); + } else { + seguid_prev = seguid_current; + seguid_current = seguid_next; + if (!last_file) + seguid_next.generate_random(); + } + + // Set the segment UIDs. + KaxSegmentUID &kax_seguid = GetChild(*kax_infos); + kax_seguid.CopyBuffer(seguid_current.data(), 128 / 8); + + if (!first_file) { + KaxPrevUID &kax_prevuid = GetChild(*kax_infos); + kax_prevuid.CopyBuffer(seguid_prev.data(), 128 / 8); + } + if (!last_file) { + KaxNextUID &kax_nextuid = GetChild(*kax_infos); + kax_nextuid.CopyBuffer(seguid_next.data(), 128 / 8); + } + kax_segment->WriteHead(*out, 5); // Reserve some space for the meta seek stuff. @@ -618,7 +719,8 @@ static void parse_args(int argc, char **argv) { } if (outfile == NULL) { - fprintf(stderr, "Error: no output files given.\n"); + fprintf(stderr, "Error: no output file given.\n\n"); + usage(); exit(1); } @@ -1196,13 +1298,16 @@ string create_output_name() { return s; } -void create_next_output_file() { +void create_next_output_file(bool last_file, bool first_file) { string this_outfile; kax_segment = new KaxSegment(); kax_cues = new KaxCues(); kax_cues->SetGlobalTimecodeScale(TIMECODE_SCALE); + fprintf(stdout, "createnext: last: %s, first: %s\n", last_file ? "true" : + "false", first_file ? "true" : "false"); + if (pass == 1) { // Open the a dummy file. try { @@ -1213,7 +1318,7 @@ void create_next_output_file() { } cluster_helper->set_output(out); - render_headers(out); + render_headers(out, last_file, first_file); return; } @@ -1235,7 +1340,7 @@ void create_next_output_file() { fprintf(stdout, "Opened '%s\' for writing.\n", this_outfile.c_str()); cluster_helper->set_output(out); - render_headers(out); + render_headers(out, last_file, first_file); file_num++; } @@ -1362,8 +1467,6 @@ void main_loop() { } } -extern vectorsplitpoints; - int main(int argc, char **argv) { int i; @@ -1380,15 +1483,15 @@ int main(int argc, char **argv) { create_readers(); pass = 1; - create_next_output_file(); + create_next_output_file(true, true); main_loop(); finish_file(); fprintf(stdout, "\nPass 2: merging the files. This will take even longer." "\n\n"); - for (i = 0; i < splitpoints.size(); i++) { - splitpoint_t *sp = splitpoints[i]; + for (i = 0; i < cluster_helper_c::splitpoints.size(); i++) { + splitpoint_t *sp = cluster_helper_c::splitpoints[i]; fprintf(stdout, "%d: tc %lld, fpos %lld + cues %lld = %lld, pn: %lld\n", i, sp->timecode, sp->filepos, sp->cues_size, sp->filepos + sp->cues_size, sp->packet_num); @@ -1399,10 +1502,12 @@ int main(int argc, char **argv) { init_globals(); cluster_helper = new cluster_helper_c(); + cluster_helper->find_next_splitpoint(); create_readers(); pass = 2; - create_next_output_file(); + create_next_output_file(cluster_helper->get_next_splitpoint() >= + cluster_helper_c::splitpoints.size(), true); main_loop(); finish_file(); @@ -1411,7 +1516,7 @@ int main(int argc, char **argv) { create_readers(); pass = 0; - create_next_output_file(); + create_next_output_file(true, true); main_loop(); finish_file(); } diff --git a/mkvmerge.h b/mkvmerge.h index 57f37fedb..490c059c2 100644 --- a/mkvmerge.h +++ b/mkvmerge.h @@ -13,7 +13,7 @@ /*! \file - \version \$Id: mkvmerge.h,v 1.15 2003/06/08 16:14:05 mosu Exp $ + \version \$Id: mkvmerge.h,v 1.16 2003/06/08 18:59:43 mosu Exp $ \brief definition of global variables found in mkvmerge.cpp \author Moritz Bunkus */ @@ -47,7 +47,7 @@ extern bool no_lacing; void add_packetizer(generic_packetizer_c *packetizer); -void create_next_output_file(); +void create_next_output_file(bool last_file = false, bool first_file = false); void finish_file(); string create_output_name();