拆分264码流

当从avc编码器拿到一帧数据时,有时会考虑按NALU头进行拆分,示例代码如下:

P帧和B帧只有一个NALU头,所以不再需要拆分,主要是I帧,一般包含7,8,6,5四部分。


/* find the size of a frame.
 * @data the memory of avc bit stream, this should be start with [00 00 00 01].
 * @data_size the length of the bit stream
 * @start the next start index of @data
 * @return return the length of the current frame which start with @data[start].
 **/
static int find_nal(unsigned char *data, int data_size, int start)
{
	int index = start + 4;

	// I frame is the last frame
	if((data[start + 4] & 0x1f) == 5) {
		return (data_size - start);
	}
	while(index < (data_size - start)) {
		if(data[index] == 0 && 
		   data[index + 1] == 0 && 
		   data[index + 2] == 0 && 
		   data[index + 3] == 1) {
			return index;
		}
		index++;
	}
	return -1;
}
/* parse a I frame and send them partly.
 * @chID the index of encoders
 * @data an avc I frame which maybe include 7, 8, 6, 5
 * @data_size the length of the I frame
 **/
static void parseIFrameAndSend(int chID, unsigned char *data, int data_size)
{
	int sps_size = 0;
	int pps_size = 0;
	int idr_size = 0;
	int invaild_size = 0;

	int start = 0;
	while(1) {
		int next_start = find_nal(data, data_size, start);
		if(next_start == -1)
			break;
		
		if((data[start+4] & 0x1f) == 7) {
			sps_size = next_start - start;
		}
		if((data[start+4] & 0x1f) == 8) {
			pps_size = next_start - start;
		}
		if((data[start+4] & 0x1f) == 6) { // the frame will be dropped
			invaild_size = next_start - start;
		}
		if((data[start+4] & 0x1f) == 5) {
			idr_size = next_start;
			break;
		}
		start = next_start;
	}

	int i = 0;
	int size = 0;
	int frame_size[3] = {sps_size, pps_size, idr_size};

	start = 0;
	for(i = 0; i < 3; i++) {
		size = frame_size[i];
		unsigned char *head = (unsigned char *)malloc(sizeof(chID) + size);
		if(NULL == head){
			printf("alloc memory for encoder stream failed\n");
			return ;
		}

		memcpy(head, &chID, sizeof(chID));
		memcpy(head + sizeof(chID), data + start, size); // copy the current frame to the allocated buffer

		// send head by socket
		if(gServerHandle != NULL)
			Socket_SendData(gServerHandle, head, (sizeof(chID) + size));

		start += size;
		#if 1
		if(i == 1) // skip 6 frame
			start += invaild_size;
		#endif
	}
}

假设当前encoder只生成I帧和P帧,使用代码如下:

void send_enc_stream(int chID, void *data, int data_size)
{
	unsigned char *p = (unsigned char *)data;
	if((p[4] & 0x1f) == 1) // get a P frame
	{
		unsigned char *head = (unsigned char *)malloc(sizeof(chID) + data_size);
		if(NULL == head){
			printf("alloc memory for encoder stream failed\n");
			return ;
		}

		memcpy(head, &chID, sizeof(chID));
		memcpy(head + sizeof(chID), data, data_size); // copy the current frame to the allocated buffer

		// send head by socket
		if(gServerHandle != NULL)
			Socket_SendData(gServerHandle, head, (sizeof(chID) + data_size));

	} 
	else if((p[4] & 0x1f) == 7) // get an I frame
	{
		parseIFrameAndSend(chID, data, data_size);
	}
}




猜你喜欢

转载自blog.csdn.net/xy_kok/article/details/78276328