From 43f22d20045052bde31ab0019f5878af460ceff7 Mon Sep 17 00:00:00 2001 From: philippegorley <philippe.gorley@savoirfairelinux.com> Date: Wed, 9 May 2018 13:36:39 -0400 Subject: [PATCH] encoder: merge common encoding code Refactors out the common code from video and audio encoding/flushing into a single method. This reuses code instead of duplicating it. The method is public in the hopes of being able to reuse MediaEncoder elsewhere in the codebase. Allow caller to specify the stream index for the future case that the AVFormatContext contains multiple streams (recording video and audio). Change-Id: Ieae52bc453ef66d141a40819ca10fedbd38d9a86 Reviewed-by: Sebastien Blin <sebastien.blin@savoirfairelinux.com> --- src/media/media_encoder.cpp | 111 ++++++++---------------------------- src/media/media_encoder.h | 4 ++ 2 files changed, 29 insertions(+), 86 deletions(-) diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index 622dedeebb..7a0b5fe513 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -300,42 +300,7 @@ MediaEncoder::encode(VideoFrame& input, bool is_keyframe, frame->key_frame = 0; } - AVPacket pkt; - memset(&pkt, 0, sizeof(pkt)); - av_init_packet(&pkt); - - int ret = 0; - ret = avcodec_send_frame(encoderCtx_, frame); - if (ret < 0) - return -1; - - while (1) { - ret = avcodec_receive_packet(encoderCtx_, &pkt); - if (ret == AVERROR(EAGAIN)) - break; - if (ret < 0) - return -1; - - if (pkt.size) { - if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, encoderCtx_->time_base, - stream_->time_base); - if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, encoderCtx_->time_base, - stream_->time_base); - - pkt.stream_index = stream_->index; - - // write the compressed frame - ret = av_write_frame(outputCtx_, &pkt); - if (ret < 0) { - RING_ERR("av_write_frame failed: %s", libav_utils::getError(ret).c_str()); - } else - break; - } - } - - av_packet_unref(&pkt); + int ret = encode(frame, stream_->index); return ret; } @@ -368,7 +333,7 @@ int MediaEncoder::encode_audio(const AudioBuffer &buffer) const auto sample_rate = buffer.getSampleRate(); while (nb_frames > 0) { - AVFrame *frame = av_frame_alloc(); + AVFrame* frame = av_frame_alloc(); if (!frame) return -1; @@ -394,8 +359,8 @@ int MediaEncoder::encode_audio(const AudioBuffer &buffer) reinterpret_cast<const uint8_t *>(offset_ptr), buffer_size, 0); if (err < 0) { - RING_ERR("Couldn't fill audio frame: %s: %d %d", libav_utils::getError(err).c_str(), - frame->nb_samples, buffer_size); + RING_ERR() << "Failed to fill audio frame of size" << buffer_size << " with " + << frame->nb_samples << " samples: " << libav_utils::getError(err); av_frame_free(&frame); return -1; } @@ -403,66 +368,35 @@ int MediaEncoder::encode_audio(const AudioBuffer &buffer) nb_frames -= frame->nb_samples; offset_ptr += frame->nb_samples * buffer.channels(); - AVPacket pkt; - av_init_packet(&pkt); - pkt.data = NULL; // packet data will be allocated by the encoder - pkt.size = 0; - int ret = 0; - - ret = avcodec_send_frame(encoderCtx_, frame); - if (ret < 0) - return -1; - - while (1) { - ret = avcodec_receive_packet(encoderCtx_, &pkt); - if (ret == AVERROR(EAGAIN)) - break; - if (ret < 0) - return -1; - - if (pkt.size) { - if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, encoderCtx_->time_base, - stream_->time_base); - if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, encoderCtx_->time_base, - stream_->time_base); - - pkt.stream_index = stream_->index; - - // write the compressed frame - ret = av_write_frame(outputCtx_, &pkt); - if (ret < 0) { - RING_ERR("av_write_frame failed: %s", libav_utils::getError(ret).c_str()); - } else - break; - } - } - - av_packet_unref(&pkt); + encode(frame, stream_->index); av_frame_free(&frame); } return 0; } -int MediaEncoder::flush() +int +MediaEncoder::encode(AVFrame* frame, int streamIdx) { + int ret = 0; AVPacket pkt; - memset(&pkt, 0, sizeof(pkt)); av_init_packet(&pkt); + pkt.data = NULL; // packet data will be allocated by the encoder + pkt.size = 0; + pkt.stream_index = streamIdx; - int ret = 0; - ret = avcodec_send_frame(encoderCtx_, nullptr); + ret = avcodec_send_frame(encoderCtx_, frame); if (ret < 0) return -1; - while (1) { + while (ret >= 0) { ret = avcodec_receive_packet(encoderCtx_, &pkt); if (ret == AVERROR(EAGAIN)) break; - if (ret < 0) - return -1; + if (ret < 0) { + RING_ERR() << "Failed to encode frame: " << libav_utils::getError(ret); + return ret; + } if (pkt.size) { if (pkt.pts != AV_NOPTS_VALUE) @@ -472,19 +406,24 @@ int MediaEncoder::flush() pkt.dts = av_rescale_q(pkt.dts, encoderCtx_->time_base, stream_->time_base); - pkt.stream_index = stream_->index; // write the compressed frame ret = av_write_frame(outputCtx_, &pkt); if (ret < 0) { - RING_ERR("av_write_frame failed: %s", libav_utils::getError(ret).c_str()); + RING_ERR() << "av_write_frame failed: " << libav_utils::getError(ret); } else break; } } + av_packet_unref(&pkt); + return 0; +} - return ret; +int +MediaEncoder::flush() +{ + return encode(nullptr, stream_->index); } std::string diff --git a/src/media/media_encoder.h b/src/media/media_encoder.h index 68285280a7..44e8244118 100644 --- a/src/media/media_encoder.h +++ b/src/media/media_encoder.h @@ -72,6 +72,10 @@ public: #endif // RING_VIDEO int encode_audio(const AudioBuffer &input); + + // frame should be ready to be sent to the encoder at this point + int encode(AVFrame* frame, int streamIdx); + int flush(); std::string print_sdp(); -- GitLab