blob: 971ac91ed46f48a503d68ae97b4d4f8fe521273c
1 | /* |
2 | * Copyright (C) 2011 The Android Open Source Project |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | #define LOG_NDEBUG 1 |
17 | #define LOG_TAG "ScreenCatch" |
18 | |
19 | #include <media/stagefright/foundation/ADebug.h> |
20 | #include <media/stagefright/MediaDefs.h> |
21 | #include <media/stagefright/MetaData.h> |
22 | #include <OMX_IVCommon.h> |
23 | #include <MetadataBufferType.h> |
24 | |
25 | #include <ui/GraphicBuffer.h> |
26 | #include <gui/ISurfaceComposer.h> |
27 | #include <gui/IGraphicBufferAlloc.h> |
28 | #include <OMX_Component.h> |
29 | |
30 | #include <utils/Log.h> |
31 | #include <utils/String8.h> |
32 | |
33 | #include <private/gui/ComposerService.h> |
34 | |
35 | #include <media/stagefright/ScreenCatch.h> |
36 | #include <media/stagefright/ScreenSource.h> |
37 | |
38 | #include <binder/IPCThreadState.h> |
39 | #include <binder/MemoryBase.h> |
40 | #include <binder/MemoryHeapBase.h> |
41 | |
42 | #include <stdio.h> |
43 | #include <assert.h> |
44 | #include <limits.h> |
45 | #include <unistd.h> |
46 | #include <fcntl.h> |
47 | #include <sched.h> |
48 | #include <sys/types.h> |
49 | #include <sys/stat.h> |
50 | |
51 | #include <binder/IServiceManager.h> |
52 | |
53 | #define BOUNDRY 32 |
54 | |
55 | #define ALIGN(x) (x + (BOUNDRY) - 1)& ~((BOUNDRY) - 1) |
56 | |
57 | namespace android { |
58 | |
59 | struct ScreenCatch::ScreenCatchClient : public BnScreenMediaSourceClient { |
60 | ScreenCatchClient(void *user) |
61 | { |
62 | mUser = user; |
63 | ALOGE("[%s %d] user:%x", __FUNCTION__, __LINE__, user); |
64 | } |
65 | |
66 | virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) |
67 | { |
68 | ALOGI("notify %d, %d, %d", msg, ext1, ext2); |
69 | } |
70 | |
71 | virtual int dataCallback(const sp<IMemory> &data) |
72 | { |
73 | return 0; |
74 | } |
75 | |
76 | protected: |
77 | void *mUser; |
78 | virtual ~ScreenCatchClient() {} |
79 | |
80 | private: |
81 | DISALLOW_EVIL_CONSTRUCTORS(ScreenCatchClient); |
82 | }; |
83 | |
84 | ScreenCatch::ScreenCatch(uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bitSize) : |
85 | mWidth(ALIGN(bufferWidth)), |
86 | mHeight(bufferHeight), |
87 | mScreenMediaSourceService(NULL), |
88 | mColorFormat(OMX_COLOR_Format32bitARGB8888), |
89 | mBitSize(bitSize) |
90 | { |
91 | ALOGE("ScreenCatch: %dx%d", bufferWidth, bufferHeight); |
92 | |
93 | if (bufferWidth <= 0 || bufferHeight <= 0 || bufferWidth > 1920 || bufferHeight > 1080) { |
94 | ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight); |
95 | } |
96 | |
97 | if (bitSize != 24 || bitSize != 32) |
98 | bitSize = 32; |
99 | |
100 | mCorpX = -1; |
101 | mCorpY = -1; |
102 | mCorpWidth = -1; |
103 | mCorpHeight = -1; |
104 | |
105 | } |
106 | |
107 | ScreenCatch::~ScreenCatch() |
108 | { |
109 | ALOGE("~ScreenCatch"); |
110 | } |
111 | |
112 | void ScreenCatch::setVideoRotation(int degree) |
113 | { |
114 | int angle; |
115 | |
116 | ALOGI("[%s %d] setVideoRotation degree:%x", __FUNCTION__, __LINE__, degree); |
117 | |
118 | } |
119 | |
120 | void ScreenCatch::setVideoCrop(int x, int y, int width, int height) |
121 | { |
122 | mCorpX = x; |
123 | mCorpY = y; |
124 | mCorpWidth = width; |
125 | mCorpHeight = height; |
126 | } |
127 | |
128 | static inline void yuv_to_rgb32(unsigned char y, unsigned char u, unsigned char v, unsigned char *rgb) |
129 | { |
130 | register int r, g, b; |
131 | |
132 | r = (1192 * (y - 16) + 1634 * (v - 128) ) >> 10; |
133 | g = (1192 * (y - 16) - 833 * (v - 128) - 400 * (u - 128) ) >> 10; |
134 | b = (1192 * (y - 16) + 2066 * (u - 128) ) >> 10; |
135 | |
136 | r = r > 255 ? 255 : r < 0 ? 0 : r; |
137 | g = g > 255 ? 255 : g < 0 ? 0 : g; |
138 | b = b > 255 ? 255 : b < 0 ? 0 : b; |
139 | |
140 | /*ARGB*/ |
141 | *rgb = (unsigned char)r; |
142 | rgb++; |
143 | *rgb = (unsigned char)g; |
144 | rgb++; |
145 | *rgb = (unsigned char)b; |
146 | rgb++; |
147 | *rgb = 0xff; |
148 | |
149 | } |
150 | |
151 | void nv21_to_rgb32(unsigned char *buf, unsigned char *rgb, int width, int height) |
152 | { |
153 | int x, y, z = 0; |
154 | int h, w; |
155 | int blocks; |
156 | unsigned char Y1, Y2, U, V; |
157 | |
158 | blocks = (width * height) * 2; |
159 | |
160 | for (h = 0, z = 0; h < height; h += 2) { |
161 | for (y = 0; y < width * 2; y += 2) { |
162 | |
163 | Y1 = buf[ h * width + y + 0]; |
164 | V = buf[ blocks / 2 + h * width / 2 + y % width + 0 ]; |
165 | Y2 = buf[ h * width + y + 1]; |
166 | U = buf[ blocks / 2 + h * width / 2 + y % width + 1 ]; |
167 | |
168 | yuv_to_rgb32(Y1, U, V, &rgb[z]); |
169 | yuv_to_rgb32(Y2, U, V, &rgb[z + 4]); |
170 | z += 8; |
171 | } |
172 | } |
173 | } |
174 | |
175 | static inline void yuv_to_rgb24(unsigned char y, unsigned char u, unsigned char v, unsigned char *rgb) |
176 | { |
177 | register int r, g, b; |
178 | |
179 | r = (1192 * (y - 16) + 1634 * (v - 128) ) >> 10; |
180 | g = (1192 * (y - 16) - 833 * (v - 128) - 400 * (u - 128) ) >> 10; |
181 | b = (1192 * (y - 16) + 2066 * (u - 128) ) >> 10; |
182 | |
183 | r = r > 255 ? 255 : r < 0 ? 0 : r; |
184 | g = g > 255 ? 255 : g < 0 ? 0 : g; |
185 | b = b > 255 ? 255 : b < 0 ? 0 : b; |
186 | |
187 | /*ARGB*/ |
188 | *rgb = (unsigned char)r; |
189 | rgb++; |
190 | *rgb = (unsigned char)g; |
191 | rgb++; |
192 | *rgb = (unsigned char)b; |
193 | } |
194 | |
195 | void nv21_to_rgb24(unsigned char *buf, unsigned char *rgb, int width, int height) |
196 | { |
197 | int x, y, z = 0; |
198 | int h, w; |
199 | int blocks; |
200 | unsigned char Y1, Y2, U, V; |
201 | |
202 | blocks = (width * height) * 2; |
203 | |
204 | for (h = 0, z = 0; h < height; h += 2) { |
205 | for (y = 0; y < width * 2; y += 2) { |
206 | |
207 | Y1 = buf[ h * width + y + 0]; |
208 | V = buf[ blocks / 2 + h * width / 2 + y % width + 0 ]; |
209 | Y2 = buf[ h * width + y + 1]; |
210 | U = buf[ blocks / 2 + h * width / 2 + y % width + 1 ]; |
211 | |
212 | yuv_to_rgb24(Y1, U, V, &rgb[z]); |
213 | yuv_to_rgb24(Y2, U, V, &rgb[z + 3]); |
214 | z += 6; |
215 | } |
216 | } |
217 | } |
218 | |
219 | int ScreenCatch::threadFunc() |
220 | { |
221 | int64_t pts; |
222 | int status; |
223 | |
224 | sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(mWidth * mHeight * 3 / 2); |
225 | sp<MemoryBase> buffer = new MemoryBase(newMemoryHeap, 0, mWidth * mHeight * 3 / 2); |
226 | |
227 | ALOGV("[%s %d] empty:%d", __FUNCTION__, __LINE__, mRawBufferQueue.empty()); |
228 | |
229 | while (mStart == true) { |
230 | |
231 | status = mScreenMediaSourceService->readBuffer(mClientId, buffer, &pts); |
232 | |
233 | if (status != OK && mStart == true) { |
234 | usleep(10000); |
235 | continue; |
236 | } |
237 | |
238 | if (mStart != true) |
239 | break; |
240 | |
241 | MediaBuffer *accessUnit; |
242 | |
243 | if (OMX_COLOR_Format24bitRGB888 == mColorFormat) { //rgb 24bit |
244 | accessUnit = new MediaBuffer(mWidth * mHeight * 3); |
245 | nv21_to_rgb24((unsigned char *)buffer->pointer(), (unsigned char *)accessUnit->data(), mWidth, mHeight); |
246 | accessUnit->set_range(0, mWidth * mHeight * 3); |
247 | } else if (OMX_COLOR_Format32bitARGB8888 == mColorFormat) { //rgba 32bit |
248 | accessUnit = new MediaBuffer(mWidth * mHeight * 4); |
249 | nv21_to_rgb32((unsigned char *)buffer->pointer(), (unsigned char *)accessUnit->data(), mWidth, mHeight); |
250 | accessUnit->set_range(0, mWidth * mHeight * 4); |
251 | } else if (OMX_COLOR_FormatYUV420SemiPlanar == mColorFormat) { //nv21 |
252 | accessUnit = new MediaBuffer(mWidth * mHeight * 3 / 2); |
253 | memcpy((unsigned char *)accessUnit->data(), (unsigned char *)buffer->pointer(), mWidth * mHeight * 3 / 2); |
254 | accessUnit->set_range(0, mWidth * mHeight * 3 / 2); |
255 | } |
256 | mRawBufferQueue.push_back(accessUnit); |
257 | } |
258 | |
259 | ALOGE("[%s %d] thread out", __FUNCTION__, __LINE__); |
260 | |
261 | mThreadOutCondition.signal(); |
262 | |
263 | return 0; |
264 | } |
265 | |
266 | void *ScreenCatch::ThreadWrapper(void *me) |
267 | { |
268 | |
269 | ScreenCatch *Convertor = static_cast<ScreenCatch *>(me); |
270 | Convertor->threadFunc(); |
271 | return NULL; |
272 | } |
273 | |
274 | status_t ScreenCatch::start(MetaData *params) |
275 | { |
276 | ALOGE("[%s %d] mWidth:%d mHeight:%d", __FUNCTION__, __LINE__, mWidth, mHeight); |
277 | Mutex::Autolock autoLock(mLock); |
278 | |
279 | status_t status; |
280 | int64_t pts; |
281 | int client_id; |
282 | |
283 | sp<IServiceManager> sm = defaultServiceManager(); |
284 | sp<IBinder> binder = sm->getService(String16("media.screenmediasource")); |
285 | mScreenMediaSourceService = interface_cast<IScreenMediaSource>(binder); |
286 | |
287 | sp<ScreenCatchClient> mIScreenSourceClient = new ScreenCatchClient(this); |
288 | |
289 | ALOGE("[%s %d] mWidth:%d mHeight:%d", __FUNCTION__, __LINE__, mWidth, mHeight); |
290 | |
291 | mScreenMediaSourceService->registerClient(mIScreenSourceClient, mWidth, mHeight, 1, SCREENMEDIASOURC_RAWDATA_TYPE, &client_id, NULL); |
292 | |
293 | ALOGE("[%s %d] client_id:%d", __FUNCTION__, __LINE__, client_id); |
294 | |
295 | mClientId = client_id; |
296 | |
297 | if (status != OK) { |
298 | ALOGE("setResolutionRatio fail"); |
299 | return !OK; |
300 | } |
301 | |
302 | ALOGV("[%s %d] mCorpX:%d mCorpY:%d mCorpWidth:%d mCorpHeight:%d", __FUNCTION__, __LINE__, mCorpX, mCorpY, mCorpWidth, mCorpHeight); |
303 | |
304 | if (mCorpX != -1) |
305 | mScreenMediaSourceService->setVideoCrop(client_id, mCorpX, mCorpY, mCorpWidth, mCorpHeight); |
306 | |
307 | |
308 | status = mScreenMediaSourceService->start(client_id); |
309 | |
310 | if (status != OK) { |
311 | mScreenMediaSourceService->unregisterClient(mClientId); |
312 | ALOGE("ScreenMediaSourceService start fail"); |
313 | return !OK; |
314 | } |
315 | |
316 | if (!(params->findInt32(kKeyColorFormat, &mColorFormat) |
317 | && (mColorFormat != OMX_COLOR_FormatYUV420SemiPlanar |
318 | || mColorFormat != OMX_COLOR_Format24bitRGB888 |
319 | || mColorFormat != OMX_COLOR_Format32bitARGB8888))) |
320 | mColorFormat = OMX_COLOR_Format32bitARGB8888; |
321 | |
322 | pthread_attr_t attr; |
323 | pthread_attr_init(&attr); |
324 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); |
325 | pthread_create(&mThread, &attr, ThreadWrapper, this); |
326 | pthread_attr_destroy(&attr); |
327 | |
328 | mStart = true; |
329 | |
330 | ALOGV("[%s %d]", __FUNCTION__, __LINE__); |
331 | return OK; |
332 | } |
333 | |
334 | status_t ScreenCatch::stop() |
335 | { |
336 | ALOGV("[%s %d]", __FUNCTION__, __LINE__); |
337 | Mutex::Autolock autoLock(mLock); |
338 | mStart = false; |
339 | |
340 | mThreadOutCondition.waitRelative(mLock, 1000000000000); |
341 | ALOGV("[%s %d]", __FUNCTION__, __LINE__); |
342 | |
343 | while (!mRawBufferQueue.empty()) { |
344 | |
345 | ALOGV("[%s %d] free buffer", __FUNCTION__, __LINE__); |
346 | |
347 | MediaBuffer *rawBuffer = *mRawBufferQueue.begin(); |
348 | mRawBufferQueue.erase(mRawBufferQueue.begin()); |
349 | rawBuffer->release(); |
350 | } |
351 | |
352 | mScreenMediaSourceService->stop(mClientId); |
353 | mScreenMediaSourceService->unregisterClient(mClientId); |
354 | |
355 | return OK; |
356 | } |
357 | |
358 | status_t ScreenCatch::read(MediaBuffer **buffer) |
359 | { |
360 | Mutex::Autolock autoLock(mLock); |
361 | |
362 | if (!mRawBufferQueue.empty()) { |
363 | MediaBuffer *rawBuffer = *mRawBufferQueue.begin(); |
364 | mRawBufferQueue.erase(mRawBufferQueue.begin()); |
365 | *buffer = rawBuffer; |
366 | return OK; |
367 | } |
368 | |
369 | return !OK; |
370 | } |
371 | |
372 | status_t ScreenCatch::free(MediaBuffer *buffer) |
373 | { |
374 | Mutex::Autolock autoLock(mLock); |
375 | buffer->release(); |
376 | return OK; |
377 | } |
378 | |
379 | } // end of namespace android |
380 |