1/**
2 * @copyright
3 *
4 *   Copyright (c) 2015, The Linux Foundation. All rights reserved.
5 *
6 *   Redistribution and use in source and binary forms, with or without
7 *   modification, are permitted provided that the following conditions are met:
8 *
9 *   * Redistributions of source code must retain the above copyright notice,
10 *     this list of conditions and the following disclaimer.
11 *   * Redistributions in binary form must reproduce the above copyright notice,
12 *     this list of conditions and the following disclaimer in the documentation
13 *     and/or other materials provided with the distribution.
14 *   * Neither the name of The Linux Foundation nor the names of its
15 *     contributors may be used to endorse or promote products derived from
16 *     this software without specific prior written permission.
17 *
18 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
20 *   FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED.
21 *   IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
22 *   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 *   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 *   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 *   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 *   DAMAGE.
29 *
30 * @file
31 *
32 *   omx_swvdec_utils.cpp
33 *
34 * @brief
35 *
36 *   OMX software video decoder utility functions source.
37 */
38
39#include <stdlib.h>
40#include <string.h>
41#include <assert.h>
42#include <pthread.h>
43
44#include <cutils/properties.h>
45
46#include "omx_swvdec_utils.h"
47
48#define OMX_SWVDEC_LOGLEVEL_DEFAULT 2 ///< default OMX SwVdec loglevel
49
50unsigned int g_omx_swvdec_logmask = (1 << OMX_SWVDEC_LOGLEVEL_DEFAULT) - 1;
51                              ///< global OMX SwVdec logmask variable definition
52
53/**
54 * @brief Initialize OMX SwVdec log level & mask.
55 */
56void omx_swvdec_log_init()
57{
58    int omx_swvdec_loglevel = OMX_SWVDEC_LOGLEVEL_DEFAULT;
59
60    char property_value[PROPERTY_VALUE_MAX] = {0};
61
62    if (property_get("omx_swvdec.log.level", property_value, NULL))
63    {
64        omx_swvdec_loglevel = atoi(property_value);
65
66        if (omx_swvdec_loglevel > 3)
67            omx_swvdec_loglevel = 3;
68        if (omx_swvdec_loglevel < 0)
69            omx_swvdec_loglevel = 0;
70
71        OMX_SWVDEC_LOG_LOW(
72            "omx_swvdec.log.level: %d; %s",
73            omx_swvdec_loglevel,
74            (omx_swvdec_loglevel == 3) ? "error, high, & low logs" :
75            ((omx_swvdec_loglevel == 2) ? "error & high logs" :
76             ((omx_swvdec_loglevel == 1) ? "error logs" :
77              "no logs")));
78    }
79
80    g_omx_swvdec_logmask = (unsigned int) ((1 << omx_swvdec_loglevel) - 1);
81}
82
83/**
84 * @brief OMX SwVdec queue constructor.
85 */
86omx_swvdec_queue::omx_swvdec_queue()
87{
88    memset(m_queue, 0, sizeof(m_queue));
89
90    m_count_total  = OMX_SWVDEC_QUEUE_ELEMENTS;
91    m_count_filled = 0;
92    m_index_write  = 0;
93    m_index_read   = 0;
94
95    pthread_mutex_init(&m_mutex, NULL);
96}
97
98/**
99 * @brief OMX SwVdec queue destructor.
100 */
101omx_swvdec_queue::~omx_swvdec_queue()
102{
103    pthread_mutex_destroy(&m_mutex);
104}
105
106/**
107 * @brief Push event to queue.
108 *
109 * @param[in] p_event_info: Pointer to event information structure.
110 *
111 * @retval  true if push successful
112 * @retval false if push unsuccessful
113 */
114bool omx_swvdec_queue::push(OMX_SWVDEC_EVENT_INFO *p_event_info)
115{
116    bool retval = true;
117
118    pthread_mutex_lock(&m_mutex);
119
120    if (m_count_filled < m_count_total)
121    {
122        m_queue[m_index_write] = *p_event_info;
123
124        m_index_write = (m_index_write + 1) % m_count_total;
125        m_count_filled++;
126    }
127    else
128    {
129        retval = false;
130    }
131
132    pthread_mutex_unlock(&m_mutex);
133
134    return retval;
135}
136
137/**
138 * @brief Pop event from queue.
139 *
140 * @param[in,out] p_event_info: Pointer to event information structure.
141 *
142 * @retval  true if pop successful
143 * @retval false if pop unsuccessful
144 */
145bool omx_swvdec_queue::pop(OMX_SWVDEC_EVENT_INFO *p_event_info)
146{
147    bool retval = true;
148
149    pthread_mutex_lock(&m_mutex);
150
151    if (m_count_filled > 0)
152    {
153        *p_event_info = m_queue[m_index_read];
154
155        memset(&m_queue[m_index_read], 0, sizeof(OMX_SWVDEC_EVENT_INFO));
156
157        m_index_read = (m_index_read + 1) % m_count_total;
158        m_count_filled--;
159    }
160    else
161    {
162        retval = false;
163    }
164
165    pthread_mutex_unlock(&m_mutex);
166
167    return retval;
168}
169
170/**
171 * @brief OMX SwVdec timestamp list constructor.
172 */
173omx_swvdec_ts_list::omx_swvdec_ts_list()
174{
175    reset();
176
177    pthread_mutex_init(&m_mutex, NULL);
178}
179
180/**
181 * @brief OMX SwVdec timestamp list destructor.
182 */
183omx_swvdec_ts_list::~omx_swvdec_ts_list()
184{
185    pthread_mutex_destroy(&m_mutex);
186}
187
188/**
189 * @brief Reset timestamp list.
190 */
191void omx_swvdec_ts_list::reset()
192{
193    memset(m_list, 0, sizeof(m_list));
194    m_count_filled = 0;
195}
196
197/**
198 * @brief Push timestamp to list, keeping lowest-valued timestamp at the end.
199 *
200 * @param[in] timestamp: Timestamp.
201 *
202 * @retval  true if push successful
203 * @retval false if push unsuccessful
204 */
205bool omx_swvdec_ts_list::push(long long timestamp)
206{
207    bool retval = true;
208
209    pthread_mutex_lock(&m_mutex);
210
211    if (m_count_filled < OMX_SWVDEC_TS_LIST_ELEMENTS)
212    {
213        int index_curr, index_prev;
214
215        long long timestamp_tmp;
216
217        // insert timestamp into list
218
219        m_list[m_count_filled].filled    = true;
220        m_list[m_count_filled].timestamp = timestamp;
221        m_count_filled++;
222
223        // iterate backwards
224
225        index_curr = m_count_filled - 1;
226        index_prev = m_count_filled - 2;
227
228        while ((index_curr > 0) &&
229               (m_list[index_curr].timestamp > m_list[index_prev].timestamp))
230        {
231            // swap timestamps
232
233            timestamp_tmp                = m_list[index_prev].timestamp;
234            m_list[index_prev].timestamp = m_list[index_curr].timestamp;
235            m_list[index_curr].timestamp = timestamp_tmp;
236
237            index_curr--;
238            index_prev--;
239        }
240    }
241    else
242    {
243        retval = false;
244    }
245
246    pthread_mutex_unlock(&m_mutex);
247
248    return retval;
249}
250
251/**
252 * @brief Pop timestamp from list.
253 *
254 * @param[in,out] p_timestamp: Pointer to timestamp variable.
255 *
256 * @retval  true if pop successful
257 * @retval false if pop unsuccessful
258 */
259bool omx_swvdec_ts_list::pop(long long *p_timestamp)
260{
261    bool retval;
262
263    pthread_mutex_lock(&m_mutex);
264
265    if (m_count_filled)
266    {
267        *p_timestamp = m_list[m_count_filled - 1].timestamp;
268        m_list[m_count_filled - 1].filled = false;
269        m_count_filled--;
270
271        retval = true;
272    }
273    else
274    {
275        retval = false;
276    }
277
278    pthread_mutex_unlock(&m_mutex);
279
280    return retval;
281}
282
283/**
284 * @brief OMX SwVdec diagnostics class constructor.
285 */
286omx_swvdec_diag::omx_swvdec_diag():
287    m_dump_ip(0),
288    m_dump_op(0),
289    m_filename_ip(NULL),
290    m_filename_op(NULL),
291    m_file_ip(NULL),
292    m_file_op(NULL)
293{
294    char property_value[PROPERTY_VALUE_MAX] = {0};
295
296    if (property_get("omx_swvdec.dump.ip", property_value, NULL))
297    {
298        m_dump_ip = atoi(property_value);
299        OMX_SWVDEC_LOG_LOW("omx_swvdec.dump.ip: %d", m_dump_ip);
300    }
301
302    if (property_get("omx_swvdec.dump.op", property_value, NULL))
303    {
304        m_dump_op = atoi(property_value);
305        OMX_SWVDEC_LOG_LOW("omx_swvdec.dump.op: %d", m_dump_op);
306    }
307
308    if (property_get("omx_swvdec.filename.ip",
309                     property_value,
310                     DIAG_FILENAME_IP))
311    {
312        OMX_SWVDEC_LOG_LOW("omx_swvdec.filename.ip: %s", m_filename_ip);
313
314        m_filename_ip =
315            (char *) malloc((strlen(property_value) + 1) * sizeof(char));
316
317        if (m_filename_ip == NULL)
318        {
319            OMX_SWVDEC_LOG_ERROR("failed to allocate %d bytes for "
320                                 "input filename string",
321                                 (strlen(property_value) + 1) * sizeof(char));
322        }
323        else
324        {
325            strncpy(m_filename_ip, property_value, strlen(property_value) + 1);
326        }
327    }
328
329    if (property_get("omx_swvdec.filename.op",
330                     property_value,
331                     DIAG_FILENAME_OP))
332    {
333        OMX_SWVDEC_LOG_LOW("omx_swvdec.filename.op: %s", m_filename_op);
334
335        m_filename_op =
336            (char *) malloc((strlen(property_value) + 1) * sizeof(char));
337
338        if (m_filename_op == NULL)
339        {
340            OMX_SWVDEC_LOG_ERROR("failed to allocate %d bytes for "
341                                 "output filename string",
342                                 (strlen(property_value) + 1) * sizeof(char));
343        }
344        else
345        {
346            strncpy(m_filename_op, property_value, strlen(property_value) + 1);
347        }
348    }
349
350    if (m_dump_ip && (m_filename_ip != NULL))
351    {
352        if ((m_file_ip = fopen(m_filename_ip, "rb")) == NULL)
353        {
354            OMX_SWVDEC_LOG_ERROR("cannot open input file '%s'", m_filename_ip);
355            m_dump_ip = 0;
356        }
357    }
358    else
359    {
360        m_dump_ip = 0;
361    }
362
363    if (m_dump_op && (m_filename_op != NULL))
364    {
365        if ((m_file_op = fopen(m_filename_op, "rb")) == NULL)
366        {
367            OMX_SWVDEC_LOG_ERROR("cannot open output file '%s'", m_filename_op);
368            m_dump_op = 0;
369        }
370    }
371    else
372    {
373        m_dump_op = 0;
374    }
375}
376
377/**
378 * @brief OMX SwVdec diagnostics class destructor.
379 */
380omx_swvdec_diag::~omx_swvdec_diag()
381{
382    if (m_file_op)
383    {
384        fclose(m_file_op);
385        m_file_op = NULL;
386    }
387
388    if (m_file_ip)
389    {
390        fclose(m_file_ip);
391        m_file_ip = NULL;
392    }
393
394    if (m_filename_op)
395    {
396        free(m_filename_op);
397        m_filename_op = NULL;
398    }
399
400    if (m_filename_ip)
401    {
402        free(m_filename_ip);
403        m_filename_ip = NULL;
404    }
405}
406
407/**
408 * @brief Dump input bitstream to file.
409 *
410 * @param[in] p_buffer:      Pointer to input bitstream buffer.
411 * @param[in] filled_length: Bitstream buffer's filled length.
412 */
413void omx_swvdec_diag::dump_ip(unsigned char *p_buffer,
414                              unsigned int   filled_length)
415{
416    if (m_dump_ip)
417    {
418        fwrite(p_buffer, sizeof(unsigned char), filled_length, m_file_ip);
419    }
420}
421
422/**
423 * @brief Dump output YUV to file.
424 *
425 * @param[in] p_buffer:  Pointer to output YUV buffer.
426 * @param[in] width:     Frame width.
427 * @param[in] height:    Frame height.
428 * @param[in] stride:    Frame stride.
429 * @param[in] scanlines: Frame scanlines.
430 */
431void omx_swvdec_diag::dump_op(unsigned char *p_buffer,
432                              unsigned int   width,
433                              unsigned int   height,
434                              unsigned int   stride,
435                              unsigned int   scanlines)
436{
437    if (m_dump_op)
438    {
439        unsigned char *p_buffer_y;
440        unsigned char *p_buffer_uv;
441
442        unsigned int ii;
443
444        p_buffer_y  = p_buffer;
445        p_buffer_uv = p_buffer + (stride * scanlines);
446
447        for (ii = 0; ii < height; ii++)
448        {
449            fwrite(p_buffer_y, sizeof(unsigned char), width, m_file_op);
450
451            p_buffer_y += stride;
452        }
453
454        for (ii = 0; ii < (height / 2); ii++)
455        {
456            fwrite(p_buffer_uv, sizeof(unsigned char), width, m_file_op);
457
458            p_buffer_uv += stride;
459        }
460    }
461}
462