zoukankan      html  css  js  c++  java
  • 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
    ");
    	}
    
    	// 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
    ");
    		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("=========================
    ");
    		}
    	} 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
    ");
    			end_of_file = 1;
    		}
    		if (rsz > 0)
    			fend += rsz;
    	}
    	if (fend > fbufsz) {
    		fprintf(stderr, "Opps: this should never happen!
    ");
    		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.
    ");
    			buf = NULL;
    			if (!end_of_file)
    				fprintf(stderr, "You should consider increase fbufsz. Current fbufsz=%d.
    ", 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
    ", 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
    ");
    		buf = NULL;
    		if (!end_of_file)
    			fprintf(stderr, "You should consider increase fbufsz. Current fbufsz=%d.
    ", 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);
    }
  • 相关阅读:
    实现移动端1像素线--stylus
    用户信息认证session和token
    深入了解new的过程,和call,apply,bind的区别
    微信公众号开发过程--踏坑指南
    Better-scroll巨坑!!!
    JS ES6中Arguments和Parameters的区别
    知识点1
    面试--随笔1
    pytts3语音合成遇到的中文问题
    需求,需要谁参与进来?
  • 原文地址:https://www.cnblogs.com/SunkingYang/p/11049141.html
Copyright © 2011-2022 走看看