NuMediaExtractor 使用随笔
记录一个随笔改动,有个改法是想获取片源中某个特定的信息,然后根据其来判断选择player,在MediaPlayerFactory@scoreFactory 中就可以直接调用extractor中来获取extractor中一些mime信息
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
int fd,
int64_t offset,
int64_t length,
float /*curScore*/) {
// ...
sp<NuMediaExtractor> extractor = new NuMediaExtractor;
extractor->setDataSource(fd, 0, 0x7ffffffffffffffL);
size_t nums = extractor->countTracks();
sp<AMessage> format;
AString mime;
for (size_t i=0; i<nums; i++) {
if (extractor->getTrackFormat(i, &format) == OK
&& format->findString("mime", &mime)) {
if (!strncasecmp(mime.c_str(), "text/pgs", 8)) {
return 1.2;
}
}
}
// ...
}
然后看了下这个用法其实在NDK中就有了,具体看 frameworks/av/media/ndk/NdkMediaExtractor.cpp
在Android P中的frameworks/base/media/jni/soundpool/SoundPool.cpp代码也可以看到其用法
static status_t decode(int fd, int64_t offset, int64_t length,
uint32_t *rate, int *numChannels, audio_format_t *audioFormat,
sp<MemoryHeapBase> heap, size_t *memsize) {
ALOGV("fd %d, offset %" PRId64 ", size %" PRId64, fd, offset, length);
AMediaExtractor *ex = AMediaExtractor_new();
status_t err = AMediaExtractor_setDataSourceFd(ex, fd, offset, length);
if (err != AMEDIA_OK) {
AMediaExtractor_delete(ex);
return err;
}
*audioFormat = AUDIO_FORMAT_PCM_16_BIT;
size_t numTracks = AMediaExtractor_getTrackCount(ex);
for (size_t i = 0; i < numTracks; i++) {
AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
const char *mime;
if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
AMediaExtractor_delete(ex);
AMediaFormat_delete(format);
return UNKNOWN_ERROR;
}
if (strncmp(mime, "audio/", 6) == 0) {
AMediaCodec *codec = AMediaCodec_createDecoderByType(mime);
if (codec == NULL
|| AMediaCodec_configure(codec, format,
NULL /* window */, NULL /* drm */, 0 /* flags */) != AMEDIA_OK
|| AMediaCodec_start(codec) != AMEDIA_OK
|| AMediaExtractor_selectTrack(ex, i) != AMEDIA_OK) {
AMediaExtractor_delete(ex);
AMediaCodec_delete(codec);
AMediaFormat_delete(format);
return UNKNOWN_ERROR;
}
bool sawInputEOS = false;
bool sawOutputEOS = false;
uint8_t* writePos = static_cast<uint8_t*>(heap->getBase());
size_t available = heap->getSize();
size_t written = 0;
AMediaFormat_delete(format);
format = AMediaCodec_getOutputFormat(codec);
while (!sawOutputEOS) {
if (!sawInputEOS) {
ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
ALOGV("input buffer %zd", bufidx);
if (bufidx >= 0) {
size_t bufsize;
uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
if (buf == nullptr) {
ALOGE("AMediaCodec_getInputBuffer returned nullptr, short decode");
break;
}
int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
ALOGV("read %d", sampleSize);
if (sampleSize < 0) {
sampleSize = 0;
sawInputEOS = true;
ALOGV("EOS");
}
int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
media_status_t mstatus = AMediaCodec_queueInputBuffer(codec, bufidx,
0 /* offset */, sampleSize, presentationTimeUs,
sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
if (mstatus != AMEDIA_OK) {
// AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
ALOGE("AMediaCodec_queueInputBuffer returned status %d, short decode",
(int)mstatus);
break;
}
(void)AMediaExtractor_advance(ex);
}
}
AMediaCodecBufferInfo info;
int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
ALOGV("dequeueoutput returned: %d", status);
if (status >= 0) {
if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
ALOGV("output EOS");
sawOutputEOS = true;
}
ALOGV("got decoded buffer size %d", info.size);
uint8_t *buf = AMediaCodec_getOutputBuffer(codec, status, NULL /* out_size */);
if (buf == nullptr) {
ALOGE("AMediaCodec_getOutputBuffer returned nullptr, short decode");
break;
}
size_t dataSize = info.size;
if (dataSize > available) {
dataSize = available;
}
memcpy(writePos, buf + info.offset, dataSize);
writePos += dataSize;
written += dataSize;
available -= dataSize;
media_status_t mstatus = AMediaCodec_releaseOutputBuffer(
codec, status, false /* render */);
if (mstatus != AMEDIA_OK) {
// AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
ALOGE("AMediaCodec_releaseOutputBuffer returned status %d, short decode",
(int)mstatus);
break;
}
if (available == 0) {
// there might be more data, but there's no space for it
sawOutputEOS = true;
}
} else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
ALOGV("output buffers changed");
} else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
AMediaFormat_delete(format);
format = AMediaCodec_getOutputFormat(codec);
ALOGV("format changed to: %s", AMediaFormat_toString(format));
} else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
ALOGV("no output buffer right now");
} else if (status <= AMEDIA_ERROR_BASE) {
ALOGE("decode error: %d", status);
break;
} else {
ALOGV("unexpected info code: %d", status);
}
}
(void)AMediaCodec_stop(codec);
(void)AMediaCodec_delete(codec);
(void)AMediaExtractor_delete(ex);
if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, numChannels)) {
(void)AMediaFormat_delete(format);
return UNKNOWN_ERROR;
}
(void)AMediaFormat_delete(format);
*memsize = written;
return OK;
}
(void)AMediaFormat_delete(format);
}
(void)AMediaExtractor_delete(ex);
return UNKNOWN_ERROR;
}
还有一个是往上对接framework MediaExtractor 接口的使用,具体可以看这篇文章分析
MediaExtractor源码分析 - 简书
网友评论