音视频处理FFMPeg开发实战(11) -- 一个简单的播放器

用FFMPeg库实现一个视频播放器,涉及到以下环节:

1、图片格式变换

由于解码出来的图片不一定是需要的格式,由于在界面上显示一般是用位图形式,可能也有第三方的显示库如SDL,不需要转化直接显示各种格式的位图。

图片格式转换,可以用滤镜。本文直接调用sws* 函数进行转换。

初始化SwsContext:


	g_pSwsContext = sws_getContext(g_decoderVideoCodecContext->width, g_decoderVideoCodecContext->height,
		g_decoderVideoCodecContext->pix_fmt,
		g_nWindowWidth, g_nWindowHeight,
		AV_PIX_FMT_RGBA,
		SWS_BICUBIC, NULL, NULL, NULL
		);

	int len = av_image_get_buffer_size(AV_PIX_FMT_RGBA, g_nWindowWidth, g_nWindowHeight, 1);
	g_rgb_buffer = (uint8_t *)av_malloc(len);
	av_image_fill_arrays(g_ConvertedFrame.data,
		g_ConvertedFrame.linesize,
		g_rgb_buffer,
		AV_PIX_FMT_RGBA,
		g_nWindowWidth,
		g_nWindowHeight, 1);

解码后的转换:

int ret = sws_scale(g_pSwsContext,
						(const uint8_t* const*)g_pSrcVideoFrame->data,
						g_pSrcVideoFrame->linesize,
						0,
						g_decoderVideoCodecContext->height,
						g_ConvertedFrame.data,
						g_ConvertedFrame.linesize);
					memcpy(image, g_rgb_buffer, g_ConvertedFrame.linesize[0]*g_nWindowHeight);

2、音频格式变换

由于解码出来的音频格式不一定是需要的格式,也需要转化。也可以用滤镜转换,本文也直接调用Swr类的库函数转换了指定的格式:

如果解码出来的不是AV_SAMPLE_FMT_S16,则调用swr_alloc()和swr_init()初始化一个转换用的SwrContext对象。

	if (fmt != AV_SAMPLE_FMT_S16)
	{
		if (g_pSwrContext)
		{
			swr_free(&g_pSwrContext);
			g_pSwrContext = nullptr;
		}

		int channel_layout = g_inputFormatContext->streams[g_nAudioIndex]->codec->channel_layout;
		int sample_rate = g_inputFormatContext->streams[g_nAudioIndex]->codec->sample_rate;
		g_pSwrContext = swr_alloc();
		av_opt_set_int(g_pSwrContext, "in_channel_layout", channel_layout, 0);
		av_opt_set_int(g_pSwrContext, "out_channel_layout", channel_layout, 0);
		av_opt_set_int(g_pSwrContext, "in_sample_rate", sample_rate, 0);
		av_opt_set_int(g_pSwrContext, "out_sample_rate", sample_rate, 0);
		av_opt_set_sample_fmt(g_pSwrContext, "in_sample_fmt", fmt, 0);
		av_opt_set_sample_fmt(g_pSwrContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
		swr_init(g_pSwrContext);
	}

解码后的格式转换:

if (g_pSwrContext)
{
	int srcNbSamples = g_pSrcAudioFrame->nb_samples;
	int srcRate = g_inputFormatContext->streams[g_nAudioIndex]->codec->sample_rate;
	int dstRate = srcRate;
	int dstNbSamples = av_rescale_rnd(srcNbSamples, dstRate, srcRate, AV_ROUND_UP);
	AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16;
	int64_t channel_layout = g_inputFormatContext->streams[g_nAudioIndex]->codec->channel_layout;
	int dstNbChannels = av_get_channel_layout_nb_channels(channel_layout);
	dstNbChannels = dstNbChannels > 0 ? dstNbChannels : 1;
	int ret = av_samples_alloc_array_and_samples(&dst_data, &dstLinesize, dstNbChannels, dstNbSamples, dst_sample_fmt, 0);

	ret = swr_convert(g_pSwrContext, dst_data, dstNbSamples, (const uint8_t **)g_pSrcAudioFrame->data, srcNbSamples);

	memcpy(g_audio_data_buffer + nAudioBufferIndex, *dst_data, dstLinesize);
	nAudioBufferIndex += dstLinesize;
	av_freep((void*)&dst_data[0]);
					audio = 1;
}

3、播放时音视频同步

本例中以音频时间去同步视频,由于人对音频更敏感,视频不太敏感。

4、工程源码下载:

本例在Debug – x86下编译成功
附带开发环境,本例仅是学习探讨FFPMEG库函数,其中还有不太完善地方需要改进。

下载源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值