OMX.cpp revision 408b8e1073385d0d09bb96b9952f84731a0b4aeb
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}
159
160status_t OMX::list_nodes(List<String8> *list) {
161    OMX_MasterInit();  // XXX Put this somewhere else.
162
163    list->clear();
164
165    OMX_U32 index = 0;
166    char componentName[256];
167    while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
168               == OMX_ErrorNone) {
169        list->push_back(String8(componentName));
170
171        ++index;
172    }
173
174    return OK;
175}
176
177status_t OMX::allocate_node(const char *name, node_id *node) {
178    Mutex::Autolock autoLock(mLock);
179
180    *node = 0;
181
182    OMX_MasterInit();  // XXX Put this somewhere else.
183
184    NodeMeta *meta = new NodeMeta(this);
185
186    OMX_HANDLETYPE handle;
187    OMX_ERRORTYPE err = OMX_MasterGetHandle(
188            &handle, const_cast<char *>(name), meta, &kCallbacks);
189
190    if (err != OMX_ErrorNone) {
191        LOGE("FAILED to allocate omx component '%s'", name);
192
193        delete meta;
194        meta = NULL;
195
196        return UNKNOWN_ERROR;
197    }
198
199    meta->setHandle(handle);
200
201    *node = meta;
202
203    return OK;
204}
205
206status_t OMX::free_node(node_id node) {
207    Mutex::Autolock autoLock(mLock);
208
209    NodeMeta *meta = static_cast<NodeMeta *>(node);
210
211    OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
212
213    delete meta;
214    meta = NULL;
215
216    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
217}
218
219status_t OMX::send_command(
220        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
221    Mutex::Autolock autoLock(mLock);
222
223    NodeMeta *meta = static_cast<NodeMeta *>(node);
224    OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
225
226    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
227}
228
229status_t OMX::get_parameter(
230        node_id node, OMX_INDEXTYPE index,
231        void *params, size_t size) {
232    Mutex::Autolock autoLock(mLock);
233
234    NodeMeta *meta = static_cast<NodeMeta *>(node);
235    OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params);
236
237    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
238}
239
240status_t OMX::set_parameter(
241        node_id node, OMX_INDEXTYPE index,
242        const void *params, size_t size) {
243    Mutex::Autolock autoLock(mLock);
244
245    NodeMeta *meta = static_cast<NodeMeta *>(node);
246    OMX_ERRORTYPE err =
247        OMX_SetParameter(meta->handle(), index, const_cast<void *>(params));
248
249    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
250}
251
252status_t OMX::use_buffer(
253        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
254        buffer_id *buffer) {
255    Mutex::Autolock autoLock(mLock);
256
257    BufferMeta *buffer_meta = new BufferMeta(this, params);
258
259    OMX_BUFFERHEADERTYPE *header;
260
261    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
262    OMX_ERRORTYPE err =
263        OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
264                      params->size(), static_cast<OMX_U8 *>(params->pointer()));
265
266    if (err != OMX_ErrorNone) {
267        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
268
269        delete buffer_meta;
270        buffer_meta = NULL;
271
272        *buffer = 0;
273        return UNKNOWN_ERROR;
274    }
275
276    *buffer = header;
277
278    return OK;
279}
280
281status_t OMX::allocate_buffer(
282        node_id node, OMX_U32 port_index, size_t size,
283        buffer_id *buffer) {
284    Mutex::Autolock autoLock(mLock);
285
286    BufferMeta *buffer_meta = new BufferMeta(this, size);
287
288    OMX_BUFFERHEADERTYPE *header;
289
290    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
291    OMX_ERRORTYPE err =
292        OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
293                           buffer_meta, size);
294
295    if (err != OMX_ErrorNone) {
296        delete buffer_meta;
297        buffer_meta = NULL;
298
299        *buffer = 0;
300        return UNKNOWN_ERROR;
301    }
302
303    *buffer = header;
304
305    return OK;
306}
307
308status_t OMX::allocate_buffer_with_backup(
309        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
310        buffer_id *buffer) {
311    Mutex::Autolock autoLock(mLock);
312
313    BufferMeta *buffer_meta = new BufferMeta(this, params, true);
314
315    OMX_BUFFERHEADERTYPE *header;
316
317    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
318    OMX_ERRORTYPE err =
319        OMX_AllocateBuffer(
320                node_meta->handle(), &header, port_index, buffer_meta,
321                params->size());
322
323    if (err != OMX_ErrorNone) {
324        delete buffer_meta;
325        buffer_meta = NULL;
326
327        *buffer = 0;
328        return UNKNOWN_ERROR;
329    }
330
331    *buffer = header;
332
333    return OK;
334}
335
336status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
337    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
338    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
339
340    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
341    OMX_ERRORTYPE err =
342        OMX_FreeBuffer(node_meta->handle(), port_index, header);
343
344    delete buffer_meta;
345    buffer_meta = NULL;
346
347    return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
348}
349
350OMX_ERRORTYPE OMX::OnEvent(
351        NodeMeta *meta,
352        OMX_IN OMX_EVENTTYPE eEvent,
353        OMX_IN OMX_U32 nData1,
354        OMX_IN OMX_U32 nData2,
355        OMX_IN OMX_PTR pEventData) {
356    LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
357
358    omx_message msg;
359    msg.type = omx_message::EVENT;
360    msg.u.event_data.node = meta;
361    msg.u.event_data.event = eEvent;
362    msg.u.event_data.data1 = nData1;
363    msg.u.event_data.data2 = nData2;
364
365    sp<IOMXObserver> observer = meta->observer();
366    if (observer.get() != NULL) {
367        observer->on_message(msg);
368    }
369
370    return OMX_ErrorNone;
371}
372
373OMX_ERRORTYPE OMX::OnEmptyBufferDone(
374        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
375    LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
376
377    omx_message msg;
378    msg.type = omx_message::EMPTY_BUFFER_DONE;
379    msg.u.buffer_data.node = meta;
380    msg.u.buffer_data.buffer = pBuffer;
381
382    sp<IOMXObserver> observer = meta->observer();
383    if (observer.get() != NULL) {
384        observer->on_message(msg);
385    }
386
387    return OMX_ErrorNone;
388}
389
390OMX_ERRORTYPE OMX::OnFillBufferDone(
391        NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
392    LOGV("OnFillBufferDone buffer=%p", pBuffer);
393    BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
394    buffer_meta->CopyFromOMX(pBuffer);
395
396    omx_message msg;
397    msg.type = omx_message::FILL_BUFFER_DONE;
398    msg.u.extended_buffer_data.node = meta;
399    msg.u.extended_buffer_data.buffer = pBuffer;
400    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
401    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
402    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
403    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
404    msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
405
406    sp<IOMXObserver> observer = meta->observer();
407    if (observer.get() != NULL) {
408        observer->on_message(msg);
409    }
410
411    return OMX_ErrorNone;
412}
413
414status_t OMX::observe_node(
415        node_id node, const sp<IOMXObserver> &observer) {
416    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
417
418    node_meta->setObserver(observer);
419
420    return OK;
421}
422
423void OMX::fill_buffer(node_id node, buffer_id buffer) {
424    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
425    header->nFilledLen = 0;
426    header->nOffset = 0;
427    header->nFlags = 0;
428
429    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
430
431    OMX_ERRORTYPE err =
432        OMX_FillThisBuffer(node_meta->handle(), header);
433    assert(err == OMX_ErrorNone);
434}
435
436void OMX::empty_buffer(
437        node_id node,
438        buffer_id buffer,
439        OMX_U32 range_offset, OMX_U32 range_length,
440        OMX_U32 flags, OMX_TICKS timestamp) {
441    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
442    header->nFilledLen = range_length;
443    header->nOffset = range_offset;
444    header->nFlags = flags;
445    header->nTimeStamp = timestamp;
446
447    BufferMeta *buffer_meta =
448        static_cast<BufferMeta *>(header->pAppPrivate);
449    buffer_meta->CopyToOMX(header);
450
451    NodeMeta *node_meta = static_cast<NodeMeta *>(node);
452
453    OMX_ERRORTYPE err =
454        OMX_EmptyThisBuffer(node_meta->handle(), header);
455    assert(err == OMX_ErrorNone);
456}
457
458////////////////////////////////////////////////////////////////////////////////
459
460sp<IOMXRenderer> OMX::createRenderer(
461        const sp<ISurface> &surface,
462        const char *componentName,
463        OMX_COLOR_FORMATTYPE colorFormat,
464        size_t encodedWidth, size_t encodedHeight,
465        size_t displayWidth, size_t displayHeight) {
466    VideoRenderer *impl = NULL;
467
468    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
469
470    if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
471        && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
472        LOGW("Using QComHardwareRenderer.");
473        impl =
474            new QComHardwareRenderer(
475                    surface,
476                    displayWidth, displayHeight,
477                    encodedWidth, encodedHeight);
478    } else if (colorFormat == OMX_COLOR_FormatCbYCrY
479            && !strcmp(componentName, "OMX.TI.Video.Decoder")) {
480        LOGW("Using TIHardwareRenderer.");
481        impl =
482            new TIHardwareRenderer(
483                    surface,
484                    displayWidth, displayHeight,
485                    encodedWidth, encodedHeight);
486    } else {
487        LOGW("Using software renderer.");
488        impl = new SoftwareRenderer(
489                surface,
490                displayWidth, displayHeight,
491                encodedWidth, encodedHeight);
492    }
493
494    return new OMXRenderer(impl);
495}
496
497OMXRenderer::OMXRenderer(VideoRenderer *impl)
498    : mImpl(impl) {
499}
500
501OMXRenderer::~OMXRenderer() {
502    delete mImpl;
503    mImpl = NULL;
504}
505
506void OMXRenderer::render(IOMX::buffer_id buffer) {
507    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
508
509    mImpl->render(
510            header->pBuffer + header->nOffset,
511            header->nFilledLen,
512            header->pPlatformPrivate);
513}
514
515}  // namespace android
516
517