I’m having some trouble setting up the
encoder to support Augmented Frames. I’m using the Unity Plugin as the base so
this is how I’m initializing the Peer Connection Factory and the Multiplex
Encoding/Decoding Factory:
g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
nullptr, webrtc::CreateBuiltinAudioEncoderFactory(),
webrtc::CreateBuiltinAudioDecoderFactory(),
std::unique_ptr<webrtc::MultiplexEncoderFactory>(
new webrtc::MultiplexEncoderFactory(
absl::make_unique<webrtc::InternalEncoderFactory>(), true)),
std::unique_ptr<webrtc::MultiplexDecoderFactory>(
new webrtc::MultiplexDecoderFactory(
absl::make_unique<webrtc::InternalDecoderFactory>(), true)),
nullptr, nullptr);
class CustomFrameSource {
public:
CustomFrameSource(int width, int height, int interval_us);
webrtc::VideoRotation GetRotation() const;
void SetRotation(webrtc::VideoRotation rotation);
// Override configuration.
webrtc::VideoFrame GetFrame(const uint8_t* dataRGBA, int strideRGBA, int width, int height,
std::unique_ptr<uint8_t[]> augmentedData, uint16_t augmentedDataSize,
webrtc::VideoRotation rotation,
int interval_us);
private:
const int width_;
const int height_;
const int interval_us_;
webrtc::VideoRotation rotation_ = webrtc::kVideoRotation_0;
int64_t next_timestamp_us_ = rtc::kNumMicrosecsPerMillisec;
};
CustomFrameSource::CustomFrameSource(int width, int height, int interval_us)
: width_(width), height_(height), interval_us_(interval_us) {
RTC_CHECK_GT(width_, 0);
RTC_CHECK_GT(height_, 0);
RTC_CHECK_GT(interval_us_, 0);
}
webrtc::VideoRotation CustomFrameSource::GetRotation() const {
return rotation_;
}
void CustomFrameSource::SetRotation(webrtc::VideoRotation rotation) {
rotation_ = rotation;
}
webrtc::VideoFrame CustomFrameSource::GetFrame(const uint8_t* dataRGBA, int strideRGBA, int width, int height,
std::unique_ptr<uint8_t[]> augmentedData, uint16_t augmentedDataSize,
webrtc::VideoRotation rotation,
int interval_us) {
RTC_CHECK_GT(width, 0);
RTC_CHECK_GT(height, 0);
RTC_CHECK_GT(interval_us, 0);
rtc::scoped_refptr<webrtc::AugmentedVideoFrameBuffer> augmentedVideoFrameBuffer =
new rtc::RefCountedObject<webrtc::AugmentedVideoFrameBuffer>(
RGBABuffer::Copy(width, height, dataRGBA, strideRGBA),
std::move(augmentedData), augmentedDataSize);
webrtc::VideoFrame::Builder builder;
builder.set_video_frame_buffer(augmentedVideoFrameBuffer)
.set_timestamp_us(next_timestamp_us_)
.set_rotation(rotation);
next_timestamp_us_ += interval_us;
return builder.build();
}
class CustomVideoSource : public rtc::AdaptedVideoTrackSource {
public:
CustomVideoSource();
~CustomVideoSource() override;
void OnFrameCaptured(const webrtc::VideoFrame& frame);
virtual void AddRef() const override { return; }
virtual rtc::RefCountReleaseStatus Release() const override { return rtc::RefCountReleaseStatus::kDroppedLastRef; }
virtual SourceState state() const override { return source_state_; }
virtual bool remote() const override { return false; }
virtual bool is_screencast() const override { return false; }
virtual absl::optional<bool> needs_denoising() const override { return false; }
protected:
SourceState source_state_ = kInitializing;
};
CustomVideoSource::CustomVideoSource() : AdaptedVideoTrackSource(60) {
source_state_ = kInitializing;
}
CustomVideoSource::~CustomVideoSource() {
source_state_ = kEnded;
}
void CustomVideoSource::OnFrameCaptured(const webrtc::VideoFrame& frame) {
source_state_ = kLive;
OnFrame(frame);
}
class VideoObserver : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
VideoObserver() {}
~VideoObserver() {}
void SetVideoCallback(I420FRAMEREADY_CALLBACK callback);
protected:
// VideoSinkInterface implementation
void OnFrame(const webrtc::VideoFrame& frame) override;
private:
I420FRAMEREADY_CALLBACK OnI420FrameReady = nullptr;
std::mutex mutex;
};
void VideoObserver::SetVideoCallback(I420FRAMEREADY_CALLBACK callback) {
std::lock_guard<std::mutex> lock(mutex);
OnI420FrameReady = callback;
}
void VideoObserver::OnFrame(const webrtc::VideoFrame& frame) {
std::unique_lock<std::mutex> lock(mutex);
if (!OnI420FrameReady)
return;
webrtc::VideoFrameBuffer* buffer = frame.video_frame_buffer().get();
webrtc::AugmentedVideoFrameBuffer* augmented_data_buffer =
static_cast<webrtc::AugmentedVideoFrameBuffer*>(
frame.video_frame_buffer().get());
uint8_t* augmented_data = augmented_data_buffer->GetAugmentingData();
uint16_t augmented_data_size = augmented_data_buffer->GetAugmentingDataSize();
if (buffer->type() != webrtc::VideoFrameBuffer::Type::kI420A) {
rtc::scoped_refptr<webrtc::I420BufferInterface> i420_buffer =
buffer->ToI420();
OnI420FrameReady(i420_buffer->DataY(), i420_buffer->DataU(),
i420_buffer->DataV(), nullptr,
i420_buffer->StrideY(), i420_buffer->StrideU(),
i420_buffer->StrideV(), 0,
frame.width(), frame.height(),
augmented_data, augmented_data_size);
} else {
// The buffer has alpha channel.
webrtc::I420ABufferInterface* i420a_buffer = buffer->GetI420A();
OnI420FrameReady(i420a_buffer->DataY(), i420a_buffer->DataU(),
i420a_buffer->DataV(), i420a_buffer->DataA(),
i420a_buffer->StrideY(), i420a_buffer->StrideU(),
i420a_buffer->StrideV(), i420a_buffer->StrideA(),
frame.width(), frame.height(),
augmented_data, augmented_data_size);
}
}