播放器
文章平均质量分 72
很难绷得住
点波关注不迷路
展开
-
播放器实战28 总结
至此,播放器的基本功能已经实现需要注意的点:1.对于多个进程共享变量要加锁,即使是一句C++语句在汇编中也是很多句,若两个线程同时访问一个变量可能会造成问题2.要进行差错控制3.在vs中切换成release模式,并在项目中添加头文件与库文件,在运行后生成.exe文件首先介绍一下静态库(静态链接库)、动态库(动态链接库)的概念,首先两者都是代码共享的方式。静态库:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷原创 2022-03-04 17:48:00 · 335 阅读 · 0 评论 -
播放器实战27 完成seek到指定位置
关于if (vt->RepaintPts(pkt, seekPts)):根据seek到的pts与实际想要的pts来判断是等待还是直接绘制等待时RepaintPts返回false,然后进入下次while绘制后RepaintPts返回true,然后更新当前的pts关于暂停:不管seek前视频是否为播放状态,则seek前统一暂停,不然如果正在播放的话解封装线程在seek,其他线程仍然在做解码,会出问题。如果seek前为播放状态,则seek结束后恢复播放,如果seek前为暂停状态,则seek结束后仍暂停原创 2022-03-01 21:36:56 · 1079 阅读 · 0 评论 -
播放器实战26 添加暂停
可能缓冲队列未播完,造成了音频播放停止的延迟,然后当if (audioplay->Getfree() < size):当缓冲中空余的空间小于需要使用的空间时等待一秒再continue(就不往播放器里写音频数据了)如果当不小时,即使isPause=true也会继续往里面写,因此把判断暂停也加进去:if (audioplay->Getfree() < size||isPause)再将音频线程中暂时设置的加锁取消掉,目的是早点停掉音频播放,并且isPause通过人为控制,只有两个状态,去锁了一般也不会造原创 2022-03-01 18:39:31 · 462 阅读 · 0 评论 -
播放器实战25 添加滑动条与窗口变化
当前解码到的pts除以总pts,是个比例,用该比例乘上进度条总长度获得一个值,用该值**传回进度条获得当前的播放位置**,并不能实现拖拽功能在xplay的构造函数中添加定时器原创 2022-02-28 22:21:26 · 311 阅读 · 0 评论 -
播放器实战24 解封装模块添加close
1.vt与at是解封装线程来调用的,因为解封装线程要负责来清理vt与at2.为了防止指针删到一半,然后其他线程突然来使用删掉的指针指针造成bug,因此要将这四句加锁3.我们在删除一个指针之后,编译器只会释放该指针所指向的内存空间,而不会删除这个指针本身,因此还要将这些new出来的指针置null对于vt与at的close来说,它们有大部分功能都是一样的,因此把一样的功能放在他们的共同基类xdecodethread中:原创 2022-02-27 22:30:23 · 1918 阅读 · 0 评论 -
播放器实战23 解码线程
对于视频线程和音频线程来说其中有很多一模一样的内容,比如用于存放pkt的队列,最大数量,解码器,push,pop等,故将他们抽象出来做为一个基类(xdecodethread),让视频线程和音频线程继承这个类,便可以使用这些共有的成员:原创 2022-02-26 23:33:12 · 2017 阅读 · 0 评论 -
播放器实战22 解决花屏与卡顿问题
引入stridestride:指在内存中每行像素所占的空间。为了实现内存对齐每行像素在内存中所占的空间并不一定是像素的宽度,可能要在每行末尾加一些字节的数据来做内存对齐查看ffmpeg结构体AVFrame中的三个成员:01.uint8_t *data[AV_NUM_DATA_POINTERS];data存储原始的音视频数据(视频为YUV,音频为PCM)。有两种存储音视频的方式,plannar方式和packet方式plannar方式:通道n的数据分别存储在data[n]中;拿YUV视频来说,就是d原创 2022-02-21 22:08:02 · 3699 阅读 · 0 评论 -
播放器实战21 解封装线程
1.在open中打开音频线程与视频线程2.当主函数调用解码线程的run时会调用xdemuxthread::start(),在该函数中调用音频线程的run与视频线程的run3.在run中通过读封装获得packet,判断其类型,若是视频则push给视频线程的队列,若是音频则push给音频线程的队列原创 2022-02-19 11:41:21 · 276 阅读 · 0 评论 -
播放器实战20 音频线程与视频线程
以音频线程为例,解封装模块调用音频线程模块,音频线程模块模块将声音播放模块,解码模块,重采样模块结合起来,用音频线程模块去调用其他模块。1.当isexit为false时,进入循环,队列为空或者没有初始化成功则解锁该线程,等待数据或者初始化,等1秒再判断一次2.当队列非空并且初始化成功之后,从队列头部弹出一个packet发给解码线程3. 可能一次send多次receive,因此一次send之后当调用析构函数使isexit=false之后或者 adecode->receive()将解码队列读干净后才进入到下原创 2022-02-19 11:15:29 · 934 阅读 · 0 评论 -
播放器实战19 Xaudio打开音频
含有纯虚函数的类被称为抽象类。抽象类只能作为派生类的基类,不能定义对象,但可以定义指针。在派生类实现该纯虚函数后,定义抽象类对象的指针,并指向或引用子类对象。1)在定义纯虚函数时,不能定义虚函数的实现部分;2)在没有重新定义这种纯虚函数之前,是不能调用这种函数的。 抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现**动态多态性**。继承于抽象类的派生类如果不能实现基类中所有的纯虚函数,那么这个派生类也就成了抽象类。因为它继承了基类的抽象函数,只要含有原创 2022-02-13 22:28:29 · 1177 阅读 · 0 评论 -
播放器实战18 xresample
re为swr_convert的返回值:每个通道的样本数量return number of samples output per channel, negative value indata->channels:为通道数av_get_bytes_per_sample:为每个采样的比特数,即该格式(S16)所占空间大小(16位即两比特)他们相乘即为每个音频通道的比特数将此相乘的结果用在音频播放中(判断该结果与剩余缓存空间哪个大,如果剩余缓存空间大的话则可以播放)原创 2022-02-13 17:37:28 · 735 阅读 · 0 评论 -
播放器实战17 xvideowidget
因为创建材质也用到高和宽,所以也放到这个接口中创建材质显卡空间要用到tex,删除也会删tex,为了防止用到一半被删掉导致程序宕掉,加个锁,其他函数用到data与tex的也要加锁,对于repaint()这种频繁出现的,要注意加锁的代码量,会影响性能,对于init这种只出现一次的无所谓原创 2022-02-09 16:54:50 · 3870 阅读 · 0 评论 -
播放器实战16 xdecode类
音频与视频解封装用一个同一个类,解码各用各的类,因此实例化了两个decode,以视频解码器为例:01.先实例化:xdecode vdecode;02.再将解封装获得的视频参数复制一份,做为参数传给vdecode:vdecode.open(demux.CopyVPara())原创 2022-02-06 00:42:04 · 1188 阅读 · 0 评论 -
播放器实战15 xdemux与avcodecparameters
读和打开不能同时进行,ic在读时初始化,若读一半ic变了的话会发生错误 if (!ic)//打开的话ic是0,否则是1做容错,虽然在main函数中看起来是read在初始化之后被调用,但假如初始化很慢,会多进程调用read,这时候ic就是空的原创 2022-02-03 12:42:47 · 1416 阅读 · 0 评论 -
播放器实战14 显示YUV
设置顶点坐标与材质坐标的变量 使用bindAttributeLocation来设置变量在着色器程序中参数列表的索引。(A_VER与T_VER都是经过宏定义的整型)vertexIn为shader中的,OpenGL并不认识,因此这里将vertexIn与索引A_VER绑定,后面往OpenGL写顶点坐标或者材质坐标时往A_VER或者T_VER里传就行了,比如:glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);原创 2022-01-25 01:32:25 · 494 阅读 · 0 评论 -
播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge
QOpenGLFunctions 类提供了跨平台的OpenGl ES2.0 API版本。OpenGL 2.0 提供了OpenGL中的子类集合,可以提供跨多个平台的桌面系统以及嵌入式OpenGL的实现。然而,却很难使用子类因为子类需要解决许多平台系统的操作问题。因此 QOpenGLFunctions提供了这样的API,可以保证在所有的OpenGL系统中使用, 并且也关注不同系统中的OpenGL的版本API的使用。Qt推荐直接继承的方式来使用 QOpenGLFunctions类,就不用把库引用进来了原创 2022-01-24 01:03:41 · 3029 阅读 · 0 评论 -
播放器实战12 QT播放音频
out->periodSize()为传入数据的大小 当缓冲区的空余大小小于一次放入的数据大小时,进入等待,等到缓冲区中多余的数据被播放了留出足够的空间了再往缓冲区放数据 ,用如下语句判断 if (out->bytesFree() < size) int len=fread(buf, 1, size, fp);将fp指向的PCM数据读到buf中 用buf做为媒介连接QT与原文件 io->write(buf, len);//将重采样后的PCM传给QT,才开始真正播放原创 2022-01-20 22:16:51 · 2266 阅读 · 0 评论 -
播放器实战11 音频重采样
和像素格式和尺寸转换步骤一样分为三步,但具体API不太一样1.创建一个pcm用于指向重采样后的音频数据的空间创建一个音频重采样上下文actx并用swr_alloc()分配空间unsigned char* pcm = NULL; SwrContext* actx = swr_alloc();2.音频重采样上下文初始化 actx = swr_alloc_set_opts( actx, av_get_default_channel_layout(2),//输出格式 AV_SAMPL原创 2022-01-19 17:45:19 · 657 阅读 · 0 评论 -
播放器实战 10 像素格式与尺寸的转换
在遍历每个packet的receive的循环中使用sws_getCachedContext先判断解码器上下文是否是视频,只有视频帧才能使用格式与尺寸转换,**该函数是对上下文变量vctx的初始化,里面存放了像素格式与尺寸转换的信息,在sws_scale()中才进行真正的转化,**原创 2022-01-19 16:05:28 · 1314 阅读 · 0 评论 -
播放器实战09 send packet与receive frame
在前面打开解码器操作时通过AVCodecContext* ac = avcodec_alloc_context3(acodec);创建了音频解码器上下文ac与视频解码器上下文vc,这里想创建一个解码器上文类型的值,但在后面才知道指向的是音频还是视频,这里先用ac表示并先初始化为0.原创 2022-01-15 17:24:35 · 493 阅读 · 0 评论 -
播放器实战08 打开AVCODEC
///02找视频解码器, const AVCodec *vcodec=avcodec_find_decoder(ic->streams[videoindex]->codecpar->codec_id); if (!vcodec) { cout << "can't find the codec id" << ic->streams[videoindex]->codecpar->codec_id << endl; getch.原创 2022-01-10 21:02:36 · 763 阅读 · 0 评论 -
播放器实战07 av_read_frame与av_seek_frame
读出当前流数据,并存于AVPacket包中,如果当前流为视频帧,则只读出一帧,如果当前流为音频帧,根据音频格式读取固定的数据。读取成功 流数据自动指向下一帧,因此不需要一个变量来遍历所有帧如果AVPacket包内存为空 读取失败,则读取无效,等待 av_read_frame()或者avformat_close_input()处理av_seek_frame(ic, videoStream, seek_pos, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME)av_原创 2022-01-09 19:40:03 · 2015 阅读 · 0 评论 -
播放器实战06 AV_stream
1.该结构体简介AVStream在FFmpeg使用过程中关于编解码至关重要的结构体之一,是对流(Stream)的封装和抽象,描述了视频、音频等流的编码格式等基本流信息。此外也是音频、视频、字母数据流的重要载体。对于一个典型的mp4格式的媒体源来说,需要经过解封装(解复用),解码然后输出的过程。而解封装从容器中分离出来的流,在FFmpeg中对应的对象就是AVStream。解复用解出来几条AVStream,就会在AVFormateContext中的nb_streams+1(总流数+1),并且将AVStrea原创 2022-01-06 13:17:34 · 1927 阅读 · 0 评论 -
播放器实战05 avformat_find_stream_info探测获取封装上下文的格式信息并打印
1.这个函数做了什么?avformat_find_stream_info主要是读一些包(packets ),然后从中提取出流的信息。有一些文件格式没有头,比如说MPEG格式的,这个时候,这个函数就很有用,因为它可以从读取到的包中获得到流的信息。在MPEG-2重复帧模式的情况下,该函数还计算真实的帧率。2.代码#include<iostream>extern "C"{#include "libavformat/avformat.h" //头文件不仅要在项目中鼠标点击配置,在代码中也要原创 2021-12-31 18:29:42 · 504 阅读 · 1 评论 -
播放器实战04 av_format打开MP4文件
注意,在源文件中添加cpp代码后在项目属性中才会出现C/C++,随后添加ffmpeg库。在项目属性中选择debug,X64的话代码上方的配置也要这么选(win32指的是32位,我们的ffmpeg库下载的是64位的,不兼容)2.代码做了什么?先设置视频文件路径,再进行参数设置,网络库初始化,设置一个解封装上文类型指针IC,再打开我们的多媒体文件,并开辟一个空间用于存放相关的信息,并将IC指向该空间最后如果打开失败则打印failed,成功则打印success————————————————版原创 2021-12-30 11:15:29 · 1233 阅读 · 0 评论 -
播放器实战03 qmake与pro
qmake介绍:qmake是创建出来用于为不同的平台和编译器书写Makefile的工具。手写Makefile是比较困难并且容易出错的,尤其是需要给不同的平台和编译器组合写几个Makefile。使用qmake,开发者创建一个简单的项目文件并且运行qmake生成适当的Makefile。qmake会注意所有的编译器和平台的依赖性,可以把开发者解放出来只关心他们的代码。——qmake用户手册qmake使用:qmake使用存储在项目(.pro)文件中的信息来决定Makefile文件中该生成什么。一个基本的项目文原创 2021-12-22 20:40:12 · 1821 阅读 · 0 评论 -
播放器实战02
#pragma comment(lib,"avcodec.lib")表示链接avcodec.lib这个库。和在工程设置里写上链入avcodec.lib的效果一样(两种方式等价,或说一个隐式一个显式调用),不过这种方法写的 程序别人在使用你的代码的时候就不用再设置工程settings了。告诉连接器连接的时候要找avcodec.lib,这样你就不用在linker的lib设置里指定这个lib了。3.在附加包含目录处选择ffmpeg库中的头文件原创 2021-12-21 19:24:30 · 427 阅读 · 0 评论 -
播放器实战01
MPEG系列的标准归属于ISO/IEC,但另一方面以制订国际通讯标准为主的机构:ITU-T,在完成H.263(针对视频会议之用的串流视频标准)后展开了更先进的H.264制订,且新制订是与ISO/IEC机构连手合作,由两机构共同成立一个名为JVT(Joint Video Team)的联合工作小组,以MPEG-4技术为基础进行更适于视频会议(Video Conference)运用的衍生发展,也因为是联合制订,因此在ITU-T方面称为H.264,在ISO/IEC的MPEG方面就称为MPEG-4 Part 10(第原创 2021-10-18 17:00:27 · 219 阅读 · 0 评论