diff options
Diffstat (limited to 'mm-video-v4l2/vidc/common/src/extra_data_handler.cpp')
-rw-r--r-- | mm-video-v4l2/vidc/common/src/extra_data_handler.cpp | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp b/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp new file mode 100644 index 00000000..aa3b563b --- /dev/null +++ b/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp @@ -0,0 +1,510 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of The Linux Foundation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +#include "extra_data_handler.h" + +extra_data_handler::extra_data_handler() +{ + rbsp_buf = (OMX_U8 *) calloc(1,100); + memset(&frame_packing_arrangement,0,sizeof(frame_packing_arrangement)); + frame_packing_arrangement.cancel_flag = 1; + pack_sei = false; + sei_payload_type = -1; +} + +extra_data_handler::~extra_data_handler() +{ + if(rbsp_buf) { + free(rbsp_buf); + rbsp_buf = NULL; + } +} + +OMX_U32 extra_data_handler::d_u(OMX_U32 num_bits) +{ + OMX_U32 rem_bits = num_bits, bins = 0, shift = 0; + + while(rem_bits >= bit_ptr) { + DEBUG_PRINT_LOW("\nIn %s() bit_ptr/byte_ptr :%d/%d/%x", __func__, bit_ptr, + byte_ptr, rbsp_buf[byte_ptr]); + bins <<= shift; + shift = (8-bit_ptr); + bins |= ((rbsp_buf[byte_ptr] << shift) & 0xFF) >> shift; + rem_bits -= bit_ptr; + bit_ptr = 8; + byte_ptr ++; + } + DEBUG_PRINT_LOW("\nIn %s() bit_ptr/byte_ptr :%d/%d/%x", __func__, bit_ptr, + byte_ptr, rbsp_buf[byte_ptr]); + + if (rem_bits) { + bins <<= rem_bits; + bins |= ((rbsp_buf[byte_ptr] << (8-bit_ptr)) & 0xFF) >> (8-rem_bits); + bit_ptr -= rem_bits; + if (bit_ptr == 0) { + bit_ptr = 8; + byte_ptr++; + } + } + DEBUG_PRINT_LOW("\nIn %s() bit_ptr/byte_ptr :%d/%d/%x", __func__, bit_ptr, + byte_ptr, rbsp_buf[byte_ptr]); + + DEBUG_PRINT_LOW("\nIn %s() bin/num_bits : %x/%d", __func__, bins, num_bits); + return bins; +} + +OMX_U32 extra_data_handler::d_ue() +{ + OMX_S32 lead_zeros = -1; + OMX_U32 symbol, bit; + do{ + bit = d_u(1); + lead_zeros++; + }while (!bit); + + symbol = ((1 << lead_zeros) - 1) + d_u(lead_zeros); + + DEBUG_PRINT_LOW("\nIn %s() symbol : %d", __func__,symbol); + return symbol; +} + +OMX_U32 extra_data_handler::parse_frame_pack(OMX_U32 payload_size) +{ + frame_packing_arrangement.id = d_ue(); + frame_packing_arrangement.cancel_flag = d_u(1); + if(!frame_packing_arrangement.cancel_flag) { + frame_packing_arrangement.type = d_u(7); + frame_packing_arrangement.quincunx_sampling_flag = d_u(1); + frame_packing_arrangement.content_interpretation_type = d_u(6); + frame_packing_arrangement.spatial_flipping_flag = d_u(1); + frame_packing_arrangement.frame0_flipped_flag = d_u(1); + frame_packing_arrangement.field_views_flag = d_u(1); + frame_packing_arrangement.current_frame_is_frame0_flag = d_u(1); + frame_packing_arrangement.frame0_self_contained_flag = d_u(1); + frame_packing_arrangement.frame1_self_contained_flag = d_u(1); + + if(!frame_packing_arrangement.quincunx_sampling_flag && + frame_packing_arrangement.type != 5) { + frame_packing_arrangement.frame0_grid_position_x = d_u(4); + frame_packing_arrangement.frame0_grid_position_y = d_u(4); + frame_packing_arrangement.frame1_grid_position_x = d_u(4); + frame_packing_arrangement.frame1_grid_position_y = d_u(4); + } + frame_packing_arrangement.reserved_byte = d_u(8); + frame_packing_arrangement.repetition_period = d_ue(); + } + frame_packing_arrangement.extension_flag = d_u(1); + + return 1; +} + +OMX_S32 extra_data_handler::parse_rbsp(OMX_U8 *buf, OMX_U32 len) +{ + OMX_U32 i = 3, j=0, startcode; + OMX_U32 nal_unit_type, nal_ref_idc, forbidden_zero_bit; + + bit_ptr = 8; + byte_ptr = 0; + + startcode = buf[0] << 16 | buf[1] <<8 | buf[2]; + + if (!startcode) { + startcode |= buf[i++]; + } + if(startcode != H264_START_CODE) { + DEBUG_PRINT_ERROR("\nERROR: In %s() Start code not found", __func__); + return -1; + } + forbidden_zero_bit = (buf[i] & 0x80) >>7; + if(forbidden_zero_bit) { + DEBUG_PRINT_ERROR("\nERROR: In %s() Non-zero forbidden bit", __func__); + return -1; + } + nal_ref_idc = (buf[i] & 0x60) >>5; + DEBUG_PRINT_LOW("\nIn %s() nal_ref_idc ; %d", __func__, nal_ref_idc); + + nal_unit_type = (buf[i++] & 0x1F); + + while(i<len) { + if(!(buf[i] + buf[i+1]) && (buf[i+2] == H264_EMULATION_BYTE) && + (i+2 < len)) { + rbsp_buf[j++] = buf[i++]; + rbsp_buf[j++] = buf[i++]; + i++; + } else + rbsp_buf[j++] = buf[i++]; + } + return nal_unit_type; +} +OMX_S32 extra_data_handler::parse_sei(OMX_U8 *buffer, OMX_U32 buffer_length) +{ + OMX_U32 nal_unit_type, payload_type = 0, payload_size = 0; + OMX_U32 marker = 0, pad = 0xFF; + + nal_unit_type = parse_rbsp(buffer, buffer_length); + + if (nal_unit_type != NAL_TYPE_SEI) { + DEBUG_PRINT_ERROR("\nERROR: In %s() - Non SEI NAL ", __func__); + return -1; + } else { + + while(rbsp_buf[byte_ptr] == 0xFF) + payload_type += rbsp_buf[byte_ptr++]; + payload_type += rbsp_buf[byte_ptr++]; + + DEBUG_PRINT_LOW("\nIn %s() payload_type : %u", __func__, payload_type); + + while(rbsp_buf[byte_ptr] == 0xFF) + payload_size += rbsp_buf[byte_ptr++]; + payload_size += rbsp_buf[byte_ptr++]; + + DEBUG_PRINT_LOW("\nIn %s() payload_size : %u", __func__, payload_size); + + switch(payload_type) { + case SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT: + DEBUG_PRINT_LOW("\nIn %s() Frame Packing SEI ", __func__); + parse_frame_pack(payload_size); + break; + default: + DEBUG_PRINT_LOW("\nINFO: In %s() Not Supported SEI NAL ", __func__); + break; + } + } + if(bit_ptr != 8) { + marker = d_u(1); + if(marker) { + if(bit_ptr != 8) { + pad = d_u(bit_ptr); + if(pad) { + DEBUG_PRINT_ERROR("\nERROR: In %s() padding Bits Error in SEI", + __func__); + return -1; + } + } + } else { + DEBUG_PRINT_ERROR("\nERROR: In %s() Marker Bit Error in SEI", + __func__); + return -1; + } + } + DEBUG_PRINT_LOW("\nIn %s() payload_size : %u/%u", __func__, + payload_size, byte_ptr); + return 1; +} + +OMX_S32 extra_data_handler::parse_ltrinfo( + OMX_BUFFERHEADERTYPE *pBufHdr, OMX_OTHER_EXTRADATATYPE *pExtra) +{ + OMX_U32 *pLTR; + pExtra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataVideoLTRInfo; + pLTR = (OMX_U32* )pExtra + 5; + DEBUG_PRINT_HIGH("ExtraData LTR ID %d", *pLTR, 0, 0); + return 0; +} +/*====================================================================== + Slice Information will be available as below (each line is of 4 bytes) + | number of slices | + | 1st slice offset | + | 1st slice size | + | .. | + | Nth slice offset | + | Nth slice size | +======================================================================*/ +OMX_S32 extra_data_handler::parse_sliceinfo( + OMX_BUFFERHEADERTYPE *pBufHdr, OMX_OTHER_EXTRADATATYPE *pExtra) +{ + OMX_U32 slice_offset = 0, slice_size = 0, total_size = 0; + OMX_U8 *pBuffer = (OMX_U8 *)pBufHdr->pBuffer; + OMX_U32 *data = (OMX_U32 *)pExtra->data; + OMX_U32 num_slices = *data; + DEBUG_PRINT_LOW("number of slices = %d", num_slices); + if ((4 + num_slices * 8) != (OMX_U32)pExtra->nDataSize) { + DEBUG_PRINT_ERROR("unknown error in slice info extradata"); + return -1; + } + for (int i = 0; i < num_slices; i++) { + slice_offset = (OMX_U32)(*(data + (i*2 + 1))); + if ((*(pBuffer + slice_offset + 0) != 0x00) || + (*(pBuffer + slice_offset + 1) != 0x00) || + (*(pBuffer + slice_offset + 2) != 0x00) || + (*(pBuffer + slice_offset + 3) != H264_START_CODE)) { + DEBUG_PRINT_ERROR("found 0x%x instead of start code at offset[%d] " + "for slice[%d]", (OMX_U32)(*(OMX_U32 *)(pBuffer + slice_offset)), + slice_offset, i); + return -1; + } + if (slice_offset != total_size) { + DEBUG_PRINT_ERROR("offset of slice number %d is not correct " + "or previous slice size is not correct", i); + return -1; + } + slice_size = (OMX_U32)(*(data + (i*2 + 2))); + total_size += slice_size; + DEBUG_PRINT_LOW("slice number %d offset/size = %d/%d", + i, slice_offset, slice_size); + } + if (pBufHdr->nFilledLen != total_size) { + DEBUG_PRINT_ERROR("frame_size[%d] is not equal to " + "total slices size[%d]", pBufHdr->nFilledLen, total_size); + return -1; + } + return 0; +} + +OMX_U32 extra_data_handler::parse_extra_data(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + DEBUG_PRINT_LOW("In %s() flags: 0x%x", __func__,buf_hdr->nFlags); + + if (buf_hdr->nFlags & OMX_BUFFERFLAG_EXTRADATA) { + + OMX_OTHER_EXTRADATATYPE *extra_data = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned)(buf_hdr->pBuffer + buf_hdr->nOffset + + buf_hdr->nFilledLen + 3)&(~3)); + + while(extra_data && + ((OMX_U32)extra_data > (OMX_U32)buf_hdr->pBuffer) && + ((OMX_U32)extra_data < (OMX_U32)buf_hdr->pBuffer + buf_hdr->nAllocLen)) { + + DEBUG_PRINT_LOW("extradata(0x%x): nSize = 0x%x, eType = 0x%x," + " nDataSize = 0x%x", (unsigned)extra_data, extra_data->nSize, + extra_data->eType, extra_data->nDataSize); + + if ((extra_data->eType == VDEC_EXTRADATA_NONE) || + (extra_data->eType == VEN_EXTRADATA_NONE)) { + DEBUG_PRINT_LOW("No more extradata available"); + extra_data->eType = OMX_ExtraDataNone; + break; + } + else if (extra_data->eType == VDEC_EXTRADATA_SEI) { + DEBUG_PRINT_LOW("Extradata SEI of size %d found, " + "parsing it", extra_data->nDataSize); + parse_sei(extra_data->data, extra_data->nDataSize); + } + else if (extra_data->eType == VEN_EXTRADATA_QCOMFILLER) { + DEBUG_PRINT_LOW("Extradata Qcom Filler found, skip %d bytes", + extra_data->nSize); + } + else if (extra_data->eType == VEN_EXTRADATA_SLICEINFO) { + DEBUG_PRINT_LOW("Extradata SliceInfo of size %d found, " + "parsing it", extra_data->nDataSize); + parse_sliceinfo(buf_hdr, extra_data); + } +#ifndef _MSM8974_ + else if (extra_data->eType == VEN_EXTRADATA_LTRINFO) { + DEBUG_PRINT_LOW("Extradata LTRInfo of size %d found, " + "parsing it", extra_data->nDataSize); + parse_ltrinfo(buf_hdr, extra_data); + } +#endif + else { + DEBUG_PRINT_ERROR("Unknown extradata(0x%x) found, nSize = 0x%x, " + "eType = 0x%x, nDataSize = 0x%x", (unsigned)extra_data, + extra_data->nSize, extra_data->eType, extra_data->nDataSize); + buf_hdr->nFlags &= ~(OMX_BUFFERFLAG_EXTRADATA); + break; + } + extra_data = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) extra_data) + + extra_data->nSize); + } + } + return 1; +} + +OMX_U32 extra_data_handler::get_frame_pack_data( + OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack) +{ + DEBUG_PRINT_LOW("\n%s:%d get frame data", __func__, __LINE__); + memcpy(&frame_pack->id,&frame_packing_arrangement.id, + FRAME_PACK_SIZE*sizeof(OMX_U32)); + return 1; +} + +OMX_U32 extra_data_handler::set_frame_pack_data(OMX_QCOM_FRAME_PACK_ARRANGEMENT + *frame_pack) +{ + DEBUG_PRINT_LOW("\n%s:%d set frame data", __func__, __LINE__); + memcpy(&frame_packing_arrangement.id, &frame_pack->id, + FRAME_PACK_SIZE*sizeof(OMX_U32)); + pack_sei = true; + sei_payload_type = SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT; + return 1; +} + +OMX_U32 extra_data_handler::e_u(OMX_U32 symbol, OMX_U32 num_bits) +{ + OMX_U32 rem_bits = num_bits, shift; + + DEBUG_PRINT_LOW("\n%s bin : %x/%d", __func__, symbol, num_bits); + + while(rem_bits >= bit_ptr) { + shift = rem_bits - bit_ptr; + rbsp_buf[byte_ptr] |= (symbol >> shift); + symbol = (symbol << (32 - shift)) >> (32 - shift); + rem_bits -= bit_ptr; + DEBUG_PRINT_LOW("\n%sstream byte/rem_bits %x/%d", __func__, + rbsp_buf[byte_ptr], rem_bits); + byte_ptr ++; + bit_ptr = 8; + } + + if(rem_bits) { + shift = bit_ptr - rem_bits; + rbsp_buf[byte_ptr] |= (symbol << shift); + bit_ptr -= rem_bits; + DEBUG_PRINT_LOW("\n%s 2 stream byte/rem_bits %x", __func__, + rbsp_buf[byte_ptr], rem_bits); + if(bit_ptr == 0) { + bit_ptr = 8; + byte_ptr++; + } + } + return 1; +} + +OMX_U32 extra_data_handler::e_ue(OMX_U32 symbol) +{ + OMX_U32 i, sym_len, sufix_len, info; + OMX_U32 nn =(symbol + 1) >> 1; + + DEBUG_PRINT_LOW("\n%s bin : %x", __func__, symbol); + + for(i=0; i < 33 && nn != 0; i++) + nn >>= 1; + + sym_len = ((i << 1) + 1); + info = symbol + 1 - (1 << i); + sufix_len = (1 << (sym_len >>1)); + info = sufix_len | (info & (sufix_len - 1)); + e_u(info, sym_len); + return 1; +} + +OMX_U32 extra_data_handler::create_frame_pack() +{ + e_ue(frame_packing_arrangement.id); + e_u(frame_packing_arrangement.cancel_flag, 1); + if(!frame_packing_arrangement.cancel_flag) { + e_u(frame_packing_arrangement.type, 7); + e_u(frame_packing_arrangement.quincunx_sampling_flag, 1); + e_u(frame_packing_arrangement.content_interpretation_type, 6); + e_u(frame_packing_arrangement.spatial_flipping_flag, 1); + e_u(frame_packing_arrangement.frame0_flipped_flag, 1); + e_u(frame_packing_arrangement.field_views_flag, 1); + e_u(frame_packing_arrangement.current_frame_is_frame0_flag, 1); + e_u(frame_packing_arrangement.frame0_self_contained_flag, 1); + e_u(frame_packing_arrangement.frame1_self_contained_flag, 1); + if(!frame_packing_arrangement.quincunx_sampling_flag && + frame_packing_arrangement.type != 5) { + e_u(frame_packing_arrangement.frame0_grid_position_x, 4); + e_u(frame_packing_arrangement.frame0_grid_position_y, 4); + e_u(frame_packing_arrangement.frame1_grid_position_x, 4); + e_u(frame_packing_arrangement.frame1_grid_position_y, 4); + } + e_u(frame_packing_arrangement.reserved_byte, 8); + e_ue(frame_packing_arrangement.repetition_period); + } + e_u(frame_packing_arrangement.extension_flag, 1); + return 1; +} + +OMX_S32 extra_data_handler::create_rbsp(OMX_U8 *buf, OMX_U32 nalu_type) +{ + OMX_U32 i, j = 7; + for(i = 0;i < 3;i++) + *buf++ = 0x00; + *buf++ = H264_START_CODE; + *buf++ = nalu_type; + *buf++ = (sei_payload_type & 0x000000FF); + *buf++ = byte_ptr - 1; //payload will contain 1 byte of rbsp_trailing_bits + //that shouldn't be taken into account + + for(i = 0;i < byte_ptr ;i += 2) { + *buf++ = rbsp_buf[i]; + j++; + if(i+1 < byte_ptr) { + *buf++ = rbsp_buf[i+1]; + j++; + if(!(rbsp_buf[i] + rbsp_buf[i+1])) { + *buf++ = H264_EMULATION_BYTE; + j++; + } + } + } + + DEBUG_PRINT_LOW("\n%s rbsp length %d", __func__, j); + return j; +} + +OMX_U32 extra_data_handler::create_sei(OMX_U8 *buffer) +{ + OMX_U32 i, ret_val = 0; + + byte_ptr = 0; + bit_ptr = 8; + + if(sei_payload_type == SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT) { + create_frame_pack(); + + if(bit_ptr != 8) { + e_u(1,1); + if(bit_ptr != 8) + e_u(0,bit_ptr); + } + + //Payload will have been byte aligned by now, + //insert the rbsp trailing bits + e_u(1, 1); + e_u(0, 7); + + ret_val = create_rbsp(buffer, NAL_TYPE_SEI); + } + + pack_sei = false; + sei_payload_type = -1; + + return ret_val; +} + +OMX_U32 extra_data_handler::create_extra_data(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + OMX_U8 *buffer = (OMX_U8 *) ((unsigned)(buf_hdr->pBuffer + + buf_hdr->nOffset + buf_hdr->nFilledLen)); + OMX_U32 msg_size; + + if(buf_hdr->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + DEBUG_PRINT_LOW("\n%s:%d create extra data with config", __func__, + __LINE__); + if(pack_sei) { + msg_size = create_sei(buffer); + if( msg_size > 0) + buf_hdr->nFilledLen += msg_size; + } + } + return 1; +} + |