• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 "goldfish_media_utils.h"
16 
17 #include "goldfish_address_space.h"
18 
19 #include <log/log.h>
20 #include <memory>
21 #include <vector>
22 #include <mutex>
23 
24 
25 
26 std::mutex sSingletonMutex;
27 std::unique_ptr<GoldfishMediaTransport> sTransport;
28 
29 class GoldfishMediaTransportImpl : public GoldfishMediaTransport {
30 public:
31     GoldfishMediaTransportImpl();
32     ~GoldfishMediaTransportImpl();
33 
34     virtual void writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr = 0) override;
35     virtual bool sendOperation(MediaCodecType type, MediaOperation op, unsigned int offSetToStartAddr = 0) override;
36     virtual uint8_t* getBaseAddr() const override;
37     virtual uint8_t* getInputAddr(unsigned int offSet = 0) const override;
38     virtual uint8_t* getOutputAddr() const override;
39     virtual uint8_t* getReturnAddr(unsigned int offSet = 0) const override;
40     virtual __u64 offsetOf(uint64_t addr) const override;
41 
42 public:
43     // each lot has 8 M
getMemorySlot()44     virtual int getMemorySlot() override {
45         std::lock_guard<std::mutex> g{mMemoryMutex};
46         for (int i = mMemoryLotsAvailable.size() - 1; i >=0 ; --i) {
47             if (mMemoryLotsAvailable[i]) {
48                 mMemoryLotsAvailable[i] = false;
49                 return i;
50             }
51         }
52         return -1;
53     }
returnMemorySlot(int lot)54     virtual void returnMemorySlot(int lot) override {
55         if (lot < 0 || lot >= mMemoryLotsAvailable.size()) {
56             return;
57         }
58         std::lock_guard<std::mutex> g{mMemoryMutex};
59         if (mMemoryLotsAvailable[lot] == false) {
60             mMemoryLotsAvailable[lot] = true;
61         } else {
62             ALOGE("Error, cannot twice");
63         }
64     }
65 private:
66     std::mutex mMemoryMutex;
67     std::vector<bool> mMemoryLotsAvailable = {true, true, true, true};
68 
69     address_space_handle_t mHandle;
70     uint64_t  mOffset;
71     uint64_t  mPhysAddr;
72     uint64_t  mSize;
73     void* mStartPtr = nullptr;
74 
75     // MediaCodecType will be or'd together with the metadata, so the highest 8-bits
76     // will have the type.
77     static __u64 makeMetadata(MediaCodecType type,
78                               MediaOperation op, uint64_t offset);
79 
80     // Chunk size for parameters/return data
81     static constexpr size_t kParamSizeBytes = 4096; // 4K
82     // Chunk size for input
83     static constexpr size_t kInputSizeBytes = 4096 * 4096; // 16M
84     // Chunk size for output
85     static constexpr size_t kOutputSizeBytes = 4096 * 4096; // 16M
86     // Maximum number of parameters that can be passed
87     static constexpr size_t kMaxParams = 32;
88     // Offset from the memory region for return data (8 is size of
89     // a parameter in bytes)
90     static constexpr size_t kReturnOffset = 8 * kMaxParams;
91 };
92 
~GoldfishMediaTransportImpl()93 GoldfishMediaTransportImpl::~GoldfishMediaTransportImpl() {
94   if(mHandle >= 0) {
95     goldfish_address_space_close(mHandle);
96     mHandle = -1;
97   }
98 }
99 
GoldfishMediaTransportImpl()100 GoldfishMediaTransportImpl::GoldfishMediaTransportImpl() {
101     // Allocate host memory; the contiguous memory region will be laid out as
102     // follows:
103     // ========================================================
104     // | kParamSizeBytes | kInputSizeBytes | kOutputSizeBytes |
105     // ========================================================
106     mHandle = goldfish_address_space_open();
107     if (mHandle < 0) {
108         ALOGE("Failed to ping host to allocate memory");
109         abort();
110     }
111     mSize = kParamSizeBytes + kInputSizeBytes + kOutputSizeBytes;
112     bool success = goldfish_address_space_allocate(mHandle, mSize, &mPhysAddr, &mOffset);
113     if (success) {
114         ALOGD("successfully allocated %d bytes in goldfish_address_block", (int)mSize);
115         mStartPtr = goldfish_address_space_map(mHandle, mOffset, mSize);
116         ALOGD("guest address is %p", mStartPtr);
117 
118         struct goldfish_address_space_ping pingInfo;
119         pingInfo.metadata = GoldfishAddressSpaceSubdeviceType::Media;
120         pingInfo.offset = mOffset;
121         if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
122             ALOGE("Failed to ping host to allocate memory");
123             abort();
124             return;
125         } else {
126             ALOGD("successfully pinged host to allocate memory");
127         }
128     } else {
129         ALOGE("failed to allocate %d bytes in goldfish_address_block", (int)mSize);
130         abort();
131     }
132 }
133 
134 // static
getInstance()135 GoldfishMediaTransport* GoldfishMediaTransport::getInstance() {
136     std::lock_guard<std::mutex> g{sSingletonMutex};
137     if (sTransport == nullptr) {
138         sTransport.reset(new GoldfishMediaTransportImpl());
139     }
140     return sTransport.get();
141 }
142 
143 // static
makeMetadata(MediaCodecType type,MediaOperation op,uint64_t offset)144 __u64 GoldfishMediaTransportImpl::makeMetadata(MediaCodecType type,
145                                                MediaOperation op, uint64_t offset) {
146     // Shift |type| into the highest 8-bits, leaving the lower bits for other
147     // metadata.
148     offset = offset >> 20;
149     return ((__u64)type << (64 - 8)) | (offset << 8) | static_cast<uint8_t>(op);
150 }
151 
getInputAddr(unsigned int offSet) const152 uint8_t* GoldfishMediaTransportImpl::getInputAddr(unsigned int offSet) const {
153     return (uint8_t*)mStartPtr + kParamSizeBytes + offSet;
154 }
155 
getOutputAddr() const156 uint8_t* GoldfishMediaTransportImpl::getOutputAddr() const {
157     return getInputAddr() + kInputSizeBytes;
158 }
159 
getBaseAddr() const160 uint8_t* GoldfishMediaTransportImpl::getBaseAddr() const {
161     return (uint8_t*)mStartPtr;
162 }
163 
getReturnAddr(unsigned int offSet) const164 uint8_t* GoldfishMediaTransportImpl::getReturnAddr(unsigned int offSet) const {
165     return (uint8_t*)mStartPtr + kReturnOffset + offSet;
166 }
167 
offsetOf(uint64_t addr) const168 __u64 GoldfishMediaTransportImpl::offsetOf(uint64_t addr) const {
169     return addr - (uint64_t)mStartPtr;
170 }
171 
writeParam(__u64 val,unsigned int num,unsigned int offSetToStartAddr)172 void GoldfishMediaTransportImpl::writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr) {
173     uint8_t* p = (uint8_t*)mStartPtr + (offSetToStartAddr);
174     uint64_t* pint = (uint64_t*)(p + 8 * num);
175     *pint = val;
176 }
177 
sendOperation(MediaCodecType type,MediaOperation op,unsigned int offSetToStartAddr)178 bool GoldfishMediaTransportImpl::sendOperation(MediaCodecType type,
179                                                MediaOperation op, unsigned int offSetToStartAddr) {
180     struct goldfish_address_space_ping pingInfo;
181     pingInfo.metadata = makeMetadata(type, op, offSetToStartAddr);
182     pingInfo.offset = mOffset; // + (offSetToStartAddr);
183     if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
184         ALOGE("failed to ping host");
185         abort();
186         return false;
187     } else {
188         ALOGD("successfully pinged host for operation type=%d, op=%d", (int)type, (int)op);
189     }
190 
191     return true;
192 }
193