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