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