blob: ef6250f144f98eb02951fcdd079752653063246e [file] [log] [blame]
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001/*
2**
3** Copyright (C) 2008 The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
Mark Salyzyn34fb2962014-06-18 16:30:56 -070018#include <inttypes.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080019#include <stdint.h>
20#include <sys/types.h>
Mark Salyzyn34fb2962014-06-18 16:30:56 -070021
Marco Nelissendab79b32019-11-18 08:25:47 -080022#include <android/IDataSource.h>
Mathias Agopian75624082009-05-19 19:08:10 -070023#include <binder/Parcel.h>
Andreas Huber1b86fe02014-01-29 11:13:26 -080024#include <media/IMediaHTTPService.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080025#include <media/IMediaMetadataRetriever.h>
Andreas Huberaf8791e2011-03-21 10:25:44 -070026#include <utils/String8.h>
Sangkyu Leed01c1482013-02-08 16:26:39 +090027#include <utils/KeyedVector.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080028
29namespace android {
30
31enum {
32 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
33 SET_DATA_SOURCE_URL,
34 SET_DATA_SOURCE_FD,
Chris Watkins99f31602015-03-20 13:06:33 -070035 SET_DATA_SOURCE_CALLBACK,
James Dong16afe2f2010-12-02 17:42:08 -080036 GET_FRAME_AT_TIME,
Chong Zhangd3e0d862017-10-03 13:17:13 -070037 GET_IMAGE_AT_INDEX,
Chong Zhang0c1407f2018-05-02 17:09:05 -070038 GET_IMAGE_RECT_AT_INDEX,
Chong Zhangd3e0d862017-10-03 13:17:13 -070039 GET_FRAME_AT_INDEX,
Dave Sparksec4dde72009-11-23 16:51:15 -080040 EXTRACT_ALBUM_ART,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080041 EXTRACT_METADATA,
42};
43
44class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
45{
46public:
Chih-Hung Hsieh090ef602016-04-27 10:39:54 -070047 explicit BpMediaMetadataRetriever(const sp<IBinder>& impl)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080048 : BpInterface<IMediaMetadataRetriever>(impl)
49 {
50 }
51
52 // disconnect from media metadata retriever service
53 void disconnect()
54 {
55 Parcel data, reply;
56 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
57 remote()->transact(DISCONNECT, data, &reply);
58 }
59
Andreas Huberaf8791e2011-03-21 10:25:44 -070060 status_t setDataSource(
Andreas Huber1b86fe02014-01-29 11:13:26 -080061 const sp<IMediaHTTPService> &httpService,
62 const char *srcUrl,
63 const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080064 {
65 Parcel data, reply;
66 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Andreas Huber1b86fe02014-01-29 11:13:26 -080067 data.writeInt32(httpService != NULL);
68 if (httpService != NULL) {
Marco Nelissen06b46062014-11-14 07:58:25 -080069 data.writeStrongBinder(IInterface::asBinder(httpService));
Andreas Huber1b86fe02014-01-29 11:13:26 -080070 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080071 data.writeCString(srcUrl);
Andreas Huberaf8791e2011-03-21 10:25:44 -070072
73 if (headers == NULL) {
74 data.writeInt32(0);
75 } else {
76 // serialize the headers
Ray Essick9c9fdf62019-05-14 12:04:42 -070077 data.writeInt32(headers->size());
Andreas Huberaf8791e2011-03-21 10:25:44 -070078 for (size_t i = 0; i < headers->size(); ++i) {
79 data.writeString8(headers->keyAt(i));
80 data.writeString8(headers->valueAt(i));
81 }
82 }
83
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080084 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
85 return reply.readInt32();
86 }
87
88 status_t setDataSource(int fd, int64_t offset, int64_t length)
89 {
90 Parcel data, reply;
91 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
92 data.writeFileDescriptor(fd);
93 data.writeInt64(offset);
94 data.writeInt64(length);
95 remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
96 return reply.readInt32();
97 }
98
Chong Zhang24c15772017-07-26 16:25:28 -070099 status_t setDataSource(const sp<IDataSource>& source, const char *mime)
Chris Watkins99f31602015-03-20 13:06:33 -0700100 {
101 Parcel data, reply;
102 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
103 data.writeStrongBinder(IInterface::asBinder(source));
Chong Zhang24c15772017-07-26 16:25:28 -0700104
105 if (mime != NULL) {
106 data.writeInt32(1);
107 data.writeCString(mime);
108 } else {
109 data.writeInt32(0);
110 }
Chris Watkins99f31602015-03-20 13:06:33 -0700111 remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
112 return reply.readInt32();
113 }
114
Chong Zhang24c15772017-07-26 16:25:28 -0700115 sp<IMemory> getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800116 {
Chong Zhang24c15772017-07-26 16:25:28 -0700117 ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d) metaOnly(%d)",
118 timeUs, option, colorFormat, metaOnly);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800119 Parcel data, reply;
120 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
James Dong16afe2f2010-12-02 17:42:08 -0800121 data.writeInt64(timeUs);
122 data.writeInt32(option);
Chong Zhang24c15772017-07-26 16:25:28 -0700123 data.writeInt32(colorFormat);
124 data.writeInt32(metaOnly);
James Dong16afe2f2010-12-02 17:42:08 -0800125 remote()->transact(GET_FRAME_AT_TIME, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800126 status_t ret = reply.readInt32();
127 if (ret != NO_ERROR) {
128 return NULL;
129 }
130 return interface_cast<IMemory>(reply.readStrongBinder());
131 }
132
Chong Zhangd5fa3572018-04-09 19:03:10 -0700133 sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly, bool thumbnail)
Chong Zhangd3e0d862017-10-03 13:17:13 -0700134 {
Chong Zhangd5fa3572018-04-09 19:03:10 -0700135 ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d) thumbnail(%d)",
136 index, colorFormat, metaOnly, thumbnail);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700137 Parcel data, reply;
138 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
139 data.writeInt32(index);
140 data.writeInt32(colorFormat);
141 data.writeInt32(metaOnly);
Chong Zhangd5fa3572018-04-09 19:03:10 -0700142 data.writeInt32(thumbnail);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700143 remote()->transact(GET_IMAGE_AT_INDEX, data, &reply);
144 status_t ret = reply.readInt32();
145 if (ret != NO_ERROR) {
146 return NULL;
147 }
148 return interface_cast<IMemory>(reply.readStrongBinder());
149 }
150
Chong Zhang0c1407f2018-05-02 17:09:05 -0700151 sp<IMemory> getImageRectAtIndex(
152 int index, int colorFormat, int left, int top, int right, int bottom)
153 {
154 ALOGV("getImageRectAtIndex: index %d, colorFormat(%d) rect {%d, %d, %d, %d}",
155 index, colorFormat, left, top, right, bottom);
156 Parcel data, reply;
157 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
158 data.writeInt32(index);
159 data.writeInt32(colorFormat);
160 data.writeInt32(left);
161 data.writeInt32(top);
162 data.writeInt32(right);
163 data.writeInt32(bottom);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700164 remote()->transact(GET_IMAGE_RECT_AT_INDEX, data, &reply);
165 status_t ret = reply.readInt32();
166 if (ret != NO_ERROR) {
167 return NULL;
168 }
169 return interface_cast<IMemory>(reply.readStrongBinder());
170 }
171
Chong Zhang76a49d62019-07-12 11:20:33 -0700172 sp<IMemory> getFrameAtIndex(
173 int index, int colorFormat, bool metaOnly)
Chong Zhangd3e0d862017-10-03 13:17:13 -0700174 {
Chong Zhang76a49d62019-07-12 11:20:33 -0700175 ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
176 index, colorFormat, metaOnly);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700177 Parcel data, reply;
178 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Chong Zhang76a49d62019-07-12 11:20:33 -0700179 data.writeInt32(index);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700180 data.writeInt32(colorFormat);
181 data.writeInt32(metaOnly);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700182 remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
183 status_t ret = reply.readInt32();
184 if (ret != NO_ERROR) {
Chong Zhang76a49d62019-07-12 11:20:33 -0700185 return NULL;
Chong Zhangd3e0d862017-10-03 13:17:13 -0700186 }
Chong Zhang76a49d62019-07-12 11:20:33 -0700187 return interface_cast<IMemory>(reply.readStrongBinder());
Chong Zhangd3e0d862017-10-03 13:17:13 -0700188 }
189
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800190 sp<IMemory> extractAlbumArt()
191 {
192 Parcel data, reply;
193 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
Dave Sparksec4dde72009-11-23 16:51:15 -0800194 remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800195 status_t ret = reply.readInt32();
196 if (ret != NO_ERROR) {
197 return NULL;
198 }
199 return interface_cast<IMemory>(reply.readStrongBinder());
200 }
201
202 const char* extractMetadata(int keyCode)
203 {
204 Parcel data, reply;
205 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
206 data.writeInt32(keyCode);
207 remote()->transact(EXTRACT_METADATA, data, &reply);
208 status_t ret = reply.readInt32();
209 if (ret != NO_ERROR) {
210 return NULL;
211 }
Sangkyu Leed01c1482013-02-08 16:26:39 +0900212 const char* str = reply.readCString();
213 if (str != NULL) {
214 String8 value(str);
215 if (mMetadata.indexOfKey(keyCode) < 0) {
216 mMetadata.add(keyCode, value);
217 } else {
218 mMetadata.replaceValueFor(keyCode, value);
219 }
Tomasz Wasilczyk09977ff2023-08-11 15:52:22 +0000220 return mMetadata.valueFor(keyCode).c_str();
Sangkyu Leed01c1482013-02-08 16:26:39 +0900221 } else {
222 return NULL;
223 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800224 }
Sangkyu Leed01c1482013-02-08 16:26:39 +0900225
226private:
227 KeyedVector<int, String8> mMetadata;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800228};
229
niko56f0cc52009-06-22 08:49:52 -0700230IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800231
232// ----------------------------------------------------------------------
233
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800234status_t BnMediaMetadataRetriever::onTransact(
235 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
236{
237 switch (code) {
238 case DISCONNECT: {
239 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
240 disconnect();
241 return NO_ERROR;
242 } break;
243 case SET_DATA_SOURCE_URL: {
244 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Andreas Huber1b86fe02014-01-29 11:13:26 -0800245
246 sp<IMediaHTTPService> httpService;
247 if (data.readInt32()) {
248 httpService =
249 interface_cast<IMediaHTTPService>(data.readStrongBinder());
250 }
251
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800252 const char* srcUrl = data.readCString();
Andreas Huberaf8791e2011-03-21 10:25:44 -0700253
Wei Jia2afac0c2016-01-07 12:13:07 -0800254 if (httpService == NULL || srcUrl == NULL) {
255 reply->writeInt32(BAD_VALUE);
256 return NO_ERROR;
257 }
258
Andreas Huberaf8791e2011-03-21 10:25:44 -0700259 KeyedVector<String8, String8> headers;
Ray Essick9c9fdf62019-05-14 12:04:42 -0700260 size_t numHeaders = (size_t) data.readInt32();
Glenn Kastene03dd222014-01-28 11:04:39 -0800261 for (size_t i = 0; i < numHeaders; ++i) {
Ray Essick9c9fdf62019-05-14 12:04:42 -0700262 String8 key;
263 String8 value;
264 status_t status;
265 status = data.readString8(&key);
266 if (status != OK) {
267 return status;
268 }
269 status = data.readString8(&value);
270 if (status != OK) {
271 return status;
272 }
273 if (headers.add(key, value) < 0) {
274 return UNKNOWN_ERROR;
275 }
Andreas Huberaf8791e2011-03-21 10:25:44 -0700276 }
277
278 reply->writeInt32(
Andreas Huber1b86fe02014-01-29 11:13:26 -0800279 setDataSource(
280 httpService, srcUrl, numHeaders > 0 ? &headers : NULL));
Andreas Huberaf8791e2011-03-21 10:25:44 -0700281
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800282 return NO_ERROR;
283 } break;
284 case SET_DATA_SOURCE_FD: {
285 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Taiju Tsuiki55203e22015-04-21 17:36:22 +0900286 int fd = data.readFileDescriptor();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800287 int64_t offset = data.readInt64();
288 int64_t length = data.readInt64();
289 reply->writeInt32(setDataSource(fd, offset, length));
290 return NO_ERROR;
291 } break;
Chris Watkins99f31602015-03-20 13:06:33 -0700292 case SET_DATA_SOURCE_CALLBACK: {
293 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
294 sp<IDataSource> source =
295 interface_cast<IDataSource>(data.readStrongBinder());
Wei Jia2afac0c2016-01-07 12:13:07 -0800296 if (source == NULL) {
297 reply->writeInt32(BAD_VALUE);
298 } else {
Chong Zhang24c15772017-07-26 16:25:28 -0700299 int32_t hasMime = data.readInt32();
300 const char *mime = NULL;
301 if (hasMime) {
302 mime = data.readCString();
303 }
304 reply->writeInt32(setDataSource(source, mime));
Wei Jia2afac0c2016-01-07 12:13:07 -0800305 }
Chris Watkins99f31602015-03-20 13:06:33 -0700306 return NO_ERROR;
307 } break;
James Dong16afe2f2010-12-02 17:42:08 -0800308 case GET_FRAME_AT_TIME: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800309 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
James Dong16afe2f2010-12-02 17:42:08 -0800310 int64_t timeUs = data.readInt64();
311 int option = data.readInt32();
Chong Zhang24c15772017-07-26 16:25:28 -0700312 int colorFormat = data.readInt32();
313 bool metaOnly = (data.readInt32() != 0);
314 ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d), metaOnly(%d)",
315 timeUs, option, colorFormat, metaOnly);
Chong Zhang24c15772017-07-26 16:25:28 -0700316 sp<IMemory> bitmap = getFrameAtTime(timeUs, option, colorFormat, metaOnly);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800317 if (bitmap != 0) { // Don't send NULL across the binder interface
318 reply->writeInt32(NO_ERROR);
Marco Nelissen06b46062014-11-14 07:58:25 -0800319 reply->writeStrongBinder(IInterface::asBinder(bitmap));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800320 } else {
321 reply->writeInt32(UNKNOWN_ERROR);
322 }
323 return NO_ERROR;
324 } break;
Chong Zhangd3e0d862017-10-03 13:17:13 -0700325 case GET_IMAGE_AT_INDEX: {
326 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
327 int index = data.readInt32();
328 int colorFormat = data.readInt32();
329 bool metaOnly = (data.readInt32() != 0);
Chong Zhangd5fa3572018-04-09 19:03:10 -0700330 bool thumbnail = (data.readInt32() != 0);
331 ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d), thumbnail(%d)",
332 index, colorFormat, metaOnly, thumbnail);
Chong Zhangd5fa3572018-04-09 19:03:10 -0700333 sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700334 if (bitmap != 0) { // Don't send NULL across the binder interface
335 reply->writeInt32(NO_ERROR);
336 reply->writeStrongBinder(IInterface::asBinder(bitmap));
337 } else {
338 reply->writeInt32(UNKNOWN_ERROR);
339 }
Chong Zhangd3e0d862017-10-03 13:17:13 -0700340 return NO_ERROR;
341 } break;
Chong Zhang0c1407f2018-05-02 17:09:05 -0700342
343 case GET_IMAGE_RECT_AT_INDEX: {
344 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
345 int index = data.readInt32();
346 int colorFormat = data.readInt32();
347 int left = data.readInt32();
348 int top = data.readInt32();
349 int right = data.readInt32();
350 int bottom = data.readInt32();
351 ALOGV("getImageRectAtIndex: index(%d), colorFormat(%d), rect {%d, %d, %d, %d}",
352 index, colorFormat, left, top, right, bottom);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700353 sp<IMemory> bitmap = getImageRectAtIndex(
354 index, colorFormat, left, top, right, bottom);
355 if (bitmap != 0) { // Don't send NULL across the binder interface
356 reply->writeInt32(NO_ERROR);
357 reply->writeStrongBinder(IInterface::asBinder(bitmap));
358 } else {
359 reply->writeInt32(UNKNOWN_ERROR);
360 }
Chong Zhang0c1407f2018-05-02 17:09:05 -0700361 return NO_ERROR;
362 } break;
363
Chong Zhangd3e0d862017-10-03 13:17:13 -0700364 case GET_FRAME_AT_INDEX: {
365 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
Chong Zhang76a49d62019-07-12 11:20:33 -0700366 int index = data.readInt32();
Chong Zhangd3e0d862017-10-03 13:17:13 -0700367 int colorFormat = data.readInt32();
368 bool metaOnly = (data.readInt32() != 0);
Chong Zhang76a49d62019-07-12 11:20:33 -0700369 ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
370 index, colorFormat, metaOnly);
Chong Zhang76a49d62019-07-12 11:20:33 -0700371 sp<IMemory> frame = getFrameAtIndex(index, colorFormat, metaOnly);
372 if (frame != nullptr) { // Don't send NULL across the binder interface
373 reply->writeInt32(NO_ERROR);
374 reply->writeStrongBinder(IInterface::asBinder(frame));
375 } else {
376 reply->writeInt32(UNKNOWN_ERROR);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700377 }
Chong Zhangd3e0d862017-10-03 13:17:13 -0700378 return NO_ERROR;
379 } break;
Dave Sparksec4dde72009-11-23 16:51:15 -0800380 case EXTRACT_ALBUM_ART: {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800381 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
382 sp<IMemory> albumArt = extractAlbumArt();
383 if (albumArt != 0) { // Don't send NULL across the binder interface
384 reply->writeInt32(NO_ERROR);
Marco Nelissen06b46062014-11-14 07:58:25 -0800385 reply->writeStrongBinder(IInterface::asBinder(albumArt));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800386 } else {
387 reply->writeInt32(UNKNOWN_ERROR);
388 }
389 return NO_ERROR;
390 } break;
391 case EXTRACT_METADATA: {
392 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
393 int keyCode = data.readInt32();
394 const char* value = extractMetadata(keyCode);
395 if (value != NULL) { // Don't send NULL across the binder interface
396 reply->writeInt32(NO_ERROR);
397 reply->writeCString(value);
398 } else {
399 reply->writeInt32(UNKNOWN_ERROR);
400 }
401 return NO_ERROR;
402 } break;
403 default:
404 return BBinder::onTransact(code, data, reply, flags);
405 }
406}
407
408// ----------------------------------------------------------------------------
409
Glenn Kasten40bc9062015-03-20 09:09:33 -0700410} // namespace android