| /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| //#define ALOG_NDEBUG 0 |
| #define ALOG_NIDEBUG 0 |
| #define LOG_TAG "QCameraMjpegDecode" |
| #include <utils/Log.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <pthread.h> |
| |
| extern "C" { |
| #include "jpeg_buffer.h" |
| #include "jpeg_common.h" |
| #include "jpegd.h" |
| } |
| |
| #include "QCameraMjpegDecode.h" |
| |
| /* TBDJ: Can be removed */ |
| #define MIN(a,b) (((a) < (b)) ? (a) : (b)) |
| |
| // Abstract the return type of the function to be run as a thread |
| #define OS_THREAD_FUNC_RET_T void * |
| |
| // Abstract the argument type to the thread function |
| #define OS_THREAD_FUNC_ARG_T void * |
| |
| // Helpful constants for return values in the thread functions |
| #define OS_THREAD_FUNC_RET_SUCCEEDED (OS_THREAD_FUNC_RET_T)0 |
| #define OS_THREAD_FUNC_RET_FAILED (OS_THREAD_FUNC_RET_T)1 |
| |
| // Abstract the function modifier placed in the beginning of the thread |
| // declaration (empty for Linux) |
| #define OS_THREAD_FUNC_MODIFIER |
| |
| #define os_mutex_init(a) pthread_mutex_init(a, NULL) |
| #define os_cond_init(a) pthread_cond_init(a, NULL) |
| #define os_mutex_lock pthread_mutex_lock |
| #define os_mutex_unlock pthread_mutex_unlock |
| #define os_cond_wait pthread_cond_wait |
| #define os_cond_signal pthread_cond_signal |
| |
| const char event_to_string[4][14] = |
| { |
| "EVENT_DONE", |
| "EVENT_WARNING", |
| "EVENT_ERROR", |
| }; |
| |
| typedef struct |
| { |
| uint32_t width; |
| uint32_t height; |
| uint32_t format; |
| uint32_t preference; |
| uint32_t abort_time; |
| uint16_t back_to_back_count; |
| /* TBDJ: Is this required */ |
| int32_t rotation; |
| /* TBDJ: Is this required */ |
| jpeg_rectangle_t region; |
| /* TBDJ: Is this required */ |
| jpegd_scale_type_t scale_factor; |
| uint32_t hw_rotation; |
| |
| char* inputMjpegBuffer; |
| int inputMjpegBufferSize; |
| char* outputYptr; |
| char* outputUVptr; |
| |
| } test_args_t; |
| |
| typedef struct |
| { |
| int tid; |
| pthread_t thread; |
| jpegd_obj_t decoder; |
| uint8_t decoding; |
| uint8_t decode_success; |
| pthread_mutex_t mutex; |
| pthread_cond_t cond; |
| test_args_t *p_args; |
| jpegd_output_buf_t *p_whole_output_buf; |
| |
| } thread_ctrl_blk_t; |
| |
| OS_THREAD_FUNC_RET_T OS_THREAD_FUNC_MODIFIER decoder_test(OS_THREAD_FUNC_ARG_T p_thread_args); |
| void decoder_event_handler(void *p_user_data, |
| jpeg_event_t event, |
| void *p_arg); |
| int decoder_output_handler(void *p_user_data, |
| jpegd_output_buf_t *p_output_buffer, |
| uint32_t first_row_id, |
| uint8_t is_last_buffer); |
| uint32_t decoder_input_req_handler(void *p_user_data, |
| jpeg_buffer_t buffer, |
| uint32_t start_offset, |
| uint32_t length); |
| static void* insertHuffmanTable(void *p, int size); |
| |
| static int mjpegd_timer_start(timespec *p_timer); |
| static int mjpegd_timer_get_elapsed(timespec *p_timer, int *elapsed_in_ms, uint8_t reset_start); |
| static int mjpegd_cond_timedwait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex, uint32_t ms); |
| |
| // Global variables |
| /* TBDJ: can be removed */ |
| thread_ctrl_blk_t *thread_ctrl_blks = NULL; |
| |
| /* |
| * This function initializes the mjpeg decoder and returns the object |
| */ |
| MJPEGD_ERR mjpegDecoderInit(void** mjpegd_obj) |
| { |
| test_args_t* mjpegd; |
| |
| ALOGD("%s: E", __func__); |
| |
| mjpegd = (test_args_t *)malloc(sizeof(test_args_t)); |
| if(!mjpegd) |
| return MJPEGD_INSUFFICIENT_MEM; |
| |
| memset(mjpegd, 0, sizeof(test_args_t)); |
| |
| /* Defaults */ |
| /* Due to current limitation, s/w decoder is selected always */ |
| mjpegd->preference = JPEG_DECODER_PREF_HW_ACCELERATED_PREFERRED; |
| mjpegd->back_to_back_count = 1; |
| mjpegd->rotation = 0; |
| mjpegd->hw_rotation = 0; |
| mjpegd->scale_factor = (jpegd_scale_type_t)1; |
| |
| /* TBDJ: can be removed */ |
| mjpegd->width = 640; |
| mjpegd->height = 480; |
| mjpegd->abort_time = 0; |
| |
| *mjpegd_obj = (void *)mjpegd; |
| |
| ALOGD("%s: X", __func__); |
| return MJPEGD_NO_ERROR; |
| } |
| |
| MJPEGD_ERR mjpegDecode( |
| void* mjpegd_obj, |
| char* inputMjpegBuffer, |
| int inputMjpegBufferSize, |
| char* outputYptr, |
| char* outputUVptr, |
| int outputFormat) |
| { |
| int rc, c, i; |
| test_args_t* mjpegd; |
| test_args_t test_args; |
| |
| ALOGD("%s: E", __func__); |
| /* store input arguments in the context */ |
| mjpegd = (test_args_t*) mjpegd_obj; |
| mjpegd->inputMjpegBuffer = inputMjpegBuffer; |
| mjpegd->inputMjpegBufferSize = inputMjpegBufferSize; |
| mjpegd->outputYptr = outputYptr; |
| mjpegd->outputUVptr = outputUVptr; |
| mjpegd->format = outputFormat; |
| |
| /* TBDJ: can be removed */ |
| memcpy(&test_args, mjpegd, sizeof(test_args_t)); |
| |
| // check the formats |
| if (((test_args.format == YCRCBLP_H1V2) || (test_args.format == YCBCRLP_H1V2) || |
| (test_args.format == YCRCBLP_H1V1) || (test_args.format == YCBCRLP_H1V1)) && |
| !(test_args.preference == JPEG_DECODER_PREF_HW_ACCELERATED_ONLY)) { |
| ALOGE("%s:These formats are not supported by SW format %d", __func__, test_args.format); |
| return 1; |
| } |
| |
| // Create thread control blocks |
| thread_ctrl_blks = (thread_ctrl_blk_t *)malloc( sizeof(thread_ctrl_blk_t)); |
| if (!thread_ctrl_blks) |
| { |
| ALOGE("%s: decoder_test failed: insufficient memory in creating thread control blocks", __func__); |
| return 1; |
| } |
| memset(thread_ctrl_blks, 0, sizeof(thread_ctrl_blk_t)); |
| // Initialize the blocks and kick off the threads |
| thread_ctrl_blks[i].tid = i; |
| thread_ctrl_blks[i].p_args = &test_args; |
| os_mutex_init(&thread_ctrl_blks[i].mutex); |
| os_cond_init(&thread_ctrl_blks[i].cond); |
| |
| rc = (int)decoder_test(&thread_ctrl_blks[i]); |
| |
| if (!rc) |
| ALOGD("%s: decoder_test finished successfully ", __func__); |
| else |
| ALOGE("%s: decoder_test failed",__func__); |
| |
| ALOGD("%s: X rc: %d", __func__, rc); |
| |
| return rc; |
| } |
| |
| OS_THREAD_FUNC_RET_T OS_THREAD_FUNC_MODIFIER decoder_test(OS_THREAD_FUNC_ARG_T arg) |
| { |
| int rc, i; |
| jpegd_obj_t decoder; |
| jpegd_src_t source; |
| jpegd_dst_t dest; |
| jpegd_cfg_t config; |
| jpeg_hdr_t header; |
| jpegd_output_buf_t p_output_buffers; |
| uint32_t output_buffers_count = 1; // currently only 1 buffer a time is supported |
| uint8_t use_pmem = true; |
| timespec os_timer; |
| thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)arg; |
| test_args_t *p_args = p_thread_arg->p_args; |
| uint32_t output_width; |
| uint32_t output_height; |
| uint32_t total_time = 0; |
| |
| ALOGD("%s: E", __func__); |
| |
| // Determine whether pmem should be used (useful for pc environment testing where |
| // pmem is not available) |
| if ((jpegd_preference_t)p_args->preference == JPEG_DECODER_PREF_SOFTWARE_PREFERRED || |
| (jpegd_preference_t)p_args->preference == JPEG_DECODER_PREF_SOFTWARE_ONLY) { |
| use_pmem = false; |
| } |
| |
| if (((jpegd_preference_t)p_args->preference != |
| JPEG_DECODER_PREF_HW_ACCELERATED_ONLY) && |
| ((jpegd_preference_t)p_args->scale_factor > 0)) { |
| ALOGI("%s: Setting scale factor to 1x", __func__); |
| } |
| |
| ALOGD("%s: before jpegd_init p_thread_arg: %p", __func__, p_thread_arg); |
| |
| // Initialize decoder |
| rc = jpegd_init(&decoder, |
| &decoder_event_handler, |
| &decoder_output_handler, |
| p_thread_arg); |
| |
| if (JPEG_FAILED(rc)) { |
| ALOGE("%s: decoder_test: jpegd_init failed", __func__); |
| goto fail; |
| } |
| p_thread_arg->decoder = decoder; |
| |
| // Set source information |
| source.p_input_req_handler = &decoder_input_req_handler; |
| source.total_length = p_args->inputMjpegBufferSize & 0xffffffff; |
| |
| rc = jpeg_buffer_init(&source.buffers[0]); |
| if (JPEG_SUCCEEDED(rc)) { |
| /* TBDJ: why buffer [1] */ |
| rc = jpeg_buffer_init(&source.buffers[1]); |
| } |
| if (JPEG_SUCCEEDED(rc)) { |
| #if 1 |
| rc = jpeg_buffer_allocate(source.buffers[0], 0xA000, use_pmem); |
| #else |
| rc = jpeg_buffer_use_external_buffer(source.buffers[0], |
| (uint8_t *)p_args->inputMjpegBuffer, |
| p_args->inputMjpegBufferSize, |
| 0); |
| #endif |
| ALOGD("%s: source.buffers[0]:%p compressed buffer ptr = %p", __func__, |
| source.buffers[0], p_args->inputMjpegBuffer); |
| } |
| if (JPEG_SUCCEEDED(rc)) { |
| #if 1 |
| rc = jpeg_buffer_allocate(source.buffers[1], 0xA000, use_pmem); |
| #else |
| rc = jpeg_buffer_use_external_buffer(source.buffers[1], |
| (uint8_t *)p_args->inputMjpegBuffer, |
| p_args->inputMjpegBufferSize, |
| 0); |
| #endif |
| ALOGD("%s: source.buffers[1]:%p compressed buffer ptr = %p", __func__, |
| source.buffers[1], p_args->inputMjpegBuffer); |
| } |
| if (JPEG_FAILED(rc)) { |
| jpeg_buffer_destroy(&source.buffers[0]); |
| jpeg_buffer_destroy(&source.buffers[1]); |
| goto fail; |
| } |
| |
| ALOGI("%s: *** Starting back-to-back decoding of %d frame(s)***\n", |
| __func__, p_args->back_to_back_count); |
| |
| // Loop to perform n back-to-back decoding (to the same output file) |
| for(i = 0; i < p_args->back_to_back_count; i++) { |
| if(mjpegd_timer_start(&os_timer) < 0) { |
| ALOGE("%s: failed to get start time", __func__); |
| } |
| |
| /* TBDJ: Every frame? */ |
| ALOGD("%s: before jpegd_set_source source.p_arg:%p", __func__, source.p_arg); |
| rc = jpegd_set_source(decoder, &source); |
| if (JPEG_FAILED(rc)) |
| { |
| ALOGE("%s: jpegd_set_source failed", __func__); |
| goto fail; |
| } |
| |
| rc = jpegd_read_header(decoder, &header); |
| if (JPEG_FAILED(rc)) |
| { |
| ALOGE("%s: jpegd_read_header failed", __func__); |
| goto fail; |
| } |
| p_args->width = header.main.width; |
| p_args->height = header.main.height; |
| ALOGD("%s: main dimension: (%dx%d) subsampling: (%d)", __func__, |
| header.main.width, header.main.height, (int)header.main.subsampling); |
| |
| // main image decoding: |
| // Set destination information |
| dest.width = (p_args->width) ? (p_args->width) : header.main.width; |
| dest.height = (p_args->height) ? (p_args->height) : header.main.height; |
| dest.output_format = (jpeg_color_format_t) p_args->format; |
| dest.region = p_args->region; |
| |
| // if region is defined, re-assign the output width/height |
| output_width = dest.width; |
| output_height = dest.height; |
| |
| if (p_args->region.right || p_args->region.bottom) |
| { |
| if (0 == p_args->rotation || 180 == p_args->rotation) |
| { |
| output_width = MIN((dest.width), |
| (uint32_t)(dest.region.right - dest.region.left + 1)); |
| output_height = MIN((dest.height), |
| (uint32_t)(dest.region.bottom - dest.region.top + 1)); |
| } |
| // Swap output width/height for 90/270 rotation cases |
| else if (90 == p_args->rotation || 270 == p_args->rotation) |
| { |
| output_height = MIN((dest.height), |
| (uint32_t)(dest.region.right - dest.region.left + 1)); |
| output_width = MIN((dest.width), |
| (uint32_t)(dest.region.bottom - dest.region.top + 1)); |
| } |
| // Unsupported rotation cases |
| else |
| { |
| goto fail; |
| } |
| } |
| |
| if (dest.output_format == YCRCBLP_H2V2 || dest.output_format == YCBCRLP_H2V2 || |
| dest.output_format == YCRCBLP_H2V1 || dest.output_format == YCBCRLP_H2V1 || |
| dest.output_format == YCRCBLP_H1V2 || dest.output_format == YCBCRLP_H1V2 || |
| dest.output_format == YCRCBLP_H1V1 || dest.output_format == YCBCRLP_H1V1) { |
| jpeg_buffer_init(&p_output_buffers.data.yuv.luma_buf); |
| jpeg_buffer_init(&p_output_buffers.data.yuv.chroma_buf); |
| } else { |
| jpeg_buffer_init(&p_output_buffers.data.rgb.rgb_buf); |
| |
| } |
| |
| { |
| // Assign 0 to tile width and height |
| // to indicate that no tiling is requested. |
| p_output_buffers.tile_width = 0; |
| p_output_buffers.tile_height = 0; |
| } |
| p_output_buffers.is_in_q = 0; |
| |
| switch (dest.output_format) |
| { |
| case YCRCBLP_H2V2: |
| case YCBCRLP_H2V2: |
| // case YCRCBLP_H2V1: |
| // case YCBCRLP_H2V1: |
| // case YCRCBLP_H1V2: |
| // case YCBCRLP_H1V2: |
| // case YCRCBLP_H1V1: |
| // case YCBCRLP_H1V1: |
| jpeg_buffer_use_external_buffer( |
| p_output_buffers.data.yuv.luma_buf, |
| (uint8_t*)p_args->outputYptr, |
| p_args->width * p_args->height * SQUARE(p_args->scale_factor), |
| 0); |
| jpeg_buffer_use_external_buffer( |
| p_output_buffers.data.yuv.chroma_buf, |
| (uint8_t*)p_args->outputUVptr, |
| p_args->width * p_args->height / 2 * SQUARE(p_args->scale_factor), |
| 0); |
| break; |
| |
| default: |
| ALOGE("%s: decoder_test: unsupported output format", __func__); |
| goto fail; |
| } |
| |
| // Set up configuration |
| memset(&config, 0, sizeof(jpegd_cfg_t)); |
| config.preference = (jpegd_preference_t) p_args->preference; |
| config.decode_from = JPEGD_DECODE_FROM_AUTO; |
| config.rotation = p_args->rotation; |
| config.scale_factor = p_args->scale_factor; |
| config.hw_rotation = p_args->hw_rotation; |
| dest.back_to_back_count = p_args->back_to_back_count; |
| |
| // Start decoding |
| p_thread_arg->decoding = true; |
| |
| rc = jpegd_start(decoder, &config, &dest, &p_output_buffers, output_buffers_count); |
| dest.back_to_back_count--; |
| |
| if(JPEG_FAILED(rc)) { |
| ALOGE("%s: decoder_test: jpegd_start failed (rc=%d)\n", |
| __func__, rc); |
| goto fail; |
| } |
| |
| ALOGD("%s: decoder_test: jpegd_start succeeded", __func__); |
| |
| // Do abort |
| if (p_args->abort_time) { |
| os_mutex_lock(&p_thread_arg->mutex); |
| while (p_thread_arg->decoding) |
| { |
| rc = mjpegd_cond_timedwait(&p_thread_arg->cond, &p_thread_arg->mutex, p_args->abort_time); |
| if (rc == JPEGERR_ETIMEDOUT) |
| { |
| // Do abort |
| os_mutex_unlock(&p_thread_arg->mutex); |
| rc = jpegd_abort(decoder); |
| if (rc) |
| { |
| ALOGE("%s: decoder_test: jpegd_abort failed: %d", __func__, rc); |
| goto fail; |
| } |
| break; |
| } |
| } |
| if (p_thread_arg->decoding) |
| os_mutex_unlock(&p_thread_arg->mutex); |
| } else { |
| // Wait until decoding is done or stopped due to error |
| os_mutex_lock(&p_thread_arg->mutex); |
| while (p_thread_arg->decoding) |
| { |
| os_cond_wait(&p_thread_arg->cond, &p_thread_arg->mutex); |
| } |
| os_mutex_unlock(&p_thread_arg->mutex); |
| } |
| |
| int diff; |
| // Display the time elapsed |
| if (mjpegd_timer_get_elapsed(&os_timer, &diff, 0) < 0) { |
| ALOGE("%s: decoder_test: failed to get elapsed time", __func__); |
| } else { |
| if(p_args->abort_time) { |
| if(p_thread_arg->decoding) { |
| ALOGI("%s: decoder_test: decoding aborted successfully after %d ms", __func__, diff); |
| goto buffer_clean_up; |
| } |
| else |
| { |
| ALOGI("%s: decoder_test: decoding stopped before abort is issued. " |
| "decode time: %d ms", __func__, diff); |
| } |
| } |
| else { |
| if(p_thread_arg->decode_success) { |
| total_time += diff; |
| ALOGI("%s: decode time: %d ms (%d frame(s), total=%dms, avg=%dms/frame)", |
| __func__, diff, i+1, total_time, total_time/(i+1)); |
| } |
| else |
| { |
| fprintf(stderr, "decoder_test: decode failed\n"); |
| } |
| } |
| } |
| } |
| |
| if(p_thread_arg->decode_success) { |
| ALOGD("%s: Frame(s) = %d, Total Time = %dms, Avg. decode time = %dms/frame)\n", |
| __func__, p_args->back_to_back_count, total_time, total_time/p_args->back_to_back_count); |
| } |
| |
| buffer_clean_up: |
| // Clean up decoder and allocate buffers |
| jpeg_buffer_destroy(&source.buffers[0]); |
| jpeg_buffer_destroy(&source.buffers[1]); |
| switch (dest.output_format) |
| { |
| case YCRCBLP_H2V2: |
| case YCBCRLP_H2V2: |
| case YCRCBLP_H2V1: |
| case YCBCRLP_H2V1: |
| case YCRCBLP_H1V2: |
| case YCBCRLP_H1V2: |
| case YCRCBLP_H1V1: |
| case YCBCRLP_H1V1: |
| jpeg_buffer_destroy(&p_output_buffers.data.yuv.luma_buf); |
| jpeg_buffer_destroy(&p_output_buffers.data.yuv.chroma_buf); |
| break; |
| default: |
| break; |
| } |
| jpegd_destroy(&decoder); |
| |
| if (!p_thread_arg->decode_success) |
| { |
| goto fail; |
| } |
| |
| ALOGD("%s: X", __func__); |
| return OS_THREAD_FUNC_RET_SUCCEEDED; |
| fail: |
| |
| ALOGD("%s: X", __func__); |
| return OS_THREAD_FUNC_RET_FAILED; |
| } |
| |
| void decoder_event_handler(void *p_user_data, |
| jpeg_event_t event, |
| void *p_arg) |
| { |
| thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)p_user_data; |
| |
| ALOGD("%s: E", __func__); |
| |
| ALOGD("%s: Event: %s\n", __func__, event_to_string[event]); |
| if (event == JPEG_EVENT_DONE) |
| { |
| p_thread_arg->decode_success = true; |
| ALOGD("%s: decode_success: %d\n", __func__, p_thread_arg->decode_success); |
| } |
| // If it is not a warning event, decoder has stopped; Signal |
| // main thread to clean up |
| if (event != JPEG_EVENT_WARNING) |
| { |
| os_mutex_lock(&p_thread_arg->mutex); |
| p_thread_arg->decoding = false; |
| os_cond_signal(&p_thread_arg->cond); |
| os_mutex_unlock(&p_thread_arg->mutex); |
| } |
| ALOGD("%s: X", __func__); |
| |
| } |
| |
| // consumes the output buffer. |
| /*TBDJ: Can be removed. Is this related to tiling */ |
| int decoder_output_handler(void *p_user_data, |
| jpegd_output_buf_t *p_output_buffer, |
| uint32_t first_row_id, |
| uint8_t is_last_buffer) |
| { |
| uint8_t* whole_output_buf_ptr, *tiling_buf_ptr; |
| |
| ALOGD("%s: E", __func__); |
| |
| thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)p_user_data; |
| |
| jpeg_buffer_get_addr(p_thread_arg->p_whole_output_buf->data.rgb.rgb_buf, &whole_output_buf_ptr); |
| jpeg_buffer_get_addr(p_output_buffer->data.rgb.rgb_buf, &tiling_buf_ptr); |
| |
| if (p_output_buffer->tile_height != 1) |
| return JPEGERR_EUNSUPPORTED; |
| |
| // testing purpose only |
| // This is to simulate that the user needs to bail out when error happens |
| // in the middle of decoding |
| //if (first_row_id == 162) |
| // return JPEGERR_EFAILED; |
| |
| // do not enqueue any buffer if it reaches the last buffer |
| if (!is_last_buffer) |
| { |
| jpegd_enqueue_output_buf(p_thread_arg->decoder, p_output_buffer, 1); |
| } |
| ALOGD("%s: X", __func__); |
| |
| return JPEGERR_SUCCESS; |
| } |
| |
| // p_reader->p_input_req_handler(p_reader->decoder, |
| // p_reader->p_input_buf, |
| // p_reader->next_byte_offset, |
| // MAX_BYTES_TO_FETCH); |
| |
| uint32_t decoder_input_req_handler(void *p_user_data, |
| jpeg_buffer_t buffer, |
| uint32_t start_offset, |
| uint32_t length) |
| { |
| uint32_t buf_size; |
| uint8_t *buf_ptr; |
| int bytes_to_read, bytes_read, rc; |
| thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)p_user_data; |
| thread_ctrl_blk_t *thread_ctrl_blk = (thread_ctrl_blk_t *)p_user_data; |
| test_args_t* mjpegd = (test_args_t*) thread_ctrl_blk->p_args; |
| |
| ALOGD("%s: E", __func__); |
| |
| jpeg_buffer_get_max_size(buffer, &buf_size); |
| jpeg_buffer_get_addr(buffer, &buf_ptr); |
| bytes_to_read = (length < buf_size) ? length : buf_size; |
| bytes_read = 0; |
| |
| ALOGD("%s: buf_ptr = %p, start_offset = %d, length = %d buf_size = %d bytes_to_read = %d", __func__, buf_ptr, start_offset, length, buf_size, bytes_to_read); |
| if (bytes_to_read) |
| { |
| /* TBDJ: Should avoid this Mem copy */ |
| #if 1 |
| memcpy(buf_ptr, (char *)mjpegd->inputMjpegBuffer + start_offset, bytes_to_read); |
| #else |
| if(JPEGERR_SUCCESS != jpeg_buffer_set_start_offset(buffer, start_offset)) |
| ALOGE("%s: jpeg_buffer_set_start_offset failed", __func__); |
| #endif |
| bytes_read = bytes_to_read; |
| } |
| |
| ALOGD("%s: X", __func__); |
| return bytes_read; |
| } |
| |
| static int mjpegd_timer_start(timespec *p_timer) |
| { |
| if (!p_timer) |
| return JPEGERR_ENULLPTR; |
| |
| if (clock_gettime(CLOCK_REALTIME, p_timer)) |
| return JPEGERR_EFAILED; |
| |
| return JPEGERR_SUCCESS; |
| } |
| |
| static int mjpegd_timer_get_elapsed(timespec *p_timer, int *elapsed_in_ms, uint8_t reset_start) |
| { |
| timespec now; |
| long diff; |
| int rc = mjpegd_timer_start(&now); |
| |
| if (JPEG_FAILED(rc)) |
| return rc; |
| |
| diff = (long)(now.tv_sec - p_timer->tv_sec) * 1000; |
| diff += (long)(now.tv_nsec - p_timer->tv_nsec) / 1000000; |
| *elapsed_in_ms = (int)diff; |
| |
| if (reset_start) |
| *p_timer = now; |
| |
| return JPEGERR_SUCCESS; |
| } |
| |
| int mjpegd_cond_timedwait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex, uint32_t ms) |
| { |
| struct timespec ts; |
| int rc = clock_gettime(CLOCK_REALTIME, &ts); |
| if (rc < 0) return rc; |
| |
| if (ms >= 1000) { |
| ts.tv_sec += (ms/1000); |
| ts.tv_nsec += ((ms%1000) * 1000000); |
| } else { |
| ts.tv_nsec += (ms * 1000000); |
| } |
| |
| rc = pthread_cond_timedwait(p_cond, p_mutex, &ts); |
| if (rc == ETIMEDOUT) |
| { |
| rc = JPEGERR_ETIMEDOUT; |
| } |
| return rc; |
| } |
| |