xref: /aosp_15_r20/frameworks/av/media/libmedia/IMediaMetadataRetriever.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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