CameraMetadata.cpp 21.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17 18
// #define LOG_NDEBUG 0

19
#define LOG_TAG "Camera2-Metadata"
20 21 22
#include <utils/Log.h>
#include <utils/Errors.h>

23
#include <camera/CameraMetadata.h>
24
#include <binder/Parcel.h>
25 26 27

namespace android {

28 29 30
#define ALIGN_TO(val, alignment) \
    (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))

31 32 33
typedef Parcel::WritableBlob WritableBlob;
typedef Parcel::ReadableBlob ReadableBlob;

34
CameraMetadata::CameraMetadata() :
35
        mBuffer(NULL), mLocked(false) {
36 37
}

38 39
CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
        mLocked(false)
40 41 42 43
{
    mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
}

44 45
CameraMetadata::CameraMetadata(const CameraMetadata &other) :
        mLocked(false) {
46 47 48
    mBuffer = clone_camera_metadata(other.mBuffer);
}

49 50
CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
        mBuffer(NULL), mLocked(false) {
51 52 53
    acquire(buffer);
}

54 55 56 57 58
CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
    return operator=(other.mBuffer);
}

CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
59 60 61 62 63
    if (mLocked) {
        ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
        return *this;
    }

64 65 66 67 68 69 70 71 72
    if (CC_LIKELY(buffer != mBuffer)) {
        camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
        clear();
        mBuffer = newBuffer;
    }
    return *this;
}

CameraMetadata::~CameraMetadata() {
73
    mLocked = false;
74 75 76
    clear();
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
const camera_metadata_t* CameraMetadata::getAndLock() {
    mLocked = true;
    return mBuffer;
}

status_t CameraMetadata::unlock(const camera_metadata_t *buffer) {
    if (!mLocked) {
        ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
        return INVALID_OPERATION;
    }
    if (buffer != mBuffer) {
        ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
                __FUNCTION__);
        return BAD_VALUE;
    }
    mLocked = false;
    return OK;
}

96
camera_metadata_t* CameraMetadata::release() {
97 98 99 100
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return NULL;
    }
101 102 103 104 105 106
    camera_metadata_t *released = mBuffer;
    mBuffer = NULL;
    return released;
}

void CameraMetadata::clear() {
107 108 109 110
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return;
    }
111 112 113 114 115 116 117
    if (mBuffer) {
        free_camera_metadata(mBuffer);
        mBuffer = NULL;
    }
}

void CameraMetadata::acquire(camera_metadata_t *buffer) {
118 119 120 121
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return;
    }
122 123
    clear();
    mBuffer = buffer;
124 125 126 127

    ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
             "%s: Failed to validate metadata structure %p",
             __FUNCTION__, buffer);
128 129 130
}

void CameraMetadata::acquire(CameraMetadata &other) {
131 132 133 134
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return;
    }
135 136 137 138
    acquire(other.release());
}

status_t CameraMetadata::append(const CameraMetadata &other) {
139 140 141 142
    return append(other.mBuffer);
}

status_t CameraMetadata::append(const camera_metadata_t* other) {
143 144 145 146
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
147 148 149 150 151
    size_t extraEntries = get_camera_metadata_entry_count(other);
    size_t extraData = get_camera_metadata_data_count(other);
    resizeIfNeeded(extraEntries, extraData);

    return append_camera_metadata(mBuffer, other);
152 153 154 155 156 157 158
}

size_t CameraMetadata::entryCount() const {
    return (mBuffer == NULL) ? 0 :
            get_camera_metadata_entry_count(mBuffer);
}

159 160 161 162
bool CameraMetadata::isEmpty() const {
    return entryCount() == 0;
}

163
status_t CameraMetadata::sort() {
164 165 166 167
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    return sort_camera_metadata(mBuffer);
}

status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
    int tagType = get_camera_metadata_tag_type(tag);
    if ( CC_UNLIKELY(tagType == -1)) {
        ALOGE("Update metadata entry: Unknown tag %d", tag);
        return INVALID_OPERATION;
    }
    if ( CC_UNLIKELY(tagType != expectedType) ) {
        ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
                "got type %s data instead ",
                get_camera_metadata_tag_name(tag), tag,
                camera_metadata_type_names[tagType],
                camera_metadata_type_names[expectedType]);
        return INVALID_OPERATION;
    }
    return OK;
}

status_t CameraMetadata::update(uint32_t tag,
        const int32_t *data, size_t data_count) {
    status_t res;
191 192 193 194
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
195 196 197
    if ( (res = checkType(tag, TYPE_INT32)) != OK) {
        return res;
    }
198
    return updateImpl(tag, (const void*)data, data_count);
199 200 201 202 203
}

