PS:在项目中运用到了硬件编码卡编H264 数据,由于解码需要sps和pps才能解除帧,那么就需要提取sps 和pps。
在使用x264 编码中 可以直接通过帧类型获取到。但是使用硬件编码则需要自己运算,下直接上代码。
软件编码x264 为例:
void encodeData(int8_t *data) {
// long long int start =printtime();
//编码
pthread_mutex_lock(&mutex);
memcpy(pic_in->img.plane[0], data, ySize);
for (int i = 0; i < uvSize; ++i) {
//间隔1个字节取一个数据
//u数据
*(pic_in->img.plane[1] + i) = *(data + ySize + i * 2 + 1);
//v数据
*(pic_in->img.plane[2] + i) = *(data + ySize + i * 2);
}
//编码出的数据
x264_nal_t *pp_nal;
//编码除了几个nalu
int pi_nal;
x264_picture_t pic_out;
//编码
int ret = x264_encoder_encode(videoCodec, &pp_nal, &pi_nal, pic_in, &pic_out);
if (ret < 0) {
pthread_mutex_unlock(&mutex);
return;
}
// long long int curr=printtime();
// LOGI("--------------->使用编码时长:%lld",(curr-start));
LOGI("--------------->编出的帧数:%d,编码的类型 %d", pi_nal);
int sps_len, pps_len;
uint8_t sps[100];
uint8_t pps[100];
for (int i = 0; i < pi_nal; ++i) {
//数据类型
if (pp_nal[i].i_type == NAL_SPS) {
// LOGI("--------------->编出的帧数 NAL_SPS");
//去掉00 00 00 01
sps_len = pp_nal[i].i_payload - 4;
memcpy(sps, pp_nal[i].p_payload + 4, sps_len);
} else if(pp_nal[i].i_type == NAL_PPS){
// LOGI("--------------->编出的帧数 NAL_PPS");
pps_len = pp_nal[i].i_payload - 4;
memcpy(pps, pp_nal[i].p_payload + 4, pps_len);
sendSpsPps(sps, pps, sps_len, pps_len);
}else {
//类型5是关键帧 , 编码后的data 数据 ,长度
sendFrame(pp_nal[i].i_type, pp_nal[i].p_payload, pp_nal[i].i_payload);
}
}
pthread_mutex_unlock(&mutex);
}
其中 pi_nal 为帧的个数,一般都是编一次出一个。
其中硬件编码:
void encodeData(int8_t *data) {
lib_encode_inbuf_update(avc_en_t, reinterpret_cast<uint8_t *>(data), 0, 0, g_width, g_height,1);
sem_wait_read(avc_en_t);
// dump 出h264 数据 么问题
// LOGI(" ------------>%p ,and ecvode lngth:%d ", data, avc_en_t->outlength);
//
// int tmpFd = open("/sdcard/test.h264", O_WRONLY | O_APPEND);
// if ( tmpFd < 0 ) {
// LOGI("Creat AF dump file failed!");
// } else {
// write(tmpFd, avc_en_t->out_buf_enc , avc_en_t->outlength);
// close(tmpFd);
// }
if (is_idr(avc_en_t->out_buf_enc)) {
unsigned int sps_size, pps_size, sei_size;
int nal_type = (avc_en_t->out_buf_enc)[4] & 0x1F;
sps_size = h264_decode_get_frame_size(reinterpret_cast<char *>(avc_en_t->out_buf_enc),
avc_en_t->outlength);
//printf("sps_size = %d!\n",sps_size);
pps_size = h264_decode_get_frame_size(
reinterpret_cast<char *>(avc_en_t->out_buf_enc + sps_size),
avc_en_t->outlength - sps_size);
sendSpsPps(avc_en_t->out_buf_enc, avc_en_t->out_buf_enc + sps_size, sps_size, pps_size);
//printf("pps_size = %d!\n",pps_size);
sei_size = h264_decode_get_frame_size(
reinterpret_cast<char *>(avc_en_t->out_buf_enc + sps_size + pps_size),
avc_en_t->outlength - sps_size - pps_size);
//printf("sei_size = %d!\n",sei_size);
sendFrame(nal_type, avc_en_t->out_buf_enc + sps_size + pps_size + sei_size,
avc_en_t->outlength - sps_size - pps_size - sei_size);
} else {
int nal_type = (avc_en_t->out_buf_enc)[4] & 0x1F;
sendFrame(nal_type, avc_en_t->out_buf_enc, avc_en_t->outlength);
LOGE("发送关键帧了");
file->Write_file("success\n", "/keyframe.txt");
}
sem_post_read(avc_en_t);//Can't be omitted
}
/***
*** 此方法可以判断帧的类型
**/
int is_idr(uint8_t *encode_card_out) {
int nal_type = (encode_card_out)[4] & 0x1F;
if (nal_type != 5 && nal_type != 7 && nal_type != 8 && nal_type != 2) {
return 0;
}
return 1;
}
unsigned int h264_decode_get_frame_size(char *stream_buff, unsigned int len) {
unsigned int i, sendlenth;
unsigned int bFindStart = 0, bFindEnd = 0;
unsigned int s32UsedBytes = 0;
unsigned int s32ReadLen = 0;
char *pu8Buf = stream_buff;
for (i = 0; i < len / 2 - 4; i++) {
//int tmp = pu8Buf[i+3] & 0x1F;
if (pu8Buf[i] == 0 && pu8Buf[i + 1] == 0 && pu8Buf[i + 2] == 1) {
bFindStart = 1;
i += 4;
break;
}
}
for (; i < len / 2 - 4; i++) {
//int tmp = pu8Buf[i+3] & 0x1F;
if (pu8Buf[i] == 0 && pu8Buf[i + 1] == 0 && pu8Buf[i + 2] == 1) {
bFindEnd = 1;
break;
}
}
if (i > 0)
s32ReadLen = i - 1;
if (bFindStart == 0) {
//printf("SAMPLE_TEST: can not find start code!s32ReadLen %d, s32UsedBytes %d. \n", s32ReadLen, s32UsedBytes);
} else if (bFindEnd == 0) {
s32ReadLen = i + 8;
}
return s32ReadLen;
}