Loading media/extractors/mp4/ItemTable.cpp +25 −2 Original line number Diff line number Diff line Loading @@ -1687,8 +1687,31 @@ status_t ItemTable::getExifOffsetAndSize(off64_t *offset, size_t *size) { } // skip the first 4-byte of the offset to TIFF header *offset = mItemIdToExifMap[exifIndex].offset + 4; *size = mItemIdToExifMap[exifIndex].size - 4; uint32_t tiffOffset; if (!mDataSource->readAt( mItemIdToExifMap[exifIndex].offset, &tiffOffset, 4)) { return ERROR_IO; } // We need 'Exif\0\0' before the tiff header tiffOffset = ntohl(tiffOffset); if (tiffOffset < 6) { return ERROR_MALFORMED; } // The first 4-byte of the item is the offset of the tiff header within the // exif data. The size of the item should be > 4 for a non-empty exif (this // was already checked when the item was added). Also check that the tiff // header offset is valid. if (mItemIdToExifMap[exifIndex].size <= 4 || tiffOffset > mItemIdToExifMap[exifIndex].size - 4) { return ERROR_MALFORMED; } // Offset of 'Exif\0\0' relative to the beginning of 'Exif' item // (first 4-byte is the tiff header offset) uint32_t exifOffset = 4 + tiffOffset - 6; *offset = mItemIdToExifMap[exifIndex].offset + exifOffset; *size = mItemIdToExifMap[exifIndex].size - exifOffset; return OK; } Loading media/libstagefright/MPEG4Writer.cpp +58 −21 Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_la static const int kTimestampDebugCount = 10; static const int kItemIdBase = 10000; static const char kExifHeader[] = {'E', 'x', 'i', 'f', '\0', '\0'}; static const int32_t kTiffHeaderOffset = htonl(sizeof(kExifHeader)); static const uint8_t kExifApp1Marker[] = {'E', 'x', 'i', 'f', 0xff, 0xe1}; static const uint8_t kMandatoryHevcNalUnitTypes[3] = { kHevcNalUnitTypeVps, Loading Loading @@ -125,7 +125,7 @@ public: bool isAudio() const { return mIsAudio; } bool isMPEG4() const { return mIsMPEG4; } bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; } bool isExifData(const MediaBufferBase *buffer) const; bool isExifData(MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const; void addChunkOffset(off64_t offset); void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif); void flushItemRefs(); Loading Loading @@ -364,7 +364,7 @@ private: Vector<uint16_t> mProperties; ItemRefs mDimgRefs; ItemRefs mCdscRefs; Vector<uint16_t> mExifList; uint16_t mImageItemId; int32_t mIsPrimary; int32_t mWidth, mHeight; Loading Loading @@ -1368,14 +1368,16 @@ void MPEG4Writer::unlock() { } off64_t MPEG4Writer::addSample_l( MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten) { MediaBuffer *buffer, bool usePrefix, uint32_t tiffHdrOffset, size_t *bytesWritten) { off64_t old_offset = mOffset; if (usePrefix) { addMultipleLengthPrefixedSamples_l(buffer); } else { if (isExif) { ::write(mFd, &kTiffHeaderOffset, 4); // exif_tiff_header_offset field if (tiffHdrOffset > 0) { tiffHdrOffset = htonl(tiffHdrOffset); ::write(mFd, &tiffHdrOffset, 4); // exif_tiff_header_offset field mOffset += 4; } Loading Loading @@ -1803,7 +1805,6 @@ MPEG4Writer::Track::Track( mStartTimestampUs(-1), mRotation(0), mDimgRefs("dimg"), mCdscRefs("cdsc"), mImageItemId(0), mIsPrimary(0), mWidth(0), Loading Loading @@ -1984,11 +1985,34 @@ status_t MPEG4Writer::setNextFd(int fd) { return OK; } bool MPEG4Writer::Track::isExifData(const MediaBufferBase *buffer) const { return mIsHeic && (buffer->range_length() > sizeof(kExifHeader)) && !memcmp((uint8_t *)buffer->data() + buffer->range_offset(), kExifHeader, sizeof(kExifHeader)); bool MPEG4Writer::Track::isExifData( MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const { if (!mIsHeic) { return false; } // Exif block starting with 'Exif\0\0' size_t length = buffer->range_length(); uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset(); if ((length > sizeof(kExifHeader)) && !memcmp(data, kExifHeader, sizeof(kExifHeader))) { *tiffHdrOffset = sizeof(kExifHeader); return true; } // Exif block starting with fourcc 'Exif' followed by APP1 marker if ((length > sizeof(kExifApp1Marker) + 2 + sizeof(kExifHeader)) && !memcmp(data, kExifApp1Marker, sizeof(kExifApp1Marker)) && !memcmp(data + sizeof(kExifApp1Marker) + 2, kExifHeader, sizeof(kExifHeader))) { // skip 'Exif' fourcc buffer->set_range(4, buffer->range_length() - 4); // 2-byte APP1 + 2-byte size followed by kExifHeader *tiffHdrOffset = 2 + 2 + sizeof(kExifHeader); return true; } return false; } void MPEG4Writer::Track::addChunkOffset(off64_t offset) { Loading @@ -2014,7 +2038,7 @@ void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size, bool } if (isExif) { mCdscRefs.value.push_back(mOwner->addItem_l({ mExifList.push_back(mOwner->addItem_l({ .itemType = "Exif", .isPrimary = false, .isHidden = false, Loading Loading @@ -2117,7 +2141,16 @@ void MPEG4Writer::Track::flushItemRefs() { if (mImageItemId > 0) { mOwner->addRefs_l(mImageItemId, mDimgRefs); mOwner->addRefs_l(mImageItemId, mCdscRefs); if (!mExifList.empty()) { // The "cdsc" ref is from the metadata/exif item to the image item. // So the refs all contain the image item. ItemRefs cdscRefs("cdsc"); cdscRefs.value.push_back(mImageItemId); for (uint16_t exifItem : mExifList) { mOwner->addRefs_l(exifItem, cdscRefs); } } } } Loading Loading @@ -2269,14 +2302,16 @@ void MPEG4Writer::writeChunkToFile(Chunk* chunk) { while (!chunk->mSamples.empty()) { List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); int32_t isExif; if (!(*it)->meta_data().findInt32(kKeyIsExif, &isExif)) { isExif = 0; uint32_t tiffHdrOffset; if (!(*it)->meta_data().findInt32( kKeyExifTiffOffset, (int32_t*)&tiffHdrOffset)) { tiffHdrOffset = 0; } bool isExif = (tiffHdrOffset > 0); bool usePrefix = chunk->mTrack->usePrefix() && !isExif; size_t bytesWritten; off64_t offset = addSample_l(*it, usePrefix, isExif, &bytesWritten); off64_t offset = addSample_l(*it, usePrefix, tiffHdrOffset, &bytesWritten); if (chunk->mTrack->isHeic()) { chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten, isExif); Loading Loading @@ -3002,10 +3037,11 @@ status_t MPEG4Writer::Track::threadEntry() { } bool isExif = false; uint32_t tiffHdrOffset = 0; int32_t isMuxerData; if (buffer->meta_data().findInt32(kKeyIsMuxerData, &isMuxerData) && isMuxerData) { // We only support one type of muxer data, which is Exif data block. isExif = isExifData(buffer); isExif = isExifData(buffer, &tiffHdrOffset); if (!isExif) { ALOGW("Ignoring bad Exif data block"); buffer->release(); Loading @@ -3027,7 +3063,7 @@ status_t MPEG4Writer::Track::threadEntry() { buffer = NULL; if (isExif) { copy->meta_data().setInt32(kKeyIsExif, 1); copy->meta_data().setInt32(kKeyExifTiffOffset, tiffHdrOffset); } bool usePrefix = this->usePrefix() && !isExif; Loading Loading @@ -3300,7 +3336,8 @@ status_t MPEG4Writer::Track::threadEntry() { } if (!hasMultipleTracks) { size_t bytesWritten; off64_t offset = mOwner->addSample_l(copy, usePrefix, isExif, &bytesWritten); off64_t offset = mOwner->addSample_l( copy, usePrefix, tiffHdrOffset, &bytesWritten); if (mIsHeic) { addItemOffsetAndSize(offset, bytesWritten, isExif); Loading media/libstagefright/include/media/stagefright/MPEG4Writer.h +3 −1 Original line number Diff line number Diff line Loading @@ -257,7 +257,9 @@ private: void initInternal(int fd, bool isFirstSession); // Acquire lock before calling these methods off64_t addSample_l(MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten); off64_t addSample_l( MediaBuffer *buffer, bool usePrefix, uint32_t tiffHdrOffset, size_t *bytesWritten); void addLengthPrefixedSample_l(MediaBuffer *buffer); void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); uint16_t addProperty_l(const ItemProperty &); Loading media/libstagefright/include/media/stagefright/MetaDataBase.h +2 −1 Original line number Diff line number Diff line Loading @@ -221,7 +221,8 @@ enum { kKeyFrameCount = 'nfrm', // int32_t, total number of frame in video track kKeyExifOffset = 'exof', // int64_t, Exif data offset kKeyExifSize = 'exsz', // int64_t, Exif data size kKeyIsExif = 'exif', // bool (int32_t) buffer contains exif data block kKeyExifTiffOffset = 'thdr', // int32_t, if > 0, buffer contains exif data block with // tiff hdr at specified offset kKeyPcmBigEndian = 'pcmb', // bool (int32_t) // Key for ALAC Magic Cookie Loading Loading
media/extractors/mp4/ItemTable.cpp +25 −2 Original line number Diff line number Diff line Loading @@ -1687,8 +1687,31 @@ status_t ItemTable::getExifOffsetAndSize(off64_t *offset, size_t *size) { } // skip the first 4-byte of the offset to TIFF header *offset = mItemIdToExifMap[exifIndex].offset + 4; *size = mItemIdToExifMap[exifIndex].size - 4; uint32_t tiffOffset; if (!mDataSource->readAt( mItemIdToExifMap[exifIndex].offset, &tiffOffset, 4)) { return ERROR_IO; } // We need 'Exif\0\0' before the tiff header tiffOffset = ntohl(tiffOffset); if (tiffOffset < 6) { return ERROR_MALFORMED; } // The first 4-byte of the item is the offset of the tiff header within the // exif data. The size of the item should be > 4 for a non-empty exif (this // was already checked when the item was added). Also check that the tiff // header offset is valid. if (mItemIdToExifMap[exifIndex].size <= 4 || tiffOffset > mItemIdToExifMap[exifIndex].size - 4) { return ERROR_MALFORMED; } // Offset of 'Exif\0\0' relative to the beginning of 'Exif' item // (first 4-byte is the tiff header offset) uint32_t exifOffset = 4 + tiffOffset - 6; *offset = mItemIdToExifMap[exifIndex].offset + exifOffset; *size = mItemIdToExifMap[exifIndex].size - exifOffset; return OK; } Loading
media/libstagefright/MPEG4Writer.cpp +58 −21 Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_la static const int kTimestampDebugCount = 10; static const int kItemIdBase = 10000; static const char kExifHeader[] = {'E', 'x', 'i', 'f', '\0', '\0'}; static const int32_t kTiffHeaderOffset = htonl(sizeof(kExifHeader)); static const uint8_t kExifApp1Marker[] = {'E', 'x', 'i', 'f', 0xff, 0xe1}; static const uint8_t kMandatoryHevcNalUnitTypes[3] = { kHevcNalUnitTypeVps, Loading Loading @@ -125,7 +125,7 @@ public: bool isAudio() const { return mIsAudio; } bool isMPEG4() const { return mIsMPEG4; } bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; } bool isExifData(const MediaBufferBase *buffer) const; bool isExifData(MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const; void addChunkOffset(off64_t offset); void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif); void flushItemRefs(); Loading Loading @@ -364,7 +364,7 @@ private: Vector<uint16_t> mProperties; ItemRefs mDimgRefs; ItemRefs mCdscRefs; Vector<uint16_t> mExifList; uint16_t mImageItemId; int32_t mIsPrimary; int32_t mWidth, mHeight; Loading Loading @@ -1368,14 +1368,16 @@ void MPEG4Writer::unlock() { } off64_t MPEG4Writer::addSample_l( MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten) { MediaBuffer *buffer, bool usePrefix, uint32_t tiffHdrOffset, size_t *bytesWritten) { off64_t old_offset = mOffset; if (usePrefix) { addMultipleLengthPrefixedSamples_l(buffer); } else { if (isExif) { ::write(mFd, &kTiffHeaderOffset, 4); // exif_tiff_header_offset field if (tiffHdrOffset > 0) { tiffHdrOffset = htonl(tiffHdrOffset); ::write(mFd, &tiffHdrOffset, 4); // exif_tiff_header_offset field mOffset += 4; } Loading Loading @@ -1803,7 +1805,6 @@ MPEG4Writer::Track::Track( mStartTimestampUs(-1), mRotation(0), mDimgRefs("dimg"), mCdscRefs("cdsc"), mImageItemId(0), mIsPrimary(0), mWidth(0), Loading Loading @@ -1984,11 +1985,34 @@ status_t MPEG4Writer::setNextFd(int fd) { return OK; } bool MPEG4Writer::Track::isExifData(const MediaBufferBase *buffer) const { return mIsHeic && (buffer->range_length() > sizeof(kExifHeader)) && !memcmp((uint8_t *)buffer->data() + buffer->range_offset(), kExifHeader, sizeof(kExifHeader)); bool MPEG4Writer::Track::isExifData( MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const { if (!mIsHeic) { return false; } // Exif block starting with 'Exif\0\0' size_t length = buffer->range_length(); uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset(); if ((length > sizeof(kExifHeader)) && !memcmp(data, kExifHeader, sizeof(kExifHeader))) { *tiffHdrOffset = sizeof(kExifHeader); return true; } // Exif block starting with fourcc 'Exif' followed by APP1 marker if ((length > sizeof(kExifApp1Marker) + 2 + sizeof(kExifHeader)) && !memcmp(data, kExifApp1Marker, sizeof(kExifApp1Marker)) && !memcmp(data + sizeof(kExifApp1Marker) + 2, kExifHeader, sizeof(kExifHeader))) { // skip 'Exif' fourcc buffer->set_range(4, buffer->range_length() - 4); // 2-byte APP1 + 2-byte size followed by kExifHeader *tiffHdrOffset = 2 + 2 + sizeof(kExifHeader); return true; } return false; } void MPEG4Writer::Track::addChunkOffset(off64_t offset) { Loading @@ -2014,7 +2038,7 @@ void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size, bool } if (isExif) { mCdscRefs.value.push_back(mOwner->addItem_l({ mExifList.push_back(mOwner->addItem_l({ .itemType = "Exif", .isPrimary = false, .isHidden = false, Loading Loading @@ -2117,7 +2141,16 @@ void MPEG4Writer::Track::flushItemRefs() { if (mImageItemId > 0) { mOwner->addRefs_l(mImageItemId, mDimgRefs); mOwner->addRefs_l(mImageItemId, mCdscRefs); if (!mExifList.empty()) { // The "cdsc" ref is from the metadata/exif item to the image item. // So the refs all contain the image item. ItemRefs cdscRefs("cdsc"); cdscRefs.value.push_back(mImageItemId); for (uint16_t exifItem : mExifList) { mOwner->addRefs_l(exifItem, cdscRefs); } } } } Loading Loading @@ -2269,14 +2302,16 @@ void MPEG4Writer::writeChunkToFile(Chunk* chunk) { while (!chunk->mSamples.empty()) { List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); int32_t isExif; if (!(*it)->meta_data().findInt32(kKeyIsExif, &isExif)) { isExif = 0; uint32_t tiffHdrOffset; if (!(*it)->meta_data().findInt32( kKeyExifTiffOffset, (int32_t*)&tiffHdrOffset)) { tiffHdrOffset = 0; } bool isExif = (tiffHdrOffset > 0); bool usePrefix = chunk->mTrack->usePrefix() && !isExif; size_t bytesWritten; off64_t offset = addSample_l(*it, usePrefix, isExif, &bytesWritten); off64_t offset = addSample_l(*it, usePrefix, tiffHdrOffset, &bytesWritten); if (chunk->mTrack->isHeic()) { chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten, isExif); Loading Loading @@ -3002,10 +3037,11 @@ status_t MPEG4Writer::Track::threadEntry() { } bool isExif = false; uint32_t tiffHdrOffset = 0; int32_t isMuxerData; if (buffer->meta_data().findInt32(kKeyIsMuxerData, &isMuxerData) && isMuxerData) { // We only support one type of muxer data, which is Exif data block. isExif = isExifData(buffer); isExif = isExifData(buffer, &tiffHdrOffset); if (!isExif) { ALOGW("Ignoring bad Exif data block"); buffer->release(); Loading @@ -3027,7 +3063,7 @@ status_t MPEG4Writer::Track::threadEntry() { buffer = NULL; if (isExif) { copy->meta_data().setInt32(kKeyIsExif, 1); copy->meta_data().setInt32(kKeyExifTiffOffset, tiffHdrOffset); } bool usePrefix = this->usePrefix() && !isExif; Loading Loading @@ -3300,7 +3336,8 @@ status_t MPEG4Writer::Track::threadEntry() { } if (!hasMultipleTracks) { size_t bytesWritten; off64_t offset = mOwner->addSample_l(copy, usePrefix, isExif, &bytesWritten); off64_t offset = mOwner->addSample_l( copy, usePrefix, tiffHdrOffset, &bytesWritten); if (mIsHeic) { addItemOffsetAndSize(offset, bytesWritten, isExif); Loading
media/libstagefright/include/media/stagefright/MPEG4Writer.h +3 −1 Original line number Diff line number Diff line Loading @@ -257,7 +257,9 @@ private: void initInternal(int fd, bool isFirstSession); // Acquire lock before calling these methods off64_t addSample_l(MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten); off64_t addSample_l( MediaBuffer *buffer, bool usePrefix, uint32_t tiffHdrOffset, size_t *bytesWritten); void addLengthPrefixedSample_l(MediaBuffer *buffer); void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); uint16_t addProperty_l(const ItemProperty &); Loading
media/libstagefright/include/media/stagefright/MetaDataBase.h +2 −1 Original line number Diff line number Diff line Loading @@ -221,7 +221,8 @@ enum { kKeyFrameCount = 'nfrm', // int32_t, total number of frame in video track kKeyExifOffset = 'exof', // int64_t, Exif data offset kKeyExifSize = 'exsz', // int64_t, Exif data size kKeyIsExif = 'exif', // bool (int32_t) buffer contains exif data block kKeyExifTiffOffset = 'thdr', // int32_t, if > 0, buffer contains exif data block with // tiff hdr at specified offset kKeyPcmBigEndian = 'pcmb', // bool (int32_t) // Key for ALAC Magic Cookie Loading