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 
50 unsigned 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  */
omx_swvdec_log_init()56 void 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  */
omx_swvdec_queue()86 omx_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  */
~omx_swvdec_queue()101 omx_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  */
push(OMX_SWVDEC_EVENT_INFO * p_event_info)114 bool 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  */
pop(OMX_SWVDEC_EVENT_INFO * p_event_info)145 bool 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  */
omx_swvdec_ts_list()173 omx_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  */
~omx_swvdec_ts_list()183 omx_swvdec_ts_list::~omx_swvdec_ts_list()
184 {
185     pthread_mutex_destroy(&m_mutex);
186 }
187 
188 /**
189  * @brief Reset timestamp list.
190  */
reset()191 void 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  */
push(long long timestamp)205 bool 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  */
pop(long long * p_timestamp)259 bool 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  */
omx_swvdec_diag()286 omx_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  */
~omx_swvdec_diag()380 omx_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  */
dump_ip(unsigned char * p_buffer,unsigned int filled_length)413 void 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  */
dump_op(unsigned char * p_buffer,unsigned int width,unsigned int height,unsigned int stride,unsigned int scanlines)431 void 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