H264解码之读取本地H264文件

读取本地文件,并逐帧读取:

onReadThread():

void RtspVideo::onReadThread()
{
	// 解码参数
	char *virInBuf = new char[MAX_DECODER_INPUT_BUFFER_SIZE];

	//初始化文件读入buf
	if (init_frame_parser() < 0) {
		fprintf(stderr, "Error: init frame parser\n");
	}

	// find the first SPS,PPS,SEI header -> 读取h264文件头到frmbuf中
	int frmlen;
	uint8_t * frmbuf;
	if ((frmlen = read_one_frame(fpi, &frmbuf, 1)) <= 0) {
		fprintf(stderr, "Error: cannot find header\n");
		deinit_frame_parser();
	}

	do {
		// read one frame
		if ((frmlen = read_one_frame(fpi, &frmbuf, 0)) <= 0) {
			break;
		}

		memcpy(virInBuf, frmbuf + 4, frmlen-4);

		{
			Poco::Mutex::ScopedLock s(m_bufLock);
			MyStruct *stu = new MyStruct();
			stu->pData = new char[frmlen-4];
			memcpy(stu->pData, virInBuf, frmlen-4);
			stu->nLen = frmlen-4;
			m_pDataCtrl.push_back(stu);
			//OutputDebugStringA("=========================\n");
		}
	} while (1);

	delete[] virInBuf;
}

 int read_one_frame(FILE *fp, uint8_t **buf, int header):

int RtspVideo::read_one_frame(FILE *fp, uint8_t **buf, int header)
{
	
	int ustart, uend;
	int cstart, cend;
	int found;
	uint8_t nal_unit_type;

	// 从文件中读取一段数据到fbuf缓冲区中,读取的长度是缓冲区最大长度的一半
	// fstart==fend : empty
	// we keep fstart<=fend. whenever fend goes beyond fbufsz, we move the data back to [0 ...)
	int rsz;
	if (!end_of_file && fend - fstart < fbufsz / 2) { // fbuf is less than half full
		if (fstart > fbufsz / 2) { 	// move back to [0 ...)
			memcpy(fbuf, fbuf + fstart, fend - fstart);
			fend -= fstart;
			fstart = 0;
		}
		// fill up to half: fbufsz/2-fend+fstart
		rsz = fread(fbuf + fend, 1, fbufsz / 2 - fend + fstart, fp);
		if (rsz < (int)(fbufsz / 2 - fend + fstart)) { // end of file
			printf("We have read all data from the input file\n");
			end_of_file = 1;
		}
		if (rsz > 0)
			fend += rsz;
	}
	if (fend > fbufsz) {
		fprintf(stderr, "Opps: this should never happen!\n");
		return -1;
	}

	// 读取文件头数据
	// now either fbuf is half full or it is end of file
	if (header) { // find header
				  // find the first SPS,PPS,SEI header
		found = 0;
		cstart = cend = -1;
		while (find_nal_unit(fbuf + fstart, fend - fstart, &ustart, &uend) > 0) {

			nal_unit_type = fbuf[fstart + ustart] & 0x1f;
			if (nal_unit_type == (uint8_t)6 || nal_unit_type == (uint8_t)7 || nal_unit_type == (uint8_t)8) {
				// SEI, SPS or PPS
				if (!found) {
					found = 1;
					cstart = fstart + ustart-4; // the start of first SPS, PPS or SEI, fbuf[cstart]: 00 00 01
// 					if (cstart > 0 && !fbuf[cstart - 1])
// 						cstart--;
				}
			}
			else {
				if (found) {
					cend = fstart + ustart-4; // the end of header before the following picture slice NAL. fbuf[cend]: 00 00 01
// 					if (!fbuf[cend - 1]) { // the following picture slice has a long start code 00 00 00 01
// 						cend--;
// 					}
					break;
				}
			}
			fstart += uend; // now fbuf[fstart] is the first byte of start code of next NAL
		}

		if (cstart < 0 || cend < 0) {
			fprintf(stderr, "Error: cannot find a NAL header.\n");
			buf = NULL;
			if (!end_of_file)
				fprintf(stderr, "You should consider increase fbufsz. Current fbufsz=%d.\n", fbufsz);
			return -1;
		}

		fstart = cend;

		// now fbuf[cstart,cend) should contain the first SPS,PPS,SEI header
		printf("Header: cstart=%x, cend=%x, length=%d\n", cstart, cend, cend - cstart);
		*buf = fbuf + cstart;

		return cend - cstart;

	}

	// 读取一段NALU数据
	cstart = cend = -1;
	found = 0;
	while (find_nal_unit(fbuf + fstart, fend - fstart, &ustart, &uend) > 0) {
		nal_unit_type = fbuf[fstart + ustart] & 0x1f;
		if (nal_unit_type == (uint8_t)6 || nal_unit_type == (uint8_t)7 || nal_unit_type == (uint8_t)8) {
			// SEI, SPS or PPS
			if (!found) {
				found = 1;
				cstart = fstart + ustart - 4 ; // the start of first SPS, PPS or SEI, fbuf[cstart]: 00 00 01
// 				if (cstart > 0 && !fbuf[cstart - 1])
// 					cstart--;
				cend = fstart + uend;
				break;
			}
		}
		else if (nal_unit_type == (uint8_t)1 || nal_unit_type == (uint8_t)5) { // IDR or non-IDR
			if (!found) { // no header
				cstart = fstart + ustart - 4;
// 				if (cstart > 0 && !fbuf[cstart - 1])
// 					cstart--;
			}
			cend = fstart + uend;
			break;
		}
		cstart = fstart + ustart - 4;
		fstart += uend; // now fbuf[fstart] is the first byte of start code of next NAL
	}

	if (cstart < 0 || cend < 0) {
		//printf("No more NALs. Exiting\n");
		buf = NULL;
		if (!end_of_file)
			fprintf(stderr, "You should consider increase fbufsz. Current fbufsz=%d.\n", fbufsz);
		return -1;
	}

	fstart = cend;

	*buf = fbuf + cstart;
	return cend - cstart+2;
}

 int find_nal_unit(uint8_t* buf, int size, int* nal_start, int* nal_end):

