codec_video_encoder.cpp 30 KB

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