欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

最简单的GB28181视频PS流播放器。

程序员文章站 2022-03-17 14:13:20
...

一 从PS流中提取h264和aac。

移步:https://blog.csdn.net/qq_39805297/article/details/107083322

二 基于ffmpeg解码h264获取rgb图像,解码aac成pcm格式。

bool H264Decoder::init()
{
	av_register_all();
	_pCodecContext = avcodec_alloc_context3(NULL);
	_pH264VideoDecoder = avcodec_find_decoder(AV_CODEC_ID_H264);
	if (_pH264VideoDecoder == NULL)
	{
		return false;
	}

	//初始化参数,下面的参数应该由具体的业务决定  AV_PIX_FMT_YUV420P;
	_pCodecContext->time_base.num = 1;
	_pCodecContext->frame_number = 1; //每包一个视频帧  
	_pCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
	_pCodecContext->bit_rate = 0;
	_pCodecContext->time_base.den = 25;//帧率  
	_pCodecContext->width = 0;//视频宽  
	_pCodecContext->height = 0;//视频高 
	_pCodecContext->pix_fmt = AV_PIX_FMT_YUVJ420P;
	_pCodecContext->color_range = AVCOL_RANGE_MPEG;

	if (avcodec_open2(_pCodecContext, _pH264VideoDecoder, NULL) < 0)
		return false;
	_pFrame = av_frame_alloc();//存储解码后AVFrame
	_pFrameRGB = nullptr;
	int ret, got_picture;

	int y_size = _pCodecContext->width * _pCodecContext->height;
	AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));//存储解码前数据包AVPacket
	av_new_packet(packet, y_size);
	return true;
}

void H264Decoder::decodeFrame(uint8_t* buffer, uint32_t bufferLen)
{
	AVPacket packet = { 0 };
	packet.data = buffer;    //这里填入一个指向完整H264数据帧的指针  
	packet.size = bufferLen;        //这个填入H264数据帧的大小  
	int ret = avcodec_send_packet(_pCodecContext, &packet);
	int got_picture = avcodec_receive_frame(_pCodecContext, _pFrame); //got_picture = 0 success, a frame was returned
	if (ret < 0)
	{
		return;
	}
	if (got_picture == 0)
	{
		//像素格式转换。pFrame转换为pFrameRGB。
		if (!_pFrameRGB)
		{
			_pFrameRGB = av_frame_alloc();
			uint8_t *video_buffer;
			video_buffer = new uint8_t[avpicture_get_size(AV_PIX_FMT_RGB32, _pCodecContext->width, _pCodecContext->height)];//分配AVFrame所需内存
			av_image_fill_arrays(_pFrameRGB->data, _pFrameRGB->linesize, video_buffer, AV_PIX_FMT_RGB32, _pCodecContext->width, _pCodecContext->height, 1);
			_imgConvertCtx = sws_getContext(_pCodecContext->width, _pCodecContext->height, _pCodecContext->pix_fmt,
				_pCodecContext->width, _pCodecContext->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
		}
		sws_scale(_imgConvertCtx, (const uint8_t* const*)_pFrame->data, _pFrame->linesize, 0, _pCodecContext->height, _pFrameRGB->data, _pFrameRGB->linesize);
		//------------显示--------
		QImage img((uchar*)_pFrameRGB->data[0], _pCodecContext->width, _pCodecContext->height, QImage::Format_RGB32);
		frameChanged(img);
	}
}
void AACDecoder::aac_decoder_create(int sample_rate, int channels, int bit_rate)
{
	AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_AAC);
	if (pCodec == NULL)
	{
		printf("find aac decoder error\r\n");
		return ;
	}
	// 创建显示contedxt
	m_pCodecCtx = avcodec_alloc_context3(pCodec);
	if (m_pCodecCtx == nullptr)
	{
		printf("can not alloc codecContext\r\n");
		return;
	}
	m_pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
	m_pCodecCtx->frame_number = 1;
	m_pCodecCtx->sample_rate = sample_rate;
	m_pCodecCtx->channels = channels;
	m_pCodecCtx->bit_rate = bit_rate;
	m_pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
	if (avcodec_open2(m_pCodecCtx, pCodec, NULL) < 0)
	{
		printf("open codec error\r\n");
		return ;
	}
	m_pFrame = av_frame_alloc();
	uint64_t out_channel_layout = channels < 2 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
	int out_nb_samples = 1024;
	enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;

	m_au_convert_ctx = swr_alloc();
	m_au_convert_ctx = swr_alloc_set_opts(m_au_convert_ctx, out_channel_layout, out_sample_fmt, sample_rate,
		out_channel_layout, AV_SAMPLE_FMT_FLTP, sample_rate, 0, NULL);
	swr_init(m_au_convert_ctx);
	int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
	m_out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
}

int AACDecoder::aac_decode_frame(uint8_t *pData, int nLen)
{
	AVPacket packet;
	av_init_packet(&packet);

	packet.size = nLen;
	packet.data = pData;
	uint8_t *out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
	if (packet.size > 0)
	{
		int ret = avcodec_send_packet(m_pCodecCtx, &packet);
		int got_picture = avcodec_receive_frame(m_pCodecCtx, m_pFrame);
		if (ret >= 0)
		{
			if (got_picture == 0)
			{
				ret = swr_convert(m_au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)m_pFrame->data, m_pFrame->nb_samples);
				frameChanged(QByteArray((char*)out_buffer, m_out_buffer_size));
			}
		}
		else
			printf("avcodec_decode_audio4 %d  sameles = %d  outSize = %d\r\n", ret, m_pFrame->nb_samples, m_out_buffer_size);
	}
	av_free(out_buffer);
	av_free_packet(&packet);
	return 0;
}

三 使用Qt进行播放。

整体的源码已上传至github:https://github.com/cdebug/GBPlayer

效果图如下:

最简单的GB28181视频PS流播放器。

相关标签: gb28181 h264 ps