在Visual Studio 2010[VC++]中使用ffmpeg类库



在Visual Studio 2010[VC++]中使用ffmpeg类库

1,准备工作

很多播放器都使用了ffmpeg这个类库来编解码,使用没有关系,但总是有些人不守规则。在耻辱榜上我看到了腾讯(QQPlayer),还有另一家深圳的公司。

image

我对GPL协议也不太了解,issue tracker中显示QQPlayer需要提供完整项目代码。我的疑问是:

如果是QQPlayer。其中集成了QQ的一些登陆模块,但这些代码不方便公开。但Player相关的代码已经公开。这样违反GPL吗?

NOTE:下文中DLL或LIB(大写指文件即avcodec.dll,avcodec.lib.etc.),dll或lib(小写,指目录)。

继上篇在MinGW中编译ffmpeg之后,我们便可以得到一些LIB和DLL,我们可以使用这些LIB和DLL来使用ffmpeg的相关功能函数。

image

其中头文件在include目录下,LIB及DLL在bin目录下。其实这些LIB并不是传统的静态库文件(真正的静态库文件是在lib目录下的*.a文件),他们是dll的导出文件。

 

另外,C99中添加了几个新的头文件,VC++中没有,所以需要你自己下载。并放至相应目录。对于VS2010来说通常是:C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include。

 

2,示例代码

网上的ffmpeg的示例代码大多过时了,在2009年初img_convert这个函数被sws_scale取代了,所以可能你从网上找到的示例代码并不可以运行(但代码运作原理还是一样的)。

我这里贴出一份当前可以运行的代码。

// ffmpeg-example.cpp : Defines the entry point for the console application.
//


#include "stdafx.h"

#define inline _inline
#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif

#ifdef __cplusplus
extern "C" {
#endif
	/*Include ffmpeg header file*/
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif

#include <stdio.h>


static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame);

int main (int argc, const char * argv[])
{
	AVFormatContext *pFormatCtx;
	int             i, videoStream;
	AVCodecContext  *pCodecCtx;
	AVCodec         *pCodec;
	AVFrame         *pFrame; 
	AVFrame         *pFrameRGB;
	AVPacket        packet;
	int             frameFinished;
	int             numBytes;
	uint8_t         *buffer;

	// Register all formats and codecs
	av_register_all();

	// Open video file
	if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
		return -1; // Couldn't open file

	// Retrieve stream information
	if(av_find_stream_info(pFormatCtx)<0)
		return -1; // Couldn't find stream information

	// Dump information about file onto standard error
	dump_format(pFormatCtx, 0, argv[1], false);

	// Find the first video stream
	videoStream=-1;
	for(i=0; i<pFormatCtx->nb_streams; i++)
		if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
		{
			videoStream=i;
			break;
		}
		if(videoStream==-1)
			return -1; // Didn't find a video stream

		// Get a pointer to the codec context for the video stream
		pCodecCtx=pFormatCtx->streams[videoStream]->codec;

		// Find the decoder for the video stream
		pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
		if(pCodec==NULL)
			return -1; // Codec not found

		// Open codec
		if(avcodec_open(pCodecCtx, pCodec)<0)
			return -1; // Could not open codec

		// Hack to correct wrong frame rates that seem to be generated by some codecs
		if(pCodecCtx->time_base.num>1000 && pCodecCtx->time_base.den==1)
			pCodecCtx->time_base.den=1000;

		// Allocate video frame
		pFrame=avcodec_alloc_frame();

		// Allocate an AVFrame structure
		pFrameRGB=avcodec_alloc_frame();
		if(pFrameRGB==NULL)
			return -1;

		// Determine required buffer size and allocate buffer
		numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
			pCodecCtx->height);

		//buffer=malloc(numBytes);
		buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

		// Assign appropriate parts of buffer to image planes in pFrameRGB
		avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
			pCodecCtx->width, pCodecCtx->height);

		// Read frames and save first five frames to disk
		i=0;
		while(av_read_frame(pFormatCtx, &packet)>=0)
		{
			// Is this a packet from the video stream?
			if(packet.stream_index==videoStream)
			{
				// Decode video frame
				avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, 
					packet.data, packet.size);

				// Did we get a video frame?
				if(frameFinished)
				{
					static struct SwsContext *img_convert_ctx;

#if 0
					// Older removed code
					// Convert the image from its native format to RGB swscale
					img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, 
						(AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, 
						pCodecCtx->height);

					// function template, for reference
					int sws_scale(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY,
						int srcSliceH, uint8_t* dst[], int dstStride[]);
#endif
					// Convert the image into YUV format that SDL uses
					if(img_convert_ctx == NULL) {
						int w = pCodecCtx->width;
						int h = pCodecCtx->height;

						img_convert_ctx = sws_getContext(w, h, 
							pCodecCtx->pix_fmt, 
							w, h, PIX_FMT_RGB24, SWS_BICUBIC,
							NULL, NULL, NULL);
						if(img_convert_ctx == NULL) {
							fprintf(stderr, "Cannot initialize the conversion context!\n");
							exit(1);
						}
					}
					int ret = sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, 
						pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
#if 0 
					// this use to be true, as of 1/2009, but apparently it is no longer true in 3/2009
					if(ret) {
						fprintf(stderr, "SWS_Scale failed [%d]!\n", ret);
						exit(-1);
					}
#endif
					// Save the frame to disk
					if(i++<=5)
						SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
				}
			}

			// Free the packet that was allocated by av_read_frame
			av_free_packet(&packet);
		}

		// Free the RGB image
		//free(buffer);
		av_free(buffer);
		av_free(pFrameRGB);

		// Free the YUV frame
		av_free(pFrame);

		// Close the codec
		avcodec_close(pCodecCtx);

		// Close the video file
		av_close_input_file(pFormatCtx);

		return 0;
}

