• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <processgroup/sched_policy.h>
27 #include <utils/String8.h>
28 #include <utils/KeyedVector.h>
29 
30 namespace android {
31 
32 enum {
33     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
34     SET_DATA_SOURCE_URL,
35     SET_DATA_SOURCE_FD,
36     SET_DATA_SOURCE_CALLBACK,
37     GET_FRAME_AT_TIME,
38     GET_IMAGE_AT_INDEX,
39     GET_IMAGE_RECT_AT_INDEX,
40     GET_FRAME_AT_INDEX,
41     EXTRACT_ALBUM_ART,
42     EXTRACT_METADATA,
43 };
44 
45 class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
46 {
47 public:
BpMediaMetadataRetriever(const sp<IBinder> & impl)48     explicit BpMediaMetadataRetriever(const sp<IBinder>& impl)
49         : BpInterface<IMediaMetadataRetriever>(impl)
50     {
51     }
52 
53     // disconnect from media metadata retriever service
disconnect()54     void disconnect()
55     {
56         Parcel data, reply;
57         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
58         remote()->transact(DISCONNECT, data, &reply);
59     }
60 
setDataSource(const sp<IMediaHTTPService> & httpService,const char * srcUrl,const KeyedVector<String8,String8> * headers)61     status_t setDataSource(
62             const sp<IMediaHTTPService> &httpService,
63             const char *srcUrl,
64             const KeyedVector<String8, String8> *headers)
65     {
66         Parcel data, reply;
67         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
68         data.writeInt32(httpService != NULL);
69         if (httpService != NULL) {
70             data.writeStrongBinder(IInterface::asBinder(httpService));
71         }
72         data.writeCString(srcUrl);
73 
74         if (headers == NULL) {
75             data.writeInt32(0);
76         } else {
77             // serialize the headers
78             data.writeInt32(headers->size());
79             for (size_t i = 0; i < headers->size(); ++i) {
80                 data.writeString8(headers->keyAt(i));
81                 data.writeString8(headers->valueAt(i));
82             }
83         }
84 
85         remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
86         return reply.readInt32();
87     }
88 
setDataSource(int fd,int64_t offset,int64_t length)89     status_t setDataSource(int fd, int64_t offset, int64_t length)
90     {
91         Parcel data, reply;
92         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
93         data.writeFileDescriptor(fd);
94         data.writeInt64(offset);
95         data.writeInt64(length);
96         remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
97         return reply.readInt32();
98     }
99 
setDataSource(const sp<IDataSource> & source,const char * mime)100     status_t setDataSource(const sp<IDataSource>& source, const char *mime)
101     {
102         Parcel data, reply;
103         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
104         data.writeStrongBinder(IInterface::asBinder(source));
105 
106         if (mime != NULL) {
107             data.writeInt32(1);
108             data.writeCString(mime);
109         } else {
110             data.writeInt32(0);
111         }
112         remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
113         return reply.readInt32();
114     }
115 
getFrameAtTime(int64_t timeUs,int option,int colorFormat,bool metaOnly)116     sp<IMemory> getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly)
117     {
118         ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d) metaOnly(%d)",
119                 timeUs, option, colorFormat, metaOnly);
120         Parcel data, reply;
121         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
122         data.writeInt64(timeUs);
123         data.writeInt32(option);
124         data.writeInt32(colorFormat);
125         data.writeInt32(metaOnly);
126         remote()->transact(GET_FRAME_AT_TIME, data, &reply);
127         status_t ret = reply.readInt32();
128         if (ret != NO_ERROR) {
129             return NULL;
130         }
131         return interface_cast<IMemory>(reply.readStrongBinder());
132     }
133 
getImageAtIndex(int index,int colorFormat,bool metaOnly,bool thumbnail)134     sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly, bool thumbnail)
135     {
136         ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d) thumbnail(%d)",
137                 index, colorFormat, metaOnly, thumbnail);
138         Parcel data, reply;
139         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
140         data.writeInt32(index);
141         data.writeInt32(colorFormat);
142         data.writeInt32(metaOnly);
143         data.writeInt32(thumbnail);
144         remote()->transact(GET_IMAGE_AT_INDEX, data, &reply);
145         status_t ret = reply.readInt32();
146         if (ret != NO_ERROR) {
147             return NULL;
148         }
149         return interface_cast<IMemory>(reply.readStrongBinder());
150     }
151 
getImageRectAtIndex(int index,int colorFormat,int left,int top,int right,int bottom)152     sp<IMemory> getImageRectAtIndex(
153             int index, int colorFormat, int left, int top, int right, int bottom)
154     {
155         ALOGV("getImageRectAtIndex: index %d, colorFormat(%d) rect {%d, %d, %d, %d}",
156                 index, colorFormat, left, top, right, bottom);
157         Parcel data, reply;
158         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
159         data.writeInt32(index);
160         data.writeInt32(colorFormat);
161         data.writeInt32(left);
162         data.writeInt32(top);
163         data.writeInt32(right);
164         data.writeInt32(bottom);
165         remote()->transact(GET_IMAGE_RECT_AT_INDEX, data, &reply);
166         status_t ret = reply.readInt32();
167         if (ret != NO_ERROR) {
168             return NULL;
169         }
170         return interface_cast<IMemory>(reply.readStrongBinder());
171     }
172 
getFrameAtIndex(int index,int colorFormat,bool metaOnly)173     sp<IMemory> getFrameAtIndex(
174             int index, int colorFormat, bool metaOnly)
175     {
176         ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
177                 index, colorFormat, metaOnly);
178         Parcel data, reply;
179         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
180         data.writeInt32(index);
181         data.writeInt32(colorFormat);
182         data.writeInt32(metaOnly);
183         remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
184         status_t ret = reply.readInt32();
185         if (ret != NO_ERROR) {
186             return NULL;
187         }
188         return interface_cast<IMemory>(reply.readStrongBinder());
189     }
190 
extractAlbumArt()191     sp<IMemory> extractAlbumArt()
192     {
193         Parcel data, reply;
194         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
195         remote()->transact(EXTRACT_ALBUM_ART, data, &reply);
196         status_t ret = reply.readInt32();
197         if (ret != NO_ERROR) {
198             return NULL;
199         }
200         return interface_cast<IMemory>(reply.readStrongBinder());
201     }
202 
extractMetadata(int keyCode)203     const char* extractMetadata(int keyCode)
204     {
205         Parcel data, reply;
206         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
207         data.writeInt32(keyCode);
208         remote()->transact(EXTRACT_METADATA, data, &reply);
209         status_t ret = reply.readInt32();
210         if (ret != NO_ERROR) {
211             return NULL;
212         }
213         const char* str = reply.readCString();
214         if (str != NULL) {
215             String8 value(str);
216             if (mMetadata.indexOfKey(keyCode) < 0) {
217                 mMetadata.add(keyCode, value);
218             } else {
219                 mMetadata.replaceValueFor(keyCode, value);
220             }
221             return mMetadata.valueFor(keyCode).c_str();
222         } else {
223             return NULL;
224         }
225     }
226 
227 private:
228     KeyedVector<int, String8> mMetadata;
229 };
230 
231 IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
232 
233 // ----------------------------------------------------------------------
234 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)235 status_t BnMediaMetadataRetriever::onTransact(
236     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
237 {
238     switch (code) {
239         case DISCONNECT: {
240             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
241             disconnect();
242             return NO_ERROR;
243         } break;
244         case SET_DATA_SOURCE_URL: {
245             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
246 
247             sp<IMediaHTTPService> httpService;
248             if (data.readInt32()) {
249                 httpService =
250                     interface_cast<IMediaHTTPService>(data.readStrongBinder());
251             }
252 
253             const char* srcUrl = data.readCString();
254 
255             if (httpService == NULL || srcUrl == NULL) {
256                 reply->writeInt32(BAD_VALUE);
257                 return NO_ERROR;
258             }
259 
260             KeyedVector<String8, String8> headers;
261             size_t numHeaders = (size_t) data.readInt32();
262             for (size_t i = 0; i < numHeaders; ++i) {
263                 String8 key;
264                 String8 value;
265                 status_t status;
266                 status = data.readString8(&key);
267                 if (status != OK) {
268                     return status;
269                 }
270                 status = data.readString8(&value);
271                 if (status != OK) {
272                     return status;
273                 }
274                 if (headers.add(key, value) < 0) {
275                     return UNKNOWN_ERROR;
276                 }
277             }
278 
279             reply->writeInt32(
280                     setDataSource(
281                         httpService, srcUrl, numHeaders > 0 ? &headers : NULL));
282 
283             return NO_ERROR;
284         } break;
285         case SET_DATA_SOURCE_FD: {
286             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
287             int fd = data.readFileDescriptor();
288             int64_t offset = data.readInt64();
289             int64_t length = data.readInt64();
290             reply->writeInt32(setDataSource(fd, offset, length));
291             return NO_ERROR;
292         } break;
293         case SET_DATA_SOURCE_CALLBACK: {
294             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
295             sp<IDataSource> source =
296                 interface_cast<IDataSource>(data.readStrongBinder());
297             if (source == NULL) {
298                 reply->writeInt32(BAD_VALUE);
299             } else {
300                 int32_t hasMime = data.readInt32();
301                 const char *mime = NULL;
302                 if (hasMime) {
303                     mime = data.readCString();
304                 }
305                 reply->writeInt32(setDataSource(source, mime));
306             }
307             return NO_ERROR;
308         } break;
309         case GET_FRAME_AT_TIME: {
310             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
311             int64_t timeUs = data.readInt64();
312             int option = data.readInt32();
313             int colorFormat = data.readInt32();
314             bool metaOnly = (data.readInt32() != 0);
315             ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d), metaOnly(%d)",
316                     timeUs, option, colorFormat, metaOnly);
317             sp<IMemory> bitmap = getFrameAtTime(timeUs, option, colorFormat, metaOnly);
318             if (bitmap != 0) {  // Don't send NULL across the binder interface
319                 reply->writeInt32(NO_ERROR);
320                 reply->writeStrongBinder(IInterface::asBinder(bitmap));
321             } else {
322                 reply->writeInt32(UNKNOWN_ERROR);
323             }
324             return NO_ERROR;
325         } break;
326         case GET_IMAGE_AT_INDEX: {
327             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
328             int index = data.readInt32();
329             int colorFormat = data.readInt32();
330             bool metaOnly = (data.readInt32() != 0);
331             bool thumbnail = (data.readInt32() != 0);
332             ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d), thumbnail(%d)",
333                     index, colorFormat, metaOnly, thumbnail);
334             sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
335             if (bitmap != 0) {  // Don't send NULL across the binder interface
336                 reply->writeInt32(NO_ERROR);
337                 reply->writeStrongBinder(IInterface::asBinder(bitmap));
338             } else {
339                 reply->writeInt32(UNKNOWN_ERROR);
340             }
341             return NO_ERROR;
342         } break;
343 
344         case GET_IMAGE_RECT_AT_INDEX: {
345             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
346             int index = data.readInt32();
347             int colorFormat = data.readInt32();
348             int left = data.readInt32();
349             int top = data.readInt32();
350             int right = data.readInt32();
351             int bottom = data.readInt32();
352             ALOGV("getImageRectAtIndex: index(%d), colorFormat(%d), rect {%d, %d, %d, %d}",
353                     index, colorFormat, left, top, right, bottom);
354             sp<IMemory> bitmap = getImageRectAtIndex(
355                     index, colorFormat, left, top, right, bottom);
356             if (bitmap != 0) {  // Don't send NULL across the binder interface
357                 reply->writeInt32(NO_ERROR);
358                 reply->writeStrongBinder(IInterface::asBinder(bitmap));
359             } else {
360                 reply->writeInt32(UNKNOWN_ERROR);
361             }
362             return NO_ERROR;
363         } break;
364 
365         case GET_FRAME_AT_INDEX: {
366             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
367             int index = data.readInt32();
368             int colorFormat = data.readInt32();
369             bool metaOnly = (data.readInt32() != 0);
370             ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
371                     index, colorFormat, metaOnly);
372             sp<IMemory> frame = getFrameAtIndex(index, colorFormat, metaOnly);
373             if (frame != nullptr) {  // Don't send NULL across the binder interface
374                 reply->writeInt32(NO_ERROR);
375                 reply->writeStrongBinder(IInterface::asBinder(frame));
376             } else {
377                 reply->writeInt32(UNKNOWN_ERROR);
378             }
379             return NO_ERROR;
380         } break;
381         case EXTRACT_ALBUM_ART: {
382             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
383             sp<IMemory> albumArt = extractAlbumArt();
384             if (albumArt != 0) {  // Don't send NULL across the binder interface
385                 reply->writeInt32(NO_ERROR);
386                 reply->writeStrongBinder(IInterface::asBinder(albumArt));
387             } else {
388                 reply->writeInt32(UNKNOWN_ERROR);
389             }
390             return NO_ERROR;
391         } break;
392         case EXTRACT_METADATA: {
393             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
394             int keyCode = data.readInt32();
395             const char* value = extractMetadata(keyCode);
396             if (value != NULL) {  // Don't send NULL across the binder interface
397                 reply->writeInt32(NO_ERROR);
398                 reply->writeCString(value);
399             } else {
400                 reply->writeInt32(UNKNOWN_ERROR);
401             }
402             return NO_ERROR;
403         } break;
404         default:
405             return BBinder::onTransact(code, data, reply, flags);
406     }
407 }
408 
409 // ----------------------------------------------------------------------------
410 
411 } // namespace android
412