OMX.cpp revision 548681f9bd906600ab523b87e045c1e829b0c767
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->hMarkTargetComponent = NULL;
221                header->nFlags = 0;
222
223                NodeMeta *node_meta = static_cast<NodeMeta *>(
224                        msg.u.buffer_data.node);
225
226                LOGV("FillThisBuffer buffer=%p", header);
227
228                OMX_ERRORTYPE err =
229                    OMX_FillThisBuffer(node_meta->handle(), header);
230                assert(err == OMX_ErrorNone);
231                break;
232            }
233
234            case omx_message::EMPTY_BUFFER:
235            {
236                OMX_BUFFERHEADERTYPE *header =
237                    static_cast<OMX_BUFFERHEADERTYPE *>(
238                            msg.u.extended_buffer_data.buffer);
239
240                header->nFilledLen = msg.u.extended_buffer_data.range_length;
241                header->nOffset = msg.u.extended_buffer_data.range_offset;
242                header->hMarkTargetComponent = NULL;
243                header->nFlags = msg.u.extended_buffer_data.flags;
244                header->nTimeStamp = msg.u.extended_buffer_data.timestamp;
245
246                BufferMeta *buffer_meta =
247                    static_cast<BufferMeta *>(header->pAppPrivate);
248                buffer_meta->CopyToOMX(header);
249
250                NodeMeta *node_meta = static_cast<NodeMeta *>(
251                        msg.u.extended_buffer_data.node);
252
253                LOGV("EmptyThisBuffer buffer=%p", header);
254
255                OMX_ERRORTYPE err =
256                    OMX_EmptyThisBuffer(node_meta->handle(), header);
257                assert(err == OMX_ErrorNone);
258                break;
259            }
260
261            case omx_message::SEND_COMMAND:
262            {
263                NodeMeta *node_meta = static_cast<NodeMeta *>(
264                        msg.u.send_command_data.node);
265
266                OMX_ERRORTYPE err =
267                    OMX_SendCommand(
268                            node_meta->handle(), msg.u.send_command_data.cmd,
269                            msg.u.send_command_data.param, NULL);
270                assert(err == OMX_ErrorNone);
271                break;
272            }
273
274            case omx_message::DISCONNECT:
275            {
276                omx_message msg;
277                msg.type = omx_message::DISCONNECTED;
278                ssize_t n = send(mSock, &msg, sizeof(msg), 0);
279                assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
280                done = true;
281                break;
282            }
283
284            default:
285                LOGE("received unknown omx_message type %d", msg.type);
286                break;
287        }
288    }
289
290    Mutex::Autolock autoLock(mLock);
291    close(mSock);
292    mSock = -1;
293}
294#endif
295
296status_t OMX::list_nodes(List<String8> *list) {
297    OMX_MasterInit();  // XXX Put this somewhere else.
298
299    list->clear();
300
301    OMX_U32 index = 0;
302    char componentName[256];
303    while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
304               == OMX_ErrorNone) {
305        list->push_back(String8(componentName));
306
307        ++index;
308    }
309
310    return OK;
311}
312
313status_t OMX::allocate_node(const char *name, node_id *node) {
314    Mutex::Autolock autoLock(mLock);
315
316    *node = 0;
317
318    OMX_MasterInit();  // XXX Put this somewhere else.
319
320    NodeMeta *meta = new NodeMeta(this);
321
322    OMX_HANDLETYPE handle;
323    OMX_ERRORTYPE err = OMX_MasterGetHandle(
324            &handle, const_cast<char *>(name), meta, &kCallbacks);
325
326    if (err != OMX_ErrorNone) {
327        LOGE("FAILED to allocate omx component '%s'", name);
328
329        delete meta;
330        meta = NULL;
331
332        return UNKNOWN_ERROR;
333    }
334
335    meta->setHandle(handle);
336
337    *node = meta;
338
339    return OK;
340}
341
342status_t OMX::free_node(node_id node) {
343    Mutex::Autolock autoLock(mLock);
344
345    NodeMeta *meta = static_cast<NodeMeta *>(node);
346
347    OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
348
349    delete meta;
350    meta = NULL;
351
352    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
353}
354
355status_t OMX::send_command(
356        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
357    Mutex::Autolock autoLock(mLock);
358
359#if IOMX_USES_SOCKETS
360    if (mSock < 0) {
361        return UNKNOWN_ERROR;
362    }
363#endif
364
365    NodeMeta *meta = static_cast<NodeMeta *>(node);
366    OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
367
368    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
369}
370
371status_t OMX::get_parameter(
372        node_id node, OMX_INDEXTYPE index,
373        void *params, size_t size) {
374    Mutex::Autolock autoLock(mLock);
375
376    NodeMeta *meta = static_cast<NodeMeta *>(node);
377    OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params);
378
379    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
380}
381
382status_t OMX::set_parameter(
383        node_id node, OMX_INDEXTYPE index,
384        const void *params, size_t size) {
385    Mutex::Autolock autoLock(mLock);
386
387    NodeMeta *meta = static_cast<NodeMeta *>(node);
388    OMX_ERRORTYPE err =
389        OMX_SetParameter(meta->handle(), index, const_cast<void *>(params));
390
391    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
392}
393
394status_t OMX::use_buffer(
395        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
396        buffer_id *buffer) {
397    Mutex::Autolock autoLock(mLock);
398
399    BufferMeta *buffer_meta = new BufferMeta(this, params);
400
401    OMX_BUFFERHEADERTYPE *header;
402
403    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
404    OMX_ERRORTYPE err =
405        OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
406                      params->size(), static_cast<OMX_U8 *>(params->pointer()));
407
408    if (err != OMX_ErrorNone) {
409        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
410
411        delete buffer_meta;
412        buffer_meta = NULL;
413
414        *buffer = 0;
415        return UNKNOWN_ERROR;
416    }
417
418    *buffer = header;
419
420    return OK;
421}
422
423status_t OMX::allocate_buffer(
424        node_id node, OMX_U32 port_index, size_t size,
425        buffer_id *buffer) {
426    Mutex::Autolock autoLock(mLock);
427
428    BufferMeta *buffer_meta = new BufferMeta(this, size);
429
430    OMX_BUFFERHEADERTYPE *header;
431
432    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
433    OMX_ERRORTYPE err =
434        OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
435                           buffer_meta, size);
436
437    if (err != OMX_ErrorNone) {
438        delete buffer_meta;
439        buffer_meta = NULL;
440
441        *buffer = 0;
442        return UNKNOWN_ERROR;
443    }
444
445    *buffer = header;
446
447    return OK;
448}
449
450status_t OMX::allocate_buffer_with_backup(
451        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
452        buffer_id *buffer) {
453    Mutex::Autolock autoLock(mLock);
454
455    BufferMeta *buffer_meta = new BufferMeta(this, params, true);
456
457    OMX_BUFFERHEADERTYPE *header;
458
459    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
460    OMX_ERRORTYPE err =
461        OMX_AllocateBuffer(
462                node_meta->handle(), &header, port_index, buffer_meta,
463                params->size());
464
465    if (err != OMX_ErrorNone) {
466        delete buffer_meta;
467        buffer_meta = NULL;
468
469        *buffer = 0;
470        return UNKNOWN_ERROR;
471    }
472
473    *buffer = header;
474
475    return OK;
476}
477
478status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
479    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
480    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
481
482    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
483    OMX_ERRORTYPE err =
484        OMX_FreeBuffer(node_meta->handle(), port_index, header);
485
486    delete buffer_meta;
487    buffer_meta = NULL;
488
489    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
490}
491
492OMX_ERRORTYPE OMX::OnEvent(
493        NodeMeta *meta,
494        OMX_IN OMX_EVENTTYPE eEvent,
495        OMX_IN OMX_U32 nData1,
496        OMX_IN OMX_U32 nData2,
497        OMX_IN OMX_PTR pEventData) {
498    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
499
500    omx_message msg;
501    msg.type = omx_message::EVENT;
502    msg.u.event_data.node = meta;
503    msg.u.event_data.event = eEvent;
504    msg.u.event_data.data1 = nData1;
505    msg.u.event_data.data2 = nData2;
506
507#if !IOMX_USES_SOCKETS
508    sp<IOMXObserver> observer = meta->observer();
509    if (observer.get() != NULL) {
510        observer->on_message(msg);
511    }
512#else
513    assert(mSock >= 0);
514
515    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
516    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
517#endif
518
519    return OMX_ErrorNone;
520}
521
522OMX_ERRORTYPE OMX::OnEmptyBufferDone(
523        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
524    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
525
526    omx_message msg;
527    msg.type = omx_message::EMPTY_BUFFER_DONE;
528    msg.u.buffer_data.node = meta;
529    msg.u.buffer_data.buffer = pBuffer;
530
531#if !IOMX_USES_SOCKETS
532    sp<IOMXObserver> observer = meta->observer();
533    if (observer.get() != NULL) {
534        observer->on_message(msg);
535    }
536#else
537    assert(mSock >= 0);
538    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
539    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
540#endif
541
542    return OMX_ErrorNone;
543}
544
545OMX_ERRORTYPE OMX::OnFillBufferDone(
546        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
547    LOGV("OnFillBufferDone buffer=%p", pBuffer);
548    BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
549    buffer_meta->CopyFromOMX(pBuffer);
550
551    omx_message msg;
552    msg.type = omx_message::FILL_BUFFER_DONE;
553    msg.u.extended_buffer_data.node = meta;
554    msg.u.extended_buffer_data.buffer = pBuffer;
555    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
556    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
557    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
558    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
559    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
560
561#if !IOMX_USES_SOCKETS
562    sp<IOMXObserver> observer = meta->observer();
563    if (observer.get() != NULL) {
564        observer->on_message(msg);
565    }
566#else
567    assert(mSock >= 0);
568
569    ssize_t n = send(mSock, &msg, sizeof(msg), 0);
570    assert(n > 0 && static_cast<size_t>(n) == sizeof(msg));
571#endif
572
573    return OMX_ErrorNone;
574}
575
576#if !IOMX_USES_SOCKETS
577status_t OMX::observe_node(
578        node_id node, const sp<IOMXObserver> &observer) {
579    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
580
581    node_meta->setObserver(observer);
582
583    return OK;
584}
585
586void OMX::fill_buffer(node_id node, buffer_id buffer) {
587    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
588    header->nFilledLen = 0;
589    header->nOffset = 0;
590    header->nFlags = 0;
591
592    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
593
594    OMX_ERRORTYPE err =
595        OMX_FillThisBuffer(node_meta->handle(), header);
596    assert(err == OMX_ErrorNone);
597}
598
599void OMX::empty_buffer(
600        node_id node,
601        buffer_id buffer,
602        OMX_U32 range_offset, OMX_U32 range_length,
603        OMX_U32 flags, OMX_TICKS timestamp) {
604    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
605    header->nFilledLen = range_length;
606    header->nOffset = range_offset;
607    header->nFlags = flags;
608    header->nTimeStamp = timestamp;
609
610    BufferMeta *buffer_meta =
611        static_cast<BufferMeta *>(header->pAppPrivate);
612    buffer_meta->CopyToOMX(header);
613
614    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
615
616    OMX_ERRORTYPE err =
617        OMX_EmptyThisBuffer(node_meta->handle(), header);
618    assert(err == OMX_ErrorNone);
619}
620#endif
621
622}  // namespace android
623
624