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