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