perf(video): 消除中间帧复制并优化 MJPEG 有界预取

通过 Bytes 所有权和只读 AVBufferRef 引用池化 NV12 输入,消除中间 AVFrame 的整帧复制,并保留 V4L2 编码包脱离硬件缓冲的处理。

允许输出健康时有界预取 MJPEG,在输出背压时优先解码前丢帧;增加等帧、输出等待、丢帧原因及编码分段耗时统计,提供预取和所有权输入的对照开关。

补充缓冲寿命、只读保护、软件编码回退和队列策略测试及接口说明,保留现有 PTS、解码 worker、音频和加密行为。
This commit is contained in:
mofeng-git
2026-10-01 20:29:06 +08:00
parent 318b58b26a
commit 2f60e61dd5
13 changed files with 994 additions and 41 deletions

View File

@@ -0,0 +1,51 @@
#ifndef OWNED_NV12_FRAME_H
#define OWNED_NV12_FRAME_H
extern "C" {
#include <libavutil/frame.h>
}
#include <limits>
#include <memory>
using RamInputRelease = void (*)(void *, uint8_t *);
struct RamFrameDeleter {
void operator()(AVFrame *frame) const { av_frame_free(&frame); }
};
using RamOwnedFrame = std::unique_ptr<AVFrame, RamFrameDeleter>;
static RamOwnedFrame make_owned_nv12_frame(const uint8_t *data, int length,
int width, int height, void *owner,
RamInputRelease release) {
const int64_t pixels = static_cast<int64_t>(width) * height;
if (!data || !release || width <= 0 || height <= 0 || width % 2 ||
height % 2 || pixels > std::numeric_limits<int>::max() / 3 * 2 ||
length < pixels + pixels / 2) {
if (release)
release(owner, const_cast<uint8_t *>(data));
return RamOwnedFrame();
}
RamOwnedFrame frame(av_frame_alloc());
if (!frame) {
release(owner, const_cast<uint8_t *>(data));
return frame;
}
frame->buf[0] = av_buffer_create(const_cast<uint8_t *>(data), length, release,
owner, AV_BUFFER_FLAG_READONLY);
if (!frame->buf[0]) {
release(owner, const_cast<uint8_t *>(data));
return RamOwnedFrame();
}
frame->format = AV_PIX_FMT_NV12;
frame->width = width;
frame->height = height;
frame->data[0] = frame->buf[0]->data;
frame->data[1] = frame->data[0] + pixels;
frame->linesize[0] = width;
frame->linesize[1] = width;
return frame;
}
#endif