• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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