portbase.cpp revision f4ab90019707fb84477f62dd3093eaff0ac466eb
1/*
2 * Copyright (C) 2009 Wind River Systems
3 *      Author: Ho-Eun Ryu <ho-eun.ryu@windriver.com>
4 */
5
6#include <stdlib.h>
7#include <string.h>
8
9#include <OMX_Core.h>
10#include <OMX_Component.h>
11
12#include <portbase.h>
13#include <componentbase.h>
14
15#define LOG_TAG "portbase"
16#include <log.h>
17
18/*
19 * constructor & destructor
20 */
21void PortBase::__PortBase(void)
22{
23    buffer_hdrs = NULL;
24    nr_buffer_hdrs = 0;
25    buffer_hdrs_completion = false;
26
27    pthread_mutex_init(&hdrs_lock, NULL);
28    pthread_cond_init(&hdrs_wait, NULL);
29
30    __queue_init(&bufferq);
31    pthread_mutex_init(&bufferq_lock, NULL);
32
33    __queue_init(&markq);
34    pthread_mutex_init(&markq_lock, NULL);
35
36    state = OMX_PortEnabled;
37    pthread_mutex_init(&state_lock, NULL);
38
39    memset(&portdefinition, 0, sizeof(portdefinition));
40    ComponentBase::SetTypeHeader(&portdefinition, sizeof(portdefinition));
41    memset(definition_format_mimetype, 0, OMX_MAX_STRINGNAME_SIZE);
42    portdefinition.format.audio.cMIMEType = &definition_format_mimetype[0];
43    portdefinition.format.video.cMIMEType = &definition_format_mimetype[0];
44    portdefinition.format.image.cMIMEType = &definition_format_mimetype[0];
45
46    memset(&audioparam, 0, sizeof(audioparam));
47
48    owner = NULL;
49    appdata = NULL;
50    callbacks = NULL;
51}
52
53PortBase::PortBase()
54{
55    __PortBase();
56}
57
58PortBase::PortBase(const OMX_PARAM_PORTDEFINITIONTYPE *portdefinition)
59{
60    __PortBase();
61    SetPortDefinition(portdefinition, true);
62}
63
64PortBase::~PortBase()
65{
66    struct list *entry, *temp;
67
68    /* should've been already freed at FreeBuffer() */
69    list_foreach_safe(buffer_hdrs, entry, temp) {
70        free(entry->data); /* OMX_BUFFERHEADERTYPE */
71        __list_delete(buffer_hdrs, entry);
72    }
73
74    pthread_cond_destroy(&hdrs_wait);
75    pthread_mutex_destroy(&hdrs_lock);
76
77    /* should've been already freed at buffer processing */
78    queue_free_all(&bufferq);
79    pthread_mutex_destroy(&bufferq_lock);
80
81    /* should've been already empty in PushThisBuffer () */
82    queue_free_all(&markq);
83    pthread_mutex_destroy(&markq_lock);
84
85    pthread_mutex_destroy(&state_lock);
86}
87
88/* end of constructor & destructor */
89
90/*
91 * accessor
92 */
93/* owner */
94void PortBase::SetOwner(OMX_COMPONENTTYPE *handle)
95{
96    owner = handle;
97}
98
99OMX_COMPONENTTYPE *PortBase::GetOwner(void)
100{
101    return owner;
102}
103
104OMX_ERRORTYPE PortBase::SetCallbacks(OMX_HANDLETYPE hComponent,
105                                     OMX_CALLBACKTYPE *pCallbacks,
106                                     OMX_PTR pAppData)
107{
108    if (owner != hComponent)
109        return OMX_ErrorBadParameter;
110
111    appdata = pAppData;
112    callbacks = pCallbacks;
113
114    return OMX_ErrorNone;
115}
116
117/* end of accessor */
118
119/*
120 * component methods & helpers
121 */
122/* Get/SetParameter */
123OMX_ERRORTYPE PortBase::SetPortDefinition(
124    const OMX_PARAM_PORTDEFINITIONTYPE *p, bool overwrite_readonly)
125{
126    OMX_PARAM_PORTDEFINITIONTYPE temp;
127
128    memcpy(&temp, &portdefinition, sizeof(temp));
129
130    if (!overwrite_readonly) {
131        if (temp.nPortIndex != p->nPortIndex)
132            return OMX_ErrorBadParameter;
133        if (temp.eDir != p->eDir)
134            return OMX_ErrorBadParameter;
135        if (temp.eDomain != p->eDomain)
136            return OMX_ErrorBadParameter;
137        if (temp.nBufferCountActual != p->nBufferCountActual) {
138            if (temp.nBufferCountMin > p->nBufferCountActual)
139                return OMX_ErrorBadParameter;
140
141            temp.nBufferCountActual = p->nBufferCountActual;
142        }
143    }
144    else {
145        temp.nPortIndex = p->nPortIndex;
146        temp.eDir = p->eDir;
147        temp.nBufferCountActual = p->nBufferCountActual;
148        temp.nBufferCountMin = p->nBufferCountMin;
149        temp.bEnabled = p->bEnabled;
150        temp.bPopulated = p->bPopulated;
151        temp.eDomain = p->eDomain;
152        temp.bBuffersContiguous = p->bBuffersContiguous;
153        temp.nBufferAlignment = p->nBufferAlignment;
154    }
155
156    switch (p->eDomain) {
157    case OMX_PortDomainAudio: {
158        OMX_AUDIO_PORTDEFINITIONTYPE *format = &temp.format.audio;
159        const OMX_AUDIO_PORTDEFINITIONTYPE *pformat = &p->format.audio;
160        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
161
162        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
163            mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
164
165        strncpy(format->cMIMEType, pformat->cMIMEType,
166                mimetype_len);
167        format->cMIMEType[mimetype_len+1] = '\0';
168        format->pNativeRender = pformat->pNativeRender;
169        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
170        format->eEncoding = pformat->eEncoding;
171
172        break;
173    }
174    case OMX_PortDomainVideo: {
175        OMX_VIDEO_PORTDEFINITIONTYPE *format = &temp.format.video;
176        const OMX_VIDEO_PORTDEFINITIONTYPE *pformat = &p->format.video;
177        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
178
179        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
180            mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
181
182        strncpy(format->cMIMEType, pformat->cMIMEType,
183                mimetype_len);
184        format->cMIMEType[mimetype_len+1] = '\0';
185        format->pNativeRender = pformat->pNativeRender;
186        format->nFrameWidth = pformat->nFrameWidth;
187        format->nFrameHeight = pformat->nFrameHeight;
188        format->nBitrate = pformat->nBitrate;
189        format->xFramerate = pformat->xFramerate;
190        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
191        format->eCompressionFormat = pformat->eCompressionFormat;
192        format->eColorFormat = pformat->eColorFormat;
193        format->pNativeWindow = pformat->pNativeWindow;
194
195        if (overwrite_readonly) {
196            format->nStride = pformat->nStride;
197            format->nSliceHeight = pformat->nSliceHeight;
198        }
199
200        break;
201    }
202    case OMX_PortDomainImage: {
203        OMX_IMAGE_PORTDEFINITIONTYPE *format = &temp.format.image;
204        const OMX_IMAGE_PORTDEFINITIONTYPE *pformat = &p->format.image;
205        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
206
207        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
208            mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
209
210        strncpy(format->cMIMEType, pformat->cMIMEType,
211                mimetype_len+1);
212        format->cMIMEType[mimetype_len+1] = '\0';
213        format->nFrameWidth = pformat->nFrameWidth;
214        format->nFrameHeight = pformat->nFrameHeight;
215        format->nStride = pformat->nStride;
216        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
217        format->eCompressionFormat = pformat->eCompressionFormat;
218        format->eColorFormat = pformat->eColorFormat;
219        format->pNativeWindow = pformat->pNativeWindow;
220
221        if (overwrite_readonly)
222            format->nSliceHeight = pformat->nSliceHeight;
223
224        break;
225    }
226    case OMX_PortDomainOther: {
227        OMX_OTHER_PORTDEFINITIONTYPE *format = &temp.format.other;
228        const OMX_OTHER_PORTDEFINITIONTYPE *pformat = &p->format.other;
229
230        format->eFormat = pformat->eFormat;
231        break;
232    }
233    default:
234        LOGE("cannot find 0x%08x port domain\n", p->eDomain);
235        return OMX_ErrorBadParameter;
236    }
237
238    memcpy(&portdefinition, &temp, sizeof(temp));
239    return OMX_ErrorNone;
240}
241
242const OMX_PARAM_PORTDEFINITIONTYPE *PortBase::GetPortDefinition(void)
243{
244    return &portdefinition;
245}
246
247/* Use/Allocate/FreeBuffer */
248OMX_ERRORTYPE PortBase::UseBuffer(OMX_BUFFERHEADERTYPE **ppBufferHdr,
249                                  OMX_U32 nPortIndex,
250                                  OMX_PTR pAppPrivate,
251                                  OMX_U32 nSizeBytes,
252                                  OMX_U8 *pBuffer)
253{
254    OMX_BUFFERHEADERTYPE *buffer_hdr;
255    struct list *entry;
256
257    pthread_mutex_lock(&hdrs_lock);
258
259    if (portdefinition.bPopulated == OMX_TRUE) {
260        pthread_mutex_unlock(&hdrs_lock);
261        return OMX_ErrorNone;
262    }
263
264    buffer_hdr = (OMX_BUFFERHEADERTYPE *)calloc(1, sizeof(*buffer_hdr));
265    if (!buffer_hdr) {
266        pthread_mutex_unlock(&hdrs_lock);
267        return OMX_ErrorInsufficientResources;
268    }
269
270    entry = list_alloc(buffer_hdr);
271    if (!entry) {
272        free(buffer_hdr);
273        pthread_mutex_unlock(&hdrs_lock);
274        return OMX_ErrorInsufficientResources;
275    }
276
277    ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr));
278    buffer_hdr->pBuffer = pBuffer;
279    buffer_hdr->nAllocLen = nSizeBytes;
280    buffer_hdr->pAppPrivate = pAppPrivate;
281    if (portdefinition.eDir == OMX_DirInput) {
282        buffer_hdr->nInputPortIndex = nPortIndex;
283        buffer_hdr->nOutputPortIndex = 0x7fffffff;
284        buffer_hdr->pInputPortPrivate = this;
285        buffer_hdr->pOutputPortPrivate = NULL;
286    }
287    else {
288        buffer_hdr->nOutputPortIndex = nPortIndex;
289        buffer_hdr->nInputPortIndex = 0x7fffffff;
290        buffer_hdr->pOutputPortPrivate = this;
291        buffer_hdr->pInputPortPrivate = NULL;
292    }
293
294    buffer_hdrs = __list_add_tail(buffer_hdrs, entry);
295    nr_buffer_hdrs++;
296
297    if (nr_buffer_hdrs >= portdefinition.nBufferCountActual) {
298        portdefinition.bPopulated = OMX_TRUE;
299        buffer_hdrs_completion = true;
300        pthread_cond_signal(&hdrs_wait);
301    }
302
303    *ppBufferHdr = buffer_hdr;
304
305    pthread_mutex_unlock(&hdrs_lock);
306    return OMX_ErrorNone;
307}
308
309OMX_ERRORTYPE PortBase::AllocateBuffer(OMX_BUFFERHEADERTYPE **ppBuffer,
310                                       OMX_U32 nPortIndex,
311                                       OMX_PTR pAppPrivate,
312                                       OMX_U32 nSizeBytes)
313{
314    OMX_BUFFERHEADERTYPE *buffer_hdr;
315    struct list *entry;
316
317    pthread_mutex_lock(&hdrs_lock);
318    if (portdefinition.bPopulated == OMX_TRUE) {
319        pthread_mutex_unlock(&hdrs_lock);
320        return OMX_ErrorNone;
321    }
322
323    buffer_hdr = (OMX_BUFFERHEADERTYPE *)
324        calloc(1, sizeof(*buffer_hdr) + nSizeBytes);
325    if (!buffer_hdr) {
326        pthread_mutex_unlock(&hdrs_lock);
327        return OMX_ErrorInsufficientResources;
328    }
329
330    entry = list_alloc(buffer_hdr);
331    if (!entry) {
332        free(buffer_hdr);
333        pthread_mutex_unlock(&hdrs_lock);
334        return OMX_ErrorInsufficientResources;
335    }
336
337    ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr));
338    buffer_hdr->pBuffer = (OMX_U8 *)buffer_hdr + sizeof(*buffer_hdr);
339    buffer_hdr->nAllocLen = nSizeBytes;
340    buffer_hdr->pAppPrivate = pAppPrivate;
341    if (portdefinition.eDir == OMX_DirInput) {
342        buffer_hdr->nInputPortIndex = nPortIndex;
343        buffer_hdr->nOutputPortIndex = (OMX_U32)-1;
344        buffer_hdr->pInputPortPrivate = this;
345        buffer_hdr->pOutputPortPrivate = NULL;
346    }
347    else {
348        buffer_hdr->nOutputPortIndex = nPortIndex;
349        buffer_hdr->nInputPortIndex = (OMX_U32)-1;
350        buffer_hdr->pOutputPortPrivate = this;
351        buffer_hdr->pInputPortPrivate = NULL;
352    }
353
354    buffer_hdrs = __list_add_tail(buffer_hdrs, entry);
355    nr_buffer_hdrs++;
356
357    if (nr_buffer_hdrs == portdefinition.nBufferCountActual) {
358        portdefinition.bPopulated = OMX_TRUE;
359        buffer_hdrs_completion = true;
360        pthread_cond_signal(&hdrs_wait);
361    }
362
363    *ppBuffer = buffer_hdr;
364
365    pthread_mutex_unlock(&hdrs_lock);
366    return OMX_ErrorNone;
367}
368
369OMX_ERRORTYPE PortBase::FreeBuffer(OMX_U32 nPortIndex,
370                                   OMX_BUFFERHEADERTYPE *pBuffer)
371{
372    struct list *entry;
373    OMX_ERRORTYPE ret;
374
375    pthread_mutex_lock(&hdrs_lock);
376    entry = list_find(buffer_hdrs, pBuffer);
377
378    if (!entry) {
379        pthread_mutex_unlock(&hdrs_lock);
380        return OMX_ErrorNone;
381    }
382
383    if (entry->data != pBuffer) {
384        pthread_mutex_unlock(&hdrs_lock);
385        return OMX_ErrorBadParameter;
386    }
387
388    ret = ComponentBase::CheckTypeHeader(pBuffer, sizeof(*pBuffer));
389    if (ret != OMX_ErrorNone) {
390        pthread_mutex_unlock(&hdrs_lock);
391        return ret;
392    }
393
394    buffer_hdrs = __list_delete(buffer_hdrs, entry);
395    nr_buffer_hdrs--;
396
397    portdefinition.bPopulated = OMX_FALSE;
398    if (!nr_buffer_hdrs) {
399        buffer_hdrs_completion = true;
400        pthread_cond_signal(&hdrs_wait);
401    }
402
403    free(pBuffer);
404
405    pthread_mutex_unlock(&hdrs_lock);
406    return OMX_ErrorNone;
407}
408
409void PortBase::WaitPortBufferCompletion(void)
410{
411    pthread_mutex_lock(&hdrs_lock);
412    if (!buffer_hdrs_completion)
413        pthread_cond_wait(&hdrs_wait, &hdrs_lock);
414    buffer_hdrs_completion = !buffer_hdrs_completion;
415    pthread_mutex_unlock(&hdrs_lock);
416}
417
418/* Empty/FillThisBuffer */
419OMX_ERRORTYPE PortBase::PushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
420{
421    int ret;
422
423    pthread_mutex_lock(&bufferq_lock);
424    ret = queue_push_tail(&bufferq, pBuffer);
425    pthread_mutex_unlock(&bufferq_lock);
426
427    if (ret)
428        return OMX_ErrorInsufficientResources;
429
430    return OMX_ErrorNone;
431}
432
433OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
434{
435    int ret;
436
437    pthread_mutex_lock(&bufferq_lock);
438    ret = queue_push_head(&bufferq, pBuffer);
439    pthread_mutex_unlock(&bufferq_lock);
440
441    if (ret)
442        return OMX_ErrorInsufficientResources;
443
444    return OMX_ErrorNone;
445}
446
447OMX_BUFFERHEADERTYPE *PortBase::PopBuffer(void)
448{
449    OMX_BUFFERHEADERTYPE *buffer;
450
451    pthread_mutex_lock(&bufferq_lock);
452    buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
453    pthread_mutex_unlock(&bufferq_lock);
454
455    return buffer;
456}
457
458OMX_U32 PortBase::BufferQueueLength(void)
459{
460    OMX_U32 length;
461
462    pthread_mutex_lock(&bufferq_lock);
463    length = queue_length(&bufferq);
464    pthread_mutex_unlock(&bufferq_lock);
465
466    return length;
467}
468
469OMX_ERRORTYPE PortBase::ReturnThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
470{
471    OMX_DIRTYPE direction = portdefinition.eDir;
472    OMX_U32 port_index;
473    OMX_ERRORTYPE (*bufferdone_callback)(OMX_HANDLETYPE,
474                                         OMX_PTR,
475                                         OMX_BUFFERHEADERTYPE *);
476
477    if (!pBuffer)
478        return OMX_ErrorBadParameter;
479
480    if (direction == OMX_DirInput) {
481        port_index = pBuffer->nInputPortIndex;
482        bufferdone_callback = callbacks->EmptyBufferDone;
483    }
484    else if (direction == OMX_DirOutput) {
485        port_index = pBuffer->nOutputPortIndex;
486        bufferdone_callback = callbacks->FillBufferDone;
487    }
488    else
489        return OMX_ErrorBadParameter;
490
491    if (port_index != portdefinition.nPortIndex)
492        return OMX_ErrorBadParameter;
493
494    return bufferdone_callback(owner, appdata, pBuffer);
495}
496
497/* SendCommand:Flush/PortEnable/Disable */
498/* must be held ComponentBase::ports_block */
499OMX_ERRORTYPE PortBase::FlushPort(void)
500{
501    OMX_BUFFERHEADERTYPE *buffer;
502
503    while ((buffer = PopBuffer()))
504        ReturnThisBuffer(buffer);
505
506    return OMX_ErrorNone;
507}
508
509OMX_STATETYPE PortBase::GetOwnerState(void)
510{
511    OMX_STATETYPE state = OMX_StateInvalid;
512
513    if (owner) {
514        ComponentBase *cbase;
515        cbase = static_cast<ComponentBase *>(owner->pComponentPrivate);
516        if (!cbase)
517            return state;
518
519        cbase->CBaseGetState((void *)owner, &state);
520    }
521
522    return state;
523}
524
525bool PortBase::IsEnabled(void)
526{
527    bool enabled;
528    bool unlock = true;
529
530    if (pthread_mutex_trylock(&state_lock))
531        unlock = false;
532
533    enabled = (state == OMX_PortEnabled) ? true : false;
534
535    if (unlock)
536        pthread_mutex_unlock(&state_lock);
537
538    return enabled;
539}
540
541OMX_DIRTYPE PortBase::GetPortDirection(void)
542{
543    return portdefinition.eDir;
544}
545
546OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark)
547{
548    int ret;
549
550    pthread_mutex_lock(&markq_lock);
551    ret = queue_push_tail(&markq, mark);
552    pthread_mutex_unlock(&markq_lock);
553
554    if (ret)
555        return OMX_ErrorInsufficientResources;
556
557    return OMX_ErrorNone;
558}
559
560OMX_MARKTYPE *PortBase::PopMark(void)
561{
562    OMX_MARKTYPE *mark;
563
564    pthread_mutex_lock(&markq_lock);
565    mark = (OMX_MARKTYPE *)queue_pop_head(&markq);
566    pthread_mutex_unlock(&markq_lock);
567
568    return mark;
569}
570
571OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition)
572{
573    OMX_U8 current;
574    OMX_ERRORTYPE ret = OMX_ErrorNone;
575
576    pthread_mutex_lock(&state_lock);
577
578    current = state;
579
580    if (current == transition) {
581        ret = OMX_ErrorSameState;
582        goto unlock;
583    }
584
585    if (transition == OMX_PortEnabled) {
586        WaitPortBufferCompletion();
587        portdefinition.bEnabled = OMX_TRUE;
588    }
589    else if(transition == OMX_PortDisabled) {
590        FlushPort();
591        WaitPortBufferCompletion();
592        portdefinition.bEnabled = OMX_FALSE;
593    }
594    else {
595        ret = OMX_ErrorBadParameter;
596        goto unlock;
597    }
598
599    state = transition;
600
601unlock:
602    pthread_mutex_unlock(&state_lock);
603    return ret;
604}
605
606/* end of component methods & helpers */
607
608/* end of PortBase */
609