1/*
2 * Copyright (C) 2014, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdint.h>
18#include <sys/types.h>
19
20#include <binder/Parcel.h>
21#include <media/stagefright/MediaCodecList.h>
22#include <media/IMediaCodecList.h>
23#include <media/MediaCodecInfo.h>
24
25#include <utils/Errors.h>  // for status_t
26
27namespace android {
28
29enum {
30    CREATE = IBinder::FIRST_CALL_TRANSACTION,
31    COUNT_CODECS,
32    GET_CODEC_INFO,
33    GET_GLOBAL_SETTINGS,
34    FIND_CODEC_BY_TYPE,
35    FIND_CODEC_BY_NAME,
36};
37
38class BpMediaCodecList: public BpInterface<IMediaCodecList>
39{
40public:
41    explicit BpMediaCodecList(const sp<IBinder>& impl)
42        : BpInterface<IMediaCodecList>(impl)
43    {
44    }
45
46    virtual size_t countCodecs() const
47    {
48        Parcel data, reply;
49        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
50        remote()->transact(COUNT_CODECS, data, &reply);
51        return static_cast<size_t>(reply.readInt32());
52    }
53
54    virtual sp<MediaCodecInfo> getCodecInfo(size_t index) const
55    {
56        Parcel data, reply;
57        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
58        data.writeInt32(index);
59        remote()->transact(GET_CODEC_INFO, data, &reply);
60        status_t err = reply.readInt32();
61        if (err == OK) {
62            return MediaCodecInfo::FromParcel(reply);
63        } else {
64            return NULL;
65        }
66    }
67
68    virtual const sp<AMessage> getGlobalSettings() const
69    {
70        Parcel data, reply;
71        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
72        remote()->transact(GET_GLOBAL_SETTINGS, data, &reply);
73        status_t err = reply.readInt32();
74        if (err == OK) {
75            return AMessage::FromParcel(reply);
76        } else {
77            return NULL;
78        }
79    }
80
81    virtual ssize_t findCodecByType(
82            const char *type, bool encoder, size_t startIndex = 0) const
83    {
84        if (startIndex > INT32_MAX) {
85            return NAME_NOT_FOUND;
86        }
87
88        Parcel data, reply;
89        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
90        data.writeCString(type);
91        data.writeInt32(encoder);
92        data.writeInt32(startIndex);
93        remote()->transact(FIND_CODEC_BY_TYPE, data, &reply);
94        return static_cast<ssize_t>(reply.readInt32());
95    }
96
97    virtual ssize_t findCodecByName(const char *name) const
98    {
99        Parcel data, reply;
100        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
101        data.writeCString(name);
102        remote()->transact(FIND_CODEC_BY_NAME, data, &reply);
103        return static_cast<ssize_t>(reply.readInt32());
104    }
105};
106
107IMPLEMENT_META_INTERFACE(MediaCodecList, "android.media.IMediaCodecList");
108
109// ----------------------------------------------------------------------
110
111status_t BnMediaCodecList::onTransact(
112    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
113{
114    switch (code) {
115        case COUNT_CODECS:
116        {
117            CHECK_INTERFACE(IMediaCodecList, data, reply);
118            size_t count = countCodecs();
119            if (count > INT32_MAX) {
120                count = INT32_MAX;
121            }
122            reply->writeInt32(count);
123            return NO_ERROR;
124        }
125        break;
126
127        case GET_CODEC_INFO:
128        {
129            CHECK_INTERFACE(IMediaCodecList, data, reply);
130            size_t index = static_cast<size_t>(data.readInt32());
131            const sp<MediaCodecInfo> info = getCodecInfo(index);
132            if (info != NULL) {
133                reply->writeInt32(OK);
134                info->writeToParcel(reply);
135            } else {
136                reply->writeInt32(-ERANGE);
137            }
138            return NO_ERROR;
139        }
140        break;
141
142        case GET_GLOBAL_SETTINGS:
143        {
144            CHECK_INTERFACE(IMediaCodecList, data, reply);
145            const sp<AMessage> info = getGlobalSettings();
146            if (info != NULL) {
147                reply->writeInt32(OK);
148                info->writeToParcel(reply);
149            } else {
150                reply->writeInt32(-ERANGE);
151            }
152            return NO_ERROR;
153        }
154        break;
155
156        case FIND_CODEC_BY_TYPE:
157        {
158            CHECK_INTERFACE(IMediaCodecList, data, reply);
159            const char *type = data.readCString();
160            if (type == NULL) {
161                reply->writeInt32(NAME_NOT_FOUND);
162                return NO_ERROR;
163            }
164            bool isEncoder = static_cast<bool>(data.readInt32());
165            size_t startIndex = static_cast<size_t>(data.readInt32());
166            ssize_t index = findCodecByType(type, isEncoder, startIndex);
167            if (index > INT32_MAX || index < 0) {
168                index = NAME_NOT_FOUND;
169            }
170            reply->writeInt32(index);
171            return NO_ERROR;
172        }
173        break;
174
175        case FIND_CODEC_BY_NAME:
176        {
177            CHECK_INTERFACE(IMediaCodecList, data, reply);
178            const char *name = data.readCString();
179            if (name == NULL) {
180                reply->writeInt32(NAME_NOT_FOUND);
181                return NO_ERROR;
182            }
183            ssize_t index = findCodecByName(name);
184            if (index > INT32_MAX || index < 0) {
185                index = NAME_NOT_FOUND;
186            }
187            reply->writeInt32(index);
188            return NO_ERROR;
189        }
190        break;
191
192        default:
193            return BBinder::onTransact(code, data, reply, flags);
194    }
195}
196
197// ----------------------------------------------------------------------------
198
199} // namespace android
200