status_t CameraMetadata::update(uint32_t tag,
        const uint8_t *data, size_t data_count) {
    status_t res;
204 205 206 207
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
208 209 210
    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
        return res;
    }
211
    return updateImpl(tag, (const void*)data, data_count);
212 213 214 215 216
}

status_t CameraMetadata::update(uint32_t tag,
        const float *data, size_t data_count) {
    status_t res;
217 218 219 220
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
221 222 223
    if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
        return res;
    }
224
    return updateImpl(tag, (const void*)data, data_count);
225 226 227 228 229
}

status_t CameraMetadata::update(uint32_t tag,
        const int64_t *data, size_t data_count) {
    status_t res;
230 231 232 233
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
234 235 236
    if ( (res = checkType(tag, TYPE_INT64)) != OK) {
        return res;
    }
237
    return updateImpl(tag, (const void*)data, data_count);
238 239 240 241 242
}

status_t CameraMetadata::update(uint32_t tag,
        const double *data, size_t data_count) {
    status_t res;
243 244 245 246
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
247 248 249
    if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
        return res;
    }
250
    return updateImpl(tag, (const void*)data, data_count);
251 252 253 254 255
}

status_t CameraMetadata::update(uint32_t tag,
        const camera_metadata_rational_t *data, size_t data_count) {
    status_t res;
256 257 258 259
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
260 261 262
    if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
        return res;
    }
263
    return updateImpl(tag, (const void*)data, data_count);
264 265 266 267 268
}

status_t CameraMetadata::update(uint32_t tag,
        const String8 &string) {
    status_t res;
269 270 271 272
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
273 274 275
    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
        return res;
    }
276 277
    // string.size() doesn't count the null termination character.
    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
278 279
}

280
status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
281 282
        size_t data_count) {
    status_t res;
283 284 285 286
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    int type = get_camera_metadata_tag_type(tag);
    if (type == -1) {
        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
        return BAD_VALUE;
    }
    size_t data_size = calculate_camera_metadata_entry_data_size(type,
            data_count);

    res = resizeIfNeeded(1, data_size);

    if (res == OK) {
        camera_metadata_entry_t entry;
        res = find_camera_metadata_entry(mBuffer, tag, &entry);
        if (res == NAME_NOT_FOUND) {
            res = add_camera_metadata_entry(mBuffer,
                    tag, data, data_count);
        } else if (res == OK) {
            res = update_camera_metadata_entry(mBuffer,
                    entry.index, data, data_count, NULL);
        }
    }

    if (res != OK) {
        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
                __FUNCTION__, get_camera_metadata_section_name(tag),
                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
    }
314 315 316 317 318 319 320 321 322

    IF_ALOGV() {
        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
                 OK,

                 "%s: Failed to validate metadata structure after update %p",
                 __FUNCTION__, mBuffer);
    }

323 324 325
    return res;
}

326 327 328 329 330
bool CameraMetadata::exists(uint32_t tag) const {
    camera_metadata_ro_entry entry;
    return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
}

331 332 333
camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
    status_t res;
    camera_metadata_entry entry;
334 335 336 337 338
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        entry.count = 0;
        return entry;
    }
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
    res = find_camera_metadata_entry(mBuffer, tag, &entry);
    if (CC_UNLIKELY( res != OK )) {
        entry.count = 0;
        entry.data.u8 = NULL;
    }
    return entry;
}

camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
    status_t res;
    camera_metadata_ro_entry entry;
    res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
    if (CC_UNLIKELY( res != OK )) {
        entry.count = 0;
        entry.data.u8 = NULL;
    }
    return entry;
}

status_t CameraMetadata::erase(uint32_t tag) {
    camera_metadata_entry_t entry;
    status_t res;
361 362 363 364
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    res = find_camera_metadata_entry(mBuffer, tag, &entry);
    if (res == NAME_NOT_FOUND) {
        return OK;
    } else if (res != OK) {
        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
                __FUNCTION__,
                get_camera_metadata_section_name(tag),
                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
        return res;
    }
    res = delete_camera_metadata_entry(mBuffer, entry.index);
    if (res != OK) {
        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
                __FUNCTION__,
                get_camera_metadata_section_name(tag),
                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
    }
    return res;
}

void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
}

