OMXNodeInstance.cpp revision 2d6d6e9a3d569eda4555c4eb68cec452be958bb1
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 "OMXNodeInstance"
19#include <utils/Log.h>
20
21#include "../include/OMXNodeInstance.h"
22
23#include "pv_omxcore.h"
24
25#include <binder/IMemory.h>
26#include <media/stagefright/MediaDebug.h>
27
28namespace android {
29
30struct BufferMeta {
31    BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
32        : mMem(mem),
33          mIsBackup(is_backup) {
34    }
35
36    BufferMeta(size_t size)
37        : mSize(size),
38          mIsBackup(false) {
39    }
40
41    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
42        if (!mIsBackup) {
43            return;
44        }
45
46        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
47               header->pBuffer + header->nOffset,
48               header->nFilledLen);
49    }
50
51    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
52        if (!mIsBackup) {
53            return;
54        }
55
56        memcpy(header->pBuffer + header->nOffset,
57               (const OMX_U8 *)mMem->pointer() + header->nOffset,
58               header->nFilledLen);
59    }
60
61private:
62    sp<IMemory> mMem;
63    size_t mSize;
64    bool mIsBackup;
65
66    BufferMeta(const BufferMeta &);
67    BufferMeta &operator=(const BufferMeta &);
68};
69
70// static
71OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
72    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
73};
74
75OMXNodeInstance::OMXNodeInstance(
76        OMX *owner, const sp<IOMXObserver> &observer)
77    : mOwner(owner),
78      mNodeID(NULL),
79      mHandle(NULL),
80      mObserver(observer) {
81}
82
83OMXNodeInstance::~OMXNodeInstance() {
84    CHECK_EQ(mHandle, NULL);
85}
86
87void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
88    CHECK_EQ(mHandle, NULL);
89    mNodeID = node_id;
90    mHandle = handle;
91}
92
93OMX *OMXNodeInstance::owner() {
94    return mOwner;
95}
96
97sp<IOMXObserver> OMXNodeInstance::observer() {
98    return mObserver;
99}
100
101OMX::node_id OMXNodeInstance::nodeID() {
102    return mNodeID;
103}
104
105static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
106    return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR;
107}
108
109status_t OMXNodeInstance::freeNode() {
110    Mutex::Autolock autoLock(mLock);
111
112    OMX_ERRORTYPE err = OMX_MasterFreeHandle(mHandle);
113    mHandle = NULL;
114
115    if (err != OMX_ErrorNone) {
116        LOGE("FreeHandle FAILED with error 0x%08x.", err);
117    }
118
119    mOwner->invalidateNodeID(mNodeID);
120    mNodeID = NULL;
121
122    LOGI("OMXNodeInstance going away.");
123    mObserver.clear();
124    // delete this;  // leads to heap-corruption???
125
126    return StatusFromOMXError(err);
127}
128
129status_t OMXNodeInstance::sendCommand(
130        OMX_COMMANDTYPE cmd, OMX_S32 param) {
131    Mutex::Autolock autoLock(mLock);
132
133    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
134    return StatusFromOMXError(err);
135}
136
137status_t OMXNodeInstance::getParameter(
138        OMX_INDEXTYPE index, void *params, size_t size) {
139    Mutex::Autolock autoLock(mLock);
140
141    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
142    return StatusFromOMXError(err);
143}
144
145status_t OMXNodeInstance::setParameter(
146        OMX_INDEXTYPE index, const void *params, size_t size) {
147    Mutex::Autolock autoLock(mLock);
148
149    OMX_ERRORTYPE err = OMX_SetParameter(
150            mHandle, index, const_cast<void *>(params));
151
152    return StatusFromOMXError(err);
153}
154
155status_t OMXNodeInstance::getConfig(
156        OMX_INDEXTYPE index, void *params, size_t size) {
157    Mutex::Autolock autoLock(mLock);
158
159    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
160    return StatusFromOMXError(err);
161}
162
163status_t OMXNodeInstance::setConfig(
164        OMX_INDEXTYPE index, const void *params, size_t size) {
165    Mutex::Autolock autoLock(mLock);
166
167    OMX_ERRORTYPE err = OMX_SetConfig(
168            mHandle, index, const_cast<void *>(params));
169
170    return StatusFromOMXError(err);
171}
172
173status_t OMXNodeInstance::useBuffer(
174        OMX_U32 portIndex, const sp<IMemory> &params,
175        OMX::buffer_id *buffer) {
176    Mutex::Autolock autoLock(mLock);
177
178    BufferMeta *buffer_meta = new BufferMeta(params);
179
180    OMX_BUFFERHEADERTYPE *header;
181
182    OMX_ERRORTYPE err = OMX_UseBuffer(
183            mHandle, &header, portIndex, buffer_meta,
184            params->size(), static_cast<OMX_U8 *>(params->pointer()));
185
186    if (err != OMX_ErrorNone) {
187        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
188
189        delete buffer_meta;
190        buffer_meta = NULL;
191
192        *buffer = 0;
193
194        return UNKNOWN_ERROR;
195    }
196
197    *buffer = header;
198
199    return OK;
200}
201
202status_t OMXNodeInstance::allocateBuffer(
203        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer) {
204    Mutex::Autolock autoLock(mLock);
205
206    BufferMeta *buffer_meta = new BufferMeta(size);
207
208    OMX_BUFFERHEADERTYPE *header;
209
210    OMX_ERRORTYPE err = OMX_AllocateBuffer(
211            mHandle, &header, portIndex, buffer_meta, size);
212
213    if (err != OMX_ErrorNone) {
214        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
215
216        delete buffer_meta;
217        buffer_meta = NULL;
218
219        *buffer = 0;
220
221        return UNKNOWN_ERROR;
222    }
223
224    *buffer = header;
225
226    return OK;
227}
228
229status_t OMXNodeInstance::allocateBufferWithBackup(
230        OMX_U32 portIndex, const sp<IMemory> &params,
231        OMX::buffer_id *buffer) {
232    Mutex::Autolock autoLock(mLock);
233
234    BufferMeta *buffer_meta = new BufferMeta(params, true);
235
236    OMX_BUFFERHEADERTYPE *header;
237
238    OMX_ERRORTYPE err = OMX_AllocateBuffer(
239            mHandle, &header, portIndex, buffer_meta, params->size());
240
241    if (err != OMX_ErrorNone) {
242        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
243
244        delete buffer_meta;
245        buffer_meta = NULL;
246
247        *buffer = 0;
248
249        return UNKNOWN_ERROR;
250    }
251
252    *buffer = header;
253
254    return OK;
255}
256
257status_t OMXNodeInstance::freeBuffer(
258        OMX_U32 portIndex, OMX::buffer_id buffer) {
259    Mutex::Autolock autoLock(mLock);
260
261    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
262    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
263
264    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
265
266    delete buffer_meta;
267    buffer_meta = NULL;
268
269    return StatusFromOMXError(err);
270}
271
272status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
273    Mutex::Autolock autoLock(mLock);
274
275    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
276    header->nFilledLen = 0;
277    header->nOffset = 0;
278    header->nFlags = 0;
279
280    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
281
282    return StatusFromOMXError(err);
283}
284
285status_t OMXNodeInstance::emptyBuffer(
286        OMX::buffer_id buffer,
287        OMX_U32 rangeOffset, OMX_U32 rangeLength,
288        OMX_U32 flags, OMX_TICKS timestamp) {
289    Mutex::Autolock autoLock(mLock);
290
291    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
292    header->nFilledLen = rangeLength;
293    header->nOffset = rangeOffset;
294    header->nFlags = flags;
295    header->nTimeStamp = timestamp;
296
297    BufferMeta *buffer_meta =
298        static_cast<BufferMeta *>(header->pAppPrivate);
299    buffer_meta->CopyToOMX(header);
300
301    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
302
303    return StatusFromOMXError(err);
304}
305
306status_t OMXNodeInstance::getExtensionIndex(
307        const char *parameterName, OMX_INDEXTYPE *index) {
308    Mutex::Autolock autoLock(mLock);
309
310    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
311            mHandle, const_cast<char *>(parameterName), index);
312
313    return StatusFromOMXError(err);
314}
315
316void OMXNodeInstance::onMessage(const omx_message &msg) {
317    if (msg.type == omx_message::FILL_BUFFER_DONE) {
318        OMX_BUFFERHEADERTYPE *buffer =
319            static_cast<OMX_BUFFERHEADERTYPE *>(
320                    msg.u.extended_buffer_data.buffer);
321
322        BufferMeta *buffer_meta =
323            static_cast<BufferMeta *>(buffer->pAppPrivate);
324
325        buffer_meta->CopyFromOMX(buffer);
326    }
327
328    mObserver->onMessage(msg);
329}
330
331void OMXNodeInstance::onObserverDied() {
332    LOGE("!!! Observer died. Quickly, do something, ... anything...");
333
334    // Try to force shutdown of the node and hope for the best.
335    freeNode();
336}
337
338void OMXNodeInstance::onGetHandleFailed() {
339    delete this;
340}
341
342// static
343OMX_ERRORTYPE OMXNodeInstance::OnEvent(
344        OMX_IN OMX_HANDLETYPE hComponent,
345        OMX_IN OMX_PTR pAppData,
346        OMX_IN OMX_EVENTTYPE eEvent,
347        OMX_IN OMX_U32 nData1,
348        OMX_IN OMX_U32 nData2,
349        OMX_IN OMX_PTR pEventData) {
350    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
351    return instance->owner()->OnEvent(
352            instance->nodeID(), eEvent, nData1, nData2, pEventData);
353}
354
355// static
356OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
357        OMX_IN OMX_HANDLETYPE hComponent,
358        OMX_IN OMX_PTR pAppData,
359        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
360    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
361    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
362}
363
364// static
365OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
366        OMX_IN OMX_HANDLETYPE hComponent,
367        OMX_IN OMX_PTR pAppData,
368        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
369    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
370    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
371}
372
373}  // namespace android
374
375