ff_rtmp_pusher.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. //
  2. // Created by xu fulong on 2022/9/9.
  3. //
  4. #include "ff_rtmp_pusher.h"
  5. #define PUSH_TAG "HttpPusher"
  6. int FFRtmpPusher::open(const char *inputPath, const char *outputPath) {
  7. int ret;
  8. avformat_network_init();
  9. ret = avformat_open_input(&inFormatCtx, inputPath, nullptr, nullptr);
  10. if (ret < 0) {
  11. LOGE(PUSH_TAG, "avformat_open_input err=%s", av_err2str(ret));
  12. return ret;
  13. }
  14. avformat_find_stream_info(inFormatCtx, nullptr);
  15. av_dump_format(inFormatCtx, 0, inputPath, 0);
  16. ret = avformat_alloc_output_context2(&outFormatCtx, nullptr, "flv", outputPath);
  17. if (ret < 0 || !outFormatCtx) {
  18. LOGE(PUSH_TAG, "alloc format_context err=%s", av_err2str(ret));
  19. return ret;
  20. }
  21. // Flv video: h264 audio: aac/mp3
  22. // If not h264, should transocde to h264
  23. for (int i = 0; i < inFormatCtx->nb_streams; ++i) {
  24. AVStream *in_stream = inFormatCtx->streams[i];
  25. const auto *codec = avcodec_find_encoder(in_stream->codecpar->codec_id);
  26. AVStream *out_stream = avformat_new_stream(outFormatCtx, codec);
  27. avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
  28. out_stream->codecpar->codec_tag = 0;
  29. if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  30. video_index = i;
  31. } else if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
  32. if (audio_index == -1) {
  33. audio_index = i;
  34. }
  35. }
  36. }
  37. if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE)) {
  38. ret = avio_open2(&outFormatCtx->pb, outputPath, AVIO_FLAG_WRITE, nullptr, nullptr);
  39. if (ret < 0) {
  40. LOGE(PUSH_TAG, "avio open error=%s", av_err2str(ret));
  41. return ret;
  42. }
  43. }
  44. ret = avformat_write_header(outFormatCtx, nullptr);
  45. if (ret < 0) {
  46. LOGE(PUSH_TAG, "avformat_write_header err=%s", av_err2str(ret));
  47. }
  48. return ret;
  49. }
  50. void rescale(AVFormatContext *in_format_ctx, AVFormatContext *out_format_ctx, AVPacket *packet) {
  51. AVStream *in_stream = in_format_ctx->streams[packet->stream_index];
  52. AVStream *out_stream = out_format_ctx->streams[packet->stream_index];
  53. packet->pts = av_rescale_q(packet->pts, in_stream->time_base, out_stream->time_base);
  54. packet->dts = av_rescale_q(packet->dts, in_stream->time_base, out_stream->time_base);
  55. packet->duration = av_rescale_q(packet->duration, in_stream->time_base, out_stream->time_base);
  56. packet->pos = -1;
  57. }
  58. int FFRtmpPusher::push() {
  59. int ret;
  60. int64_t startTime = av_gettime();
  61. while (true) {
  62. ret = av_read_frame(inFormatCtx, &packet);
  63. if (ret < 0) {
  64. LOGE(PUSH_TAG, "av_read_frame err=%s", av_err2str(ret));
  65. break;
  66. }
  67. if (packet.stream_index != video_index && packet.stream_index != audio_index)
  68. continue;
  69. // sync
  70. AVRational time_base = inFormatCtx->streams[packet.stream_index]->time_base;
  71. int64_t pts_time = av_rescale_q(packet.pts, time_base, AV_TIME_BASE_Q);
  72. int64_t cur_time = av_gettime() - startTime;
  73. if (pts_time > cur_time) {
  74. av_usleep((unsigned int)(pts_time - cur_time));
  75. }
  76. rescale(inFormatCtx, outFormatCtx, &packet);
  77. ret = av_interleaved_write_frame(outFormatCtx, &packet);
  78. if (ret < 0) {
  79. LOGE(PUSH_TAG, "write frame err=%s", av_err2str(ret));
  80. break;
  81. }
  82. av_packet_unref(&packet);
  83. }
  84. return ret;
  85. }
  86. void FFRtmpPusher::close() {
  87. if (outFormatCtx) {
  88. av_write_trailer(outFormatCtx);
  89. avformat_close_input(&outFormatCtx);
  90. outFormatCtx = nullptr;
  91. }
  92. if (inFormatCtx) {
  93. avformat_close_input(&inFormatCtx);
  94. inFormatCtx = nullptr;
  95. }
  96. }