blob: a2057ab436b3ce2710194b4e77ebd45fa406ebae [file] [log] [blame]
// Copyright 2018 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.
#include "goldfish_media_utils.h"
#include "goldfish_address_space.h"
#include <log/log.h>
#define DEBUG 0
#if DEBUG
# define DDD(...) ALOGD(__VA_ARGS__)
#else
# define DDD(...) ((void)0)
#endif
#include <memory>
#include <vector>
#include <mutex>
std::mutex sSingletonMutex;
std::unique_ptr<GoldfishMediaTransport> sTransport;
class GoldfishMediaTransportImpl : public GoldfishMediaTransport {
public:
GoldfishMediaTransportImpl();
~GoldfishMediaTransportImpl();
virtual void writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr = 0) override;
virtual bool sendOperation(MediaCodecType type, MediaOperation op, unsigned int offSetToStartAddr = 0) override;
virtual uint8_t* getBaseAddr() const override;
virtual uint8_t* getInputAddr(unsigned int offSet = 0) const override;
virtual uint8_t* getOutputAddr() const override;
virtual uint8_t* getReturnAddr(unsigned int offSet = 0) const override;
virtual __u64 offsetOf(uint64_t addr) const override;
public:
// each lot has 8 M
virtual int getMemorySlot() override {
std::lock_guard<std::mutex> g{mMemoryMutex};
for (int i = mMemoryLotsAvailable.size() - 1; i >=0 ; --i) {
if (mMemoryLotsAvailable[i]) {
mMemoryLotsAvailable[i] = false;
return i;
}
}
return -1;
}
virtual void returnMemorySlot(int lot) override {
if (lot < 0 || lot >= mMemoryLotsAvailable.size()) {
return;
}
std::lock_guard<std::mutex> g{mMemoryMutex};
if (mMemoryLotsAvailable[lot] == false) {
mMemoryLotsAvailable[lot] = true;
} else {
ALOGE("Error, cannot twice");
}
}
private:
std::mutex mMemoryMutex;
std::vector<bool> mMemoryLotsAvailable = {true, true, true, true};
address_space_handle_t mHandle;
uint64_t mOffset;
uint64_t mPhysAddr;
uint64_t mSize;
void* mStartPtr = nullptr;
// MediaCodecType will be or'd together with the metadata, so the highest 8-bits
// will have the type.
static __u64 makeMetadata(MediaCodecType type,
MediaOperation op, uint64_t offset);
// Chunk size for parameters/return data
static constexpr size_t kParamSizeBytes = 4096; // 4K
// Chunk size for input
static constexpr size_t kInputSizeBytes = 4096 * 4096; // 16M
// Chunk size for output
static constexpr size_t kOutputSizeBytes = 4096 * 4096; // 16M
// Maximum number of parameters that can be passed
static constexpr size_t kMaxParams = 32;
// Offset from the memory region for return data (8 is size of
// a parameter in bytes)
static constexpr size_t kReturnOffset = 8 * kMaxParams;
};
GoldfishMediaTransportImpl::~GoldfishMediaTransportImpl() {
if(mHandle >= 0) {
goldfish_address_space_close(mHandle);
mHandle = -1;
}
}
GoldfishMediaTransportImpl::GoldfishMediaTransportImpl() {
// Allocate host memory; the contiguous memory region will be laid out as
// follows:
// ========================================================
// | kParamSizeBytes | kInputSizeBytes | kOutputSizeBytes |
// ========================================================
mHandle = goldfish_address_space_open();
if (mHandle < 0) {
ALOGE("Failed to ping host to allocate memory");
abort();
}
mSize = kParamSizeBytes + kInputSizeBytes + kOutputSizeBytes;
bool success = goldfish_address_space_allocate(mHandle, mSize, &mPhysAddr, &mOffset);
if (success) {
ALOGI("successfully allocated %d bytes in goldfish_address_block", (int)mSize);
mStartPtr = goldfish_address_space_map(mHandle, mOffset, mSize);
ALOGI("guest address is %p", mStartPtr);
struct goldfish_address_space_ping pingInfo;
pingInfo.metadata = GoldfishAddressSpaceSubdeviceType::Media;
pingInfo.offset = mOffset;
if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
ALOGE("Failed to ping host to allocate memory");
abort();
return;
} else {
ALOGI("successfully pinged host to allocate memory");
}
} else {
ALOGE("failed to allocate %d bytes in goldfish_address_block", (int)mSize);
abort();
}
}
// static
GoldfishMediaTransport* GoldfishMediaTransport::getInstance() {
std::lock_guard<std::mutex> g{sSingletonMutex};
if (sTransport == nullptr) {
sTransport.reset(new GoldfishMediaTransportImpl());
}
return sTransport.get();
}
// static
__u64 GoldfishMediaTransportImpl::makeMetadata(MediaCodecType type,
MediaOperation op, uint64_t offset) {
// Shift |type| into the highest 8-bits, leaving the lower bits for other
// metadata.
offset = offset >> 20;
return ((__u64)type << (64 - 8)) | (offset << 8) | static_cast<uint8_t>(op);
}
uint8_t* GoldfishMediaTransportImpl::getInputAddr(unsigned int offSet) const {
return (uint8_t*)mStartPtr + kParamSizeBytes + offSet;
}
uint8_t* GoldfishMediaTransportImpl::getOutputAddr() const {
return getInputAddr() + kInputSizeBytes;
}
uint8_t* GoldfishMediaTransportImpl::getBaseAddr() const {
return (uint8_t*)mStartPtr;
}
uint8_t* GoldfishMediaTransportImpl::getReturnAddr(unsigned int offSet) const {
return (uint8_t*)mStartPtr + kReturnOffset + offSet;
}
__u64 GoldfishMediaTransportImpl::offsetOf(uint64_t addr) const {
return addr - (uint64_t)mStartPtr;
}
void GoldfishMediaTransportImpl::writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr) {
uint8_t* p = (uint8_t*)mStartPtr + (offSetToStartAddr);
uint64_t* pint = (uint64_t*)(p + 8 * num);
*pint = val;
}
bool GoldfishMediaTransportImpl::sendOperation(MediaCodecType type,
MediaOperation op, unsigned int offSetToStartAddr) {
struct goldfish_address_space_ping pingInfo;
pingInfo.metadata = makeMetadata(type, op, offSetToStartAddr);
pingInfo.offset = mOffset; // + (offSetToStartAddr);
if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
ALOGE("failed to ping host");
abort();
return false;
} else {
DDD("successfully pinged host for operation type=%d, op=%d", (int)type, (int)op);
}
return true;
}