解码H264视频文件实现类似av_parser_parse2功能

#include "SubsectionDecoder.h"
#include "H264_2_RGB.h"
#include <pthread.h>
#include <iostream>
#include <Windows.h>

#ifdef _WIN32
#pragma comment(lib, "pthreadVC2.lib")
#endif

using namespace SubDecode;

//6000000
#define MX_RTP_BUF  (1000*1000*6)

int info4 = 0, info5 = 0;

static int FindStartCode2(unsigned char *Buf)
{
	if (Buf[0] != 0 || Buf[1] != 0 || Buf[2] != 1) return 0; //0x000001?
	else return 1;
}

static int FindStartCode3(unsigned char *Buf)
{
	if (Buf[0] != 0 || Buf[1] != 0 || Buf[2] != 0 || Buf[3] != 1) return 0;//0x00000001?
	else return 1;
}


int SubsectionDecoder::GetAnnexbNALU(NALU_t *nalu)
{
	int pos = 0;
	int StartCodeFound, rewind;
	unsigned char *Buf;
	m_nIndex = 0;

	if ((Buf = (unsigned char*)calloc(nalu->max_size, sizeof(char))) == NULL)
	{
		printf("GetAnnexbNALU: Could not allocate Buf memory\n");
		return -1;
	}
	nalu->startcodeprefix_len = 3;
	//获取数据
	memcpy(Buf, m_pMaxBuf, 3);
	m_nCurSize -= 3;
	m_nIndex += 3;
	info4 = FindStartCode2(Buf);
	if (info4 != 1)
	{
		memcpy(Buf + 3, m_pMaxBuf + m_nIndex, 1);
		m_nCurSize -= 1;
		m_nIndex += 1;
		info5 = FindStartCode3(Buf);
		if (info5 != 1)
		{
			//移动内存
			memmove(m_pMaxBuf, m_pMaxBuf + m_nIndex, m_nCurSize);
			free(Buf);
			return -1;
		}
		else
		{
			pos = 4;
			nalu->startcodeprefix_len = 4;
		}
	}
	else
	{
		nalu->startcodeprefix_len = 3;
		pos = 3;
	}
	StartCodeFound = 0;
	info4 = 0;
	info5 = 0;

	while (!StartCodeFound)
	{
		if (m_nCurSize <= 0)
		{
			nalu->len = (pos - 1) - nalu->startcodeprefix_len;
			memcpy(nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);
			nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit
			nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit
			nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit
			free(Buf);
			//移动内存
			memmove(m_pMaxBuf, m_pMaxBuf + m_nIndex, m_nCurSize);
			return pos - 1;
		}

		//整理内存
		Buf[pos++] = m_pMaxBuf[m_nIndex];//*m_pMaxBuf + m_nIndex;//(m_pMaxBuf)[m_nIndex];
		m_nIndex++;
		m_nCurSize--;
		info5 = FindStartCode3(&Buf[pos - 4]);
		if (info5 != 1)
			info4 = FindStartCode2(&Buf[pos - 3]);
		StartCodeFound = (info4 == 1 || info5 == 1);
	}

	// Here, we have found another start code (and read length of startcode bytes more than we should
	// have.  Hence, go back in the file
	rewind = (info5 == 1) ? -4 : -3;

	//调整空间
	m_nCurSize -= rewind;
	m_nIndex += rewind;

	// Here the Start code, the complete NALU, and the next start code is in the Buf.  
	// The size of Buf is pos, pos+rewind are the number of bytes excluding the next
	// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code
	nalu->len = (pos + rewind) - nalu->startcodeprefix_len;
	memcpy(nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//
	nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit
	nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit
	nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit
	free(Buf);

	//移动内存
	memmove(m_pMaxBuf, m_pMaxBuf + m_nIndex, m_nCurSize);

	return (pos + rewind);
}

int SubsectionDecoder::PushStream2Play(unsigned char * pBuf, int nbufsize, void* pUserData)
{
	if (m_nCurSize > MX_RTP_BUF)
		return -1;
	memcpy(m_pMaxBuf + m_nCurSize, pBuf, nbufsize);
	m_nCurSize += nbufsize;
	if (m_nCurSize < 40 * 1000)
	{
		if (nbufsize >= 1024)
		{
			return -2;
		}
	}

	int data_offset = 0;
	int nal_num = 0;
	//解码用另加
	unsigned char *m_pData = (unsigned char *)calloc(1000 * 1000, sizeof(char));
	int sizeHeBing = 0;
	unsigned char* outputBuf;
	unsigned int nOutSize;
	int nHeight;
	int nWidth;
	bool bInit = false;
	int data_length;

	//while(m_nCurSize > 10000 && GetAnnexbNALU(m_pNalu) > 0)
	data_length = GetAnnexbNALU(m_pNalu);
	if(data_length > 0)
	{
		//解码视频并显示
		memset(m_pData, 0, 4);
		m_pData[3] = 1;
		memcpy(m_pData + 4, m_pNalu->buf, m_pNalu->len);
		sizeHeBing = m_pNalu->len + 4;

		H264_2_RGB(m_pData, sizeHeBing, outputBuf, &nOutSize, &nWidth, &nHeight);
	}
	free(m_pData);
	return 0;
}

SubsectionDecoder::SubsectionDecoder():m_nCurSize(0), m_bdecoding(true)
{
	H264_Init(AV_CODEC_ID_H264);
	m_pMaxBuf = (unsigned char*)malloc(sizeof(uint8_t)*MX_RTP_BUF);
	if (m_pMaxBuf == NULL)
		exit(-1);

	InitNalu();
}

int SubsectionDecoder::UnInitNalu()
{
	if(m_pNalu->buf != NULL)
		free(m_pNalu->buf);
	if(m_pNalu != NULL)
		free(m_pNalu);
	return 0;
}

SubsectionDecoder:: ~SubsectionDecoder()
{
	m_bdecoding = false;
	//pthread_kill(m_pid, 0);
	H264_Release();
	free(m_pMaxBuf);
	UnInitNalu();
	//pthread_mutex_destroy(&m_mutex);
}

int SubsectionDecoder::PushStreamData(unsigned char * pBuf, int nbufSize)
{
	if (MX_RTP_BUF < (m_nCurSize + nbufSize))
		return m_nCurSize;
	if (pBuf != NULL && nbufSize > 0)
	{
		LockMemery();
		memcpy(m_pMaxBuf + m_nCurSize, pBuf, nbufSize);
		m_nCurSize += nbufSize;
		UnLockMemery();
	}
	return m_nCurSize;
}

void* decodeThread(void* pUserData)
{
	SubsectionDecoder *pDecoder = (SubsectionDecoder*)pUserData;
	NALU_t *n;
	int buffersize = 100000;
	FILE *myout = stdout;

	n = (NALU_t*)calloc(1, sizeof(NALU_t));
	if (n == NULL) {
		printf("Alloc NALU Error\n");
		return 0;
	}

	n->max_size = buffersize;
	n->buf = (char*)calloc(buffersize, sizeof(char));
	if (n->buf == NULL) {
		free(n);
		printf("AllocNALU: n->buf");
		return 0;
	}

	int data_offset = 0;
	int nal_num = 0;
	printf("-----+-------- NALU Table ------+---------+\n");
	printf(" NUM |    POS  |    IDC |  TYPE |   LEN   |\n");
	printf("-----+---------+--------+-------+---------+\n");

	//解码用另加
	unsigned char *m_pData = (unsigned char *)calloc(1000 * 1000, sizeof(char));
	int sizeHeBing = 0;
	unsigned char* outputBuf;
	unsigned int nOutSize;
	int nHeight;
	int nWidth;
	bool bInit = false;
	while (pDecoder->GetRunStatus())
	{
		int nCurSize = pDecoder->GetCurMemSize();
		if (nCurSize <= (4 * 1000))
		{
			Sleep(1);
			continue;
		}
			
		int data_lenth;
		pDecoder->LockMemery();
		data_lenth = pDecoder->GetAnnexbNALU(n);
		pDecoder->UnLockMemery();

		if (data_lenth > 0)
		{
			//解码视频并显示
			memset(m_pData, 0, 4);
			m_pData[3] = 1;
			memcpy(m_pData + 4, n->buf, n->len);
			sizeHeBing = n->len + 4;

			H264_2_RGB(m_pData, sizeHeBing, outputBuf, &nOutSize, &nWidth, &nHeight);
		}
	}
	return NULL;
}

int SubsectionDecoder::InitNalu()
{
	int buffersize = 100000;
	FILE *myout = stdout;

	m_pNalu = (NALU_t*)calloc(1, sizeof(NALU_t));
	if (m_pNalu == NULL) {
		printf("Alloc NALU Error\n");
		return -1;
	}

	m_pNalu->max_size = buffersize;
	m_pNalu->buf = (char*)calloc(buffersize, sizeof(char));
	if (m_pNalu->buf == NULL) {
		free(m_pNalu);
		printf("AllocNALU: n->buf");
		return -1;
	}
}

int SubsectionDecoder::LockMemery()
{
	pthread_mutex_lock(&m_mutex);
	return 0;
}

int SubsectionDecoder::UnLockMemery()
{
	pthread_mutex_unlock(&m_mutex);
	return 0;
}

void* SubsectionDecoder::GetUserData()
{
	return m_pUserData;
}

bool SubsectionDecoder::SetOutputBuf(RgbBufOut bufProc, void* pUserData)
{
	m_proRgbBuf = bufProc;
	if (bufProc == NULL)
		return false;

	m_pUserData = pUserData;
	return true;
#if 0
	pthread_mutex_init(&m_mutex, NULL);
	if (pthread_create(&m_pid, NULL, decodeThread, this) == 0)
	{
		std::cout << "create decoder thread success" << std::endl;
		pthread_detach(m_pid);
	}
	else
	{
		std::cout << "create decoder thread failed" << std::endl;
	}
#endif
}

具体的实现类,参考雷神的代码,不是将文件整个读入,改为一点一点的推送buffer

#pragma once

#include "StreamDetector.h"
#include <pthread.h>


namespace SubDecode {
	/**
	次类用作,读取视频文件,然后批量解码的功能库
	------------------------------------------------------------------------
	1         2           3           4            5            6           7

	void* _memmove(void* dest, const void* src, size_t count)
	*/

	typedef void(*RgbBufOut)(void* pUserData, unsigned char* pBufOut, int pBufSize, int nWidth, int nHeight, int nLineWidth);

	///Nalu类型枚举
	typedef enum {
		NALU_TYPE_SLICE = 1,
		NALU_TYPE_DPA = 2,
		NALU_TYPE_DPB = 3,
		NALU_TYPE_DPC = 4,
		NALU_TYPE_IDR = 5,
		NALU_TYPE_SEI = 6,
		NALU_TYPE_SPS = 7,
		NALU_TYPE_PPS = 8,
		NALU_TYPE_AUD = 9,
		NALU_TYPE_EOSEQ = 10,
		NALU_TYPE_EOSTREAM = 11,
		NALU_TYPE_FILL = 12,
	} NaluType;

	//Nalu属性
	typedef enum {
		NALU_PRIORITY_DISPOSABLE = 0,
		NALU_PRIRITY_LOW = 1,
		NALU_PRIORITY_HIGH = 2,
		NALU_PRIORITY_HIGHEST = 3
	} NaluPriority;

	class EXPORT_DLL SubsectionDecoder {
	public:
		SubsectionDecoder();

		int InitNalu();

		int UnInitNalu();

		virtual ~SubsectionDecoder();

		int PushStreamData(unsigned char * pBuf, int nbufSize);

		int PushStream2Play(unsigned char * pBuf, int nbufsize, void* pUserData);

		bool SetOutputBuf(RgbBufOut bufProc, void* pUserData);

		int LockMemery();

		int UnLockMemery();

		void* GetUserData();

		int GetAnnexbNALU(NALU_t *nalu);

		int GetCurMemSize() { return m_nCurSize; };

		int GetRunStatus() { return m_bdecoding; };

		bool SetRunStatus(bool bFlag) { m_bdecoding = bFlag; return m_bdecoding; };

	private:
		unsigned char* m_pMaxBuf;  //当前buffer存放的数据
		int m_nCurSize;			   //当前buffer的大小
		RgbBufOut m_proRgbBuf;
		pthread_t m_pid;           //解码线程
		pthread_mutex_t m_mutex;   //解码线程锁
		NALU_t *m_pNalu;		   //nalu结构体
		void* m_pUserData;
		int m_nIndex;				//当前吃调的内存
		bool m_bdecoding;			//正在解码
	};
}

调用方法

	SubsectionDecoder *pDecoder = new SubsectionDecoder;
	FILE * fph264 = fopen("G:\\UbuntuFiles\\bxg.h264", "rb");
	//FILE * fph264 = fopen("sample_720p.h264", "rb");
	//FILE * fph264 = fopen("bigbuckbunny_480x272.h264", "rb");
	if (fph264 == NULL)
	{
		printf("open file faield\n");
		return -1;
	}
	unsigned char buf[1024] = {};
	//pDecoder->SetOutputBuf(RgbBufOutProc, NULL);
	while (!feof(fph264))
	{
		int nLen = fread(buf, 1, 1024, fph264);
		pDecoder->PushStream2Play(buf, nLen, nullptr);
		Sleep(1);
	}
	//pDecoder->SetRunStatus(false);
	
	delete pDecoder;

工程目录,可能有没用的代码,不想删除:

https://download.csdn.net/download/chnim/10675494

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

telllong

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值