Make VideoTrack and VideoTrackRenderers implement rtc::VideoSourceInterface.

This patch tries to only change the interface to VideoTrack, with
minimal changes to the implementation. Some points worth noting:

VideoTrackRenderers should ultimately be deleted, but it is kept for
now since we need an object implementing webrtc::VideoRenderer, and
that shouldn't be VideoTrack.

BUG=webrtc:5426
TBR=glaznev@webrtc.org  // please look at  examples

Review URL: https://codereview.webrtc.org/1684423002

Cr-Commit-Position: refs/heads/master@{#11775}
This commit is contained in:
nisse 2016-02-26 01:24:58 -08:00 committed by Commit bot
parent fc59c4425e
commit db25d2e8c5
10 changed files with 148 additions and 52 deletions

View File

@ -24,6 +24,7 @@
#include "webrtc/base/refcount.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/media/base/videosinkinterface.h"
#include "webrtc/media/base/videosourceinterface.h"
namespace cricket {
@ -121,12 +122,30 @@ class VideoRendererInterface
class VideoSourceInterface;
class VideoTrackInterface : public MediaStreamTrackInterface {
class VideoTrackInterface
: public MediaStreamTrackInterface,
public rtc::VideoSourceInterface<cricket::VideoFrame> {
public:
// Register a renderer that will render all frames received on this track.
virtual void AddRenderer(VideoRendererInterface* renderer) = 0;
// Deregister a renderer.
virtual void RemoveRenderer(VideoRendererInterface* renderer) = 0;
// Make an unqualified VideoSourceInterface resolve to
// webrtc::VideoSourceInterface, not our base class
// rtc::VideoSourceInterface<cricket::VideoFrame>.
using VideoSourceInterface = webrtc::VideoSourceInterface;
// AddRenderer and RemoveRenderer are for backwards compatibility
// only. They are obsoleted by the methods of
// rtc::VideoSourceInterface.
virtual void AddRenderer(VideoRendererInterface* renderer) {
AddOrUpdateSink(renderer, rtc::VideoSinkWants());
}
virtual void RemoveRenderer(VideoRendererInterface* renderer) {
RemoveSink(renderer);
}
// Register a video sink for this track.
void AddOrUpdateSink(rtc::VideoSinkInterface<cricket::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override{};
void RemoveSink(
rtc::VideoSinkInterface<cricket::VideoFrame>* sink) override{};
virtual VideoSourceInterface* GetSource() const = 0;

View File

@ -48,6 +48,11 @@ BEGIN_PROXY_MAP(VideoTrack)
PROXY_METHOD1(void, AddRenderer, VideoRendererInterface*)
PROXY_METHOD1(void, RemoveRenderer, VideoRendererInterface*)
PROXY_METHOD2(void,
AddOrUpdateSink,
rtc::VideoSinkInterface<cricket::VideoFrame>*,
const rtc::VideoSinkWants&)
PROXY_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<cricket::VideoFrame>*)
PROXY_CONSTMETHOD0(VideoSourceInterface*, GetSource)
PROXY_METHOD0(rtc::VideoSinkInterface<cricket::VideoFrame>*, GetSink)

View File

@ -16,18 +16,43 @@
namespace webrtc {
class FakeVideoTrackRenderer : public VideoRendererInterface {
class FakeVideoTrackRenderer
: public rtc::VideoSinkInterface<cricket::VideoFrame> {
public:
FakeVideoTrackRenderer(VideoTrackInterface* video_track)
: video_track_(video_track), last_frame_(NULL) {
video_track_->AddRenderer(this);
: video_track_(video_track) {
video_track_->AddOrUpdateSink(this, rtc::VideoSinkWants());
}
~FakeVideoTrackRenderer() {
video_track_->RemoveRenderer(this);
~FakeVideoTrackRenderer() { video_track_->RemoveSink(this); }
virtual void OnFrame(const cricket::VideoFrame& video_frame) override {
fake_renderer_.RenderFrame(&video_frame);
}
int errors() const { return fake_renderer_.errors(); }
int width() const { return fake_renderer_.width(); }
int height() const { return fake_renderer_.height(); }
bool black_frame() const { return fake_renderer_.black_frame(); }
int num_rendered_frames() const {
return fake_renderer_.num_rendered_frames();
}
private:
cricket::FakeVideoRenderer fake_renderer_;
rtc::scoped_refptr<VideoTrackInterface> video_track_;
};
// Similar class, testing the deprecated AddRenderer/RemoveRenderer methods.
class FakeVideoTrackRendererOld : public VideoRendererInterface {
public:
FakeVideoTrackRendererOld(VideoTrackInterface* video_track)
: video_track_(video_track) {
video_track_->AddRenderer(this);
}
~FakeVideoTrackRendererOld() { video_track_->RemoveRenderer(this); }
virtual void RenderFrame(const cricket::VideoFrame* video_frame) override {
last_frame_ = const_cast<cricket::VideoFrame*>(video_frame);
fake_renderer_.RenderFrame(video_frame);
}
@ -39,14 +64,10 @@ class FakeVideoTrackRenderer : public VideoRendererInterface {
int num_rendered_frames() const {
return fake_renderer_.num_rendered_frames();
}
const cricket::VideoFrame* last_frame() const { return last_frame_; }
private:
cricket::FakeVideoRenderer fake_renderer_;
rtc::scoped_refptr<VideoTrackInterface> video_track_;
// Weak reference for frame pointer comparison only.
cricket::VideoFrame* last_frame_;
};
} // namespace webrtc

View File

@ -33,12 +33,15 @@ std::string VideoTrack::kind() const {
return kVideoKind;
}
void VideoTrack::AddRenderer(VideoRendererInterface* renderer) {
renderers_.AddRenderer(renderer);
void VideoTrack::AddOrUpdateSink(
rtc::VideoSinkInterface<cricket::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) {
renderers_.AddOrUpdateSink(sink, wants);
}
void VideoTrack::RemoveRenderer(VideoRendererInterface* renderer) {
renderers_.RemoveRenderer(renderer);
void VideoTrack::RemoveSink(
rtc::VideoSinkInterface<cricket::VideoFrame>* sink) {
renderers_.RemoveSink(sink);
}
rtc::VideoSinkInterface<cricket::VideoFrame>* VideoTrack::GetSink() {
@ -51,7 +54,8 @@ bool VideoTrack::set_enabled(bool enable) {
}
rtc::scoped_refptr<VideoTrack> VideoTrack::Create(
const std::string& id, VideoSourceInterface* source) {
const std::string& id,
VideoSourceInterface* source) {
rtc::RefCountedObject<VideoTrack>* track =
new rtc::RefCountedObject<VideoTrack>(id, source);
return track;

View File

@ -22,11 +22,13 @@ namespace webrtc {
class VideoTrack : public MediaStreamTrack<VideoTrackInterface> {
public:
static rtc::scoped_refptr<VideoTrack> Create(
const std::string& label, VideoSourceInterface* source);
static rtc::scoped_refptr<VideoTrack> Create(const std::string& label,
VideoSourceInterface* source);
void AddOrUpdateSink(rtc::VideoSinkInterface<cricket::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override;
void RemoveSink(rtc::VideoSinkInterface<cricket::VideoFrame>* sink) override;
virtual void AddRenderer(VideoRendererInterface* renderer);
virtual void RemoveRenderer(VideoRendererInterface* renderer);
virtual VideoSourceInterface* GetSource() const {
return video_source_.get();
}

View File

@ -21,6 +21,7 @@
#include "webrtc/pc/channelmanager.h"
using webrtc::FakeVideoTrackRenderer;
using webrtc::FakeVideoTrackRendererOld;
using webrtc::VideoSource;
using webrtc::VideoTrack;
using webrtc::VideoTrackInterface;
@ -86,6 +87,47 @@ TEST_F(VideoTrackTest, RenderVideo) {
EXPECT_EQ(2, renderer_1->num_rendered_frames());
EXPECT_EQ(1, renderer_2->num_rendered_frames());
video_track_->RemoveSink(renderer_1.get());
renderer_input->OnFrame(frame);
EXPECT_EQ(2, renderer_1->num_rendered_frames());
EXPECT_EQ(2, renderer_2->num_rendered_frames());
}
// Test adding renderers to a video track and render to them by
// providing frames to the source. Uses the old VideoTrack interface
// with AddRenderer and RemoveRenderer.
TEST_F(VideoTrackTest, RenderVideoOld) {
// FakeVideoTrackRenderer register itself to |video_track_|
rtc::scoped_ptr<FakeVideoTrackRendererOld> renderer_1(
new FakeVideoTrackRendererOld(video_track_.get()));
rtc::VideoSinkInterface<cricket::VideoFrame>* renderer_input =
video_track_->GetSink();
ASSERT_FALSE(renderer_input == NULL);
cricket::WebRtcVideoFrame frame;
frame.InitToBlack(123, 123, 0);
renderer_input->OnFrame(frame);
EXPECT_EQ(1, renderer_1->num_rendered_frames());
EXPECT_EQ(123, renderer_1->width());
EXPECT_EQ(123, renderer_1->height());
// FakeVideoTrackRenderer register itself to |video_track_|
rtc::scoped_ptr<FakeVideoTrackRenderer> renderer_2(
new FakeVideoTrackRenderer(video_track_.get()));
renderer_input->OnFrame(frame);
EXPECT_EQ(123, renderer_1->width());
EXPECT_EQ(123, renderer_1->height());
EXPECT_EQ(123, renderer_2->width());
EXPECT_EQ(123, renderer_2->height());
EXPECT_EQ(2, renderer_1->num_rendered_frames());
EXPECT_EQ(1, renderer_2->num_rendered_frames());
video_track_->RemoveRenderer(renderer_1.get());
renderer_input->OnFrame(frame);

View File

@ -19,17 +19,21 @@ VideoTrackRenderers::VideoTrackRenderers() : enabled_(true) {
VideoTrackRenderers::~VideoTrackRenderers() {
}
void VideoTrackRenderers::AddRenderer(VideoRendererInterface* renderer) {
if (!renderer) {
return;
}
void VideoTrackRenderers::AddOrUpdateSink(
VideoSinkInterface<cricket::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) {
// TODO(nisse): Currently ignores wants. We should somehow use
// VideoBroadcaster, but we need to sort out its threading issues
// first.
rtc::CritScope cs(&critical_section_);
renderers_.insert(renderer);
if (std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end())
sinks_.push_back(sink);
}
void VideoTrackRenderers::RemoveRenderer(VideoRendererInterface* renderer) {
void VideoTrackRenderers::RemoveSink(
VideoSinkInterface<cricket::VideoFrame>* sink) {
rtc::CritScope cs(&critical_section_);
renderers_.erase(renderer);
sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());
}
void VideoTrackRenderers::SetEnabled(bool enable) {
@ -41,7 +45,7 @@ bool VideoTrackRenderers::RenderFrame(const cricket::VideoFrame* frame) {
{
rtc::CritScope cs(&critical_section_);
if (enabled_) {
RenderFrameToRenderers(frame);
RenderFrameToSinks(*frame);
return true;
}
}
@ -64,17 +68,16 @@ bool VideoTrackRenderers::RenderFrame(const cricket::VideoFrame* frame) {
// enabled while we generated the black frame. I think the
// enabled-ness ought to be applied at the track output, and hence
// an enabled track shouldn't send any blacked out frames.
RenderFrameToRenderers(enabled_ ? frame : &black);
RenderFrameToSinks(enabled_ ? *frame : black);
return true;
}
}
// Called with critical_section_ already locked
void VideoTrackRenderers::RenderFrameToRenderers(
const cricket::VideoFrame* frame) {
for (VideoRendererInterface* renderer : renderers_) {
renderer->RenderFrame(frame);
void VideoTrackRenderers::RenderFrameToSinks(const cricket::VideoFrame& frame) {
for (auto sink : sinks_) {
sink->OnFrame(frame);
}
}

View File

@ -25,7 +25,9 @@ namespace webrtc {
// Each VideoTrack owns a VideoTrackRenderers instance.
// The class is thread safe. Rendering to the added VideoRendererInterfaces is
// done on the same thread as the cricket::VideoRenderer.
class VideoTrackRenderers : public cricket::VideoRenderer {
class VideoTrackRenderers
: public cricket::VideoRenderer,
public rtc::VideoSourceInterface<cricket::VideoFrame> {
public:
VideoTrackRenderers();
~VideoTrackRenderers();
@ -34,18 +36,18 @@ class VideoTrackRenderers : public cricket::VideoRenderer {
// incoming frames are replaced by black frames.
virtual bool RenderFrame(const cricket::VideoFrame* frame);
void AddRenderer(VideoRendererInterface* renderer);
void RemoveRenderer(VideoRendererInterface* renderer);
void AddOrUpdateSink(VideoSinkInterface<cricket::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override;
void RemoveSink(VideoSinkInterface<cricket::VideoFrame>* sink) override;
void SetEnabled(bool enable);
private:
// Pass the frame on to to each registered renderer. Requires
// critical_section_ already locked.
void RenderFrameToRenderers(const cricket::VideoFrame* frame);
void RenderFrameToSinks(const cricket::VideoFrame& frame);
bool enabled_;
std::set<VideoRendererInterface*> renderers_;
std::vector<VideoSinkInterface<cricket::VideoFrame>*> sinks_;
rtc::CriticalSection critical_section_; // Protects the above variables
};

View File

@ -460,11 +460,11 @@ GtkMainWnd::VideoRenderer::VideoRenderer(
height_(0),
main_wnd_(main_wnd),
rendered_track_(track_to_render) {
rendered_track_->AddRenderer(this);
rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants());
}
GtkMainWnd::VideoRenderer::~VideoRenderer() {
rendered_track_->RemoveRenderer(this);
rendered_track_->RemoveSink(this);
}
void GtkMainWnd::VideoRenderer::SetSize(int width, int height) {
@ -480,11 +480,11 @@ void GtkMainWnd::VideoRenderer::SetSize(int width, int height) {
gdk_threads_leave();
}
void GtkMainWnd::VideoRenderer::RenderFrame(
const cricket::VideoFrame* video_frame) {
void GtkMainWnd::VideoRenderer::OnFrame(
const cricket::VideoFrame& video_frame) {
gdk_threads_enter();
const cricket::VideoFrame* frame = video_frame->GetCopyWithRotationApplied();
const cricket::VideoFrame* frame = video_frame.GetCopyWithRotationApplied();
SetSize(static_cast<int>(frame->GetWidth()),
static_cast<int>(frame->GetHeight()));
@ -511,5 +511,3 @@ void GtkMainWnd::VideoRenderer::RenderFrame(
g_idle_add(Redraw, main_wnd_);
}

View File

@ -71,7 +71,7 @@ class GtkMainWnd : public MainWindow {
void OnRedraw();
protected:
class VideoRenderer : public webrtc::VideoRendererInterface {
class VideoRenderer : public rtc::VideoSinkInterface<cricket::VideoFrame> {
public:
VideoRenderer(GtkMainWnd* main_wnd,
webrtc::VideoTrackInterface* track_to_render);
@ -79,7 +79,7 @@ class GtkMainWnd : public MainWindow {
// VideoRendererInterface implementation
virtual void SetSize(int width, int height);
virtual void RenderFrame(const cricket::VideoFrame* frame);
virtual void OnFrame(const cricket::VideoFrame& frame);
const uint8_t* image() const { return image_.get(); }