blob: b4cad0b5ba1d63234f89ac3ec46dafefbe2898d5 [file] [log] [blame]
/*
* Copyright (C) 2019 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 "extractor"
#include <iostream>
#include "Extractor.h"
int32_t Extractor::initExtractor(int32_t fd, size_t fileSize) {
mStats = new Stats();
mFrameBuf = (uint8_t *)calloc(kMaxBufferSize, sizeof(uint8_t));
if (!mFrameBuf) return -1;
int64_t sTime = mStats->getCurTime();
mExtractor = AMediaExtractor_new();
if (!mExtractor) return AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
media_status_t status = AMediaExtractor_setDataSourceFd(mExtractor, fd, 0, fileSize);
if (status != AMEDIA_OK) return status;
int64_t eTime = mStats->getCurTime();
int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
mStats->setInitTime(timeTaken);
return AMediaExtractor_getTrackCount(mExtractor);
}
void *Extractor::getCSDSample(AMediaCodecBufferInfo &frameInfo, int32_t csdIndex) {
char csdName[kMaxCSDStrlen];
void *csdBuffer = nullptr;
frameInfo.presentationTimeUs = 0;
frameInfo.flags = AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
snprintf(csdName, sizeof(csdName), "csd-%d", csdIndex);
size_t size;
bool csdFound = AMediaFormat_getBuffer(mFormat, csdName, &csdBuffer, &size);
if (!csdFound) return nullptr;
frameInfo.size = (int32_t)size;
mStats->addFrameSize(frameInfo.size);
return csdBuffer;
}
int32_t Extractor::getFrameSample(AMediaCodecBufferInfo &frameInfo) {
int32_t size = AMediaExtractor_readSampleData(mExtractor, mFrameBuf, kMaxBufferSize);
if (size < 0) return -1;
frameInfo.flags = AMediaExtractor_getSampleFlags(mExtractor);
frameInfo.size = size;
mStats->addFrameSize(frameInfo.size);
frameInfo.presentationTimeUs = AMediaExtractor_getSampleTime(mExtractor);
AMediaExtractor_advance(mExtractor);
return 0;
}
int32_t Extractor::setupTrackFormat(int32_t trackId) {
AMediaExtractor_selectTrack(mExtractor, trackId);
mFormat = AMediaExtractor_getTrackFormat(mExtractor, trackId);
if (!mFormat) return AMEDIA_ERROR_INVALID_OBJECT;
bool durationFound = AMediaFormat_getInt64(mFormat, AMEDIAFORMAT_KEY_DURATION, &mDurationUs);
if (!durationFound) return AMEDIA_ERROR_INVALID_OBJECT;
return AMEDIA_OK;
}
int32_t Extractor::extract(int32_t trackId) {
int32_t status = setupTrackFormat(trackId);
if (status != AMEDIA_OK) return status;
int32_t idx = 0;
AMediaCodecBufferInfo frameInfo;
while (1) {
memset(&frameInfo, 0, sizeof(AMediaCodecBufferInfo));
void *csdBuffer = getCSDSample(frameInfo, idx);
if (!csdBuffer || !frameInfo.size) break;
idx++;
}
mStats->setStartTime();
while (1) {
int32_t status = getFrameSample(frameInfo);
if (status || !frameInfo.size) break;
mStats->addOutputTime();
}
if (mFormat) {
AMediaFormat_delete(mFormat);
mFormat = nullptr;
}
AMediaExtractor_unselectTrack(mExtractor, trackId);
return AMEDIA_OK;
}
void Extractor::dumpStatistics(string inputReference) {
string operation = "extract";
mStats->dumpStatistics(operation, inputReference, mDurationUs);
}
void Extractor::deInitExtractor() {
if (mFrameBuf) {
free(mFrameBuf);
mFrameBuf = nullptr;
}
int64_t sTime = mStats->getCurTime();
if (mExtractor) {
// TODO: (b/140128505) Multiple calls result in DoS.
// Uncomment call to AMediaExtractor_delete() once this is resolved
// AMediaExtractor_delete(mExtractor);
mExtractor = nullptr;
}
int64_t eTime = mStats->getCurTime();
int64_t deInitTime = mStats->getTimeDiff(sTime, eTime);
mStats->setDeInitTime(deInitTime);
}