diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index dd9b059897b69cf25836d4a4d9618e4c4d994cde..816ee9477993ec6ebfeebbf770d99ceb3bab031f 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -64,7 +64,9 @@ constexpr double LOGREG_PARAM_B_HEVC {-5.}; MediaEncoder::MediaEncoder() : outputCtx_(avformat_alloc_context()) -{} +{ + JAMI_DBG("[%p] New instance created", this); +} MediaEncoder::~MediaEncoder() { @@ -86,6 +88,8 @@ MediaEncoder::~MediaEncoder() avformat_free_context(outputCtx_); } av_dict_free(&options_); + + JAMI_DBG("[%p] Instance destroyed", this); } void @@ -168,10 +172,6 @@ MediaEncoder::openOutput(const std::string& filename, const std::string& format) avformat_alloc_output_context2(&outputCtx_, nullptr, nullptr, filename.c_str()); else avformat_alloc_output_context2(&outputCtx_, nullptr, format.c_str(), filename.c_str()); - -#ifdef RING_ACCEL - enableAccel_ = Manager::instance().videoPreferences.getEncodingAccelerated(); -#endif } int @@ -179,15 +179,35 @@ MediaEncoder::addStream(const SystemCodecInfo& systemCodecInfo) { if (systemCodecInfo.mediaType == MEDIA_AUDIO) { audioCodec_ = systemCodecInfo.name; - return initStream(systemCodecInfo, nullptr); } else { videoCodec_ = systemCodecInfo.name; - // TODO only support 1 audio stream and 1 video stream per encoder - if (audioOpts_.isValid()) - return 1; // stream will be added to AVFormatContext after audio stream - else - return 0; // only a video stream } + + auto stream = avformat_new_stream(outputCtx_, outputCodec_); + + if (stream == nullptr) { + JAMI_ERR("[%p] Failed to create coding instance for %s", this, systemCodecInfo.name.c_str()); + return -1; + } + + JAMI_DBG("[%p] Created new coding instance for %s @ index %d", + this, + systemCodecInfo.name.c_str(), + stream->index); + // Only init audio now, video will be intialized when + // encoding the first frame. + if (systemCodecInfo.mediaType == MEDIA_AUDIO) { + return initStream(systemCodecInfo); + } + + // If audio options are valid, it means this session is used + // for both audio and video streams, thus the video will be + // at index 1, otherwise it will be at index 0. + // TODO. Hacky, needs better solution. + if (audioOpts_.isValid()) + return 1; + else + return 0; } int @@ -203,7 +223,23 @@ MediaEncoder::initStream(const std::string& codecName, AVBufferRef* framesCtx) int MediaEncoder::initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* framesCtx) { + JAMI_DBG("[%p] Initializing stream: codec type %d, name %s, lib %s", + this, + systemCodecInfo.codecType, + systemCodecInfo.name.c_str(), + systemCodecInfo.libName.c_str()); + std::lock_guard<std::mutex> lk(encMutex_); + + if (!outputCtx_) + throw MediaEncoderException("Cannot allocate stream"); + + // Must already have codec instance(s) + if (outputCtx_->nb_streams == 0) { + JAMI_ERR("[%p] Can not init, output context has no coding sessions!", this); + throw MediaEncoderException("Can not init, output context has no coding sessions!"); + } + AVCodecContext* encoderCtx = nullptr; AVMediaType mediaType; @@ -212,19 +248,26 @@ MediaEncoder::initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* fr else if (systemCodecInfo.mediaType == MEDIA_AUDIO) mediaType = AVMEDIA_TYPE_AUDIO; - AVStream* stream; - if (!outputCtx_) - throw MediaEncoderException("Cannot allocate stream"); - // add video stream to outputformat context - if (outputCtx_->nb_streams <= 0) - stream = avformat_new_stream(outputCtx_, outputCodec_); - else { - stream = outputCtx_->streams[0]; - stream->codecpar->width = videoOpts_.width; - stream->codecpar->height = videoOpts_.height; + AVStream* stream {nullptr}; + + // Only supports one audio and one video streams at most per instance. + for (unsigned i = 0; i < outputCtx_->nb_streams; i++) { + stream = outputCtx_->streams[i]; + if (stream->codecpar->codec_type == mediaType) { + if (mediaType == AVMEDIA_TYPE_VIDEO) { + stream->codecpar->width = videoOpts_.width; + stream->codecpar->height = videoOpts_.height; + } + break; + } } - if (!stream) + + if (stream == nullptr) { + JAMI_ERR("[%p] Can not init, output context has no coding sessions for %s", + this, + systemCodecInfo.name.c_str()); throw MediaEncoderException("Cannot allocate stream"); + } currentStreamIdx_ = stream->index; #ifdef RING_ACCEL @@ -490,7 +533,7 @@ bool MediaEncoder::send(AVPacket& pkt, int streamIdx) { if (!initialized_) { - streamIdx = initStream(videoCodec_, nullptr); + streamIdx = initStream(videoCodec_); startIO(); } if (streamIdx < 0) diff --git a/src/media/media_encoder.h b/src/media/media_encoder.h index 787f2eb9ede4ea4f759679eedbfdfc03d105db32..2a6d0141e9a2cc88729479aa8ca06681de3233be 100644 --- a/src/media/media_encoder.h +++ b/src/media/media_encoder.h @@ -122,8 +122,8 @@ private: AVCodecContext* prepareEncoderContext(AVCodec* outputCodec, bool is_video); void forcePresetX2645(AVCodecContext* encoderCtx); void extractProfileLevelID(const std::string& parameters, AVCodecContext* ctx); - int initStream(const std::string& codecName, AVBufferRef* framesCtx); - int initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* framesCtx); + int initStream(const std::string& codecName, AVBufferRef* framesCtx = {}); + int initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* framesCtx = {}); void openIOContext(); void startIO(); AVCodecContext* getCurrentVideoAVCtx(); @@ -167,7 +167,7 @@ private: int scaledFrameBufferSize_ = 0; #ifdef RING_ACCEL - bool enableAccel_ = true; + bool enableAccel_ {false}; std::unique_ptr<video::HardwareAccel> accel_; #endif diff --git a/src/media/media_recorder.cpp b/src/media/media_recorder.cpp index 415865af43342c055075b0bb546c420761d044f6..35132505eacbd4fc3cbd01549392144dbed7768d 100644 --- a/src/media/media_recorder.cpp +++ b/src/media/media_recorder.cpp @@ -85,8 +85,7 @@ struct MediaRecorder::StreamObserver : public Observer<std::shared_ptr<MediaFram JAMI_ERR("Accel failure: %s", e.what()); return; } - } - else + } else #endif framePtr = std::static_pointer_cast<VideoFrame>(m); int angle = framePtr->getOrientation(); @@ -264,10 +263,9 @@ MediaRecorder::onFrame(const std::string& name, const std::shared_ptr<MediaFrame (AVPixelFormat)(std::static_pointer_cast<VideoFrame>(frame))->format()); if (desc && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { try { - clone = video::HardwareAccel::transferToMainMemory(*std::static_pointer_cast<VideoFrame>( - frame), - static_cast<AVPixelFormat>( - ms.format)); + clone = video::HardwareAccel::transferToMainMemory( + *std::static_pointer_cast<VideoFrame>(frame), + static_cast<AVPixelFormat>(ms.format)); } catch (const std::runtime_error& e) { JAMI_ERR("Accel failure: %s", e.what()); return; @@ -351,16 +349,6 @@ MediaRecorder::initRecord() encoder_->setOptions(audioStream); } - if (hasVideo_) { - auto videoCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>( - getSystemCodecContainer()->searchCodecByName("VP8", jami::MEDIA_VIDEO)); - videoIdx_ = encoder_->addStream(*videoCodec.get()); - if (videoIdx_ < 0) { - JAMI_ERR() << "Failed to add video stream to encoder"; - return -1; - } - } - if (hasAudio_) { auto audioCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>( getSystemCodecContainer()->searchCodecByName("opus", jami::MEDIA_AUDIO)); @@ -371,6 +359,16 @@ MediaRecorder::initRecord() } } + if (hasVideo_) { + auto videoCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>( + getSystemCodecContainer()->searchCodecByName("VP8", jami::MEDIA_VIDEO)); + videoIdx_ = encoder_->addStream(*videoCodec.get()); + if (videoIdx_ < 0) { + JAMI_ERR() << "Failed to add video stream to encoder"; + return -1; + } + } + encoder_->setIOContext(nullptr); JAMI_DBG() << "Recording initialized"; diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 54bcd74a712fc0265a8ac8c01a5457ea63fe7f7c..e9c198a585b8cedb34bfe38aa0cac03167034ea2 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -149,7 +149,11 @@ VideoRtpSession::startSender() send_.linkableHW = conference_ == nullptr; send_.bitrate = videoBitrateInfo_.videoBitrateCurrent; - bool isScreenScharing = localVideoParams_.format == "x11grab"; + // NOTE: + // Current implementation does not handle resolution change + // (needed by window sharing feature) with HW codecs, so HW + // codecs will be disabled for now. + bool allowHwAccel = (localVideoParams_.format != "x11grab"); if (socketPair_) initSeqVal_ = socketPair_->lastSeqValOut(); @@ -167,13 +171,8 @@ VideoRtpSession::startSender() send_.bitrate, static_cast<rational<int>>(localVideoParams_.framerate)) : videoMixer_->getStream("Video Sender"); - sender_.reset(new VideoSender(getRemoteRtpUri(), - ms, - send_, - *socketPair_, - initSeqVal_ + 1, - mtu_, - isScreenScharing)); + sender_.reset(new VideoSender( + getRemoteRtpUri(), ms, send_, *socketPair_, initSeqVal_ + 1, mtu_, allowHwAccel)); if (changeOrientationCallback_) sender_->setChangeOrientationCallback(changeOrientationCallback_); if (socketPair_) diff --git a/src/media/video/video_sender.cpp b/src/media/video/video_sender.cpp index 4a35f3ead0a278ceab4e30a2b75cdaffd7586b24..f4a45a0efb5483f8bef11d320c9f0964d7435acd 100644 --- a/src/media/video/video_sender.cpp +++ b/src/media/video/video_sender.cpp @@ -48,7 +48,7 @@ VideoSender::VideoSender(const std::string& dest, SocketPair& socketPair, const uint16_t seqVal, uint16_t mtu, - bool isScreenScharing = false) + bool enableHwAccel) : muxContext_(socketPair.createIOContext(mtu)) , videoEncoder_(new MediaEncoder) { @@ -56,24 +56,19 @@ VideoSender::VideoSender(const std::string& dest, videoEncoder_->openOutput(dest, "rtp"); videoEncoder_->setOptions(opts); videoEncoder_->setOptions(args); +#ifdef RING_ACCEL + videoEncoder_->enableAccel(enableHwAccel + and Manager::instance().videoPreferences.getEncodingAccelerated()); +#endif videoEncoder_->addStream(args.codec->systemCodecInfo); videoEncoder_->setInitSeqVal(seqVal); videoEncoder_->setIOContext(muxContext_->getContext()); -#ifdef RING_ACCEL - if (isScreenScharing) - videoEncoder_->enableAccel(false); -#endif // Send local video codec in SmartInfo Smartools::getInstance().setLocalVideoCodec(videoEncoder_->getVideoCodec()); // Send the resolution in smartInfo Smartools::getInstance().setResolution("local", opts.width, opts.height); } -VideoSender::~VideoSender() -{ - videoEncoder_->flush(); -} - void VideoSender::encodeAndSendVideo(const std::shared_ptr<VideoFrame>& input_frame) { diff --git a/src/media/video/video_sender.h b/src/media/video/video_sender.h index 0d2ca3068caf4893f38ea6851bea536359cf69a7..aaa8a4414602ff36e4cd97586f87b295a0ffa1c0 100644 --- a/src/media/video/video_sender.h +++ b/src/media/video/video_sender.h @@ -49,9 +49,9 @@ public: SocketPair& socketPair, const uint16_t seqVal, uint16_t mtu, - bool isScreenScharing); + bool allowHwAccel = true); - ~VideoSender(); + ~VideoSender() {}; void forceKeyFrame();