blob: e79a09ea3ac15990ffe1e5ad6f1969c042bf0aa0 [file] [log] [blame]
#include <media/stagefright/NuMediaExtractor.h>
#include <media/stagefright/AnotherPacketSource.h>
#include <media/stagefright/ATSParser.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
namespace android {
NuMediaExtractor::NuMediaExtractor()
: mFlags(0),
mParser(new ATSParser),
mFile(NULL),
mNumTracks(0),
mAudioTrackIndex(-1),
mVideoTrackIndex(-1),
mNextIndex(-1) {
mFinalResult[0] = mFinalResult[1] = OK;
}
NuMediaExtractor::~NuMediaExtractor() {
if (mFile) {
fclose(mFile);
mFile = NULL;
}
}
status_t NuMediaExtractor::setDataSource(const char *path) {
if (mFile) {
return UNKNOWN_ERROR;
}
mFile = fopen(path, "rb");
if (!mFile) {
return -ENOENT;
}
for (size_t i = 0; i < 1024; ++i) {
if (mVideoSource == NULL) {
mVideoSource = mParser->getSource(ATSParser::VIDEO);
}
if (mAudioSource == NULL) {
mAudioSource = mParser->getSource(ATSParser::AUDIO);
}
if (feedMoreData() != OK) {
break;
}
}
if (mAudioSource != NULL && mAudioSource->getFormat() == NULL) {
mAudioSource.reset();
}
if (mVideoSource != NULL && mVideoSource->getFormat() == NULL) {
mVideoSource.reset();
}
mNumTracks = 0;
if (mAudioSource != NULL) {
mAudioTrackIndex = mNumTracks;
++mNumTracks;
}
if (mVideoSource != NULL) {
mVideoTrackIndex = mNumTracks;
++mNumTracks;
}
return OK;
}
size_t NuMediaExtractor::countTracks() const {
return mNumTracks;
}
status_t NuMediaExtractor::getTrackFormat(
size_t index, std::shared_ptr<AMessage> *format) const {
CHECK_LT(index, mNumTracks);
std::shared_ptr<MetaData> meta;
if ((ssize_t)index == mAudioTrackIndex) {
meta = mAudioSource->getFormat();
} else {
meta = mVideoSource->getFormat();
}
return convertMetaDataToMessage(meta, format);
}
status_t NuMediaExtractor::selectTrack(size_t index) {
CHECK_LT(index, mNumTracks);
if ((ssize_t)index == mAudioTrackIndex) {
mFlags |= FLAG_AUDIO_SELECTED;
} else {
mFlags |= FLAG_VIDEO_SELECTED;
}
return OK;
}
status_t NuMediaExtractor::getSampleTime(int64_t *timeUs) {
fetchSamples();
if (mNextIndex < 0) {
return ERROR_END_OF_STREAM;
}
CHECK(mNextBuffer[mNextIndex]->meta()->findInt64("timeUs", timeUs));
return OK;
}
status_t NuMediaExtractor::getSampleTrackIndex(size_t *index) {
fetchSamples();
if (mNextIndex < 0) {
return ERROR_END_OF_STREAM;
}
*index = mNextIndex;
return OK;
}
status_t NuMediaExtractor::readSampleData(std::shared_ptr<ABuffer> accessUnit) {
fetchSamples();
if (mNextIndex < 0) {
return ERROR_END_OF_STREAM;
}
accessUnit->setRange(0, mNextBuffer[mNextIndex]->size());
memcpy(accessUnit->data(),
mNextBuffer[mNextIndex]->data(),
mNextBuffer[mNextIndex]->size());
return OK;
}
status_t NuMediaExtractor::advance() {
if (mNextIndex < 0) {
return ERROR_END_OF_STREAM;
}
mNextBuffer[mNextIndex].reset();
mNextIndex = -1;
return OK;
}
void NuMediaExtractor::fetchSamples() {
status_t err;
if ((mFlags & FLAG_AUDIO_SELECTED)
&& mNextBuffer[mAudioTrackIndex] == NULL
&& mFinalResult[mAudioTrackIndex] == OK) {
status_t finalResult;
while (!mAudioSource->hasBufferAvailable(&finalResult)
&& finalResult == OK) {
feedMoreData();
}
err = mAudioSource->dequeueAccessUnit(&mNextBuffer[mAudioTrackIndex]);
if (err != OK) {
mFinalResult[mAudioTrackIndex] = err;
}
}
if ((mFlags & FLAG_VIDEO_SELECTED)
&& mNextBuffer[mVideoTrackIndex] == NULL
&& mFinalResult[mVideoTrackIndex] == OK) {
status_t finalResult;
while (!mVideoSource->hasBufferAvailable(&finalResult)
&& finalResult == OK) {
feedMoreData();
}
err = mVideoSource->dequeueAccessUnit(&mNextBuffer[mVideoTrackIndex]);
if (err != OK) {
mFinalResult[mVideoTrackIndex] = err;
}
}
bool haveValidTime = false;
int64_t minTimeUs = -1ll;
size_t minIndex = 0;
if ((mFlags & FLAG_AUDIO_SELECTED)
&& mNextBuffer[mAudioTrackIndex] != NULL) {
CHECK(mNextBuffer[mAudioTrackIndex]->meta()->findInt64("timeUs", &minTimeUs));
haveValidTime = true;
minIndex = mAudioTrackIndex;
}
if ((mFlags & FLAG_VIDEO_SELECTED)
&& mNextBuffer[mVideoTrackIndex] != NULL) {
int64_t timeUs;
CHECK(mNextBuffer[mVideoTrackIndex]->meta()->findInt64("timeUs", &timeUs));
if (!haveValidTime || timeUs < minTimeUs) {
haveValidTime = true;
minTimeUs = timeUs;
minIndex = mVideoTrackIndex;
}
}
if (!haveValidTime) {
mNextIndex = -1;
} else {
mNextIndex = minIndex;
}
}
status_t NuMediaExtractor::feedMoreData() {
uint8_t packet[188];
ssize_t n = fread(packet, 1, sizeof(packet), mFile);
status_t err;
if (n < (ssize_t)sizeof(packet)) {
err = UNKNOWN_ERROR;
} else {
err = mParser->feedTSPacket(packet, sizeof(packet));
}
if (err != OK) {
mParser->signalEOS(err);
return err;
}
return OK;
}
} // namespace android