blob: 4a53b8b6595ab626a2fd851e93b49b84a146f780 [file] [log] [blame]
#include "viddec_fw_workload.h"
#include "viddec_parser_ops.h"
#include "viddec_fw_mp4.h"
#include "viddec_mp4_parse.h"
#ifdef ANDROID
#include "viddec_types.h"
#endif
uint32_t viddec_fw_mp4_populate_attr(viddec_workload_t *wl, viddec_mp4_parser_t *parser)
{
uint32_t result = MP4_STATUS_OK;
viddec_frame_attributes_t *attr = &(wl->attrs);
mp4_VideoObjectLayer_t *vol = &(parser->info.VisualObject.VideoObject);
memset(attr, 0, sizeof(viddec_frame_attributes_t));
attr->cont_size.width = vol->video_object_layer_width;
attr->cont_size.height = vol->video_object_layer_height;
// Translate vop_coding_type
switch(vol->VideoObjectPlane.vop_coding_type)
{
case MP4_VOP_TYPE_B:
attr->frame_type = VIDDEC_FRAME_TYPE_B;
break;
case MP4_VOP_TYPE_P:
attr->frame_type = VIDDEC_FRAME_TYPE_P;
break;
case MP4_VOP_TYPE_S:
attr->frame_type = VIDDEC_FRAME_TYPE_S;
break;
case MP4_VOP_TYPE_I:
attr->frame_type = VIDDEC_FRAME_TYPE_I;
break;
default:
break;
} // switch on vop_coding_type
attr->mpeg4.top_field_first = vol->VideoObjectPlane.top_field_first;
return result;
} // viddec_fw_mp4_populate_attr
uint32_t viddec_fw_mp4_insert_vol_workitem(void *parent, viddec_mp4_parser_t *parser)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
viddec_fw_mp4_vol_info_t vol_info;
mp4_VideoObjectLayer_t *vol = &(parser->info.VisualObject.VideoObject);
memset(&vol_info, 0, sizeof(viddec_fw_mp4_vol_info_t));
// Get vol_flags
viddec_fw_mp4_set_reversible_vlc(&vol_info, vol->reversible_vlc);
viddec_fw_mp4_set_data_partitioned(&vol_info, vol->data_partitioned);
viddec_fw_mp4_set_resync_marker_disable(&vol_info, vol->resync_marker_disable);
viddec_fw_mp4_set_quarter_sample(&vol_info, vol->quarter_sample);
viddec_fw_mp4_set_obmc_disable(&vol_info, vol->obmc_disable);
viddec_fw_mp4_set_interlaced(&vol_info, vol->interlaced);
viddec_fw_mp4_set_vol_shape(&vol_info, vol->video_object_layer_shape);
viddec_fw_mp4_set_short_video_header_flag(&vol_info, vol->short_video_header);
// Get vol_size
viddec_fw_mp4_set_vol_width(&vol_info, vol->video_object_layer_width);
viddec_fw_mp4_set_vol_height(&vol_info, vol->video_object_layer_height);
// Get vol_item
viddec_fw_mp4_set_quant_type(&vol_info, vol->quant_type);
viddec_fw_mp4_set_quant_precision(&vol_info, vol->quant_precision);
viddec_fw_mp4_set_sprite_warping_accuracy(&vol_info, vol->sprite_info.sprite_warping_accuracy);
viddec_fw_mp4_set_sprite_warping_points(&vol_info, vol->sprite_info.no_of_sprite_warping_points);
viddec_fw_mp4_set_sprite_enable(&vol_info, vol->sprite_enable);
viddec_fw_mp4_set_vop_time_increment_resolution(&vol_info, vol->vop_time_increment_resolution);
wi.vwi_type = VIDDEC_WORKLOAD_MP4_VOL_INFO;
wi.vwi_payload[0] = vol_info.vol_flags;
wi.vwi_payload[1] = vol_info.vol_size;
wi.vwi_payload[2] = vol_info.vol_item;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_vol_workitem
uint32_t viddec_fw_mp4_insert_vop_workitem(void *parent, viddec_mp4_parser_t *parser)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
viddec_fw_mp4_vop_info_t vop_info;
mp4_VideoObjectPlane_t *vop = &(parser->info.VisualObject.VideoObject.VideoObjectPlane);
uint32_t byte = 0;
unsigned char is_emul;
memset(&vop_info, 0, sizeof(viddec_fw_mp4_vop_info_t));
// Get frame_info
viddec_fw_mp4_set_past_field_frame(&vop_info, parser->ref_frame[VIDDEC_MP4_INDX_2].is_field);
viddec_fw_mp4_set_past_frame_id(&vop_info, VIDDEC_MP4_FRAME_PAST);
viddec_fw_mp4_set_future_field_frame(&vop_info, parser->ref_frame[VIDDEC_MP4_INDX_1].is_field);
viddec_fw_mp4_set_future_frame_id(&vop_info, VIDDEC_MP4_FRAME_FUTURE);
viddec_fw_mp4_set_current_field_frame(&vop_info, parser->ref_frame[VIDDEC_MP4_INDX_0].is_field);
viddec_fw_mp4_set_current_frame_id(&vop_info, VIDDEC_MP4_FRAME_CURRENT);
// HW has a limitation that the enums for PAST(1), FUTURE(2) and CURRENT(0) cannot be changed and
// the spec does not support field pictures. Hence the field_frame bits are always zero.
// This gives us the constant 0x10200.
vop_info.frame_info = 0x10200;
// Get vop_data
// Quant scale is in the video_packet_header or the gob_layer - both of which are parsed by the BSP
viddec_fw_mp4_set_vop_quant_scale(&vop_info, 0);
viddec_fw_mp4_set_vop_fcode_backward(&vop_info, vop->vop_fcode_backward);
viddec_fw_mp4_set_vop_fcode_forward(&vop_info, vop->vop_fcode_forward);
viddec_fw_mp4_set_vop_quant(&vop_info, vop->vop_quant);
viddec_fw_mp4_set_alternate_vertical_scan_flag(&vop_info, vop->alternate_vertical_scan_flag);
viddec_fw_mp4_set_top_field_first(&vop_info, vop->top_field_first);
viddec_fw_mp4_set_intra_dc_vlc_thr(&vop_info, vop->intra_dc_vlc_thr);
viddec_fw_mp4_set_vop_rounding_type(&vop_info, vop->vop_rounding_type);
viddec_fw_mp4_set_vop_coding_type(&vop_info, vop->vop_coding_type);
// Get vol_item
result = viddec_pm_get_au_pos(parent, &vop_info.bit_offset, &byte, &is_emul);
wi.vwi_type = VIDDEC_WORKLOAD_MP4_VOP_INFO;
wi.vwi_payload[0] = vop_info.frame_info;
wi.vwi_payload[1] = vop_info.vop_data;
wi.vwi_payload[2] = vop_info.bit_offset;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_vop_workitem
uint32_t viddec_fw_mp4_insert_vpsh_workitem(void *parent, viddec_mp4_parser_t *parser)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
viddec_fw_mp4_svh_t svh_info;
mp4_VideoObjectPlaneH263 *svh = &(parser->info.VisualObject.VideoObject.VideoObjectPlaneH263);
memset(&svh_info, 0, sizeof(viddec_fw_mp4_svh_t));
// Get svh_data
viddec_fw_mp4_set_temporal_reference(&svh_info, svh->temporal_reference);
viddec_fw_mp4_set_num_macroblocks_in_gob(&svh_info, svh->num_macroblocks_in_gob);
viddec_fw_mp4_set_num_gobs_in_vop(&svh_info, svh->num_gobs_in_vop);
viddec_fw_mp4_set_num_rows_in_gob(&svh_info, svh->num_rows_in_gob);
wi.vwi_type = VIDDEC_WORKLOAD_MP4_SVH;
wi.vwi_payload[0] = svh_info.svh_data;
wi.vwi_payload[1] = svh_info.pad1;
wi.vwi_payload[2] = svh_info.pad2;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_vpsh_workitem
uint32_t viddec_fw_mp4_insert_sprite_workitem(void *parent, viddec_mp4_parser_t *parser)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
viddec_fw_mp4_sprite_trajectory_t sprite_info;
mp4_VideoObjectLayer_t *vol = &(parser->info.VisualObject.VideoObject);
mp4_VideoObjectPlane_t *vop = &(parser->info.VisualObject.VideoObject.VideoObjectPlane);
uint8_t no_of_entries_per_item = 3;
uint8_t no_of_sprite_workitems = 0;
uint8_t warp_index = 0;
int i, j;
if(!vol->sprite_info.no_of_sprite_warping_points)
return result;
no_of_sprite_workitems = (vol->sprite_info.no_of_sprite_warping_points > 3) ? 2 : 1;
for(i=0; i<no_of_sprite_workitems; i++)
{
memset(&sprite_info, 0, sizeof(viddec_fw_mp4_sprite_trajectory_t));
for(j=0; j<no_of_entries_per_item; j++)
{
if(warp_index < vol->sprite_info.no_of_sprite_warping_points)
{
viddec_fw_mp4_set_warping_point_index(sprite_info.warping_mv_code[j], warp_index);
viddec_fw_mp4_set_warping_mv_code_du(sprite_info.warping_mv_code[j], vop->warping_mv_code_du[warp_index]);
viddec_fw_mp4_set_warping_mv_code_dv(sprite_info.warping_mv_code[j], vop->warping_mv_code_dv[warp_index]);
}
else
{
sprite_info.warping_mv_code[j] = 0xF << 28;
}
warp_index++;
}
wi.vwi_type = VIDDEC_WORKLOAD_MP4_SPRT_TRAJ;
wi.vwi_payload[0] = sprite_info.warping_mv_code[0];
wi.vwi_payload[1] = sprite_info.warping_mv_code[1];
wi.vwi_payload[2] = sprite_info.warping_mv_code[2];
result = viddec_pm_append_workitem(parent, &wi, false);
}
return result;
} // viddec_fw_mp4_insert_sprite_workitem
uint32_t viddec_fw_mp4_insert_bvop_workitem(void *parent, viddec_mp4_parser_t *parser)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
mp4_VideoObjectLayer_t *vol = &(parser->info.VisualObject.VideoObject);
wi.vwi_type = VIDDEC_WORKLOAD_MP4_BVOP_INFO;
wi.vwi_payload[0] = vol->Tframe;
wi.vwi_payload[1] = vol->TRD;
wi.vwi_payload[2] = vol->TRB;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_bvop_workitem
uint32_t viddec_fw_mp4_insert_qmat(void *parent, uint8_t intra_quant_flag, uint32_t *qmat)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
uint8_t i;
// No of items = (64/4 Dwords / 3 entries per workload item)
// 64 8b entries => 64 * 8 / 32 DWORDS => 64/4 DWORDS => 16 DWORDS
// Each item can store 3 DWORDS, 16 DWORDS => 16/3 items => 6 items
for(i=0; i<6; i++)
{
memset(&wi, 0, sizeof(viddec_workload_item_t));
if(intra_quant_flag)
wi.vwi_type = VIDDEC_WORKLOAD_MP4_IQUANT;
else
wi.vwi_type = VIDDEC_WORKLOAD_MP4_NIQUANT;
if(i == 6)
{
wi.vwi_payload[0] = qmat[0];
wi.vwi_payload[1] = 0;
wi.vwi_payload[2] = 0;
}
else
{
wi.vwi_payload[0] = qmat[0];
wi.vwi_payload[1] = qmat[1];
wi.vwi_payload[2] = qmat[2];
}
qmat += 3;
result = viddec_pm_append_workitem(parent, &wi, false);
}
return result;
} // viddec_fw_mp4_insert_qmat
uint32_t viddec_fw_mp4_insert_inversequant_workitem(void *parent, mp4_VOLQuant_mat_t *qmat)
{
uint32_t result = MP4_STATUS_OK;
if(qmat->load_intra_quant_mat)
{
result = viddec_fw_mp4_insert_qmat(parent, true, (uint32_t *) &(qmat->intra_quant_mat));
}
if(qmat->load_nonintra_quant_mat)
{
result = viddec_fw_mp4_insert_qmat(parent, false, (uint32_t *) &(qmat->nonintra_quant_mat));
}
return result;
} // viddec_fw_mp4_insert_inversequant_workitem
uint32_t viddec_fw_mp4_insert_past_frame_workitem(void *parent)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
wi.vwi_type = VIDDEC_WORKLOAD_MP4_PAST_FRAME;
wi.ref_frame.reference_id = 0;
wi.ref_frame.luma_phys_addr = 0;
wi.ref_frame.chroma_phys_addr = 0;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_past_frame_workitem
uint32_t viddec_fw_mp4_insert_future_frame_workitem(void *parent)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
wi.vwi_type = VIDDEC_WORKLOAD_MP4_FUTURE_FRAME;
wi.ref_frame.reference_id = 0;
wi.ref_frame.luma_phys_addr = 0;
wi.ref_frame.chroma_phys_addr = 0;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_future_frame_workitem
uint32_t viddec_fw_mp4_insert_reorder_workitem(void *parent)
{
uint32_t result = MP4_STATUS_OK;
viddec_workload_item_t wi;
// Move frame at location 1 of the reference table to location 0
wi.vwi_type = VIDDEC_WORKLOAD_REFERENCE_FRAME_REORDER;
wi.ref_reorder.ref_table_offset = 0;
wi.ref_reorder.ref_reorder_00010203 = 0x01010203;
wi.ref_reorder.ref_reorder_04050607 = 0x04050607;
result = viddec_pm_append_workitem(parent, &wi, false);
return result;
} // viddec_fw_mp4_insert_reorder_workitem
uint32_t viddec_fw_mp4_emit_workload(void *parent, void *ctxt)
{
uint32_t result = 0;
viddec_mp4_parser_t *parser = (viddec_mp4_parser_t *) ctxt;
viddec_workload_t *wl = viddec_pm_get_header(parent);
result = viddec_fw_mp4_populate_attr(wl, parser);
result = viddec_fw_mp4_insert_vol_workitem(parent, parser);
result = viddec_fw_mp4_insert_vop_workitem(parent, parser);
result = viddec_fw_mp4_insert_sprite_workitem(parent, parser);
result = viddec_fw_mp4_insert_inversequant_workitem(parent, &(parser->info.VisualObject.VideoObject.quant_mat_info));
if(parser->info.VisualObject.VideoObject.short_video_header)
result = viddec_fw_mp4_insert_vpsh_workitem(parent, parser);
if(!parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_coded)
wl->is_reference_frame |= WORKLOAD_SKIPPED_FRAME;
// Send reference re-order tag for all reference frame types
if (parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_coding_type != MP4_VOP_TYPE_B)
{
result = viddec_fw_mp4_insert_reorder_workitem(parent);
}
// Handle vop_coding_type based information
switch(parser->info.VisualObject.VideoObject.VideoObjectPlane.vop_coding_type)
{
case MP4_VOP_TYPE_B:
result = viddec_fw_mp4_insert_bvop_workitem(parent, parser);
result = viddec_fw_mp4_insert_past_frame_workitem(parent);
result = viddec_fw_mp4_insert_future_frame_workitem(parent);
break;
case MP4_VOP_TYPE_P:
case MP4_VOP_TYPE_S:
result = viddec_fw_mp4_insert_past_frame_workitem(parent);
// Deliberate fall-thru to type I
case MP4_VOP_TYPE_I:
wl->is_reference_frame |= WORKLOAD_REFERENCE_FRAME | (1 & WORKLOAD_REFERENCE_FRAME_BMASK);
// Swap reference information
parser->ref_frame[VIDDEC_MP4_INDX_2] = parser->ref_frame[VIDDEC_MP4_INDX_1];
parser->ref_frame[VIDDEC_MP4_INDX_1] = parser->ref_frame[VIDDEC_MP4_INDX_0];
break;
break;
default:
break;
} // switch on vop_coding_type
result = viddec_pm_append_pixeldata(parent);
return result;
} // viddec_fw_mp4_emit_workload