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