OMX.cpp revision 20111aa043c5f404472bc63b90bc5aad906b1101
1/*
2 * Copyright (C) 2009 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//#define LOG_NDEBUG 0
18#define LOG_TAG "OMX"
19#include <utils/Log.h>
20
21#include <sys/socket.h>
22
23#undef NDEBUG
24#include <assert.h>
25
26#include "OMX.h"
27#include "pv_omxcore.h"
28
29#include <binder/IMemory.h>
30
31#include <OMX_Component.h>
32
33namespace android {
34
35class NodeMeta {
36public:
37    NodeMeta(OMX *owner)
38        : mOwner(owner),
39          mHandle(NULL) {
40    }
41
42    OMX *owner() const {
43        return mOwner;
44    }
45
46    void setHandle(OMX_HANDLETYPE handle) {
47        assert(mHandle == NULL);
48        mHandle = handle;
49    }
50
51    OMX_HANDLETYPE handle() const {
52        return mHandle;
53    }
54
55    void setObserver(const sp<IOMXObserver> &observer) {
56        mObserver = observer;
57    }
58
59    sp<IOMXObserver> observer() {
60        return mObserver;
61    }
62
63private:
64    OMX *mOwner;
65    OMX_HANDLETYPE mHandle;
66    sp<IOMXObserver> mObserver;
67
68    NodeMeta(const NodeMeta &);
69    NodeMeta &operator=(const NodeMeta &);
70};
71
72class BufferMeta {
73public:
74    BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
75        : mOwner(owner),
76          mMem(mem),
77          mIsBackup(is_backup) {
78    }
79
80    BufferMeta(OMX *owner, size_t size)
81        : mOwner(owner),
82          mSize(size),
83          mIsBackup(false) {
84    }
85
86    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
87        if (!mIsBackup) {
88            return;
89        }
90
91        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
92               header->pBuffer + header->nOffset,
93               header->nFilledLen);
94    }
95
96    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
97        if (!mIsBackup) {
98            return;
99        }
100
101        memcpy(header->pBuffer + header->nOffset,
102               (const OMX_U8 *)mMem->pointer() + header->nOffset,
103               header->nFilledLen);
104    }
105
106private:
107    OMX *mOwner;
108    sp<IMemory> mMem;
109    size_t mSize;
110    bool mIsBackup;
111
112    BufferMeta(const BufferMeta &);
113    BufferMeta &operator=(const BufferMeta &);
114};
115
116// static
117OMX_CALLBACKTYPE OMX::kCallbacks = {
118    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
119};
120
121// static
122OMX_ERRORTYPE OMX::OnEvent(
123        OMX_IN OMX_HANDLETYPE hComponent,
124        OMX_IN OMX_PTR pAppData,
125        OMX_IN OMX_EVENTTYPE eEvent,
126        OMX_IN OMX_U32 nData1,
127        OMX_IN OMX_U32 nData2,
128        OMX_IN OMX_PTR pEventData) {
129    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
130    return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData);
131}
132
133// static
134OMX_ERRORTYPE OMX::OnEmptyBufferDone(
135        OMX_IN OMX_HANDLETYPE hComponent,
136        OMX_IN OMX_PTR pAppData,
137        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
138    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
139    return meta->owner()->OnEmptyBufferDone(meta, pBuffer);
140}
141
142// static
143OMX_ERRORTYPE OMX::OnFillBufferDone(
144        OMX_IN OMX_HANDLETYPE hComponent,
145        OMX_IN OMX_PTR pAppData,
146        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
147    NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
148    return meta->owner()->OnFillBufferDone(meta, pBuffer);
149}
150
151OMX::OMX()
152#if IOMX_USES_SOCKETS
153    : mSock(-1)
154#endif
155{
156}
157
158OMX::~OMX() {
159#if IOMX_USES_SOCKETS
160    assert(mSock < 0);
161#endif
162}
163
164#if IOMX_USES_SOCKETS
165status_t OMX::connect(int *sd) {
166    Mutex::Autolock autoLock(mLock);
167
168    if (mSock >= 0) {
169        return UNKNOWN_ERROR;
170    }
171
172    int sockets[2];
173    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
174        return UNKNOWN_ERROR;
175    }
176
177    mSock = sockets[0];
178    *sd = sockets[1];
179
180    pthread_attr_t attr;
181    pthread_attr_init(&attr);
182    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
183
184    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
185    assert(err == 0);
186
187    pthread_attr_destroy(&attr);
188
189    return OK;
190}
191
192// static
193void *OMX::ThreadWrapper(void *me) {
194    ((OMX *)me)->threadEntry();
195
196    return NULL;
197}
198
199void OMX::threadEntry() {
200    bool done = false;
201    while (!done) {
202        omx_message msg;
203        ssize_t n = recv(mSock, &msg, sizeof(msg), 0);
204
205        if (n <= 0) {
206            break;
207        }
208
209        Mutex::Autolock autoLock(mLock);
210
211        switch (msg.type) {
212            case omx_message::FILL_BUFFER:
213            {
214                OMX_BUFFERHEADERTYPE *header =
215                    static_cast<OMX_BUFFERHEADERTYPE *>(
216                            msg.u.buffer_data.buffer);
217
218                header->nFilledLen = 0;
219                header->nOffset = 0;
220                header->nFlags = 0;
221
222                NodeMeta *node_meta = static_cast<NodeMeta *>(
223                        msg.u.buffer_data.node);
224
225                LOGV("FillThisBuffer buffer=%p", header);
226
227                OMX_ERRORTYPE err =
228                    OMX_FillThisBuffer(node_meta->handle(), header);
229                assert(err == OMX_ErrorNone);
230                break;
231            }
232
233            case omx_message::EMPTY_BUFFER:
234            {
235                OMX_BUFFERHEADERTYPE *header =
236                    static_cast<OMX_BUFFERHEADERTYPE *>(
237                            msg.u.extended_buffer_data.buffer);
238
239                header->nFilledLen = msg.u.extended_buffer_data.range_length;
240                header->nOffset = msg.u.extended_buffer_data.range_offset;
241                header->nFlags = msg.u.extended_buffer_data.flags;
242                header->nTimeStamp = msg.u.extended_buffer_data.timestamp;
243
244                BufferMeta *buffer_meta =
245                    static_cast<BufferMeta *>(header->pAppPrivate);
246                buffer_meta->CopyToOMX(header);
247
248                NodeMeta *node_meta = static_cast<NodeMeta *>(
249                        msg.u.extended_buffer_data.node);
250
251                LOGV("EmptyThisBuffer buffer=%p", header);
252
253                OMX_ERRORTYPE err =
254                    OMX_EmptyThisBuffer(node_meta->handle(), header);
255                assert(err == OMX_ErrorNone);
256                break;
257            }
258
259            case omx_message::SEND_COMMAND:
260            {
261                NodeMeta *node_meta = static_cast<NodeMeta *>(
262                        msg.u.send_command_data.node);
263
264                OMX_ERRORTYPE err =
265                    OMX_SendCommand(
266                            node_meta->handle(), msg.u.send_command_data.cmd,
267                            msg.u.send_command_data.param, NULL);
268                assert(err == OMX_ErrorNone);
269                break;
270            }
271
272            case omx_message::DISCONNECT:
273            {
274                omx_message msg;
275                msg.type = omx_message::DISCONNECTED;
276                ssize_t n = send(mSock, &msg, sizeof(msg), 0);
277                assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
278                done = true;
279                break;
280            }
281
282            default:
283                LOGE("received unknown omx_message type %d", msg.type);
284                break;
285        }
286    }
287
288    Mutex::Autolock autoLock(mLock);
289    close(mSock);
290    mSock = -1;
291}
292#endif
293
294status_t OMX::list_nodes(List<String8> *list) {
295    OMX_MasterInit();  // XXX Put this somewhere else.
296
297    list->clear();
298
299    OMX_U32 index = 0;
300    char componentName[256];
301    while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
302               == OMX_ErrorNone) {
303        list->push_back(String8(componentName));
304
305        ++index;
306    }
307
308    return OK;
309}
310
311status_t OMX::allocate_node(const char *name, node_id *node) {
312    Mutex::Autolock autoLock(mLock);
313
314    *node = 0;
315
316    OMX_MasterInit();  // XXX Put this somewhere else.
317
318    NodeMeta *meta = new NodeMeta(this);
319
320    OMX_HANDLETYPE handle;
321    OMX_ERRORTYPE err = OMX_MasterGetHandle(
322            &handle, const_cast<char *>(name), meta, &kCallbacks);
323
324    if (err != OMX_ErrorNone) {
325        LOGE("FAILED to allocate omx component '%s'", name);
326
327        delete meta;
328        meta = NULL;
329
330        return UNKNOWN_ERROR;
331    }
332
333    meta->setHandle(handle);
334
335    *node = meta;
336
337    return OK;
338}
339
340status_t OMX::free_node(node_id node) {
341    Mutex::Autolock autoLock(mLock);
342
343    NodeMeta *meta = static_cast<NodeMeta *>(node);
344
345    OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
346
347    delete meta;
348    meta = NULL;
349
350    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
351}
352
353status_t OMX::send_command(
354        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
355    Mutex::Autolock autoLock(mLock);
356
357#if IOMX_USES_SOCKETS
358    if (mSock < 0) {
359        return UNKNOWN_ERROR;
360    }
361#endif
362
363    NodeMeta *meta = static_cast<NodeMeta *>(node);
364    OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
365
366    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
367}
368
369status_t OMX::get_parameter(
370        node_id node, OMX_INDEXTYPE index,
371        void *params, size_t size) {
372    Mutex::Autolock autoLock(mLock);
373
374    NodeMeta *meta = static_cast<NodeMeta *>(node);
375    OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params);
376
377    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
378}
379
380status_t OMX::set_parameter(
381        node_id node, OMX_INDEXTYPE index,
382        const void *params, size_t size) {
383    Mutex::Autolock autoLock(mLock);
384
385    NodeMeta *meta = static_cast<NodeMeta *>(node);
386    OMX_ERRORTYPE err =
387        OMX_SetParameter(meta->handle(), index, const_cast<void *>(params));
388
389    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
390}
391
392status_t OMX::use_buffer(
393        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
394        buffer_id *buffer) {
395    Mutex::Autolock autoLock(mLock);
396
397    BufferMeta *buffer_meta = new BufferMeta(this, params);
398
399    OMX_BUFFERHEADERTYPE *header;
400
401    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
402    OMX_ERRORTYPE err =
403        OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
404                      params->size(), static_cast<OMX_U8 *>(params->pointer()));
405
406    if (err != OMX_ErrorNone) {
407        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
408
409        delete buffer_meta;
410        buffer_meta = NULL;
411
412        *buffer = 0;
413        return UNKNOWN_ERROR;
414    }
415
416    *buffer = header;
417
418    return OK;
419}
420
421status_t OMX::allocate_buffer(
422        node_id node, OMX_U32 port_index, size_t size,
423        buffer_id *buffer) {
424    Mutex::Autolock autoLock(mLock);
425
426    BufferMeta *buffer_meta = new BufferMeta(this, size);
427
428    OMX_BUFFERHEADERTYPE *header;
429
430    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
431    OMX_ERRORTYPE err =
432        OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
433                           buffer_meta, size);
434
435    if (err != OMX_ErrorNone) {
436        delete buffer_meta;
437        buffer_meta = NULL;
438
439        *buffer = 0;
440        return UNKNOWN_ERROR;
441    }
442
443    *buffer = header;
444
445    return OK;
446}
447
448status_t OMX::allocate_buffer_with_backup(
449        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
450        buffer_id *buffer) {
451    Mutex::Autolock autoLock(mLock);
452
453    BufferMeta *buffer_meta = new BufferMeta(this, params, true);
454
455    OMX_BUFFERHEADERTYPE *header;
456
457    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
458    OMX_ERRORTYPE err =
459        OMX_AllocateBuffer(
460                node_meta->handle(), &header, port_index, buffer_meta,
461                params->size());
462
463    if (err != OMX_ErrorNone) {
464        delete buffer_meta;
465        buffer_meta = NULL;
466
467        *buffer = 0;
468        return UNKNOWN_ERROR;
469    }
470
471    *buffer = header;
472
473    return OK;
474}
475
476status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
477    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
478    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
479
480    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
481    OMX_ERRORTYPE err =
482        OMX_FreeBuffer(node_meta->handle(), port_index, header);
483
484    delete buffer_meta;
485    buffer_meta = NULL;
486
487    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
488}
489
490OMX_ERRORTYPE OMX::OnEvent(
491        NodeMeta *meta,
492        OMX_IN OMX_EVENTTYPE eEvent,
493        OMX_IN OMX_U32 nData1,
494        OMX_IN OMX_U32 nData2,
495        OMX_IN OMX_PTR pEventData) {
496    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
497
498    omx_message msg;
499    msg.type = omx_message::EVENT;
500    msg.u.event_data.node = meta;
501    msg.u.event_data.event = eEvent;
502    msg.u.event_data.data1 = nData1;
503    msg.u.event_data.data2 = nData2;
504
505#if !IOMX_USES_SOCKETS
506    sp<IOMXObserver> observer = meta->observer();
507    if (observer.get() != NULL) {
508        observer->on_message(msg);
509    }
510#else
511    assert(mSock >= 0);
512
513    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
514    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
515#endif
516
517    return OMX_ErrorNone;
518}
519
520OMX_ERRORTYPE OMX::OnEmptyBufferDone(
521        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
522    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
523
524    omx_message msg;
525    msg.type = omx_message::EMPTY_BUFFER_DONE;
526    msg.u.buffer_data.node = meta;
527    msg.u.buffer_data.buffer = pBuffer;
528
529#if !IOMX_USES_SOCKETS
530    sp<IOMXObserver> observer = meta->observer();
531    if (observer.get() != NULL) {
532        observer->on_message(msg);
533    }
534#else
535    assert(mSock >= 0);
536    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
537    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
538#endif
539
540    return OMX_ErrorNone;
541}
542
543OMX_ERRORTYPE OMX::OnFillBufferDone(
544        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
545    LOGV("OnFillBufferDone buffer=%p", pBuffer);
546    BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
547    buffer_meta->CopyFromOMX(pBuffer);
548
549    omx_message msg;
550    msg.type = omx_message::FILL_BUFFER_DONE;
551    msg.u.extended_buffer_data.node = meta;
552    msg.u.extended_buffer_data.buffer = pBuffer;
553    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
554    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
555    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
556    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
557    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
558
559#if !IOMX_USES_SOCKETS
560    sp<IOMXObserver> observer = meta->observer();
561    if (observer.get() != NULL) {
562        observer->on_message(msg);
563    }
564#else
565    assert(mSock >= 0);
566
567    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
568    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
569#endif
570
571    return OMX_ErrorNone;
572}
573
574#if !IOMX_USES_SOCKETS
575status_t OMX::observe_node(
576        node_id node, const sp<IOMXObserver> &observer) {
577    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
578
579    node_meta->setObserver(observer);
580
581    return OK;
582}
583
584void OMX::fill_buffer(node_id node, buffer_id buffer) {
585    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
586    header->nFilledLen = 0;
587    header->nOffset = 0;
588    header->nFlags = 0;
589
590    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
591
592    OMX_ERRORTYPE err =
593        OMX_FillThisBuffer(node_meta->handle(), header);
594    assert(err == OMX_ErrorNone);
595}
596
597void OMX::empty_buffer(
598        node_id node,
599        buffer_id buffer,
600        OMX_U32 range_offset, OMX_U32 range_length,
601        OMX_U32 flags, OMX_TICKS timestamp) {
602    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
603    header->nFilledLen = range_length;
604    header->nOffset = range_offset;
605    header->nFlags = flags;
606    header->nTimeStamp = timestamp;
607
608    BufferMeta *buffer_meta =
609        static_cast<BufferMeta *>(header->pAppPrivate);
610    buffer_meta->CopyToOMX(header);
611
612    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
613
614    OMX_ERRORTYPE err =
615        OMX_EmptyThisBuffer(node_meta->handle(), header);
616    assert(err == OMX_ErrorNone);
617}
618#endif
619
620}  // namespace android
621
622