1 /*
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
18 #include <inttypes.h>
19 #include <stdint.h>
20 #include <sys/types.h>
21
22 #include <android/IDataSource.h>
23 #include <binder/Parcel.h>
24 #include <media/IMediaHTTPService.h>
25 #include <media/IMediaMetadataRetriever.h>
26 #include <utils/String8.h>
27 #include <utils/KeyedVector.h>
28
29 namespace android {
30
31 enum {
32 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
33 SET_DATA_SOURCE_URL,
34 SET_DATA_SOURCE_FD,
35 SET_DATA_SOURCE_CALLBACK,
36 GET_FRAME_AT_TIME,
37 GET_IMAGE_AT_INDEX,
38 GET_IMAGE_RECT_AT_INDEX,
39 GET_FRAME_AT_INDEX,
40 EXTRACT_ALBUM_ART,
41 EXTRACT_METADATA,
42 };
43
44 class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
45 {
46 public:
BpMediaMetadataRetriever(const sp<IBinder> & impl)47 explicit BpMediaMetadataRetriever(const sp<IBinder>& impl)
48 : BpInterface<IMediaMetadataRetriever>(impl)
49 {
50 }
51
52 // disconnect from media metadata retriever service
disconnect()53 void disconnect()
54 {
55 Parcel data, reply;
56 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
57 remote()->transact(DISCONNECT, data, &reply);
58 }
59
setDataSource(const sp<IMediaHTTPService> & httpService,const char * srcUrl,const KeyedVector<String8,String8> * headers)60 status_t setDataSource(
61 const sp<IMediaHTTPService> &httpService,
62 const char *srcUrl,
63 const KeyedVector<String8, String8> *headers)
64 {
65 Parcel data, reply;
66 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
67 data.writeInt32(httpService != NULL);
68 if (httpService != NULL) {
69 data.writeStrongBinder(IInterface::asBinder(httpService));
70 }
71 data.writeCString(srcUrl);
72
73 if (headers == NULL) {
74 data.writeInt32(0);
75 } else {
76 // serialize the headers
77 data.writeInt32(headers->size());
78 for (size_t i = 0; i < headers->size(); ++i) {
79 data.writeString8(headers->keyAt(i));
80 data.writeString8(headers->valueAt(i));
81 }
82 }
83
84 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
85 return reply.readInt32();
86 }
87
setDataSource(int fd,int64_t offset,int64_t length)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
setDataSource(const sp<IDataSource> & source,const char * mime)99 status_t setDataSource(const sp<IDataSource>& source, const char *mime)
100 {
101 Parcel data, reply;
102 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
103 data.writeStrongBinder(IInterface::asBinder(source));
104
105 if (mime != NULL) {
106 data.writeInt32(1);
107 data.writeCString(mime);
108 } else {
109 data.writeInt32(0);
110 }
111 remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
112 return reply.readInt32();
113 }
114
getFrameAtTime(int64_t timeUs,int option,int colorFormat,bool metaOnly)115 sp<IMemory> getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly)
116 {
117 ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d) metaOnly(%d)",
118 timeUs, option, colorFormat, metaOnly);
119 Parcel data, reply;
120 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
121 data.writeInt64(timeUs);
122 data.writeInt32(option);
123 data.writeInt32(colorFormat);
124 data.writeInt32(metaOnly);
125 remote()->transact(GET_FRAME_AT_TIME, data, &reply);
126 status_t ret = reply.readInt32();
127 if (ret != NO_ERROR) {
128 return NULL;
129 }
130 return interface_cast<IMemory>(reply.readStrongBinder());
131 }
132
getImageAtIndex(int index,int colorFormat,bool metaOnly,bool thumbnail)133 sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly, bool thumbnail)
134 {
135 ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d) thumbnail(%d)",
136 index, colorFormat, metaOnly, thumbnail);
137 Parcel data, reply;
138 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
139 data.writeInt32(index);
140 data.writeInt32(colorFormat);
141 data.writeInt32(metaOnly);
142 data.writeInt32(thumbnail);
143 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
getImageRectAtIndex(int index,int colorFormat,int left,int top,int right,int bottom)151 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);
164 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
getFrameAtIndex(int index,int colorFormat,bool metaOnly)172 sp<IMemory> getFrameAtIndex(
173 int index, int colorFormat, bool metaOnly)
174 {
175 ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
176 index, colorFormat, metaOnly);
177 Parcel data, reply;
178 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
179 data.writeInt32(index);
180 data.writeInt32(colorFormat);
181 data.writeInt32(metaOnly);
182 remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
183 status_t ret = reply.readInt32();
184 if (ret != NO_ERROR) {
185 return NULL;
186 }
187 return interface_cast<IMemory>(reply.readStrongBinder());
188 }
189
extractAlbumArt()190 sp<IMemory> extractAlbumArt()
191 {
192 Parcel data, reply;
193 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
194 remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
195 status_t ret = reply.readInt32();
196 if (ret != NO_ERROR) {
197 return NULL;
198 }
199 return interface_cast<IMemory>(reply.readStrongBinder());
200 }
201
extractMetadata(int keyCode)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 }
212 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 }
220 return mMetadata.valueFor(keyCode).c_str();
221 } else {
222 return NULL;
223 }
224 }
225
226 private:
227 KeyedVector<int, String8> mMetadata;
228 };
229
230 IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
231
232 // ----------------------------------------------------------------------
233
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)234 status_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);
245
246 sp<IMediaHTTPService> httpService;
247 if (data.readInt32()) {
248 httpService =
249 interface_cast<IMediaHTTPService>(data.readStrongBinder());
250 }
251
252 const char* srcUrl = data.readCString();
253
254 if (httpService == NULL || srcUrl == NULL) {
255 reply->writeInt32(BAD_VALUE);
256 return NO_ERROR;
257 }
258
259 KeyedVector<String8, String8> headers;
260 size_t numHeaders = (size_t) data.readInt32();
261 for (size_t i = 0; i < numHeaders; ++i) {
262 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 }
276 }
277
278 reply->writeInt32(
279 setDataSource(
280 httpService, srcUrl, numHeaders > 0 ? &headers : NULL));
281
282 return NO_ERROR;
283 } break;
284 case SET_DATA_SOURCE_FD: {
285 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
286 int fd = data.readFileDescriptor();
287 int64_t offset = data.readInt64();
288 int64_t length = data.readInt64();
289 reply->writeInt32(setDataSource(fd, offset, length));
290 return NO_ERROR;
291 } break;
292 case SET_DATA_SOURCE_CALLBACK: {
293 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
294 sp<IDataSource> source =
295 interface_cast<IDataSource>(data.readStrongBinder());
296 if (source == NULL) {
297 reply->writeInt32(BAD_VALUE);
298 } else {
299 int32_t hasMime = data.readInt32();
300 const char *mime = NULL;
301 if (hasMime) {
302 mime = data.readCString();
303 }
304 reply->writeInt32(setDataSource(source, mime));
305 }
306 return NO_ERROR;
307 } break;
308 case GET_FRAME_AT_TIME: {
309 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
310 int64_t timeUs = data.readInt64();
311 int option = data.readInt32();
312 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);
316 sp<IMemory> bitmap = getFrameAtTime(timeUs, option, colorFormat, metaOnly);
317 if (bitmap != 0) { // Don't send NULL across the binder interface
318 reply->writeInt32(NO_ERROR);
319 reply->writeStrongBinder(IInterface::asBinder(bitmap));
320 } else {
321 reply->writeInt32(UNKNOWN_ERROR);
322 }
323 return NO_ERROR;
324 } break;
325 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);
330 bool thumbnail = (data.readInt32() != 0);
331 ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d), thumbnail(%d)",
332 index, colorFormat, metaOnly, thumbnail);
333 sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
334 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 }
340 return NO_ERROR;
341 } break;
342
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);
353 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 }
361 return NO_ERROR;
362 } break;
363
364 case GET_FRAME_AT_INDEX: {
365 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
366 int index = data.readInt32();
367 int colorFormat = data.readInt32();
368 bool metaOnly = (data.readInt32() != 0);
369 ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
370 index, colorFormat, metaOnly);
371 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);
377 }
378 return NO_ERROR;
379 } break;
380 case EXTRACT_ALBUM_ART: {
381 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);
385 reply->writeStrongBinder(IInterface::asBinder(albumArt));
386 } 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
410 } // namespace android
411