static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
	FILE *pFile;
	char szFilename[32];
	int  y;

	// Open file
	sprintf(szFilename, "frame%d.ppm", iFrame);
	pFile=fopen(szFilename, "wb");
	if(pFile==NULL)
		return;

	// Write header
	fprintf(pFile, "P6\n%d %d\n255\n", width, height);

	// Write pixel data
	for(y=0; y<height; y++)
		fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

	// Close file
	fclose(pFile);
}

 

显示代码中有几个地方需要注意一下。就是开头的宏定义部分。第一个是C99中添加了inline关键字,第二个是对ffmpeg头文件中INT64_C的模拟(可能也是为了解决与C99的兼容问题)。第三个是使用extern C在C++代码中使用C的头文件。

 

3,设置Visual Studio

在你编译,调用上面的代码之前你还要在Visual Stuido中做相应的设置,才可以正确引用ffmpeg的库。

3.1 设置ffmpeg头文件位置

右击项目->属性,添加Include文件目录位置:

image

 

3.2 设置LIB文件位置

image

 

3.3 设置所引用的LIB文件

image

 

如果一切正常,这时你便可以编译成功。

 

4,可能出现的问题

4.1 运行时出错

虽然你可以成功编译,但你F5,调试时会出现以下错误。

image

原因是,你虽然引用了LIB文件,但这并不是真正的静态库文件,而是对DLL的引用,所以当你调用ffmpeg库函数时,需要DLL文件在场。你可以用dumpbin(VS自带工具)来查看你生成的exe中引用了哪些DLL文件。你在命令行输入:

>dumpbin ffmpeg-example.exe /imports

你可以从输出中看出你实际引用以下几个的DLL文件。

avcodec-52.dll 
avformat-52.dll 
swscale-0.dll 
avutil-50.dll 

 

还有些朋友可能想将ffmpeg库进行静态引用,这样就不需要这些DLL文件了。这样做是可行的,但是不推荐的。

 

4.2 av_open_input_file失败

在VS的Command Argumetns中使用全路径。

image

Visual Studio使用FFmpeg DLL进行硬件加速,主要是为了在视频处理、播放或编码时利用GPU的能力来提高性能。FFmpeg是一个非常强大的多媒体框架,支持众多的编码和解码格式。硬件加速可以通过FFmpeg的硬件加速编解码器接口来实现,例如使用NVENC、VA-API等硬件加速API。 以下是使用FFmpeg DLL进行硬件加速的基本步骤: 1. 确保你有支持硬件加速的FFmpeg版本,该版本包含了相应的硬件加速,如nvidia-encode.dll(对于NVENC)。 2. 在你的项目配置FFmpeg DLL,确保所需的硬件加速(如nvidia-encode.dll)被包含在项目,并在运行时能够被正确加载。 3. 初始化FFmpeg硬件加速模块。这通常涉及到设置编码器或解码器的硬件加速选项,并提供必要的硬件上下文。 4. 在编码或解码时,使用硬件加速选项来指导FFmpeg使用GPU进行操作。 5. 通过适当的错误检查和资源管理,确保在处理完视频后正确释放所使用的硬件加速资源。 示例代码(以C++为例): ```cpp extern "C" { #include <libavcodec/avcodec.h> #include <libavcodec/nvenc.h> } // 初始化NVENC硬件加速编码器 void initializeNVENC(AVCodecContext* codecContext) { // 检查是否支持NVENC if (!avcodec_find_encoder_by_name("h264_nvenc")) { // 报错处理 } // 设置编码器的硬件加速相关参数 codecContext->hwaccel = av_hwaccel_find codec("cuda"); codecContext->hwaccel_context = NULL; // 其他编码器配置... // 打开硬件加速编解码器 if (avcodec_open2(codecContext, avcodec_find_encoder_by_name("h264_nvenc"), NULL) < 0) { // 报错处理 } } // 在适当的位置调用initializeNVENC函数 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值