/* * Copyright 2018 NXP */ /* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ /*! * @file insert_startcode.c * * copyright here may be changed later * * */ #include "insert_startcode.h" // Global VC1 ID and version u_int32 uVC1CodecID = 0x10; // Simple = 0x10, Main = 0x11 u_int32 uVC1VersionID = 1; static int insert_RCV_seqhdr(unsigned char *pHeader, u_int32 *pHeaderLen, unsigned char *src, u_int32 nFrameSize, u_int32 nWidth, u_int32 nHeight, int *pNoError) { int nHeaderLen; unsigned int nValue; unsigned int HdrExtDataLen; int i = 0; int profile; nHeaderLen = RCV_HEADER_LEN; //Number of Frames, Header Extension Bit, Codec Version nValue = RCV_NUM_FRAMES | RCV_SET_HDR_EXT | RCV_CODEC_VERSION; pHeader[i++] = (unsigned char)nValue; pHeader[i++] = (unsigned char)(nValue >> 8); pHeader[i++] = (unsigned char)(nValue >> 16); #if 0 //1 ??? pHeader[i++] = 0xC5; #else pHeader[i++] = (unsigned char)(nValue >> 24); #endif //Header Extension Size //ASF Parser gives 5 bytes whereas the VPU expects only 4 bytes, so limiting it HdrExtDataLen = 4; pHeader[i++] = (unsigned char)HdrExtDataLen; pHeader[i++] = (unsigned char)(HdrExtDataLen >> 8); pHeader[i++] = (unsigned char)(HdrExtDataLen >> 16); pHeader[i++] = (unsigned char)(HdrExtDataLen >> 24); profile = (*src)>>4; if ((profile != 0) && (profile != 4) && (profile != 12)) { //it is reasonable to return error immediately since only one sequence header inserted in whole rcv clip *pNoError = 0; } memcpy(pHeader+i, src, HdrExtDataLen); i += HdrExtDataLen; //Height pHeader[i++] = (unsigned char)nHeight; pHeader[i++] = (unsigned char)(((nHeight >> 8) & 0xff)); pHeader[i++] = (unsigned char)(((nHeight >> 16) & 0xff)); pHeader[i++] = (unsigned char)(((nHeight >> 24) & 0xff)); //Width pHeader[i++] = (unsigned char)nWidth; pHeader[i++] = (unsigned char)(((nWidth >> 8) & 0xff)); pHeader[i++] = (unsigned char)(((nWidth >> 16) & 0xff)); pHeader[i++] = (unsigned char)(((nWidth >> 24) & 0xff)); //Frame Size pHeader[i++] = (unsigned char)nFrameSize; pHeader[i++] = (unsigned char)(nFrameSize >> 8); pHeader[i++] = (unsigned char)(nFrameSize >> 16); #if 0 //1 ??? pHeader[i++] = (unsigned char)((nFrameSize >> 24)); #else pHeader[i++] = (unsigned char)((nFrameSize >> 24) | 0x80); #endif *pHeaderLen = nHeaderLen; return 1; } static int insert_RCV_pichdr(unsigned char *pHeader, int *pHeaderLen, unsigned int nInSize) { pHeader[0] = (unsigned char)nInSize; pHeader[1] = (unsigned char)(nInSize >> 8); pHeader[2] = (unsigned char)(nInSize >> 16); pHeader[3] = (unsigned char)(nInSize >> 24); *pHeaderLen = 4; return 1; } /* * Byte 0-3: Startcode * Byte 4: Payload length bits[23:16] * Byte 5: Payload length bits[15:8] * Byte 6: 0x4e * Byte 7: Payload length bits[7:0] * Byte 8: Codec ID Non-zero * Byte 9: Codec Version ID Non-zero * Byte 10: Picture Width bits[15:8] * Byte 11: Picture Width bits[7:0] * Byte 12: 0x58 * Byte 13: Picture Height bits[15:8] * Byte 14: Picture Height bits[7:0] * Byte 15: 0x50 */ static void insert_payload_header_vc1(u_int8 *dst, u_int32 uScodeType, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight) { // Startcode dst[0] = 0x00; dst[1] = 0x00; dst[2] = 0x01; dst[3] = uScodeType; // Length dst[4] = ((uPayloadSize>>16)&0xff); dst[5] = ((uPayloadSize>>8)&0xff); dst[6] = 0x4e; dst[7] = ((uPayloadSize>>0)&0xff); // Codec ID and Version dst[8] = uVC1CodecID; dst[9] = uVC1VersionID; // Width dst[10] = ((uWidth>>8)&0xff); dst[11] = ((uWidth>>0)&0xff); dst[12] = 0x58; // Height dst[13] = ((uHeight>>8)&0xff); dst[14] = ((uHeight>>0)&0xff); dst[15] = 0x50; } static int VC1CreateNALSeqHeader(unsigned char *pHeader, int *pHeaderLen, unsigned char *pCodecPri, int nCodecSize, unsigned int *pData, int nMaxHeader) { int nHeaderLen; unsigned char temp[4] = {0x00, 0x00, 0x01, 0x0D}; nHeaderLen = nCodecSize - 1; if ((4+nHeaderLen) > nMaxHeader) { nHeaderLen = nMaxHeader - 4; vpu_dbg(LVL_ERR, "error: header length %d overrun !!! \r\n", nCodecSize); } memcpy(pHeader, pCodecPri+1, nHeaderLen); if (VC1_IS_NOT_NAL(pData[0])) { //insert 0x0000010D at the end of header memcpy(pHeader+nHeaderLen, temp, 4); nHeaderLen += 4; } *pHeaderLen = nHeaderLen; return 1; } static int VC1CreateNalFrameHeader(unsigned char *pHeader, int *pHeaderLen, unsigned int *pInData) { unsigned int VC1Id; VC1Id = *pInData; if (VC1_IS_NOT_NAL(VC1Id)) { //need insert header : special ID pHeader[0] = 0x0; pHeader[1] = 0x0; pHeader[2] = 0x01; pHeader[3] = 0x0D; *pHeaderLen = 4; } else { //need not insert header //do nothing *pHeaderLen = 0; } return 1; } void vp6_scd_sequence_header(unsigned char *buffer, int pic_width, int pic_height) { int Length = 0; buffer[0] = 0x00; buffer[1] = 0x00; buffer[2] = 0x01; buffer[3] = 0x31; buffer[4] = (Length+12)>>16; buffer[5] = (Length+12)>>8; buffer[6] = 0x4e; buffer[7] = (Length+12); buffer[8] = 0x36; buffer[9] = 0x1; buffer[10] = pic_width>>8; buffer[11] = pic_width; buffer[12] = 0x58; buffer[13] = pic_height>>8; buffer[14] = pic_height; buffer[15] = 0x50; } void vp6_scd_frame_header(unsigned char *buffer, int pic_width, int pic_height, int Length) { buffer[0] = 0x00; buffer[1] = 0x00; buffer[2] = 0x01; buffer[3] = 0x32; buffer[4] = (Length+12)>>16; buffer[5] = (Length+12)>>8; buffer[6] = 0x4e; buffer[7] = (Length+12); buffer[8] = 0x36; buffer[9] = 0x1; buffer[10] = pic_width>>8; buffer[11] = pic_width; buffer[12] = 0x58; buffer[13] = pic_height>>8; buffer[14] = pic_height; buffer[15] = 0x50; } void vp8_ivf_sequence_header(unsigned char *buffer, int pic_width, int pic_height) { int Length = 32; buffer[0] = 0x44; buffer[1] = 0x4b; buffer[2] = 0x49; buffer[3] = 0x46; //0-3byte signature "DKIF" buffer[4] = 0x00; buffer[5] = 0x00; //4-5byte version 0 buffer[6] = Length; buffer[7] = Length >> 8; //length of Header buffer[8] = 0x56; buffer[9] = 0x50; buffer[10] = 0x38; buffer[11] = 0x30; //VP8 fourcc buffer[12] = pic_width; buffer[13] = pic_width >> 8; buffer[14] = pic_height; buffer[15] = pic_height >> 8; buffer[16] = 0xe8; buffer[17] = 0x03; buffer[18] = 0x00; buffer[19] = 0x00; //16-19 frame rate buffer[20] = 0x01; buffer[21] = 0x00; buffer[22] = 0x00; buffer[23] = 0x00; //20-23 time scale buffer[24] = 0xdf; buffer[25] = 0xf9; buffer[26] = 0x09; buffer[27] = 0x00; //24-27 number frames //28-31 unused } void vp8_ivf_frame_header(unsigned char *buffer, u_int32 FrameSize) { buffer[0] = FrameSize; buffer[1] = FrameSize >> 8; buffer[2] = FrameSize >> 16; buffer[3] = FrameSize >> 24; //4-11 timestamp } void vp8_scd_sequence_header(unsigned char *buffer, int pic_width, int pic_height) { int Length = 32; buffer[0] = 0x00; buffer[1] = 0x00; buffer[2] = 0x01; buffer[3] = 0x31; buffer[4] = (Length+12)>>16; buffer[5] = (Length+12)>>8; buffer[6] = 0x4e; buffer[7] = (Length+12); buffer[8] = 0x36; buffer[9] = 0x1; buffer[10] = pic_width>>8; buffer[11] = pic_width; buffer[12] = 0x58; buffer[13] = pic_height>>8; buffer[14] = pic_height; buffer[15] = 0x50; } void vp8_scd_frame_header(unsigned char *buffer, int pic_width, int pic_height, int Length) { buffer[0] = 0x00; buffer[1] = 0x00; buffer[2] = 0x01; buffer[3] = 0x32; buffer[4] = (Length+12)>>16; buffer[5] = (Length+12)>>8; buffer[6] = 0x4e; buffer[7] = (Length+12); buffer[8] = 0x36; buffer[9] = 0x1; buffer[10] = pic_width>>8; buffer[11] = pic_width; buffer[12] = 0x58; buffer[13] = pic_height>>8; buffer[14] = pic_height; buffer[15] = 0x50; } static void insert_payload_header_divx(u_int8 *dst, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight) { // Startcode dst[0] = 0x00; dst[1] = 0x00; dst[2] = 0x01; dst[3] = 0x32; // Length dst[4] = ((uPayloadSize>>16)&0xff); dst[5] = ((uPayloadSize>>8)&0xff); dst[6] = 0x4e; dst[7] = ((uPayloadSize>>0)&0xff); // Codec ID and Version dst[8] = 0x38; dst[9] = 0x01; // Width dst[10] = ((uWidth>>8)&0xff); dst[11] = ((uWidth>>0)&0xff); dst[12] = 0x58; // Height dst[13] = ((uHeight>>8)&0xff); dst[14] = ((uHeight>>0)&0xff); dst[15] = 0x50; } static void insert_seq_header_spk(u_int8 *dst, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight) { // Startcode dst[0] = 0x00; dst[1] = 0x00; dst[2] = 0x01; dst[3] = 0x31; // Length dst[4] = ((uPayloadSize>>16)&0xff); dst[5] = ((uPayloadSize>>8)&0xff); dst[6] = 0x4e; dst[7] = ((uPayloadSize>>0)&0xff); // Codec ID and Version dst[8] = 0x39; dst[9] = 0x01; // Width dst[10] = ((uWidth>>8)&0xff); dst[11] = ((uWidth>>0)&0xff); dst[12] = 0x58; // Height dst[13] = ((uHeight>>8)&0xff); dst[14] = ((uHeight>>0)&0xff); dst[15] = 0x50; } static void insert_frame_header_spk(u_int8 *dst, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight) { uPayloadSize = 0; // Startcode dst[0] = 0x00; dst[1] = 0x00; dst[2] = 0x01; dst[3] = 0x32; // Length dst[4] = ((uPayloadSize>>16)&0xff); dst[5] = ((uPayloadSize>>8)&0xff); dst[6] = 0x4e; dst[7] = ((uPayloadSize>>0)&0xff); // Codec ID and Version dst[8] = 0x39; dst[9] = 0x01; // Width dst[10] = ((uWidth>>8)&0xff); dst[11] = ((uWidth>>0)&0xff); dst[12] = 0x58; // Height dst[13] = ((uHeight>>8)&0xff); dst[14] = ((uHeight>>0)&0xff); dst[15] = 0x50; } u_int32 insert_scode_4_seq(struct vpu_ctx *ctx, u_int8 *src, u_int8 *dst, u_int32 vdec_std, u_int32 uPayloadSize) { struct queue_data *q_data = &ctx->q_data[V4L2_SRC]; u_int32 length = 0; switch (vdec_std) { case VPU_VIDEO_VC1: { if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) { u_int8 Header[VC1_MAX_SEQ_HEADER_SIZE]; u_int32 uWidth = q_data->width; u_int32 uHeight = q_data->height; //Width & Height in the generic payload header are ignored u_int32 FrameSize = 0x60; u_int32 HeaderLen, NoError = 1; //insert startcode for vc1 insert_payload_header_vc1(dst, VC1_SCODE_NEW_SEQUENCE, 20, uWidth, uHeight); length = 16; //insert RCV sequence header for vc1 v1, length=20 insert_RCV_seqhdr(Header, &HeaderLen, src, FrameSize, uWidth, uHeight, &NoError); HeaderLen = RCV_HEADER_LEN - 4; memcpy(dst + 16, Header, HeaderLen); length += HeaderLen; } else { u_int8 Header[VC1_MAX_SEQ_HEADER_SIZE]; u_int32 HeaderLen; VC1CreateNALSeqHeader(Header, &HeaderLen, src, uPayloadSize, (unsigned int *)src, VC1_MAX_SEQ_HEADER_SIZE); if (VC1_IS_NOT_NAL(((unsigned int *)src)[0])) HeaderLen -= 4; memcpy(dst, Header, HeaderLen); length += HeaderLen; } } break; case VPU_VIDEO_VP6: { vp6_scd_sequence_header(dst, q_data->width, q_data->height); length = 16; } break; case VPU_VIDEO_VP8: { u_int8 seq_header[32] = {0}; u_int8 frame_header[8] = {0}; vp8_scd_sequence_header(dst, q_data->width, q_data->height); length = 16; vp8_ivf_sequence_header(seq_header, q_data->width, q_data->height); memcpy(dst+length, seq_header, 32); length += 32; vp8_scd_frame_header(dst + length, q_data->width, q_data->height, uPayloadSize); length += 16; vp8_ivf_frame_header(frame_header, uPayloadSize); memcpy(dst+length, frame_header, 8); length += 8; memcpy(dst+length, src, uPayloadSize); length += uPayloadSize; } break; case VPU_VIDEO_ASP: { if (q_data->fourcc == VPU_PIX_FMT_DIVX) { insert_payload_header_divx(dst, uPayloadSize, q_data->width, q_data->height); length = 16; memcpy(dst+length, src, uPayloadSize); length += uPayloadSize; } } break; case VPU_VIDEO_SPK: { insert_seq_header_spk(dst, uPayloadSize, q_data->width, q_data->height); length = 16; } break; default: break; } return length; } u_int32 insert_scode_4_pic(struct vpu_ctx *ctx, u_int8 *dst, u_int8 *src, u_int32 vdec_std, u_int32 uPayloadSize) { struct queue_data *q_data = &ctx->q_data[V4L2_SRC]; u_int32 length = 0; switch (vdec_std) { case VPU_VIDEO_VC1: { if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) { u_int8 Header[VC1_MAX_FRM_HEADER_SIZE]; u_int32 HeaderLen; u_int32 uWidth = q_data->width; u_int32 uHeight = q_data->height; //Width & Height in the generic payload header are ignored insert_payload_header_vc1(dst, VC1_SCODE_NEW_PICTURE, uPayloadSize + 4, uWidth, uHeight); insert_RCV_pichdr(Header, &HeaderLen, uPayloadSize); memcpy(dst+16, Header, 4); length = 16 + 4; } else { u_int8 Header[VC1_MAX_FRM_HEADER_SIZE]; u_int32 HeaderLen; VC1CreateNalFrameHeader(Header, (int *)(&HeaderLen), (unsigned int *)(src)); memcpy(dst, Header, HeaderLen); length = HeaderLen; } } break; case VPU_VIDEO_VP6: { vp6_scd_frame_header(dst, q_data->width, q_data->height, uPayloadSize); length = 16; } break; case VPU_VIDEO_VP8: { u_int8 frame_header[8]; vp8_scd_frame_header(dst, q_data->width, q_data->height, uPayloadSize); length = 16; vp8_ivf_frame_header(frame_header, uPayloadSize); memcpy(dst+length, frame_header, 8); length += 8; } break; case VPU_VIDEO_ASP: { if (q_data->fourcc == VPU_PIX_FMT_DIVX) { insert_payload_header_divx(dst, uPayloadSize, q_data->width, q_data->height); length = 16; } } break; case VPU_VIDEO_SPK: { insert_frame_header_spk(dst, uPayloadSize, q_data->width, q_data->height); length = 16; } break; default: break; } return length; }