blob: 275f43c0fa61b188374503a118e22c53885739f4 [file] [log] [blame]
/*
INTEL CONFIDENTIAL
Copyright 2009 Intel Corporation All Rights Reserved.
The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel’s prior express written permission.
No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
*/
#ifdef ANDROID
#define true 1
#define false 0
#endif
#include <glib.h>
#include <dlfcn.h>
#include "vc1.h"
#include "h264.h"
#include "vbp_loader.h"
#include "vbp_utils.h"
#include "vbp_vc1_parser.h"
#include "vbp_h264_parser.h"
#include "vbp_mp42_parser.h"
/* buffer counter */
uint32 buffer_counter = 0;
/**
*
* uninitialize parser context
*
*/
static uint32 vbp_utils_uninitialize_context(vbp_context *pcontext)
{
uint32 error = VBP_OK;
if (NULL == pcontext)
{
return error;
}
/* not need to reset parser entry points. */
g_free(pcontext->parser_ops);
pcontext->parser_ops = NULL;
if (pcontext->fd_parser)
{
dlclose(pcontext->fd_parser);
pcontext->fd_parser = NULL;
}
return error;
}
/**
*
* initialize parser context
*
*/
static uint32 vbp_utils_initialize_context(vbp_context *pcontext)
{
uint32 error = VBP_OK;
char *parser_name;
switch (pcontext->parser_type)
{
case VBP_VC1:
#ifndef ANDROID
parser_name = "libmixvbp_vc1.so.0";
#else
parser_name = "libmixvbp_vc1.so";
#endif
break;
/* MPEG-2 parser is not supported. */
/* case VBP_MPEG2:
parser_name = "libmixvbp_mpeg2.so.0";
break;*/
case VBP_MPEG4:
#ifndef ANDROID
parser_name = "libmixvbp_mpeg4.so.0";
#else
parser_name = "libmixvbp_mpeg4.so";
#endif
break;
case VBP_H264:
#ifndef ANDROID
parser_name = "libmixvbp_h264.so.0";
#else
parser_name = "libmixvbp_h264.so";
#endif
break;
default:
g_warning ("Warning! Unsupported parser type!");
return VBP_TYPE;
}
pcontext->fd_parser = dlopen(parser_name, RTLD_LAZY);
if (NULL == pcontext->fd_parser)
{
ETRACE("Failed to load parser %s.", parser_name);
error = VBP_LOAD;
goto cleanup;
}
pcontext->parser_ops = g_try_new(viddec_parser_ops_t, 1);
if (NULL == pcontext->parser_ops)
{
ETRACE("Failed to allocate memory");
error = VBP_MEM;
goto cleanup;
}
#define SET_FUNC_POINTER(X, Y)\
case X:\
pcontext->func_init_parser_entries = vbp_init_parser_entries_##Y;\
pcontext->func_allocate_query_data = vbp_allocate_query_data_##Y;\
pcontext->func_free_query_data = vbp_free_query_data_##Y;\
pcontext->func_parse_init_data = vbp_parse_init_data_##Y;\
pcontext->func_parse_start_code = vbp_parse_start_code_##Y;\
pcontext->func_process_parsing_result = vbp_process_parsing_result_##Y;\
pcontext->func_populate_query_data = vbp_populate_query_data_##Y;\
break;
switch (pcontext->parser_type)
{
SET_FUNC_POINTER(VBP_VC1, vc1);
SET_FUNC_POINTER(VBP_MPEG4, mp42);
SET_FUNC_POINTER(VBP_H264, h264);
}
/* set entry points for parser operations:
init
parse_sc
parse_syntax
get_cxt_size
is_wkld_done
is_frame_start
*/
error = pcontext->func_init_parser_entries(pcontext);
cleanup:
if (VBP_OK != error)
{
/* no need to log error. the loader would have done so already. */
vbp_utils_uninitialize_context(pcontext);
}
return error;
}
/**
*
* free allocated memory.
*
*/
static uint32 vbp_utils_free_parser_memory(vbp_context *pcontext)
{
if (NULL == pcontext)
{
return VBP_OK;
}
if (pcontext->func_free_query_data)
{
pcontext->func_free_query_data(pcontext);
}
g_free(pcontext->workload2);
pcontext->workload2 = NULL;
g_free(pcontext->workload1);
pcontext->workload1 = NULL;
g_free(pcontext->persist_mem);
pcontext->persist_mem = NULL;
g_free(pcontext->parser_cxt);
pcontext->parser_cxt = NULL;
return VBP_OK;
}
/**
*
* allocate memory
*
*/
static uint32 vbp_utils_allocate_parser_memory(vbp_context *pcontext)
{
/* pcontext is guaranteed to be valid input. */
uint32 error = VBP_OK;
viddec_parser_memory_sizes_t sizes;
pcontext->parser_cxt = g_try_new(viddec_pm_cxt_t, 1);
if (NULL == pcontext->parser_cxt)
{
ETRACE("Failed to allocate memory");
error = VBP_MEM;
goto cleanup;
}
/* invoke parser entry to get context size */
/* no return value, should always succeed. */
pcontext->parser_ops->get_cxt_size(&sizes);
/* allocate persistent memory for parser */
if (sizes.persist_size)
{
pcontext->persist_mem = g_try_malloc(sizes.persist_size);
if (NULL == pcontext->persist_mem)
{
ETRACE("Failed to allocate memory");
error = VBP_MEM;
goto cleanup;
}
}
else
{
/* OK for VC-1, MPEG2 and MPEG4. */
if ((VBP_VC1 == pcontext->parser_type) ||
(VBP_MPEG2 == pcontext->parser_type) ||
(VBP_MPEG4 == pcontext->parser_type))
{
pcontext->persist_mem = NULL;
}
else
{
/* mandatory for H.264 */
ETRACE("Failed to allocate memory");
error = VBP_CXT;
goto cleanup;
}
}
/* allocate a new workload with 1000 items. */
pcontext->workload1 = g_try_malloc(sizeof(viddec_workload_t) +
(MAX_WORKLOAD_ITEMS * sizeof(viddec_workload_item_t)));
if (NULL == pcontext->workload1)
{
ETRACE("Failed to allocate memory");
error = VBP_MEM;
goto cleanup;
}
/* allocate a second workload with 1000 items. */
pcontext->workload2 = g_try_malloc(sizeof(viddec_workload_t) +
(MAX_WORKLOAD_ITEMS * sizeof(viddec_workload_item_t)));
if (NULL == pcontext->workload2)
{
ETRACE("Failed to allocate memory");
error = VBP_MEM;
goto cleanup;
}
/* allocate format-specific query data */
error = pcontext->func_allocate_query_data(pcontext);
cleanup:
if (error != VBP_OK)
{
vbp_utils_free_parser_memory(pcontext);
}
return error;
}
/**
*
* parse the elementary sample buffer or codec configuration data
*
*/
static uint32 vbp_utils_parse_es_buffer(vbp_context *pcontext, uint8 init_data_flag)
{
viddec_pm_cxt_t *cxt = pcontext->parser_cxt;
viddec_parser_ops_t *ops = pcontext->parser_ops;
uint32 error = VBP_OK;
int i;
/* reset list number. func_parse_init_data or func_parse_start_code will
* set it equal to number of sequence headers, picture headers or slices headers
* found in the sample buffer
*/
cxt->list.num_items = 0;
/**
* READ THIS NOTE: cxt->getbits.is_emul_reqd must be set to 1
* for H.264 and MPEG-4, VC1 advanced profile and set to 0
* for VC1 simple or main profile when parsing the frame
* buffer. When parsing the sequence header, it must be set to 1
* always.
*
* PARSER IMPLEMENTOR: set this flag in the parser.
*/
/*
if ((codec_type == VBP_H264) || (codec_type == VBP_MPEG4))
{
cxt->getbits.is_emul_reqd = 1;
}
*/
/* populate the list.*/
if (init_data_flag)
{
error = pcontext->func_parse_init_data(pcontext);
}
else
{
error = pcontext->func_parse_start_code(pcontext);
}
if (VBP_OK != error)
{
ETRACE("Failed to parse the start code!");
return error;
}
/* set up bitstream buffer */
cxt->getbits.list = &(cxt->list);
/* setup buffer pointer */
cxt->getbits.bstrm_buf.buf = cxt->parse_cubby.buf;
/*
* TO DO:
* check if cxt->getbits.is_emul_reqd is set properly
*/
for (i = 0; i < cxt->list.num_items; i++)
{
/* setup bitstream parser */
cxt->getbits.bstrm_buf.buf_index = cxt->list.data[i].stpos;
cxt->getbits.bstrm_buf.buf_st = cxt->list.data[i].stpos;
cxt->getbits.bstrm_buf.buf_end = cxt->list.data[i].edpos;
/* It is possible to end up with buf_offset not equal zero. */
cxt->getbits.bstrm_buf.buf_bitoff = 0;
cxt->getbits.au_pos = 0;
cxt->getbits.list_off = 0;
cxt->getbits.phase = 0;
cxt->getbits.emulation_byte_counter = 0;
cxt->list.start_offset = cxt->list.data[i].stpos;
cxt->list.end_offset = cxt->list.data[i].edpos;
cxt->list.total_bytes = cxt->list.data[i].edpos - cxt->list.data[i].stpos;
/* invoke parse entry point to parse the buffer */
error = ops->parse_syntax((void *)cxt, (void *)&(cxt->codec_data[0]));
/* can't return error for now. Neet further investigation */
/*if (0 != error)
{
ETRACE("failed to parse the syntax: %d!", error);
return error;
}*/
/*
* process parsing result
*/
error = pcontext->func_process_parsing_result(pcontext, i);
if (0 != error)
{
ETRACE("Failed to process parsing result.");
return error;
}
}
/* currently always assume a complete frame is supplied for parsing, so
* there is no need to check if workload is done
*/
/*
uint32_t codec_errors = 0;
uint32_t state;
error = ops->is_wkld_done(
(void *)cxt,
(void *)&(cxt->codec_data[0]),
(uint32_t)cxt->sc_prefix_info.next_sc,
&codec_errors);
state = (ret == VIDDEC_PARSE_FRMDONE) ? VBP_DONE : VBP_OK;
return state;
*/
return VBP_OK;
}
/**
*
* create the parser context
*
*/
uint32 vbp_utils_create_context(uint32 parser_type, vbp_context **ppcontext)
{
uint32 error = VBP_OK;
vbp_context *pcontext = NULL;
/* prevention from the failure */
*ppcontext = NULL;
pcontext = g_try_new0(vbp_context, 1);
if (NULL == pcontext)
{
error = VBP_MEM;
goto cleanup;
}
pcontext->parser_type = parser_type;
/* load parser, initialize parser operators and entry points */
error = vbp_utils_initialize_context(pcontext);
if (VBP_OK != error)
{
goto cleanup;
}
/* allocate parser context, persistent memory, query data and workload */
error = vbp_utils_allocate_parser_memory(pcontext);
if (VBP_OK != error)
{
goto cleanup;
}
viddec_pm_utils_list_init(&(pcontext->parser_cxt->list));
viddec_pm_utils_bstream_init(&(pcontext->parser_cxt->getbits), NULL, 0);
pcontext->parser_cxt->cur_buf.list_index = -1;
pcontext->parser_cxt->parse_cubby.phase = 0;
/* invoke the entry point to initialize the parser. */
pcontext->parser_ops->init(
(void *)pcontext->parser_cxt->codec_data,
(void *)pcontext->persist_mem,
FALSE);
viddec_emit_init(&(pcontext->parser_cxt->emitter));
/* overwrite init with our number of items. */
pcontext->parser_cxt->emitter.cur.max_items = MAX_WORKLOAD_ITEMS;
pcontext->parser_cxt->emitter.next.max_items = MAX_WORKLOAD_ITEMS;
/* set up to find the first start code. */
pcontext->parser_cxt->sc_prefix_info.first_sc_detect = 1;
/* indicates initialized OK. */
pcontext->identifier = MAGIC_NUMBER;
*ppcontext = pcontext;
error = VBP_OK;
cleanup:
if (VBP_OK != error)
{
vbp_utils_free_parser_memory(pcontext);
vbp_utils_uninitialize_context(pcontext);
g_free(pcontext);
pcontext = NULL;
}
return error;
}
/**
*
* destroy the context.
*
*/
uint32 vbp_utils_destroy_context(vbp_context *pcontext)
{
/* entry point, not need to validate input parameters. */
vbp_utils_free_parser_memory(pcontext);
vbp_utils_uninitialize_context(pcontext);
g_free(pcontext);
pcontext = NULL;
return VBP_OK;
}
/**
*
* parse the sample buffer or parser configuration data.
*
*/
uint32 vbp_utils_parse_buffer(vbp_context *pcontext, uint8 *data, uint32 size, uint8 init_data_flag)
{
/* entry point, not need to validate input parameters. */
uint32 error = VBP_OK;
//ITRACE("buffer counter: %d",buffer_counter);
/* set up emitter. */
pcontext->parser_cxt->emitter.cur.data = pcontext->workload1;
pcontext->parser_cxt->emitter.next.data = pcontext->workload2;
/* reset bit offset */
pcontext->parser_cxt->getbits.bstrm_buf.buf_bitoff = 0;
/* set up cubby. */
pcontext->parser_cxt->parse_cubby.buf = data;
pcontext->parser_cxt->parse_cubby.size = size;
pcontext->parser_cxt->parse_cubby.phase = 0;
error = vbp_utils_parse_es_buffer(pcontext, init_data_flag);
/* rolling count of buffers. */
if (0 == init_data_flag)
{
buffer_counter++;
}
return error;
}
/**
*
* provide query data back to the consumer
*
*/
uint32 vbp_utils_query(vbp_context *pcontext, void **data)
{
/* entry point, not need to validate input parameters. */
uint32 error = VBP_OK;
error = pcontext->func_populate_query_data(pcontext);
if (VBP_OK == error)
{
*data = pcontext->query_data;
}
else
{
*data = NULL;
}
return error;
}
/**
*
* flush parsing buffer. Currently it is no op.
*
*/
uint32 vbp_utils_flush(vbp_context *pcontext)
{
return VBP_IMPL;
}