blob: 0f3ed5c56c07dd8d8cd96e6daeba9aac34ddd4dd [file]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/protocol/webrtc_video_renderer_adapter.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/threading/worker_pool.h"
#include "remoting/protocol/frame_consumer.h"
#include "third_party/libyuv/include/libyuv/video_common.h"
#include "third_party/webrtc/media/base/videoframe.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
namespace remoting {
namespace protocol {
namespace {
std::unique_ptr<webrtc::DesktopFrame> ConvertYuvToRgb(
std::unique_ptr<cricket::VideoFrame> yuv_frame,
std::unique_ptr<webrtc::DesktopFrame> rgb_frame,
uint32_t format) {
yuv_frame->ConvertToRgbBuffer(
format, rgb_frame->data(),
std::abs(rgb_frame->stride()) * rgb_frame->size().height(),
rgb_frame->stride());
rgb_frame->mutable_updated_region()->AddRect(
webrtc::DesktopRect::MakeSize(rgb_frame->size()));
return rgb_frame;
}
} // namespace
WebrtcVideoRendererAdapter::WebrtcVideoRendererAdapter(
scoped_refptr<webrtc::MediaStreamInterface> media_stream,
FrameConsumer* frame_consumer)
: media_stream_(std::move(media_stream)),
frame_consumer_(frame_consumer),
output_format_fourcc_(frame_consumer_->GetPixelFormat() ==
FrameConsumer::FORMAT_BGRA
? libyuv::FOURCC_ARGB
: libyuv::FOURCC_ABGR),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_factory_(this) {
webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks();
if (video_tracks.empty()) {
LOG(ERROR) << "Received media stream with no video tracks.";
return;
}
if (video_tracks.size() > 1U) {
LOG(WARNING) << "Received media stream with multiple video tracks.";
}
video_tracks[0]->AddOrUpdateSink(this, rtc::VideoSinkWants());
}
WebrtcVideoRendererAdapter::~WebrtcVideoRendererAdapter() {
DCHECK(task_runner_->BelongsToCurrentThread());
webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks();
DCHECK(!video_tracks.empty());
video_tracks[0]->RemoveSink(this);
}
void WebrtcVideoRendererAdapter::OnFrame(const cricket::VideoFrame& frame) {
task_runner_->PostTask(
FROM_HERE,
base::Bind(&WebrtcVideoRendererAdapter::HandleFrameOnMainThread,
weak_factory_.GetWeakPtr(),
base::Passed(base::WrapUnique(frame.Copy()))));
}
void WebrtcVideoRendererAdapter::HandleFrameOnMainThread(
std::unique_ptr<cricket::VideoFrame> frame) {
DCHECK(task_runner_->BelongsToCurrentThread());
std::unique_ptr<webrtc::DesktopFrame> rgb_frame =
frame_consumer_->AllocateFrame(
webrtc::DesktopSize(frame->width(), frame->height()));
if (static_cast<uint64_t>(frame->timestamp_us()) >= rtc::TimeMicros()) {
// The host sets playout delay to 0, so all incoming frames are expected to
// be rendered as so as they are received.
LOG(WARNING) << "Received frame with playout delay greater than 0.";
}
base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(false).get(), FROM_HERE,
base::Bind(&ConvertYuvToRgb, base::Passed(&frame),
base::Passed(&rgb_frame), output_format_fourcc_),
base::Bind(&WebrtcVideoRendererAdapter::DrawFrame,
weak_factory_.GetWeakPtr()));
}
void WebrtcVideoRendererAdapter::DrawFrame(
std::unique_ptr<webrtc::DesktopFrame> frame) {
DCHECK(task_runner_->BelongsToCurrentThread());
frame_consumer_->DrawFrame(std::move(frame), base::Closure());
}
} // namespace protocol
} // namespace remoting