1 /*
2    mkvmerge -- utility for splicing together matroska files
3    from component media subtypes
4 
5    Distributed under the GPL v2
6    see the file COPYING for details
7    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8 
9    Written by Moritz Bunkus <moritz@bunkus.org>.
10 */
11 
12 #include "common/common_pch.h"
13 
14 #include "common/construct.h"
15 #include "common/date_time.h"
16 #include "common/strings/formatting.h"
17 #include "common/tags/tags.h"
18 #include "common/track_statistics.h"
19 
20 void
create_tags(libmatroska::KaxTags & tags,std::string const & writing_app,std::optional<QDateTime> const & writing_date) const21 track_statistics_c::create_tags(libmatroska::KaxTags &tags,
22                                 std::string const &writing_app,
23                                 std::optional<QDateTime> const &writing_date)
24   const {
25   auto bps      = get_bits_per_second();
26   auto duration = get_duration();
27   auto names    = std::vector<std::string>{ "BPS"s, "DURATION"s, "NUMBER_OF_FRAMES"s, "NUMBER_OF_BYTES"s };
28 
29   mtx::tags::remove_simple_tags_for<libmatroska::KaxTagTrackUID>(tags, m_track_uid, "BPS");
30   mtx::tags::remove_simple_tags_for<libmatroska::KaxTagTrackUID>(tags, m_track_uid, "DURATION");
31   mtx::tags::remove_simple_tags_for<libmatroska::KaxTagTrackUID>(tags, m_track_uid, "NUMBER_OF_FRAMES");
32   mtx::tags::remove_simple_tags_for<libmatroska::KaxTagTrackUID>(tags, m_track_uid, "NUMBER_OF_BYTES");
33 
34   auto tag = find_or_create_tag(tags);
35 
36   mtx::tags::set_simple(*tag, "BPS",              fmt::to_string(bps ? *bps : 0));
37   mtx::tags::set_simple(*tag, "DURATION",         mtx::string::format_timestamp(duration ? *duration : 0));
38   mtx::tags::set_simple(*tag, "NUMBER_OF_FRAMES", fmt::to_string(m_num_frames));
39   mtx::tags::set_simple(*tag, "NUMBER_OF_BYTES",  fmt::to_string(m_num_bytes));
40 
41   if (!m_source_id.empty()) {
42     mtx::tags::set_simple(*tag, "SOURCE_ID", m_source_id);
43     names.emplace_back("SOURCE_ID"s);
44   }
45 
46   mtx::tags::set_simple(*tag, "_STATISTICS_WRITING_APP", writing_app);
47 
48   if (writing_date) {
49     auto writing_date_str = mtx::date_time::format(writing_date->toUTC(), "%Y-%m-%d %H:%M:%S");
50     mtx::tags::set_simple(*tag, "_STATISTICS_WRITING_DATE_UTC", writing_date_str);
51   }
52 
53   mtx::tags::set_simple(*tag, "_STATISTICS_TAGS", mtx::string::join(names, " "));
54 }
55 
56 libmatroska::KaxTag *
find_or_create_tag(libmatroska::KaxTags & tags) const57 track_statistics_c::find_or_create_tag(libmatroska::KaxTags &tags)
58   const {
59   for (auto &element : tags) {
60     auto tag = dynamic_cast<libmatroska::KaxTag *>(element);
61     if (!tag)
62       continue;
63 
64     auto targets = FindChild<libmatroska::KaxTagTargets>(*tag);
65     if (!targets)
66       continue;
67 
68     auto actual_target_type_value = static_cast<mtx::tags::target_type_e>(FindChildValue<libmatroska::KaxTagTargetTypeValue>(*targets, 0ull));
69     auto actual_id                = FindChildValue<libmatroska::KaxTagTrackUID>(*targets, 0ull);
70     auto actual_target_type       = FindChild<libmatroska::KaxTagTargetType>(*targets);
71 
72     if (   (actual_target_type_value == mtx::tags::Movie)
73         && (actual_id                == m_track_uid)
74         && !actual_target_type)
75       return tag;
76   }
77 
78   using namespace mtx::construct;
79 
80   auto tag = cons<libmatroska::KaxTag>(cons<libmatroska::KaxTagTargets>(new libmatroska::KaxTagTargetTypeValue, mtx::tags::Movie,
81                                                                         new libmatroska::KaxTagTrackUID,        m_track_uid));
82   tags.PushElement(*tag);
83 
84   return tag;
85 }
86