书接前文
omxcodec创建完了以后,后面就要开始读取数据,解码,送出数据一系列的操作
接着看initvideodecoder,create omxcodec以后,调用了strat方法,代码如下
{
CODEC_LOGV("OMXCodec::start ");
Mutex::Autolock autoLock(mLock);
if (mState != LOADED) {
return UNKNOWN_ERROR;
}
sp<MetaData> params = new MetaData;
if (mQuirks & kWantsNALFragments) {
params->setInt32(kKeyWantsNALFragments, true);
}
if (meta) {
int64_t startTimeUs = 0;
int64_t timeUs;
if (meta->findInt64(kKeyTime, &timeUs)) {
startTimeUs = timeUs;
}
params->setInt64(kKeyTime, startTimeUs);
}
status_t err = mSource->start(params.get());
if (err != OK) {
return err;
}
mCodecSpecificDataIndex = 0;
mInitialBufferSubmit = true;
mSignalledEOS = false;
mNoMoreOutputData = false;
mOutputPortSettingsHaveChanged = false;
mSeekTimeUs = -1;
mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
mTargetTimeUs = -1;
mFilledBuffers.clear();
mPaused = false;
err = init();
if (err != OK) {
ALOGV("init failed, so stop source");
mSource->stop();
}
return err;
}
初始化一些参数,init函数接着看
{
// mLock is held.
CHECK_EQ((int)mState, (int)LOADED);
status_t err;
if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
setState(LOADED_TO_IDLE);
}
err = allocateBuffers();
if (err != (status_t)OK) {
return err;
}
if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
CHECK_EQ(err, (status_t)OK);
setState(LOADED_TO_IDLE);
}
while (mState != EXECUTING && mState != ERROR) {
mAsyncCompletion.wait(mLock);
}
return mState == ERROR ? UNKNOWN_ERROR : OK;
}
omxcodec有一些状态的转换,然后就是allocateBuffers这个函数了
{
if (mNativeWindow != NULL && portIndex == kPortIndexOutput) {
return allocateOutputBuffersFromNativeWindow();
}
if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) {
ALOGE("protected output buffers must be stent to an ANativeWindow");
return PERMISSION_DENIED;
}
status_t err = OK;
if ((mFlags & kStoreMetaDataInVideoBuffers)
&& portIndex == kPortIndexInput) {
err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);
if (err != OK) {
ALOGE("Storing meta data in video buffers is not supported");
return err;
}
}
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = portIndex;
err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
if (err != OK) {
return err;
}
size_t totalSize = def.nBufferCountActual * def.nBufferSize;
mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec");
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
CHECK(mem.get() != NULL);
BufferInfo info;
info.mData = NULL;
info.mSize = def.nBufferSize;
IOMX::buffer_id buffer;
if (portIndex == kPortIndexInput
&& ((mQuirks & kRequiresAllocateBufferOnInputPorts)
|| (mFlags & kUseSecureInputBuffers))) {
if (mOMXLivesLocally) {
mem.clear();
err = mOMX->allocateBuffer(
mNode, portIndex, def.nBufferSize, &buffer,
&info.mData);
} else {
err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &buffer);
}
} else if (portIndex == kPortIndexOutput
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
if (mOMXLivesLocally) {
mem.clear();
err = mOMX->allocateBuffer(
mNode, portIndex, def.nBufferSize, &buffer,
&info.mData);
} else {
err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &buffer);
}
} else {
err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
}
if (err != OK) {
ALOGE("allocate_buffer_with_backup failed");
return err;
}
if (mem != NULL) {
info.mData = mem->pointer();
}
info.mBuffer = buffer;
info.mStatus = OWNED_BY_US;
info.mMem = mem;
info.mMediaBuffer = NULL;
if (portIndex == kPortIndexOutput) {
if (!(mOMXLivesLocally
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)
&& (mQuirks & kDefersOutputBufferAllocation))) {
// If the node does not fill in the buffer ptr at this time,
// we will defer creating the MediaBuffer until receiving
// the first FILL_BUFFER_DONE notification instead.
info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize);
info.mMediaBuffer->setObserver(this);
}
}
mPortBuffers[portIndex].push(info);
CODEC_LOGV("allocated buffer %p on %s port", buffer,
portIndex == kPortIndexInput ? "input" : "output");
}
if (portIndex == kPortIndexOutput) {
sp<MetaData> meta = mSource->getFormat();
int32_t delay = 0;
if (!meta->findInt32(kKeyEncoderDelay, &delay)) {
delay = 0;
}
int32_t padding = 0;
if (!meta->findInt32(kKeyEncoderPadding, &padding)) {
padding = 0;
}
int32_t numchannels = 0;
if (delay + padding) {
if (mOutputFormat->findInt32(kKeyChannelCount, &numchannels)) {
size_t frameSize = numchannels * sizeof(int16_t);
if (mSkipCutBuffer != NULL) {
size_t prevbuffersize = mSkipCutBuffer->size();
if (prevbuffersize != 0) {
ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize);
}
}
mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize);
}
}
}
// dumpPortStatus(portIndex);
if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {
Vector<MediaBuffer *> buffers;
for (size_t i = 0; i < def.nBufferCountActual; ++i) {
const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i);
MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize);
buffers.push(mbuf);
}
status_t err = mSource->setBuffers(buffers);
if (err != OK) {
for (size_t i = 0; i < def.nBufferCountActual; ++i) {
buffers.editItemAt(i)->release();
}
buffers.clear();
CODEC_LOGE(
"Codec requested to use secure input buffers but "
"upstream source didn't support that.");
return err;
}
}
return OK;
}
这个函数挺重要的,omx node是通过port来通信的,inport和output,输入node只有inport,而输出node就只有outport,中间解码的node就需要两个port
先看inport的内存分配,有两个函数 allocatebuffer 和 usebuffer,如果不需要node重新分配内存,那就只需要使用application分配的内存,否则会在port上面重新分配内存
为什么需要再port上面重新分配内存呢,可能是DRM等原因考虑。
在看一下outport的分配
{
// Get the number of buffers needed.
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
if (err != OK) {
return err;
}
err = native_window_set_buffers_geometry(
mNativeWindow.get(),
def.format.video.nFrameWidth,
def.format.video.nFrameHeight,
def.format.video.eColorFormat);
if (err != 0) {
ALOGE("native_window_set_buffers_geometry failed: %s (%d)",
strerror(-err), -err);
return err;
}
initNativeWindowCrop();
err = applyRotation();
if (err != OK) {
return err;
}
// Set up the native window.
OMX_U32 usage = 0;
err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage);
if (err != 0) {
ALOGW("querying usage flags from OMX IL component failed: %d", err);
// XXX: Currently this error is logged, but not fatal.
usage = 0;
}
if (mFlags & kEnableGrallocUsageProtected) {
usage |= GRALLOC_USAGE_PROTECTED;
}
// Make sure to check whether either Stagefright or the video decoder
// requested protected buffers.
if (usage & GRALLOC_USAGE_PROTECTED) {
// Verify that the ANativeWindow sends images directly to
// SurfaceFlinger.
int queuesToNativeWindow = 0;
err = mNativeWindow->query(
mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
&queuesToNativeWindow);
if (err != 0) {
ALOGE("error authenticating native window: %d", err);
return err;
}
if (queuesToNativeWindow != 1) {
ALOGE("native window could not be authenticated");
return PERMISSION_DENIED;
}
}
ALOGV("native_window_set_usage usage=0x%lx", usage);
/* all commons */
usage |= (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
ALOGV("native_window_set_usage usage=0x%lx", usage);
err = native_window_set_usage(
mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
if (err != 0) {
ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
return err;
}
int minUndequeuedBufs = 0;
err = mNativeWindow->query(mNativeWindow.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
if (err != 0) {
ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
strerror(-err), -err);
return err;
}
// XXX: Is this the right logic to use? It's not clear to me what the OMX
// buffer counts refer to - how do they account for the renderer holding on
// to buffers?
if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
def.nBufferCountActual = newBufferCount;
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
if (err != OK) {
CODEC_LOGE("setting nBufferCountActual to %lu failed: %d",
newBufferCount, err);
return err;
}
}
err = native_window_set_buffer_count(
mNativeWindow.get(), def.nBufferCountActual);
if (err != 0) {
ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
-err);
return err;
}
CODEC_LOGV("allocating %lu buffers from a native window of size %lu on "
"output port", def.nBufferCountActual, def.nBufferSize);
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
ANativeWindowBuffer* buf;
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
break;
}
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
BufferInfo info;
info.mData = NULL;
info.mSize = def.nBufferSize;
info.mStatus = OWNED_BY_US;
info.mMem = NULL;
info.mMediaBuffer = new MediaBuffer(graphicBuffer);
info.mMediaBuffer->setObserver(this);
mPortBuffers[kPortIndexOutput].push(info);
IOMX::buffer_id bufferId;
err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer,
&bufferId);
if (err != 0) {
CODEC_LOGE("registering GraphicBuffer with OMX IL component "
"failed: %d", err);
break;
}
mPortBuffers[kPortIndexOutput].editItemAt(i).mBuffer = bufferId;
CODEC_LOGV("registered graphic buffer with ID %p (pointer = %p)",
bufferId, graphicBuffer.get());
}
OMX_U32 cancelStart;
OMX_U32 cancelEnd;
if (err != 0) {
// If an error occurred while dequeuing we need to cancel any buffers
// that were dequeued.
cancelStart = 0;
cancelEnd = mPortBuffers[kPortIndexOutput].size();
} else {
// Return the last two buffers to the native window.
cancelStart = def.nBufferCountActual - minUndequeuedBufs;
cancelEnd = def.nBufferCountActual;
}
for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(i);
cancelBufferToNativeWindow(info);
}
return err;
}
start的准备也做完了,主要是给port分配内存,基本也只是摘抄代码了
start以后,就要kick off了,下篇开始播放了