Write Exif data block for HEIF files
Pass in Exif data block as a muxer data sample on each
image track. Add support in MPEG4Writer to write it out.
Allow grid to be used even when there is only 1 tile,
as some encoders can't encode very small images, using
grid allows them to encode in a supported size then apply
a crop to final size.
Also be more strict on esitmating the file level meta
size, since we now have to also reserve for Exif items.
bug: 79476308
Change-Id: I4b7d3af18cfb55a52f7218d9e7b6ad6f85f34343
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index b6787af..ca9deab 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -506,7 +506,7 @@
ImageItem &derivedImage = itemIdToItemMap.editValueAt(itemIndex);
if (!derivedImage.dimgRefs.empty()) {
- ALOGW("dimgRefs if not clean!");
+ ALOGW("dimgRefs not clean!");
}
derivedImage.dimgRefs.appendVector(mRefs);
@@ -1490,6 +1490,17 @@
const ImageItem *image = &mItemIdToItemMap[itemIndex];
+ ssize_t tileItemIndex = -1;
+ if (image->isGrid()) {
+ if (image->dimgRefs.empty()) {
+ return NULL;
+ }
+ tileItemIndex = mItemIdToItemMap.indexOfKey(image->dimgRefs[0]);
+ if (tileItemIndex < 0) {
+ return NULL;
+ }
+ }
+
sp<MetaData> meta = new MetaData;
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
@@ -1530,10 +1541,6 @@
}
if (image->isGrid()) {
- ssize_t tileItemIndex = mItemIdToItemMap.indexOfKey(image->dimgRefs[0]);
- if (tileItemIndex < 0) {
- return NULL;
- }
meta->setInt32(kKeyGridRows, image->rows);
meta->setInt32(kKeyGridCols, image->columns);
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index f1b7806..6ad2441 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -70,6 +70,7 @@
kKeyWantsNALFragments = 'NALf',
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
+ kKeyIsMuxerData = 'muxd', // int32_t (bool)
kKeyTime = 'time', // int64_t (usecs)
kKeyDecodingTime = 'decT', // int64_t (decoding timestamp in usecs)
kKeyNTPTime = 'ntpT', // uint64_t (ntp-timestamp)
@@ -220,6 +221,7 @@
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
};
enum {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 550a99c..6ff3d78 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -83,6 +83,9 @@
static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_layers_count";
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 kMandatoryHevcNalUnitTypes[3] = {
kHevcNalUnitTypeVps,
@@ -112,7 +115,7 @@
int64_t getDurationUs() const;
int64_t getEstimatedTrackSizeBytes() const;
- int32_t getMetaSizeIncrease() const;
+ int32_t getMetaSizeIncrease(int32_t angle, int32_t trackCount) const;
void writeTrackHeader(bool use32BitOffset = true);
int64_t getMinCttsOffsetTimeUs();
void bufferChunk(int64_t timestampUs);
@@ -122,8 +125,10 @@
bool isAudio() const { return mIsAudio; }
bool isMPEG4() const { return mIsMPEG4; }
bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; }
+ bool isExifData(const MediaBufferBase *buffer) const;
void addChunkOffset(off64_t offset);
- void addItemOffsetAndSize(off64_t offset, size_t size);
+ void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif);
+ void flushItemRefs();
int32_t getTrackId() const { return mTrackId; }
status_t dump(int fd, const Vector<String16>& args) const;
static const char *getFourCCForMime(const char *mime);
@@ -355,7 +360,9 @@
int32_t mRotation;
Vector<uint16_t> mProperties;
- Vector<uint16_t> mDimgRefs;
+ ItemRefs mDimgRefs;
+ ItemRefs mCdscRefs;
+ uint16_t mImageItemId;
int32_t mIsPrimary;
int32_t mWidth, mHeight;
int32_t mTileWidth, mTileHeight;
@@ -499,6 +506,7 @@
mPrimaryItemId = 0;
mAssociationEntryCount = 0;
mNumGrids = 0;
+ mHasRefs = false;
// Following variables only need to be set for the first recording session.
// And they will stay the same for all the recording sessions.
@@ -680,7 +688,12 @@
#endif
}
-int64_t MPEG4Writer::estimateFileLevelMetaSize() {
+int64_t MPEG4Writer::estimateFileLevelMetaSize(MetaData *params) {
+ int32_t rotation;
+ if (!params || !params->findInt32(kKeyRotation, &rotation)) {
+ rotation = 0;
+ }
+
// base meta size
int64_t metaSize = 12 // meta fullbox header
+ 33 // hdlr box
@@ -695,7 +708,7 @@
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
if ((*it)->isHeic()) {
- metaSize += (*it)->getMetaSizeIncrease();
+ metaSize += (*it)->getMetaSizeIncrease(rotation, mTracks.size());
}
}
@@ -900,7 +913,7 @@
if (mInMemoryCacheSize == 0) {
int32_t bitRate = -1;
if (mHasFileLevelMeta) {
- mInMemoryCacheSize += estimateFileLevelMetaSize();
+ mInMemoryCacheSize += estimateFileLevelMetaSize(param);
}
if (mHasMoovBox) {
if (param) {
@@ -1344,12 +1357,17 @@
}
off64_t MPEG4Writer::addSample_l(
- MediaBuffer *buffer, bool usePrefix, size_t *bytesWritten) {
+ MediaBuffer *buffer, bool usePrefix, bool isExif, 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
+ mOffset += 4;
+ }
+
::write(mFd,
(const uint8_t *)buffer->data() + buffer->range_offset(),
buffer->range_length());
@@ -1767,6 +1785,9 @@
mReachedEOS(false),
mStartTimestampUs(-1),
mRotation(0),
+ mDimgRefs("dimg"),
+ mCdscRefs("cdsc"),
+ mImageItemId(0),
mIsPrimary(0),
mWidth(0),
mHeight(0),
@@ -1933,6 +1954,13 @@
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));
+}
+
void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
CHECK(!mIsHeic);
if (mOwner->use32BitFileOffset()) {
@@ -1943,7 +1971,7 @@
}
}
-void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size) {
+void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size, bool isExif) {
CHECK(mIsHeic);
if (offset > UINT32_MAX || size > UINT32_MAX) {
@@ -1954,6 +1982,18 @@
if (mIsMalformed) {
return;
}
+
+ if (isExif) {
+ mCdscRefs.value.push_back(mOwner->addItem_l({
+ .itemType = "Exif",
+ .isPrimary = false,
+ .isHidden = false,
+ .offset = (uint32_t)offset,
+ .size = (uint32_t)size,
+ }));
+ return;
+ }
+
if (mTileIndex >= mNumTiles) {
ALOGW("Ignoring excess tiles!");
return;
@@ -1968,7 +2008,7 @@
default: break; // don't set if invalid
}
- bool hasGrid = (mNumTiles > 1);
+ bool hasGrid = (mTileWidth > 0);
if (mProperties.empty()) {
mProperties.push_back(mOwner->addProperty_l({
@@ -1990,18 +2030,16 @@
}
}
- uint16_t itemId = mOwner->addItem_l({
- .itemType = "hvc1",
- .isPrimary = hasGrid ? false : (mIsPrimary != 0),
- .isHidden = hasGrid,
- .offset = (uint32_t)offset,
- .size = (uint32_t)size,
- .properties = mProperties,
- });
-
mTileIndex++;
if (hasGrid) {
- mDimgRefs.push_back(itemId);
+ mDimgRefs.value.push_back(mOwner->addItem_l({
+ .itemType = "hvc1",
+ .isPrimary = false,
+ .isHidden = true,
+ .offset = (uint32_t)offset,
+ .size = (uint32_t)size,
+ .properties = mProperties,
+ }));
if (mTileIndex == mNumTiles) {
mProperties.clear();
@@ -2016,7 +2054,7 @@
.rotation = heifRotation,
}));
}
- mOwner->addItem_l({
+ mImageItemId = mOwner->addItem_l({
.itemType = "grid",
.isPrimary = (mIsPrimary != 0),
.isHidden = false,
@@ -2025,9 +2063,31 @@
.width = (uint32_t)mWidth,
.height = (uint32_t)mHeight,
.properties = mProperties,
- .dimgRefs = mDimgRefs,
});
}
+ } else {
+ mImageItemId = mOwner->addItem_l({
+ .itemType = "hvc1",
+ .isPrimary = (mIsPrimary != 0),
+ .isHidden = false,
+ .offset = (uint32_t)offset,
+ .size = (uint32_t)size,
+ .properties = mProperties,
+ });
+ }
+}
+
+// Flush out the item refs for this track. Note that it must be called after the
+// writer thread has stopped, because there might be pending items in the last
+// few chunks written by the writer thread (as opposed to the track). In particular,
+// it affects the 'dimg' refs for tiled image, as we only have the refs after the
+// last tile sample is written.
+void MPEG4Writer::Track::flushItemRefs() {
+ CHECK(mIsHeic);
+
+ if (mImageItemId > 0) {
+ mOwner->addRefs_l(mImageItemId, mDimgRefs);
+ mOwner->addRefs_l(mImageItemId, mCdscRefs);
}
}
@@ -2174,15 +2234,20 @@
chunk->mTimeStampUs, chunk->mTrack->getTrackType());
int32_t isFirstSample = true;
- bool usePrefix = chunk->mTrack->usePrefix();
while (!chunk->mSamples.empty()) {
List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
+ int32_t isExif;
+ if (!(*it)->meta_data().findInt32(kKeyIsExif, &isExif)) {
+ isExif = 0;
+ }
+ bool usePrefix = chunk->mTrack->usePrefix() && !isExif;
+
size_t bytesWritten;
- off64_t offset = addSample_l(*it, usePrefix, &bytesWritten);
+ off64_t offset = addSample_l(*it, usePrefix, isExif, &bytesWritten);
if (chunk->mTrack->isHeic()) {
- chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten);
+ chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten, isExif);
} else if (isFirstSample) {
chunk->mTrack->addChunkOffset(offset);
isFirstSample = false;
@@ -2904,6 +2969,19 @@
break;
}
+ bool isExif = false;
+ 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);
+ if (!isExif) {
+ ALOGW("Ignoring bad Exif data block");
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+ }
+
++nActualFrames;
// Make a deep copy of the MediaBuffer and Metadata and release
@@ -2916,10 +2994,15 @@
buffer->release();
buffer = NULL;
- if (usePrefix()) StripStartcode(copy);
+ if (isExif) {
+ copy->meta_data().setInt32(kKeyIsExif, 1);
+ }
+ bool usePrefix = this->usePrefix() && !isExif;
+
+ if (usePrefix) StripStartcode(copy);
size_t sampleSize = copy->range_length();
- if (usePrefix()) {
+ if (usePrefix) {
if (mOwner->useNalLengthFour()) {
sampleSize += 4;
} else {
@@ -3185,10 +3268,10 @@
}
if (!hasMultipleTracks) {
size_t bytesWritten;
- off64_t offset = mOwner->addSample_l(copy, usePrefix(), &bytesWritten);
+ off64_t offset = mOwner->addSample_l(copy, usePrefix, isExif, &bytesWritten);
if (mIsHeic) {
- addItemOffsetAndSize(offset, bytesWritten);
+ addItemOffsetAndSize(offset, bytesWritten, isExif);
} else {
uint32_t count = (mOwner->use32BitFileOffset()
? mStcoTableEntries->count()
@@ -3450,10 +3533,12 @@
return mEstimatedTrackSizeBytes;
}
-int32_t MPEG4Writer::Track::getMetaSizeIncrease() const {
+int32_t MPEG4Writer::Track::getMetaSizeIncrease(
+ int32_t angle, int32_t trackCount) const {
CHECK(mIsHeic);
- int32_t grid = (mNumTiles > 1);
+ int32_t grid = (mTileWidth > 0);
+ int32_t rotate = (angle > 0);
// Note that the rotation angle is in the file meta, and we don't have
// it until start, so here the calculation has to assume rotation.
@@ -3461,25 +3546,34 @@
// increase to ipco
int32_t increase = 20 * (grid + 1) // 'ispe' property
+ (8 + mCodecSpecificDataSize) // 'hvcC' property
- + 9; // 'irot' property (worst case)
+ ;
+
+ if (rotate) {
+ increase += 9; // 'irot' property (worst case)
+ }
// increase to iref and idat
if (grid) {
- increase += (8 + 2 + 2 + mNumTiles * 2) // 'dimg' in iref
- + 12; // ImageGrid in 'idat' (worst case)
+ increase += (12 + mNumTiles * 2) // 'dimg' in iref
+ + 12; // ImageGrid in 'idat' (worst case)
}
- // increase to iloc, iinf and ipma
- increase += (16 // increase to 'iloc'
- + 21 // increase to 'iinf'
- + (3 + 2 * 2)) // increase to 'ipma' (worst case, 2 props x 2 bytes)
- * (mNumTiles + grid);
+ increase += (12 + 2); // 'cdsc' in iref
- // adjust to ipma:
- // if rotation is present and only one tile, it could ref 3 properties
- if (!grid) {
- increase += 2;
- }
+ // increase to iloc, iinf
+ increase += (16 // increase to 'iloc'
+ + 21) // increase to 'iinf'
+ * (mNumTiles + grid + 1); // "+1" is for 'Exif'
+
+ // When total # of properties is > 127, the properties id becomes 2-byte.
+ // We write 4 properties at most for each image (2x'ispe', 1x'hvcC', 1x'irot').
+ // Set the threshold to be 30.
+ int32_t propBytes = trackCount > 30 ? 2 : 1;
+
+ // increase to ipma
+ increase += (3 + 2 * propBytes) * mNumTiles // 'ispe' + 'hvcC'
+ + grid * (3 + propBytes) // 'ispe' for grid
+ + rotate * propBytes; // 'irot' (either on grid or tile)
return increase;
}
@@ -4239,7 +4333,7 @@
writeInt16((uint16_t)itemCount);
for (size_t i = 0; i < itemCount; i++) {
writeInfeBox(mItems[i].itemId, mItems[i].itemType,
- mItems[i].isHidden ? 1 : 0);
+ (mItems[i].isImage() && mItems[i].isHidden) ? 1 : 0);
}
endBox();
@@ -4274,21 +4368,21 @@
writeInt32(0); // Version = 0, Flags = 0
{
for (size_t i = 0; i < mItems.size(); i++) {
- if (!mItems[i].isGrid()) {
- continue;
+ for (size_t r = 0; r < mItems[i].refsList.size(); r++) {
+ const ItemRefs &refs = mItems[i].refsList[r];
+ beginBox(refs.key);
+ writeInt16(mItems[i].itemId);
+ size_t refCount = refs.value.size();
+ if (refCount > 65535) {
+ ALOGW("too many entries in %s", refs.key);
+ refCount = 65535;
+ }
+ writeInt16((uint16_t)refCount);
+ for (size_t refIndex = 0; refIndex < refCount; refIndex++) {
+ writeInt16(refs.value[refIndex]);
+ }
+ endBox();
}
- beginBox("dimg");
- writeInt16(mItems[i].itemId);
- size_t refCount = mItems[i].dimgRefs.size();
- if (refCount > 65535) {
- ALOGW("too many entries in dimg");
- refCount = 65535;
- }
- writeInt16((uint16_t)refCount);
- for (size_t refIndex = 0; refIndex < refCount; refIndex++) {
- writeInt16(mItems[i].dimgRefs[refIndex]);
- }
- endBox();
}
}
endBox();
@@ -4384,32 +4478,45 @@
}
void MPEG4Writer::writeFileLevelMetaBox() {
- if (mItems.empty()) {
- ALOGE("no valid item was found");
- return;
- }
-
// patch up the mPrimaryItemId and count items with prop associations
uint16_t firstVisibleItemId = 0;
+ uint16_t firstImageItemId = 0;
for (size_t index = 0; index < mItems.size(); index++) {
+ if (!mItems[index].isImage()) continue;
+
if (mItems[index].isPrimary) {
mPrimaryItemId = mItems[index].itemId;
- } else if (!firstVisibleItemId && !mItems[index].isHidden) {
+ }
+ if (!firstImageItemId) {
+ firstImageItemId = mItems[index].itemId;
+ }
+ if (!firstVisibleItemId && !mItems[index].isHidden) {
firstVisibleItemId = mItems[index].itemId;
}
-
if (!mItems[index].properties.empty()) {
mAssociationEntryCount++;
}
}
+ if (!firstImageItemId) {
+ ALOGE("no valid image was found");
+ return;
+ }
+
if (mPrimaryItemId == 0) {
if (firstVisibleItemId > 0) {
- ALOGW("didn't find primary, using first visible item");
+ ALOGW("didn't find primary, using first visible image");
mPrimaryItemId = firstVisibleItemId;
} else {
- ALOGW("no primary and no visible item, using first item");
- mPrimaryItemId = mItems[0].itemId;
+ ALOGW("no primary and no visible item, using first image");
+ mPrimaryItemId = firstImageItemId;
+ }
+ }
+
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ if ((*it)->isHeic()) {
+ (*it)->flushItemRefs();
}
}
@@ -4422,6 +4529,8 @@
writeIprpBox();
if (mNumGrids > 0) {
writeIdatBox();
+ }
+ if (mHasRefs) {
writeIrefBox();
}
endBox();
@@ -4445,8 +4554,8 @@
size_t index = mItems.size();
mItems.push_back(info);
- // make the item id start at 10000
- mItems.editItemAt(index).itemId = index + 10000;
+ // make the item id start at kItemIdBase
+ mItems.editItemAt(index).itemId = index + kItemIdBase;
#if (LOG_NDEBUG==0)
if (!info.properties.empty()) {
@@ -4464,6 +4573,20 @@
return mItems[index].itemId;
}
+void MPEG4Writer::addRefs_l(uint16_t itemId, const ItemRefs &refs) {
+ if (refs.value.empty()) {
+ return;
+ }
+ if (itemId < kItemIdBase) {
+ ALOGW("itemId shouldn't be smaller than kItemIdBase");
+ return;
+ }
+
+ size_t index = itemId - kItemIdBase;
+ mItems.editItemAt(index).refsList.push_back(refs);
+ mHasRefs = true;
+}
+
/*
* Geodata is stored according to ISO-6709 standard.
*/
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 23e543d..98f59b5 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -190,6 +190,10 @@
sampleMetaData.setInt32(kKeyIsSyncFrame, true);
}
+ if (flags & MediaCodec::BUFFER_FLAG_MUXER_DATA) {
+ sampleMetaData.setInt32(kKeyIsMuxerData, 1);
+ }
+
sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
// This pushBuffer will wait until the mediaBuffer is consumed.
return currentTrack->pushBuffer(mediaBuffer);
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 7b41362..f18940d 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -132,7 +132,7 @@
status_t startTracks(MetaData *params);
size_t numTracks();
int64_t estimateMoovBoxSize(int32_t bitRate);
- int64_t estimateFileLevelMetaSize();
+ int64_t estimateFileLevelMetaSize(MetaData *params);
void writeCachedBoxToFile(const char *type);
struct Chunk {
@@ -167,8 +167,10 @@
Condition mChunkReadyCondition; // Signal that chunks are available
// HEIF writing
+ typedef key_value_pair_t< const char *, Vector<uint16_t> > ItemRefs;
typedef struct _ItemInfo {
bool isGrid() const { return !strcmp("grid", itemType); }
+ bool isImage() const { return !strcmp("hvc1", itemType) || isGrid(); }
const char *itemType;
uint16_t itemId;
bool isPrimary;
@@ -188,7 +190,7 @@
};
};
Vector<uint16_t> properties;
- Vector<uint16_t> dimgRefs;
+ Vector<ItemRefs> refsList;
} ItemInfo;
typedef struct _ItemProperty {
@@ -204,6 +206,7 @@
uint32_t mPrimaryItemId;
uint32_t mAssociationEntryCount;
uint32_t mNumGrids;
+ bool mHasRefs;
Vector<ItemInfo> mItems;
Vector<ItemProperty> mProperties;
@@ -252,11 +255,12 @@
void initInternal(int fd, bool isFirstSession);
// Acquire lock before calling these methods
- off64_t addSample_l(MediaBuffer *buffer, bool usePrefix, size_t *bytesWritten);
+ off64_t addSample_l(MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten);
void addLengthPrefixedSample_l(MediaBuffer *buffer);
void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer);
uint16_t addProperty_l(const ItemProperty &);
uint16_t addItem_l(const ItemInfo &);
+ void addRefs_l(uint16_t itemId, const ItemRefs &);
bool exceedsFileSizeLimit();
bool use32BitFileOffset() const;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 67808f1..ad02004 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -61,9 +61,11 @@
};
enum BufferFlags {
- BUFFER_FLAG_SYNCFRAME = 1,
- BUFFER_FLAG_CODECCONFIG = 2,
- BUFFER_FLAG_EOS = 4,
+ BUFFER_FLAG_SYNCFRAME = 1,
+ BUFFER_FLAG_CODECCONFIG = 2,
+ BUFFER_FLAG_EOS = 4,
+ BUFFER_FLAG_PARTIAL_FRAME = 8,
+ BUFFER_FLAG_MUXER_DATA = 16,
};
enum {