status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
    if (mBuffer == NULL) {
        mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
        if (mBuffer == NULL) {
            ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
            return NO_MEMORY;
        }
    } else {
        size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
        size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
        size_t newEntryCount = currentEntryCount +
                extraEntries;
        newEntryCount = (newEntryCount > currentEntryCap) ?
                newEntryCount * 2 : currentEntryCap;

        size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
        size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
        size_t newDataCount = currentDataCount +
                extraData;
        newDataCount = (newDataCount > currentDataCap) ?
                newDataCount * 2 : currentDataCap;

        if (newEntryCount > currentEntryCap ||
                newDataCount > currentDataCap) {
            camera_metadata_t *oldBuffer = mBuffer;
            mBuffer = allocate_camera_metadata(newEntryCount,
                    newDataCount);
            if (mBuffer == NULL) {
                ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
                return NO_MEMORY;
            }
            append_camera_metadata(mBuffer, oldBuffer);
            free_camera_metadata(oldBuffer);
        }
    }
    return OK;
}

427 428 429 430 431 432 433 434 435 436 437
status_t CameraMetadata::readFromParcel(const Parcel& data,
                                        camera_metadata_t** out) {

    status_t err = OK;

    camera_metadata_t* metadata = NULL;

    if (out) {
        *out = NULL;
    }

438 439 440 441
    // See CameraMetadata::writeToParcel for parcel data layout diagram and explanation.
    // arg0 = blobSize (int32)
    int32_t blobSizeTmp = -1;
    if ((err = data.readInt32(&blobSizeTmp)) != OK) {
442 443 444 445
        ALOGE("%s: Failed to read metadata size (error %d %s)",
              __FUNCTION__, err, strerror(-err));
        return err;
    }
446 447
    const size_t blobSize = static_cast<size_t>(blobSizeTmp);
    const size_t alignment = get_camera_metadata_alignment();
448

449 450
    // Special case: zero blob size means zero sized (NULL) metadata.
    if (blobSize == 0) {
451 452 453 454
        ALOGV("%s: Read 0-sized metadata", __FUNCTION__);
        return OK;
    }

455 456 457 458 459 460 461 462 463
    if (blobSize <= alignment) {
        ALOGE("%s: metadata blob is malformed, blobSize(%zu) should be larger than alignment(%zu)",
                __FUNCTION__, blobSize, alignment);
        return BAD_VALUE;
    }

    const size_t metadataSize = blobSize - alignment;

    // NOTE: this doesn't make sense to me. shouldn't the blob
464 465 466 467 468
    // know how big it is? why do we have to specify the size
    // to Parcel::readBlob ?
    ReadableBlob blob;
    // arg1 = metadata (blob)
    do {
469 470
        if ((err = data.readBlob(blobSize, &blob)) != OK) {
            ALOGE("%s: Failed to read metadata blob (sized %zu). Possible "
471
                  " serialization bug. Error %d %s",
472
                  __FUNCTION__, blobSize, err, strerror(-err));
473 474 475
            break;
        }

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
        // arg2 = offset (blob)
        // Must be after blob since we don't know offset until after writeBlob.
        int32_t offsetTmp;
        if ((err = data.readInt32(&offsetTmp)) != OK) {
            ALOGE("%s: Failed to read metadata offsetTmp (error %d %s)",
                  __FUNCTION__, err, strerror(-err));
            break;
        }
        const size_t offset = static_cast<size_t>(offsetTmp);
        if (offset >= alignment) {
            ALOGE("%s: metadata offset(%zu) should be less than alignment(%zu)",
                    __FUNCTION__, blobSize, alignment);
            err = BAD_VALUE;
            break;
        }

        const uintptr_t metadataStart = reinterpret_cast<uintptr_t>(blob.data()) + offset;
        const camera_metadata_t* tmp =
                       reinterpret_cast<const camera_metadata_t*>(metadataStart);
        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
                __FUNCTION__, alignment, tmp, offset);
497 498 499 500
        metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
        if (metadata == NULL) {
            // We consider that allocation only fails if the validation
            // also failed, therefore the readFromParcel was a failure.
501
            ALOGE("%s: metadata allocation and copy failed", __FUNCTION__);
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
            err = BAD_VALUE;
        }
    } while(0);
    blob.release();

    if (out) {
        ALOGV("%s: Set out metadata to %p", __FUNCTION__, metadata);
        *out = metadata;
    } else if (metadata != NULL) {
        ALOGV("%s: Freed camera metadata at %p", __FUNCTION__, metadata);
        free_camera_metadata(metadata);
    }

    return err;
}

