Convert Ogg and Flac extractors to use AMediaFormat

Bug: 111407253
Test: manual, CTS
Change-Id: I8aeb44ceeb831bb558cac1123f0aaade8163abf8
gugelfrei
Marco Nelissen 6 years ago
parent fdd42e9535
commit 4d026f5583

@ -1 +0,0 @@
../../media/libmediaextractor/include/media/VorbisComment.h

@ -10,11 +10,14 @@ cc_library_shared {
shared_libs: [
"liblog",
"libmediaextractor",
"libmediandk",
],
static_libs: [
"libFLAC",
"libstagefright_foundation",
"libstagefright_metadatautils",
"libutils",
],
name: "libflacextractor",

@ -25,7 +25,7 @@
#include "FLAC/stream_decoder.h"
#include <media/MediaExtractorPluginApi.h>
#include <media/VorbisComment.h>
#include <media/NdkMediaFormat.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
@ -33,24 +33,25 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/MediaBufferBase.h>
namespace android {
class FLACParser;
class FLACSource : public MediaTrackHelper {
class FLACSource : public MediaTrackHelperV2 {
public:
FLACSource(
DataSourceHelper *dataSource,
MetaDataBase &meta);
AMediaFormat *meta);
virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &meta);
virtual media_status_t start();
virtual media_status_t stop();
virtual media_status_t getFormat(AMediaFormat *meta);
virtual status_t read(
virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@ -58,7 +59,7 @@ protected:
private:
DataSourceHelper *mDataSource;
MetaDataBase mTrackMetadata;
AMediaFormat *mTrackMetadata;
FLACParser *mParser;
bool mInitCheck;
bool mStarted;
@ -81,8 +82,8 @@ public:
explicit FLACParser(
DataSourceHelper *dataSource,
// If metadata pointers aren't provided, we don't fill them
MetaDataBase *fileMetadata = 0,
MetaDataBase *trackMetadata = 0);
AMediaFormat *fileMetadata = 0,
AMediaFormat *trackMetadata = 0);
virtual ~FLACParser();
@ -119,8 +120,8 @@ public:
private:
DataSourceHelper *mDataSource;
MetaDataBase *mFileMetadata;
MetaDataBase *mTrackMetadata;
AMediaFormat *mFileMetadata;
AMediaFormat *mTrackMetadata;
bool mInitCheck;
// media buffers
@ -364,8 +365,8 @@ void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata)
case FLAC__METADATA_TYPE_PICTURE:
if (mFileMetadata != 0) {
const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
mFileMetadata->setData(kKeyAlbumArt,
MetaData::TYPE_NONE, p->data, p->data_length);
AMediaFormat_setBuffer(mFileMetadata, AMEDIAFORMAT_KEY_ALBUMART,
p->data, p->data_length);
}
break;
default:
@ -487,8 +488,8 @@ static void copyTrespass(
FLACParser::FLACParser(
DataSourceHelper *dataSource,
MetaDataBase *fileMetadata,
MetaDataBase *trackMetadata)
AMediaFormat *fileMetadata,
AMediaFormat *trackMetadata)
: mDataSource(dataSource),
mFileMetadata(fileMetadata),
mTrackMetadata(trackMetadata),
@ -614,20 +615,25 @@ status_t FLACParser::init()
}
// populate track metadata
if (mTrackMetadata != 0) {
mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
mTrackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
AMediaFormat_setString(mTrackMetadata,
AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_CHANNEL_COUNT, getChannels());
AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
// sample rate is non-zero, so division by zero not possible
mTrackMetadata->setInt64(kKeyDuration,
(getTotalSamples() * 1000000LL) / getSampleRate());
AMediaFormat_setInt64(mTrackMetadata,
AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
}
} else {
ALOGE("missing STREAMINFO");
return NO_INIT;
}
if (mFileMetadata != 0) {
mFileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
AMediaFormat_setString(mFileMetadata,
AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
}
return OK;
}
@ -708,7 +714,7 @@ MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
FLACSource::FLACSource(
DataSourceHelper *dataSource,
MetaDataBase &trackMetadata)
AMediaFormat *trackMetadata)
: mDataSource(dataSource),
mTrackMetadata(trackMetadata),
mParser(0),
@ -730,7 +736,7 @@ FLACSource::~FLACSource()
delete mParser;
}
status_t FLACSource::start()
media_status_t FLACSource::start()
{
ALOGV("FLACSource::start");
@ -738,10 +744,10 @@ status_t FLACSource::start()
mParser->allocateBuffers();
mStarted = true;
return OK;
return AMEDIA_OK;
}
status_t FLACSource::stop()
media_status_t FLACSource::stop()
{
ALOGV("FLACSource::stop");
@ -749,16 +755,15 @@ status_t FLACSource::stop()
mParser->releaseBuffers();
mStarted = false;
return OK;
return AMEDIA_OK;
}
status_t FLACSource::getFormat(MetaDataBase &meta)
media_status_t FLACSource::getFormat(AMediaFormat *meta)
{
meta = mTrackMetadata;
return OK;
return AMediaFormat_copy(meta, mTrackMetadata);
}
status_t FLACSource::read(
media_status_t FLACSource::read(
MediaBufferBase **outBuffer, const ReadOptions *options)
{
MediaBufferBase *buffer;
@ -782,7 +787,7 @@ status_t FLACSource::read(
buffer = mParser->readBuffer();
}
*outBuffer = buffer;
return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
}
// FLACExtractor
@ -795,7 +800,9 @@ FLACExtractor::FLACExtractor(
{
ALOGV("FLACExtractor::FLACExtractor");
// FLACParser will fill in the metadata for us
mParser = new FLACParser(mDataSource, &mFileMetadata, &mTrackMetadata);
mFileMetadata = AMediaFormat_new();
mTrackMetadata = AMediaFormat_new();
mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
mInitCheck = mParser->initCheck();
}
@ -804,6 +811,8 @@ FLACExtractor::~FLACExtractor()
ALOGV("~FLACExtractor::FLACExtractor");
delete mParser;
delete mDataSource;
AMediaFormat_delete(mFileMetadata);
AMediaFormat_delete(mTrackMetadata);
}
size_t FLACExtractor::countTracks()
@ -811,7 +820,7 @@ size_t FLACExtractor::countTracks()
return mInitCheck == OK ? 1 : 0;
}
MediaTrackHelper *FLACExtractor::getTrack(size_t index)
MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
@ -819,20 +828,18 @@ MediaTrackHelper *FLACExtractor::getTrack(size_t index)
return new FLACSource(mDataSource, mTrackMetadata);
}
status_t FLACExtractor::getTrackMetaData(
MetaDataBase &meta,
media_status_t FLACExtractor::getTrackMetaData(
AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index > 0) {
return UNKNOWN_ERROR;
return AMEDIA_ERROR_UNKNOWN;
}
meta = mTrackMetadata;
return OK;
return AMediaFormat_copy(meta, mTrackMetadata);
}
status_t FLACExtractor::getMetaData(MetaDataBase &meta)
media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
{
meta = mFileMetadata;
return OK;
return AMediaFormat_copy(meta, mFileMetadata);
}
// Sniffer
@ -861,22 +868,22 @@ extern "C" {
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
EXTRACTORDEF_VERSION,
EXTRACTORDEF_VERSION_CURRENT,
UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
1,
"FLAC Extractor",
{
[](
.v2 = [](
CDataSource *source,
float *confidence,
void **,
FreeMetaFunc *) -> CreatorFunc {
FreeMetaFunc *) -> CreatorFuncV2 {
DataSourceHelper helper(source);
if (SniffFLAC(&helper, confidence)) {
return [](
CDataSource *source,
void *) -> CMediaExtractor* {
return wrap(new FLACExtractor(new DataSourceHelper(source)));};
void *) -> CMediaExtractorV2* {
return wrapV2(new FLACExtractor(new DataSourceHelper(source)));};
}
return NULL;
}

@ -20,23 +20,23 @@
#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MetaDataBase.h>
#include <media/NdkMediaFormat.h>
#include <utils/String8.h>
namespace android {
class FLACParser;
class FLACExtractor : public MediaExtractorPluginHelper {
class FLACExtractor : public MediaExtractorPluginHelperV2 {
public:
explicit FLACExtractor(DataSourceHelper *source);
virtual size_t countTracks();
virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual MediaTrackHelperV2 *getTrack(size_t index);
virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "FLACExtractor"; }
protected:
@ -46,10 +46,10 @@ private:
DataSourceHelper *mDataSource;
FLACParser *mParser;
status_t mInitCheck;
MetaDataBase mFileMetadata;
AMediaFormat *mFileMetadata;
// There is only one track
MetaDataBase mTrackMetadata;
AMediaFormat *mTrackMetadata;
FLACExtractor(const FLACExtractor &);
FLACExtractor &operator=(const FLACExtractor &);

@ -10,10 +10,12 @@ cc_library_shared {
shared_libs: [
"liblog",
"libmediaextractor",
"libmediandk",
],
static_libs: [
"libstagefright_foundation",
"libstagefright_metadatautils",
"libutils",
"libvorbisidec",
],

@ -24,7 +24,6 @@
#include <utils/Vector.h>
#include <media/DataSourceBase.h>
#include <media/ExtractorUtils.h>
#include <media/VorbisComment.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
@ -34,6 +33,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaDataBase.h>
#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
extern "C" {
@ -47,15 +47,15 @@ extern "C" {
namespace android {
struct OggSource : public MediaTrackHelper {
struct OggSource : public MediaTrackHelperV2 {
explicit OggSource(OggExtractor *extractor);
virtual status_t getFormat(MetaDataBase &);
virtual media_status_t getFormat(AMediaFormat *);
virtual status_t start();
virtual status_t stop();
virtual media_status_t start();
virtual media_status_t stop();
virtual status_t read(
virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@ -77,7 +77,7 @@ struct MyOggExtractor {
int64_t seekPreRollUs);
virtual ~MyOggExtractor();
status_t getFormat(MetaDataBase &) const;
media_status_t getFormat(AMediaFormat *) const;
// Returns an approximate bitrate in bits per second.
virtual uint64_t approxBitrate() const = 0;
@ -88,9 +88,8 @@ struct MyOggExtractor {
status_t init();
status_t getFileMetaData(MetaDataBase &meta) {
meta = mFileMeta;
return OK;
media_status_t getFileMetaData(AMediaFormat *meta) {
return AMediaFormat_copy(meta, mFileMeta);
}
protected:
@ -129,8 +128,8 @@ protected:
vorbis_info mVi;
vorbis_comment mVc;
MetaDataBase mMeta;
MetaDataBase mFileMeta;
AMediaFormat *mMeta;
AMediaFormat *mFileMeta;
Vector<TOCEntry> mTableOfContents;
@ -237,27 +236,27 @@ OggSource::~OggSource() {
}
}
status_t OggSource::getFormat(MetaDataBase &meta) {
media_status_t OggSource::getFormat(AMediaFormat *meta) {
return mExtractor->mImpl->getFormat(meta);
}
status_t OggSource::start() {
media_status_t OggSource::start() {
if (mStarted) {
return INVALID_OPERATION;
return AMEDIA_ERROR_INVALID_OPERATION;
}
mStarted = true;
return OK;
return AMEDIA_OK;
}
status_t OggSource::stop() {
media_status_t OggSource::stop() {
mStarted = false;
return OK;
return AMEDIA_OK;
}
status_t OggSource::read(
media_status_t OggSource::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
@ -266,7 +265,7 @@ status_t OggSource::read(
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
status_t err = mExtractor->mImpl->seekToTime(seekTimeUs);
if (err != OK) {
return err;
return AMEDIA_ERROR_UNKNOWN;
}
}
@ -274,7 +273,7 @@ status_t OggSource::read(
status_t err = mExtractor->mImpl->readNextPacket(&packet);
if (err != OK) {
return err;
return AMEDIA_ERROR_UNKNOWN;
}
#if 0
@ -290,7 +289,7 @@ status_t OggSource::read(
*out = packet;
return OK;
return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
@ -316,16 +315,19 @@ MyOggExtractor::MyOggExtractor(
vorbis_info_init(&mVi);
vorbis_comment_init(&mVc);
mMeta = AMediaFormat_new();
mFileMeta = AMediaFormat_new();
}
MyOggExtractor::~MyOggExtractor() {
AMediaFormat_delete(mFileMeta);
AMediaFormat_delete(mMeta);
vorbis_comment_clear(&mVc);
vorbis_info_clear(&mVi);
}
status_t MyOggExtractor::getFormat(MetaDataBase &meta) const {
meta = mMeta;
return OK;
media_status_t MyOggExtractor::getFormat(AMediaFormat *meta) const {
return AMediaFormat_copy(meta, mMeta);
}
status_t MyOggExtractor::findNextPage(
@ -832,7 +834,7 @@ status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisT
}
status_t MyOggExtractor::init() {
mMeta.setCString(kKeyMIMEType, mMimeType);
AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, mMimeType);
status_t err;
MediaBufferBase *packet;
@ -865,7 +867,7 @@ status_t MyOggExtractor::init() {
int64_t durationUs = getTimeUsOfGranule(lastGranulePosition);
mMeta.setInt64(kKeyDuration, durationUs);
AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
buildTableOfContents();
}
@ -981,11 +983,14 @@ status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
mChannelCount = data[9];
mCodecDelay = U16LE_AT(&data[10]);
mMeta.setData(kKeyOpusHeader, 0, data, size);
mMeta.setInt32(kKeySampleRate, kOpusSampleRate);
mMeta.setInt32(kKeyChannelCount, mChannelCount);
mMeta.setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
mMeta.setInt64(kKeyOpusCodecDelay /* ns */,
// kKeyOpusHeader is csd-0
AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, kOpusSampleRate);
AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mChannelCount);
// are these actually used anywhere?
// (they are kKeyOpusSeekPreRoll and kKeyOpusCodecDelay respectively)
AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_2, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_1,
mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
return OK;
@ -1122,10 +1127,10 @@ status_t MyVorbisExtractor::verifyHeader(
return ERROR_MALFORMED;
}
mMeta.setData(kKeyVorbisInfo, 0, data, size);
mMeta.setInt32(kKeySampleRate, mVi.rate);
mMeta.setInt32(kKeyChannelCount, mVi.channels);
mMeta.setInt32(kKeyBitRate, mVi.bitrate_nominal);
AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mVi.rate);
AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mVi.channels);
AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, mVi.bitrate_nominal);
ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
@ -1140,7 +1145,7 @@ status_t MyVorbisExtractor::verifyHeader(
if (mSource->getSize(&size) == OK) {
uint64_t bps = approxBitrate();
if (bps != 0) {
mMeta.setInt64(kKeyDuration, size * 8000000ll / bps);
AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, size * 8000000ll / bps);
}
}
break;
@ -1162,7 +1167,7 @@ status_t MyVorbisExtractor::verifyHeader(
return ERROR_MALFORMED;
}
mMeta.setData(kKeyVorbisBooks, 0, data, size);
AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
break;
}
}
@ -1180,12 +1185,12 @@ uint64_t MyVorbisExtractor::approxBitrate() const {
void MyOggExtractor::parseFileMetaData() {
mFileMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
AMediaFormat_setString(mFileMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_OGG);
for (int i = 0; i < mVc.comments; ++i) {
const char *comment = mVc.user_comments[i];
size_t commentLength = mVc.comment_lengths[i];
parseVorbisComment(&mFileMeta, comment, commentLength);
parseVorbisComment(mFileMeta, comment, commentLength);
//ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
}
}
@ -1227,7 +1232,7 @@ size_t OggExtractor::countTracks() {
return mInitCheck != OK ? 0 : 1;
}
MediaTrackHelper *OggExtractor::getTrack(size_t index) {
MediaTrackHelperV2 *OggExtractor::getTrack(size_t index) {
if (index >= 1) {
return NULL;
}
@ -1235,27 +1240,27 @@ MediaTrackHelper *OggExtractor::getTrack(size_t index) {
return new OggSource(this);
}
status_t OggExtractor::getTrackMetaData(
MetaDataBase &meta,
media_status_t OggExtractor::getTrackMetaData(
AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (index >= 1) {
return UNKNOWN_ERROR;
return AMEDIA_ERROR_UNKNOWN;
}
return mImpl->getFormat(meta);
}
status_t OggExtractor::getMetaData(MetaDataBase &meta) {
media_status_t OggExtractor::getMetaData(AMediaFormat *meta) {
return mImpl->getFileMetaData(meta);
}
static CMediaExtractor* CreateExtractor(
static CMediaExtractorV2* CreateExtractor(
CDataSource *source,
void *) {
return wrap(new OggExtractor(new DataSourceHelper(source)));
return wrapV2(new OggExtractor(new DataSourceHelper(source)));
}
static CreatorFunc Sniff(
static CreatorFuncV2 Sniff(
CDataSource *source,
float *confidence,
void **,
@ -1276,11 +1281,11 @@ extern "C" {
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
EXTRACTORDEF_VERSION,
EXTRACTORDEF_VERSION_CURRENT,
UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
1, // version
"Ogg Extractor",
{ Sniff }
{ .v2 = Sniff }
};
}

@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/NdkMediaFormat.h>
namespace android {
@ -30,14 +31,14 @@ class String8;
struct MyOggExtractor;
struct OggSource;
struct OggExtractor : public MediaExtractorPluginHelper {
struct OggExtractor : public MediaExtractorPluginHelperV2 {
explicit OggExtractor(DataSourceHelper *source);
virtual size_t countTracks();
virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual MediaTrackHelperV2 *getTrack(size_t index);
virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "OggExtractor"; }
protected:

@ -38,7 +38,6 @@ cc_library {
"MediaSource.cpp",
"MetaData.cpp",
"MetaDataBase.cpp",
"VorbisComment.cpp",
],
clang: true,

@ -1,151 +0,0 @@
/*
* Copyright (C) 2018 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "VorbisComment"
#include <utils/Log.h>
#include "media/VorbisComment.h"
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/MetaDataBase.h>
namespace android {
static void extractAlbumArt(
MetaDataBase *fileMeta, const void *data, size_t size) {
ALOGV("extractAlbumArt from '%s'", (const char *)data);
sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
if (flacBuffer == NULL) {
ALOGE("malformed base64 encoded data.");
return;
}
size_t flacSize = flacBuffer->size();
uint8_t *flac = flacBuffer->data();
ALOGV("got flac of size %zu", flacSize);
uint32_t picType;
uint32_t typeLen;
uint32_t descLen;
uint32_t dataLen;
char type[128];
if (flacSize < 8) {
return;
}
picType = U32_AT(flac);
if (picType != 3) {
// This is not a front cover.
return;
}
typeLen = U32_AT(&flac[4]);
if (typeLen > sizeof(type) - 1) {
return;
}
// we've already checked above that flacSize >= 8
if (flacSize - 8 < typeLen) {
return;
}
memcpy(type, &flac[8], typeLen);
type[typeLen] = '\0';
ALOGV("picType = %d, type = '%s'", picType, type);
if (!strcmp(type, "-->")) {
// This is not inline cover art, but an external url instead.
return;
}
if (flacSize < 32 || flacSize - 32 < typeLen) {
return;
}
descLen = U32_AT(&flac[8 + typeLen]);
if (flacSize - 32 - typeLen < descLen) {
return;
}
dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
// we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
if (flacSize - 32 - typeLen - descLen < dataLen) {
return;
}
ALOGV("got image data, %zu trailing bytes",
flacSize - 32 - typeLen - descLen - dataLen);
fileMeta->setData(
kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
}
void parseVorbisComment(
MetaDataBase *fileMeta, const char *comment, size_t commentLength)
{
struct {
const char *const mTag;
uint32_t mKey;
} kMap[] = {
{ "TITLE", kKeyTitle },
{ "ARTIST", kKeyArtist },
{ "ALBUMARTIST", kKeyAlbumArtist },
{ "ALBUM ARTIST", kKeyAlbumArtist },
{ "COMPILATION", kKeyCompilation },
{ "ALBUM", kKeyAlbum },
{ "COMPOSER", kKeyComposer },
{ "GENRE", kKeyGenre },
{ "AUTHOR", kKeyAuthor },
{ "TRACKNUMBER", kKeyCDTrackNumber },
{ "DISCNUMBER", kKeyDiscNumber },
{ "DATE", kKeyDate },
{ "YEAR", kKeyYear },
{ "LYRICIST", kKeyWriter },
{ "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
{ "ANDROID_LOOP", kKeyAutoLoop },
};
for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
size_t tagLen = strlen(kMap[j].mTag);
if (!strncasecmp(kMap[j].mTag, comment, tagLen)
&& comment[tagLen] == '=') {
if (kMap[j].mKey == kKeyAlbumArt) {
extractAlbumArt(
fileMeta,
&comment[tagLen + 1],
commentLength - tagLen - 1);
} else if (kMap[j].mKey == kKeyAutoLoop) {
if (!strcasecmp(&comment[tagLen + 1], "true")) {
fileMeta->setInt32(kKeyAutoLoop, true);
}
} else {
fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
}
}
}
}
} // namespace android

@ -1,30 +0,0 @@
/*
* Copyright (C) 2018 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 VORBIS_COMMENT_H_
#define VORBIS_COMMENT_H_
namespace android {
class MetaDataBase;
void parseVorbisComment(
MetaDataBase *fileMeta, const char *comment, size_t commentLength);
} // namespace android
#endif // VORBIS_COMMENT_H_

@ -19,8 +19,10 @@
#include <utils/Log.h>
#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/Utils.h>
@ -192,4 +194,135 @@ bool MakeAACCodecSpecificData(
return true;
}
static void extractAlbumArt(
AMediaFormat *fileMeta, const void *data, size_t size) {
ALOGV("extractAlbumArt from '%s'", (const char *)data);
size_t inLen = strnlen((const char *)data, size);
size_t flacSize = inLen / 4 * 3;
uint8_t *flac = new uint8_t[flacSize];
if (!decodeBase64(flac, &flacSize, (const char*)data)) {
ALOGE("malformed base64 encoded data.");
delete[] flac;
return;
}
ALOGV("got flac of size %zu", flacSize);
uint32_t picType;
uint32_t typeLen;
uint32_t descLen;
uint32_t dataLen;
char type[128];
if (flacSize < 8) {
delete[] flac;
return;
}
picType = U32_AT(flac);
if (picType != 3) {
// This is not a front cover.
delete[] flac;
return;
}
typeLen = U32_AT(&flac[4]);
if (typeLen > sizeof(type) - 1) {
delete[] flac;
return;
}
// we've already checked above that flacSize >= 8
if (flacSize - 8 < typeLen) {
delete[] flac;
return;
}
memcpy(type, &flac[8], typeLen);
type[typeLen] = '\0';
ALOGV("picType = %d, type = '%s'", picType, type);
if (!strcmp(type, "-->")) {
// This is not inline cover art, but an external url instead.
delete[] flac;
return;
}
if (flacSize < 32 || flacSize - 32 < typeLen) {
delete[] flac;
return;
}
descLen = U32_AT(&flac[8 + typeLen]);
if (flacSize - 32 - typeLen < descLen) {
delete[] flac;
return;
}
dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
// we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
if (flacSize - 32 - typeLen - descLen < dataLen) {
delete[] flac;
return;
}
ALOGV("got image data, %zu trailing bytes",
flacSize - 32 - typeLen - descLen - dataLen);
AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
&flac[8 + typeLen + 4 + descLen + 20], dataLen);
delete[] flac;
}
void parseVorbisComment(
AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
struct {
const char *const mTag;
const char *mKey;
} kMap[] = {
{ "TITLE", AMEDIAFORMAT_KEY_TITLE },
{ "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
{ "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
{ "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
{ "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
{ "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
{ "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
{ "GENRE", AMEDIAFORMAT_KEY_GENRE },
{ "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
{ "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
{ "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
{ "DATE", AMEDIAFORMAT_KEY_DATE },
{ "YEAR", AMEDIAFORMAT_KEY_YEAR },
{ "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
{ "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
{ "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
};
for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
size_t tagLen = strlen(kMap[j].mTag);
if (!strncasecmp(kMap[j].mTag, comment, tagLen)
&& comment[tagLen] == '=') {
if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
extractAlbumArt(
fileMeta,
&comment[tagLen + 1],
commentLength - tagLen - 1);
} else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
if (!strcasecmp(&comment[tagLen + 1], "true")) {
AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
}
} else {
AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
}
}
}
}
} // namespace android

@ -578,8 +578,10 @@ std::vector<std::pair<const char *, uint32_t>> tagMappings {
{ "cdtracknum", kKeyCDTrackNumber },
{ "compilation", kKeyCompilation },
{ "composer", kKeyComposer },
{ "date", kKeyDate },
{ "discnum", kKeyDiscNumber },
{ "genre", kKeyGenre },
{ "lyricist", kKeyWriter },
{ "title", kKeyTitle },
{ "year", kKeyYear },
}
@ -596,6 +598,11 @@ void convertMessageToMetaDataTags(const sp<AMessage> &msg, sp<MetaData> &meta) {
if (msg->findBuffer("albumart", &buf)) {
meta->setData(kKeyAlbumArt, MetaDataBase::Type::TYPE_NONE, buf->data(), buf->size());
}
int32_t loop;
if (msg->findInt32("loop", &loop)) {
meta->setInt32(kKeyAutoLoop, loop);
}
}
void convertMetaDataToMessageTags(const MetaDataBase *meta, sp<AMessage> format) {
@ -612,6 +619,10 @@ void convertMetaDataToMessageTags(const MetaDataBase *meta, sp<AMessage> format)
sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
format->setBuffer("albumart", buf);
}
int32_t loop;
if (meta->findInt32(kKeyAutoLoop, &loop)) {
format->setInt32("loop", loop);
}
}
status_t convertMetaDataToMessage(

@ -28,14 +28,31 @@ sp<ABuffer> decodeBase64(const AString &s) {
return NULL;
}
size_t bufSize = n / 4 * 3;
sp<ABuffer> buf = new ABuffer(bufSize);
if (decodeBase64(buf->data(), &bufSize, s.c_str())) {
buf->setRange(0, bufSize);
return buf;
}
return NULL;
}
bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) {
size_t n = strlen(s);
if ((n % 4) != 0) {
return false;
}
size_t padding = 0;
if (n >= 1 && s.c_str()[n - 1] == '=') {
if (n >= 1 && s[n - 1] == '=') {
padding = 1;
if (n >= 2 && s.c_str()[n - 2] == '=') {
if (n >= 2 && s[n - 2] == '=') {
padding = 2;
if (n >= 3 && s.c_str()[n - 3] == '=') {
if (n >= 3 && s[n - 3] == '=') {
padding = 3;
}
}
@ -45,15 +62,13 @@ sp<ABuffer> decodeBase64(const AString &s) {
// already made sure that n % 4 == 0.
size_t outLen = (n / 4) * 3 - padding;
sp<ABuffer> buffer = new ABuffer(outLen);
uint8_t *out = buffer->data();
if (out == NULL || buffer->size() < outLen) {
return NULL;
if (out == NULL || *inOutBufSize < outLen) {
return false;
}
size_t j = 0;
uint32_t accum = 0;
for (size_t i = 0; i < n; ++i) {
char c = s.c_str()[i];
char c = s[i];
unsigned value;
if (c >= 'A' && c <= 'Z') {
value = c - 'A';
@ -66,10 +81,10 @@ sp<ABuffer> decodeBase64(const AString &s) {
} else if (c == '/' || c == '_') {
value = 63;
} else if (c != '=') {
return NULL;
return false;
} else {
if (i < n - padding) {
return NULL;
return false;
}
value = 0;
@ -86,7 +101,8 @@ sp<ABuffer> decodeBase64(const AString &s) {
}
}
return buffer;
*inOutBufSize = j;
return true;
}
static char encode6Bit(unsigned x) {

@ -26,6 +26,9 @@ struct ABuffer;
struct AString;
sp<ABuffer> decodeBase64(const AString &s);
bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s);
void encodeBase64(const void *data, size_t size, AString *out);
void encodeBase64Url(const void *data, size_t size, AString *out);

@ -34,6 +34,9 @@ bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sam
bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
void parseVorbisComment(
AMediaFormat *fileMeta, const char *comment, size_t commentLength);
} // namespace android
#endif // META_DATA_UTILS_H_

@ -291,6 +291,7 @@ EXPORT const char* AMEDIAFORMAT_KEY_CSD = "csd";
EXPORT const char* AMEDIAFORMAT_KEY_CSD_0 = "csd-0";
EXPORT const char* AMEDIAFORMAT_KEY_CSD_1 = "csd-1";
EXPORT const char* AMEDIAFORMAT_KEY_CSD_2 = "csd-2";
EXPORT const char* AMEDIAFORMAT_KEY_DATE = "date";
EXPORT const char* AMEDIAFORMAT_KEY_DISCNUMBER = "discnum";
EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop";
EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_HEIGHT = "display-height";
@ -314,6 +315,8 @@ EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval";
EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency";
EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level";
EXPORT const char* AMEDIAFORMAT_KEY_LOOP = "loop";
EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";

@ -184,10 +184,13 @@ extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_COMPILATION __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_COMPOSER __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_DATE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_DISCNUMBER __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_ENCODER_DELAY __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_ENCODER_PADDING __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_LOOP __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_TITLE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_YEAR __INTRODUCED_IN(29);

Loading…
Cancel
Save