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    FIND_CODEC_BY_TYPE,
34    FIND_CODEC_BY_NAME,
35};
36
37class BpMediaCodecList: public BpInterface<IMediaCodecList>
38{
39public:
40    BpMediaCodecList(const sp<IBinder>& impl)
41        : BpInterface<IMediaCodecList>(impl)
42    {
43    }
44
45    virtual size_t countCodecs() const
46    {
47        Parcel data, reply;
48        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
49        remote()->transact(COUNT_CODECS, data, &reply);
50        return static_cast<size_t>(reply.readInt32());
51    }
52
53    virtual sp<MediaCodecInfo> getCodecInfo(size_t index) const
54    {
55        Parcel data, reply;
56        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
57        data.writeInt32(index);
58        remote()->transact(GET_CODEC_INFO, data, &reply);
59        status_t err = reply.readInt32();
60        if (err == OK) {
61            return MediaCodecInfo::FromParcel(reply);
62        } else {
63            return NULL;
64        }
65    }
66
67    virtual ssize_t findCodecByType(
68            const char *type, bool encoder, size_t startIndex = 0) const
69    {
70        if (startIndex > INT32_MAX) {
71            return NAME_NOT_FOUND;
72        }
73
74        Parcel data, reply;
75        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
76        data.writeCString(type);
77        data.writeInt32(encoder);
78        data.writeInt32(startIndex);
79        remote()->transact(FIND_CODEC_BY_TYPE, data, &reply);
80        return static_cast<ssize_t>(reply.readInt32());
81    }
82
83    virtual ssize_t findCodecByName(const char *name) const
84    {
85        Parcel data, reply;
86        data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor());
87        data.writeCString(name);
88        remote()->transact(FIND_CODEC_BY_NAME, data, &reply);
89        return static_cast<ssize_t>(reply.readInt32());
90    }
91};
92
93IMPLEMENT_META_INTERFACE(MediaCodecList, "android.media.IMediaCodecList");
94
95// ----------------------------------------------------------------------
96
97status_t BnMediaCodecList::onTransact(
98    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
99{
100    switch (code) {
101        case COUNT_CODECS:
102        {
103            CHECK_INTERFACE(IMediaCodecList, data, reply);
104            size_t count = countCodecs();
105            if (count > INT32_MAX) {
106                count = INT32_MAX;
107            }
108            reply->writeInt32(count);
109            return NO_ERROR;
110        }
111        break;
112
113        case GET_CODEC_INFO:
114        {
115            CHECK_INTERFACE(IMediaCodecList, data, reply);
116            size_t index = static_cast<size_t>(data.readInt32());
117            const sp<MediaCodecInfo> info = getCodecInfo(index);
118            if (info != NULL) {
119                reply->writeInt32(OK);
120                info->writeToParcel(reply);
121            } else {
122                reply->writeInt32(-ERANGE);
123            }
124            return NO_ERROR;
125        }
126        break;
127
128        case FIND_CODEC_BY_TYPE:
129        {
130            CHECK_INTERFACE(IMediaCodecList, data, reply);
131            const char *type = data.readCString();
132            bool isEncoder = static_cast<bool>(data.readInt32());
133            size_t startIndex = static_cast<size_t>(data.readInt32());
134            ssize_t index = findCodecByType(type, isEncoder, startIndex);
135            if (index > INT32_MAX || index < 0) {
136                index = NAME_NOT_FOUND;
137            }
138            reply->writeInt32(index);
139            return NO_ERROR;
140        }
141        break;
142
143        case FIND_CODEC_BY_NAME:
144        {
145            CHECK_INTERFACE(IMediaCodecList, data, reply);
146            const char *name = data.readCString();
147            ssize_t index = findCodecByName(name);
148            if (index > INT32_MAX || index < 0) {
149                index = NAME_NOT_FOUND;
150            }
151            reply->writeInt32(index);
152            return NO_ERROR;
153        }
154        break;
155
156        default:
157            return BBinder::onTransact(code, data, reply, flags);
158    }
159}
160
161// ----------------------------------------------------------------------------
162
163}; // namespace android
164