## 一、前言说明
推流组件写了这么久,主要都是推720P/1080P/2K这种分辨率的,现在突然间来了用户需要8K,一开始心里没底,后面试了下效果,远超预期好的一逼,CPU资源占用居然是0%,你说谁看到了不震惊,毕竟分辨率摆在这里,你要想想用播放器去播放器8K的文件,动不动就99%的占用,而且很多人电脑都根本无法播放8K,一打开就卡死。为什么推流这里可以做到这么低的资源占用呢?主要得益于之前做的一个策略处理,那就是如果源头是264/265流,直接不用解码就可以推流,通过av_read_frame取出来的avpacket包直接转发出去即可,完全不用解码,这样就不涉及到资源占用,而写入那边基本上的压力都在网络带宽,如果是写入文件则压力在磁盘写入的速度。
我在推流组件的开发上投入了不少时间,一直以来主要处理的都是 720P、1080P、2K 这类分辨率的推流需求,对于 8K 推流,起初心里确实没什么底。但当我们实际尝试后,效果却远超预期,好到让人惊喜。最让人震惊的是,8K 推流时 CPU 资源占用居然能达到 0%。要知道,用播放器播放 8K 文件时,CPU 占用动不动就飙升到 99%,而且很多电脑根本无法承受 8K 播放的压力,一打开就会卡死。那为什么推流在 8K 分辨率下能做到这么低的资源占用呢?这主要得益于我们之前制定的一个策略处理。具体来说,如果推流的源头是 264/265 流,我们就采用直接推流的方式,不需要进行解码。通过 av_read_frame 取出来的 avpacket 包可以直接转发出去,整个过程完全不涉及解码操作,自然也就不会占用过多资源。在这种情况下,推流时的压力主要集中在网络带宽上,如果是将内容写入文件,那么压力则转移到了磁盘的写入速度上。这种策略充分利用了原始流的特性,避开了解码这个高资源消耗的环节,从而实现了 8K 推流时的高效表现。
## 二、效果图
## 三、相关代码
```cpp
#include "ffmpegsavesimple.h"
#include "ffmpegsavehelper.h"
//用法示例(保存文件/推流)
#if 0
FFmpegSaveSimple *f = new FFmpegSaveSimple(this);
f->setUrl("f:/mp4/push/1.mp4", "f:/1.mp4");
f->setUrl("f:/mp4/push/1.mp4", "rtmp://127.0.0.1/stream");
f->start();
#endif
FFmpegSaveSimple::FFmpegSaveSimple(QObject *parent) : QThread(parent)
{
stopped = false;
saveFile = false;
audioIndex = -1;
videoIndex = -1;
formatCtxIn = NULL;
formatCtxOut = NULL;
//初始化ffmpeg的库
FFmpegHelper::initLib();
}
FFmpegSaveSimple::~FFmpegSaveSimple()
{
this->stop();
this->close();
}
void FFmpegSaveSimple::run()
{
if (!this->openInput() || !this->openOutput()) {
this->close();
return;
}
int ret;
AVPacket packet;
qint64 videoCount = 0;
qint64 startTime = av_gettime();
while (!stopped) {
//读取一帧
int index = packet.stream_index;
if ((ret = av_read_frame(formatCtxIn, &packet)) < 0) {
if (ret == AVERROR_EOF || ret == AVERROR_EXIT) {
debug(0, "文件结束");
break;
} else {
debug(ret, "读取出错");
continue;
}
}
//取出输入输出流的时间基
AVStream *streamIn = formatCtxIn->streams;
AVStream *streamOut = formatCtxOut->streams;
AVRational timeBaseIn = streamIn->time_base;
AVRational timeBaseOut = streamOut->time_base;
if (index == videoIndex) {
videoCount++;
} else if (index == audioIndex) {
}
//纠正有些文件比如h264格式的没有pts
if (packet.pts == AV_NOPTS_VALUE) {
qreal fps = av_q2d(formatCtxIn->streams->r_frame_rate);
FFmpegSaveHelper::rescalePacket(&packet, timeBaseIn, videoCount, fps);
}
//推流需要延时/防止数据过大撑爆缓存
if (!saveFile && index == videoIndex) {
FFmpegHelper::delayTime(formatCtxIn, &packet, startTime);
}
//重新调整时间基准
FFmpegSaveHelper::rescalePacket(&packet, timeBaseIn, timeBaseOut);
qDebug()