1 #include "dynamic_depth/device.h"
2
3 #include <libxml/tree.h>
4
5 #include "android-base/logging.h"
6 #include "dynamic_depth/const.h"
7 #include "dynamic_depth/vendor_info.h"
8 #include "xmpmeta/xml/const.h"
9 #include "xmpmeta/xml/deserializer_impl.h"
10 #include "xmpmeta/xml/search.h"
11 #include "xmpmeta/xml/serializer_impl.h"
12 #include "xmpmeta/xml/utils.h"
13 #include "xmpmeta/xmp_data.h"
14 #include "xmpmeta/xmp_parser.h"
15 #include "xmpmeta/xmp_writer.h"
16
17 using ::dynamic_depth::xmpmeta::CreateXmpData;
18 using ::dynamic_depth::xmpmeta::XmpData;
19 using ::dynamic_depth::xmpmeta::xml::DepthFirstSearch;
20 using ::dynamic_depth::xmpmeta::xml::DeserializerImpl;
21 using ::dynamic_depth::xmpmeta::xml::GetFirstDescriptionElement;
22 using ::dynamic_depth::xmpmeta::xml::Serializer;
23 using ::dynamic_depth::xmpmeta::xml::SerializerImpl;
24 using ::dynamic_depth::xmpmeta::xml::ToXmlChar;
25 using ::dynamic_depth::xmpmeta::xml::XmlConst;
26
27 namespace dynamic_depth {
28 namespace {
29
30 const char kRevision[] = "Revision";
31 const char kNamespaceHref[] = "http://ns.google.com/photos/dd/1.0/device/";
32
33 // Parses Device fields and children elements from xmlDocPtr.
ParseFields(const xmlDocPtr & xmlDoc)34 std::unique_ptr<Device> ParseFields(const xmlDocPtr& xmlDoc) {
35 // Find and parse the Device node.
36 // Only these two fields are required to be present; the rest are optional.
37 // TODO(miraleung): Search for Device by namespace.
38 xmlNodePtr description_node =
39 DepthFirstSearch(xmlDoc, XmlConst::RdfDescription());
40 if (description_node == nullptr) {
41 LOG(ERROR) << "No rdf description found";
42 return nullptr;
43 }
44
45 const DeserializerImpl deserializer(description_node);
46 auto cameras = Cameras::FromDeserializer(deserializer);
47 if (cameras == nullptr) {
48 LOG(ERROR) << "No cameras found";
49 return nullptr;
50 }
51
52 auto container = Container::FromDeserializer(deserializer);
53
54 // The list of cameras is now guaranteed to have at least one element, because
55 // of implementation in cameras.cc
56 auto planes = Planes::FromDeserializer(deserializer);
57 auto earth_pose = EarthPose::FromDeserializer(deserializer);
58 auto pose = Pose::FromDeserializer(deserializer, DynamicDepthConst::Device());
59 auto profiles = Profiles::FromDeserializer(deserializer);
60 auto vendor_info =
61 VendorInfo::FromDeserializer(deserializer, DynamicDepthConst::Device());
62 auto app_info =
63 AppInfo::FromDeserializer(deserializer, DynamicDepthConst::Device());
64
65 std::unique_ptr<DeviceParams> params(
66 new DeviceParams(std::move(cameras))); // NOLINT
67 params->container = std::move(container);
68 params->planes = std::move(planes);
69 params->earth_pose = std::move(earth_pose);
70 params->pose = std::move(pose);
71 params->profiles = std::move(profiles);
72 params->vendor_info = std::move(vendor_info);
73 params->app_info = std::move(app_info);
74 return Device::FromData(std::move(params));
75 }
76
77 // Parses Device fields and children elements from XmpData.
ParseFields(const XmpData & xmp)78 std::unique_ptr<Device> ParseFields(const XmpData& xmp) {
79 if (xmp.ExtendedSection() == nullptr) {
80 LOG(ERROR) << "XMP extended section is null";
81 return nullptr;
82 }
83
84 return ParseFields(xmp.ExtendedSection());
85 }
86
87 } // namespace
88
89 // Private constructor.
Device(std::unique_ptr<DeviceParams> params)90 Device::Device(std::unique_ptr<DeviceParams> params) {
91 params_ = std::move(params);
92 }
93
94 // Public methods.
FromData(std::unique_ptr<DeviceParams> params)95 std::unique_ptr<Device> Device::FromData(std::unique_ptr<DeviceParams> params) {
96 if (params->cameras == nullptr) {
97 LOG(ERROR) << "At least one camera must be provided";
98 return nullptr;
99 }
100
101 // The list of cameras is now guaranteed to have at least one element, because
102 // of the implementation in cameras.cc
103 return std::unique_ptr<Device>(new Device(std::move(params))); // NOLINT
104 }
105
FromXmp(const XmpData & xmp)106 std::unique_ptr<Device> Device::FromXmp(const XmpData& xmp) {
107 return ParseFields(xmp);
108 }
109
FromJpegFile(const string & filename)110 std::unique_ptr<Device> Device::FromJpegFile(const string& filename) {
111 XmpData xmp;
112 const bool kSkipExtended = false;
113 if (!ReadXmpHeader(filename, kSkipExtended, &xmp)) {
114 return nullptr;
115 }
116 return FromXmp(xmp);
117 }
118
119 // Creates a Device by parsing XML file containing the metadata.
FromXmlFile(const string & filename)120 std::unique_ptr<Device> Device::FromXmlFile(const string& filename) {
121 xmlDocPtr xmlDoc = xmlReadFile(filename.c_str(), nullptr, 0);
122 if (xmlDoc == nullptr) {
123 LOG(ERROR) << "Failed to read file: " << filename;
124 return nullptr;
125 }
126
127 auto device = ParseFields(xmlDoc);
128 xmlFreeDoc(xmlDoc);
129 return device;
130 }
131
GetCameras() const132 const Cameras* Device::GetCameras() const { return params_->cameras.get(); }
133
GetContainer() const134 const Container* Device::GetContainer() const {
135 return params_->container.get();
136 }
137
GetEarthPose() const138 const EarthPose* Device::GetEarthPose() const {
139 return params_->earth_pose.get();
140 }
141
GetPose() const142 const Pose* Device::GetPose() const { return params_->pose.get(); }
143
GetPlanes() const144 const Planes* Device::GetPlanes() const { return params_->planes.get(); }
145
GetProfiles() const146 const Profiles* Device::GetProfiles() const { return params_->profiles.get(); }
147
GetVendorInfo() const148 const VendorInfo* Device::GetVendorInfo() const {
149 return params_->vendor_info.get();
150 }
151
GetAppInfo() const152 const AppInfo* Device::GetAppInfo() const { return params_->app_info.get(); }
153
154 // This cannot be const because of memory management for the namespaces.
155 // namespaces_ are freed when the XML document(s) in xmp are freed.
156 // If namespaces_ are populated at object creation time and this
157 // object is serialized, freeing the xmlNs objects in the destructor will result
158 // memory management errors.
SerializeToXmp(XmpData * xmp)159 bool Device::SerializeToXmp(XmpData* xmp) {
160 if (xmp == nullptr || xmp->StandardSection() == nullptr ||
161 xmp->ExtendedSection() == nullptr) {
162 LOG(ERROR) << "XmpData or its sections are null";
163 return false;
164 }
165 return Serialize(xmp->MutableExtendedSection());
166 }
167
SerializeToXmlFile(const char * filename)168 bool Device::SerializeToXmlFile(const char* filename) {
169 std::unique_ptr<XmpData> xmp_data = CreateXmpData(true);
170 if (!Serialize(xmp_data->MutableExtendedSection())) {
171 return false;
172 }
173 return xmlSaveFile(filename, xmp_data->ExtendedSection()) != -1;
174 }
175
176 // Private methods.
Serialize(xmlDocPtr * xmlDoc)177 bool Device::Serialize(xmlDocPtr* xmlDoc) {
178 xmlNodePtr root_node = GetFirstDescriptionElement(*xmlDoc);
179 if (root_node == nullptr) {
180 LOG(ERROR) << "Extended section has no rdf:Description node";
181 return false;
182 }
183
184 if (params_->cameras == nullptr) {
185 LOG(ERROR) << "At least one camera must be present, stopping serialization";
186 return false;
187 }
188
189 PopulateNamespaces();
190 xmlNsPtr prev_ns = root_node->ns;
191 for (const auto& entry : namespaces_) {
192 if (prev_ns != nullptr) {
193 prev_ns->next = entry.second;
194 }
195 prev_ns = entry.second;
196 }
197
198 // Set up serialization on the first description node in the extended section.
199 SerializerImpl device_serializer(namespaces_, root_node);
200
201 // Serialize elements.
202 if (params_->container &&
203 !params_->container->Serialize(&device_serializer)) {
204 return false;
205 }
206
207 if (params_->earth_pose) {
208 std::unique_ptr<Serializer> earth_pose_serializer =
209 device_serializer.CreateSerializer(
210 DynamicDepthConst::Namespace(DynamicDepthConst::EarthPose()),
211 DynamicDepthConst::EarthPose());
212 if (!params_->earth_pose->Serialize(earth_pose_serializer.get())) {
213 return false;
214 }
215 }
216
217 if (params_->pose) {
218 std::unique_ptr<Serializer> pose_serializer =
219 device_serializer.CreateSerializer(DynamicDepthConst::Device(),
220 DynamicDepthConst::Pose());
221 if (!params_->pose->Serialize(pose_serializer.get())) {
222 return false;
223 }
224 }
225
226 if (params_->profiles && !params_->profiles->Serialize(&device_serializer)) {
227 return false;
228 }
229
230 // Serialize Planes before Cameras, since the data in Planes is likely to be
231 // significantly smaller than the potential media types in a Camera.
232 if (params_->planes && !params_->planes->Serialize(&device_serializer)) {
233 return false;
234 }
235
236 if (params_->cameras && !params_->cameras->Serialize(&device_serializer)) {
237 return false;
238 }
239
240 if (params_->vendor_info) {
241 std::unique_ptr<Serializer> vendor_info_serializer =
242 device_serializer.CreateSerializer(DynamicDepthConst::Device(),
243 DynamicDepthConst::VendorInfo());
244 if (!params_->vendor_info->Serialize(vendor_info_serializer.get())) {
245 return false;
246 }
247 }
248
249 if (params_->app_info) {
250 std::unique_ptr<Serializer> app_info_serializer =
251 device_serializer.CreateSerializer(DynamicDepthConst::Device(),
252 DynamicDepthConst::AppInfo());
253 if (!params_->app_info->Serialize(app_info_serializer.get())) {
254 return false;
255 }
256 }
257
258 return true;
259 }
GetNamespaces(std::unordered_map<string,string> * ns_name_href_map) const260 void Device::GetNamespaces(
261 std::unordered_map<string, string>* ns_name_href_map) const {
262 if (ns_name_href_map == nullptr) {
263 LOG(ERROR) << "Namespace list is null";
264 return;
265 }
266 ns_name_href_map->emplace(XmlConst::RdfPrefix(), XmlConst::RdfNodeNs());
267 ns_name_href_map->emplace(DynamicDepthConst::Device(), kNamespaceHref);
268 if (params_->earth_pose) {
269 params_->earth_pose->GetNamespaces(ns_name_href_map);
270 }
271 if (params_->pose) {
272 params_->pose->GetNamespaces(ns_name_href_map);
273 }
274 if (params_->profiles) {
275 params_->profiles->GetNamespaces(ns_name_href_map);
276 }
277 if (params_->planes) {
278 params_->planes->GetNamespaces(ns_name_href_map);
279 }
280 if (params_->cameras) {
281 params_->cameras->GetNamespaces(ns_name_href_map);
282 }
283 if (params_->container) {
284 params_->container->GetNamespaces(ns_name_href_map);
285 }
286 if (params_->vendor_info) {
287 params_->vendor_info->GetNamespaces(ns_name_href_map);
288 }
289 if (params_->app_info) {
290 params_->app_info->GetNamespaces(ns_name_href_map);
291 }
292 }
293
294 // Gathers all the XML namespaces of child elements.
PopulateNamespaces()295 void Device::PopulateNamespaces() {
296 std::unordered_map<string, string> ns_name_href_map;
297 GetNamespaces(&ns_name_href_map);
298 for (const auto& entry : ns_name_href_map) {
299 if (!namespaces_.count(entry.first)) {
300 namespaces_.emplace(entry.first,
301 xmlNewNs(nullptr, ToXmlChar(entry.second.data()),
302 ToXmlChar(entry.first.data())));
303 }
304 }
305 }
306
307 } // namespace dynamic_depth
308