blob: dfa536bd17f5c18c4845c8867038e0daacd37a46 [file] [log] [blame]
/* INTEL CONFIDENTIAL
* Copyright (c) 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 <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"
typedef struct vbp_mp42_parser_private_t vbp_mp42_parser_private;
struct vbp_mp42_parser_private_t
{
bool short_video_header;
};
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,
const bool svh_search);
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;
}
#ifdef VBP
pcontext->parser_ops->parse_sc = NULL;
#else
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;
}
#endif
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;
}
#ifdef VBP
pcontext->parser_ops->is_wkld_done = NULL;
#else
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;
}
#endif
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]);
vbp_mp42_parser_private *parser_private = (vbp_mp42_parser_private *)pcontext->parser_private;
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");
parser_private->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;
vbp_mp42_parser_private *parser_private = (vbp_mp42_parser_private *)pcontext->parser_private;
// reset query data for the new sample buffer
query_data->number_picture_data= 0;
query_data->number_pictures = 0;
// emulation prevention byte is not needed
cxt->getbits.is_emul_reqd = 0;
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,
parser_private->short_video_header);
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 (parser_private->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);
vbp_mp42_parser_private *parser_private = (vbp_mp42_parser_private *)pcontext->parser_private;
codec_data->bit_rate = parser->info.VisualObject.VideoObject.VOLControlParameters.bit_rate;
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 (parser_private->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 = parser_private->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_malloc_set0(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 = vbp_malloc_set0(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;
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 = 1; //quant_mat_info->load_intra_quant_mat;
iq_matrix->load_non_intra_quant_mat = 1; // = 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,
const bool svh_search)
{
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);
if (svh_search)
{
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;
/* The offsets are relative to parent->parse_cubby.buf */
viddec_pm_get_au_pos(parent, &bit_offset, &byte_offset, &is_emul);
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 (pcontext->parser_private)
{
free(pcontext->parser_private);
pcontext->parser_private = NULL;
}
if (query_data)
{
current = query_data->picture_data;
while (current != NULL)
{
next = current->next_picture_data;
free(current);
current = next;
}
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 = vbp_malloc_set0(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;
pcontext->parser_private = NULL;
vbp_mp42_parser_private *parser_private = NULL;
parser_private = vbp_malloc_set0(vbp_mp42_parser_private, 1);
if (NULL == parser_private)
{
goto cleanup;
}
/* assign the pointer */
pcontext->parser_private = (void *)parser_private;
/* init the pointer */
parser_private->short_video_header = TRUE;
return VBP_OK;
cleanup:
vbp_free_query_data_mp42(pcontext);
return VBP_MEM;
}