• 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 <stdint.h>
19 #include <sys/types.h>
20 #include <binder/Parcel.h>
21 #include <SkBitmap.h>
22 #include <media/IMediaMetadataRetriever.h>
23 #include <utils/String8.h>
24 
25 // The binder is supposed to propagate the scheduler group across
26 // the binder interface so that remote calls are executed with
27 // the same priority as local calls. This is currently not working
28 // so this change puts in a temporary hack to fix the issue with
29 // metadata retrieval which can be a huge CPU hit if done on a
30 // foreground thread.
31 #ifndef DISABLE_GROUP_SCHEDULE_HACK
32 
33 #undef LOG_TAG
34 #define LOG_TAG "IMediaMetadataRetriever"
35 #include <utils/Log.h>
36 #include <cutils/sched_policy.h>
37 
38 namespace android {
39 
sendSchedPolicy(Parcel & data)40 static void sendSchedPolicy(Parcel& data)
41 {
42     SchedPolicy policy;
43     get_sched_policy(gettid(), &policy);
44     data.writeInt32(policy);
45 }
46 
setSchedPolicy(const Parcel & data)47 static void setSchedPolicy(const Parcel& data)
48 {
49     SchedPolicy policy = (SchedPolicy) data.readInt32();
50     set_sched_policy(gettid(), policy);
51 }
restoreSchedPolicy()52 static void restoreSchedPolicy()
53 {
54     set_sched_policy(gettid(), SP_FOREGROUND);
55 }
56 }; // end namespace android
57 #endif
58 
59 namespace android {
60 
61 enum {
62     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
63     SET_DATA_SOURCE_URL,
64     SET_DATA_SOURCE_FD,
65     GET_FRAME_AT_TIME,
66     EXTRACT_ALBUM_ART,
67     EXTRACT_METADATA,
68 };
69 
70 class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
71 {
72 public:
BpMediaMetadataRetriever(const sp<IBinder> & impl)73     BpMediaMetadataRetriever(const sp<IBinder>& impl)
74         : BpInterface<IMediaMetadataRetriever>(impl)
75     {
76     }
77 
78     // disconnect from media metadata retriever service
disconnect()79     void disconnect()
80     {
81         Parcel data, reply;
82         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
83         remote()->transact(DISCONNECT, data, &reply);
84     }
85 
setDataSource(const char * srcUrl,const KeyedVector<String8,String8> * headers)86     status_t setDataSource(
87             const char *srcUrl, const KeyedVector<String8, String8> *headers)
88     {
89         Parcel data, reply;
90         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
91         data.writeCString(srcUrl);
92 
93         if (headers == NULL) {
94             data.writeInt32(0);
95         } else {
96             // serialize the headers
97             data.writeInt32(headers->size());
98             for (size_t i = 0; i < headers->size(); ++i) {
99                 data.writeString8(headers->keyAt(i));
100                 data.writeString8(headers->valueAt(i));
101             }
102         }
103 
104         remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
105         return reply.readInt32();
106     }
107 
setDataSource(int fd,int64_t offset,int64_t length)108     status_t setDataSource(int fd, int64_t offset, int64_t length)
109     {
110         Parcel data, reply;
111         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
112         data.writeFileDescriptor(fd);
113         data.writeInt64(offset);
114         data.writeInt64(length);
115         remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
116         return reply.readInt32();
117     }
118 
getFrameAtTime(int64_t timeUs,int option)119     sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
120     {
121         LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
122         Parcel data, reply;
123         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
124         data.writeInt64(timeUs);
125         data.writeInt32(option);
126 #ifndef DISABLE_GROUP_SCHEDULE_HACK
127         sendSchedPolicy(data);
128 #endif
129         remote()->transact(GET_FRAME_AT_TIME, data, &reply);
130         status_t ret = reply.readInt32();
131         if (ret != NO_ERROR) {
132             return NULL;
133         }
134         return interface_cast<IMemory>(reply.readStrongBinder());
135     }
136 
extractAlbumArt()137     sp<IMemory> extractAlbumArt()
138     {
139         Parcel data, reply;
140         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
141 #ifndef DISABLE_GROUP_SCHEDULE_HACK
142         sendSchedPolicy(data);
143 #endif
144         remote()->transact(EXTRACT_ALBUM_ART, 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 
extractMetadata(int keyCode)152     const char* extractMetadata(int keyCode)
153     {
154         Parcel data, reply;
155         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
156 #ifndef DISABLE_GROUP_SCHEDULE_HACK
157         sendSchedPolicy(data);
158 #endif
159         data.writeInt32(keyCode);
160         remote()->transact(EXTRACT_METADATA, data, &reply);
161         status_t ret = reply.readInt32();
162         if (ret != NO_ERROR) {
163             return NULL;
164         }
165         return reply.readCString();
166     }
167 };
168 
169 IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
170 
171 // ----------------------------------------------------------------------
172 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)173 status_t BnMediaMetadataRetriever::onTransact(
174     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
175 {
176     switch (code) {
177         case DISCONNECT: {
178             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
179             disconnect();
180             return NO_ERROR;
181         } break;
182         case SET_DATA_SOURCE_URL: {
183             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
184             const char* srcUrl = data.readCString();
185 
186             KeyedVector<String8, String8> headers;
187             int32_t numHeaders = data.readInt32();
188             for (int i = 0; i < numHeaders; ++i) {
189                 String8 key = data.readString8();
190                 String8 value = data.readString8();
191                 headers.add(key, value);
192             }
193 
194             reply->writeInt32(
195                     setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL));
196 
197             return NO_ERROR;
198         } break;
199         case SET_DATA_SOURCE_FD: {
200             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
201             int fd = dup(data.readFileDescriptor());
202             int64_t offset = data.readInt64();
203             int64_t length = data.readInt64();
204             reply->writeInt32(setDataSource(fd, offset, length));
205             return NO_ERROR;
206         } break;
207         case GET_FRAME_AT_TIME: {
208             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
209             int64_t timeUs = data.readInt64();
210             int option = data.readInt32();
211             LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
212 #ifndef DISABLE_GROUP_SCHEDULE_HACK
213             setSchedPolicy(data);
214 #endif
215             sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
216             if (bitmap != 0) {  // Don't send NULL across the binder interface
217                 reply->writeInt32(NO_ERROR);
218                 reply->writeStrongBinder(bitmap->asBinder());
219             } else {
220                 reply->writeInt32(UNKNOWN_ERROR);
221             }
222 #ifndef DISABLE_GROUP_SCHEDULE_HACK
223             restoreSchedPolicy();
224 #endif
225             return NO_ERROR;
226         } break;
227         case EXTRACT_ALBUM_ART: {
228             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
229 #ifndef DISABLE_GROUP_SCHEDULE_HACK
230             setSchedPolicy(data);
231 #endif
232             sp<IMemory> albumArt = extractAlbumArt();
233             if (albumArt != 0) {  // Don't send NULL across the binder interface
234                 reply->writeInt32(NO_ERROR);
235                 reply->writeStrongBinder(albumArt->asBinder());
236             } else {
237                 reply->writeInt32(UNKNOWN_ERROR);
238             }
239 #ifndef DISABLE_GROUP_SCHEDULE_HACK
240             restoreSchedPolicy();
241 #endif
242             return NO_ERROR;
243         } break;
244         case EXTRACT_METADATA: {
245             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
246 #ifndef DISABLE_GROUP_SCHEDULE_HACK
247             setSchedPolicy(data);
248 #endif
249             int keyCode = data.readInt32();
250             const char* value = extractMetadata(keyCode);
251             if (value != NULL) {  // Don't send NULL across the binder interface
252                 reply->writeInt32(NO_ERROR);
253                 reply->writeCString(value);
254             } else {
255                 reply->writeInt32(UNKNOWN_ERROR);
256             }
257 #ifndef DISABLE_GROUP_SCHEDULE_HACK
258             restoreSchedPolicy();
259 #endif
260             return NO_ERROR;
261         } break;
262         default:
263             return BBinder::onTransact(code, data, reply, flags);
264     }
265 }
266 
267 // ----------------------------------------------------------------------------
268 
269 }; // namespace android
270