status_t CameraMetadata::writeToParcel(Parcel& data,
                                       const camera_metadata_t* metadata) {
    status_t res = OK;

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
    /**
     * Below is the camera metadata parcel layout:
     *
     * |--------------------------------------------|
     * |             arg0: blobSize                 |
     * |              (length = 4)                  |
     * |--------------------------------------------|<--Skip the rest if blobSize == 0.
     * |                                            |
     * |                                            |
     * |              arg1: blob                    |
     * | (length = variable, see arg1 layout below) |
     * |                                            |
     * |                                            |
     * |--------------------------------------------|
     * |              arg2: offset                  |
     * |              (length = 4)                  |
     * |--------------------------------------------|
     */

    // arg0 = blobSize (int32)
542
    if (metadata == NULL) {
543
        // Write zero blobSize for null metadata.
544 545 546
        return data.writeInt32(0);
    }

547 548 549 550 551
    /**
     * Always make the blob size sufficiently larger, as we need put alignment
     * padding and metadata into the blob. Since we don't know the alignment
     * offset before writeBlob. Then write the metadata to aligned offset.
     */
552
    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
553 554 555
    const size_t alignment = get_camera_metadata_alignment();
    const size_t blobSize = metadataSize + alignment;
    res = data.writeInt32(static_cast<int32_t>(blobSize));
556 557 558 559
    if (res != OK) {
        return res;
    }

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
    size_t offset = 0;
    /**
     * arg1 = metadata (blob).
     *
     * The blob size is the sum of front padding size, metadata size and back padding
     * size, which is equal to metadataSize + alignment.
     *
     * The blob layout is:
     * |------------------------------------|<----Start address of the blob (unaligned).
     * |           front padding            |
     * |          (size = offset)           |
     * |------------------------------------|<----Aligned start address of metadata.
     * |                                    |
     * |                                    |
     * |            metadata                |
     * |       (size = metadataSize)        |
     * |                                    |
     * |                                    |
     * |------------------------------------|
     * |           back padding             |
     * |     (size = alignment - offset)    |
     * |------------------------------------|<----End address of blob.
     *                                            (Blob start address + blob size).
     */
584 585
    WritableBlob blob;
    do {
586
        res = data.writeBlob(blobSize, &blob);
587 588 589
        if (res != OK) {
            break;
        }
590 591 592
        const uintptr_t metadataStart = ALIGN_TO(blob.data(), alignment);
        offset = metadataStart - reinterpret_cast<uintptr_t>(blob.data());
        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
593 594
                __FUNCTION__, alignment,
                reinterpret_cast<const void *>(metadataStart), offset);
595
        copy_camera_metadata(reinterpret_cast<void*>(metadataStart), metadataSize, metadata);
596 597 598 599 600 601 602 603 604 605 606

        // Not too big of a problem since receiving side does hard validation
        // Don't check the size since the compact size could be larger
        if (validate_camera_metadata_structure(metadata, /*size*/NULL) != OK) {
            ALOGW("%s: Failed to validate metadata %p before writing blob",
                   __FUNCTION__, metadata);
        }

    } while(false);
    blob.release();

607 608 609
    // arg2 = offset (int32)
    res = data.writeInt32(static_cast<int32_t>(offset));

610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
    return res;
}

status_t CameraMetadata::readFromParcel(Parcel *parcel) {

    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);

    status_t res = OK;

    if (parcel == NULL) {
        ALOGE("%s: parcel is null", __FUNCTION__);
        return BAD_VALUE;
    }

    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }

    camera_metadata *buffer = NULL;
    // TODO: reading should return a status code, in case validation fails
    res = CameraMetadata::readFromParcel(*parcel, &buffer);

    if (res != NO_ERROR) {
        ALOGE("%s: Failed to read from parcel. Metadata is unchanged.",
              __FUNCTION__);
        return res;
    }

    clear();
    mBuffer = buffer;

    return OK;
}

status_t CameraMetadata::writeToParcel(Parcel *parcel) const {

    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);

    if (parcel == NULL) {
        ALOGE("%s: parcel is null", __FUNCTION__);
        return BAD_VALUE;
    }

    return CameraMetadata::writeToParcel(*parcel, mBuffer);
}

void CameraMetadata::swap(CameraMetadata& other) {
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return;
    } else if (other.mLocked) {
        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
        return;
    }

    camera_metadata* thisBuf = mBuffer;
    camera_metadata* otherBuf = other.mBuffer;

    other.mBuffer = thisBuf;
    mBuffer = otherBuf;
}

673
}; // namespace android