IOMX.cpp revision f4148b55c5d6f68b22462e3880015fefa91ae7c6
1//#define LOG_NDEBUG 0
2#define LOG_TAG "IOMX"
3#include <utils/Log.h>
4
5#include <binder/IMemory.h>
6#include <binder/Parcel.h>
7#include <media/IOMX.h>
8#include <ui/ISurface.h>
9#include <ui/Surface.h>
10
11namespace android {
12
13enum {
14    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
15    LIST_NODES,
16    ALLOCATE_NODE,
17    FREE_NODE,
18    SEND_COMMAND,
19    GET_PARAMETER,
20    SET_PARAMETER,
21    USE_BUFFER,
22    ALLOC_BUFFER,
23    ALLOC_BUFFER_WITH_BACKUP,
24    FREE_BUFFER,
25    OBSERVE_NODE,
26    FILL_BUFFER,
27    EMPTY_BUFFER,
28    CREATE_RENDERER,
29    OBSERVER_ON_MSG,
30    RENDERER_RENDER,
31};
32
33sp<IOMXRenderer> IOMX::createRenderer(
34        const sp<Surface> &surface,
35        const char *componentName,
36        OMX_COLOR_FORMATTYPE colorFormat,
37        size_t encodedWidth, size_t encodedHeight,
38        size_t displayWidth, size_t displayHeight) {
39    return createRenderer(
40            surface->getISurface(),
41            componentName, colorFormat, encodedWidth, encodedHeight,
42            displayWidth, displayHeight);
43}
44
45static void *readVoidStar(const Parcel *parcel) {
46    // FIX if sizeof(void *) != sizeof(int32)
47    return (void *)parcel->readInt32();
48}
49
50static void writeVoidStar(void *x, Parcel *parcel) {
51    // FIX if sizeof(void *) != sizeof(int32)
52    parcel->writeInt32((int32_t)x);
53}
54
55class BpOMX : public BpInterface<IOMX> {
56public:
57    BpOMX(const sp<IBinder> &impl)
58        : BpInterface<IOMX>(impl) {
59    }
60
61    virtual status_t list_nodes(List<String8> *list) {
62        list->clear();
63
64        Parcel data, reply;
65        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
66        remote()->transact(LIST_NODES, data, &reply);
67
68        int32_t n = reply.readInt32();
69        for (int32_t i = 0; i < n; ++i) {
70            String8 s = reply.readString8();
71
72            list->push_back(s);
73        }
74
75        return OK;
76    }
77
78    virtual status_t allocate_node(const char *name, node_id *node) {
79        Parcel data, reply;
80        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
81        data.writeCString(name);
82        remote()->transact(ALLOCATE_NODE, data, &reply);
83
84        status_t err = reply.readInt32();
85        if (err == OK) {
86            *node = readVoidStar(&reply);
87        } else {
88            *node = 0;
89        }
90
91        return err;
92    }
93
94    virtual status_t free_node(node_id node) {
95        Parcel data, reply;
96        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
97        writeVoidStar(node, &data);
98        remote()->transact(FREE_NODE, data, &reply);
99
100        return reply.readInt32();
101    }
102
103    virtual status_t send_command(
104            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
105        Parcel data, reply;
106        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
107        writeVoidStar(node, &data);
108        data.writeInt32(cmd);
109        data.writeInt32(param);
110        remote()->transact(SEND_COMMAND, data, &reply);
111
112        return reply.readInt32();
113    }
114
115    virtual status_t get_parameter(
116            node_id node, OMX_INDEXTYPE index,
117            void *params, size_t size) {
118        Parcel data, reply;
119        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
120        writeVoidStar(node, &data);
121        data.writeInt32(index);
122        data.writeInt32(size);
123        data.write(params, size);
124        remote()->transact(GET_PARAMETER, data, &reply);
125
126        status_t err = reply.readInt32();
127        if (err != OK) {
128            return err;
129        }
130
131        reply.read(params, size);
132
133        return OK;
134    }
135
136    virtual status_t set_parameter(
137            node_id node, OMX_INDEXTYPE index,
138            const void *params, size_t size) {
139        Parcel data, reply;
140        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
141        writeVoidStar(node, &data);
142        data.writeInt32(index);
143        data.writeInt32(size);
144        data.write(params, size);
145        remote()->transact(SET_PARAMETER, data, &reply);
146
147        return reply.readInt32();
148    }
149
150    virtual status_t use_buffer(
151            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
152            buffer_id *buffer) {
153        Parcel data, reply;
154        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
155        writeVoidStar(node, &data);
156        data.writeInt32(port_index);
157        data.writeStrongBinder(params->asBinder());
158        remote()->transact(USE_BUFFER, data, &reply);
159
160        status_t err = reply.readInt32();
161        if (err != OK) {
162            *buffer = 0;
163
164            return err;
165        }
166
167        *buffer = readVoidStar(&reply);
168
169        return err;
170    }
171
172    virtual status_t allocate_buffer(
173            node_id node, OMX_U32 port_index, size_t size,
174            buffer_id *buffer) {
175        Parcel data, reply;
176        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
177        writeVoidStar(node, &data);
178        data.writeInt32(port_index);
179        data.writeInt32(size);
180        remote()->transact(ALLOC_BUFFER, data, &reply);
181
182        status_t err = reply.readInt32();
183        if (err != OK) {
184            *buffer = 0;
185
186            return err;
187        }
188
189        *buffer = readVoidStar(&reply);
190
191        return err;
192    }
193
194    virtual status_t allocate_buffer_with_backup(
195            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
196            buffer_id *buffer) {
197        Parcel data, reply;
198        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
199        writeVoidStar(node, &data);
200        data.writeInt32(port_index);
201        data.writeStrongBinder(params->asBinder());
202        remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
203
204        status_t err = reply.readInt32();
205        if (err != OK) {
206            *buffer = 0;
207
208            return err;
209        }
210
211        *buffer = readVoidStar(&reply);
212
213        return err;
214    }
215
216    virtual status_t free_buffer(
217            node_id node, OMX_U32 port_index, buffer_id buffer) {
218        Parcel data, reply;
219        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
220        writeVoidStar(node, &data);
221        data.writeInt32(port_index);
222        writeVoidStar(buffer, &data);
223        remote()->transact(FREE_BUFFER, data, &reply);
224
225        return reply.readInt32();
226    }
227
228    virtual status_t observe_node(
229            node_id node, const sp<IOMXObserver> &observer) {
230        Parcel data, reply;
231        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
232        writeVoidStar(node, &data);
233        data.writeStrongBinder(observer->asBinder());
234        remote()->transact(OBSERVE_NODE, data, &reply);
235
236        return reply.readInt32();
237    }
238
239    virtual void fill_buffer(node_id node, buffer_id buffer) {
240        Parcel data, reply;
241        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
242        writeVoidStar(node, &data);
243        writeVoidStar(buffer, &data);
244        remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
245    }
246
247    virtual void empty_buffer(
248            node_id node,
249            buffer_id buffer,
250            OMX_U32 range_offset, OMX_U32 range_length,
251            OMX_U32 flags, OMX_TICKS timestamp) {
252        Parcel data, reply;
253        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
254        writeVoidStar(node, &data);
255        writeVoidStar(buffer, &data);
256        data.writeInt32(range_offset);
257        data.writeInt32(range_length);
258        data.writeInt32(flags);
259        data.writeInt64(timestamp);
260        remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
261    }
262
263    virtual sp<IOMXRenderer> createRenderer(
264            const sp<ISurface> &surface,
265            const char *componentName,
266            OMX_COLOR_FORMATTYPE colorFormat,
267            size_t encodedWidth, size_t encodedHeight,
268            size_t displayWidth, size_t displayHeight) {
269        Parcel data, reply;
270        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
271
272        data.writeStrongBinder(surface->asBinder());
273        data.writeCString(componentName);
274        data.writeInt32(colorFormat);
275        data.writeInt32(encodedWidth);
276        data.writeInt32(encodedHeight);
277        data.writeInt32(displayWidth);
278        data.writeInt32(displayHeight);
279
280        remote()->transact(CREATE_RENDERER, data, &reply);
281
282        return interface_cast<IOMXRenderer>(reply.readStrongBinder());
283    }
284};
285
286IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
287
288////////////////////////////////////////////////////////////////////////////////
289
290#define CHECK_INTERFACE(interface, data, reply) \
291        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
292            LOGW("Call incorrectly routed to " #interface); \
293            return PERMISSION_DENIED; \
294        } } while (0)
295
296status_t BnOMX::onTransact(
297    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
298    switch (code) {
299        case LIST_NODES:
300        {
301            CHECK_INTERFACE(IOMX, data, reply);
302
303            List<String8> list;
304            list_nodes(&list);
305
306            reply->writeInt32(list.size());
307            for (List<String8>::iterator it = list.begin();
308                 it != list.end(); ++it) {
309                reply->writeString8(*it);
310            }
311
312            return NO_ERROR;
313        }
314
315        case ALLOCATE_NODE:
316        {
317            CHECK_INTERFACE(IOMX, data, reply);
318
319            node_id node;
320            status_t err = allocate_node(data.readCString(), &node);
321            reply->writeInt32(err);
322            if (err == OK) {
323                writeVoidStar(node, reply);
324            }
325
326            return NO_ERROR;
327        }
328
329        case FREE_NODE:
330        {
331            CHECK_INTERFACE(IOMX, data, reply);
332
333            node_id node = readVoidStar(&data);
334
335            reply->writeInt32(free_node(node));
336
337            return NO_ERROR;
338        }
339
340        case SEND_COMMAND:
341        {
342            CHECK_INTERFACE(IOMX, data, reply);
343
344            node_id node = readVoidStar(&data);
345
346            OMX_COMMANDTYPE cmd =
347                static_cast<OMX_COMMANDTYPE>(data.readInt32());
348
349            OMX_S32 param = data.readInt32();
350            reply->writeInt32(send_command(node, cmd, param));
351
352            return NO_ERROR;
353        }
354
355        case GET_PARAMETER:
356        {
357            CHECK_INTERFACE(IOMX, data, reply);
358
359            node_id node = readVoidStar(&data);
360            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
361
362            size_t size = data.readInt32();
363
364            // XXX I am not happy with this but Parcel::readInplace didn't work.
365            void *params = malloc(size);
366            data.read(params, size);
367
368            status_t err = get_parameter(node, index, params, size);
369
370            reply->writeInt32(err);
371
372            if (err == OK) {
373                reply->write(params, size);
374            }
375
376            free(params);
377            params = NULL;
378
379            return NO_ERROR;
380        }
381
382        case SET_PARAMETER:
383        {
384            CHECK_INTERFACE(IOMX, data, reply);
385
386            node_id node = readVoidStar(&data);
387            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
388
389            size_t size = data.readInt32();
390            void *params = const_cast<void *>(data.readInplace(size));
391
392            reply->writeInt32(set_parameter(node, index, params, size));
393
394            return NO_ERROR;
395        }
396
397        case USE_BUFFER:
398        {
399            CHECK_INTERFACE(IOMX, data, reply);
400
401            node_id node = readVoidStar(&data);
402            OMX_U32 port_index = data.readInt32();
403            sp<IMemory> params =
404                interface_cast<IMemory>(data.readStrongBinder());
405
406            buffer_id buffer;
407            status_t err = use_buffer(node, port_index, params, &buffer);
408            reply->writeInt32(err);
409
410            if (err == OK) {
411                writeVoidStar(buffer, reply);
412            }
413
414            return NO_ERROR;
415        }
416
417        case ALLOC_BUFFER:
418        {
419            CHECK_INTERFACE(IOMX, data, reply);
420
421            node_id node = readVoidStar(&data);
422            OMX_U32 port_index = data.readInt32();
423            size_t size = data.readInt32();
424
425            buffer_id buffer;
426            status_t err = allocate_buffer(node, port_index, size, &buffer);
427            reply->writeInt32(err);
428
429            if (err == OK) {
430                writeVoidStar(buffer, reply);
431            }
432
433            return NO_ERROR;
434        }
435
436        case ALLOC_BUFFER_WITH_BACKUP:
437        {
438            CHECK_INTERFACE(IOMX, data, reply);
439
440            node_id node = readVoidStar(&data);
441            OMX_U32 port_index = data.readInt32();
442            sp<IMemory> params =
443                interface_cast<IMemory>(data.readStrongBinder());
444
445            buffer_id buffer;
446            status_t err = allocate_buffer_with_backup(
447                    node, port_index, params, &buffer);
448
449            reply->writeInt32(err);
450
451            if (err == OK) {
452                writeVoidStar(buffer, reply);
453            }
454
455            return NO_ERROR;
456        }
457
458        case FREE_BUFFER:
459        {
460            CHECK_INTERFACE(IOMX, data, reply);
461
462            node_id node = readVoidStar(&data);
463            OMX_U32 port_index = data.readInt32();
464            buffer_id buffer = readVoidStar(&data);
465            reply->writeInt32(free_buffer(node, port_index, buffer));
466
467            return NO_ERROR;
468        }
469
470        case OBSERVE_NODE:
471        {
472            CHECK_INTERFACE(IOMX, data, reply);
473
474            node_id node = readVoidStar(&data);
475            sp<IOMXObserver> observer =
476                interface_cast<IOMXObserver>(data.readStrongBinder());
477            reply->writeInt32(observe_node(node, observer));
478
479            return NO_ERROR;
480        }
481
482        case FILL_BUFFER:
483        {
484            CHECK_INTERFACE(IOMX, data, reply);
485
486            node_id node = readVoidStar(&data);
487            buffer_id buffer = readVoidStar(&data);
488            fill_buffer(node, buffer);
489
490            return NO_ERROR;
491        }
492
493        case EMPTY_BUFFER:
494        {
495            CHECK_INTERFACE(IOMX, data, reply);
496
497            node_id node = readVoidStar(&data);
498            buffer_id buffer = readVoidStar(&data);
499            OMX_U32 range_offset = data.readInt32();
500            OMX_U32 range_length = data.readInt32();
501            OMX_U32 flags = data.readInt32();
502            OMX_TICKS timestamp = data.readInt64();
503
504            empty_buffer(
505                    node, buffer, range_offset, range_length,
506                    flags, timestamp);
507
508            return NO_ERROR;
509        }
510
511        case CREATE_RENDERER:
512        {
513            CHECK_INTERFACE(IOMX, data, reply);
514
515            sp<ISurface> isurface =
516                interface_cast<ISurface>(data.readStrongBinder());
517
518            const char *componentName = data.readCString();
519
520            OMX_COLOR_FORMATTYPE colorFormat =
521                static_cast<OMX_COLOR_FORMATTYPE>(data.readInt32());
522
523            size_t encodedWidth = (size_t)data.readInt32();
524            size_t encodedHeight = (size_t)data.readInt32();
525            size_t displayWidth = (size_t)data.readInt32();
526            size_t displayHeight = (size_t)data.readInt32();
527
528            sp<IOMXRenderer> renderer =
529                createRenderer(isurface, componentName, colorFormat,
530                               encodedWidth, encodedHeight,
531                               displayWidth, displayHeight);
532
533            reply->writeStrongBinder(renderer->asBinder());
534
535            return OK;
536        }
537
538        default:
539            return BBinder::onTransact(code, data, reply, flags);
540    }
541}
542
543////////////////////////////////////////////////////////////////////////////////
544
545class BpOMXObserver : public BpInterface<IOMXObserver> {
546public:
547    BpOMXObserver(const sp<IBinder> &impl)
548        : BpInterface<IOMXObserver>(impl) {
549    }
550
551    virtual void on_message(const omx_message &msg) {
552        Parcel data, reply;
553        data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
554        data.write(&msg, sizeof(msg));
555
556        remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
557    }
558};
559
560IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
561
562status_t BnOMXObserver::onTransact(
563    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
564    switch (code) {
565        case OBSERVER_ON_MSG:
566        {
567            CHECK_INTERFACE(IOMXObserver, data, reply);
568
569            omx_message msg;
570            data.read(&msg, sizeof(msg));
571
572            // XXX Could use readInplace maybe?
573            on_message(msg);
574
575            return NO_ERROR;
576        }
577
578        default:
579            return BBinder::onTransact(code, data, reply, flags);
580    }
581}
582
583////////////////////////////////////////////////////////////////////////////////
584
585class BpOMXRenderer : public BpInterface<IOMXRenderer> {
586public:
587    BpOMXRenderer(const sp<IBinder> &impl)
588        : BpInterface<IOMXRenderer>(impl) {
589    }
590
591    virtual void render(IOMX::buffer_id buffer) {
592        Parcel data, reply;
593        data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
594        writeVoidStar(buffer, &data);
595
596        // NOTE: Do NOT make this a ONE_WAY call, it must be synchronous
597        // so that the caller knows when to recycle the buffer.
598        remote()->transact(RENDERER_RENDER, data, &reply);
599    }
600};
601
602IMPLEMENT_META_INTERFACE(OMXRenderer, "android.hardware.IOMXRenderer");
603
604status_t BnOMXRenderer::onTransact(
605    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
606    switch (code) {
607        case RENDERER_RENDER:
608        {
609            CHECK_INTERFACE(IOMXRenderer, data, reply);
610
611            IOMX::buffer_id buffer = readVoidStar(&data);
612
613            render(buffer);
614
615            return NO_ERROR;
616        }
617
618        default:
619            return BBinder::onTransact(code, data, reply, flags);
620    }
621}
622
623}  // namespace android
624