第二章:ffmpeg和QT开发播放器之初尝试

1、创建工程文件

建立一个新的文件,以后就按照这个工程逐渐修改,成为最终的项目。
       这里需要注意的是需要勾选Multimedia这个多媒体库,才能进行多媒体播放。

                                

       然后base class选择Qwidget

                                

同样的,需要配置输出目录,我们制定到一个地方,这样省得编译调试的时候乱糟糟的,然后将平台工具集选择支持win xp的即可。

                        

然后到安装目录中的Qt\Qt5.8.0\5.8\msvc2013\bin拷贝这四个dll文件到刚刚我们设置的bin文件夹中,运行xplay.exe。是可以看到跳出编译好的窗口的。这样qt部分应该是没问题。

                                               

       接下来就是ffmpe部分的,当然,还是老样子,记得先把include和lib路径添加进来。然后还要设置调试路径和调试控制台。(参考第一章后面几部)编译完之后再运行,就可以出现以下的窗口了。

                            

之后在main.cpp中,添加代码,然后再编译。

#include "xplay.h"
#include <QtWidgets/QApplication>
#pragma comment(lib,"avformat.lib")
extern "C"{
#include <libavformat/avformat.h>
}
int main(int argc, char *argv[])
{
	int totalSec = 0;
	char re = 0;
	av_register_all();
	char *path = "my.mp4";
	AVFormatContext *ic = NULL;

	re = avformat_open_input(&ic, path, 0, 0);
	if (re == 0)
	{
		totalSec = ic->duration / AV_TIME_BASE;
		printf("file totalSec is %d\n", totalSec);
		avformat_close_input(&ic);
	}
	QApplication a(argc, argv);
	Xplay w;
	w.show();
	return a.exec();
}

       这段代码用于测试这个视频的长短。

                        

2、其他

       追加错误信息的打印,这里只做笔记,所以不做过多过程的记录。

if (re != 0)
{
	char buf[1024] = { 0 };
	av_strerror(re, buf, sizeof(buf));
	printf("open failed %s\n",path, buf);
	getchar();
	return -1;
}

av_strerror这个函数是用来储存错误信息的,然后它需要用到#pragma comment(lib,"avutil.lib")这个lib。

for (;;)
{
	re = av_read_frame(ic, &pkt);
	av_packet_unref(&pkt);	//用于清理空间,防止内存泄露。
}

       这里要说一点,读取的一帧视频大小是不固定的,因为这个视频是压缩视频。所以这个av_read_frame会为我们分配空间。

av_packet_unref这个函数是用来清除我们刚刚读取到pkt的数据的,这样做是为了防止内存泄露。然后这个函数需要用到#pragma comment(lib,"avcodec.lib")这个lib。

       

pkt里面有pts和dts

           pts存放的是时间戳,是以AVStream->time_bash作为单位的。这样可以推算出时间的,这个就是一个显示的时间。

           dts是解码时间

       压缩算法有帧类压缩和根据前后对应关系进行压缩这两种。
       对于运动视频,使用帧率压缩效果不咋地,大致就是先压缩成jpg图片再合成视频,这样的视频要么非常大要么效果差。
h264就可以使用根据前后关系对比压缩。根据前一帧、这一帧、下一帧来压缩的,所以就有了关键帧、P帧、B帧。
       关键帧是完整的帧、可以设置为50帧来一个关键帧。


       P帧是根据关键帧来的,P帧是存储与上一帧的变化。

       B帧是存储上一帧与下一帧的变化。

       B帧的出现,就需要考虑到一个问题。

       当前帧要解码就必先读出下一帧,所以就需要缓冲压缩机制,先把下一帧压缩。但是显示的时候不能先显示下一帧,所以就会出现显示帧会与解码帧顺序不对应。

       最终代码写到了现在这个样子
#include "xplay.h"
#include <QtWidgets/QApplication>
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
extern "C"{
#include <libavformat/avformat.h>
}

//为了将pkt.pts转换成秒的函数。
static double r2d(AVRational r)
{
	return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}

int main(int argc, char *argv[])
{
	int totalSec = 0;
	int pts = 0; 
	char re = 0;
	av_register_all();
	char *path = "my.mp4"; 
	AVFormatContext *ic = NULL;
	AVPacket pkt;		//存放读取的数据包

	re = avformat_open_input(&ic, path, 0, 0);

	if (re != 0)
	{
		char buf[1024] = { 0 };

		av_strerror(re, buf, sizeof(buf));

		printf("open failed %s\n",path, buf);
		getchar();
		return -1;
	}

	totalSec = ic->duration / AV_TIME_BASE;		//计算出进度条时间
	printf("file totalSec is %d\n", totalSec);

	for (;;)
	{
		re = av_read_frame(ic, &pkt);
		if (re != 0) break;
		pts = pkt.pts * r2d(ic->streams[pkt.stream_index]->time_base) *1000;
		printf("pts = %d\n", pts);

		av_packet_unref(&pkt);	//用于清理空间,防止内存泄露。
	}
	
	avformat_close_input(&ic);
	
	QApplication a(argc, argv);
	Xplay w;
	w.show();
	return a.exec();
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值