Commit dfdee183 authored by Philippe Gorley's avatar Philippe Gorley Committed by Adrien Béraud

encoder: lazy initialize video stream

Sets up video streams upon receiving the first video frame. Audio
streams are still initialized as soon as possible.

This allows a video encoder to use the pixel format of its received
frames, and to set up a hardware transcoding pipeline if it receives
a hardware frame.

Change-Id: I622fc44b6096d63d7423837d2f2ec15680548a83
parent 6d2de6ca
......@@ -72,10 +72,12 @@ AudioSender::setup(SocketPair& socketPair)
RING_DBG("audioEncoder_->openOutput %s", dest_.c_str());
audioEncoder_->openOutput(dest_, "rtp");
audioEncoder_->setOptions(args_);
auto codec = std::static_pointer_cast<AccountAudioCodecInfo>(args_.codec);
auto ms = MediaStream("audio sender", codec->audioformat);
audioEncoder_->setOptions(ms);
audioEncoder_->addStream(args_.codec->systemCodecInfo);
audioEncoder_->setInitSeqVal(seqVal_);
audioEncoder_->setIOContext(muxContext_->getContext());
audioEncoder_->startIO();
} catch (const MediaEncoderException &e) {
RING_ERR("%s", e.what());
return false;
......
This diff is collapsed.
......@@ -32,7 +32,6 @@
#include "noncopyable.h"
#include "media_buffer.h"
#include "media_codec.h"
#include "media_device.h"
#include "media_stream.h"
#include <map>
......@@ -67,12 +66,11 @@ public:
~MediaEncoder();
void openOutput(const std::string& filename, const std::string& format="");
void setDeviceOptions(const DeviceParams& args);
void setMetadata(const std::string& title, const std::string& description);
void setOptions(const MediaStream& opts);
void setOptions(const MediaDescription& args);
void setOptions(std::map<std::string, std::string> options);
int addStream(const SystemCodecInfo& codec);
void setIOContext(AVIOContext* ioctx);
void startIO();
void setIOContext(AVIOContext* ioctx) { ioCtx_ = ioctx; }
bool send(AVPacket& packet, int streamIdx = -1);
......@@ -91,8 +89,8 @@ public:
/* getWidth and getHeight return size of the encoded frame.
* Values have meaning only after openLiveOutput call.
*/
int getWidth() const { return device_.width; }
int getHeight() const { return device_.height; }
int getWidth() const { return videoOpts_.width; };
int getHeight() const { return videoOpts_.height; };
void setInitSeqVal(uint16_t seqVal);
uint16_t getLastSeqValue();
......@@ -112,11 +110,17 @@ private:
AVCodecContext* prepareEncoderContext(AVCodec* outputCodec, bool is_video);
void forcePresetX264(AVCodecContext* encoderCtx);
void extractProfileLevelID(const std::string &parameters, AVCodecContext *ctx);
int initStream(const std::string& codecName);
int initStream(const SystemCodecInfo& systemCodecInfo);
void openIOContext();
void startIO();
std::vector<AVCodecContext*> encoders_;
AVFormatContext *outputCtx_ = nullptr;
AVIOContext* ioCtx_ = nullptr;
int currentStreamIdx_ = -1;
unsigned sent_samples = 0;
bool initialized_ {false};
#ifdef RING_VIDEO
video::VideoScaler scaler_;
......@@ -133,9 +137,11 @@ private:
protected:
void readConfig(AVDictionary** dict, AVCodecContext* encoderCtx);
AVDictionary *options_ = nullptr;
DeviceParams device_;
std::shared_ptr<const AccountCodecInfo> codec_;
AVDictionary* options_ = nullptr;
MediaStream videoOpts_;
MediaStream audioOpts_;
std::string videoCodec_;
std::string audioCodec_;
};
} // namespace ring
......
......@@ -243,8 +243,6 @@ MediaRecorder::initRecord()
// need to get encoder parameters before calling openFileOutput
// openFileOutput needs to be called before adding any streams
std::map<std::string, std::string> encoderOptions;
std::stringstream timestampString;
timestampString << std::put_time(&startTime_, "%Y-%m-%d %H:%M:%S");
......@@ -254,13 +252,17 @@ MediaRecorder::initRecord()
title_ = ss.str();
}
title_ = replaceAll(title_, "%TIMESTAMP", timestampString.str());
encoderOptions["title"] = title_;
if (description_.empty()) {
description_ = "Recorded with Jami https://jami.net";
}
description_ = replaceAll(description_, "%TIMESTAMP", timestampString.str());
encoderOptions["description"] = description_;
encoder_->setMetadata(title_, description_);
encoder_->openOutput(getPath());
#ifdef RING_ACCEL
encoder_->enableAccel(false); // TODO recorder has problems with hardware encoding
#endif
videoFilter_.reset();
if (hasVideo_) {
......@@ -269,11 +271,7 @@ MediaRecorder::initRecord()
RING_ERR() << "Could not retrieve video recorder stream properties";
return -1;
}
encoderOptions["width"] = std::to_string(videoStream.width);
encoderOptions["height"] = std::to_string(videoStream.height);
std::stringstream fps;
fps << videoStream.frameRate;
encoderOptions["framerate"] = fps.str();
encoder_->setOptions(videoStream);
}
audioFilter_.reset();
......@@ -283,13 +281,9 @@ MediaRecorder::initRecord()
RING_ERR() << "Could not retrieve audio recorder stream properties";
return -1;
}
encoderOptions["sample_rate"] = std::to_string(audioStream.sampleRate);
encoderOptions["channels"] = std::to_string(audioStream.nbChannels);
encoder_->setOptions(audioStream);
}
encoder_->openOutput(getPath());
encoder_->setOptions(encoderOptions);
if (hasVideo_) {
auto videoCodec = std::static_pointer_cast<ring::SystemVideoCodecInfo>(
getSystemCodecContainer()->searchCodecByName("VP8", ring::MEDIA_VIDEO));
......@@ -310,13 +304,7 @@ MediaRecorder::initRecord()
}
}
try {
encoder_->setIOContext(nullptr);
encoder_->startIO();
} catch (const MediaEncoderException& e) {
RING_ERR() << "Could not start recorder: " << e.what();
return -1;
}
encoder_->setIOContext(nullptr);
RING_DBG() << "Recording initialized";
return 0;
......
......@@ -26,6 +26,7 @@
#include "client/videomanager.h"
#include "logger.h"
#include "manager.h"
#include "media_device.h"
#include "smartools.h"
#include "sip/sipcall.h"
#ifdef RING_ACCEL
......@@ -51,14 +52,12 @@ VideoSender::VideoSender(const std::string& dest, const DeviceParams& dev,
{
keyFrameFreq_ = dev.framerate.numerator() * KEY_FRAME_PERIOD;
videoEncoder_->openOutput(dest, "rtp");
videoEncoder_->setDeviceOptions(dev);
auto opts = MediaStream("video sender", AV_PIX_FMT_YUV420P, 1 / (rational<int>)dev.framerate, dev.width, dev.height, 1, (rational<int>)dev.framerate);
videoEncoder_->setOptions(opts);
videoEncoder_->setOptions(args);
videoEncoder_->addStream(args.codec->systemCodecInfo);
videoEncoder_->setInitSeqVal(seqVal);
videoEncoder_->setIOContext(muxContext_->getContext());
videoEncoder_->startIO();
videoEncoder_->print_sdp();
// Send local video codec in SmartInfo
Smartools::getInstance().setLocalVideoCodec(videoEncoder_->getEncoderName());
......@@ -72,7 +71,6 @@ VideoSender::~VideoSender()
videoEncoder_->flush();
}
void
VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
{
......@@ -117,6 +115,10 @@ VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
if (videoEncoder_->encode(swFrame, is_keyframe, frameNumber_++) < 0)
RING_ERR("encoding failed");
}
#ifdef DEBUG_SDP
if (frameNumber_ == 1) // video stream is lazy initialized, wait for first frame
videoEncoder_->print_sdp();
#endif
}
void
......
......@@ -34,6 +34,7 @@
// Forward declarations
namespace ring {
class SocketPair;
struct DeviceParams;
struct AccountVideoCodecInfo;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment