- Add sync frame flags - modify width & height value when get format after set format for capture - modify poll function - decrease MIN_BUFFER_COUNT count to 3 - change file license Signed-off-by: Huang Chaofan <chaofan.huang@nxp.com> (cherry picked from commit 378f251af9ccd6b94b48ff88582b9044c9ac367d)
547 lines
13 KiB
C
547 lines
13 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|
|
|
|
|