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;
}
涉及三个类
1 样本率 ,样本大小 (比特数位数 16 或者32 )
2 通道数(左右两个)
3 小段字节序列
4 类型
###播放设备
传进一个 QAuFormat
1 QIODevice成功之后 start() 返回一个 类
2 suspend() 挂起 缓冲区还在
3 resum ()
4 bufferSize() 缓冲大小 一般三万个
5 bytesFree() 判断是可以写进去
6 periodSize() 暂时用不到
// 准备好 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 的重复文件