C ++/Qt实现播放器三天

音视频的基本知识

1、MPEG -4 是一套用于音频你、视频得信息压缩编码软件
2、 FFmpeg 常用封装格式
AVI 压缩标准可任意选择
FLV TS 流媒体格式
ASF
MP4 格式
3、 FFmpg 编码格式 H264 (AVC PART10) , WMV
XVID (Part2) ,mjpeg
音频 aac MP3 ape flac
在这里插入图片描述
4 Qt 准备
开发环境配置
这里选择 VS2019 和 Qt 5.12

第二天

5 f’fmpeg SDK 软硬件解码基础
有以下几点 解封装、软件解码、像素格式转换
重采样、pts/sts、同步策略

解封装 接口

av_register_all() // 注册
avformat_network_init() //网络摄像头
avformat_open_input() // 打开视频
avfaormat_find_stream_info() // 查找信息之前版本信息等
av_find_best_stream() // 查找视频音频流
三个结构体
AVRormatContext // 上下文信息
AVStream // 音频视频流
AVPacket // 解封装后得数据包

确保 已经注册
在这里插入图片描述声明被否决问题
参考链接 https://blog.csdn.net/qq_34732729/article/details/104830063?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2

AVFormatContext 结构体 常用内容

在这里插入图片描述
AVStream
AVRation time_base (分数)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
pkt 不能为NULL
AVPacket 结构群体
在这里插入图片描述
在这里插入图片描述
拖动到相应的位置 (视频 或者音频 问题)
av_seek_frame 函数
flag 解决问题
在这里插入图片描述
在这里插入图片描述

解码部分

1 不同数据要用不同解码器
(1)注册解码器
avcode_register_all();
(2) 硬解码
在这里插入图片描述
解码还需要上下文 需要AVCodecContext(新版本需要创建)
在这里插入图片描述
开始一帧一帧的
AVFrame 结构体
AVFrame *frame=av_frame_alloc(); 分配内存
void av_frame_frame(AVFrame ** frame);
int av_frame_ref(AVFrame *dst ,const AVFrame * src)
在这里插入图片描述
在这里插入图片描述
接封装有一个上下文 ,解码有一个上下文
此上下文 贯穿整个过程
AVPacket 放在缓存中(应用记数 +1 、-1 )
send 只负责 把数据写到队列中 (结尾发一个 None)
在这里插入图片描述
传同一个对象 会先删除然后再进行操作 不会溢出
receive 一次会收多个 所以要 for 循环
音频视频解码是分开新版本的

视频像素和尺寸转换

sws_getContext 像素上下文
在这里插入图片描述
flag 的 插值 补充方式 根据矩阵来算(只要指尺寸的斌变换)

// 成功之后进行转换
				if (vctx)
				{   
					// 申请空间分配字节的大小  不考虑对齐问题  (直接宽*高=像素个数 ,每个像素4 个字节 32为)
					if (!rgb) rgb = new unsigned char[frame->width * frame->height * 4];
					uint8_t* data[2] = { 0 };
					data[0] = rgb;
					int lines[2] = { 0 };
					lines[0] = frame->width * 4;  // 一行的字节数 
					re = sws_scale(vctx,     // 返回值为高度
						frame->data,		//输入数据
						frame->linesize,	//输入行大小
						0,                  // 切片从0开始
						frame->height,		//输入高度
						data,				//输出数据和大小
						lines
					);
					cout << "sws_scale = " << re << endl;
				}

音频的重采样

都有一个上下文 (因为是基于C语言的)
在这里插入图片描述
在这里插入图片描述

基于Qt 的音频录制

涉及三个类

参数设置

在这里插入图片描述
1 样本率 ,样本大小 (比特数位数 16 或者32 )
2 通道数(左右两个)
3 小段字节序列
4 类型
###播放设备
在这里插入图片描述
传进一个 QAuFormat
1 QIODevice成功之后 start() 返回一个 类
在这里插入图片描述
2 suspend() 挂起 缓冲区还在
3 resum ()
4 bufferSize() 缓冲大小 一般三万个
5 bytesFree() 判断是可以写进去
6 periodSize() 暂时用不到

测试pcm 文件

// 准备好 pcm 数据
// ffmpeg -i test.mp4 -f s16e out.pcm

QAudioFormat fmt;
	//程序例子
	fmt.setSampleRate(44100);
	fmt.setChannelCount(2);
	fmt.setSampleSize(16);
	fmt.setCodec("audio/pcm");
	fmt.setByteOrder(QAudioFormat::LittleEndian); //小端口模式
	fmt.setSampleType(QAudioFormat::UnSignedInt);

Qt openGl 编程
在这里插入图片描述
为什么 用QOpen’GLWidget
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
转换 是固定的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include "XVideoWidegt.h"
#include "qdebug.h"

//自动加双引号
#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4

FILE* fp = NULL;

//顶点shader
const char* vString = GET_STR(
	attribute vec4 vertexIn;
	attribute vec2 textureIn;
	varying vec2 textureOut;  // 顶点和片元共享
	void main(void)
	{
		gl_Position = vertexIn;
		textureOut = textureIn;
	}
);


