1. 程式人生 > >ffmpeg解封裝,學習記錄。

ffmpeg解封裝,學習記錄。

CFilePlugEx::CFilePlugEx(INT uiSocketIndex, UINT uiPkgSize, string&sourcePath, BYTE _type)
	: m_sourcePath(sourcePath)
 ,m_uiPagSize(uiPkgSize)
, m_uiSocketIndex(uiSocketIndex)
, m_pIfmtCtx(nullptr)
,m_type(_type)
{
	m_nVideoIndex = -1;
	m_nAudioIndex = -1;
	m_bIsInitSuccess = false;
	m_nBufSize = 0;
	m_nBufIndex = 0;
	m_bIsInitSuccess = InitFFmepg();
}


CFilePlugEx::~CFilePlugEx()
{
	
}

bool CFilePlugEx::StartSendAV(std::function<void(char*fileBuf, int len, UINT uiSocketIndex, BYTE _type)> lambdaCallBabck)
{
	if (!m_bIsInitSuccess)
	{
		MessageBox(0, L"FFMEPG 初始化錯誤\n", L"錯誤", 0);
		return false;
	}
	if (m_nBufIndex >= m_nBufSize)
	{
		m_nBufIndex = 0;
		m_nBufSize = 0;
		if(!ReadFrame(m_avPkt, m_nBufSize)) {
			if (m_nBufSize == -1)//讀取檔案錯誤,可能讀完了流
			{
				MessageBox(0, L"讀取檔案錯誤,可能讀完了流\n", L"錯誤", 0);
				return false;
			}
			if (m_nBufSize == 0)//可能讀取了異常資料幀
			{
				av_free_packet(&m_avPkt);
				m_avPkt.size = 0;
				return true;
			}
	   }
	}
	int len1 = m_nBufSize - m_nBufIndex;
	if (len1 >m_uiPagSize)//剩餘的資料 比預設的大
	{
		lambdaCallBabck((char*)m_avPkt.data + m_nBufIndex, m_uiPagSize, m_uiSocketIndex, m_type);
		m_nBufIndex += m_uiPagSize;
	}
	if (len1<= m_uiPagSize) //剩餘的小於預設值 不完整簡單處理髮送。
	{
		lambdaCallBabck((char*)m_avPkt.data + m_nBufIndex, len1, m_uiSocketIndex, m_type);
		m_nBufIndex = 0;
		m_nBufSize = 0;
		av_free_packet(&m_avPkt);
		m_avPkt.size = 0;
	}
	return true;
}

void CFilePlugEx::StopSendAv()
{
	av_free_packet(&m_avPkt);
	avformat_close_input(&m_pIfmtCtx);
}

bool CFilePlugEx::InitFFmepg()
{
	av_register_all();
	if ((avformat_open_input(&m_pIfmtCtx, m_sourcePath.c_str(), 0, 0)) < 0) {
		TRACE("Could not open input file.\n");
		goto end;
	}
	if ((avformat_find_stream_info(m_pIfmtCtx, 0)) < 0) {
		TRACE("Failed to retrieve input stream information\n");
		goto end;
	}
	for (auto i = 0; i < m_pIfmtCtx->nb_streams; i++) {
		AVStream *in_stream = m_pIfmtCtx->streams[i];
		if (in_stream->codec->codec_id == AV_CODEC_ID_NONE && m_pIfmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
			in_stream->codec->codec_id = AV_CODEC_ID_PCM_ALAW;
			in_stream->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW;
		}
		if (m_pIfmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
			if (m_nVideoIndex != -1) {
				continue;
			}
			m_nVideoIndex = i;
		}
		else if (m_pIfmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
			if (m_nAudioIndex != -1) {
				continue;
			}
			m_nAudioIndex = i;
		}
		else {
			break;
		}
	}
	if (m_nAudioIndex == -1&& m_nVideoIndex == -1)
	{
		TRACE("Failed to find stream\n");
		goto end;
	}
	avcodec_register_all();
	return true;
end:
	avformat_close_input(&m_pIfmtCtx);
	return false;
}

int my_av_bsf_filter(const AVBitStreamFilter *filter, AVPacket *pPacket, const AVCodecParameters *src)
{
	int ret;
	AVBSFContext *ctx = NULL;
	if (!filter)
		return 0;

	ret = av_bsf_alloc(filter, &ctx);
	if (ret < 0)
		return ret;
	ret = avcodec_parameters_copy(ctx->par_in, src);
	if (ret < 0)
		return ret;

	ret = av_bsf_init(ctx);
	if (ret < 0)
		return ret;

	AVPacket pkt = { 0 };
	pkt.data = pPacket->data;
	pkt.size = pPacket->size;

	ret = av_bsf_send_packet(ctx, &pkt);
	if (ret < 0)
		return ret;

	ret = av_bsf_receive_packet(ctx, &pkt);
	if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
		return 0;
	else if (ret < 0)
		return ret;

	uint8_t **poutbuf = &(pPacket->data);
	int *poutbuf_size = &(pPacket->size);

	*poutbuf = (uint8_t*)av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE);
	if (!*poutbuf) {
		av_packet_unref(&pkt);
		return AVERROR(ENOMEM);
	}
	*poutbuf_size = pkt.size;
	memcpy(*poutbuf, pkt.data, pkt.size);

	av_packet_unref(&pkt);

	/* drain all the remaining packets we cannot return */
	while (ret >= 0) {
		ret = av_bsf_receive_packet(ctx, &pkt);
		av_packet_unref(&pkt);
	}

	av_bsf_free(&ctx);
	return 1;
}

bool CFilePlugEx::ReadFrame(AVPacket &pkt, unsigned int &len)
{
	const AVBitStreamFilter *pavBitStFilter = av_bsf_get_by_name("h264_mp4toannexb");
	AVStream *in_stream;
	if (av_read_frame(m_pIfmtCtx, &pkt) < 0)
	{
		len = -1;
		return false;
	}		
	in_stream = m_pIfmtCtx->streams[pkt.stream_index];
	
	if (pkt.stream_index == m_nVideoIndex) {//視訊流
		if (m_type == 0x10)
		{
			my_av_bsf_filter(pavBitStFilter, &pkt, in_stream->codecpar);
			len = pkt.size;
		}
	}
	else if(pkt.stream_index == m_nAudioIndex)//音訊流
	{
		if (m_type == 0x01)
		{
			len = pkt.size;
		}
	}
	else//其他型別的,此時還未結束 可能讀取異常
	{
		len = 0;
		return false;
	}

	return true;
}