1// Copyright 2023 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15syntax = "proto3"; 16 17package google.streetview.publish.v1; 18 19import "google/api/field_behavior.proto"; 20import "google/api/resource.proto"; 21import "google/protobuf/duration.proto"; 22import "google/protobuf/timestamp.proto"; 23import "google/type/latlng.proto"; 24 25option go_package = "google.golang.org/genproto/googleapis/streetview/publish/v1;publish"; 26option java_outer_classname = "StreetViewPublishResources"; 27option java_package = "com.google.geo.ugc.streetview.publish.v1"; 28 29// Upload reference for media files. 30message UploadRef { 31 // Required. 32 oneof file_source { 33 // An upload reference should be unique for each user. It follows 34 // the form: 35 // "https://streetviewpublish.googleapis.com/media/user/{account_id}/photo/{upload_reference}" 36 string upload_url = 1; 37 } 38} 39 40// Identifier for a [Photo][google.streetview.publish.v1.Photo]. 41message PhotoId { 42 // A unique identifier for a photo. 43 string id = 1; 44} 45 46// Level information containing level number and its corresponding name. 47message Level { 48 // Optional. Floor number, used for ordering. 0 indicates the ground level, 1 49 // indicates the first level above ground level, -1 indicates the first level 50 // under ground level. Non-integer values are OK. 51 double number = 1 [(google.api.field_behavior) = OPTIONAL]; 52 53 // Required. A name assigned to this Level, restricted to 3 characters. 54 // Consider how the elevator buttons would be labeled for this level if there 55 // was an elevator. 56 string name = 2 [(google.api.field_behavior) = REQUIRED]; 57} 58 59// Raw pose measurement for an entity. 60message Pose { 61 // Latitude and longitude pair of the pose, as explained here: 62 // https://cloud.google.com/datastore/docs/reference/rest/Shared.Types/LatLng 63 // When creating a [Photo][google.streetview.publish.v1.Photo], if the 64 // latitude and longitude pair are not provided, the geolocation from the 65 // exif header is used. A latitude and longitude pair not provided in the 66 // photo or exif header causes the photo process to fail. 67 google.type.LatLng lat_lng_pair = 1; 68 69 // Altitude of the pose in meters above WGS84 ellipsoid. 70 // NaN indicates an unmeasured quantity. 71 double altitude = 2; 72 73 // The following pose parameters pertain to the center of the photo. They 74 // match https://developers.google.com/streetview/spherical-metadata. 75 // Compass heading, measured at the center of the photo in degrees clockwise 76 // from North. Value must be >=0 and <360. NaN indicates an unmeasured 77 // quantity. 78 double heading = 3; 79 80 // Pitch, measured at the center of the photo in degrees. Value must be >=-90 81 // and <= 90. A value of -90 means looking directly down, and a value of 90 82 // means looking directly up. 83 // NaN indicates an unmeasured quantity. 84 double pitch = 4; 85 86 // Roll, measured in degrees. Value must be >= 0 and <360. A value of 0 87 // means level with the horizon. 88 // NaN indicates an unmeasured quantity. 89 double roll = 5; 90 91 // Time of the GPS record since UTC epoch. 92 google.protobuf.Timestamp gps_record_timestamp_unix_epoch = 6; 93 94 // Level (the floor in a building) used to configure vertical navigation. 95 Level level = 7; 96 97 // The estimated horizontal accuracy of this pose in meters with 68% 98 // confidence (one standard deviation). For example, on Android, this value is 99 // available from this method: 100 // https://developer.android.com/reference/android/location/Location#getAccuracy(). 101 // Other platforms have different methods of obtaining similar accuracy 102 // estimations. 103 float accuracy_meters = 9; 104} 105 106// IMU data from the device sensors. 107message Imu { 108 // A Generic 3d measurement sample. 109 message Measurement3d { 110 // The timestamp of the IMU measurement. 111 google.protobuf.Timestamp capture_time = 1; 112 113 // The sensor measurement in the x axis. 114 float x = 2; 115 116 // The sensor measurement in the y axis. 117 float y = 3; 118 119 // The sensor measurement in the z axis. 120 float z = 4; 121 } 122 123 // The accelerometer measurements in meters/sec^2 with increasing timestamps 124 // from devices. 125 repeated Measurement3d accel_mpsps = 1; 126 127 // The gyroscope measurements in radians/sec with increasing timestamps from 128 // devices. 129 repeated Measurement3d gyro_rps = 2; 130 131 // The magnetometer measurements of the magnetic field in microtesla (uT) with 132 // increasing timestamps from devices. 133 repeated Measurement3d mag_ut = 3; 134} 135 136// Place metadata for an entity. 137message Place { 138 // Place identifier, as described in 139 // https://developers.google.com/places/place-id. 140 string place_id = 1; 141 142 // Output only. The name of the place, localized to the language_code. 143 string name = 2 [(google.api.field_behavior) = OUTPUT_ONLY]; 144 145 // Output only. The language_code that the name is localized with. This should 146 // be the language_code specified in the request, but may be a fallback. 147 string language_code = 3 [(google.api.field_behavior) = OUTPUT_ONLY]; 148} 149 150// A connection is the link from a source photo to a destination photo. 151message Connection { 152 // Required. The destination of the connection from the containing photo to 153 // another photo. 154 PhotoId target = 1 [(google.api.field_behavior) = REQUIRED]; 155} 156 157// Photo is used to store 360 photos along with photo metadata. 158message Photo { 159 // Status of rights transfer. 160 enum TransferStatus { 161 // The status of this transfer is unspecified. 162 TRANSFER_STATUS_UNKNOWN = 0; 163 164 // This photo has never been in a transfer. 165 NEVER_TRANSFERRED = 1; 166 167 // This photo transfer has been initiated, but the receiver has not yet 168 // responded. 169 PENDING = 2; 170 171 // The photo transfer has been completed, and this photo has been 172 // transferred to the recipient. 173 COMPLETED = 3; 174 175 // The recipient rejected this photo transfer. 176 REJECTED = 4; 177 178 // The photo transfer expired before the recipient took any action. 179 EXPIRED = 5; 180 181 // The sender cancelled this photo transfer. 182 CANCELLED = 6; 183 184 // The recipient owns this photo due to a rights transfer. 185 RECEIVED_VIA_TRANSFER = 7; 186 } 187 188 // Publication status of the photo in Google Maps. 189 enum MapsPublishStatus { 190 // The status of the photo is unknown. 191 UNSPECIFIED_MAPS_PUBLISH_STATUS = 0; 192 193 // The photo is published to the public through Google Maps. 194 PUBLISHED = 1; 195 196 // The photo has been rejected for an unknown reason. 197 REJECTED_UNKNOWN = 2; 198 } 199 200 // Required. Output only. Required when updating a photo. Output only when 201 // creating a photo. Identifier for the photo, which is unique among all 202 // photos in Google. 203 PhotoId photo_id = 1 [ 204 (google.api.field_behavior) = REQUIRED, 205 (google.api.field_behavior) = OUTPUT_ONLY 206 ]; 207 208 // Input only. Required when creating a photo. Input only. The resource URL 209 // where the photo bytes are uploaded to. 210 UploadRef upload_reference = 2 [(google.api.field_behavior) = INPUT_ONLY]; 211 212 // Output only. The download URL for the photo bytes. This field is set only 213 // when 214 // [GetPhotoRequest.view][google.streetview.publish.v1.GetPhotoRequest.view] 215 // is set to 216 // [PhotoView.INCLUDE_DOWNLOAD_URL][google.streetview.publish.v1.PhotoView.INCLUDE_DOWNLOAD_URL]. 217 string download_url = 3 [(google.api.field_behavior) = OUTPUT_ONLY]; 218 219 // Output only. The thumbnail URL for showing a preview of the given photo. 220 string thumbnail_url = 9 [(google.api.field_behavior) = OUTPUT_ONLY]; 221 222 // Output only. The share link for the photo. 223 string share_link = 11 [(google.api.field_behavior) = OUTPUT_ONLY]; 224 225 // Optional. Pose of the photo. 226 Pose pose = 4 [(google.api.field_behavior) = OPTIONAL]; 227 228 // Optional. Connections to other photos. A connection represents the link 229 // from this photo to another photo. 230 repeated Connection connections = 5 [(google.api.field_behavior) = OPTIONAL]; 231 232 // Optional. Absolute time when the photo was captured. 233 // When the photo has no exif timestamp, this is used to set a timestamp in 234 // the photo metadata. 235 google.protobuf.Timestamp capture_time = 6 236 [(google.api.field_behavior) = OPTIONAL]; 237 238 // Output only. Time when the image was uploaded. 239 google.protobuf.Timestamp upload_time = 14 240 [(google.api.field_behavior) = OUTPUT_ONLY]; 241 242 // Optional. Places where this photo belongs. 243 repeated Place places = 7 [(google.api.field_behavior) = OPTIONAL]; 244 245 // Output only. View count of the photo. 246 int64 view_count = 10 [(google.api.field_behavior) = OUTPUT_ONLY]; 247 248 // Output only. Status of rights transfer on this photo. 249 TransferStatus transfer_status = 12 250 [(google.api.field_behavior) = OUTPUT_ONLY]; 251 252 // Output only. Status in Google Maps, whether this photo was published or 253 // rejected. 254 MapsPublishStatus maps_publish_status = 13 255 [(google.api.field_behavior) = OUTPUT_ONLY]; 256} 257 258// A sequence of 360 photos along with metadata. 259message PhotoSequence { 260 // Primary source of GPS measurements. 261 enum GpsSource { 262 // GPS in raw_gps_timeline takes precedence if it exists. 263 PHOTO_SEQUENCE = 0; 264 265 // GPS in Camera Motion Metadata Track (CAMM) takes precedence if it exists. 266 CAMERA_MOTION_METADATA_TRACK = 1; 267 } 268 269 // Output only. Unique identifier for the photo sequence. 270 // This also acts as a long running operation ID if uploading is performed 271 // asynchronously. 272 string id = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; 273 274 // Output only. Photos with increasing timestamps. 275 repeated Photo photos = 2 [(google.api.field_behavior) = OUTPUT_ONLY]; 276 277 // Input only. Required when creating photo sequence. The resource name 278 // where the bytes of the photo sequence (in the form of video) are uploaded. 279 UploadRef upload_reference = 3 [(google.api.field_behavior) = INPUT_ONLY]; 280 281 // Optional. Absolute time when the photo sequence starts to be captured. 282 // If the photo sequence is a video, this is the start time of the video. 283 // If this field is populated in input, it overrides the capture time in the 284 // video or XDM file. 285 google.protobuf.Timestamp capture_time_override = 4 286 [(google.api.field_behavior) = OPTIONAL]; 287 288 // Output only. The time this photo sequence was created in uSV Store service. 289 google.protobuf.Timestamp upload_time = 18 290 [(google.api.field_behavior) = OUTPUT_ONLY]; 291 292 // Input only. Raw GPS measurements with increasing timestamps from the device 293 // that aren't time synced with each photo. These raw measurements will be 294 // used to infer the pose of each frame. Required in input when InputType is 295 // VIDEO and raw GPS measurements are not in Camera Motion Metadata Track 296 // (CAMM). User can indicate which takes precedence using gps_source if raw 297 // GPS measurements are provided in both raw_gps_timeline and Camera Motion 298 // Metadata Track (CAMM). 299 repeated Pose raw_gps_timeline = 7 [(google.api.field_behavior) = INPUT_ONLY]; 300 301 // Input only. If both raw_gps_timeline and 302 // the Camera Motion Metadata Track (CAMM) contain GPS measurements, 303 // indicate which takes precedence. 304 GpsSource gps_source = 8 [(google.api.field_behavior) = INPUT_ONLY]; 305 306 // Input only. Three axis IMU data for the collection. 307 // If this data is too large to put in the request, then it should be put in 308 // the CAMM track for the video. This data always takes precedence over the 309 // equivalent CAMM data, if it exists. 310 Imu imu = 11 [(google.api.field_behavior) = INPUT_ONLY]; 311 312 // Output only. The processing state of this sequence. 313 ProcessingState processing_state = 12 314 [(google.api.field_behavior) = OUTPUT_ONLY]; 315 316 // Output only. If this sequence has processing_state = FAILED, this will 317 // contain the reason why it failed. If the processing_state is any other 318 // value, this field will be unset. 319 ProcessingFailureReason failure_reason = 13 320 [(google.api.field_behavior) = OUTPUT_ONLY]; 321 322 // Output only. If this sequence has `failure_reason` set, this may contain 323 // additional details about the failure. 324 ProcessingFailureDetails failure_details = 23 325 [(google.api.field_behavior) = OUTPUT_ONLY]; 326 327 // Output only. The computed distance of the photo sequence in meters. 328 double distance_meters = 16 [(google.api.field_behavior) = OUTPUT_ONLY]; 329 330 // Output only. A rectangular box that encapsulates every image in this photo 331 // sequence. 332 LatLngBounds sequence_bounds = 20 [(google.api.field_behavior) = OUTPUT_ONLY]; 333 334 // Output only. The total number of views that all the published images in 335 // this PhotoSequence have received. 336 int64 view_count = 21 [(google.api.field_behavior) = OUTPUT_ONLY]; 337 338 // Output only. The filename of the upload. Does not include the directory 339 // path. Only available if the sequence was uploaded on a platform that 340 // provides the filename. 341 string filename = 22 [(google.api.field_behavior) = OUTPUT_ONLY]; 342} 343 344// A rectangle in geographical coordinates. 345message LatLngBounds { 346 // The southwest corner of these bounds. 347 google.type.LatLng southwest = 1; 348 349 // The northeast corner of these bounds. 350 google.type.LatLng northeast = 2; 351} 352 353// The processing state of the sequence. The states move as follows: 354// 355// ``` 356// +-------------------------+ 357// | | 358// +---v---+ +----------+ +----+----+ 359// |PENDING+-->PROCESSING+-->PROCESSED| 360// +---+---+ +----+-----+ +----+----+ 361// | | | 362// | +--v---+ | 363// +-------->FAILED<---------+ 364// +------+ 365// ``` 366// 367// The sequence may move to FAILED from any state. Additionally, a processed 368// sequence may be re-processed at any time. 369enum ProcessingState { 370 // The state is unspecified, this is the default value. 371 PROCESSING_STATE_UNSPECIFIED = 0; 372 373 // The sequence has not yet started processing. 374 PENDING = 1; 375 376 // The sequence is currently in processing. 377 PROCESSING = 2; 378 379 // The sequence has finished processing including refining position. 380 PROCESSED = 3; 381 382 // The sequence failed processing. See FailureReason for more details. 383 FAILED = 4; 384} 385 386// The possible reasons this [PhotoSequence] 387// [google.streetview.publish.v1.PhotoSequence] failed to process. 388enum ProcessingFailureReason { 389 // The failure reason is unspecified, this is the default value. 390 PROCESSING_FAILURE_REASON_UNSPECIFIED = 0; 391 392 // Video frame's resolution is too small. 393 LOW_RESOLUTION = 1; 394 395 // This video has been uploaded before. 396 DUPLICATE = 2; 397 398 // Too few GPS points. 399 INSUFFICIENT_GPS = 3; 400 401 // No overlap between the time frame of GPS track and the time frame of 402 // video. 403 NO_OVERLAP_GPS = 4; 404 405 // GPS is invalid (e.x. all GPS points are at (0,0)) 406 INVALID_GPS = 5; 407 408 // The sequence of photos could not be accurately located in the world. 409 FAILED_TO_REFINE_POSITIONS = 6; 410 411 // The sequence was taken down for policy reasons. 412 TAKEDOWN = 7; 413 414 // The video file was corrupt or could not be decoded. 415 CORRUPT_VIDEO = 8; 416 417 // A permanent failure in the underlying system occurred. 418 INTERNAL = 9; 419 420 // The video format is invalid or unsupported. 421 INVALID_VIDEO_FORMAT = 10; 422 423 // Invalid image aspect ratio found. 424 INVALID_VIDEO_DIMENSIONS = 11; 425 426 // Invalid capture time. Timestamps were from the future. 427 INVALID_CAPTURE_TIME = 12; 428 429 // GPS data contains a gap greater than 5 seconds in duration. 430 GPS_DATA_GAP = 13; 431 432 // GPS data is too erratic to be processed. 433 JUMPY_GPS = 14; 434 435 // IMU (Accelerometer, Gyroscope, etc.) data are not valid. They may be 436 // missing required fields (x, y, z or time), may not be formatted correctly, 437 // or any other issue that prevents our systems from parsing it. 438 INVALID_IMU = 15; 439 440 // Too few IMU points. 441 INSUFFICIENT_IMU = 21; 442 443 // Insufficient overlap in the time frame between GPS, IMU, and other time 444 // series data. 445 INSUFFICIENT_OVERLAP_TIME_SERIES = 22; 446 447 // IMU (Accelerometer, Gyroscope, etc.) data contain gaps greater than 0.1 448 // seconds in duration. 449 IMU_DATA_GAP = 16; 450 451 // The camera is not supported. 452 UNSUPPORTED_CAMERA = 17; 453 454 // Some frames were indoors, which is unsupported. 455 NOT_OUTDOORS = 18; 456 457 // Not enough video frames. 458 INSUFFICIENT_VIDEO_FRAMES = 19; 459 460 // Not enough moving data. 461 INSUFFICIENT_MOVEMENT = 20; 462 463 // Mast is down. 464 MAST_DOWN = 27; 465 466 // Camera is covered. 467 CAMERA_COVERED = 28; 468} 469 470// Additional details to accompany the ProcessingFailureReason enum. 471// This message is always expected to be used in conjunction with 472// ProcessingFailureReason, and the oneof value set in this message should match 473// the FailureReason. 474message ProcessingFailureDetails { 475 // Only one set of details will be set, and must match the corresponding enum 476 // in ProcessingFailureReason. 477 oneof details { 478 // See InsufficientGpsFailureDetails. 479 InsufficientGpsFailureDetails insufficient_gps_details = 1; 480 481 // See GpsDataGapFailureDetails. 482 GpsDataGapFailureDetails gps_data_gap_details = 2; 483 484 // See ImuDataGapFailureDetails. 485 ImuDataGapFailureDetails imu_data_gap_details = 3; 486 487 // See NotOutdoorsFailureDetails. 488 NotOutdoorsFailureDetails not_outdoors_details = 4; 489 490 // See NoOverlapGpsFailureDetails. 491 NoOverlapGpsFailureDetails no_overlap_gps_details = 5; 492 } 493} 494 495// Details related to ProcessingFailureReason#INSUFFICIENT_GPS. 496message InsufficientGpsFailureDetails { 497 // The number of GPS points that were found in the video. 498 optional int32 gps_points_found = 1; 499} 500 501// Details related to ProcessingFailureReason#GPS_DATA_GAP. 502// If there are multiple GPS data gaps, only the one with the largest duration 503// is reported here. 504message GpsDataGapFailureDetails { 505 // The duration of the gap in GPS data that was found. 506 optional google.protobuf.Duration gap_duration = 1; 507 508 // Relative time (from the start of the video stream) when the gap started. 509 optional google.protobuf.Duration gap_start_time = 2; 510} 511 512// Details related to ProcessingFailureReason#IMU_DATA_GAP. 513// If there are multiple IMU data gaps, only the one with the largest duration 514// is reported here. 515message ImuDataGapFailureDetails { 516 // The duration of the gap in IMU data that was found. 517 optional google.protobuf.Duration gap_duration = 1; 518 519 // Relative time (from the start of the video stream) when the gap started. 520 optional google.protobuf.Duration gap_start_time = 2; 521} 522 523// Details related to ProcessingFailureReason#NOT_OUTDOORS. 524// If there are multiple indoor frames found, the first frame is recorded here. 525message NotOutdoorsFailureDetails { 526 // Relative time (from the start of the video stream) when an indoor frame was 527 // found. 528 optional google.protobuf.Duration start_time = 1; 529} 530 531// Details related to PhotoSequenceProcessingFailureReason#NO_OVERLAP_GPS. 532message NoOverlapGpsFailureDetails { 533 // Time of first recorded GPS point. 534 optional google.protobuf.Timestamp gps_start_time = 1; 535 536 // Time of last recorded GPS point. 537 optional google.protobuf.Timestamp gps_end_time = 2; 538 539 // Start time of video. 540 optional google.protobuf.Timestamp video_start_time = 3; 541 542 // End time of video. 543 optional google.protobuf.Timestamp video_end_time = 4; 544} 545