1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/webrtc/webrtc_video_track_adapter.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/synchronization/lock.h"
9 #include "content/common/media/media_stream_options.h"
10 #include "content/renderer/media/media_stream_video_source.h"
11 #include "content/renderer/media/media_stream_video_track.h"
15 bool ConstraintKeyExists(const blink::WebMediaConstraints
& constraints
,
16 const blink::WebString
& name
) {
17 blink::WebString value_str
;
18 return constraints
.getMandatoryConstraintValue(name
, value_str
) ||
19 constraints
.getOptionalConstraintValue(name
, value_str
);
22 } // anonymouse namespace
26 // Simple help class used for receiving video frames on the IO-thread from
27 // a MediaStreamVideoTrack and forward the frames to a
28 // WebRtcVideoCapturerAdapter on libjingle's worker thread.
29 // WebRtcVideoCapturerAdapter implements a video capturer for libjingle.
30 class WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter
31 : public base::RefCountedThreadSafe
<WebRtcVideoSourceAdapter
> {
33 WebRtcVideoSourceAdapter(
34 const scoped_refptr
<base::MessageLoopProxy
>& libjingle_worker_thread
,
35 const scoped_refptr
<webrtc::VideoSourceInterface
>& source
,
36 WebRtcVideoCapturerAdapter
* capture_adapter
);
38 // WebRtcVideoTrackAdapter can be destroyed on the main render thread or
39 // libjingles worker thread since it posts video frames on that thread. But
40 // |video_source_| must be released on the main render thread before the
41 // PeerConnectionFactory has been destroyed. The only way to ensure that is
42 // to make sure |video_source_| is released when WebRtcVideoTrackAdapter() is
44 void ReleaseSourceOnMainThread();
46 void OnVideoFrameOnIO(const scoped_refptr
<media::VideoFrame
>& frame
,
47 const media::VideoCaptureFormat
& format
,
48 const base::TimeTicks
& estimated_capture_time
);
51 void OnVideoFrameOnWorkerThread(
52 const scoped_refptr
<media::VideoFrame
>& frame
,
53 const media::VideoCaptureFormat
& format
,
54 const base::TimeTicks
& estimated_capture_time
);
55 friend class base::RefCountedThreadSafe
<WebRtcVideoSourceAdapter
>;
56 virtual ~WebRtcVideoSourceAdapter();
58 scoped_refptr
<base::MessageLoopProxy
> render_thread_message_loop_
;
60 // |render_thread_checker_| is bound to the main render thread.
61 base::ThreadChecker render_thread_checker_
;
62 // Used to DCHECK that frames are called on the IO-thread.
63 base::ThreadChecker io_thread_checker_
;
65 // Used for posting frames to libjingle's worker thread. Accessed on the
67 scoped_refptr
<base::MessageLoopProxy
> libjingle_worker_thread_
;
69 scoped_refptr
<webrtc::VideoSourceInterface
> video_source_
;
71 // Used to protect |capture_adapter_|. It is taken by libjingle's worker
72 // thread for each video frame that is delivered but only taken on the
73 // main render thread in ReleaseSourceOnMainThread() when
74 // the owning WebRtcVideoTrackAdapter is being destroyed.
75 base::Lock capture_adapter_stop_lock_
;
76 // |capture_adapter_| is owned by |video_source_|
77 WebRtcVideoCapturerAdapter
* capture_adapter_
;
80 WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::WebRtcVideoSourceAdapter(
81 const scoped_refptr
<base::MessageLoopProxy
>& libjingle_worker_thread
,
82 const scoped_refptr
<webrtc::VideoSourceInterface
>& source
,
83 WebRtcVideoCapturerAdapter
* capture_adapter
)
84 : render_thread_message_loop_(base::MessageLoopProxy::current()),
85 libjingle_worker_thread_(libjingle_worker_thread
),
86 video_source_(source
),
87 capture_adapter_(capture_adapter
) {
88 io_thread_checker_
.DetachFromThread();
91 WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::~WebRtcVideoSourceAdapter() {
92 DVLOG(3) << "~WebRtcVideoSourceAdapter()";
93 DCHECK(!capture_adapter_
);
94 // This object can be destroyed on the main render thread or libjingles
95 // worker thread since it posts video frames on that thread. But
96 // |video_source_| must be released on the main render thread before the
97 // PeerConnectionFactory has been destroyed. The only way to ensure that is
98 // to make sure |video_source_| is released when WebRtcVideoTrackAdapter() is
102 void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::
103 ReleaseSourceOnMainThread() {
104 DCHECK(render_thread_checker_
.CalledOnValidThread());
105 // Since frames are posted to the worker thread, this object might be deleted
106 // on that thread. However, since |video_source_| was created on the render
107 // thread, it should be released on the render thread.
108 base::AutoLock
auto_lock(capture_adapter_stop_lock_
);
109 // |video_source| owns |capture_adapter_|.
110 capture_adapter_
= NULL
;
111 video_source_
= NULL
;
114 void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnIO(
115 const scoped_refptr
<media::VideoFrame
>& frame
,
116 const media::VideoCaptureFormat
& format
,
117 const base::TimeTicks
& estimated_capture_time
) {
118 DCHECK(io_thread_checker_
.CalledOnValidThread());
119 libjingle_worker_thread_
->PostTask(
121 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread
,
122 this, frame
, format
, estimated_capture_time
));
126 WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread(
127 const scoped_refptr
<media::VideoFrame
>& frame
,
128 const media::VideoCaptureFormat
& format
,
129 const base::TimeTicks
& estimated_capture_time
) {
130 DCHECK(libjingle_worker_thread_
->BelongsToCurrentThread());
131 base::AutoLock
auto_lock(capture_adapter_stop_lock_
);
132 if (capture_adapter_
)
133 capture_adapter_
->OnFrameCaptured(frame
);
136 WebRtcVideoTrackAdapter::WebRtcVideoTrackAdapter(
137 const blink::WebMediaStreamTrack
& track
,
138 PeerConnectionDependencyFactory
* factory
)
139 : web_track_(track
) {
140 const blink::WebMediaConstraints
& constraints
=
141 MediaStreamVideoTrack::GetVideoTrack(track
)->constraints();
143 bool is_screencast
= ConstraintKeyExists(
144 constraints
, base::UTF8ToUTF16(kMediaStreamSource
));
145 WebRtcVideoCapturerAdapter
* capture_adapter
=
146 factory
->CreateVideoCapturer(is_screencast
);
148 // |video_source| owns |capture_adapter|
149 scoped_refptr
<webrtc::VideoSourceInterface
> video_source(
150 factory
->CreateVideoSource(capture_adapter
,
151 track
.source().constraints()));
153 video_track_
= factory
->CreateLocalVideoTrack(web_track_
.id().utf8(),
156 video_track_
->set_enabled(web_track_
.isEnabled());
158 source_adapter_
= new WebRtcVideoSourceAdapter(
159 factory
->GetWebRtcWorkerThread(),
165 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO
,
169 DVLOG(3) << "WebRtcVideoTrackAdapter ctor() : is_screencast "
173 WebRtcVideoTrackAdapter::~WebRtcVideoTrackAdapter() {
174 DCHECK(thread_checker_
.CalledOnValidThread());
175 DVLOG(3) << "WebRtcVideoTrackAdapter dtor().";
176 RemoveFromVideoTrack(this, web_track_
);
177 source_adapter_
->ReleaseSourceOnMainThread();
180 void WebRtcVideoTrackAdapter::OnEnabledChanged(bool enabled
) {
181 DCHECK(thread_checker_
.CalledOnValidThread());
182 video_track_
->set_enabled(enabled
);
185 } // namespace content