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