blob: 9765f283a865b6e021cf7ddb3669396e6626b2c6 [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.
*/
#include <glib.h>
#include <dlfcn.h>
#include <string.h>
#include "vbp_loader.h"
#include "vbp_utils.h"
#include "vbp_mp42_parser.h"
#include "../codecs/mp4/parser/viddec_mp4_parse.h"
static bool short_video_header = TRUE;
static uint8 mp4_aspect_ratio_table[][2] =
{
// forbidden
{0, 0},
{1, 1},
{12, 11},
{10, 11},
{16, 11},
{40, 33},
// reserved
{0, 0}
};
/*
* Some divX avi files contains 2 frames in one gstbuffer.
*/
uint32 vbp_get_sc_pos_mp42(
uint8 *buf,
uint32 length,
uint32 *sc_end_pos,
uint8 *is_normal_sc,
uint8* resync_marker);
void vbp_on_vop_mp42(vbp_context *pcontext, int list_index);
void vbp_on_vop_svh_mp42(vbp_context *pcontext, int list_index);
void vbp_fill_codec_data(vbp_context *pcontext);
vbp_picture_data_mp42* vbp_get_mp42_picture_data(vbp_data_mp42 * query_data);
uint32 vbp_process_slices_mp42(vbp_context *pcontext, int list_index);
uint32 vbp_process_slices_svh_mp42(vbp_context *pcontext, int list_index);
uint32 vbp_process_video_packet_mp42(vbp_context *pcontext);
static inline uint32 vbp_sprite_trajectory_mp42(
void *parent,
mp4_VideoObjectLayer_t *vidObjLay,
mp4_VideoObjectPlane_t *vidObjPlane);
static inline uint32 vbp_sprite_dmv_length_mp42(
void * parent,
int32_t *dmv_length);
/**
*
*/
uint32 vbp_init_parser_entries_mp42( vbp_context *pcontext)
{
if (NULL == pcontext->parser_ops)
{
// absolutely impossible, just sanity check
return VBP_PARM;
}
pcontext->parser_ops->init = dlsym(pcontext->fd_parser, "viddec_mp4_init");
if (pcontext->parser_ops->init == NULL)
{
ETRACE ("Failed to set entry point." );
return VBP_LOAD;
}
pcontext->parser_ops->parse_sc = dlsym(pcontext->fd_parser, "viddec_parse_sc_mp4");
if (pcontext->parser_ops->parse_sc == NULL)
{
ETRACE ("Failed to set entry point." );
return VBP_LOAD;
}
pcontext->parser_ops->parse_syntax = dlsym(pcontext->fd_parser, "viddec_mp4_parse");
if (pcontext->parser_ops->parse_syntax == NULL)
{
ETRACE ("Failed to set entry point." );
return VBP_LOAD;
}
pcontext->parser_ops->get_cxt_size =dlsym(pcontext->fd_parser, "viddec_mp4_get_context_size");
if (pcontext->parser_ops->get_cxt_size == NULL)
{
ETRACE ("Failed to set entry point." );
return VBP_LOAD;
}
pcontext->parser_ops->is_wkld_done = dlsym(pcontext->fd_parser, "viddec_mp4_wkld_done");
if (pcontext->parser_ops->is_wkld_done == NULL)
{
ETRACE ("Failed to set entry point." );
return VBP_LOAD;
}
return VBP_OK;
}
/*
* For the codec_data passed by gstreamer
*/
uint32 vbp_parse_init_data_mp42(vbp_context *pcontext)
{
uint32 ret = VBP_OK;
ret = vbp_parse_start_code_mp42(pcontext);
return ret;
}
uint32 vbp_process_parsing_result_mp42(vbp_context *pcontext, int list_index)
{
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
viddec_mp4_parser_t *parser =
(viddec_mp4_parser_t *) &(pcontext->parser_cxt->codec_data[0]);
uint8 is_svh = 0;
uint32 current_sc = parser->current_sc;
is_svh = parser->cur_sc_prefix ? false : true;
if (!is_svh)
{
// remove prefix from current_sc
current_sc &= 0x0FF;
switch (current_sc)
{
case MP4_SC_VISUAL_OBJECT_SEQUENCE:
VTRACE ("Visual Object Sequence is parsed.\n");
query_data->codec_data.profile_and_level_indication
= parser->info.profile_and_level_indication;
VTRACE ("profile_and_level_indication = 0x%x\n", parser->info.profile_and_level_indication);
break;
case MP4_SC_VIDEO_OBJECT_PLANE:
VTRACE ("Video Object Plane is parsed.\n");
vbp_on_vop_mp42(pcontext, list_index);
break;
default:
if ((current_sc >= MP4_SC_VIDEO_OBJECT_LAYER_MIN) &&
(current_sc <= MP4_SC_VIDEO_OBJECT_LAYER_MAX))
{
VTRACE ("Video Object Layer is parsed\n");
short_video_header = FALSE;
vbp_fill_codec_data(pcontext);
}
else if (current_sc <= MP4_SC_VIDEO_OBJECT_MAX &&
current_sc >= MP4_SC_VIDEO_OBJECT_MIN)
{
if (parser->sc_seen == MP4_SC_SEEN_SVH)
{
// this should never happen!!!!
WTRACE ("Short video header is parsed.\n");
vbp_on_vop_svh_mp42(pcontext, list_index);
}
}
break;
}
}
else
{
if (parser->sc_seen == MP4_SC_SEEN_SVH)
{
VTRACE ("Short video header is parsed.\n");
vbp_on_vop_svh_mp42(pcontext, list_index);
}
}
return VBP_OK;
}
/*
* partial frame handling:
*
* h.263: picture header is lost if the first GOB is discarded, a redudant pic header must be
* conveyed in the packet (RFC 4629) for each following GOB, otherwise,
* picture can't be decoded.
*
* MPEG4: VideoObjectPlane header is lost if the first slice is discarded. However, picture
* is still decodable as long as the header_extension_code is 1 in video_packet_header.
*
*MPEG-4 with short header: video_plane_with_short_header is lost if the first GOB
* is discarded. As this header is not duplicated (RFC 3016), picture is not decodable.
*
* In sum:
* If buffer contains the 32-bit start code (0x000001xx), proceed as normal.
*
* If buffer contains 22-bits of "0000 0000 0000 0000 1000 00", which indicates h.263
* picture start code or short_video_start_marker, proceed as normal.
*
* If buffer contains 22-bits of "0000 0000 0000 0000 1XXX XX", (when XXX XX starts from 000 01), which
* indicates h.263 Group Start code or gob_resync_marker of gob_layer in MPEG-4 with
* short header, we should report packet as a partial frame - no more parsing is needed.
*
* If buffer contains a string of 0 between 16 bits and 22 bits, followed by 1-bit of '1', which indicates a resync-marker,
* the buffer will be immeidately parsed and num_items is set to 0.
*/
uint32 vbp_parse_start_code_mp42(vbp_context *pcontext)
{
viddec_pm_cxt_t *cxt = pcontext->parser_cxt;
uint8 *buf = NULL;
uint32 size = 0;
uint32 sc_end_pos = -1;
uint32 bytes_parsed = 0;
viddec_mp4_parser_t *pinfo = NULL;
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
// reset query data for the new sample buffer
query_data->number_picture_data= 0;
query_data->number_pictures = 0;
// emulation prevention byte is always present
cxt->getbits.is_emul_reqd = 1;
cxt->list.num_items = 0;
cxt->list.data[0].stpos = 0;
cxt->list.data[0].edpos = cxt->parse_cubby.size;
buf = cxt->parse_cubby.buf;
size = cxt->parse_cubby.size;
pinfo = (viddec_mp4_parser_t *) &(cxt->codec_data[0]);
uint8 is_normal_sc = 0;
uint8 resync_marker = 0;
uint32 found_sc = 0;
uint32 ret = VBP_OK;
while (1)
{
found_sc = vbp_get_sc_pos_mp42(buf + bytes_parsed, size- bytes_parsed,
&sc_end_pos, &is_normal_sc, &resync_marker);
VTRACE("buf=%x, bytes_parsed=%d, unparsed=%d", (uint32)buf, bytes_parsed, size- bytes_parsed);
VTRACE("found_sc=%d, cxt->list.num_items=%d, resync_marker=%d, ",
found_sc, cxt->list.num_items, resync_marker);
if (found_sc)
{
cxt->list.data[cxt->list.num_items].stpos = bytes_parsed
+ sc_end_pos - 3;
if (cxt->list.num_items != 0)
{
cxt->list.data[cxt->list.num_items - 1].edpos = bytes_parsed
+ sc_end_pos - 3;
}
bytes_parsed += sc_end_pos;
cxt->list.num_items++;
pinfo->cur_sc_prefix = is_normal_sc;
}
else
{
if (cxt->list.num_items != 0)
{
cxt->list.data[cxt->list.num_items - 1].edpos
= cxt->parse_cubby.size;
break;
}
else
{
WTRACE ("No start-code is found in cubby buffer! The size of cubby is %d\n", size);
cxt->list.num_items = 1;
cxt->list.data[0].stpos = 0;
cxt->list.data[0].edpos = cxt->parse_cubby.size;
if (resync_marker)
{
// either the first slice (GOB) is lost or parser receives a single slice (GOB)
if (short_video_header)
{
// TODO: revisit if HW supportd GOB layer decoding for h.263
WTRACE("Partial frame: GOB buffer.\n");
ret = VBP_PARTIAL;
}
else
{
WTRACE("Partial frame: video packet header buffer.\n");
ret = vbp_process_video_packet_mp42(pcontext);
}
// set num_items to 0 so buffer will not be parsed again
cxt->list.num_items = 0;
}
else
{
ETRACE("Invalid data received.\n");
cxt->list.num_items = 0;
return VBP_DATA;
}
break;
}
}
}
return ret;
}
uint32 vbp_populate_query_data_mp42(vbp_context *pcontext)
{
#if 0
vbp_dump_query_data(pcontext);
#endif
return VBP_OK;
}
vbp_picture_data_mp42* vbp_get_mp42_picture_data(vbp_data_mp42 * query_data)
{
vbp_picture_data_mp42 *picture_data = query_data->picture_data;
int num_pictures = query_data->number_picture_data;
while (num_pictures > 1)
{
picture_data = picture_data->next_picture_data;
num_pictures--;
}
return picture_data;
}
void vbp_fill_codec_data(vbp_context *pcontext)
{
viddec_mp4_parser_t *parser =
(viddec_mp4_parser_t *) &(pcontext->parser_cxt->codec_data[0]);
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
vbp_codec_data_mp42* codec_data = &(query_data->codec_data);
codec_data->profile_and_level_indication
= parser->info.profile_and_level_indication;
codec_data->video_object_layer_width =
parser->info.VisualObject.VideoObject.video_object_layer_width;
codec_data->video_object_layer_height =
parser->info.VisualObject.VideoObject.video_object_layer_height;
if (parser->info.VisualObject.VideoSignalType.is_video_signal_type)
{
codec_data->video_format =
parser->info.VisualObject.VideoSignalType.video_format;
}
else
{
// Unspecified video format
codec_data->video_format = 5;
}
codec_data->video_range =
parser->info.VisualObject.VideoSignalType.video_range;
if (parser->info.VisualObject.VideoSignalType.is_colour_description)
{
codec_data->matrix_coefficients =
parser->info.VisualObject.VideoSignalType.matrix_coefficients;
}
else if (short_video_header)
{
// SMPTE 170M
codec_data->matrix_coefficients = 6;
}
else
{
// ITU-R Recommendation BT.709
codec_data->matrix_coefficients = 1;
}
codec_data->short_video_header = short_video_header;
// aspect ratio
codec_data->aspect_ratio_info = parser->info.VisualObject.VideoObject.aspect_ratio_info;
if (codec_data->aspect_ratio_info < 6)
{
codec_data->par_width = mp4_aspect_ratio_table[codec_data->aspect_ratio_info][0];
codec_data->par_height = mp4_aspect_ratio_table[codec_data->aspect_ratio_info][1];
}
else if (codec_data->aspect_ratio_info == 15)
{
codec_data->par_width = parser->info.VisualObject.VideoObject.aspect_ratio_info_par_width;
codec_data->par_height = parser->info.VisualObject.VideoObject.aspect_ratio_info_par_height;
}
else
{
codec_data->par_width = 0;
codec_data->par_height = 0;
}
}
void vbp_fill_slice_data(vbp_context *pcontext, int list_index)
{
viddec_mp4_parser_t *parser =
(viddec_mp4_parser_t *) &(pcontext->parser_cxt->codec_data[0]);
if (!parser->info.VisualObject.VideoObject.short_video_header)
{
vbp_process_slices_mp42(pcontext, list_index);
}
else
{
vbp_process_slices_svh_mp42(pcontext, list_index);
}
}
void vbp_fill_picture_param(vbp_context *pcontext, uint8 new_picture_flag)
{
viddec_mp4_parser_t *parser =
(viddec_mp4_parser_t *) &(pcontext->parser_cxt->codec_data[0]);
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
vbp_picture_data_mp42 *picture_data = NULL;
VAPictureParameterBufferMPEG4 *picture_param = NULL;
if (new_picture_flag)
{
query_data->number_pictures++;
}
picture_data = query_data->picture_data;
if (picture_data == NULL || query_data->number_picture_data == 0)
{
// first entry
if (picture_data == NULL)
{
picture_data = (vbp_picture_data_mp42*)g_try_new0(vbp_picture_data_mp42, 1);
query_data->picture_data = picture_data;
}
query_data->number_picture_data = 1;
}
else
{
// find the last active one
int i = query_data->number_picture_data;
while (i > 1)
{
picture_data = picture_data->next_picture_data;
i--;
}
if (picture_data->next_picture_data == NULL)
{
picture_data->next_picture_data = g_try_new0(vbp_picture_data_mp42, 1);
}
query_data->number_picture_data++;
picture_data = picture_data->next_picture_data;
}
picture_param = &(picture_data->picture_param);
uint8 idx = 0;
picture_data->new_picture_flag = new_picture_flag;
picture_data->vop_coded
= parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_coded;
VTRACE ("vop_coded = %d\n", picture_data->vop_coded);
picture_data->vop_time_increment =
parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_time_increment;
// fill picture_param
/*
* NOTE: for short video header, the parser saves vop_width and vop_height
* to VOL->video_object_layer_width and VOL->video_object_layer_height
*/
picture_param->vop_width
= parser->info.VisualObject.VideoObject.video_object_layer_width;
picture_param->vop_height
= parser->info.VisualObject.VideoObject.video_object_layer_height;
picture_param->forward_reference_picture = VA_INVALID_SURFACE;
picture_param->backward_reference_picture = VA_INVALID_SURFACE;
// Fill VAPictureParameterBufferMPEG4::vol_fields
picture_param->vol_fields.bits.short_video_header
= parser->info.VisualObject.VideoObject.short_video_header;
picture_param->vol_fields.bits.chroma_format
= parser->info.VisualObject.VideoObject.VOLControlParameters.chroma_format;
/* TODO: find out why testsuite always set this value to be 0 */
picture_param->vol_fields.bits.chroma_format = 0;
picture_param->vol_fields.bits.interlaced
= parser->info.VisualObject.VideoObject.interlaced;
picture_param->vol_fields.bits.obmc_disable
= parser->info.VisualObject.VideoObject.obmc_disable;
picture_param->vol_fields.bits.sprite_enable
= parser->info.VisualObject.VideoObject.sprite_enable;
picture_param->vol_fields.bits.sprite_warping_accuracy
= parser->info.VisualObject.VideoObject.sprite_info.sprite_warping_accuracy;
picture_param->vol_fields.bits.quant_type
= parser->info.VisualObject.VideoObject.quant_type;
picture_param->vol_fields.bits.quarter_sample
= parser->info.VisualObject.VideoObject.quarter_sample;
picture_param->vol_fields.bits.data_partitioned
= parser->info.VisualObject.VideoObject.data_partitioned;
picture_param->vol_fields.bits.reversible_vlc
= parser->info.VisualObject.VideoObject.reversible_vlc;
picture_param->vol_fields.bits.resync_marker_disable
= parser->info.VisualObject.VideoObject.resync_marker_disable;
picture_param->no_of_sprite_warping_points
= parser->info.VisualObject.VideoObject.sprite_info.no_of_sprite_warping_points;
for (idx = 0; idx < 3; idx++)
{
picture_param->sprite_trajectory_du[idx]
= parser->info.VisualObject.VideoObject.VideoObjectPlane.warping_mv_code_du[idx];
picture_param->sprite_trajectory_dv[idx]
= parser->info.VisualObject.VideoObject.VideoObjectPlane.warping_mv_code_dv[idx];
}
picture_param->quant_precision
= parser->info.VisualObject.VideoObject.quant_precision;
// fill VAPictureParameterBufferMPEG4::vop_fields
if (!parser->info.VisualObject.VideoObject.short_video_header)
{
picture_param->vop_fields.bits.vop_coding_type
= parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_coding_type;
}
else
{
picture_param->vop_fields.bits.vop_coding_type
= parser->info.VisualObject.VideoObject.VideoObjectPlaneH263.picture_coding_type;
}
/*
* TODO:
* fill picture_param->vop_fields.bits.backward_reference_vop_coding_type
* This shall be done in mixvideoformat_mp42. See M42 spec 7.6.7
*/
if (picture_param->vop_fields.bits.vop_coding_type != MP4_VOP_TYPE_B)
{
picture_param->vop_fields.bits.backward_reference_vop_coding_type
= picture_param->vop_fields.bits.vop_coding_type;
}
picture_param->vop_fields.bits.vop_rounding_type
= parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_rounding_type;
picture_param->vop_fields.bits.intra_dc_vlc_thr
= parser->info.VisualObject.VideoObject.VideoObjectPlane.intra_dc_vlc_thr;
picture_param->vop_fields.bits.top_field_first
= parser->info.VisualObject.VideoObject.VideoObjectPlane.top_field_first;
picture_param->vop_fields.bits.alternate_vertical_scan_flag
= parser->info.VisualObject.VideoObject.VideoObjectPlane.alternate_vertical_scan_flag;
picture_param->vop_fcode_forward
= parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_fcode_forward;
picture_param->vop_fcode_backward
= parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_fcode_backward;
picture_param->vop_time_increment_resolution
= parser->info.VisualObject.VideoObject.vop_time_increment_resolution;
// short header related
picture_param->num_gobs_in_vop
= parser->info.VisualObject.VideoObject.VideoObjectPlaneH263.num_gobs_in_vop;
picture_param->num_macroblocks_in_gob
= parser->info.VisualObject.VideoObject.VideoObjectPlaneH263.num_macroblocks_in_gob;
// for direct mode prediction
picture_param->TRB = parser->info.VisualObject.VideoObject.TRB;
picture_param->TRD = parser->info.VisualObject.VideoObject.TRD;
}
void vbp_fill_iq_matrix_buffer(vbp_context *pcontext)
{
viddec_mp4_parser_t *parser =
(viddec_mp4_parser_t *) &(pcontext->parser_cxt->codec_data[0]);
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
mp4_VOLQuant_mat_t *quant_mat_info =
&(parser->info.VisualObject.VideoObject.quant_mat_info);
VAIQMatrixBufferMPEG4 *iq_matrix = NULL;
iq_matrix = &(query_data->iq_matrix_buffer);
iq_matrix->load_intra_quant_mat = quant_mat_info->load_intra_quant_mat;
iq_matrix->load_non_intra_quant_mat
= quant_mat_info->load_nonintra_quant_mat;
memcpy(iq_matrix->intra_quant_mat, quant_mat_info->intra_quant_mat, 64);
memcpy(iq_matrix->non_intra_quant_mat, quant_mat_info->nonintra_quant_mat, 64);
}
void vbp_on_vop_mp42(vbp_context *pcontext, int list_index)
{
vbp_fill_codec_data(pcontext);
vbp_fill_picture_param(pcontext, 1);
vbp_fill_iq_matrix_buffer(pcontext);
vbp_fill_slice_data(pcontext, list_index);
}
void vbp_on_vop_svh_mp42(vbp_context *pcontext, int list_index)
{
vbp_fill_codec_data(pcontext);
vbp_fill_picture_param(pcontext, 1);
vbp_fill_iq_matrix_buffer(pcontext);
vbp_fill_slice_data(pcontext, list_index);
}
uint32 vbp_get_sc_pos_mp42(
uint8 *buf,
uint32 length,
uint32 *sc_end_pos,
uint8 *is_normal_sc,
uint8 *resync_marker)
{
uint8 *ptr = buf;
uint32 size;
uint32 data_left = 0, phase = 0, ret = 0;
size = 0;
data_left = length;
*sc_end_pos = -1;
/* parse until there is more data and start code not found */
while ((data_left > 0) && (phase < 3))
{
/* Check if we are byte aligned & phase=0, if thats the case we can check
work at a time instead of byte*/
if (((((uint32) ptr) & 0x3) == 0) && (phase == 0))
{
while (data_left > 3)
{
uint32 data;
char mask1 = 0, mask2 = 0;
data = *((uint32 *) ptr);
#ifndef MFDBIGENDIAN
data = SWAP_WORD(data);
#endif
mask1 = (FIRST_STARTCODE_BYTE != (data & SC_BYTE_MASK0));
mask2 = (FIRST_STARTCODE_BYTE != (data & SC_BYTE_MASK1));
/* If second byte and fourth byte are not zero's then we cannot have a start code here as we need
two consecutive zero bytes for a start code pattern */
if (mask1 && mask2)
{
/* Success so skip 4 bytes and start over */
ptr += 4;
size += 4;
data_left -= 4;
continue;
}
else
{
break;
}
}
}
/* At this point either data is not on a word boundary or phase > 0 or On a word boundary but we detected
two zero bytes in the word so we look one byte at a time*/
if (data_left > 0)
{
if (*ptr == FIRST_STARTCODE_BYTE)
{
/* Phase can be 3 only if third start code byte is found */
phase++;
ptr++;
size++;
data_left--;
if (phase > 2)
{
phase = 2;
if ((((uint32) ptr) & 0x3) == 0)
{
while (data_left > 3)
{
if (*((uint32 *) ptr) != 0)
{
break;
}
ptr += 4;
size += 4;
data_left -= 4;
}
}
}
}
else
{
uint8 normal_sc = 0, short_sc = 0;
if (phase == 2)
{
normal_sc = (*ptr == THIRD_STARTCODE_BYTE);
short_sc = (SHORT_THIRD_STARTCODE_BYTE == (*ptr & 0xFC));
*is_normal_sc = normal_sc;
// at least 16-bit 0, may be GOB start code or
// resync marker.
*resync_marker = 1;
}
if (!(normal_sc | short_sc))
{
phase = 0;
}
else
{
/* Match for start code so update context with byte position */
*sc_end_pos = size;
phase = 3;
}
ptr++;
size++;
data_left--;
}
}
}
if ((data_left > 0) && (phase == 3))
{
(*sc_end_pos)++;
phase++;
ret = 1;
}
// Return 1 only if phase is 4, else always return 0
return ret;
}
uint32 vbp_macroblock_number_length_mp42(uint32 numOfMbs)
{
uint32 length = 0;
numOfMbs--;
do
{
numOfMbs >>= 1;
length++;
}
while (numOfMbs);
return length;
}
uint32 vbp_parse_video_packet_header_mp42(
void *parent,
viddec_mp4_parser_t *parser_cxt,
uint16_t *quant_scale,
uint32 *macroblock_number)
{
uint32 ret = VBP_DATA;
mp4_Info_t *pInfo = &(parser_cxt->info);
mp4_VideoObjectLayer_t *vidObjLay = &(pInfo->VisualObject.VideoObject);
mp4_VideoObjectPlane_t *vidObjPlane =
&(pInfo->VisualObject.VideoObject.VideoObjectPlane);
uint32 code = 0;
int32_t getbits = 0;
uint16_t _quant_scale = 0;
uint32 _macroblock_number = 0;
uint32 header_extension_codes = 0;
uint8 vop_coding_type = vidObjPlane->vop_coding_type;
if (vidObjLay->video_object_layer_shape != MP4_SHAPE_TYPE_RECTANGULAR)
{
return VBP_DATA;
}
do
{
// get macroblock_number
uint16_t mbs_x = (vidObjLay->video_object_layer_width + 15) >> 4;
uint16_t mbs_y = (vidObjLay->video_object_layer_height + 15) >> 4;
uint32 length = vbp_macroblock_number_length_mp42(mbs_x * mbs_y);
getbits = viddec_pm_get_bits(parent, &code, length);
BREAK_GETBITS_FAIL(getbits, ret);
_macroblock_number = code;
// quant_scale
if (vidObjLay->video_object_layer_shape != MP4_SHAPE_TYPE_BINARYONLY)
{
getbits = viddec_pm_get_bits(parent, &code, vidObjLay->quant_precision);
BREAK_GETBITS_FAIL(getbits, ret);
_quant_scale = code;
}
// header_extension_codes
if (vidObjLay->video_object_layer_shape == MP4_SHAPE_TYPE_RECTANGULAR)
{
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
header_extension_codes = code;
}
if (header_extension_codes)
{
// modulo time base
do
{
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
} while (code);
// marker_bit
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
// vop_time_increment
uint32 numbits = 0;
numbits = vidObjLay->vop_time_increment_resolution_bits;
if (numbits == 0)
{
// ??
numbits = 1;
}
getbits = viddec_pm_get_bits(parent, &code, numbits);
BREAK_GETBITS_FAIL(getbits, ret);
vidObjPlane->vop_time_increment = code;
// marker_bit
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
// vop_coding_type
getbits = viddec_pm_get_bits(parent, &code, 2);
BREAK_GETBITS_FAIL(getbits, ret);
vop_coding_type = code & 0x3;
vidObjPlane->vop_coding_type = vop_coding_type;
if (vidObjLay->video_object_layer_shape != MP4_SHAPE_TYPE_BINARYONLY)
{
// intra_dc_vlc_thr
getbits = viddec_pm_get_bits(parent, &code, 3);
BREAK_GETBITS_FAIL(getbits, ret);
vidObjPlane->intra_dc_vlc_thr = code;
if ((vidObjLay->sprite_enable == MP4_SPRITE_GMC) &&
(vop_coding_type == MP4_VOP_TYPE_S) &&
(vidObjLay->sprite_info.no_of_sprite_warping_points> 0))
{
if (vbp_sprite_trajectory_mp42(parent, vidObjLay,
vidObjPlane) != VBP_OK)
{
break;
}
}
if (vidObjLay->reduced_resolution_vop_enable &&
(vidObjLay->video_object_layer_shape == MP4_SHAPE_TYPE_RECTANGULAR) &&
((vop_coding_type == MP4_VOP_TYPE_I) ||
(vop_coding_type == MP4_VOP_TYPE_P)))
{
// vop_reduced_resolution
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
}
if (vop_coding_type != MP4_VOP_TYPE_I)
{
// vop_fcode_forward
getbits = viddec_pm_get_bits(parent, &code, 3);
BREAK_GETBITS_FAIL(getbits, ret);
vidObjPlane->vop_fcode_forward = code;
}
if (vop_coding_type == MP4_VOP_TYPE_B)
{
// vop_fcode_backward
getbits = viddec_pm_get_bits(parent, &code, 3);
BREAK_GETBITS_FAIL(getbits, ret);
vidObjPlane->vop_fcode_backward = code;
}
}
}
if (vidObjLay->newpred_enable)
{
// New pred mode not supported in HW, but, does libva support this?
ret = VBP_DATA;
break;
}
*quant_scale = _quant_scale;
*macroblock_number = _macroblock_number;
ret = VBP_OK;
}
while (0);
return ret;
}
uint32 vbp_resync_marker_Length_mp42(viddec_mp4_parser_t *parser_cxt)
{
mp4_Info_t *pInfo = &(parser_cxt->info);
mp4_VideoObjectPlane_t *vidObjPlane =
&(pInfo->VisualObject.VideoObject.VideoObjectPlane);
uint32 resync_marker_length = 0;
if (vidObjPlane->vop_coding_type == MP4_VOP_TYPE_I)
{
resync_marker_length = 17;
}
else if (vidObjPlane->vop_coding_type == MP4_VOP_TYPE_B)
{
uint8 fcode_max = vidObjPlane->vop_fcode_forward;
if (fcode_max < vidObjPlane->vop_fcode_backward)
{
fcode_max = vidObjPlane->vop_fcode_backward;
}
resync_marker_length = 16 + fcode_max;
// resync_marker is max(15+fcode,17) zeros followed by a one
if (resync_marker_length < 18)
resync_marker_length = 18;
}
else
{
resync_marker_length = 16 + vidObjPlane->vop_fcode_forward;
}
return resync_marker_length;
}
uint32 vbp_process_slices_svh_mp42(vbp_context *pcontext, int list_index)
{
uint32 ret = VBP_OK;
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
viddec_pm_cxt_t *parent = pcontext->parser_cxt;
viddec_mp4_parser_t *parser_cxt =
(viddec_mp4_parser_t *) &(parent->codec_data[0]);
vbp_picture_data_mp42 *picture_data = vbp_get_mp42_picture_data(query_data);
vbp_slice_data_mp42 *slice_data = &(picture_data->slice_data);
VASliceParameterBufferMPEG4* slice_param = &(slice_data->slice_param);
uint8 is_emul = 0;
uint32 bit_offset = 0;
uint32 byte_offset = 0;
// The offsets are relative to parent->parse_cubby.buf
viddec_pm_get_au_pos(parent, &bit_offset, &byte_offset, &is_emul);
slice_data->buffer_addr = parent->parse_cubby.buf;
slice_data->slice_offset = byte_offset
+ parent->list.data[list_index].stpos;
slice_data->slice_size = parent->list.data[list_index].edpos
- parent->list.data[list_index].stpos - byte_offset;
slice_param->slice_data_size = slice_data->slice_size;
slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
slice_param->slice_data_offset = 0;
slice_param->macroblock_offset = bit_offset;
slice_param->macroblock_number = 0;
slice_param->quant_scale
= parser_cxt->info.VisualObject.VideoObject.VideoObjectPlaneH263.vop_quant;
return ret;
}
uint32 vbp_process_slices_mp42(vbp_context *pcontext, int list_index)
{
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
viddec_pm_cxt_t *parent = pcontext->parser_cxt;
viddec_mp4_parser_t *parser_cxt = (viddec_mp4_parser_t *) &(parent->codec_data[0]);
vbp_picture_data_mp42 *picture_data = NULL;
vbp_slice_data_mp42 *slice_data = NULL;
VASliceParameterBufferMPEG4* slice_param = NULL;
uint32 ret = VBP_OK;
uint8 is_emul = 0;
uint32 bit_offset = 0;
uint32 byte_offset = 0;
uint32 code = 0;
int32_t getbits = 0;
uint32 resync_marker_length = 0;
#ifdef VBP_TRACE
uint32 list_size_at_index = parent->list.data[list_index].edpos
- parent->list.data[list_index].stpos;
VTRACE ("list_index = %d list_size_at_index = %d\n", list_index,
list_size_at_index);
VTRACE ("list_index = %d edpos = %d stpos = %d\n", list_index,
parent->list.data[list_index].edpos,
parent->list.data[list_index].stpos);
#endif
/* The offsets are relative to parent->parse_cubby.buf */
viddec_pm_get_au_pos(parent, &bit_offset, &byte_offset, &is_emul);
#if 0
if (is_emul) {
g_print("*** emul != 0\n");
/*byte_offset += 1;*/
}
#endif
picture_data = vbp_get_mp42_picture_data(query_data);
slice_data = &(picture_data->slice_data);
slice_param = &(slice_data->slice_param);
slice_data->buffer_addr = parent->parse_cubby.buf;
slice_data->slice_offset = byte_offset
+ parent->list.data[list_index].stpos;
slice_data->slice_size = parent->list.data[list_index].edpos
- parent->list.data[list_index].stpos - byte_offset;
slice_param->slice_data_size = slice_data->slice_size;
slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
slice_param->slice_data_offset = 0;
slice_param->macroblock_offset = bit_offset;
slice_param->macroblock_number = 0;
slice_param->quant_scale
= parser_cxt->info.VisualObject.VideoObject.VideoObjectPlane.vop_quant;
if (parser_cxt->info.VisualObject.VideoObject.resync_marker_disable)
{
// no resync_marker
return VBP_OK;
}
// scan for resync_marker
viddec_pm_get_au_pos(parent, &bit_offset, &byte_offset, &is_emul);
if (bit_offset)
{
// byte-aligned
getbits = viddec_pm_get_bits(parent, &code, 8 - bit_offset);
if (getbits == -1)
{
return VBP_DATA;
}
}
// get resync_marker_length
resync_marker_length = vbp_resync_marker_Length_mp42(parser_cxt);
uint16_t quant_scale = 0;
uint32 macroblock_number = 0;
while (1)
{
getbits = viddec_pm_peek_bits(parent, &code, resync_marker_length);
// return VBP_OK as resync_marker may not be present
BREAK_GETBITS_FAIL(getbits, ret);
if (code != 1)
{
getbits = viddec_pm_get_bits(parent, &code, 8);
BREAK_GETBITS_FAIL(getbits, ret);
continue;
}
// We found resync_marker
viddec_pm_get_au_pos(parent, &bit_offset, &byte_offset, &is_emul);
// update slice data as we found resync_marker
slice_data->slice_size -= (parent->list.data[list_index].edpos
- parent->list.data[list_index].stpos - byte_offset);
slice_param->slice_data_size = slice_data->slice_size;
// skip resync marker
getbits = viddec_pm_get_bits(parent, &code, resync_marker_length);
// return VBP_DATA, this should never happen!
BREAK_GETBITS_FAIL(getbits, ret);
// parse video_packet_header
ret = vbp_parse_video_packet_header_mp42(parent, parser_cxt,
&quant_scale, &macroblock_number);
if (ret != VBP_OK)
{
ETRACE("Failed to parse video packet header.\n");
return ret;
}
// new_picture_flag = 0, this is not the first slice of a picture
vbp_fill_picture_param(pcontext, 0);
picture_data = vbp_get_mp42_picture_data(query_data);
slice_data = &(picture_data->slice_data);
slice_param = &(slice_data->slice_param);
viddec_pm_get_au_pos(parent, &bit_offset, &byte_offset, &is_emul);
slice_data->buffer_addr = parent->parse_cubby.buf;
slice_data->slice_offset = byte_offset
+ parent->list.data[list_index].stpos;
slice_data->slice_size = parent->list.data[list_index].edpos
- parent->list.data[list_index].stpos - byte_offset;
slice_param->slice_data_size = slice_data->slice_size;
slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
slice_param->slice_data_offset = 0;
slice_param->macroblock_offset = bit_offset;
slice_param->macroblock_number = macroblock_number;
slice_param->quant_scale = quant_scale;
if (bit_offset)
{
// byte-align parsing position
getbits = viddec_pm_get_bits(parent, &code, 8 - bit_offset);
if (getbits == -1)
{
ETRACE("Failed to align parser to byte position.\n");
return VBP_DATA;
}
}
}
return VBP_OK;
}
uint32 vbp_process_video_packet_mp42(vbp_context *pcontext)
{
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
viddec_pm_cxt_t *parent = pcontext->parser_cxt;
viddec_mp4_parser_t *parser_cxt = (viddec_mp4_parser_t *) &(parent->codec_data[0]);
uint32 code = 0;
int32_t getbits = 0;
uint32 ret = VBP_DATA;
// setup bitstream parser
parent->getbits.list = &(parent->list);
parent->getbits.bstrm_buf.buf = parent->parse_cubby.buf;
parent->getbits.bstrm_buf.buf_index = 0;
parent->getbits.bstrm_buf.buf_st = 0;
parent->getbits.bstrm_buf.buf_end = parent->parse_cubby.size;
parent->getbits.bstrm_buf.buf_bitoff = 0;
parent->getbits.au_pos = 0;
parent->getbits.list_off = 0;
parent->getbits.phase = 0;
parent->getbits.emulation_byte_counter = 0;
parent->list.start_offset = 0;
parent->list.end_offset = parent->parse_cubby.size;
parent->list.total_bytes = parent->parse_cubby.size;
// skip leading zero-byte
while (code == 0)
{
getbits = viddec_pm_get_bits(parent, &code, 8);
BREAK_GETBITS_FAIL(getbits, ret);
getbits = viddec_pm_peek_bits(parent, &code, 8);
BREAK_GETBITS_FAIL(getbits, ret);
}
if (getbits != 0)
{
return VBP_DATA;
}
// resync-marker is represented as 17-23 bits. (16-22 bits of 0)
// as 16-bit '0' has been skipped, we try to parse buffer bit by bit
// until bit 1 is encounted or up to 7 bits are parsed.
code = 0;
uint8 count = 0;
while (code == 0 && count < 7)
{
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
count++;
}
if (code == 0 || getbits != 0)
{
ETRACE("no resync-marker in the buffer.\n");
return ret;
}
// resync marker is skipped
uint16_t quant_scale = 0;
uint32 macroblock_number = 0;
// parse video_packet_header
vbp_parse_video_packet_header_mp42(parent, parser_cxt,
&quant_scale, &macroblock_number);
// new_picture_flag = 0, this is not the first slice of a picture
vbp_fill_picture_param(pcontext, 0);
vbp_picture_data_mp42 *picture_data = NULL;
vbp_slice_data_mp42 *slice_data = NULL;
VASliceParameterBufferMPEG4* slice_param = NULL;
picture_data = vbp_get_mp42_picture_data(query_data);
slice_data = &(picture_data->slice_data);
slice_param = &(slice_data->slice_param);
ret = vbp_process_slices_mp42(pcontext, 0);
// update slice's QP and macro_block number as it is set to 0 by default.
slice_param->macroblock_number = macroblock_number;
slice_param->quant_scale = quant_scale;
// VOP must be coded!
picture_data->vop_coded = 1;
return ret;
}
static inline uint32 vbp_sprite_dmv_length_mp42(
void * parent,
int32_t *dmv_length)
{
uint32 code, skip;
int32_t getbits = 0;
uint32 ret = VBP_DATA;
*dmv_length = 0;
skip = 3;
do
{
getbits = viddec_pm_peek_bits(parent, &code, skip);
BREAK_GETBITS_FAIL(getbits, ret);
if (code == 7)
{
viddec_pm_skip_bits(parent, skip);
getbits = viddec_pm_peek_bits(parent, &code, 9);
BREAK_GETBITS_FAIL(getbits, ret);
skip = 1;
while ((code & 256) != 0)
{
// count number of 1 bits
code <<= 1;
skip++;
}
*dmv_length = 5 + skip;
}
else
{
skip = (code <= 1) ? 2 : 3;
*dmv_length = code - 1;
}
viddec_pm_skip_bits(parent, skip);
ret = VBP_OK;
}
while (0);
return ret;
}
static inline uint32 vbp_sprite_trajectory_mp42(
void *parent,
mp4_VideoObjectLayer_t *vidObjLay,
mp4_VideoObjectPlane_t *vidObjPlane)
{
uint32 code, i;
int32_t dmv_length = 0, dmv_code = 0, getbits = 0;
uint32 ret = VBP_OK;
for (i = 0; i < (uint32) vidObjLay->sprite_info.no_of_sprite_warping_points; i++)
{
ret = VBP_DATA;
ret = vbp_sprite_dmv_length_mp42(parent, &dmv_length);
if (ret != VBP_OK)
{
break;
}
if (dmv_length <= 0)
{
dmv_code = 0;
}
else
{
getbits = viddec_pm_get_bits(parent, &code, (uint32) dmv_length);
BREAK_GETBITS_FAIL(getbits, ret);
dmv_code = (int32_t) code;
if ((dmv_code & (1 << (dmv_length - 1))) == 0)
{
dmv_code -= (1 << dmv_length) - 1;
}
}
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
if (code != 1)
{
ret = VBP_DATA;
break;
}
vidObjPlane->warping_mv_code_du[i] = dmv_code;
// TODO: create another inline function to avoid code duplication
ret = vbp_sprite_dmv_length_mp42(parent, &dmv_length);
if (ret != VBP_OK)
{
break;
}
// reset return value in case early break
ret = VBP_DATA;
if (dmv_length <= 0)
{
dmv_code = 0;
}
else
{
getbits = viddec_pm_get_bits(parent, &code, (uint32) dmv_length);
BREAK_GETBITS_FAIL(getbits, ret);
dmv_code = (int32_t) code;
if ((dmv_code & (1 << (dmv_length - 1))) == 0)
{
dmv_code -= (1 << dmv_length) - 1;
}
}
getbits = viddec_pm_get_bits(parent, &code, 1);
BREAK_GETBITS_FAIL(getbits, ret);
if (code != 1)
{
break;
}
vidObjPlane->warping_mv_code_dv[i] = dmv_code;
// set to VBP_OK
ret = VBP_OK;
}
return ret;
}
/*
* free memory of vbp_data_mp42 structure and its members
*/
uint32 vbp_free_query_data_mp42(vbp_context *pcontext)
{
vbp_data_mp42 *query_data = (vbp_data_mp42 *) pcontext->query_data;
vbp_picture_data_mp42* current = NULL;
vbp_picture_data_mp42* next = NULL;
if (query_data)
{
current = query_data->picture_data;
while (current != NULL)
{
next = current->next_picture_data;
g_free(current);
current = next;
}
g_free(query_data);
}
pcontext->query_data = NULL;
return VBP_OK;
}
/*
* Allocate memory for vbp_data_mp42 structure and all its members.
*/
uint32 vbp_allocate_query_data_mp42(vbp_context *pcontext)
{
vbp_data_mp42 *query_data;
pcontext->query_data = NULL;
query_data = g_try_new0(vbp_data_mp42, 1);
if (query_data == NULL)
{
goto cleanup;
}
pcontext->query_data = (void *) query_data;
query_data->picture_data = NULL;
query_data->number_picture_data = 0;
query_data->number_pictures = 0;
return VBP_OK;
cleanup:
vbp_free_query_data_mp42(pcontext);
return VBP_MEM;
}