1 // Copyright 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "host-common/address_space_host_media.h"
16 #include "host-common/vm_operations.h"
17 #include "aemu/base/AlignedBuf.h"
18 
19 #define AS_DEVICE_DEBUG 0
20 
21 #if AS_DEVICE_DEBUG
22 #define AS_DEVICE_DPRINT(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
23 #else
24 #define AS_DEVICE_DPRINT(fmt,...)
25 #endif
26 
27 namespace android {
28 namespace emulation {
29 
30 enum class DecoderType : uint8_t {
31     Vpx = 0,
32     H264 = 1,
33 };
34 
AddressSpaceHostMediaContext(const struct AddressSpaceCreateInfo & create,const address_space_device_control_ops * ops)35 AddressSpaceHostMediaContext::AddressSpaceHostMediaContext(
36     const struct AddressSpaceCreateInfo& create, const address_space_device_control_ops* ops)
37     : mControlOps(ops) {
38     // The memory is allocated in the snapshot load if called from a snapshot load().
39     if (!create.fromSnapshot) {
40         mGuestAddr = create.physAddr;
41         allocatePages(create.physAddr, kNumPages);
42     }
43 }
44 
~AddressSpaceHostMediaContext()45 AddressSpaceHostMediaContext::~AddressSpaceHostMediaContext() {
46     deallocatePages(mGuestAddr, kNumPages);
47 }
48 
perform(AddressSpaceDevicePingInfo * info)49 void AddressSpaceHostMediaContext::perform(AddressSpaceDevicePingInfo *info) {
50     handleMediaRequest(info);
51 }
52 
getDeviceType() const53 AddressSpaceDeviceType AddressSpaceHostMediaContext::getDeviceType() const {
54     return AddressSpaceDeviceType::Media;
55 }
56 
save(base::Stream * stream) const57 void AddressSpaceHostMediaContext::save(base::Stream* stream) const {
58     AS_DEVICE_DPRINT("Saving Host Media snapshot");
59     stream->putBe64(mGuestAddr);
60     int numActiveDecoders = 0;
61     if (mVpxDecoder != nullptr) {
62         ++ numActiveDecoders;
63     }
64     if (mH264Decoder != nullptr) {
65         ++ numActiveDecoders;
66     }
67 
68     stream->putBe32(numActiveDecoders);
69     if (mVpxDecoder != nullptr) {
70         AS_DEVICE_DPRINT("Saving VpxDecoder snapshot");
71         stream->putBe32((uint32_t)DecoderType::Vpx);
72         mVpxDecoder->save(stream);
73     }
74     if (mH264Decoder != nullptr) {
75         AS_DEVICE_DPRINT("Saving H264Decoder snapshot");
76         stream->putBe32((uint32_t)DecoderType::H264);
77         mH264Decoder->save(stream);
78     }
79 }
80 
load(base::Stream * stream)81 bool AddressSpaceHostMediaContext::load(base::Stream* stream) {
82     deallocatePages(mGuestAddr, kNumPages);
83     AS_DEVICE_DPRINT("Loading Host Media snapshot");
84     mGuestAddr = stream->getBe64();
85     allocatePages(mGuestAddr, kNumPages);
86 
87     int numActiveDecoders = stream->getBe32();
88     for (int i = 0; i < numActiveDecoders; ++i) {
89         stream->getBe32();
90         // TODO: Add support for virtio-gpu-as-video-decode
91         // switch (t) {
92         // case DecoderType::Vpx:
93         //     AS_DEVICE_DPRINT("Loading VpxDecoder snapshot");
94         //     mVpxDecoder.reset(new MediaVpxDecoder);
95         //     mVpxDecoder->load(stream);
96         //     break;
97         // case DecoderType::H264:
98         //     AS_DEVICE_DPRINT("Loading H264Decoder snapshot");
99         //     mH264Decoder.reset(MediaH264Decoder::create());
100         //     mH264Decoder->load(stream);
101         //     break;
102         // default:
103         //     break;
104         // }
105     }
106     return true;
107 }
108 
allocatePages(uint64_t phys_addr,int num_pages)109 void AddressSpaceHostMediaContext::allocatePages(uint64_t phys_addr, int num_pages) {
110     mHostBuffer = android::aligned_buf_alloc(kAlignment, num_pages * 4096);
111     mControlOps->add_memory_mapping(
112         phys_addr, mHostBuffer, num_pages * 4096);
113     AS_DEVICE_DPRINT("Allocating host memory for media context: guest_addr 0x%" PRIx64 ", 0x%" PRIx64,
114                      (uint64_t)phys_addr, (uint64_t)mHostBuffer);
115 }
116 
deallocatePages(uint64_t phys_addr,int num_pages)117 void AddressSpaceHostMediaContext::deallocatePages(uint64_t phys_addr,
118                                                    int num_pages) {
119     if (mHostBuffer == nullptr) {
120         return;
121     }
122 
123     mControlOps->remove_memory_mapping(phys_addr, mHostBuffer,
124                                        num_pages * 4096);
125     android::aligned_buf_free(mHostBuffer);
126     mHostBuffer = nullptr;
127     AS_DEVICE_DPRINT(
128             "De-Allocating host memory for media context: guest_addr 0x%" PRIx64
129             ", 0x%" PRIx64,
130             (uint64_t)phys_addr, (uint64_t)mHostBuffer);
131 }
132 
133 // static
getMediaCodecType(uint64_t metadata)134 MediaCodecType AddressSpaceHostMediaContext::getMediaCodecType(uint64_t metadata) {
135     // Metadata has the following structure:
136     // - Upper 8 bits has the codec type (MediaCodecType)
137     // - Lower 56 bits has metadata specifically for that codec
138     //
139     // We need to hand the data off to the right codec depending on which
140     // codec type we get.
141     uint8_t ret = (uint8_t)(metadata >> (64 - 8));
142     return ret > static_cast<uint8_t>(MediaCodecType::Max) ?
143             MediaCodecType::Max : (MediaCodecType)ret;
144 }
145 
146 // static
getMediaOperation(uint64_t metadata)147 MediaOperation AddressSpaceHostMediaContext::getMediaOperation(uint64_t metadata) {
148     // Metadata has the following structure:
149     // - Upper 8 bits has the codec type (MediaCodecType)
150     // - Lower 56 bits has metadata specifically for that codec
151     //
152     // We need to hand the data off to the right codec depending on which
153     // codec type we get.
154     uint8_t ret = (uint8_t)(metadata & 0xFF);
155     return ret > static_cast<uint8_t>(MediaOperation::Max) ?
156             MediaOperation::Max : (MediaOperation)ret;
157 }
158 
getAddrSlot(uint64_t metadata)159 static uint64_t getAddrSlot(uint64_t metadata) {
160     uint64_t ret = metadata << 8;  // get rid of typecode
161     ret = ret >> 16;               // get rid of opcode
162     return ret;
163 }
164 
handleMediaRequest(AddressSpaceDevicePingInfo * info)165 void AddressSpaceHostMediaContext::handleMediaRequest(AddressSpaceDevicePingInfo *info) {
166     auto codecType = getMediaCodecType(info->metadata);
167     auto op = getMediaOperation(info->metadata);
168     auto slot = getAddrSlot(info->metadata);
169     uint64_t offSetAddr = slot << 20;
170 
171     AS_DEVICE_DPRINT("Got media request (type=%u, op=%u, slot=%lld)",
172                      static_cast<uint8_t>(codecType), static_cast<uint8_t>(op),
173                      (long long)(getAddrSlot(info->metadata)));
174 
175     switch (codecType) {
176         case MediaCodecType::VP8Codec:
177         case MediaCodecType::VP9Codec:
178             // if (!mVpxDecoder) {
179             //     mVpxDecoder.reset(new MediaVpxDecoder);
180             // }
181             mVpxDecoder->handlePing(
182                     codecType, op,
183                     (uint8_t*)(mControlOps->get_host_ptr(info->phys_addr)) +
184                             offSetAddr);
185             break;
186         case MediaCodecType::H264Codec:
187             // if (!mH264Decoder) {
188             //     mH264Decoder.reset(MediaH264Decoder::create());
189             // }
190             mH264Decoder->handlePing(
191                     codecType, op,
192                     (uint8_t*)(mControlOps->get_host_ptr(info->phys_addr)) +
193                             offSetAddr);
194             break;
195         default:
196             AS_DEVICE_DPRINT("codec type %d not implemented", (int)codecType);
197             break;
198     }
199 }
200 
201 }  // namespace emulation
202 }  // namespace android
203