diff options
57 files changed, 4548 insertions, 95 deletions
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index 678d642..563c0b5 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -25,6 +25,7 @@ extern const char *MEDIA_MIMETYPE_IMAGE_JPEG; extern const char *MEDIA_MIMETYPE_VIDEO_VP8; extern const char *MEDIA_MIMETYPE_VIDEO_VP9; extern const char *MEDIA_MIMETYPE_VIDEO_AVC; +extern const char *MEDIA_MIMETYPE_VIDEO_HEVC; extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4; extern const char *MEDIA_MIMETYPE_VIDEO_H263; extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2; diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 3901e79..5116d1e 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -20,6 +20,7 @@ #include <stdint.h> #include <sys/types.h> +#include <audio_utils/minifloat.h> #include <utils/threads.h> #include <utils/Log.h> #include <utils/RefBase.h> @@ -110,11 +111,8 @@ private: // force to 32-bit. The client and server may have different typedefs for size_t. uint32_t mMinimum; // server wakes up client if available >= mMinimum - // Channel volumes are fixed point U4.12, so 0x1000 means 1.0. - // Left channel is in [0:15], right channel is in [16:31]. - // Always read and write the combined pair atomically. - // For AudioTrack only, not used by AudioRecord. - uint32_t mVolumeLR; + // Stereo gains for AudioTrack only, not used by AudioRecord. + gain_minifloat_packed_t mVolumeLR; uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz // or 0 == default. Write-only client, read-only server. @@ -285,8 +283,8 @@ public: mCblk->mSendLevel = uint16_t(sendLevel * 0x1000); } - // caller must limit to 0 <= volumeLR <= 0x10001000 - void setVolumeLR(uint32_t volumeLR) { + // set stereo gains + void setVolumeLR(gain_minifloat_packed_t volumeLR) { mCblk->mVolumeLR = volumeLR; } @@ -405,7 +403,7 @@ public: // return value of these methods must be validated by the caller uint32_t getSampleRate() const { return mCblk->mSampleRate; } uint16_t getSendLevel_U4_12() const { return mCblk->mSendLevel; } - uint32_t getVolumeLR() const { return mCblk->mVolumeLR; } + gain_minifloat_packed_t getVolumeLR() const { return mCblk->mVolumeLR; } // estimated total number of filled frames available to server to read, // which may include non-contiguous frames diff --git a/media/img_utils/Android.mk b/media/img_utils/Android.mk new file mode 100644 index 0000000..1cd00bd --- /dev/null +++ b/media/img_utils/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2014 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. + +include $(call all-subdir-makefiles) diff --git a/media/img_utils/include/img_utils/ByteArrayOutput.h b/media/img_utils/include/img_utils/ByteArrayOutput.h new file mode 100644 index 0000000..ba73977 --- /dev/null +++ b/media/img_utils/include/img_utils/ByteArrayOutput.h @@ -0,0 +1,82 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_BYTE_ARRAY_OUTPUT_H +#define IMG_UTILS_BYTE_ARRAY_OUTPUT_H + +#include <img_utils/Output.h> + +#include <utils/Errors.h> +#include <utils/Vector.h> + +#include <cutils/compiler.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * Utility class that accumulates written bytes into a buffer. + */ +class ANDROID_API ByteArrayOutput : public Output { + public: + + ByteArrayOutput(); + + virtual ~ByteArrayOutput(); + + /** + * Open this ByteArrayOutput. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Write bytes from the given buffer. The number of bytes given in the count + * argument will be written. Bytes will be written from the given buffer starting + * at the index given in the offset argument. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t write(const uint8_t* buf, size_t offset, size_t count); + + /** + * Close this ByteArrayOutput. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); + + /** + * Get current size of the array of bytes written. + */ + virtual size_t getSize() const; + + /** + * Get pointer to array of bytes written. It is not valid to use this pointer if + * open, write, or close is called after this method. + */ + virtual const uint8_t* getArray() const; + + protected: + Vector<uint8_t> mByteArray; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_BYTE_ARRAY_OUTPUT_H*/ diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h new file mode 100644 index 0000000..4389b02 --- /dev/null +++ b/media/img_utils/include/img_utils/DngUtils.h @@ -0,0 +1,132 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_DNG_UTILS_H +#define IMG_UTILS_DNG_UTILS_H + +#include <img_utils/ByteArrayOutput.h> +#include <img_utils/EndianUtils.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/RefBase.h> + +#include <cutils/compiler.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +#define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0]))) + +/** + * Utility class for building values for the OpcodeList tags specified + * in the Adobe DNG 1.4 spec. + */ +class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { + public: + enum CfaLayout { + CFA_RGGB = 0, + CFA_GRBG, + CFA_GBRG, + CFA_BGGR, + }; + + OpcodeListBuilder(); + virtual ~OpcodeListBuilder(); + + /** + * Get the total size of this opcode list in bytes. + */ + virtual size_t getSize() const; + + /** + * Get the number of opcodes defined in this list. + */ + virtual uint32_t getCount() const; + + /** + * Write the opcode list into the given buffer. This buffer + * must be able to hold at least as many elements as returned + * by calling the getSize() method. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t buildOpList(/*out*/ uint8_t* buf) const; + + /** + * Add GainMap opcode(s) for the given metadata parameters. The given + * CFA layout must match the layout of the shading map passed into the + * lensShadingMap parameter. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addGainMapsForMetadata(uint32_t lsmWidth, + uint32_t lsmHeight, + uint32_t activeAreaTop, + uint32_t activeAreaLeft, + uint32_t activeAreaBottom, + uint32_t activeAreaRight, + CfaLayout cfa, + const float* lensShadingMap); + + + /** + * Add a GainMap opcode with the given fields. The mapGains array + * must have mapPointsV * mapPointsH * mapPlanes elements. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addGainMap(uint32_t top, + uint32_t left, + uint32_t bottom, + uint32_t right, + uint32_t plane, + uint32_t planes, + uint32_t rowPitch, + uint32_t colPitch, + uint32_t mapPointsV, + uint32_t mapPointsH, + double mapSpacingV, + double mapSpacingH, + double mapOriginV, + double mapOriginH, + uint32_t mapPlanes, + const float* mapGains); + + // TODO: Add other Opcode methods + protected: + static const uint32_t FLAG_OPTIONAL = 0x1u; + static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u; + + enum { + GAIN_MAP_ID = 9, + LSM_R_IND = 0, + LSM_GE_IND = 1, + LSM_GO_IND = 2, + LSM_B_IND = 3, + }; + + uint32_t mCount; + ByteArrayOutput mOpList; + EndianOutput mEndianOut; + +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_DNG_UTILS_H*/ diff --git a/media/img_utils/include/img_utils/EndianUtils.h b/media/img_utils/include/img_utils/EndianUtils.h new file mode 100644 index 0000000..e99be1a --- /dev/null +++ b/media/img_utils/include/img_utils/EndianUtils.h @@ -0,0 +1,250 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_ENDIAN_UTILS +#define IMG_UTILS_ENDIAN_UTILS + +#include <img_utils/Output.h> + +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <stdint.h> +#include <endian.h> +#include <assert.h> + +namespace android { +namespace img_utils { + +/** + * Endianness types supported. + */ +enum ANDROID_API Endianness { + UNDEFINED_ENDIAN, // Default endianness will be used. + BIG, + LITTLE +}; + +/** + * Convert from the native device endianness to big endian. + */ +template<typename T> +T convertToBigEndian(T in); + +/** + * Convert from the native device endianness to little endian. + */ +template<typename T> +T convertToLittleEndian(T in); + +/** + * A utility class for writing to an Output with the given endianness. + */ +class ANDROID_API EndianOutput : public Output { + public: + /** + * Wrap the given Output. Calling write methods will result in + * writes to this output. + */ + EndianOutput(Output* out, Endianness end=LITTLE); + + virtual ~EndianOutput(); + + /** + * Call open on the wrapped output. + */ + virtual status_t open(); + + /** + * Call close on the wrapped output. + */ + virtual status_t close(); + + /** + * Set the endianness to use when writing. + */ + virtual void setEndianness(Endianness end); + + /** + * Get the currently configured endianness. + */ + virtual Endianness getEndianness() const; + + /** + * Get the current number of bytes written by this EndianOutput. + */ + virtual uint32_t getCurrentOffset() const; + + + // TODO: switch write methods to uint32_t instead of size_t, + // the max size of a TIFF files is bounded + + /** + * The following methods will write elements from given input buffer to the output. + * Count elements in the buffer will be written with the endianness set for this + * EndianOutput. If the given offset is greater than zero, that many elements will + * be skipped in the buffer before writing. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t write(const uint8_t* buf, size_t offset, size_t count); + + virtual status_t write(const int8_t* buf, size_t offset, size_t count); + + virtual status_t write(const uint16_t* buf, size_t offset, size_t count); + + virtual status_t write(const int16_t* buf, size_t offset, size_t count); + + virtual status_t write(const uint32_t* buf, size_t offset, size_t count); + + virtual status_t write(const int32_t* buf, size_t offset, size_t count); + + virtual status_t write(const uint64_t* buf, size_t offset, size_t count); + + virtual status_t write(const int64_t* buf, size_t offset, size_t count); + + virtual status_t write(const float* buf, size_t offset, size_t count); + + virtual status_t write(const double* buf, size_t offset, size_t count); + + protected: + template<typename T> + inline status_t writeHelper(const T* buf, size_t offset, size_t count); + + uint32_t mOffset; + Output* mOutput; + Endianness mEndian; +}; + +template<typename T> +inline status_t EndianOutput::writeHelper(const T* buf, size_t offset, size_t count) { + assert(offset <= count); + status_t res = OK; + size_t size = sizeof(T); + switch(mEndian) { + case BIG: { + for (size_t i = offset; i < count; ++i) { + T tmp = convertToBigEndian<T>(buf[offset + i]); + if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size)) + != OK) { + return res; + } + mOffset += size; + } + break; + } + case LITTLE: { + for (size_t i = offset; i < count; ++i) { + T tmp = convertToLittleEndian<T>(buf[offset + i]); + if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size)) + != OK) { + return res; + } + mOffset += size; + } + break; + } + default: { + return BAD_VALUE; + } + } + return res; +} + +template<> +inline uint8_t convertToBigEndian(uint8_t in) { + return in; +} + +template<> +inline int8_t convertToBigEndian(int8_t in) { + return in; +} + +template<> +inline uint16_t convertToBigEndian(uint16_t in) { + return htobe16(in); +} + +template<> +inline int16_t convertToBigEndian(int16_t in) { + return htobe16(in); +} + +template<> +inline uint32_t convertToBigEndian(uint32_t in) { + return htobe32(in); +} + +template<> +inline int32_t convertToBigEndian(int32_t in) { + return htobe32(in); +} + +template<> +inline uint64_t convertToBigEndian(uint64_t in) { + return htobe64(in); +} + +template<> +inline int64_t convertToBigEndian(int64_t in) { + return htobe64(in); +} + +template<> +inline uint8_t convertToLittleEndian(uint8_t in) { + return in; +} + +template<> +inline int8_t convertToLittleEndian(int8_t in) { + return in; +} + +template<> +inline uint16_t convertToLittleEndian(uint16_t in) { + return htole16(in); +} + +template<> +inline int16_t convertToLittleEndian(int16_t in) { + return htole16(in); +} + +template<> +inline uint32_t convertToLittleEndian(uint32_t in) { + return htole32(in); +} + +template<> +inline int32_t convertToLittleEndian(int32_t in) { + return htole32(in); +} + +template<> +inline uint64_t convertToLittleEndian(uint64_t in) { + return htole64(in); +} + +template<> +inline int64_t convertToLittleEndian(int64_t in) { + return htole64(in); +} + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_ENDIAN_UTILS*/ + diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h new file mode 100644 index 0000000..d3c5ec1 --- /dev/null +++ b/media/img_utils/include/img_utils/FileInput.h @@ -0,0 +1,76 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_FILE_INPUT_H +#define IMG_UTILS_FILE_INPUT_H + +#include <img_utils/Input.h> + +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <utils/String8.h> +#include <stdio.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * Utility class for reading from a file. + */ +class ANDROID_API FileInput : public Input { + public: + /** + * Create a file input for the given path. + */ + FileInput(String8 path); + + virtual ~FileInput(); + + /** + * Open a file descriptor to the path given in the constructor. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Read bytes from the file into the given buffer. At most, the number + * of bytes given in the count argument will be read. Bytes will be written + * into the given buffer starting at the index given in the offset argument. + * + * Returns the number of bytes read. If an error has occurred, the value pointed + * to by the given status_t pointer will be set to a negative error code. + */ + virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err); + + /** + * Close the file descriptor to the path given in the constructor. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); + private: + FILE *mFp; + String8 mPath; + bool mOpen; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + + +#endif /*IMG_UTILS_INPUT_H*/ diff --git a/media/img_utils/include/img_utils/FileOutput.h b/media/img_utils/include/img_utils/FileOutput.h new file mode 100644 index 0000000..fd5be27 --- /dev/null +++ b/media/img_utils/include/img_utils/FileOutput.h @@ -0,0 +1,46 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_FILE_OUTPUT_H +#define IMG_UTILS_FILE_OUTPUT_H + +#include <img_utils/Output.h> +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <utils/String8.h> +#include <stdio.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +class ANDROID_API FileOutput : public Output { + public: + FileOutput(String8 path); + virtual ~FileOutput(); + virtual status_t open(); + virtual status_t write(const uint8_t* buf, size_t offset, size_t count); + virtual status_t close(); + private: + FILE *mFp; + String8 mPath; + bool mOpen; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_FILE_OUTPUT_H*/ diff --git a/media/img_utils/include/img_utils/Input.h b/media/img_utils/include/img_utils/Input.h new file mode 100644 index 0000000..2166601 --- /dev/null +++ b/media/img_utils/include/img_utils/Input.h @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_INPUT_H +#define IMG_UTILS_INPUT_H + +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * Utility class used as a source of bytes. + */ +class ANDROID_API Input { + public: + virtual ~Input(); + + /** + * Open this Input. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Read bytes into the given buffer. At most, the number of bytes given in the + * count argument will be read. Bytes will be written into the given buffer starting + * at the index given in the offset argument. + * + * Returns the number of bytes read. If an error has occurred, the value pointed + * to by the given status_t pointer will be set to a negative error code. + */ + virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err) = 0; + + /** + * Close the Input. It is not valid to call open on a previously closed Input. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + + +#endif /*IMG_UTILS_INPUT_H*/ diff --git a/media/img_utils/include/img_utils/Orderable.h b/media/img_utils/include/img_utils/Orderable.h new file mode 100644 index 0000000..87253a4 --- /dev/null +++ b/media/img_utils/include/img_utils/Orderable.h @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_ORDERABLE +#define IMG_UTILS_ORDERABLE + +#include <cutils/compiler.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +#define COMPARE_DEF(op) \ +inline bool operator op (const Orderable& orderable) const; + +/** + * Subclasses of Orderable can be compared and sorted. This is + * intended to be used to create sorted arrays of TIFF entries + * and IFDs. + */ +class ANDROID_API Orderable { + public: + virtual ~Orderable(); + + /** + * Comparison operatotors are based on the value returned + * from this method. + */ + virtual uint32_t getComparableValue() const = 0; + + COMPARE_DEF(>) + COMPARE_DEF(<) + COMPARE_DEF(>=) + COMPARE_DEF(<=) + COMPARE_DEF(==) + COMPARE_DEF(!=) +}; + +#undef COMPARE_DEF + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_ORDERABLE*/ diff --git a/media/img_utils/include/img_utils/Output.h b/media/img_utils/include/img_utils/Output.h new file mode 100644 index 0000000..35fae23 --- /dev/null +++ b/media/img_utils/include/img_utils/Output.h @@ -0,0 +1,61 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_OUTPUT_H +#define IMG_UTILS_OUTPUT_H + +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * Utility class used to output bytes. + */ +class ANDROID_API Output { + public: + virtual ~Output(); + + /** + * Open this Output. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t open(); + + /** + * Write bytes from the given buffer. The number of bytes given in the count + * argument will be written. Bytes will be written from the given buffer starting + * at the index given in the offset argument. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t write(const uint8_t* buf, size_t offset, size_t count) = 0; + + /** + * Close this Output. It is not valid to call open on a previously closed Output. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t close(); +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_OUTPUT_H*/ diff --git a/media/img_utils/include/img_utils/Pair.h b/media/img_utils/include/img_utils/Pair.h new file mode 100644 index 0000000..d651cac --- /dev/null +++ b/media/img_utils/include/img_utils/Pair.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_PAIR_H +#define IMG_UTILS_PAIR_H + +#include <cutils/compiler.h> + +namespace android { +namespace img_utils { + +/** + * Generic pair utility class. Nothing special here. + */ +template<typename F, typename S> +class ANDROID_API Pair { + public: + F first; + S second; + + Pair() {} + + Pair(const Pair& o) : first(o.first), second(o.second) {} + + Pair(const F& f, const S& s) : first(f), second(s) {} +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_PAIR_H*/ diff --git a/media/img_utils/include/img_utils/SortedEntryVector.h b/media/img_utils/include/img_utils/SortedEntryVector.h new file mode 100644 index 0000000..f059a82 --- /dev/null +++ b/media/img_utils/include/img_utils/SortedEntryVector.h @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_SORTED_ENTRY_VECTOR_H +#define IMG_UTILS_SORTED_ENTRY_VECTOR_H + +#include <img_utils/TiffEntry.h> + +#include <utils/StrongPointer.h> +#include <utils/SortedVector.h> + +namespace android { +namespace img_utils { + +/** + * Subclass of SortedVector that has been extended to + * do comparisons/lookups based on the tag ID of the entries. + */ +class SortedEntryVector : public SortedVector<sp<TiffEntry> > { + public: + virtual ~SortedEntryVector(); + + /** + * Returns the index of the entry with the given tag ID, or + * -1 if none exists. + */ + ssize_t indexOfTag(uint16_t tag) const; + + protected: + /** + * Compare tag ID. + */ + virtual int do_compare(const void* lhs, const void* rhs) const; +}; + + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_SORTED_ENTRY_VECTOR_H*/ diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h new file mode 100644 index 0000000..9232e58 --- /dev/null +++ b/media/img_utils/include/img_utils/TagDefinitions.h @@ -0,0 +1,1139 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_TAG_DEFINITION_H +#define IMG_UTILS_TIFF_TAG_DEFINITION_H + +#include <img_utils/TiffEntry.h> +#include <img_utils/Output.h> +#include <img_utils/TiffHelpers.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * Tag definitions contain information about standard TIFF compatible tags. + */ +typedef struct TagDefinition { + // The specified tag ID. + uint16_t tagId; + // The default type for this tag. This must be a valid TIFF type. + TagType defaultType; + // The default Image File Directory (IFD) for this tag. + uint32_t defaultIfd; + // The valid count for this tag, or 0 if the count is not fixed. + uint32_t fixedCount; + // The endianness of the tag value, or UNDEFINED_ENDIAN if there is no fixed endian + Endianness fixedEndian; +} TagDefinition_t; + +/** + * Convenience defines for tag ids. + */ +enum { + TAG_RAWTOPREVIEWGAIN = 0xC7A8u, + TAG_NEWRAWIMAGEDIGEST = 0xC7A7u, + TAG_ORIGINALDEFAULTCROPSIZE = 0xC793u, + TAG_ORIGINALBESTQUALITYFINALSIZE = 0xC792u, + TAG_ORIGINALDEFAULTFINALSIZE = 0xC791u, + TAG_PROFILEHUESATMAPENCODING = 0xC7A3u, + TAG_PROFILELOOKTABLEENCODING = 0xC7A4u, + TAG_BASELINEEXPOSUREOFFSET = 0xC7A5u, + TAG_DEFAULTBLACKRENDER = 0xC7A6u, + TAG_DEFAULTUSERCROP = 0xC7B5u, + TAG_NOISEPROFILE = 0xC761u, + TAG_OPCODELIST3 = 0xC74Eu, + TAG_OPCODELIST2 = 0xC741u, + TAG_OPCODELIST1 = 0xC740u, + TAG_PROFILELOOKTABLEDATA = 0xC726u, + TAG_PROFILELOOKTABLEDIMS = 0xC725u, + TAG_ROWINTERLEAVEFACTOR = 0xC71Fu, + TAG_SUBTILEBLOCKSIZE = 0xC71Eu, + TAG_ORIGINALRAWFILEDIGEST = 0xC71Du, + TAG_RAWIMAGEDIGEST = 0xC71Cu, + TAG_PREVIEWDATETIME = 0xC71Bu, + TAG_PREVIEWCOLORSPACE = 0xC71Au, + TAG_PREVIEWSETTINGSDIGEST = 0xC719u, + TAG_PREVIEWSETTINGSNAME = 0xC718u, + TAG_PREVIEWAPPLICATIONVERSION = 0xC717u, + TAG_PREVIEWAPPLICATIONNAME = 0xC716u, + TAG_FORWARDMATRIX2 = 0xC715u, + TAG_FORWARDMATRIX1 = 0xC714u, + TAG_PROFILECOPYRIGHT = 0xC6FEu, + TAG_PROFILEEMBEDPOLICY = 0xC6FDu, + TAG_PROFILETONECURVE = 0xC6FCu, + TAG_PROFILEHUESATMAPDATA2 = 0xC6FBu, + TAG_PROFILEHUESATMAPDATA1 = 0xC6FAu, + TAG_PROFILEHUESATMAPDIMS = 0xC6F9u, + TAG_PROFILENAME = 0xC6F8u, + TAG_NOISEREDUCTIONAPPLIED = 0xC6F7u, + TAG_ASSHOTPROFILENAME = 0xC6F6u, + TAG_EXTRACAMERAPROFILES = 0xC6F5u, + TAG_PROFILECALIBRATIONSIGNATURE = 0xC6F4u, + TAG_CAMERACALIBRATIONSIGNATURE = 0xC6F3u, + TAG_COLORIMETRICREFERENCE = 0xC6BFu, + TAG_CURRENTPREPROFILEMATRIX = 0xC692u, + TAG_CURRENTICCPROFILE = 0xC691u, + TAG_ASSHOTPREPROFILEMATRIX = 0xC690u, + TAG_ASSHOTICCPROFILE = 0xC68Fu, + TAG_MASKEDAREAS = 0xC68Eu, + TAG_ACTIVEAREA = 0xC68Du, + TAG_ORIGINALRAWFILEDATA = 0xC68Cu, + TAG_ORIGINALRAWFILENAME = 0xC68Bu, + TAG_RAWDATAUNIQUEID = 0xC65Du, + TAG_MAKERNOTESAFETY = 0xC635u, + TAG_DNGPRIVATEDATA = 0xC634u, + TAG_SHADOWSCALE = 0xC633u, + TAG_ANTIALIASSTRENGTH = 0xC632u, + TAG_CHROMABLURRADIUS = 0xC631u, + TAG_LENSINFO = 0xC630u, + TAG_CAMERASERIALNUMBER = 0xC62Fu, + TAG_LINEARRESPONSELIMIT = 0xC62Eu, + TAG_BAYERGREENSPLIT = 0xC62Du, + TAG_BASELINESHARPNESS = 0xC62Cu, + TAG_BASELINENOISE = 0xC62Bu, + TAG_BASELINEEXPOSURE = 0xC62Au, + TAG_ASSHOTWHITEXY = 0xC629u, + TAG_ASSHOTNEUTRAL = 0xC628u, + TAG_ANALOGBALANCE = 0xC627u, + TAG_REDUCTIONMATRIX2 = 0xC626u, + TAG_REDUCTIONMATRIX1 = 0xC625u, + TAG_CAMERACALIBRATION2 = 0xC624u, + TAG_CAMERACALIBRATION1 = 0xC623u, + TAG_COLORMATRIX2 = 0xC622u, + TAG_COLORMATRIX1 = 0xC621u, + TAG_CALIBRATIONILLUMINANT2 = 0xC65Bu, + TAG_CALIBRATIONILLUMINANT1 = 0xC65Au, + TAG_DEFAULTCROPSIZE = 0xC620u, + TAG_DEFAULTCROPORIGIN = 0xC61Fu, + TAG_BESTQUALITYSCALE = 0xC65Cu, + TAG_DEFAULTSCALE = 0xC61Eu, + TAG_WHITELEVEL = 0xC61Du, + TAG_BLACKLEVELDELTAV = 0xC61Cu, + TAG_BLACKLEVELDELTAH = 0xC61Bu, + TAG_BLACKLEVEL = 0xC61Au, + TAG_BLACKLEVELREPEATDIM = 0xC619u, + TAG_LINEARIZATIONTABLE = 0xC618u, + TAG_CFALAYOUT = 0xC617u, + TAG_CFAPLANECOLOR = 0xC616u, + TAG_LOCALIZEDCAMERAMODEL = 0xC615u, + TAG_UNIQUECAMERAMODEL = 0xC614u, + TAG_DNGBACKWARDVERSION = 0xC613u, + TAG_DNGVERSION = 0xC612u, + TAG_SUBFILETYPE = 0x00FFu, + TAG_YRESOLUTION = 0x011Bu, + TAG_XRESOLUTION = 0x011Au, + TAG_THRESHHOLDING = 0x0107u, + TAG_STRIPOFFSETS = 0x0111u, + TAG_STRIPBYTECOUNTS = 0x0117u, + TAG_SOFTWARE = 0x0131u, + TAG_SAMPLESPERPIXEL = 0x0115u, + TAG_ROWSPERSTRIP = 0x0116u, + TAG_RESOLUTIONUNIT = 0x0128u, + TAG_PLANARCONFIGURATION = 0x011Cu, + TAG_PHOTOMETRICINTERPRETATION = 0x0106u, + TAG_ORIENTATION = 0x0112u, + TAG_NEWSUBFILETYPE = 0x00FEu, + TAG_MODEL = 0x0110u, + TAG_MINSAMPLEVALUE = 0x0118u, + TAG_MAXSAMPLEVALUE = 0x0119u, + TAG_MAKE = 0x010Fu, + TAG_IMAGEWIDTH = 0x0100u, + TAG_IMAGELENGTH = 0x0101u, + TAG_IMAGEDESCRIPTION = 0x010Eu, + TAG_HOSTCOMPUTER = 0x013Cu, + TAG_GRAYRESPONSEUNIT = 0x0122u, + TAG_GRAYRESPONSECURVE = 0x0123u, + TAG_FREEOFFSETS = 0x0120u, + TAG_FREEBYTECOUNTS = 0x0121u, + TAG_FILLORDER = 0x010Au, + TAG_EXTRASAMPLES = 0x0152u, + TAG_DATETIME = 0x0132u, + TAG_COPYRIGHT = 0x8298u, + TAG_COMPRESSION = 0x0103u, + TAG_COLORMAP = 0x0140u, + TAG_CELLWIDTH = 0x0108u, + TAG_CELLLENGTH = 0x0109u, + TAG_BITSPERSAMPLE = 0x0102u, + TAG_ARTIST = 0x013Bu, + TAG_EXIFVERSION = 0x9000u, + TAG_CFAREPEATPATTERNDIM = 0x828Du, + TAG_CFAPATTERN = 0x828Eu, + TAG_SUBIFDS = 0x014Au, +}; + +/** + * TIFF_EP_TAG_DEFINITIONS contains tags defined in the TIFF EP spec + */ +const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] = { + { // PhotometricInterpretation + 0x0106u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // SubIfds + 0x014Au, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CFAPattern + 0x828Eu, + BYTE, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CFARepeatPatternDim + 0x828Du, + SHORT, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + /*TODO: Remaining TIFF EP tags*/ +}; + +/** + * EXIF_2_3_TAG_DEFINITIONS contains tags defined in the Jeita EXIF 2.3 spec + */ +const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = { + { // ExifVersion + 0x9000u, + UNDEFINED, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + /*TODO: Remaining EXIF 2.3 tags*/ +}; + +/** + * TIFF_6_TAG_DEFINITIONS contains tags defined in the TIFF 6.0 spec + */ +const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = { + { // SubFileType + 0x00FFu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Artist + 0x013Bu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // BitsPerSample + 0x0102u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CellLength + 0x0109u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // CellWidth + 0x0108u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // ColorMap + 0x0140u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // Compression + 0x0103u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Copyright + 0x8298u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // DateTime + 0x0132u, + ASCII, + IFD_0, + 20, + UNDEFINED_ENDIAN + }, + { // ExtraSamples + 0x0152u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // FillOrder + 0x010Au, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // FreeByteCounts + 0x0121u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // FreeOffsets + 0x0120u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // GrayResponseCurve + 0x0123u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // GrayResponseUnit + 0x0122u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // HostComputer + 0x013Cu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ImageDescription + 0x010Eu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ImageLength + 0x0101u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // ImageWidth + 0x0100u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Make + 0x010Fu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // MaxSampleValue + 0x0119u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // MinSampleValue + 0x0118u, + SHORT, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // Model + 0x0110u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // NewSubfileType + 0x00FEu, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Orientation + 0x0112u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // PhotoMetricInterpretation + 0x0106u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // PlanarConfiguration + 0x011Cu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // ResolutionUnit + 0x0128u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // RowsPerStrip + 0x0116u, + LONG, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // SamplesPerPixel + 0x0115u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Software + 0x0131u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // StripByteCounts + 0x0117u, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // StripOffsets + 0x0111u, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // SubfileType + 0x00FFu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // Threshholding + 0x0107u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // XResolution + 0x011Au, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // YResolution + 0x011Bu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // YResolution + 0x011Bu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + } +}; + +/** + * DNG_TAG_DEFINITIONS contains tags defined in the DNG 1.4 spec + */ +const TagDefinition_t DNG_TAG_DEFINITIONS[] = { + { // DNGVersion + 0xC612u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // DNGBackwardVersion + 0xC613u, + BYTE, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // UniqueCameraModel + 0xC614u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // LocalizedCameraModel + 0xC615u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CFAPlaneColor + 0xC616u, + BYTE, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // CFALayout + 0xC617u, + SHORT, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // LinearizationTable + 0xC618u, + SHORT, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // BlackLevelRepeatDim + 0xC619u, + SHORT, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // BlackLevel + 0xC61Au, + LONG, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // BlackLevelDeltaH + 0xC61Bu, + SRATIONAL, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // BlackLevelDeltaV + 0xC61Cu, + SRATIONAL, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // WhiteLevel + 0xC61Du, + LONG, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // DefaultScale + 0xC61Eu, + RATIONAL, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // BestQualityScale + 0xC65Cu, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // DefaultCropOrigin + 0xC61Fu, + LONG, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // DefaultCropSize + 0xC620u, + LONG, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // CalibrationIlluminant1 + 0xC65Au, + SHORT, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // CalibrationIlluminant2 + 0xC65Bu, + SHORT, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ColorMatrix1 + 0xC621u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ColorMatrix2 + 0xC622u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // CameraCalibration1 + 0xC623u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CameraCalibration2 + 0xC624u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ReductionMatrix1 + 0xC625u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ReductionMatrix2 + 0xC626u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // AnalogBalance + 0xC627u, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotNeutral + 0xC628u, + RATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotWhiteXY + 0xC629u, + RATIONAL, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // BaselineExposure + 0xC62Au, + SRATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // BaselineNoise + 0xC62Bu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // BaselineSharpness + 0xC62Cu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // BayerGreenSplit + 0xC62Du, + LONG, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // LinearResponseLimit + 0xC62Eu, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // CameraSerialNumber + 0xC62Fu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // LensInfo + 0xC630u, + RATIONAL, + IFD_0, + 4, + UNDEFINED_ENDIAN + }, + { // ChromaBlurRadius + 0xC631u, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // AntiAliasStrength + 0xC632u, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ShadowScale + 0xC633u, + RATIONAL, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // DNGPrivateData + 0xC634u, + BYTE, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // MakerNoteSafety + 0xC635u, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // RawDataUniqueID + 0xC65Du, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // OriginalRawFileName + 0xC68Bu, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // OriginalRawFileData + 0xC68Cu, + UNDEFINED, + IFD_0, + 0, + BIG + }, + { // ActiveArea + 0xC68Du, + LONG, + RAW_IFD, + 4, + UNDEFINED_ENDIAN + }, + { // MaskedAreas + 0xC68Eu, + LONG, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotICCProfile + 0xC68Fu, + UNDEFINED, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotPreProfileMatrix + 0xC690u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CurrentICCProfile + 0xC691u, + UNDEFINED, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CurrentICCProfile + 0xC691u, + UNDEFINED, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // CurrentPreProfileMatrix + 0xC692u, + SRATIONAL, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ColorimetricReference + 0xC6BFu, + SHORT, + IFD_0, + 1, + UNDEFINED_ENDIAN + }, + { // CameraCalibrationSignature + 0xC6F3u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileCalibrationSignature + 0xC6F4u, + ASCII, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ExtraCameraProfiles + 0xC6F5u, + LONG, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // AsShotProfileName + 0xC6F6u, + ASCII, + IFD_0, + 0, + UNDEFINED_ENDIAN + }, + { // NoiseReductionApplied + 0xC6F7u, + RATIONAL, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileName + 0xC6F8u, + ASCII, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapDims + 0xC6F9u, + LONG, + PROFILE_IFD, + 3, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapData1 + 0xC6FAu, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapData2 + 0xC6FBu, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileToneCurve + 0xC6FCu, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ProfileEmbedPolicy + 0xC6FDu, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileCopyright + 0xC6FEu, + ASCII, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ForwardMatrix1 + 0xC714u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // ForwardMatrix2 + 0xC715u, + SRATIONAL, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewApplicationName + 0xC716u, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewApplicationVersion + 0xC717u, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewSettingsName + 0xC718u, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // PreviewSettingsDigest + 0xC719u, + BYTE, + PREVIEW_IFD, + 16, + UNDEFINED_ENDIAN + }, + { // PreviewColorSpace + 0xC71Au, + LONG, + PREVIEW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // PreviewDateTime + 0xC71Bu, + ASCII, + PREVIEW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // RawImageDigest + 0xC71Cu, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // OriginalRawFileDigest + 0xC71Du, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // SubTileBlockSize + 0xC71Eu, + LONG, + RAW_IFD, + 2, + UNDEFINED_ENDIAN + }, + { // RowInterleaveFactor + 0xC71Fu, + LONG, + RAW_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileLookTableDims + 0xC725u, + LONG, + PROFILE_IFD, + 3, + UNDEFINED_ENDIAN + }, + { // ProfileLookTableData + 0xC726u, + FLOAT, + PROFILE_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // OpcodeList1 + 0xC740u, + UNDEFINED, + RAW_IFD, + 0, + BIG + }, + { // OpcodeList2 + 0xC741u, + UNDEFINED, + RAW_IFD, + 0, + BIG + }, + { // OpcodeList3 + 0xC74Eu, + UNDEFINED, + RAW_IFD, + 0, + BIG + }, + { // NoiseProfile + 0xC761u, + DOUBLE, + RAW_IFD, + 0, + UNDEFINED_ENDIAN + }, + { // DefaultUserCrop + 0xC7B5u, + RATIONAL, + RAW_IFD, + 4, + UNDEFINED_ENDIAN + }, + { // DefaultBlackRender + 0xC7A6u, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // BaselineExposureOffset + 0xC7A5u, + RATIONAL, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileLookTableEncoding + 0xC7A4u, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // ProfileHueSatMapEncoding + 0xC7A3u, + LONG, + PROFILE_IFD, + 1, + UNDEFINED_ENDIAN + }, + { // OriginalDefaultFinalSize + 0xC791u, + LONG, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // OriginalBestQualityFinalSize + 0xC792u, + LONG, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // OriginalDefaultCropSize + 0xC793u, + LONG, + IFD_0, + 2, + UNDEFINED_ENDIAN + }, + { // NewRawImageDigest + 0xC7A7u, + BYTE, + IFD_0, + 16, + UNDEFINED_ENDIAN + }, + { // RawToPreviewGain + 0xC7A8u, + DOUBLE, + PREVIEW_IFD, + 1, + UNDEFINED_ENDIAN + }, +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_TAG_DEFINITION_H*/ diff --git a/media/img_utils/include/img_utils/TiffEntry.h b/media/img_utils/include/img_utils/TiffEntry.h new file mode 100644 index 0000000..cd01640 --- /dev/null +++ b/media/img_utils/include/img_utils/TiffEntry.h @@ -0,0 +1,129 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_ENTRY +#define IMG_UTILS_TIFF_ENTRY + +#include <img_utils/TiffWritable.h> +#include <img_utils/TiffHelpers.h> +#include <img_utils/EndianUtils.h> + +#include <cutils/compiler.h> +#include <utils/String8.h> +#include <utils/Errors.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +#define COMPARE_DEF(op) \ +inline bool operator op (const TiffEntry& entry) const; + +/** + * This class holds a single TIFF IFD entry. + */ +class ANDROID_API TiffEntry : public TiffWritable { + public: + // TODO: Copy constructor/equals here. + virtual ~TiffEntry(); + + /** + * Write the 12-byte IFD entry to the output. The given offset will be + * set as the tag value if the size of the tag value exceeds the max + * size for the TIFF Value field (4 bytes), and should be word aligned. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const = 0; + + /** + * Get the count set for this entry. This corresponds to the TIFF Count + * field. + */ + virtual uint32_t getCount() const = 0; + + /** + * Get the tag id set for this entry. This corresponds to the TIFF Tag + * field. + */ + virtual uint16_t getTag() const = 0; + + /** + * Get the type set for this entry. This corresponds to the TIFF Type + * field. + */ + virtual TagType getType() const = 0; + + /** + * Get the defined endianness for this entry. If this is defined, + * the tag value will be written with the given byte order. + */ + virtual Endianness getEndianness() const = 0; + + /** + * Get the value for this entry. This corresponds to the TIFF Value + * field. + * + * Returns NULL if the value is NULL, or if the type used does not + * match the type of this tag. + */ + template<typename T> + const T* getData() const; + + String8 toString() const; + + /** + * Force the type used here to be a valid TIFF type. + * + * Returns NULL if the given value is NULL, or if the type given does + * not match the type of the value given. + */ + template<typename T> + static const T* forceValidType(TagType type, const T* value); + + virtual const void* getDataHelper() const = 0; + + COMPARE_DEF(>) + COMPARE_DEF(<) + + protected: + enum { + MAX_PRINT_STRING_LENGTH = 256 + }; +}; + +#define COMPARE(op) \ +bool TiffEntry::operator op (const TiffEntry& entry) const { \ + return getComparableValue() op entry.getComparableValue(); \ +} + +COMPARE(>) +COMPARE(<) + + +template<typename T> +const T* TiffEntry::getData() const { + const T* value = reinterpret_cast<const T*>(getDataHelper()); + return forceValidType<T>(getType(), value); +} + +#undef COMPARE +#undef COMPARE_DEF + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_ENTRY*/ diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h new file mode 100644 index 0000000..cbe0e9a --- /dev/null +++ b/media/img_utils/include/img_utils/TiffEntryImpl.h @@ -0,0 +1,190 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_ENTRY_IMPL +#define IMG_UTILS_TIFF_ENTRY_IMPL + +#include <img_utils/TiffEntry.h> +#include <img_utils/TiffHelpers.h> +#include <img_utils/Output.h> +#include <img_utils/EndianUtils.h> + +#include <utils/Log.h> +#include <utils/Errors.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +template<typename T> +class TiffEntryImpl : public TiffEntry { + public: + // TODO: Copy constructor/equals here. + TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, const T* data); + virtual ~TiffEntryImpl(); + + status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const; + status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const; + + uint32_t getCount() const; + uint16_t getTag() const; + TagType getType() const; + Endianness getEndianness() const; + size_t getSize() const; + uint32_t getComparableValue() const; + + protected: + const void* getDataHelper() const; + uint32_t getActualSize() const; + + uint16_t mTag; + uint16_t mType; + uint32_t mCount; + Endianness mEnd; + T* mData; + +}; + +template<typename T> +TiffEntryImpl<T>::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, + const T* data) + : mTag(tag), mType(static_cast<uint16_t>(type)), mCount(count), mEnd(end) { + count = (type == RATIONAL || type == SRATIONAL) ? count * 2 : count; + mData = new T[count](); + for (uint32_t i = 0; i < count; ++i) { + mData[i] = data[i]; + } +} + +template<typename T> +TiffEntryImpl<T>::~TiffEntryImpl() { + if (mData) { + delete[] mData; + } +} + +template<typename T> +uint32_t TiffEntryImpl<T>::getCount() const { + return mCount; +} + +template<typename T> +uint16_t TiffEntryImpl<T>::getTag() const { + return mTag; +} + +template<typename T> +TagType TiffEntryImpl<T>::getType() const { + return static_cast<TagType>(mType); +} + +template<typename T> +const void* TiffEntryImpl<T>::getDataHelper() const { + return reinterpret_cast<const void*>(mData); +} + +template<typename T> +size_t TiffEntryImpl<T>::getSize() const { + uint32_t total = getActualSize(); + WORD_ALIGN(total) + return (total <= OFFSET_SIZE) ? 0 : total; +} + +template<typename T> +uint32_t TiffEntryImpl<T>::getActualSize() const { + uint32_t total = sizeof(T) * mCount; + if (getType() == RATIONAL || getType() == SRATIONAL) { + // 2 ints stored for each rational, multiply by 2 + total <<= 1; + } + return total; +} + +template<typename T> +Endianness TiffEntryImpl<T>::getEndianness() const { + return mEnd; +} + +template<typename T> +uint32_t TiffEntryImpl<T>::getComparableValue() const { + return mTag; +} + +template<typename T> +status_t TiffEntryImpl<T>::writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const { + assert((offset % TIFF_WORD_SIZE) == 0); + status_t ret = OK; + BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mType, 0, 1), ret); + BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret); + + uint32_t dataSize = getActualSize(); + if (dataSize > OFFSET_SIZE) { + BAIL_ON_FAIL(out->write(&offset, 0, 1), ret); + } else { + uint32_t count = mCount; + if (getType() == RATIONAL || getType() == SRATIONAL) { + /** + * Rationals are stored as an array of ints. Each + * rational is represented by 2 ints. To recover the + * size of the array here, multiply the count by 2. + */ + count <<= 1; + } + BAIL_ON_FAIL(out->write(mData, 0, count), ret); + ZERO_TILL_WORD(out, dataSize, ret); + } + return ret; +} + +template<typename T> +status_t TiffEntryImpl<T>::writeData(uint32_t offset, EndianOutput* out) const { + status_t ret = OK; + + // Some tags have fixed-endian value output + Endianness tmp = UNDEFINED_ENDIAN; + if (mEnd != UNDEFINED_ENDIAN) { + tmp = out->getEndianness(); + out->setEndianness(mEnd); + } + + uint32_t count = mCount; + if (getType() == RATIONAL || getType() == SRATIONAL) { + /** + * Rationals are stored as an array of ints. Each + * rational is represented by 2 ints. To recover the + * size of the array here, multiply the count by 2. + */ + count <<= 1; + } + + BAIL_ON_FAIL(out->write(mData, 0, count), ret); + + if (mEnd != UNDEFINED_ENDIAN) { + out->setEndianness(tmp); + } + + // Write to next word alignment + ZERO_TILL_WORD(out, sizeof(T) * count, ret); + return ret; +} + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_ENTRY_IMPL*/ + + diff --git a/media/img_utils/include/img_utils/TiffHelpers.h b/media/img_utils/include/img_utils/TiffHelpers.h new file mode 100644 index 0000000..fd0ea7a --- /dev/null +++ b/media/img_utils/include/img_utils/TiffHelpers.h @@ -0,0 +1,132 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_HELPERS_H +#define IMG_UTILS_TIFF_HELPERS_H + +#include <stdint.h> + +namespace android { +namespace img_utils { + +const uint8_t ZERO_WORD[] = {0, 0, 0, 0}; + +#define BAIL_ON_FAIL(x, flag) \ + if ((flag = (x)) != OK) return flag; + +#define BYTES_TILL_WORD(index) \ + ((TIFF_WORD_SIZE - ((index) % TIFF_WORD_SIZE)) % TIFF_WORD_SIZE) + +#define WORD_ALIGN(count) \ + count += BYTES_TILL_WORD(count); + +#define ZERO_TILL_WORD(output, index, ret) \ + { \ + size_t remaining = BYTES_TILL_WORD(index); \ + if (remaining > 0) { \ + BAIL_ON_FAIL(output->write(ZERO_WORD, 0, remaining), ret); \ + } \ + } + +/** + * Basic TIFF header constants. + */ +enum { + BAD_OFFSET = 0, + TIFF_WORD_SIZE = 4, // Size in bytes + IFD_HEADER_SIZE = 2, // Size in bytes + IFD_FOOTER_SIZE = 4, // Size in bytes + TIFF_ENTRY_SIZE = 12, // Size in bytes + MAX_IFD_ENTRIES = UINT16_MAX, + FILE_HEADER_SIZE = 8, // Size in bytes + ENDIAN_MARKER_SIZE = 2, // Size in bytes + TIFF_MARKER_SIZE = 2, // Size in bytes + OFFSET_MARKER_SIZE = 4, // Size in bytes + TIFF_FILE_MARKER = 42, + BIG_ENDIAN_MARKER = 0x4D4Du, + LITTLE_ENDIAN_MARKER = 0x4949u +}; + +/** + * Constants for the TIFF tag types. + */ +enum TagType { + UNKNOWN_TAGTYPE = 0, + BYTE=1, + ASCII, + SHORT, + LONG, + RATIONAL, + SBYTE, + UNDEFINED, + SSHORT, + SLONG, + SRATIONAL, + FLOAT, + DOUBLE +}; + +/** + * Sizes of the TIFF entry fields (in bytes). + */ +enum { + TAG_SIZE = 2, + TYPE_SIZE = 2, + COUNT_SIZE = 4, + OFFSET_SIZE = 4 +}; + +/** + * Convenience IFD id constants. + */ +enum { + IFD_0 = 0, + RAW_IFD, + PROFILE_IFD, + PREVIEW_IFD +}; + +inline size_t getTypeSize(TagType type) { + switch(type) { + case UNDEFINED: + case ASCII: + case BYTE: + case SBYTE: + return 1; + case SHORT: + case SSHORT: + return 2; + case LONG: + case SLONG: + case FLOAT: + return 4; + case RATIONAL: + case SRATIONAL: + case DOUBLE: + return 8; + default: + return 0; + } +} + +inline uint32_t calculateIfdSize(size_t numberOfEntries) { + return IFD_HEADER_SIZE + IFD_FOOTER_SIZE + TIFF_ENTRY_SIZE * numberOfEntries; +} + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_HELPERS_H*/ diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h new file mode 100644 index 0000000..9400456 --- /dev/null +++ b/media/img_utils/include/img_utils/TiffIfd.h @@ -0,0 +1,124 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_IFD_H +#define IMG_UTILS_TIFF_IFD_H + +#include <img_utils/TiffWritable.h> +#include <img_utils/TiffEntry.h> +#include <img_utils/Output.h> +#include <img_utils/SortedEntryVector.h> + +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <utils/String8.h> +#include <utils/SortedVector.h> +#include <utils/StrongPointer.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * This class holds a single TIFF Image File Directory (IFD) structure. + * + * This maps to the TIFF IFD structure that is logically composed of: + * - A 2-byte field listing the number of entries. + * - A list of 12-byte TIFF entries. + * - A 4-byte offset to the next IFD. + */ +class ANDROID_API TiffIfd : public TiffWritable { + public: + // TODO: Copy constructor/equals here - needed for SubIfds. + TiffIfd(uint32_t ifdId); + virtual ~TiffIfd(); + + /** + * Add a TiffEntry to this IFD or replace an existing entry with the + * same tag ID. No validation is done. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t addEntry(const sp<TiffEntry>& entry); + + /** + * Set the pointer to the next IFD. This is used to create a linked + * list of IFDs as defined by the TIFF 6.0 spec., and is not included + * when calculating the size of IFD and entries for the getSize() + * method (unlike SubIFDs). + */ + virtual void setNextIfd(const sp<TiffIfd>& ifd); + + /** + * Get the pointer to the next IFD, or NULL if none exists. + */ + virtual sp<TiffIfd> getNextIfd() const; + + /** + * Write the IFD data. This includes the IFD header, entries, footer, + * and the corresponding values for each entry (recursively including + * sub-IFDs). The written amount should end on a word boundary, and + * the given offset should be word aligned. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const; + + /** + * Get the size of the IFD. This includes the IFD header, entries, footer, + * and the corresponding values for each entry (recursively including + * any sub-IFDs). + */ + virtual size_t getSize() const; + + /** + * Get the id of this IFD. + */ + virtual uint32_t getId() const; + + /** + * Get an entry with the given tag ID. + * + * Returns a strong pointer to the entry if it exists, or an empty strong + * pointer. + */ + virtual sp<TiffEntry> getEntry(uint16_t tag) const; + + /** + * Get a formatted string representing this IFD. + */ + String8 toString() const; + + /** + * Print a formatted string representing this IFD to logcat. + */ + void log() const; + + /** + * Get value used to determine sort order. + */ + virtual uint32_t getComparableValue() const; + protected: + virtual uint32_t checkAndGetOffset(uint32_t offset) const; + SortedEntryVector mEntries; + sp<TiffIfd> mNextIfd; + uint32_t mIfdId; +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_IFD_H*/ diff --git a/media/img_utils/include/img_utils/TiffWritable.h b/media/img_utils/include/img_utils/TiffWritable.h new file mode 100644 index 0000000..a72cecc --- /dev/null +++ b/media/img_utils/include/img_utils/TiffWritable.h @@ -0,0 +1,60 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_WRITABLE +#define IMG_UTILS_TIFF_WRITABLE + +#include <img_utils/Orderable.h> +#include <img_utils/EndianUtils.h> +#include <img_utils/Output.h> + +#include <cutils/compiler.h> +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +/** + * TiffWritable subclasses represent TIFF metadata objects that can be written + * to an EndianOutput object. This is used for TIFF entries and IFDs. + */ +class ANDROID_API TiffWritable : public Orderable, public LightRefBase<TiffWritable> { + public: + TiffWritable(); + virtual ~TiffWritable(); + + /** + * Write the data to the output. The given offset is used to calculate + * the header offset for values written. The offset is defined + * relative to the beginning of the TIFF header, and is word aligned. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const = 0; + + /** + * Get the size of the data to write. + */ + virtual size_t getSize() const = 0; + +}; + +} /*namespace img_utils*/ +} /*namespace android*/ + +#endif /*IMG_UTILS_TIFF_WRITABLE*/ diff --git a/media/img_utils/include/img_utils/TiffWriter.h b/media/img_utils/include/img_utils/TiffWriter.h new file mode 100644 index 0000000..ec27fc3 --- /dev/null +++ b/media/img_utils/include/img_utils/TiffWriter.h @@ -0,0 +1,267 @@ +/* + * Copyright 2014 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. + */ + +#ifndef IMG_UTILS_TIFF_WRITER_H +#define IMG_UTILS_TIFF_WRITER_H + +#include <img_utils/EndianUtils.h> +#include <img_utils/TiffEntryImpl.h> +#include <img_utils/TagDefinitions.h> + +#include <utils/Log.h> +#include <utils/Errors.h> +#include <utils/StrongPointer.h> +#include <utils/KeyedVector.h> +#include <utils/Vector.h> + +#include <cutils/compiler.h> +#include <stdint.h> + +namespace android { +namespace img_utils { + +class TiffEntry; +class TiffIfd; +class Output; + +/** + * This class holds a collection of TIFF IFDs that can be written as a + * complete DNG file header. + * + * This maps to the TIFF header structure that is logically composed of: + * - An 8-byte file header containing an endianness indicator, the TIFF + * file marker, and the offset to the first IFD. + * - A list of TIFF IFD structures. + */ +class ANDROID_API TiffWriter : public LightRefBase<TiffWriter> { + public: + + /** + * Constructs a TiffWriter with the default tag mappings. This enables + * all of the tags defined in TagDefinitions.h, and uses the following + * mapping precedence to resolve collisions: + * (highest precedence) TIFF/EP > DNG > EXIF 2.3 > TIFF 6.0 + */ + TiffWriter(); + + /** + * Constructs a TiffWriter with the given tag mappings. The mapping + * precedence will be in the order that the definition maps are given, + * where the lower index map gets precedence. + * + * This can be used with user-defined definitions, or definitions form + * TagDefinitions.h + * + * The enabledDefinitions mapping object is owned by the caller, and must + * stay alive for the lifespan of the constructed TiffWriter object. + */ + TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions, + size_t length); + + virtual ~TiffWriter(); + + /** + * Write a TIFF header containing each IFD set. This will recursively + * write all SubIFDs and tags. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t write(Output* out, Endianness end = LITTLE); + + /** + * Get the total size in bytes of the TIFF header. This includes all + * IFDs, tags, and values set for this TiffWriter. + */ + virtual uint32_t getTotalSize() const; + + /** + * Add the given entry to its default IFD. If that IFD does not + * exist, it will be created. + */ + virtual status_t addEntry(const sp<TiffEntry>& entry); + + /** + * Build an entry for a known tag. This tag must be one of the tags + * defined in one of the definition vectors this TIFF writer was constructed + * with. The count and type are validated. If this succeeds, the resulting + * entry will be placed in the outEntry pointer. + * + * Returns OK on success, or a negative error code on failure. Valid + * error codes for this method are: + * - BAD_INDEX - The given tag doesn't exist. + * - BAD_VALUE - The given count doesn't match the required count for + * this tag. + * - BAD_TYPE - The type of the given data isn't compatible with the + * type required for this tag. + */ + template<typename T> + status_t buildEntry(uint16_t tag, uint32_t count, const T* data, + /*out*/sp<TiffEntry>* outEntry) const; + + /** + * Build an entry for a known tag and add it to the IFD with the given ID. + * This tag must be defined in one of the definition vectors this TIFF writer + * was constructed with. The count and type are validated. If this succeeds, + * the resulting entry will be placed in the outEntry pointer. + * + * Returns OK on success, or a negative error code on failure. Valid + * error codes for this method are: + * - BAD_INDEX - The given tag doesn't exist. + * - BAD_VALUE - The given count doesn't match the required count for + * this tag. + * - BAD_TYPE - The type of the given data isn't compatible with the + * type required for this tag. + * - NAME_NOT_FOUND - No ifd exists with the given ID. + */ + template<typename T> + status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd); + + /** + * Return the TIFF entry with the given tag ID in the IFD with the given ID, + * or an empty pointer if none exists. + */ + virtual sp<TiffEntry> getEntry(uint16_t tag, uint32_t ifd) const; + + /** + * Add the given IFD to the end of the top-level IFD chain. No + * validation is done. + * + * Returns OK on success, or a negative error code on failure. + */ + virtual status_t uncheckedAddIfd(const sp<TiffIfd>& ifd); + + /** + * Create an empty IFD with the given ID and add it to the end of the + * list of IFDs. + */ + virtual status_t addIfd(uint32_t ifd); + + /** + * Build an entry. No validation is done. + * + * WARNING: Using this method can result in creating poorly formatted + * TIFF files. + * + * Returns a TiffEntry with the given tag, type, count, endianness, + * and data. + */ + template<typename T> + static sp<TiffEntry> uncheckedBuildEntry(uint16_t tag, TagType type, + uint32_t count, Endianness end, const T* data); + + /** + * Utility function to build atag-to-definition mapping from a given + * array of tag definitions. + */ + static KeyedVector<uint16_t, const TagDefinition_t*> buildTagMap( + const TagDefinition_t* definitions, size_t length); + + /** + * Returns the default type for the given tag ID. + */ + virtual TagType getDefaultType(uint16_t tag) const; + + /** + * Returns the default count for a given tag ID, or 0 if this + * tag normally has a variable count. + */ + virtual uint32_t getDefaultCount(uint16_t tag) const; + + /** + * Returns true if a definition exist for the given tag ID. + */ + virtual bool checkIfDefined(uint16_t tag) const; + + /** + * Print the currently configured IFDs and entries to logcat. + */ + virtual void log() const; + + protected: + enum { + DEFAULT_NUM_TAG_MAPS = 4, + }; + + sp<TiffIfd> findLastIfd(); + status_t writeFileHeader(EndianOutput& out); + const TagDefinition_t* lookupDefinition(uint16_t tag) const; + status_t calculateOffsets(); + + sp<TiffIfd> mIfd; + KeyedVector<uint32_t, sp<TiffIfd> > mNamedIfds; + KeyedVector<uint16_t, const TagDefinition_t*>* mTagMaps; + size_t mNumTagMaps; + + static KeyedVector<uint16_t, const TagDefinition_t*> sTagMaps[]; +}; + +template<typename T> +status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data, + /*out*/sp<TiffEntry>* outEntry) const { + const TagDefinition_t* definition = lookupDefinition(tag); + + if (definition == NULL) { + ALOGE("%s: No such tag exists for id %x.", __FUNCTION__, tag); + return BAD_INDEX; + } + + uint32_t fixedCount = definition->fixedCount; + if (fixedCount > 0 && fixedCount != count) { + ALOGE("%s: Invalid count %d for tag %x (expects %d).", __FUNCTION__, count, tag, + fixedCount); + return BAD_VALUE; + } + + TagType fixedType = definition->defaultType; + if (TiffEntry::forceValidType(fixedType, data) == NULL) { + ALOGE("%s: Invalid type used for tag value for tag %x.", __FUNCTION__, tag); + return BAD_TYPE; + } + + *outEntry = new TiffEntryImpl<T>(tag, fixedType, count, + definition->fixedEndian, data); + + return OK; +} + +template<typename T> +status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) { + sp<TiffEntry> outEntry; + status_t ret = buildEntry<T>(tag, count, data, &outEntry); + if (ret != OK) { + ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag); + return ret; + } + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd); + return NAME_NOT_FOUND; + } + return mNamedIfds[index]->addEntry(outEntry); +} + +template<typename T> +sp<TiffEntry> TiffWriter::uncheckedBuildEntry(uint16_t tag, TagType type, uint32_t count, + Endianness end, const T* data) { + TiffEntryImpl<T>* entry = new TiffEntryImpl<T>(tag, type, count, end, data); + return sp<TiffEntry>(entry); +} + +} /*namespace img_utils*/ +} /*namespace android*/ + + +#endif /*IMG_UTILS_TIFF_WRITER_H*/ diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk new file mode 100644 index 0000000..80893be --- /dev/null +++ b/media/img_utils/src/Android.mk @@ -0,0 +1,61 @@ +# Copyright 2014 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + EndianUtils.cpp \ + FileInput.cpp \ + FileOutput.cpp \ + SortedEntryVector.cpp \ + Input.cpp \ + Output.cpp \ + Orderable.cpp \ + TiffIfd.cpp \ + TiffWritable.cpp \ + TiffWriter.cpp \ + TiffEntry.cpp \ + TiffEntryImpl.cpp \ + ByteArrayOutput.cpp \ + DngUtils.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libexpat \ + libutils \ + libcutils \ + libcamera_metadata \ + libcamera_client + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../include \ + system/media/camera/include + +LOCAL_CFLAGS += \ + -Wall \ + -Wextra \ + -Werror \ + -fvisibility=hidden + +ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),) + # Enable assert() in eng builds + LOCAL_CFLAGS += -UNDEBUG -DLOG_NDEBUG=1 +endif + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include + +LOCAL_MODULE := libimg_utils + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/img_utils/src/ByteArrayOutput.cpp b/media/img_utils/src/ByteArrayOutput.cpp new file mode 100644 index 0000000..db2d248 --- /dev/null +++ b/media/img_utils/src/ByteArrayOutput.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/ByteArrayOutput.h> + +#include <utils/Log.h> + +namespace android { +namespace img_utils { + +ByteArrayOutput::ByteArrayOutput() {} + +ByteArrayOutput::~ByteArrayOutput() {} + +status_t ByteArrayOutput::open() { + return OK; +} + +status_t ByteArrayOutput::write(const uint8_t* buf, size_t offset, size_t count) { + if (mByteArray.appendArray(buf + offset, count) < 0) { + ALOGE("%s: Failed to write to ByteArrayOutput.", __FUNCTION__); + return BAD_VALUE; + } + return OK; +} + +status_t ByteArrayOutput::close() { + mByteArray.clear(); + return OK; +} + +size_t ByteArrayOutput::getSize() const { + return mByteArray.size(); +} + +const uint8_t* ByteArrayOutput::getArray() const { + return mByteArray.array(); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp new file mode 100644 index 0000000..788dfc8 --- /dev/null +++ b/media/img_utils/src/DngUtils.cpp @@ -0,0 +1,280 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/DngUtils.h> + +namespace android { +namespace img_utils { + +OpcodeListBuilder::OpcodeListBuilder() : mOpList(), mEndianOut(&mOpList, BIG) { + if(mEndianOut.open() != OK) { + ALOGE("%s: Open failed.", __FUNCTION__); + } +} + +OpcodeListBuilder::~OpcodeListBuilder() { + if(mEndianOut.close() != OK) { + ALOGE("%s: Close failed.", __FUNCTION__); + } +} + +size_t OpcodeListBuilder::getSize() const { + return mOpList.getSize() + sizeof(mCount); +} + +uint32_t OpcodeListBuilder::getCount() const { + return mCount; +} + +status_t OpcodeListBuilder::buildOpList(uint8_t* buf) const { + uint32_t count = convertToBigEndian(mCount); + memcpy(buf, &count, sizeof(count)); + memcpy(buf + sizeof(count), mOpList.getArray(), mOpList.getSize()); + return OK; +} + +status_t OpcodeListBuilder::addGainMapsForMetadata(uint32_t lsmWidth, + uint32_t lsmHeight, + uint32_t activeAreaTop, + uint32_t activeAreaLeft, + uint32_t activeAreaBottom, + uint32_t activeAreaRight, + CfaLayout cfa, + const float* lensShadingMap) { + uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft; + uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop; + double spacingV = 1.0 / lsmHeight; + double spacingH = 1.0 / lsmWidth; + + float redMap[lsmWidth * lsmHeight]; + float greenEvenMap[lsmWidth * lsmHeight]; + float greenOddMap[lsmWidth * lsmHeight]; + float blueMap[lsmWidth * lsmHeight]; + + size_t lsmMapSize = lsmWidth * lsmHeight * 4; + + // Split lens shading map channels into separate arrays + size_t j = 0; + for (size_t i = 0; i < lsmMapSize; i += 4, ++j) { + redMap[j] = lensShadingMap[i + LSM_R_IND]; + greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND]; + greenOddMap[j] = lensShadingMap[i + LSM_GO_IND]; + blueMap[j] = lensShadingMap[i + LSM_B_IND]; + } + + uint32_t redTop = 0; + uint32_t redLeft = 0; + uint32_t greenEvenTop = 0; + uint32_t greenEvenLeft = 1; + uint32_t greenOddTop = 1; + uint32_t greenOddLeft = 0; + uint32_t blueTop = 1; + uint32_t blueLeft = 1; + + switch(cfa) { + case CFA_RGGB: + redTop = 0; + redLeft = 0; + greenEvenTop = 0; + greenEvenLeft = 1; + greenOddTop = 1; + greenOddLeft = 0; + blueTop = 1; + blueLeft = 1; + break; + case CFA_GRBG: + redTop = 0; + redLeft = 1; + greenEvenTop = 0; + greenEvenLeft = 0; + greenOddTop = 1; + greenOddLeft = 1; + blueTop = 1; + blueLeft = 0; + break; + case CFA_GBRG: + redTop = 1; + redLeft = 0; + greenEvenTop = 0; + greenEvenLeft = 0; + greenOddTop = 1; + greenOddLeft = 1; + blueTop = 0; + blueLeft = 1; + break; + case CFA_BGGR: + redTop = 1; + redLeft = 1; + greenEvenTop = 0; + greenEvenLeft = 1; + greenOddTop = 1; + greenOddLeft = 0; + blueTop = 0; + blueLeft = 0; + break; + default: + ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa); + return BAD_VALUE; + } + + status_t err = addGainMap(/*top*/redTop, + /*left*/redLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/redMap); + if (err != OK) return err; + + err = addGainMap(/*top*/greenEvenTop, + /*left*/greenEvenLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/greenEvenMap); + if (err != OK) return err; + + err = addGainMap(/*top*/greenOddTop, + /*left*/greenOddLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/greenOddMap); + if (err != OK) return err; + + err = addGainMap(/*top*/blueTop, + /*left*/blueLeft, + /*bottom*/activeAreaHeight - 1, + /*right*/activeAreaWidth - 1, + /*plane*/0, + /*planes*/1, + /*rowPitch*/2, + /*colPitch*/2, + /*mapPointsV*/lsmHeight, + /*mapPointsH*/lsmWidth, + /*mapSpacingV*/spacingV, + /*mapSpacingH*/spacingH, + /*mapOriginV*/0, + /*mapOriginH*/0, + /*mapPlanes*/1, + /*mapGains*/blueMap); + return err; +} + +status_t OpcodeListBuilder::addGainMap(uint32_t top, + uint32_t left, + uint32_t bottom, + uint32_t right, + uint32_t plane, + uint32_t planes, + uint32_t rowPitch, + uint32_t colPitch, + uint32_t mapPointsV, + uint32_t mapPointsH, + double mapSpacingV, + double mapSpacingH, + double mapOriginV, + double mapOriginH, + uint32_t mapPlanes, + const float* mapGains) { + + uint32_t opcodeId = GAIN_MAP_ID; + + status_t err = mEndianOut.write(&opcodeId, 0, 1); + if (err != OK) return err; + + uint8_t version[] = {1, 3, 0, 0}; + err = mEndianOut.write(version, 0, NELEMS(version)); + if (err != OK) return err; + + uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW; + err = mEndianOut.write(&flags, 0, 1); + if (err != OK) return err; + + const uint32_t NUMBER_INT_ARGS = 11; + const uint32_t NUMBER_DOUBLE_ARGS = 4; + + uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) + + mapPointsV * mapPointsH * mapPlanes * sizeof(float); + + err = mEndianOut.write(&totalSize, 0, 1); + if (err != OK) return err; + + // Batch writes as much as possible + uint32_t settings1[] = { top, + left, + bottom, + right, + plane, + planes, + rowPitch, + colPitch, + mapPointsV, + mapPointsH }; + + err = mEndianOut.write(settings1, 0, NELEMS(settings1)); + if (err != OK) return err; + + double settings2[] = { mapSpacingV, + mapSpacingH, + mapOriginV, + mapOriginH }; + + err = mEndianOut.write(settings2, 0, NELEMS(settings2)); + if (err != OK) return err; + + err = mEndianOut.write(&mapPlanes, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes); + if (err != OK) return err; + + mCount++; + + return OK; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/EndianUtils.cpp b/media/img_utils/src/EndianUtils.cpp new file mode 100644 index 0000000..8681cbe --- /dev/null +++ b/media/img_utils/src/EndianUtils.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/EndianUtils.h> + +namespace android { +namespace img_utils { + +EndianOutput::EndianOutput(Output* out, Endianness end) + : mOffset(0), mOutput(out), mEndian(end) {} + +EndianOutput::~EndianOutput() {} + +status_t EndianOutput::open() { + mOffset = 0; + return mOutput->open(); +} + +status_t EndianOutput::close() { + return mOutput->close(); +} + +void EndianOutput::setEndianness(Endianness end) { + mEndian = end; +} + +uint32_t EndianOutput::getCurrentOffset() const { + return mOffset; +} + +Endianness EndianOutput::getEndianness() const { + return mEndian; +} + +status_t EndianOutput::write(const uint8_t* buf, size_t offset, size_t count) { + status_t res = OK; + if((res = mOutput->write(buf, offset, count)) == OK) { + mOffset += count; + } + return res; +} + +status_t EndianOutput::write(const int8_t* buf, size_t offset, size_t count) { + return write(reinterpret_cast<const uint8_t*>(buf), offset, count); +} + +#define DEFINE_WRITE(_type_) \ +status_t EndianOutput::write(const _type_* buf, size_t offset, size_t count) { \ + return writeHelper<_type_>(buf, offset, count); \ +} + +DEFINE_WRITE(uint16_t) +DEFINE_WRITE(int16_t) +DEFINE_WRITE(uint32_t) +DEFINE_WRITE(int32_t) +DEFINE_WRITE(uint64_t) +DEFINE_WRITE(int64_t) + +status_t EndianOutput::write(const float* buf, size_t offset, size_t count) { + assert(sizeof(float) == sizeof(uint32_t)); + return writeHelper<uint32_t>(reinterpret_cast<const uint32_t*>(buf), offset, count); +} + +status_t EndianOutput::write(const double* buf, size_t offset, size_t count) { + assert(sizeof(double) == sizeof(uint64_t)); + return writeHelper<uint64_t>(reinterpret_cast<const uint64_t*>(buf), offset, count); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp new file mode 100644 index 0000000..e43fd53 --- /dev/null +++ b/media/img_utils/src/FileInput.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/FileInput.h> + +#include <utils/Log.h> + +namespace android { +namespace img_utils { + +FileInput::FileInput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {} + +FileInput::~FileInput() { + if (mOpen) { + ALOGE("%s: FileInput destroyed without calling close!", __FUNCTION__); + close(); + } + +} + +status_t FileInput::open() { + if (mOpen) { + ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string()); + return OK; + } + mFp = ::fopen(mPath, "rb"); + if (!mFp) { + ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string()); + return BAD_VALUE; + } + mOpen = true; + return OK; +} + +size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) { + if (!mOpen) { + ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string()); + if (err != NULL) *err = BAD_VALUE; + return 0; + } + + size_t bytesRead = ::fread(buf + offset, sizeof(uint8_t), count, mFp); + int error = ::ferror(mFp); + if (error != 0) { + ALOGE("%s: Error %d occurred while reading file %s.", __FUNCTION__, error, mPath.string()); + if (err != NULL) *err = BAD_VALUE; + } + return bytesRead; +} + +status_t FileInput::close() { + if(!mOpen) { + ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string()); + return OK; + } + + status_t ret = OK; + if(::fclose(mFp) != 0) { + ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string()); + ret = BAD_VALUE; + } + mOpen = false; + return OK; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/FileOutput.cpp b/media/img_utils/src/FileOutput.cpp new file mode 100644 index 0000000..ce763ff --- /dev/null +++ b/media/img_utils/src/FileOutput.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/FileOutput.h> + +#include <utils/Log.h> + +namespace android { +namespace img_utils { + +FileOutput::FileOutput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {} + +FileOutput::~FileOutput() { + if (mOpen) { + ALOGW("%s: Destructor called with %s still open.", __FUNCTION__, mPath.string()); + close(); + } +} + +status_t FileOutput::open() { + if (mOpen) { + ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string()); + return OK; + } + mFp = ::fopen(mPath, "wb"); + if (!mFp) { + ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string()); + return BAD_VALUE; + } + mOpen = true; + return OK; +} + +status_t FileOutput::write(const uint8_t* buf, size_t offset, size_t count) { + if (!mOpen) { + ALOGE("%s: Could not write file %s, file not open.", __FUNCTION__, mPath.string()); + return BAD_VALUE; + } + + ::fwrite(buf + offset, sizeof(uint8_t), count, mFp); + + int error = ::ferror(mFp); + if (error != 0) { + ALOGE("%s: Error %d occurred while writing file %s.", __FUNCTION__, error, mPath.string()); + return BAD_VALUE; + } + return OK; +} + +status_t FileOutput::close() { + if(!mOpen) { + ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string()); + return OK; + } + + status_t ret = OK; + if(::fclose(mFp) != 0) { + ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string()); + ret = BAD_VALUE; + } + mOpen = false; + return OK; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp new file mode 100644 index 0000000..1e51e10 --- /dev/null +++ b/media/img_utils/src/Input.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/Input.h> + +namespace android { +namespace img_utils { + +Input::~Input() {} +status_t Input::open() { return OK; } +status_t Input::close() { return OK; } + + +} /*namespace img_utils*/ +} /*namespace android*/ + diff --git a/media/img_utils/src/Orderable.cpp b/media/img_utils/src/Orderable.cpp new file mode 100644 index 0000000..300f122 --- /dev/null +++ b/media/img_utils/src/Orderable.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/Orderable.h> + +#include <utils/Log.h> + +namespace android { +namespace img_utils { + +#define COMPARE(op) \ +bool Orderable::operator op (const Orderable& orderable) const { \ + return getComparableValue() op orderable.getComparableValue(); \ +} + +COMPARE(>) +COMPARE(<) +COMPARE(>=) +COMPARE(<=) +COMPARE(==) +COMPARE(!=) + +Orderable::~Orderable() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/Output.cpp b/media/img_utils/src/Output.cpp new file mode 100644 index 0000000..0e395b9 --- /dev/null +++ b/media/img_utils/src/Output.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2014 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. + */ + + +#include <img_utils/Output.h> + +namespace android { +namespace img_utils { + +Output::~Output() {} +status_t Output::open() { return OK; } +status_t Output::close() { return OK; } + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/SortedEntryVector.cpp b/media/img_utils/src/SortedEntryVector.cpp new file mode 100644 index 0000000..f0e1fa1 --- /dev/null +++ b/media/img_utils/src/SortedEntryVector.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/SortedEntryVector.h> + +#include <utils/TypeHelpers.h> +#include <utils/Log.h> + +namespace android { +namespace img_utils { + +SortedEntryVector::~SortedEntryVector() {} + +ssize_t SortedEntryVector::indexOfTag(uint16_t tag) const { + // TODO: Use binary search here. + for (size_t i = 0; i < size(); ++i) { + if (itemAt(i)->getTag() == tag) { + return i; + } + } + return -1; +} + +int SortedEntryVector::do_compare(const void* lhs, const void* rhs) const { + const sp<TiffEntry>* lEntry = reinterpret_cast<const sp<TiffEntry>*>(lhs); + const sp<TiffEntry>* rEntry = reinterpret_cast<const sp<TiffEntry>*>(rhs); + return compare_type(**lEntry, **rEntry); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp new file mode 100644 index 0000000..e028827 --- /dev/null +++ b/media/img_utils/src/TiffEntry.cpp @@ -0,0 +1,238 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/TiffIfd.h> +#include <img_utils/TiffHelpers.h> +#include <img_utils/TiffEntry.h> + +#include <utils/Errors.h> +#include <utils/StrongPointer.h> +#include <utils/Vector.h> + +namespace android { +namespace img_utils { + +TiffEntry::~TiffEntry() {} + +/** + * Specialize for each valid type, including sub-IFDs. + * + * Values with types other than the ones given here should not compile. + */ +template<> +const Vector<sp<TiffIfd> >* TiffEntry::forceValidType<Vector<sp<TiffIfd> > >(TagType type, + const Vector<sp<TiffIfd> >* value) { + if (type == LONG) { + return value; + } + ALOGE("%s: Value of type 'ifd vector' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const sp<TiffIfd>* TiffEntry::forceValidType<sp<TiffIfd> >(TagType type, const sp<TiffIfd>* value) { + if (type == LONG) { + return value; + } + ALOGE("%s: Value of type 'ifd' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const uint8_t* TiffEntry::forceValidType<uint8_t>(TagType type, const uint8_t* value) { + if (type == BYTE || type == ASCII || type == UNDEFINED) { + return value; + } + ALOGE("%s: Value of type 'uint8_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const int8_t* TiffEntry::forceValidType<int8_t>(TagType type, const int8_t* value) { + if (type == SBYTE || type == ASCII || type == UNDEFINED) { + return value; + } + ALOGE("%s: Value of type 'int8_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const uint16_t* TiffEntry::forceValidType<uint16_t>(TagType type, const uint16_t* value) { + if (type == SHORT) { + return value; + } + ALOGE("%s: Value of type 'uint16_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const int16_t* TiffEntry::forceValidType<int16_t>(TagType type, const int16_t* value) { + if (type == SSHORT) { + return value; + } + ALOGE("%s: Value of type 'int16_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const uint32_t* TiffEntry::forceValidType<uint32_t>(TagType type, const uint32_t* value) { + if (type == LONG || type == RATIONAL) { + return value; + } + ALOGE("%s: Value of type 'uint32_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const int32_t* TiffEntry::forceValidType<int32_t>(TagType type, const int32_t* value) { + if (type == SLONG || type == SRATIONAL) { + return value; + } + ALOGE("%s: Value of type 'int32_t' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const double* TiffEntry::forceValidType<double>(TagType type, const double* value) { + if (type == DOUBLE) { + return value; + } + ALOGE("%s: Value of type 'double' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +template<> +const float* TiffEntry::forceValidType<float>(TagType type, const float* value) { + if (type == FLOAT) { + return value; + } + ALOGE("%s: Value of type 'float' is not valid for tag with TIFF type %d.", + __FUNCTION__, type); + return NULL; +} + +String8 TiffEntry::toString() const { + String8 output; + uint32_t count = getCount(); + output.appendFormat("[id: %x, type: %d, count: %u, value: '", getTag(), getType(), count); + + size_t cappedCount = count; + if (count > MAX_PRINT_STRING_LENGTH) { + cappedCount = MAX_PRINT_STRING_LENGTH; + } + + TagType type = getType(); + switch (type) { + case UNDEFINED: + case BYTE: { + const uint8_t* typed_data = getData<uint8_t>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%u ", typed_data[i]); + } + break; + } + case ASCII: { + const char* typed_data = reinterpret_cast<const char*>(getData<uint8_t>()); + size_t len = count; + if (count > MAX_PRINT_STRING_LENGTH) { + len = MAX_PRINT_STRING_LENGTH; + } + output.append(typed_data, len); + break; + } + case SHORT: { + const uint16_t* typed_data = getData<uint16_t>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%u ", typed_data[i]); + } + break; + } + case LONG: { + const uint32_t* typed_data = getData<uint32_t>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%u ", typed_data[i]); + } + break; + } + case RATIONAL: { + const uint32_t* typed_data = getData<uint32_t>(); + cappedCount <<= 1; + for (size_t i = 0; i < cappedCount; i+=2) { + output.appendFormat("%u/%u ", typed_data[i], typed_data[i + 1]); + } + break; + } + case SBYTE: { + const int8_t* typed_data = getData<int8_t>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%d ", typed_data[i]); + } + break; + } + case SSHORT: { + const int16_t* typed_data = getData<int16_t>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%d ", typed_data[i]); + } + break; + } + case SLONG: { + const int32_t* typed_data = getData<int32_t>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%d ", typed_data[i]); + } + break; + } + case SRATIONAL: { + const int32_t* typed_data = getData<int32_t>(); + cappedCount <<= 1; + for (size_t i = 0; i < cappedCount; i+=2) { + output.appendFormat("%d/%d ", typed_data[i], typed_data[i + 1]); + } + break; + } + case FLOAT: + case DOUBLE: { + const float* typed_data = getData<float>(); + for (size_t i = 0; i < cappedCount; ++i) { + output.appendFormat("%f ", typed_data[i]); + } + break; + } + default: { + output.append("unknown type "); + break; + } + } + + if (count > MAX_PRINT_STRING_LENGTH) { + output.append("..."); + } + output.append("']"); + return output; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp new file mode 100644 index 0000000..6efa458 --- /dev/null +++ b/media/img_utils/src/TiffEntryImpl.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/TiffEntryImpl.h> +#include <img_utils/TiffIfd.h> + +#include <utils/Vector.h> + +namespace android { +namespace img_utils { + +template<> +size_t TiffEntryImpl<TiffIfd>::getSize() const { + uint32_t total = 0; + for (uint32_t i = 0; i < mCount; ++i) { + total += mData[i].getSize(); + } + return total; +} + +template<> +status_t TiffEntryImpl<TiffIfd>::writeData(uint32_t offset, EndianOutput* out) const { + status_t ret = OK; + for (uint32_t i = 0; i < mCount; ++i) { + BAIL_ON_FAIL(mData[i].writeData(offset, out), ret); + } + return ret; +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp new file mode 100644 index 0000000..1b3b40d --- /dev/null +++ b/media/img_utils/src/TiffIfd.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/TiffIfd.h> +#include <img_utils/TiffHelpers.h> + +#include <utils/Log.h> + +namespace android { +namespace img_utils { + +TiffIfd::TiffIfd(uint32_t ifdId) + : mNextIfd(), mIfdId(ifdId) {} + +TiffIfd::~TiffIfd() {} + +status_t TiffIfd::addEntry(const sp<TiffEntry>& entry) { + size_t size = mEntries.size(); + if (size >= MAX_IFD_ENTRIES) { + ALOGW("%s: Failed to add entry for tag 0x%x to IFD %u, too many entries in IFD!", + __FUNCTION__, entry->getTag(), mIfdId); + return BAD_INDEX; + } + + if (mEntries.add(entry) < 0) { + ALOGW("%s: Failed to add entry for tag 0x%x to ifd %u.", __FUNCTION__, entry->getTag(), + mIfdId); + return BAD_INDEX; + } + return OK; +} + +sp<TiffEntry> TiffIfd::getEntry(uint16_t tag) const { + ssize_t index = mEntries.indexOfTag(tag); + if (index < 0) { + ALOGW("%s: No entry for tag 0x%x in ifd %u.", __FUNCTION__, tag, mIfdId); + return NULL; + } + return mEntries[index]; +} + +void TiffIfd::setNextIfd(const sp<TiffIfd>& ifd) { + mNextIfd = ifd; +} + +sp<TiffIfd> TiffIfd::getNextIfd() const { + return mNextIfd; +} + +uint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const { + size_t size = mEntries.size(); + + if (size > MAX_IFD_ENTRIES) { + ALOGW("%s: Could not calculate IFD offsets, IFD %u contains too many entries.", + __FUNCTION__, mIfdId); + return BAD_OFFSET; + } + + if (size <= 0) { + ALOGW("%s: Could not calculate IFD offsets, IFD %u contains no entries.", __FUNCTION__, + mIfdId); + return BAD_OFFSET; + } + + if (offset == BAD_OFFSET) { + ALOGW("%s: Could not calculate IFD offsets, IFD %u had a bad initial offset.", + __FUNCTION__, mIfdId); + return BAD_OFFSET; + } + + uint32_t ifdSize = calculateIfdSize(size); + WORD_ALIGN(ifdSize); + return offset + ifdSize; +} + +status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const { + assert((offset % TIFF_WORD_SIZE) == 0); + status_t ret = OK; + + ALOGV("%s: IFD %u written to offset %u", __FUNCTION__, mIfdId, offset ); + uint32_t valueOffset = checkAndGetOffset(offset); + if (valueOffset == 0) { + return BAD_VALUE; + } + + size_t size = mEntries.size(); + + // Writer IFD header (2 bytes, number of entries). + uint16_t header = static_cast<uint16_t>(size); + BAIL_ON_FAIL(out->write(&header, 0, 1), ret); + + // Write tag entries + for (size_t i = 0; i < size; ++i) { + BAIL_ON_FAIL(mEntries[i]->writeTagInfo(valueOffset, out), ret); + valueOffset += mEntries[i]->getSize(); + } + + // Writer IFD footer (4 bytes, offset to next IFD). + uint32_t footer = (mNextIfd != NULL) ? offset + getSize() : 0; + BAIL_ON_FAIL(out->write(&footer, 0, 1), ret); + + assert(out->getCurrentOffset() == offset + calculateIfdSize(size)); + + // Write zeroes till word aligned + ZERO_TILL_WORD(out, calculateIfdSize(size), ret); + + // Write values for each tag entry + for (size_t i = 0; i < size; ++i) { + size_t last = out->getCurrentOffset(); + // Only write values that are too large to fit in the 12-byte TIFF entry + if (mEntries[i]->getSize() > OFFSET_SIZE) { + BAIL_ON_FAIL(mEntries[i]->writeData(out->getCurrentOffset(), out), ret); + } + size_t next = out->getCurrentOffset(); + size_t diff = (next - last); + size_t actual = mEntries[i]->getSize(); + if (diff != actual) { + ALOGW("Sizes do not match for tag %x. Expected %zu, received %zu", + mEntries[i]->getTag(), actual, diff); + } + } + + assert(out->getCurrentOffset() == offset + getSize()); + + return ret; +} + +size_t TiffIfd::getSize() const { + size_t size = mEntries.size(); + uint32_t total = calculateIfdSize(size); + WORD_ALIGN(total); + for (size_t i = 0; i < size; ++i) { + total += mEntries[i]->getSize(); + } + return total; +} + +uint32_t TiffIfd::getId() const { + return mIfdId; +} + +uint32_t TiffIfd::getComparableValue() const { + return mIfdId; +} + +String8 TiffIfd::toString() const { + size_t s = mEntries.size(); + String8 output; + output.appendFormat("[ifd: %x, num_entries: %zu, entries:\n", getId(), s); + for(size_t i = 0; i < mEntries.size(); ++i) { + output.append("\t"); + output.append(mEntries[i]->toString()); + output.append("\n"); + } + output.append(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0)); + return output; +} + +void TiffIfd::log() const { + size_t s = mEntries.size(); + ALOGI("[ifd: %x, num_entries: %zu, entries:\n", getId(), s); + for(size_t i = 0; i < s; ++i) { + ALOGI("\t%s", mEntries[i]->toString().string()); + } + ALOGI(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0)); +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffWritable.cpp b/media/img_utils/src/TiffWritable.cpp new file mode 100644 index 0000000..f8d7de7 --- /dev/null +++ b/media/img_utils/src/TiffWritable.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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. + */ + + +#include <img_utils/TiffWritable.h> +#include <img_utils/TiffHelpers.h> + +#include <assert.h> + +namespace android { +namespace img_utils { + +TiffWritable::TiffWritable() {} + +TiffWritable::~TiffWritable() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp new file mode 100644 index 0000000..2439033 --- /dev/null +++ b/media/img_utils/src/TiffWriter.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2014 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. + */ + +#include <img_utils/TiffIfd.h> +#include <img_utils/TiffHelpers.h> +#include <img_utils/TiffWriter.h> +#include <img_utils/TagDefinitions.h> + +#include <assert.h> + +namespace android { +namespace img_utils { + +KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::buildTagMap( + const TagDefinition_t* definitions, size_t length) { + KeyedVector<uint16_t, const TagDefinition_t*> map; + for(size_t i = 0; i < length; ++i) { + map.add(definitions[i].tagId, definitions + i); + } + return map; +} + +#define COMPARE(op) \ +bool Orderable::operator op (const Orderable& orderable) const { \ + return getComparableValue() op orderable.getComparableValue(); \ +} + +#define ARRAY_SIZE(array) \ + (sizeof(array) / sizeof(array[0])) + +KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::sTagMaps[] = { + buildTagMap(TIFF_EP_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_EP_TAG_DEFINITIONS)), + buildTagMap(DNG_TAG_DEFINITIONS, ARRAY_SIZE(DNG_TAG_DEFINITIONS)), + buildTagMap(EXIF_2_3_TAG_DEFINITIONS, ARRAY_SIZE(EXIF_2_3_TAG_DEFINITIONS)), + buildTagMap(TIFF_6_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_6_TAG_DEFINITIONS)) +}; + +TiffWriter::TiffWriter() : mTagMaps(sTagMaps), mNumTagMaps(DEFAULT_NUM_TAG_MAPS) {} + +TiffWriter::TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions, + size_t length) : mTagMaps(enabledDefinitions), mNumTagMaps(length) {} + +TiffWriter::~TiffWriter() {} + +status_t TiffWriter::write(Output* out, Endianness end) { + status_t ret = OK; + EndianOutput endOut(out, end); + + if (mIfd == NULL) { + ALOGE("%s: Tiff header is empty.", __FUNCTION__); + return BAD_VALUE; + } + BAIL_ON_FAIL(writeFileHeader(endOut), ret); + + uint32_t offset = FILE_HEADER_SIZE; + sp<TiffIfd> ifd = mIfd; + while(ifd != NULL) { + BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret); + offset += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + return ret; +} + + +const TagDefinition_t* TiffWriter::lookupDefinition(uint16_t tag) const { + const TagDefinition_t* definition = NULL; + for (size_t i = 0; i < mNumTagMaps; ++i) { + ssize_t index = mTagMaps[i].indexOfKey(tag); + if (index >= 0) { + definition = mTagMaps[i][index]; + break; + } + } + + if (definition == NULL) { + ALOGE("%s: No definition exists for tag with id %x.", __FUNCTION__, tag); + } + return definition; +} + +sp<TiffEntry> TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd); + return NULL; + } + return mNamedIfds[index]->getEntry(tag); +} + + +// TODO: Fix this to handle IFD position in chain/sub-IFD tree +status_t TiffWriter::addEntry(const sp<TiffEntry>& entry) { + uint16_t tag = entry->getTag(); + + const TagDefinition_t* definition = lookupDefinition(tag); + + if (definition == NULL) { + return BAD_INDEX; + } + uint32_t ifdId = 0; // TODO: all in IFD0 for now. + + ssize_t index = mNamedIfds.indexOfKey(ifdId); + + // Add a new IFD if necessary + if (index < 0) { + sp<TiffIfd> ifdEntry = new TiffIfd(ifdId); + if (mIfd == NULL) { + mIfd = ifdEntry; + } + index = mNamedIfds.add(ifdId, ifdEntry); + assert(index >= 0); + } + + sp<TiffIfd> selectedIfd = mNamedIfds[index]; + return selectedIfd->addEntry(entry); +} + +status_t TiffWriter::uncheckedAddIfd(const sp<TiffIfd>& ifd) { + mNamedIfds.add(ifd->getId(), ifd); + sp<TiffIfd> last = findLastIfd(); + if (last == NULL) { + mIfd = ifd; + } else { + last->setNextIfd(ifd); + } + last = ifd->getNextIfd(); + while (last != NULL) { + mNamedIfds.add(last->getId(), last); + last = last->getNextIfd(); + } + return OK; +} + +status_t TiffWriter::addIfd(uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); + return BAD_VALUE; + } + sp<TiffIfd> newIfd = new TiffIfd(ifd); + if (mIfd == NULL) { + mIfd = newIfd; + } else { + sp<TiffIfd> last = findLastIfd(); + last->setNextIfd(newIfd); + } + mNamedIfds.add(ifd, newIfd); + return OK; +} + +TagType TiffWriter::getDefaultType(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag); + return UNKNOWN_TAGTYPE; + } + return definition->defaultType; +} + +uint32_t TiffWriter::getDefaultCount(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag); + return 0; + } + return definition->fixedCount; +} + +bool TiffWriter::checkIfDefined(uint16_t tag) const { + return lookupDefinition(tag) != NULL; +} + +sp<TiffIfd> TiffWriter::findLastIfd() { + sp<TiffIfd> ifd = mIfd; + while(ifd != NULL) { + sp<TiffIfd> nextIfd = ifd->getNextIfd(); + if (nextIfd == NULL) { + break; + } + ifd = nextIfd; + } + return ifd; +} + +status_t TiffWriter::writeFileHeader(EndianOutput& out) { + status_t ret = OK; + uint16_t endMarker = (out.getEndianness() == BIG) ? BIG_ENDIAN_MARKER : LITTLE_ENDIAN_MARKER; + BAIL_ON_FAIL(out.write(&endMarker, 0, 1), ret); + + uint16_t tiffMarker = TIFF_FILE_MARKER; + BAIL_ON_FAIL(out.write(&tiffMarker, 0, 1), ret); + + uint32_t offsetMarker = FILE_HEADER_SIZE; + BAIL_ON_FAIL(out.write(&offsetMarker, 0, 1), ret); + return ret; +} + +uint32_t TiffWriter::getTotalSize() const { + uint32_t totalSize = FILE_HEADER_SIZE; + sp<TiffIfd> ifd = mIfd; + while(ifd != NULL) { + totalSize += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + return totalSize; +} + +void TiffWriter::log() const { + ALOGI("%s: TiffWriter:", __FUNCTION__); + sp<TiffIfd> ifd = mIfd; + while(ifd != NULL) { + ifd->log(); + ifd = ifd->getNextIfd(); + } +} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index 661fde9..6686f27 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -118,7 +118,7 @@ void Downmix_testIndexComputation(uint32_t mask) { hasBacks = true; } - const int numChan = popcount(mask); + const int numChan = audio_channel_count_from_out_mask(mask); const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER); const bool hasLFE = ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY); @@ -629,7 +629,8 @@ int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bo ALOGE("Downmix_Configure error: input channel mask can't be 0"); return -EINVAL; } - pDownmixer->input_channel_count = popcount(pConfig->inputCfg.channels); + pDownmixer->input_channel_count = + audio_channel_count_from_out_mask(pConfig->inputCfg.channels); } Downmix_Reset(pDownmixer, init); @@ -997,7 +998,7 @@ bool Downmix_foldGeneric( hasBacks = true; } - const int numChan = popcount(mask); + const int numChan = audio_channel_count_from_out_mask(mask); const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER); const bool hasLFE = ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY); diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp index a96a703..cf98f56 100644 --- a/media/libeffects/preprocessing/PreProcessing.cpp +++ b/media/libeffects/preprocessing/PreProcessing.cpp @@ -879,8 +879,8 @@ int Session_ReleaseEffect(preproc_session_t *session, int Session_SetConfig(preproc_session_t *session, effect_config_t *config) { uint32_t sr; - uint32_t inCnl = popcount(config->inputCfg.channels); - uint32_t outCnl = popcount(config->outputCfg.channels); + uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels); + uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels); if (config->inputCfg.samplingRate != config->outputCfg.samplingRate || config->inputCfg.format != config->outputCfg.format || @@ -1035,7 +1035,7 @@ int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) { return -EINVAL; } - uint32_t inCnl = popcount(config->inputCfg.channels); + uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels); int status = session->apm->set_num_reverse_channels(inCnl); if (status < 0) { return -EINVAL; diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 47cab62..e5089da 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -207,7 +207,8 @@ int Visualizer_init(VisualizerContext *pContext) pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED; // measurement initialization - pContext->mChannelCount = popcount(pContext->mConfig.inputCfg.channels); + pContext->mChannelCount = + audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels); pContext->mMeasurementMode = MEASUREMENT_MODE_NONE; pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS; pContext->mMeasurementBufferIdx = 0; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 97ab8f8..1c808d0 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -51,7 +51,8 @@ status_t AudioRecord::getMinFrameCount( // We double the size of input buffer for ping pong use of record buffer. // Assumes audio_is_linear_pcm(format) - if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) { + if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) * + audio_bytes_per_sample(format))) == 0) { ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x", sampleRate, format, channelMask); return BAD_VALUE; @@ -193,7 +194,7 @@ status_t AudioRecord::set( return BAD_VALUE; } mChannelMask = channelMask; - uint32_t channelCount = popcount(channelMask); + uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); mChannelCount = channelCount; if (audio_is_linear_pcm(format)) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index aaaa3f1..7d3ecc5 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -19,6 +19,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "AudioTrack" +#include <math.h> #include <sys/resource.h> #include <audio_utils/primitives.h> #include <binder/IPCThreadState.h> @@ -290,7 +291,7 @@ status_t AudioTrack::set( return BAD_VALUE; } mChannelMask = channelMask; - uint32_t channelCount = popcount(channelMask); + uint32_t channelCount = audio_channel_count_from_out_mask(channelMask); mChannelCount = channelCount; // AudioFlinger does not currently support 8-bit data in shared memory @@ -566,7 +567,9 @@ void AudioTrack::pause() status_t AudioTrack::setVolume(float left, float right) { - if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) { + // This duplicates a test by AudioTrack JNI, but that is not the only caller + if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY || + isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) { return BAD_VALUE; } @@ -574,7 +577,7 @@ status_t AudioTrack::setVolume(float left, float right) mVolume[AUDIO_INTERLEAVE_LEFT] = left; mVolume[AUDIO_INTERLEAVE_RIGHT] = right; - mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); + mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right))); if (isOffloaded_l()) { mAudioTrack->signal(); @@ -589,7 +592,8 @@ status_t AudioTrack::setVolume(float volume) status_t AudioTrack::setAuxEffectSendLevel(float level) { - if (level < 0.0f || level > 1.0f) { + // This duplicates a test by AudioTrack JNI, but that is not the only caller + if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) { return BAD_VALUE; } @@ -1137,8 +1141,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); mProxy = mStaticProxy; } - mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) | - uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000)); + mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setEpoch(epoch); diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 323b675..27a3718 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -27,7 +27,7 @@ namespace android { audio_track_cblk_t::audio_track_cblk_t() : mServer(0), mFutex(0), mMinimum(0), - mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0) + mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0) { memset(&u, 0, sizeof(u)); } diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp index af8f365..6aab48a 100644 --- a/media/libnbaio/AudioStreamInSource.cpp +++ b/media/libnbaio/AudioStreamInSource.cpp @@ -46,7 +46,8 @@ ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOf uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat); + mFormat = Format_from_SR_C(sampleRate, + audio_channel_count_from_in_mask(channelMask), streamFormat); mFrameSize = Format_frameSize(mFormat); } return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers); diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp index c28d34d..0d5f935 100644 --- a/media/libnbaio/AudioStreamOutSink.cpp +++ b/media/libnbaio/AudioStreamOutSink.cpp @@ -43,7 +43,8 @@ ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOff uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common); audio_channel_mask_t channelMask = (audio_channel_mask_t) mStream->common.get_channels(&mStream->common); - mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat); + mFormat = Format_from_SR_C(sampleRate, + audio_channel_count_from_out_mask(channelMask), streamFormat); mFrameSize = Format_frameSize(mFormat); } return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 2e8e412..8f154be 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -990,6 +990,8 @@ status_t ACodec::setComponentRole( "audio_decoder.g711alaw", "audio_encoder.g711alaw" }, { MEDIA_MIMETYPE_VIDEO_AVC, "video_decoder.avc", "video_encoder.avc" }, + { MEDIA_MIMETYPE_VIDEO_HEVC, + "video_decoder.hevc", "video_encoder.hevc" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "video_decoder.mpeg4", "video_encoder.mpeg4" }, { MEDIA_MIMETYPE_VIDEO_H263, @@ -1811,6 +1813,7 @@ static const struct VideoCodingMapEntry { OMX_VIDEO_CODINGTYPE mVideoCodingType; } kVideoCodingMapEntry[] = { { MEDIA_MIMETYPE_VIDEO_AVC, OMX_VIDEO_CodingAVC }, + { MEDIA_MIMETYPE_VIDEO_HEVC, OMX_VIDEO_CodingHEVC }, { MEDIA_MIMETYPE_VIDEO_MPEG4, OMX_VIDEO_CodingMPEG4 }, { MEDIA_MIMETYPE_VIDEO_H263, OMX_VIDEO_CodingH263 }, { MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 }, diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index c670bb4..8229e55 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -23,6 +23,7 @@ const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg"; const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"; const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"; const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; +const char *MEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc"; const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp"; const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2"; diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp index af5be70..4504c2b 100644 --- a/media/libstagefright/foundation/ANetworkSession.cpp +++ b/media/libstagefright/foundation/ANetworkSession.cpp @@ -623,7 +623,7 @@ status_t ANetworkSession::Session::writeMore() { CHECK_EQ(mState, CONNECTED); CHECK(!mOutFragments.empty()); - ssize_t n; + ssize_t n = -1; while (!mOutFragments.empty()) { const Fragment &frag = *mOutFragments.begin(); diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index d3e546a..5bc3f2f 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -35,7 +35,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/services/medialog \ frameworks/av/services/audioflinger \ frameworks/av/services/audiopolicy \ - frameworks/av/services/camera/libcameraservice + frameworks/av/services/camera/libcameraservice \ + $(call include-path-for, audio-utils) LOCAL_MODULE:= mediaserver LOCAL_32_BIT_ONLY := true diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 11170c2..45e17f8 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1837,7 +1837,8 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, if (status == BAD_VALUE && reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT && (config.sample_rate <= 2 * reqSamplingRate) && - (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannelMask) <= FCC_2)) { + (audio_channel_count_from_in_mask(config.channel_mask) <= FCC_2) && + (audio_channel_count_from_in_mask(reqChannelMask) <= FCC_2)) { // FIXME describe the change proposed by HAL (save old values so we can log them here) ALOGV("openInput() reopening with proposed sampling rate and channel mask"); inStream = NULL; @@ -1857,7 +1858,8 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, TEE_SINK_OLD, // copy input using an existing pipe } kind; NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common), - popcount(inStream->common.get_channels(&inStream->common))); + audio_channel_count_from_in_mask( + inStream->common.get_channels(&inStream->common))); if (!mTeeSinkInputEnabled) { kind = TEE_SINK_NO; } else if (!Format_isValid(format)) { diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index d69d6a2..d2ded9a 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -82,9 +82,6 @@ class ServerProxy; static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3); -#define MAX_GAIN 4096.0f -#define MAX_GAIN_INT 0x1000 - #define INCLUDING_FROM_AUDIOFLINGER_H class AudioFlinger : diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 2d67efb..805eaa4 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -159,7 +159,6 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId) if (names != 0) { int n = __builtin_ctz(names); ALOGV("add track (%d)", n); - mTrackNames |= 1 << n; // assume default parameters for the track, except where noted below track_t* t = &mState.tracks[n]; t->needs = 0; @@ -175,10 +174,10 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId) // no initialization needed // t->prevAuxLevel // t->frameCount - t->channelCount = 2; + t->channelCount = audio_channel_count_from_out_mask(channelMask); t->enabled = false; t->format = 16; - t->channelMask = AUDIO_CHANNEL_OUT_STEREO; + t->channelMask = channelMask; t->sessionId = sessionId; // setBufferProvider(name, AudioBufferProvider *) is required before enable(name) t->bufferProvider = NULL; @@ -196,12 +195,14 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId) t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT; status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask); - if (status == OK) { - return TRACK0 + n; + if (status != OK) { + ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask); + return -1; } - ALOGE("AudioMixer::getTrackName(0x%x) failed, error preparing track for downmix", - channelMask); + mTrackNames |= 1 << n; + return TRACK0 + n; } + ALOGE("AudioMixer::getTrackName out of available tracks"); return -1; } @@ -215,7 +216,7 @@ void AudioMixer::invalidateState(uint32_t mask) status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask) { - uint32_t channelCount = popcount(mask); + uint32_t channelCount = audio_channel_count_from_out_mask(mask); ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount); status_t status = OK; if (channelCount > MAX_NUM_CHANNELS) { @@ -410,7 +411,7 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) audio_channel_mask_t mask = static_cast<audio_channel_mask_t>(reinterpret_cast<uintptr_t>(value)); if (track.channelMask != mask) { - uint32_t channelCount = popcount(mask); + uint32_t channelCount = audio_channel_count_from_out_mask(mask); ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount); track.channelMask = mask; track.channelCount = channelCount; diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index e5e120c..09e63a6 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -30,6 +30,9 @@ #include <system/audio.h> #include <media/nbaio/NBLog.h> +// FIXME This is actually unity gain, which might not be max in future, expressed in U.12 +#define MAX_GAIN_INT AudioMixer::UNITY_GAIN + namespace android { // ---------------------------------------------------------------------------- @@ -91,6 +94,7 @@ public: REMOVE = 0x4102, // Remove the sample rate converter on this track name; // the track is restored to the mix sample rate. // for target RAMP_VOLUME and VOLUME (8 channels max) + // FIXME use float for these 3 to improve the dynamic range VOLUME0 = 0x4200, VOLUME1 = 0x4201, AUXLEVEL = 0x4210, diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h index ccc4825..4170fd4 100644 --- a/services/audioflinger/Effects.h +++ b/services/audioflinger/Effects.h @@ -270,6 +270,7 @@ public: sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type); + // FIXME use float to improve the dynamic range bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(audio_devices_t device); void setMode_l(audio_mode_t mode); diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 5cb42cc..1caed11 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -224,17 +224,13 @@ void FastMixer::onStateChange() AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1); if (mixer != NULL) { - // calling getTrackName with default channel mask and a random invalid - // sessionId (no effects here) - name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO, -555); + name = mixer->getTrackName(fastTrack->mChannelMask, AUDIO_SESSION_OUTPUT_MIX); ALOG_ASSERT(name >= 0); fastTrackNames[i] = name; mixer->setBufferProvider(name, bufferProvider); mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, (void *) mixBuffer); // newly allocated track names default to full scale volume - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, - (void *)(uintptr_t)fastTrack->mChannelMask); mixer->enable(name); } generations[i] = fastTrack->mGeneration; @@ -257,9 +253,9 @@ void FastMixer::onStateChange() mixer->setBufferProvider(name, bufferProvider); if (fastTrack->mVolumeProvider == NULL) { mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, - (void *)0x1000); + (void *) MAX_GAIN_INT); mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, - (void *)0x1000); + (void *) MAX_GAIN_INT); } mixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::REMOVE, NULL); @@ -312,11 +308,13 @@ void FastMixer::onWork() int name = fastTrackNames[i]; ALOG_ASSERT(name >= 0); if (fastTrack->mVolumeProvider != NULL) { - uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); + gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, - (void *)(uintptr_t)(vlr & 0xFFFF)); + (void *) (uintptr_t) + (float_from_gain(gain_minifloat_unpack_left(vlr)) * MAX_GAIN_INT)); mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, - (void *)(uintptr_t)(vlr >> 16)); + (void *) (uintptr_t) + (float_from_gain(gain_minifloat_unpack_right(vlr)) * MAX_GAIN_INT)); } // FIXME The current implementation of framesReady() for fast tracks // takes a tryLock, which can block diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h index be1a376..e388fb3 100644 --- a/services/audioflinger/FastMixerState.h +++ b/services/audioflinger/FastMixerState.h @@ -17,6 +17,7 @@ #ifndef ANDROID_AUDIO_FAST_MIXER_STATE_H #define ANDROID_AUDIO_FAST_MIXER_STATE_H +#include <audio_utils/minifloat.h> #include <system/audio.h> #include <media/ExtendedAudioBufferProvider.h> #include <media/nbaio/NBAIO.h> @@ -29,9 +30,8 @@ struct FastMixerDumpState; class VolumeProvider { public: - // Return the track volume in U4_12 format: left in lower half, right in upper half. The - // provider implementation is responsible for validating that the return value is in range. - virtual uint32_t getVolumeLR() = 0; + // The provider implementation is responsible for validating that the return value is in range. + virtual gain_minifloat_packed_t getVolumeLR() = 0; protected: VolumeProvider() { } virtual ~VolumeProvider() { } diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 08b1728..6f1f293 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -65,7 +65,7 @@ public: void signal(); // implement FastMixerState::VolumeProvider interface - virtual uint32_t getVolumeLR(); + virtual gain_minifloat_packed_t getVolumeLR(); virtual status_t setSyncEvent(const sp<SyncEvent>& event); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 2d4e025..ce08ff1 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -35,6 +35,7 @@ #include <audio_effects/effect_aec.h> #include <audio_utils/primitives.h> #include <audio_utils/format.h> +#include <audio_utils/minifloat.h> // NBAIO implementations #include <media/nbaio/AudioStreamOutSink.h> @@ -1730,7 +1731,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() LOG_ALWAYS_FATAL("HAL channel mask %#x not supported for mixed output; " "must be AUDIO_CHANNEL_OUT_STEREO", mChannelMask); } - mChannelCount = popcount(mChannelMask); + mChannelCount = audio_channel_count_from_out_mask(mChannelMask); mFormat = mOutput->stream->common.get_format(&mOutput->stream->common); if (!audio_is_valid_format(mFormat)) { LOG_ALWAYS_FATAL("HAL format %#x not valid for output", mFormat); @@ -3255,21 +3256,23 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy; - uint32_t vlr = proxy->getVolumeLR(); - vl = vlr & 0xFFFF; - vr = vlr >> 16; + gain_minifloat_packed_t vlr = proxy->getVolumeLR(); + float vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); + float vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); // track volumes come from shared memory, so can't be trusted and must be clamped - if (vl > MAX_GAIN_INT) { - ALOGV("Track left volume out of range: %04X", vl); - vl = MAX_GAIN_INT; + if (vlf > GAIN_FLOAT_UNITY) { + ALOGV("Track left volume out of range: %.3g", vlf); + vlf = GAIN_FLOAT_UNITY; } - if (vr > MAX_GAIN_INT) { - ALOGV("Track right volume out of range: %04X", vr); - vr = MAX_GAIN_INT; + if (vrf > GAIN_FLOAT_UNITY) { + ALOGV("Track right volume out of range: %.3g", vrf); + vrf = GAIN_FLOAT_UNITY; } // now apply the master volume and stream type volume - vl = (uint32_t)(v * vl) << 12; - vr = (uint32_t)(v * vr) << 12; + // FIXME we're losing the wonderful dynamic range in the minifloat representation + float v8_24 = v * (MAX_GAIN_INT * MAX_GAIN_INT); + vl = (uint32_t) (v8_24 * vlf); + vr = (uint32_t) (v8_24 * vrf); // assuming master volume and stream type volume each go up to 1.0, // vl and vr are now in 8.24 format @@ -3296,6 +3299,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac track->mHasVolumeController = false; } + // FIXME Use float // Convert volumes from 8.24 to 4.12 format // This additional clamping is needed in case chain->setVolume_l() overshot vl = (vl + (1 << 11)) >> 12; @@ -3750,13 +3754,17 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr float typeVolume = mStreamTypes[track->streamType()].volume; float v = mMasterVolume * typeVolume; AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy; - uint32_t vlr = proxy->getVolumeLR(); - float v_clamped = v * (vlr & 0xFFFF); - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - left = v_clamped/MAX_GAIN; - v_clamped = v * (vlr >> 16); - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - right = v_clamped/MAX_GAIN; + gain_minifloat_packed_t vlr = proxy->getVolumeLR(); + left = float_from_gain(gain_minifloat_unpack_left(vlr)); + if (left > GAIN_FLOAT_UNITY) { + left = GAIN_FLOAT_UNITY; + } + left *= v; + right = float_from_gain(gain_minifloat_unpack_right(vlr)); + if (right > GAIN_FLOAT_UNITY) { + right = GAIN_FLOAT_UNITY; + } + right *= v; } if (lastTrack) { @@ -4152,7 +4160,10 @@ void AudioFlinger::OffloadThread::threadLoop_exit() mMixerStatus = MIXER_DRAIN_ALL; threadLoop_drain(); } - mCallbackThread->exit(); + if (mUseAsyncWrite) { + ALOG_ASSERT(mCallbackThread != 0); + mCallbackThread->exit(); + } PlaybackThread::threadLoop_exit(); } @@ -5564,8 +5575,8 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP reqFormat == AUDIO_FORMAT_PCM_16_BIT && (mInput->stream->common.get_sample_rate(&mInput->stream->common) <= (2 * samplingRate)) && - popcount(mInput->stream->common.get_channels(&mInput->stream->common)) - <= FCC_2 && + audio_channel_count_from_in_mask( + mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 && (channelMask == AUDIO_CHANNEL_IN_MONO || channelMask == AUDIO_CHANNEL_IN_STEREO)) { status = NO_ERROR; @@ -5619,7 +5630,7 @@ void AudioFlinger::RecordThread::readInputParameters_l() { mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common); mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common); - mChannelCount = popcount(mChannelMask); + mChannelCount = audio_channel_count_from_in_mask(mChannelMask); mFormat = mInput->stream->common.get_format(&mInput->stream->common); if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat); diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 6dc7f30..de1782d 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -34,6 +34,7 @@ #include <media/nbaio/Pipe.h> #include <media/nbaio/PipeReader.h> +#include <audio_utils/minifloat.h> // ---------------------------------------------------------------------------- @@ -81,7 +82,9 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( mSampleRate(sampleRate), mFormat(format), mChannelMask(channelMask), - mChannelCount(popcount(channelMask)), + mChannelCount(isOut ? + audio_channel_count_from_out_mask(channelMask) : + audio_channel_count_from_in_mask(channelMask)), mFrameSize(audio_is_linear_pcm(format) ? mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)), mFrameCount(frameCount), @@ -459,7 +462,7 @@ void AudioFlinger::PlaybackThread::Track::destroy() void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active) { - uint32_t vlr = mAudioTrackServerProxy->getVolumeLR(); + gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR(); if (isFastTrack()) { sprintf(buffer, " F %2d", mFastIndex); } else if (mName >= AudioMixer::TRACK0) { @@ -532,8 +535,8 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool a stateChar, mFillingUpStatus, mAudioTrackServerProxy->getSampleRate(), - 20.0 * log10((vlr & 0xFFFF) / 4096.0), - 20.0 * log10((vlr >> 16) / 4096.0), + 20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))), + 20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))), mCblk->mServer, mMainBuffer, mAuxBuffer, @@ -959,27 +962,27 @@ void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_ // implement VolumeBufferProvider interface -uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR() +gain_minifloat_packed_t AudioFlinger::PlaybackThread::Track::getVolumeLR() { // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs ALOG_ASSERT(isFastTrack() && (mCblk != NULL)); - uint32_t vlr = mAudioTrackServerProxy->getVolumeLR(); - uint32_t vl = vlr & 0xFFFF; - uint32_t vr = vlr >> 16; + gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR(); + float vl = float_from_gain(gain_minifloat_unpack_left(vlr)); + float vr = float_from_gain(gain_minifloat_unpack_right(vlr)); // track volumes come from shared memory, so can't be trusted and must be clamped - if (vl > MAX_GAIN_INT) { - vl = MAX_GAIN_INT; + if (vl > GAIN_FLOAT_UNITY) { + vl = GAIN_FLOAT_UNITY; } - if (vr > MAX_GAIN_INT) { - vr = MAX_GAIN_INT; + if (vr > GAIN_FLOAT_UNITY) { + vr = GAIN_FLOAT_UNITY; } // now apply the cached master volume and stream type volume; // this is trusted but lacks any synchronization or barrier so may be stale float v = mCachedVolume; vl *= v; vr *= v; - // re-combine into U4.16 - vlr = (vr << 16) | (vl & 0xFFFF); + // re-combine into packed minifloat + vlr = gain_minifloat_pack(gain_from_float(vl), gain_from_float(vr)); // FIXME look at mute, pause, and stop flags return vlr; } @@ -1590,7 +1593,7 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( // since client and server are in the same process, // the buffer has the same virtual address on both sides mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize); - mClientProxy->setVolumeLR((uint32_t(uint16_t(0x1000)) << 16) | uint16_t(0x1000)); + mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); mClientProxy->setSendLevel(0.0); mClientProxy->setSampleRate(sampleRate); mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize, @@ -1849,7 +1852,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize); - uint32_t channelCount = popcount(channelMask); + uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); // FIXME I don't understand either of the channel count checks if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 && channelCount <= FCC_2) { |