summaryrefslogtreecommitdiff
path: root/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp
diff options
context:
space:
mode:
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.cpp510
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;
+}
+