/** this function is taken from the h264bitstream library written by Alex Izvorski and Alex Giladi
Find the beginning and end of a NAL (Network Abstraction Layer) unit in a byte buffer containing H264 bitstream data.
@param[in]   buf        the buffer
@param[in]   size       the size of the buffer
@param[out]  nal_start  the beginning offset of the nal
@param[out]  nal_end    the end offset of the nal
@return                 the length of the nal, or 0 if did not find start of nal, or -1 if did not find end of nal
*/
int RtspVideo::find_nal_unit(uint8_t* buf, int size, int* nal_start, int* nal_end)
{
	if (NULL == buf)
	{
		return 0;
	}
	int i;
	// find start
	*nal_start = 0;
	*nal_end = 0;

	i = 0;
	while (   //( next_bits( 24 ) != 0x000001 && next_bits( 32 ) != 0x00000001 )
		//(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) &&
		(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01)
		)
	{
		i++; // skip leading zero
		if (i + 4 >= size) { return 0; } // did not find nal start
	}

// 	if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) // ( next_bits( 24 ) != 0x000001 )
// 	{
// 		i++;
// 	}
	if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01) // ( next_bits( 24 ) != 0x000001 )
	{
		i++;
	}

	//if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) { /* error, should never happen */ return 0; }
	//i += 3;
	if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01) { /* error, should never happen */ return 0; }
	i += 4;
	*nal_start = i;

// 	while (   //( next_bits( 24 ) != 0x000000 && next_bits( 24 ) != 0x000001 )
// 		(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0) &&
// 		(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01)
// 		)
// 	{
// 		i++;
// 		// FIXME the next line fails when reading a nal that ends exactly at the end of the data
// 		if (i + 3 >= size) { *nal_end = size; return -1; } // did not find nal end, stream ended first
// 	}

	while (   //( next_bits( 24 ) != 0x000000 && next_bits( 24 ) != 0x000001 )
		//(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0) &&
		(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01)
		)
	{
		i++;
		// FIXME the next line fails when reading a nal that ends exactly at the end of the data
		if (i + 4 >= size) { *nal_end = size; return -1; } // did not find nal end, stream ended first
	}

	*nal_end = i;
	return (*nal_end - *nal_start);
}

 

 

你可能感兴趣的:(H264解码显示开发记)