void GPUHardware::binderDied(const wp<IBinder>& who) { Mutex::Autolock _l(mLock); pid_t pid = mRegisteredClients.valueFor(who); if (pid != 0) { ssize_t index = mClients.indexOfKey(pid); if (index >= 0) { //LOGD("*** removing client at %d", index); Client& client(mClients.editValueAt(index)); client.revokeAllHeaps(); // not really needed in theory mClients.removeItemsAt(index); if (mClients.size() == 0) { //LOGD("*** was last client closing everything"); mCallback.clear(); mAllocator.clear(); mCurrentAllocator.clear(); mSMIHeap.clear(); mREGHeap.clear(); // NOTE: we cannot clear the EBI heap because surfaceflinger // itself may be using it, since this is where surfaces // are allocated. if we're in the middle of compositing // a surface (even if its process just died), we cannot // rip the heap under our feet. mOwner = NO_OWNER; } } } }
void HeapCache::pin_heap(const sp<IBinder>& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info(mHeapCache.editValueAt(i)); android_atomic_inc(&info.count); binder->linkToDeath(this); } else { LOGE("pin_heap binder=%p not found!!!", binder.get()); } }
GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid) { ssize_t index = mClients.indexOfKey(pid); if (index < 0) { Client client; client.pid = pid; client.smi.heap = mSMIHeap; client.ebi.heap = mEBIHeap; client.reg.heap = mREGHeap; index = mClients.add(pid, client); } Client& client(mClients.editValueAt(index)); client.createClientHeaps(); return client; }
void GPUHardware::releaseLocked() { //LOGD("revoking gpu from pid %d", mOwner); if (mOwner != NO_OWNER) { // this may fail because the client might have died, and have // been removed from the list. ssize_t index = mClients.indexOfKey(mOwner); if (index >= 0) { Client& client(mClients.editValueAt(index)); client.revokeAllHeaps(); } mOwner = NO_OWNER; mCurrentAllocator.clear(); mCallback.clear(); } }
void HeapCache::free_heap(const wp<IBinder>& binder) { sp<IMemoryHeap> rel; { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info(mHeapCache.editValueAt(i)); int32_t c = android_atomic_dec(&info.count); if (c == 1) { ALOGD_IF(VERBOSE, "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.unsafe_get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, info.count); rel = mHeapCache.valueAt(i).heap; mHeapCache.removeItemsAt(i); } } else { ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get()); } } }
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info = mHeapCache.editValueAt(i); ALOGD_IF(VERBOSE, "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, info.count); android_atomic_inc(&info.count); return info.heap; } else { heap_info_t info; info.heap = interface_cast<IMemoryHeap>(binder); info.count = 1; //ALOGD("adding binder=%p, heap=%p, count=%d", // binder.get(), info.heap.get(), info.count); mHeapCache.add(binder, info); return info.heap; } }
static int decode( const android::sp<android::ALooper> &looper, const char *path, bool useAudio, bool useVideo, const android::sp<android::Surface> &surface) { using namespace android; static int64_t kTimeout = 500ll; sp<NuMediaExtractor> extractor = new NuMediaExtractor; if (extractor->setDataSource(path) != OK) { fprintf(stderr, "unable to instantiate extractor.\n"); return 1; } KeyedVector<size_t, CodecState> stateByTrack; bool haveAudio = false; bool haveVideo = false; for (size_t i = 0; i < extractor->countTracks(); ++i) { sp<AMessage> format; status_t err = extractor->getTrackFormat(i, &format); CHECK_EQ(err, (status_t)OK); AString mime; CHECK(format->findString("mime", &mime)); bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6); bool isVideo = !strncasecmp(mime.c_str(), "video/", 6); if (useAudio && !haveAudio && isAudio) { haveAudio = true; } else if (useVideo && !haveVideo && isVideo) { haveVideo = true; } else { continue; } ALOGV("selecting track %d", i); err = extractor->selectTrack(i); CHECK_EQ(err, (status_t)OK); CodecState *state = &stateByTrack.editValueAt(stateByTrack.add(i, CodecState())); state->mNumBytesDecoded = 0; state->mNumBuffersDecoded = 0; state->mIsAudio = isAudio; state->mCodec = MediaCodec::CreateByType( looper, mime.c_str(), false /* encoder */); CHECK(state->mCodec != NULL); err = state->mCodec->configure( format, isVideo ? surface : NULL, NULL /* crypto */, 0 /* flags */); CHECK_EQ(err, (status_t)OK); state->mSignalledInputEOS = false; state->mSawOutputEOS = false; } CHECK(!stateByTrack.isEmpty()); int64_t startTimeUs = ALooper::GetNowUs(); for (size_t i = 0; i < stateByTrack.size(); ++i) { CodecState *state = &stateByTrack.editValueAt(i); sp<MediaCodec> codec = state->mCodec; CHECK_EQ((status_t)OK, codec->start()); CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers)); CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers)); ALOGV("got %d input and %d output buffers", state->mInBuffers.size(), state->mOutBuffers.size()); } bool sawInputEOS = false; for (;;) { if (!sawInputEOS) { size_t trackIndex; status_t err = extractor->getSampleTrackIndex(&trackIndex); if (err != OK) { ALOGV("saw input eos"); sawInputEOS = true; } else { CodecState *state = &stateByTrack.editValueFor(trackIndex); size_t index; err = state->mCodec->dequeueInputBuffer(&index, kTimeout); if (err == OK) { ALOGV("filling input buffer %d", index); const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index); err = extractor->readSampleData(buffer); CHECK_EQ(err, (status_t)OK); int64_t timeUs; err = extractor->getSampleTime(&timeUs); CHECK_EQ(err, (status_t)OK); uint32_t bufferFlags = 0; err = state->mCodec->queueInputBuffer( index, 0 /* offset */, buffer->size(), timeUs, bufferFlags); CHECK_EQ(err, (status_t)OK); extractor->advance(); } else { CHECK_EQ(err, -EAGAIN); } } } else { for (size_t i = 0; i < stateByTrack.size(); ++i) { CodecState *state = &stateByTrack.editValueAt(i); if (!state->mSignalledInputEOS) { size_t index; status_t err = state->mCodec->dequeueInputBuffer(&index, kTimeout); if (err == OK) { ALOGV("signalling input EOS on track %d", i); err = state->mCodec->queueInputBuffer( index, 0 /* offset */, 0 /* size */, 0ll /* timeUs */, MediaCodec::BUFFER_FLAG_EOS); CHECK_EQ(err, (status_t)OK); state->mSignalledInputEOS = true; } else { CHECK_EQ(err, -EAGAIN); } } } } bool sawOutputEOSOnAllTracks = true; for (size_t i = 0; i < stateByTrack.size(); ++i) { CodecState *state = &stateByTrack.editValueAt(i); if (!state->mSawOutputEOS) { sawOutputEOSOnAllTracks = false; break; } } if (sawOutputEOSOnAllTracks) { break; } for (size_t i = 0; i < stateByTrack.size(); ++i) { CodecState *state = &stateByTrack.editValueAt(i); if (state->mSawOutputEOS) { continue; } size_t index; size_t offset; size_t size; int64_t presentationTimeUs; uint32_t flags; status_t err = state->mCodec->dequeueOutputBuffer( &index, &offset, &size, &presentationTimeUs, &flags, kTimeout); if (err == OK) { ALOGV("draining output buffer %d, time = %lld us", index, presentationTimeUs); ++state->mNumBuffersDecoded; state->mNumBytesDecoded += size; err = state->mCodec->releaseOutputBuffer(index); CHECK_EQ(err, (status_t)OK); if (flags & MediaCodec::BUFFER_FLAG_EOS) { ALOGV("reached EOS on output."); state->mSawOutputEOS = true; } } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { ALOGV("INFO_OUTPUT_BUFFERS_CHANGED"); CHECK_EQ((status_t)OK, state->mCodec->getOutputBuffers(&state->mOutBuffers)); ALOGV("got %d output buffers", state->mOutBuffers.size()); } else if (err == INFO_FORMAT_CHANGED) { sp<AMessage> format; CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format)); ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str()); } else { CHECK_EQ(err, -EAGAIN); } } } int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs; for (size_t i = 0; i < stateByTrack.size(); ++i) { CodecState *state = &stateByTrack.editValueAt(i); CHECK_EQ((status_t)OK, state->mCodec->release()); if (state->mIsAudio) { printf("track %zu: %" PRId64 " bytes received. %.2f KB/sec\n", i, state->mNumBytesDecoded, state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); } else { printf("track %zu: %" PRId64 " frames decoded, %.2f fps. %" PRId64 " bytes received. %.2f KB/sec\n", i, state->mNumBuffersDecoded, state->mNumBuffersDecoded * 1E6 / elapsedTimeUs, state->mNumBytesDecoded, state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); } } return 0; }