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