codec_video_encoder.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. #include "codec_video_encoder.h"
  2. #include "../base/logger.h"
  3. #include <algorithm>
  4. #include <chrono>
  5. extern "C" {
  6. #include <libswscale/swscale.h>
  7. #include <libavutil/imgutils.h>
  8. }
  9. namespace av {
  10. namespace codec {
  11. // 静态成员初始化
  12. std::vector<std::string> VideoEncoder::supportedEncoders_;
  13. std::once_flag VideoEncoder::encodersInitFlag_;
  14. // PixelFormatConverter 实现
  15. PixelFormatConverter::PixelFormatConverter(AVPixelFormat srcFormat, AVPixelFormat dstFormat)
  16. : swsCtx_(nullptr)
  17. , srcFormat_(srcFormat)
  18. , dstFormat_(dstFormat)
  19. , width_(0)
  20. , height_(0) {
  21. }
  22. PixelFormatConverter::~PixelFormatConverter() {
  23. if (swsCtx_) {
  24. sws_freeContext(swsCtx_);
  25. }
  26. }
  27. bool PixelFormatConverter::setSize(int width, int height) {
  28. if (width_ == width && height_ == height && swsCtx_) {
  29. return true;
  30. }
  31. width_ = width;
  32. height_ = height;
  33. if (swsCtx_) {
  34. sws_freeContext(swsCtx_);
  35. }
  36. swsCtx_ = sws_getContext(
  37. width, height, srcFormat_,
  38. width, height, dstFormat_,
  39. SWS_BILINEAR, nullptr, nullptr, nullptr
  40. );
  41. if (!swsCtx_) {
  42. AV_LOGGER_ERROR("创建像素格式转换器失败");
  43. return false;
  44. }
  45. // 创建目标帧
  46. dstFrame_ = makeAVFrame();
  47. if (!dstFrame_) {
  48. AV_LOGGER_ERROR("分配目标帧失败");
  49. return false;
  50. }
  51. dstFrame_->format = dstFormat_;
  52. dstFrame_->width = width;
  53. dstFrame_->height = height;
  54. if (av_frame_get_buffer(dstFrame_.get(), 32) < 0) {
  55. AV_LOGGER_ERROR("分配帧缓冲区失败");
  56. return false;
  57. }
  58. return true;
  59. }
  60. AVFramePtr PixelFormatConverter::convert(const AVFramePtr& srcFrame) {
  61. if (!srcFrame || !swsCtx_) {
  62. return nullptr;
  63. }
  64. if (!setSize(srcFrame->width, srcFrame->height)) {
  65. return nullptr;
  66. }
  67. // 复制时间戳等信息
  68. av_frame_copy_props(dstFrame_.get(), srcFrame.get());
  69. // 执行格式转换
  70. int ret = sws_scale(
  71. swsCtx_,
  72. srcFrame->data, srcFrame->linesize,
  73. 0, srcFrame->height,
  74. dstFrame_->data, dstFrame_->linesize
  75. );
  76. if (ret < 0) {
  77. AV_LOGGER_ERRORF("像素格式转换失败: {}", ffmpeg_utils::errorToString(ret));
  78. return nullptr;
  79. }
  80. // 创建一个新的帧来返回,避免拷贝构造
  81. AVFramePtr resultFrame = makeAVFrame();
  82. if (!resultFrame) {
  83. return nullptr;
  84. }
  85. // 复制帧数据
  86. if (av_frame_ref(resultFrame.get(), dstFrame_.get()) < 0) {
  87. return nullptr;
  88. }
  89. return resultFrame;
  90. }
  91. // VideoEncoder 实现
  92. VideoEncoder::VideoEncoder()
  93. : AbstractEncoder(MediaType::VIDEO)
  94. , isHardwareEncoder_(false)
  95. , hwDeviceCtx_(nullptr) {
  96. AV_LOGGER_DEBUG("创建视频编码器");
  97. }
  98. VideoEncoder::~VideoEncoder() {
  99. close();
  100. AV_LOGGER_DEBUG("视频编码器已销毁");
  101. }
  102. ErrorCode VideoEncoder::open(const CodecParams& params) {
  103. std::lock_guard<std::mutex> lock(encodeMutex_);
  104. if (state_ != CodecState::IDLE && state_ != CodecState::CLOSED) {
  105. AV_LOGGER_WARNING("编码器已打开,先关闭再重新打开");
  106. close();
  107. }
  108. if (!validateParams(params)) {
  109. return ErrorCode::INVALID_ARGUMENT;
  110. }
  111. videoParams_ = static_cast<const VideoEncoderParams&>(params);
  112. params_ = params;
  113. ErrorCode result = initEncoder();
  114. if (result != ErrorCode::OK) {
  115. close();
  116. return result;
  117. }
  118. setState(CodecState::OPENED);
  119. AV_LOGGER_INFOF("视频编码器已打开: {} ({}x{} @ {}fps)",
  120. videoParams_.codecName, videoParams_.width,
  121. videoParams_.height, videoParams_.fps);
  122. return ErrorCode::OK;
  123. }
  124. void VideoEncoder::close() {
  125. std::lock_guard<std::mutex> lock(encodeMutex_);
  126. if (state_ == CodecState::CLOSED || state_ == CodecState::IDLE) {
  127. return;
  128. }
  129. // 清理硬件资源
  130. if (hwDeviceCtx_) {
  131. av_buffer_unref(&hwDeviceCtx_);
  132. hwDeviceCtx_ = nullptr;
  133. }
  134. hwFrame_.reset();
  135. convertedFrame_.reset();
  136. converter_.reset();
  137. // 清理编解码上下文
  138. codecCtx_.reset();
  139. codec_ = nullptr;
  140. setState(CodecState::CLOSED);
  141. AV_LOGGER_DEBUG("视频编码器已关闭");
  142. }
  143. ErrorCode VideoEncoder::flush() {
  144. std::lock_guard<std::mutex> lock(encodeMutex_);
  145. if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) {
  146. return ErrorCode::INVALID_STATE;
  147. }
  148. setState(CodecState::FLUSHING);
  149. // 发送空帧来刷新编码器
  150. int ret = avcodec_send_frame(codecCtx_.get(), nullptr);
  151. if (ret < 0 && ret != AVERROR_EOF) {
  152. AV_LOGGER_ERRORF("刷新编码器失败: {}", ffmpeg_utils::errorToString(ret));
  153. reportError(static_cast<ErrorCode>(ret));
  154. return static_cast<ErrorCode>(ret);
  155. }
  156. setState(CodecState::OPENED);
  157. return ErrorCode::OK;
  158. }
  159. ErrorCode VideoEncoder::encode(const AVFramePtr& frame, std::vector<AVPacketPtr>& packets) {
  160. std::lock_guard<std::mutex> lock(encodeMutex_);
  161. if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) {
  162. return ErrorCode::INVALID_STATE;
  163. }
  164. setState(CodecState::RUNNING);
  165. auto startTime = std::chrono::high_resolution_clock::now();
  166. ErrorCode result = encodeFrame(frame, packets);
  167. auto endTime = std::chrono::high_resolution_clock::now();
  168. double processTime = std::chrono::duration<double, std::milli>(endTime - startTime).count();
  169. updateStats(result == ErrorCode::OK, processTime,
  170. frame ? frame->width * frame->height * 3 / 2 : 0);
  171. if (frameCallback_ && frame) {
  172. frameCallback_(frame);
  173. }
  174. for (const auto& packet : packets) {
  175. if (packetCallback_) {
  176. packetCallback_(packet);
  177. }
  178. }
  179. return result;
  180. }
  181. ErrorCode VideoEncoder::finishEncode(std::vector<AVPacketPtr>& packets) {
  182. return flush();
  183. }
  184. bool VideoEncoder::validateParams(const CodecParams& params) {
  185. if (params.type != MediaType::VIDEO) {
  186. AV_LOGGER_ERROR("参数媒体类型不是视频");
  187. return false;
  188. }
  189. const auto& videoParams = static_cast<const VideoEncoderParams&>(params);
  190. if (videoParams.width <= 0 || videoParams.height <= 0) {
  191. AV_LOGGER_ERROR("视频尺寸无效");
  192. return false;
  193. }
  194. if (videoParams.fps <= 0) {
  195. AV_LOGGER_ERROR("帧率无效");
  196. return false;
  197. }
  198. if (videoParams.bitRate <= 0) {
  199. AV_LOGGER_ERROR("比特率无效");
  200. return false;
  201. }
  202. if (videoParams.codecName.empty()) {
  203. AV_LOGGER_ERROR("编码器名称为空");
  204. return false;
  205. }
  206. return true;
  207. }
  208. ErrorCode VideoEncoder::initEncoder() {
  209. // 查找编码器
  210. codec_ = avcodec_find_encoder_by_name(videoParams_.codecName.c_str());
  211. if (!codec_) {
  212. AV_LOGGER_ERRORF("未找到编码器: {}", videoParams_.codecName);
  213. return ErrorCode::CODEC_NOT_FOUND;
  214. }
  215. if (codec_->type != AVMEDIA_TYPE_VIDEO) {
  216. AV_LOGGER_ERROR("编码器类型不是视频");
  217. return ErrorCode::INVALID_ARGUMENT;
  218. }
  219. // 创建编码上下文
  220. codecCtx_ = makeAVCodecContext(codec_);
  221. if (!codecCtx_) {
  222. AV_LOGGER_ERROR("分配编码上下文失败");
  223. return ErrorCode::OUT_OF_MEMORY;
  224. }
  225. // 设置硬件加速
  226. if (videoParams_.hardwareAccel && isHardwareEncoder(videoParams_.codecName)) {
  227. ErrorCode result = setupHardwareAcceleration();
  228. if (result != ErrorCode::OK) {
  229. AV_LOGGER_WARNING("硬件加速设置失败,回退到软件编码");
  230. isHardwareEncoder_ = false;
  231. // 清理硬件资源
  232. if (hwDeviceCtx_) {
  233. av_buffer_unref(&hwDeviceCtx_);
  234. hwDeviceCtx_ = nullptr;
  235. }
  236. }
  237. }
  238. // 设置编码器参数(在硬件加速设置之后)
  239. ErrorCode result = setupEncoderParams();
  240. if (result != ErrorCode::OK) {
  241. return result;
  242. }
  243. // 打开编码器前的详细日志
  244. AV_LOGGER_INFOF("准备打开编码器: {}", videoParams_.codecName);
  245. AV_LOGGER_INFOF("编码器参数: {}x{}, 比特率: {}, 帧率: {}, 像素格式: {}",
  246. codecCtx_->width, codecCtx_->height, codecCtx_->bit_rate,
  247. codecCtx_->framerate.num, static_cast<int>(codecCtx_->pix_fmt));
  248. if (isHardwareEncoder_) {
  249. AV_LOGGER_INFOF("硬件编码器状态: 设备上下文={}, 帧上下文={}",
  250. hwDeviceCtx_ ? "已创建" : "未创建",
  251. codecCtx_->hw_frames_ctx ? "已设置" : "未设置");
  252. }
  253. // 验证编码器参数
  254. if (codecCtx_->width <= 0 || codecCtx_->height <= 0) {
  255. AV_LOGGER_ERROR("无效的视频尺寸参数");
  256. return ErrorCode::INVALID_PARAMS;
  257. }
  258. if (codecCtx_->bit_rate <= 0) {
  259. AV_LOGGER_ERROR("无效的比特率参数");
  260. return ErrorCode::INVALID_PARAMS;
  261. }
  262. // 打开编码器
  263. int ret = avcodec_open2(codecCtx_.get(), codec_, nullptr);
  264. if (ret < 0) {
  265. AV_LOGGER_ERRORF("打开编码器失败: {} (错误码: {})", ffmpeg_utils::errorToString(ret), ret);
  266. // 详细错误分析
  267. if (ret == AVERROR(EINVAL)) {
  268. AV_LOGGER_ERROR("编码器参数无效 - 可能的原因:");
  269. AV_LOGGER_ERROR(" 1. 不支持的像素格式或分辨率组合");
  270. AV_LOGGER_ERROR(" 2. 硬件编码器参数配置错误");
  271. AV_LOGGER_ERROR(" 3. 硬件设备上下文与编码器不匹配");
  272. } else if (ret == AVERROR(EBUSY)) {
  273. AV_LOGGER_ERROR("硬件设备忙碌 - 可能被其他进程占用");
  274. } else if (ret == AVERROR(ENOMEM)) {
  275. AV_LOGGER_ERROR("内存不足 - 无法分配编码器资源");
  276. }
  277. return static_cast<ErrorCode>(ret);
  278. }
  279. AV_LOGGER_INFOF("编码器打开成功: {}", videoParams_.codecName);
  280. return ErrorCode::OK;
  281. }
  282. ErrorCode VideoEncoder::setupEncoderParams() {
  283. codecCtx_->bit_rate = videoParams_.bitRate;
  284. codecCtx_->width = videoParams_.width;
  285. codecCtx_->height = videoParams_.height;
  286. codecCtx_->time_base = {1, videoParams_.fps};
  287. codecCtx_->framerate = {videoParams_.fps, 1};
  288. codecCtx_->gop_size = videoParams_.gopSize;
  289. codecCtx_->max_b_frames = videoParams_.maxBFrames;
  290. // 设置像素格式
  291. if (isHardwareEncoder_) {
  292. AVPixelFormat hwPixFmt = getHardwarePixelFormat();
  293. if (hwPixFmt == AV_PIX_FMT_NONE) {
  294. AV_LOGGER_ERRORF("获取硬件像素格式失败,编码器: {}", videoParams_.codecName);
  295. return ErrorCode::NOT_SUPPORTED;
  296. }
  297. codecCtx_->pix_fmt = hwPixFmt;
  298. AV_LOGGER_INFOF("设置硬件编码器像素格式: {} ({})",
  299. static_cast<int>(hwPixFmt), av_get_pix_fmt_name(hwPixFmt));
  300. } else {
  301. codecCtx_->pix_fmt = videoParams_.pixelFormat;
  302. AV_LOGGER_INFOF("设置软件编码器像素格式: {} ({})",
  303. static_cast<int>(videoParams_.pixelFormat),
  304. av_get_pix_fmt_name(videoParams_.pixelFormat));
  305. }
  306. // 针对不同编码器设置特定参数
  307. if (videoParams_.codecName == "h264_nvenc") {
  308. AV_LOGGER_INFO("设置NVENC编码器参数...");
  309. // NVENC 特定参数 - 使用更保守的设置
  310. int ret;
  311. ret = av_opt_set(codecCtx_->priv_data, "preset", "medium", 0);
  312. AV_LOGGER_INFOF("设置preset=medium: {}", ret == 0 ? "成功" : "失败");
  313. ret = av_opt_set(codecCtx_->priv_data, "profile", "main", 0);
  314. AV_LOGGER_INFOF("设置profile=main: {}", ret == 0 ? "成功" : "失败");
  315. ret = av_opt_set(codecCtx_->priv_data, "rc", "vbr", 0);
  316. AV_LOGGER_INFOF("设置rc=vbr: {}", ret == 0 ? "成功" : "失败");
  317. ret = av_opt_set_int(codecCtx_->priv_data, "surfaces", 16, 0);
  318. AV_LOGGER_INFOF("设置surfaces=16: {}", ret == 0 ? "成功" : "失败");
  319. ret = av_opt_set_int(codecCtx_->priv_data, "delay", 0, 0);
  320. AV_LOGGER_INFOF("设置delay=0: {}", ret == 0 ? "成功" : "失败");
  321. if (videoParams_.lowLatency) {
  322. AV_LOGGER_INFO("启用低延迟模式");
  323. ret = av_opt_set(codecCtx_->priv_data, "preset", "fast", 0);
  324. AV_LOGGER_INFOF("设置preset=fast: {}", ret == 0 ? "成功" : "失败");
  325. ret = av_opt_set(codecCtx_->priv_data, "tune", "ll", 0);
  326. AV_LOGGER_INFOF("设置tune=ll: {}", ret == 0 ? "成功" : "失败");
  327. }
  328. } else if (videoParams_.codecName == "h264_qsv") {
  329. // QSV 特定参数
  330. av_opt_set(codecCtx_->priv_data, "preset", "fast", 0);
  331. av_opt_set(codecCtx_->priv_data, "profile", "high", 0);
  332. if (videoParams_.lowLatency) {
  333. av_opt_set(codecCtx_->priv_data, "preset", "veryfast", 0);
  334. }
  335. } else if (videoParams_.codecName == "h264_amf") {
  336. // AMF 特定参数
  337. av_opt_set(codecCtx_->priv_data, "quality", "speed", 0);
  338. av_opt_set(codecCtx_->priv_data, "profile", "high", 0);
  339. if (videoParams_.lowLatency) {
  340. av_opt_set(codecCtx_->priv_data, "usage", "lowlatency", 0);
  341. }
  342. } else {
  343. // 软件编码器参数
  344. if (!videoParams_.preset.empty()) {
  345. av_opt_set(codecCtx_->priv_data, "preset", videoParams_.preset.c_str(), 0);
  346. }
  347. if (!videoParams_.tune.empty()) {
  348. av_opt_set(codecCtx_->priv_data, "tune", videoParams_.tune.c_str(), 0);
  349. }
  350. if (videoParams_.lowLatency) {
  351. av_opt_set(codecCtx_->priv_data, "preset", "ultrafast", 0);
  352. av_opt_set(codecCtx_->priv_data, "tune", "zerolatency", 0);
  353. }
  354. }
  355. return ErrorCode::OK;
  356. }
  357. ErrorCode VideoEncoder::setupHardwareAcceleration() {
  358. isHardwareEncoder_ = true;
  359. AVHWDeviceType hwType = getHardwareDeviceType();
  360. if (hwType == AV_HWDEVICE_TYPE_NONE) {
  361. AV_LOGGER_ERRORF("不支持的硬件编码器: {}", videoParams_.codecName);
  362. return ErrorCode::NOT_SUPPORTED;
  363. }
  364. AV_LOGGER_INFOF("开始设置硬件加速: 编码器={}, 设备类型={}",
  365. videoParams_.codecName, static_cast<int>(hwType));
  366. // 对于CUDA设备,检查可用性
  367. if (hwType == AV_HWDEVICE_TYPE_CUDA) {
  368. AV_LOGGER_INFO("检查CUDA设备可用性...");
  369. // 这里可以添加CUDA设备检查逻辑
  370. }
  371. // 创建硬件设备上下文
  372. AV_LOGGER_INFO("创建硬件设备上下文...");
  373. int ret = av_hwdevice_ctx_create(&hwDeviceCtx_, hwType, nullptr, nullptr, 0);
  374. if (ret < 0) {
  375. AV_LOGGER_ERRORF("创建硬件设备上下文失败: {} (编码器: {}, 错误码: {})",
  376. ffmpeg_utils::errorToString(ret), videoParams_.codecName, ret);
  377. // 特定错误处理
  378. if (ret == AVERROR(ENOENT)) {
  379. AV_LOGGER_ERROR("硬件设备不存在或驱动未安装");
  380. if (hwType == AV_HWDEVICE_TYPE_CUDA) {
  381. AV_LOGGER_ERROR("请检查NVIDIA驱动和CUDA是否正确安装");
  382. }
  383. } else if (ret == AVERROR(EBUSY)) {
  384. AV_LOGGER_ERROR("硬件设备正在被其他进程使用");
  385. } else if (ret == AVERROR(EINVAL)) {
  386. AV_LOGGER_ERROR("硬件设备参数无效");
  387. } else if (ret == AVERROR(ENOMEM)) {
  388. AV_LOGGER_ERROR("内存不足,无法创建硬件设备上下文");
  389. }
  390. return static_cast<ErrorCode>(ret);
  391. }
  392. AV_LOGGER_INFOF("硬件设备上下文创建成功: {}", videoParams_.codecName);
  393. // 设置硬件帧上下文
  394. return setupHardwareFrameContext();
  395. }
  396. ErrorCode VideoEncoder::setupHardwareFrameContext() {
  397. AVBufferRef* hwFramesRef = av_hwframe_ctx_alloc(hwDeviceCtx_);
  398. if (!hwFramesRef) {
  399. AV_LOGGER_ERROR("分配硬件帧上下文失败");
  400. return ErrorCode::OUT_OF_MEMORY;
  401. }
  402. AVHWFramesContext* framesCtx = reinterpret_cast<AVHWFramesContext*>(hwFramesRef->data);
  403. framesCtx->format = getHardwarePixelFormat();
  404. // 设置软件格式 - 统一使用NV12格式,这是大多数硬件编码器的首选格式
  405. framesCtx->sw_format = AV_PIX_FMT_NV12;
  406. framesCtx->width = videoParams_.width;
  407. framesCtx->height = videoParams_.height;
  408. framesCtx->initial_pool_size = 8; // 增加池大小以提高稳定性
  409. AV_LOGGER_INFOF("设置硬件帧上下文: {}x{}, 硬件格式: {}, 软件格式: {}, 池大小: {}",
  410. framesCtx->width, framesCtx->height,
  411. static_cast<int>(framesCtx->format),
  412. static_cast<int>(framesCtx->sw_format),
  413. framesCtx->initial_pool_size);
  414. int ret = av_hwframe_ctx_init(hwFramesRef);
  415. if (ret < 0) {
  416. AV_LOGGER_ERRORF("初始化硬件帧上下文失败: {}", ffmpeg_utils::errorToString(ret));
  417. av_buffer_unref(&hwFramesRef);
  418. return static_cast<ErrorCode>(ret);
  419. }
  420. codecCtx_->hw_frames_ctx = av_buffer_ref(hwFramesRef);
  421. av_buffer_unref(&hwFramesRef);
  422. AV_LOGGER_INFO("硬件帧上下文初始化成功");
  423. return ErrorCode::OK;
  424. }
  425. AVFramePtr VideoEncoder::convertFrame(const AVFramePtr& frame) {
  426. if (!frame) {
  427. return nullptr;
  428. }
  429. AVPixelFormat targetFormat;
  430. if (isHardwareEncoder_) {
  431. // 硬件编码器统一使用NV12格式,与硬件帧上下文保持一致
  432. targetFormat = AV_PIX_FMT_NV12;
  433. } else {
  434. targetFormat = videoParams_.pixelFormat;
  435. }
  436. // 如果格式已经匹配,创建新帧返回
  437. if (frame->format == targetFormat) {
  438. // 创建一个新的帧来返回,避免拷贝构造
  439. AVFramePtr resultFrame = makeAVFrame();
  440. if (!resultFrame) {
  441. return nullptr;
  442. }
  443. // 复制帧数据
  444. if (av_frame_ref(resultFrame.get(), frame.get()) < 0) {
  445. return nullptr;
  446. }
  447. return resultFrame;
  448. }
  449. // 创建转换器
  450. if (!converter_ ||
  451. converter_->srcFormat_ != static_cast<AVPixelFormat>(frame->format) ||
  452. converter_->dstFormat_ != targetFormat) {
  453. converter_ = std::make_unique<PixelFormatConverter>(
  454. static_cast<AVPixelFormat>(frame->format), targetFormat);
  455. }
  456. return converter_->convert(frame);
  457. }
  458. AVFramePtr VideoEncoder::transferToHardware(const AVFramePtr& frame) {
  459. if (!isHardwareEncoder_ || !frame) {
  460. // 创建一个新的帧来返回,避免拷贝构造
  461. if (frame) {
  462. AVFramePtr resultFrame = makeAVFrame();
  463. if (!resultFrame) {
  464. return nullptr;
  465. }
  466. // 复制帧数据
  467. if (av_frame_ref(resultFrame.get(), frame.get()) < 0) {
  468. return nullptr;
  469. }
  470. return resultFrame;
  471. }
  472. return nullptr;
  473. }
  474. // 分配硬件帧
  475. hwFrame_ = makeAVFrame();
  476. if (!hwFrame_) {
  477. AV_LOGGER_ERROR("分配硬件帧失败");
  478. return nullptr;
  479. }
  480. int ret = av_hwframe_get_buffer(codecCtx_->hw_frames_ctx, hwFrame_.get(), 0);
  481. if (ret < 0) {
  482. AV_LOGGER_ERRORF("获取硬件帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
  483. return nullptr;
  484. }
  485. // 传输数据到硬件
  486. ret = av_hwframe_transfer_data(hwFrame_.get(), frame.get(), 0);
  487. if (ret < 0) {
  488. AV_LOGGER_ERRORF("传输数据到硬件失败: {}", ffmpeg_utils::errorToString(ret));
  489. return nullptr;
  490. }
  491. // 复制时间戳等信息
  492. av_frame_copy_props(hwFrame_.get(), frame.get());
  493. return std::move(hwFrame_);
  494. }
  495. ErrorCode VideoEncoder::encodeFrame(const AVFramePtr& frame, std::vector<AVPacketPtr>& packets) {
  496. AVFramePtr processedFrame;
  497. if (frame) {
  498. // 格式转换
  499. auto convertedFrame = convertFrame(frame);
  500. if (!convertedFrame) {
  501. AV_LOGGER_ERROR("帧格式转换失败");
  502. return ErrorCode::CONVERSION_FAILED;
  503. }
  504. processedFrame = std::move(convertedFrame);
  505. // 硬件传输
  506. auto hwFrame = transferToHardware(processedFrame);
  507. if (!hwFrame) {
  508. AV_LOGGER_ERROR("硬件传输失败");
  509. return ErrorCode::HARDWARE_ERROR;
  510. }
  511. processedFrame = std::move(hwFrame);
  512. }
  513. // 发送帧到编码器
  514. int ret = avcodec_send_frame(codecCtx_.get(), processedFrame ? processedFrame.get() : nullptr);
  515. if (ret < 0) {
  516. AV_LOGGER_ERRORF("发送帧到编码器失败: {}", ffmpeg_utils::errorToString(ret));
  517. return static_cast<ErrorCode>(ret);
  518. }
  519. // 接收编码后的包
  520. return receivePackets(packets);
  521. }
  522. ErrorCode VideoEncoder::receivePackets(std::vector<AVPacketPtr>& packets) {
  523. while (true) {
  524. AVPacketPtr packet = makeAVPacket();
  525. if (!packet) {
  526. return ErrorCode::OUT_OF_MEMORY;
  527. }
  528. int ret = avcodec_receive_packet(codecCtx_.get(), packet.get());
  529. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  530. break; // 需要更多输入或已结束
  531. }
  532. if (ret < 0) {
  533. AV_LOGGER_ERRORF("接收编码包失败: {}", ffmpeg_utils::errorToString(ret));
  534. return static_cast<ErrorCode>(ret);
  535. }
  536. packets.push_back(std::move(packet));
  537. }
  538. return ErrorCode::OK;
  539. }
  540. AVHWDeviceType VideoEncoder::getHardwareDeviceType() const {
  541. if (videoParams_.codecName == "h264_nvenc") {
  542. return AV_HWDEVICE_TYPE_CUDA;
  543. } else if (videoParams_.codecName == "h264_qsv") {
  544. return AV_HWDEVICE_TYPE_QSV;
  545. } else if (videoParams_.codecName == "h264_amf") {
  546. return AV_HWDEVICE_TYPE_D3D11VA;
  547. } else if (videoParams_.codecName == "h264_videotoolbox") {
  548. return AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
  549. }
  550. return AV_HWDEVICE_TYPE_NONE;
  551. }
  552. AVPixelFormat VideoEncoder::getHardwarePixelFormat() const {
  553. if (videoParams_.codecName == "h264_nvenc") {
  554. return AV_PIX_FMT_CUDA;
  555. } else if (videoParams_.codecName == "h264_qsv") {
  556. return AV_PIX_FMT_QSV;
  557. } else if (videoParams_.codecName == "h264_amf") {
  558. return AV_PIX_FMT_D3D11;
  559. } else if (videoParams_.codecName == "h264_videotoolbox") {
  560. return AV_PIX_FMT_VIDEOTOOLBOX;
  561. }
  562. AV_LOGGER_ERRORF("未知的硬件编码器: {}", videoParams_.codecName);
  563. return AV_PIX_FMT_NONE;
  564. }
  565. std::vector<std::string> VideoEncoder::getSupportedEncoders() {
  566. std::call_once(encodersInitFlag_, findUsableEncoders);
  567. return supportedEncoders_;
  568. }
  569. bool VideoEncoder::isHardwareEncoder(const std::string& codecName) {
  570. for (const char* hwEncoder : HARDWARE_ENCODERS) {
  571. if (codecName == hwEncoder) {
  572. return true;
  573. }
  574. }
  575. return false;
  576. }
  577. std::string VideoEncoder::getRecommendedEncoder() {
  578. auto encoders = getSupportedEncoders();
  579. // 优先选择硬件编码器
  580. for (const char* hwEncoder : HARDWARE_ENCODERS) {
  581. if (std::find(encoders.begin(), encoders.end(), hwEncoder) != encoders.end()) {
  582. return hwEncoder;
  583. }
  584. }
  585. // 回退到软件编码器
  586. for (const char* swEncoder : SOFTWARE_ENCODERS) {
  587. if (std::find(encoders.begin(), encoders.end(), swEncoder) != encoders.end()) {
  588. return swEncoder;
  589. }
  590. }
  591. return encoders.empty() ? "" : encoders[0];
  592. }
  593. void VideoEncoder::findUsableEncoders() {
  594. AV_LOGGER_INFO("查找可用的视频编码器...");
  595. // 测试硬件编码器
  596. for (const char* encoder : HARDWARE_ENCODERS) {
  597. if (CodecFactory::isCodecSupported(encoder, CodecType::ENCODER, MediaType::VIDEO)) {
  598. supportedEncoders_.emplace_back(encoder);
  599. AV_LOGGER_INFOF("找到硬件编码器: {}", encoder);
  600. }
  601. }
  602. // 测试软件编码器
  603. for (const char* encoder : SOFTWARE_ENCODERS) {
  604. if (CodecFactory::isCodecSupported(encoder, CodecType::ENCODER, MediaType::VIDEO)) {
  605. supportedEncoders_.emplace_back(encoder);
  606. AV_LOGGER_INFOF("找到软件编码器: {}", encoder);
  607. }
  608. }
  609. AV_LOGGER_INFOF("总共找到 {} 个可用的视频编码器", supportedEncoders_.size());
  610. }
  611. // VideoEncoderFactory 实现
  612. std::unique_ptr<VideoEncoder> VideoEncoderFactory::create(const std::string& codecName) {
  613. auto encoder = std::make_unique<VideoEncoder>();
  614. if (!codecName.empty()) {
  615. if (!CodecFactory::isCodecSupported(codecName, CodecType::ENCODER, MediaType::VIDEO)) {
  616. AV_LOGGER_ERRORF("不支持的编码器: {}", codecName);
  617. return nullptr;
  618. }
  619. }
  620. return encoder;
  621. }
  622. std::unique_ptr<VideoEncoder> VideoEncoderFactory::createBest(bool preferHardware) {
  623. std::string codecName;
  624. if (preferHardware) {
  625. codecName = VideoEncoder::getRecommendedEncoder();
  626. } else {
  627. // 优先选择软件编码器
  628. auto encoders = VideoEncoder::getSupportedEncoders();
  629. for (const char* swEncoder : VideoEncoder::SOFTWARE_ENCODERS) {
  630. if (std::find(encoders.begin(), encoders.end(), swEncoder) != encoders.end()) {
  631. codecName = swEncoder;
  632. break;
  633. }
  634. }
  635. }
  636. if (codecName.empty()) {
  637. AV_LOGGER_ERROR("未找到可用的视频编码器");
  638. return nullptr;
  639. }
  640. return create(codecName);
  641. }
  642. } // namespace codec
  643. } // namespace av