// Copyright 2019 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 "host-common/address_space_host_media.h" #include "host-common/vm_operations.h" #include "aemu/base/AlignedBuf.h" #define AS_DEVICE_DEBUG 0 #if AS_DEVICE_DEBUG #define AS_DEVICE_DPRINT(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); #else #define AS_DEVICE_DPRINT(fmt,...) #endif namespace android { namespace emulation { enum class DecoderType : uint8_t { Vpx = 0, H264 = 1, }; AddressSpaceHostMediaContext::AddressSpaceHostMediaContext( const struct AddressSpaceCreateInfo& create, const address_space_device_control_ops* ops) : mControlOps(ops) { // The memory is allocated in the snapshot load if called from a snapshot load(). if (!create.fromSnapshot) { mGuestAddr = create.physAddr; allocatePages(create.physAddr, kNumPages); } } AddressSpaceHostMediaContext::~AddressSpaceHostMediaContext() { deallocatePages(mGuestAddr, kNumPages); } void AddressSpaceHostMediaContext::perform(AddressSpaceDevicePingInfo *info) { handleMediaRequest(info); } AddressSpaceDeviceType AddressSpaceHostMediaContext::getDeviceType() const { return AddressSpaceDeviceType::Media; } void AddressSpaceHostMediaContext::save(base::Stream* stream) const { AS_DEVICE_DPRINT("Saving Host Media snapshot"); stream->putBe64(mGuestAddr); int numActiveDecoders = 0; if (mVpxDecoder != nullptr) { ++ numActiveDecoders; } if (mH264Decoder != nullptr) { ++ numActiveDecoders; } stream->putBe32(numActiveDecoders); if (mVpxDecoder != nullptr) { AS_DEVICE_DPRINT("Saving VpxDecoder snapshot"); stream->putBe32((uint32_t)DecoderType::Vpx); mVpxDecoder->save(stream); } if (mH264Decoder != nullptr) { AS_DEVICE_DPRINT("Saving H264Decoder snapshot"); stream->putBe32((uint32_t)DecoderType::H264); mH264Decoder->save(stream); } } bool AddressSpaceHostMediaContext::load(base::Stream* stream) { deallocatePages(mGuestAddr, kNumPages); AS_DEVICE_DPRINT("Loading Host Media snapshot"); mGuestAddr = stream->getBe64(); allocatePages(mGuestAddr, kNumPages); int numActiveDecoders = stream->getBe32(); for (int i = 0; i < numActiveDecoders; ++i) { stream->getBe32(); // TODO: Add support for virtio-gpu-as-video-decode // switch (t) { // case DecoderType::Vpx: // AS_DEVICE_DPRINT("Loading VpxDecoder snapshot"); // mVpxDecoder.reset(new MediaVpxDecoder); // mVpxDecoder->load(stream); // break; // case DecoderType::H264: // AS_DEVICE_DPRINT("Loading H264Decoder snapshot"); // mH264Decoder.reset(MediaH264Decoder::create()); // mH264Decoder->load(stream); // break; // default: // break; // } } return true; } void AddressSpaceHostMediaContext::allocatePages(uint64_t phys_addr, int num_pages) { mHostBuffer = android::aligned_buf_alloc(kAlignment, num_pages * 4096); mControlOps->add_memory_mapping( phys_addr, mHostBuffer, num_pages * 4096); AS_DEVICE_DPRINT("Allocating host memory for media context: guest_addr 0x%" PRIx64 ", 0x%" PRIx64, (uint64_t)phys_addr, (uint64_t)mHostBuffer); } void AddressSpaceHostMediaContext::deallocatePages(uint64_t phys_addr, int num_pages) { if (mHostBuffer == nullptr) { return; } mControlOps->remove_memory_mapping(phys_addr, mHostBuffer, num_pages * 4096); android::aligned_buf_free(mHostBuffer); mHostBuffer = nullptr; AS_DEVICE_DPRINT( "De-Allocating host memory for media context: guest_addr 0x%" PRIx64 ", 0x%" PRIx64, (uint64_t)phys_addr, (uint64_t)mHostBuffer); } // static MediaCodecType AddressSpaceHostMediaContext::getMediaCodecType(uint64_t metadata) { // Metadata has the following structure: // - Upper 8 bits has the codec type (MediaCodecType) // - Lower 56 bits has metadata specifically for that codec // // We need to hand the data off to the right codec depending on which // codec type we get. uint8_t ret = (uint8_t)(metadata >> (64 - 8)); return ret > static_cast(MediaCodecType::Max) ? MediaCodecType::Max : (MediaCodecType)ret; } // static MediaOperation AddressSpaceHostMediaContext::getMediaOperation(uint64_t metadata) { // Metadata has the following structure: // - Upper 8 bits has the codec type (MediaCodecType) // - Lower 56 bits has metadata specifically for that codec // // We need to hand the data off to the right codec depending on which // codec type we get. uint8_t ret = (uint8_t)(metadata & 0xFF); return ret > static_cast(MediaOperation::Max) ? MediaOperation::Max : (MediaOperation)ret; } static uint64_t getAddrSlot(uint64_t metadata) { uint64_t ret = metadata << 8; // get rid of typecode ret = ret >> 16; // get rid of opcode return ret; } void AddressSpaceHostMediaContext::handleMediaRequest(AddressSpaceDevicePingInfo *info) { auto codecType = getMediaCodecType(info->metadata); auto op = getMediaOperation(info->metadata); auto slot = getAddrSlot(info->metadata); uint64_t offSetAddr = slot << 20; AS_DEVICE_DPRINT("Got media request (type=%u, op=%u, slot=%lld)", static_cast(codecType), static_cast(op), (long long)(getAddrSlot(info->metadata))); switch (codecType) { case MediaCodecType::VP8Codec: case MediaCodecType::VP9Codec: // if (!mVpxDecoder) { // mVpxDecoder.reset(new MediaVpxDecoder); // } mVpxDecoder->handlePing( codecType, op, (uint8_t*)(mControlOps->get_host_ptr(info->phys_addr)) + offSetAddr); break; case MediaCodecType::H264Codec: // if (!mH264Decoder) { // mH264Decoder.reset(MediaH264Decoder::create()); // } mH264Decoder->handlePing( codecType, op, (uint8_t*)(mControlOps->get_host_ptr(info->phys_addr)) + offSetAddr); break; default: AS_DEVICE_DPRINT("codec type %d not implemented", (int)codecType); break; } } } // namespace emulation } // namespace android