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