//片元shader
const char* tString = GET_STR(
		varying vec2 textureOut;
	uniform sampler2D tex_y;   // uniform  内存访问的
	uniform sampler2D tex_u;
	uniform sampler2D tex_v;
	void main(void)
	{
		vec3 yuv;
		vec3 rgb;
		yuv.x = texture2D(tex_y, textureOut).r;
		yuv.y = texture2D(tex_u, textureOut).r - 0.5;
		yuv.z = texture2D(tex_v, textureOut).r - 0.5;
		rgb = mat3(1.0, 1.0, 1.0,
			0.0, -0.39465, 2.03211,
			1.13983, -0.58060, 0.0) * yuv;   // 矩阵转换 公式固定
		gl_FragColor = vec4(rgb, 1.0);
}

);




// 准备yuv  数据

// ffmpeg -i test.1080.mp4 -t 10 -s 240x128 -pix_fmt_yuv yuv420p qout240x128.yuv 
XVideoWidegt::XVideoWidegt(QWidget *parent)
	: QOpenGLWidget(parent)
{
}
XVideoWidegt::~XVideoWidegt()
{
}




// 初始化gl
void XVideoWidegt::initializeGL()
{
	qDebug() << "initializeGL";

	//初始化opengl (QOpenGLFunctions 继承的) 函数

	initializeOpenGLFunctions();

	// program(在类中先创建对象) 加载shader 脚本 采用qt 封装的方法

	// program 加载shader (顶点和片元) 脚本

	/*
	// 片元(像素)
	program.addShaderFromSourceCode(QGLShader::Fragment,);
	// 顶点
	program.addShaderFromSourceCode(QGLShader::Vertex,);*
	*/



	qDebug() << program.addShaderFromSourceCode(QGLShader::Fragment, tString);
	//顶点shader
	qDebug() << program.addShaderFromSourceCode(QGLShader::Vertex, vString);
	
	//设置顶点坐标的 标量
	program.bindAttributeLocation("vertexIn", A_VER);
	//设置材质坐标
	program.bindAttributeLocation("textureIn", T_VER);

	// 编译shader 
	qDebug()<<"program.link()="<<program.link();

	// 绑定让 shader和opengl 关联起来 
	qDebug() << "program.bind()=" << program.bind();


	// 传递顶点和材质坐标

	//顶点 
	static const GLfloat ver[] = {
		-1.0f,-1.0f,
		1.0f,-1.0f,
		-1.0f, 1.0f,
		1.0f,1.0f
	};
	//材质
	static const GLfloat tex[] = {
		0.0f, 1.0f,
		1.0f, 1.0f,
		0.0f, 0.0f,
		1.0f, 0.0f
	};

	//顶点
	glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
	glEnableVertexAttribArray(A_VER);

	//材质
	glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
	glEnableVertexAttribArray(T_VER);

	//从shader 获取材质
	unis[0] = program.uniformLocation("tex_y");
	unis[1] = program.uniformLocation("tex_u");
	unis[2] = program.uniformLocation("tex_v");

	//创建材质
	glGenTextures(3, texs);
	//Y
	glBindTexture(GL_TEXTURE_2D, texs[0]);
	//放大过滤,线性插值
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//创建材质显卡空间
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	//U
	glBindTexture(GL_TEXTURE_2D, texs[1]);
	//放大过滤,线性插值
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//创建材质显卡空间
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	//V
	glBindTexture(GL_TEXTURE_2D, texs[2]);
	//放大过滤,线性插值
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//创建材质显卡空间
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	///分配材质内存空间
	datas[0] = new unsigned char[width * height];		// Y
	datas[1] = new unsigned char[width * height / 4];	//U
	datas[2] = new unsigned char[width * height / 4];	//V
	
	fp = fopen("out240x128.yuv", "rb");
	if (!fp)
	{
		qDebug() << "out 240x128.yuv file open  failed";
	}
}

// 刷新显示 
void XVideoWidegt::paintGL()
{
	if (feof(fp))  // 如果到了结尾
	{
		fseek(fp, 0, SEEK_SET); //  //到了结尾 移动到开始
	}

	fread(datas[0], 1, width * height, fp); //读入到缓冲区
	fread(datas[1], 1, width * height/4, fp); //读入到缓冲区
	fread(datas[2], 1, width * height/4, fp); //读入到缓冲区
    
	// 显示方法
	// 激活texture
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, texs[0]);  // 0层绑定到绑定y材质中
	// 修改材质内容(复制内存的内容)
	glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_RED,GL_UNSIGNED_BYTE,datas[0]);
	//与shader uni关联起来
	glUniform1i(unis[0], 0);

	glActiveTexture(GL_TEXTURE0+1);
	glBindTexture(GL_TEXTURE_2D, texs[1]);  // 0层绑定到绑定U材质中
	// 修改材质内容(复制内存的内容)
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height/2, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
	//与shader uni关联起来
	glUniform1i(unis[1], 1);

	glActiveTexture(GL_TEXTURE0+2);
	glBindTexture(GL_TEXTURE_2D, texs[2]);  // 0层绑定到绑定V材质中
	// 修改材质内容(复制内存的内容)
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height/2, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
	//与shader uni关联起来
	glUniform1i(unis[2], 2);
	

	//显示 (画三角想 从 0下标开始 画四个顶点)
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	qDebug() << "paintGL";
}

// 窗口尺寸变化
void XVideoWidegt::resizeGL(int width, int height )
{
	qDebug() << "resizeGL" << width << ":" << height;
} 

第三天

错误

 ## 傻逼了   在头文件放置了 cpp 的重复文件

在这里插入图片描述
在这里插入图片描述
##错误2 在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值