1 #include <log/log.h>
2 
3 #include "goldfish_media_utils.h"
4 #include "goldfish_vpx_defs.h"
5 #include <cstdlib>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <linux/ioctl.h>
9 #include <linux/types.h>
10 #include <string>
11 #include <sys/ioctl.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 
17 #include <memory>
18 #include <mutex>
19 #include <vector>
20 
21 #define DEBUG 0
22 #if DEBUG
23 #define DDD(...) ALOGD(__VA_ARGS__)
24 #else
25 #define DDD(...) ((void)0)
26 #endif
27 
28 // static vpx_image_t myImg;
29 static uint64_t s_CtxId = 0;
30 static std::mutex sCtxidMutex;
31 
applyForOneId()32 static uint64_t applyForOneId() {
33     DDD("%s %d", __func__, __LINE__);
34     std::lock_guard<std::mutex> g{sCtxidMutex};
35     ++s_CtxId;
36     return s_CtxId;
37 }
38 
sendVpxOperation(vpx_codec_ctx_t * ctx,MediaOperation op)39 static void sendVpxOperation(vpx_codec_ctx_t *ctx, MediaOperation op) {
40     DDD("%s %d", __func__, __LINE__);
41     if (ctx->memory_slot < 0) {
42         ALOGE("ERROR: Failed %s %d: there is no memory slot", __func__,
43               __LINE__);
44     }
45     auto transport = GoldfishMediaTransport::getInstance();
46     transport->sendOperation(ctx->vpversion == 9 ? MediaCodecType::VP9Codec
47                                                  : MediaCodecType::VP8Codec,
48                              op, ctx->address_offset);
49 }
50 
vpx_codec_destroy(vpx_codec_ctx_t * ctx)51 int vpx_codec_destroy(vpx_codec_ctx_t *ctx) {
52     DDD("%s %d", __func__, __LINE__);
53     if (!ctx) {
54         ALOGE("ERROR: Failed %s %d: ctx is nullptr", __func__, __LINE__);
55         return -1;
56     }
57     auto transport = GoldfishMediaTransport::getInstance();
58     transport->writeParam(ctx->id, 0, ctx->address_offset);
59     sendVpxOperation(ctx, MediaOperation::DestroyContext);
60     transport->returnMemorySlot(ctx->memory_slot);
61     ctx->memory_slot = -1;
62     return 0;
63 }
64 
vpx_codec_dec_init(vpx_codec_ctx_t * ctx)65 int vpx_codec_dec_init(vpx_codec_ctx_t *ctx) {
66     DDD("%s %d", __func__, __LINE__);
67     auto transport = GoldfishMediaTransport::getInstance();
68     int slot = transport->getMemorySlot();
69     if (slot < 0) {
70         ALOGE("ERROR: Failed %s %d: cannot get memory slot", __func__,
71               __LINE__);
72         return -1;
73     } else {
74         DDD("got slot %d", slot);
75     }
76     ctx->id = applyForOneId();
77     ctx->memory_slot = slot;
78     ctx->address_offset =
79         static_cast<unsigned int>(ctx->memory_slot) * (1 << 20);
80     DDD("got address offset 0x%x version %d", (int)(ctx->address_offset),
81         ctx->version);
82 
83     // data and dst are on the host side actually
84     ctx->data = transport->getInputAddr(ctx->address_offset);
85     ctx->dst =
86         transport->getInputAddr(ctx->address_offset); // re-use input address
87     transport->writeParam(ctx->id, 0, ctx->address_offset);
88     transport->writeParam(ctx->version, 1, ctx->address_offset);
89     sendVpxOperation(ctx, MediaOperation::InitContext);
90     return 0;
91 }
92 
getReturnCode(uint8_t * ptr)93 static int getReturnCode(uint8_t *ptr) {
94     int *pint = (int *)(ptr);
95     return *pint;
96 }
97 
98 // vpx_image_t myImg;
getVpxFrame(uint8_t * ptr,vpx_image_t & myImg)99 static void getVpxFrame(uint8_t *ptr, vpx_image_t &myImg) {
100     DDD("%s %d", __func__, __LINE__);
101     uint8_t *imgptr = (ptr + 8);
102     myImg.fmt = *(vpx_img_fmt_t *)imgptr;
103     imgptr += 8;
104     myImg.d_w = *(unsigned int *)imgptr;
105     imgptr += 8;
106     myImg.d_h = *(unsigned int *)imgptr;
107     imgptr += 8;
108     myImg.user_priv = (void *)(*(uint64_t *)imgptr);
109     DDD("fmt %d dw %d dh %d userpriv %p", (int)myImg.fmt, (int)myImg.d_w,
110         (int)myImg.d_h, myImg.user_priv);
111 }
112 
113 // TODO: we might not need to do the putting all the time
vpx_codec_get_frame(vpx_codec_ctx_t * ctx,int hostColorBufferId)114 vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx, int hostColorBufferId) {
115     DDD("%s %d %p", __func__, __LINE__);
116     (void)hostColorBufferId;
117     if (!ctx) {
118         ALOGE("ERROR: Failed %s %d: ctx is nullptr", __func__, __LINE__);
119         return nullptr;
120     }
121     auto transport = GoldfishMediaTransport::getInstance();
122 
123     transport->writeParam(ctx->id, 0, ctx->address_offset);
124     transport->writeParam(ctx->outputBufferWidth, 1, ctx->address_offset);
125     transport->writeParam(ctx->outputBufferHeight, 2, ctx->address_offset);
126     transport->writeParam(ctx->width, 3, ctx->address_offset);
127     transport->writeParam(ctx->height, 4, ctx->address_offset);
128     transport->writeParam(ctx->bpp, 5, ctx->address_offset);
129     transport->writeParam(ctx->hostColorBufferId, 6, ctx->address_offset);
130     transport->writeParam(transport->offsetOf((uint64_t)(ctx->dst)) -
131                               ctx->address_offset,
132                           7, ctx->address_offset);
133 
134     sendVpxOperation(ctx, MediaOperation::GetImage);
135 
136     auto *retptr = transport->getReturnAddr(ctx->address_offset);
137     int ret = getReturnCode(retptr);
138     if (ret) {
139         return nullptr;
140     }
141     getVpxFrame(retptr, ctx->myImg);
142     return &(ctx->myImg);
143 }
144 
vpx_codec_send_metadata(vpx_codec_ctx_t * ctx,void * ptr)145 void vpx_codec_send_metadata(vpx_codec_ctx_t *ctx, void *ptr) {
146     MetaDataColorAspects& meta = *(MetaDataColorAspects*)ptr;
147     auto transport = GoldfishMediaTransport::getInstance();
148     transport->writeParam(ctx->id, 0, ctx->address_offset);
149     transport->writeParam(meta.type, 1, ctx->address_offset);
150     transport->writeParam(meta.primaries, 2, ctx->address_offset);
151     transport->writeParam(meta.range, 3, ctx->address_offset);
152     transport->writeParam(meta.transfer, 4, ctx->address_offset);
153     sendVpxOperation(ctx, MediaOperation::SendMetadata);
154 }
155 
vpx_codec_flush(vpx_codec_ctx_t * ctx)156 int vpx_codec_flush(vpx_codec_ctx_t *ctx) {
157     DDD("%s %d", __func__, __LINE__);
158     if (!ctx) {
159         ALOGE("ERROR: Failed %s %d: ctx is nullptr", __func__, __LINE__);
160         return -1;
161     }
162     auto transport = GoldfishMediaTransport::getInstance();
163     transport->writeParam(ctx->id, 0, ctx->address_offset);
164     sendVpxOperation(ctx, MediaOperation::Flush);
165     return 0;
166 }
167 
vpx_codec_decode(vpx_codec_ctx_t * ctx,const uint8_t * data,unsigned int data_sz,void * user_priv,long deadline)168 int vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data,
169                      unsigned int data_sz, void *user_priv, long deadline) {
170     if (!ctx) {
171         ALOGE("ERROR: Failed %s %d: ctx is nullptr", __func__, __LINE__);
172         return -1;
173     }
174     (void)deadline;
175     DDD("%s %d data size %d userpriv %p", __func__, __LINE__, (int)data_sz,
176         user_priv);
177     auto transport = GoldfishMediaTransport::getInstance();
178     memcpy(ctx->data, data, data_sz);
179 
180     transport->writeParam(ctx->id, 0, ctx->address_offset);
181     transport->writeParam(transport->offsetOf((uint64_t)(ctx->data)) -
182                               ctx->address_offset,
183                           1, ctx->address_offset);
184     transport->writeParam((__u64)data_sz, 2, ctx->address_offset);
185     transport->writeParam((__u64)user_priv, 3, ctx->address_offset);
186     sendVpxOperation(ctx, MediaOperation::DecodeImage);
187     return 0;
188 }
189