video_encoder.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "video_encoder.h"
  2. extern "C" {
  3. #include <libavutil/opt.h>
  4. }
  5. std::vector<std::string> Encoder<MediaType::VIDEO>::_usableEncoders;
  6. Encoder<MediaType::VIDEO>::Encoder() {}
  7. bool Encoder<MediaType::VIDEO>::Open(const Param& encodeParam, AVFormatContext* fmtCtx)
  8. {
  9. Close();
  10. _isOpen = false;
  11. __CheckBool(_Init(encodeParam, fmtCtx));
  12. // 打开编码器
  13. __CheckBool(avcodec_open2(_codecCtx, _codec, nullptr) >= 0);
  14. _isOpen = true;
  15. return true;
  16. }
  17. bool Encoder<MediaType::VIDEO>::PushFrame(AVFrame* frame, bool isEnd, uint64_t pts)
  18. {
  19. if (!isEnd) {
  20. __CheckBool(_Trans(frame));
  21. frame = _bufferFrame;
  22. __CheckBool(frame);
  23. } else {
  24. frame = nullptr; // 直接刷新编码器缓存
  25. }
  26. if (frame != nullptr) {
  27. frame->pts = pts;
  28. }
  29. __CheckBool(avcodec_send_frame(_codecCtx, frame) >= 0);
  30. return true;
  31. }
  32. void Encoder<MediaType::VIDEO>::AfterEncode()
  33. {
  34. if (_isHardware) {
  35. Free(_hwFrame, [this] { av_frame_free(&_hwFrame); });
  36. }
  37. }
  38. void Encoder<MediaType::VIDEO>::Close()
  39. {
  40. if (_codecCtx != nullptr) {
  41. avcodec_free_context(&_codecCtx);
  42. }
  43. Free(_codecCtx, [this] { avcodec_free_context(&_codecCtx); });
  44. Free(_hwDeviceCtx, [this] { av_buffer_unref(&_hwDeviceCtx); });
  45. _converter = nullptr;
  46. }
  47. const std::vector<std::string>& Encoder<MediaType::VIDEO>::GetUsableEncoders()
  48. {
  49. if (_usableEncoders.empty()) {
  50. _FindUsableEncoders();
  51. }
  52. return _usableEncoders;
  53. }
  54. void Encoder<MediaType::VIDEO>::_FindUsableEncoders()
  55. {
  56. // 尝试打开编码器看看编码器能不能用
  57. Param param;
  58. param.bitRate = 1000;
  59. param.fps = 30;
  60. param.width = 1920;
  61. param.height = 1080;
  62. Encoder encoder;
  63. AVFormatContext* fmtCtx = nullptr;
  64. __CheckNo(avformat_alloc_output_context2(&fmtCtx, nullptr, nullptr, "test.mp4") >= 0);
  65. for (const auto& name : _encoderNames) {
  66. if (strcmp(name, "libx264") == 0) { // 软件编码器必定支持
  67. _usableEncoders.push_back(name);
  68. continue;
  69. }
  70. param.name = name;
  71. if (encoder.Open(param, fmtCtx)) {
  72. _usableEncoders.push_back(name);
  73. }
  74. encoder.Close();
  75. }
  76. Free(fmtCtx, [&fmtCtx] { avformat_free_context(fmtCtx); });
  77. }
  78. bool Encoder<MediaType::VIDEO>::_Init(const Param& encodeParam, AVFormatContext* fmtCtx)
  79. {
  80. _isHardware = encodeParam.name != "libx264";
  81. AVHWDeviceType hwType;
  82. if (encodeParam.name == "libx264") {
  83. _pixFmt = AV_PIX_FMT_NV12;
  84. } else if (encodeParam.name == "h264_nvenc") {
  85. _pixFmt = AV_PIX_FMT_CUDA;
  86. hwType = AV_HWDEVICE_TYPE_CUDA;
  87. } else if (encodeParam.name == "h264_qsv") {
  88. _pixFmt = AV_PIX_FMT_QSV;
  89. hwType = AV_HWDEVICE_TYPE_QSV;
  90. } else if (encodeParam.name == "h264_amf") {
  91. _pixFmt = AV_PIX_FMT_VULKAN;
  92. hwType = AV_HWDEVICE_TYPE_VULKAN;
  93. }
  94. _isHardware = _pixFmt != AV_PIX_FMT_NV12;
  95. if (_isHardware
  96. && av_hwdevice_ctx_create(&_hwDeviceCtx, hwType, nullptr, nullptr, 0) < 0) { // 硬件解码
  97. __DebugPrint("av_hwdevice_ctx_create failed\n");
  98. return false;
  99. }
  100. __CheckBool(_codec = avcodec_find_encoder_by_name(encodeParam.name.c_str()));
  101. __CheckBool(_codecCtx = avcodec_alloc_context3(_codec));
  102. _codecCtx->bit_rate = encodeParam.bitRate;
  103. _codecCtx->width = encodeParam.width;
  104. _codecCtx->height = encodeParam.height;
  105. _codecCtx->time_base = {1, encodeParam.fps};
  106. _codecCtx->framerate = {encodeParam.fps, 1};
  107. // 影响缓冲区大小
  108. _codecCtx->gop_size = 5;
  109. _codecCtx->max_b_frames = 0;
  110. _codecCtx->pix_fmt = _pixFmt;
  111. /* Some formats want stream headers to be separate. */
  112. if (fmtCtx->oformat->flags & AVFMT_GLOBALHEADER) {
  113. _codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  114. }
  115. if (!_isHardware) { // 软件编码设置为快,避免占用过高的 CPU ,反正硬盘不值钱
  116. // av_opt_set(_codecCtx->priv_data, "preset", "veryfast", 0);
  117. av_opt_set(_codecCtx->priv_data, "preset", "ultrafast", 0); // 使用最快的预设
  118. av_opt_set(_codecCtx->priv_data, "tune", "zerolatency", 0); // 零延迟调优
  119. } else {
  120. // 为硬件编码器添加低延迟设置
  121. av_opt_set(_codecCtx->priv_data, "preset", "llhp", 0); // 低延迟高性能
  122. av_opt_set(_codecCtx->priv_data, "zerolatency", "1", 0);
  123. }
  124. __CheckBool(!_isHardware || _SetHwFrameCtx());
  125. return true;
  126. }
  127. bool Encoder<MediaType::VIDEO>::_SetHwFrameCtx()
  128. {
  129. AVBufferRef* hwFramesRef;
  130. AVHWFramesContext* framesCtx = nullptr;
  131. __CheckBool(hwFramesRef = av_hwframe_ctx_alloc(_hwDeviceCtx));
  132. framesCtx = (AVHWFramesContext*) (hwFramesRef->data);
  133. framesCtx->format = _pixFmt;
  134. framesCtx->sw_format = AV_PIX_FMT_NV12;
  135. framesCtx->width = _codecCtx->width;
  136. framesCtx->height = _codecCtx->height;
  137. framesCtx->initial_pool_size = 20;
  138. if (av_hwframe_ctx_init(hwFramesRef) < 0) {
  139. __DebugPrint("av_hwframe_ctx_init failed\n");
  140. av_buffer_unref(&hwFramesRef);
  141. return false;
  142. }
  143. __CheckBool(_codecCtx->hw_frames_ctx = av_buffer_ref(hwFramesRef));
  144. av_buffer_unref(&hwFramesRef);
  145. return true;
  146. }
  147. bool Encoder<MediaType::VIDEO>::_Trans(AVFrame* frame)
  148. {
  149. std::lock_guard<std::mutex> lk(__mtx);
  150. if (!_isOpen) {
  151. return false;
  152. }
  153. if (frame->format == AV_PIX_FMT_NV12) {
  154. _bufferFrame = frame;
  155. } else {
  156. if (_converter == nullptr) {
  157. _converter = std::make_unique<FfmpegConverter>(AVPixelFormat(frame->format),
  158. AV_PIX_FMT_NV12);
  159. _converter->SetSize(frame->width, frame->height);
  160. }
  161. _bufferFrame = _converter->Trans(frame);
  162. }
  163. if (_isHardware) {
  164. _bufferFrame = _ToHardware();
  165. }
  166. __CheckBool(_bufferFrame);
  167. return true;
  168. }
  169. AVFrame* Encoder<MediaType::VIDEO>::_ToHardware()
  170. {
  171. if (_bufferFrame == nullptr) {
  172. return nullptr;
  173. }
  174. __CheckNullptr(_hwFrame = av_frame_alloc());
  175. __CheckNullptr(av_hwframe_get_buffer(_codecCtx->hw_frames_ctx, _hwFrame, 0) >= 0);
  176. __CheckNullptr(_hwFrame->hw_frames_ctx);
  177. __CheckNullptr(av_hwframe_transfer_data(_hwFrame, _bufferFrame, 0) >= 0);
  178. return _hwFrame;
  179. }