blob: dbd8a893ad6c2c5e2e9f0eb517d5067a98b28019 [file] [log] [blame]
/*
* 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 + 8);
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 + 8);
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;
}