av_muxer.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "av_muxer.h"
  2. bool AvMuxer::Open(std::string_view filePath, std::string_view format)
  3. {
  4. Close();
  5. _isOpenFile = false;
  6. _filePath = filePath;
  7. __CheckBool(avformat_alloc_output_context2(&_fmtCtx, nullptr, format.data(), _filePath.c_str()) >= 0);
  8. __CheckBool(_fmtCtx);
  9. return true;
  10. }
  11. bool AvMuxer::WriteHeader()
  12. {
  13. av_dump_format(_fmtCtx, 0, _filePath.data(), 1);
  14. // 打开输出文件
  15. if (!(_fmtCtx->oformat->flags & AVFMT_NOFILE)) {
  16. __CheckBool(avio_open(&_fmtCtx->pb, _filePath.c_str(), AVIO_FLAG_WRITE) >= 0);
  17. }
  18. // 写入文件头
  19. __CheckBool(avformat_write_header(_fmtCtx, nullptr) >= 0);
  20. // _fmtCtx->flags |= AVFMT_FLAG_NOBUFFER; // 无缓冲
  21. // _fmtCtx->flags |= AVFMT_FLAG_FLUSH_PACKETS; // 立即刷新数据包
  22. _isOpenFile = true;
  23. return true;
  24. }
  25. int AvMuxer::AddVideoStream(const Encoder<MediaType::VIDEO>::Param& param)
  26. {
  27. __Check(-1, _fmtCtx->oformat->video_codec != AV_CODEC_ID_NONE);
  28. Info info;
  29. info.pts = 0;
  30. info.fps = param.fps;
  31. auto encoder = new Encoder<MediaType::VIDEO>;
  32. __Check(-1, encoder->Open(param, _fmtCtx));
  33. info.type = MediaType::VIDEO;
  34. info.encoder = encoder;
  35. __Check(-1, _AddStream(info));
  36. _infos.back().stream->time_base = {1, info.fps};
  37. return info.streamIndex;
  38. }
  39. int AvMuxer::AddAudioStream(const Encoder<MediaType::AUDIO>::Param& param)
  40. {
  41. __Check(-1, _fmtCtx->oformat->audio_codec != AV_CODEC_ID_NONE);
  42. Info info;
  43. info.pts = 0;
  44. info.fps = AUDIO_SAMPLE_RATE;
  45. auto encoder = new Encoder<MediaType::AUDIO>;
  46. info.type = MediaType::AUDIO;
  47. info.encoder = encoder;
  48. __Check(-1, encoder->Open(param, _fmtCtx));
  49. __Check(-1, _AddStream(info));
  50. _infos.back().stream->time_base = {1, AUDIO_SAMPLE_RATE};
  51. return info.streamIndex;
  52. }
  53. bool AvMuxer::Write(AVFrame* frame, int streamIndex, bool isEnd)
  54. {
  55. // 此函数不能被多个流同时调用
  56. std::lock_guard<std::mutex> lk(_mtx);
  57. __CheckBool(_infos.size() > streamIndex);
  58. auto&& info = _infos[streamIndex];
  59. if (info.isEnd) {
  60. return true;
  61. }
  62. if (isEnd) {
  63. info.isEnd = isEnd;
  64. frame = nullptr;
  65. }
  66. __CheckBool(info.encoder);
  67. // 检测流之间时间是不是差的太多,如果差的太多,直接弃掉数据多的流数据
  68. if (!_CheckTime(double(info.pts) / info.fps)) {
  69. info.isEncodeOverload = true;
  70. return false;
  71. }
  72. info.isEncodeOverload = false;
  73. __CheckBool(info.encoder->PushFrame(frame, isEnd, info.pts));
  74. info.pts += info.type == MediaType::AUDIO ? info.encoder->GetCtx()->frame_size : 1; // 更新 pts
  75. AVPacket* packet = nullptr;
  76. while ((packet = info.encoder->Encode())) {
  77. av_packet_rescale_ts(packet, info.encoder->GetCtx()->time_base, info.stream->time_base);
  78. packet->stream_index = info.stream->index;
  79. __CheckBool(av_interleaved_write_frame(_fmtCtx, packet) >= 0);
  80. }
  81. info.encoder->AfterEncode();
  82. return true;
  83. }
  84. bool AvMuxer::_CheckTime(double time)
  85. {
  86. auto minTime = double(_infos.front().pts) / _infos.front().fps;
  87. for (int idx = 1; idx < _infos.size(); ++idx) {
  88. minTime = std::min(double(_infos[idx].pts) / _infos[idx].fps, minTime);
  89. }
  90. if (time - minTime > 0.1) { // 说明相差的太多了,下一帧不能再送往编码器
  91. return false;
  92. }
  93. return true;
  94. }
  95. void AvMuxer::Close()
  96. {
  97. if (_fmtCtx == nullptr) {
  98. return;
  99. }
  100. // 清空编码器缓存
  101. for (int index = 0; index < _infos.size(); ++index) {
  102. __DebugPrint("stream: %d, time:%f", index, double(_infos[index].pts) / _infos[index].fps);
  103. }
  104. if (_isOpenFile) {
  105. __CheckNo(av_write_trailer(_fmtCtx) >= 0);
  106. Free(_fmtCtx->pb, [this] { avio_closep(&_fmtCtx->pb); });
  107. }
  108. _isOpenFile = false;
  109. for (auto&& info : _infos) {
  110. info.encoder->Close();
  111. Free(info.encoder, [&info] {info.encoder->Close(); delete info.encoder; });
  112. }
  113. _infos.clear();
  114. Free(_fmtCtx, [this] { avformat_free_context(_fmtCtx); });
  115. }
  116. bool AvMuxer::_AddStream(Info& info)
  117. {
  118. __CheckBool(info.stream = avformat_new_stream(_fmtCtx, nullptr));
  119. info.stream->id = _fmtCtx->nb_streams - 1;
  120. __CheckBool(avcodec_parameters_from_context(info.stream->codecpar, info.encoder->GetCtx()) >= 0);
  121. info.streamIndex = _fmtCtx->nb_streams - 1;
  122. info.pts = 0;
  123. info.isEnd = false;
  124. _infos.push_back(info);
  125. return true;
  126. }
  127. AVCodecContext* AvMuxer::GetCodecCtx(int streamIndex)
  128. {
  129. __CheckNullptr(streamIndex >= 0 && _infos.size() > streamIndex);
  130. return _infos[streamIndex].encoder->GetCtx();
  131. }
  132. bool AvMuxer::IsEncodeOverload() const
  133. {
  134. for (auto&& info : _infos) {
  135. if (info.isEncodeOverload) {
  136. return true;
  137. }
  138. }
  139. return false;
  140. }