diff --git a/src/common/property_element.cpp b/src/common/property_element.cpp new file mode 100644 index 000000000..b693f3256 --- /dev/null +++ b/src/common/property_element.cpp @@ -0,0 +1,186 @@ +/** + mkvpropedit -- utility for editing properties of existing Matroska files + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html + + \file + + \author Written by Moritz Bunkus . +*/ + +#include "common/os.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "common/ebml.h" +#include "common/translation.h" +#include "common/xml/element_mapping.h" +#include "propedit/property_element.h" + +std::map > property_element_c::s_properties; +std::map > property_element_c::s_composed_properties; + +property_element_c::property_element_c(const std::string &name, + const EbmlCallbacks &callbacks, + const translatable_string_c &title, + const translatable_string_c &description, + const EbmlCallbacks &sub_master_callbacks) + : m_name(name) + , m_title(title) + , m_description(description) + , m_callbacks(&callbacks) + , m_sub_master_callbacks(&sub_master_callbacks) + , m_type(EBMLT_SKIP) +{ + derive_type(); +} + +property_element_c::property_element_c() + : m_callbacks(NULL) + , m_sub_master_callbacks(NULL) + , m_type(EBMLT_SKIP) +{ +} + +bool +property_element_c::is_valid() + const +{ + return !m_name.empty() && (NULL != m_callbacks) && (EBMLT_SKIP != m_type); +} + +void +property_element_c::derive_type() { + EbmlElement *e = &m_callbacks->Create(); + + m_type = NULL != dynamic_cast(e) ? EBMLT_BINARY + : NULL != dynamic_cast(e) ? EBMLT_FLOAT + : NULL != dynamic_cast(e) ? EBMLT_INT + : NULL != dynamic_cast(e) ? EBMLT_STRING + : NULL != dynamic_cast(e) ? EBMLT_UINT + : NULL != dynamic_cast(e) ? EBMLT_USTRING + : EBMLT_SKIP; + + if (EBMLT_SKIP == m_type) + mxerror(boost::format("property_element_c::derive_type(): programming error: unknown type for EBML ID %|1$08x|\n") % m_callbacks->GlobalId.Value); + + if ((EBMLT_UINT == m_type) && (m_name.find("flag") != std::string::npos)) + m_type = EBMLT_BOOL; + + delete e; +} + +#define ELE(name, callbacks, title, description) s_properties[current_index].push_back(property_element_c(name, callbacks, title, description, *sub_master_callbacks)) + +void +property_element_c::init_tables() { + const EbmlCallbacks *sub_master_callbacks = NULL; + + s_properties.clear(); + + s_properties[KaxInfo::ClassInfos.GlobalId.Value] = std::vector(); + s_properties[KaxTracks::ClassInfos.GlobalId.Value] = std::vector(); + uint32_t current_index = KaxInfo::ClassInfos.GlobalId.Value; + + ELE("title", KaxTitle::ClassInfos, Y("Title"), Y("The title for the whole movie.")); + ELE("segment-filename", KaxSegmentFilename::ClassInfos, Y("Segment filename"), Y("The file name for this segment.")); + ELE("prev-filename", KaxPrevFilename::ClassInfos, Y("Previous filename"), Y("An escaped filename corresponding to\nthe previous segment.")); + ELE("next-filename", KaxNextFilename::ClassInfos, Y("Next filename"), Y("An escaped filename corresponding to\nthe next segment.")); + ELE("segment-uid", KaxSegmentUID::ClassInfos, Y("Segment unique ID"), Y("A randomly generated unique ID to identify the current\n" + "segment between many others (128 bits).")); + ELE("prev-uid", KaxPrevUID::ClassInfos, Y("Previous segment's unique ID"), Y("A unique ID to identify the previous chained\nsegment (128 bits).")); + ELE("next-uid", KaxNextUID::ClassInfos, Y("Next segment's unique ID"), Y("A unique ID to identify the next chained\nsegment (128 bits).")); + + current_index = KaxTracks::ClassInfos.GlobalId.Value; + + ELE("track-number", KaxTrackNumber::ClassInfos, Y("Track number"), Y("The track number as used in the Block Header.")); + ELE("track-uid", KaxTrackUID::ClassInfos, Y("Track UID"), Y("A unique ID to identify the Track. This should be\nkept the same when making a " + "direct stream copy\nof the Track to another file.")); + ELE("flag-default", KaxTrackFlagDefault::ClassInfos, Y("'Default track' flag"), Y("Set if that track (audio, video or subs) SHOULD\nbe used if no language found matches the\n" + "user preference.")); + ELE("flag-enabled", KaxTrackFlagEnabled::ClassInfos, Y("'Track enabled' flag"), Y("Set if the track is used.")); + ELE("flag-forced", KaxTrackFlagForced::ClassInfos, Y("'Forced display' flag"), Y("Set if that track MUST be used during playback.\n" + "There can be many forced track for a kind (audio,\nvideo or subs). " + "The player should select the one\nwhose language matches the user preference or the\n" + "default + forced track.")); + ELE("min-cache", KaxTrackMinCache::ClassInfos, Y("Minimum cache"), Y("The minimum number of frames a player\nshould be able to cache during playback.\n" + "If set to 0, the reference pseudo-cache system\nis not used.")); + ELE("max-cache", KaxTrackMaxCache::ClassInfos, Y("Maximum cache"), Y("The maximum number of frames a player\nshould be able to cache during playback.\n" + "If set to 0, the reference pseudo-cache system\nis not used.")); + ELE("default-duration", KaxTrackDefaultDuration::ClassInfos, Y("Default duration"), Y("Number of nanoseconds (not scaled) per frame.")); + ELE("track-timecode-scale", KaxTrackTimecodeScale::ClassInfos, Y("Timecode scaling"), Y("The scale to apply on this track to work at normal\nspeed in relation with other tracks " + "(mostly used\nto adjust video speed when the audio length differs).")); + ELE("name", KaxTrackName::ClassInfos, Y("Name"), Y("A human-readable track name.")); + ELE("language", KaxTrackLanguage::ClassInfos, Y("Language"), Y("Specifies the language of the track in the\nMatroska languages form.")); + ELE("codec-id", KaxCodecID::ClassInfos, Y("Codec ID"), Y("An ID corresponding to the codec.")); + ELE("codec-name", KaxCodecName::ClassInfos, Y("Codec name"), Y("A human-readable string specifying the codec.")); + + sub_master_callbacks = &KaxTrackVideo::ClassInfos; + + ELE("pixel-width", KaxVideoPixelWidth::ClassInfos, Y("Video pixel width"), Y("Width of the encoded video frames in pixels.")); + ELE("pixel-height", KaxVideoPixelHeight::ClassInfos, Y("Video pixel height"), Y("Height of the encoded video frames in pixels.")); + ELE("display-width", KaxVideoDisplayWidth::ClassInfos, Y("Video display width"), Y("Width of the video frames to display.")); + ELE("display-height", KaxVideoDisplayHeight::ClassInfos, Y("Video display height"), Y("Height of the video frames to display.")); + ELE("display-unit", KaxVideoDisplayUnit::ClassInfos, Y("Video display unit"), Y("Type of the unit for DisplayWidth/Height\n(0: pixels, 1: centimeters, 2: inches).")); + ELE("pixel-crop-left", KaxVideoPixelCropLeft::ClassInfos, Y("Video crop left"), Y("The number of video pixels to remove\non the left of the image.")); + ELE("pixel-crop-top", KaxVideoPixelCropTop::ClassInfos, Y("Video crop top"), Y("The number of video pixels to remove\non the top of the image.")); + ELE("pixel-crop-right", KaxVideoPixelCropRight::ClassInfos, Y("Video crop right"), Y("The number of video pixels to remove\non the right of the image.")); + ELE("pixel-crop-bottom", KaxVideoPixelCropBottom::ClassInfos, Y("Video crop bottom"), Y("The number of video pixels to remove\non the bottom of the image.")); + ELE("aspect-ratio-type", KaxVideoAspectRatio::ClassInfos, Y("Video aspect ratio type"), Y("Specify the possible modifications to the aspect ratio\n" + "(0: free resizing, 1: keep aspect ratio, 2: fixed).")); + ELE("stereo-mode", KaxVideoStereoMode::ClassInfos, Y("Video stereo mode"), Y("Stereo-3D video mode (0: mono, 1: right eye,\n2: left eye, 3: both eyes).")); + + sub_master_callbacks = &KaxTrackAudio::ClassInfos; + + ELE("sampling-frequency", KaxAudioSamplingFreq::ClassInfos, Y("Audio sampling frequency"), Y("Sampling frequency in Hz.")); + ELE("output-sampling-frequency", KaxAudioOutputSamplingFreq::ClassInfos, Y("Audio output sampling frequency"), Y("Real output sampling frequency in Hz.")); + ELE("channels", KaxAudioChannels::ClassInfos, Y("Audio channels"), Y("Numbers of channels in the track.")); + ELE("bit-depth", KaxAudioBitDepth::ClassInfos, Y("Audio bit depth"), Y("Bits per sample, mostly used for PCM.")); +} + +std::vector & +property_element_c::get_table_for(const EbmlCallbacks &master_callbacks, + const EbmlCallbacks *sub_master_callbacks, + bool full_table) { + if (s_properties.empty()) + init_tables(); + + std::map >::iterator src_map_it = s_properties.find(master_callbacks.GlobalId.Value); + if (s_properties.end() == src_map_it) + mxerror(boost::format("property_element_c::get_table_for(): programming error: no table found for EBML ID %|1$08x|\n") % master_callbacks.GlobalId.Value); + + if (full_table) + return src_map_it->second; + + uint32_t element_id = NULL == sub_master_callbacks ? master_callbacks.GlobalId.Value : sub_master_callbacks->GlobalId.Value; + std::map >::iterator composed_map_it = s_composed_properties.find(element_id); + if (s_composed_properties.end() != composed_map_it) + return composed_map_it->second; + + s_composed_properties[element_id] = std::vector(); + std::vector &table = s_composed_properties[sub_master_callbacks->GlobalId.Value]; + std::vector::iterator property_it; + + mxforeach(property_it, src_map_it->second) + if ((NULL == property_it->m_sub_master_callbacks) || (sub_master_callbacks->GlobalId == property_it->m_sub_master_callbacks->GlobalId)) + table.push_back(*property_it); + + return table; +} diff --git a/src/common/property_element.h b/src/common/property_element.h new file mode 100644 index 000000000..ee81f384d --- /dev/null +++ b/src/common/property_element.h @@ -0,0 +1,66 @@ +/** + mkvpropedit -- utility for editing properties of existing Matroska files + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html + + \file + + \author Written by Moritz Bunkus . +*/ + +#ifndef __COMMON_PROPERTY_TABLE_H +#define __COMMON_PROPERTY_TABLE_H + +#include "common/os.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "common/ebml.h" +#include "common/translation.h" +#include "common/xml/element_mapping.h" + +#define NO_CONTAINER EbmlId(static_cast(0), 0) + +class property_element_c { +public: + std::string m_name; + translatable_string_c m_title, m_description; + + const EbmlCallbacks *m_callbacks; + const EbmlCallbacks *m_sub_master_callbacks; + + ebml_type_e m_type; + + property_element_c(); + property_element_c(const std::string &name, const EbmlCallbacks &callbacks, const translatable_string_c &title, const translatable_string_c &description, + const EbmlCallbacks &sub_master_callbacks); + + bool is_valid() const; + +private: + void derive_type(); + +private: // static + static std::map > s_properties; + static std::map > s_composed_properties; + +public: // static + static void init_tables(); + static std::vector &get_table_for(const EbmlCallbacks &master_callbacks, const EbmlCallbacks *sub_master_callbacks = NULL, bool full_table = false); +}; +typedef counted_ptr property_element_cptr; + +#endif // __COMMON_PROPERTY_TABLE_H