Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(484)

Side by Side Diff: content/renderer/media/video_track_adapter.cc

Issue 246433006: Change MediaStreamVideoSource to output different resolutions to different tracks depending on the … (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "content/renderer/media/video_track_adapter.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/debug/trace_event.h"
13 #include "base/location.h"
14 #include "media/base/video_util.h"
15
16 namespace {
17
18 // Empty method used for keeping a reference to the original media::VideoFrame
19 // in VideoFrameResolutionAdapter::DeliverFrame if cropping is needed.
20 // The reference to |frame| is kept in the closure that calls this method.
21 void ReleaseOriginalFrame(
22 const scoped_refptr<media::VideoFrame>& frame) {
23 }
24
25 } // anonymous namespace
26
27 namespace content {
28
29 // VideoFrameResolutionAdapter is created on the main
30 // render thread but operates on the IO-thread. It does the resolution
31 // adaptation and delivers frames to all registered tracks on the IO-thread.
32 // All method calls except creation, must be on the IO-thread.
33 class VideoTrackAdapter::VideoFrameResolutionAdapter
34 : public base::RefCountedThreadSafe<VideoFrameResolutionAdapter> {
35 public:
36 VideoFrameResolutionAdapter(
37 int max_width,
38 int max_height,
39 double min_aspect_ratio,
40 double max_aspect_ratio);
41
42 // Add |callback| to receive video frames on the IO-thread.
43 void AddCallback(const MediaStreamVideoTrack* track,
44 const VideoCaptureDeliverFrameCB& callback);
45
46 // Removes |callback| associated with |id| from receiving video frames if
perkj_chrome 2014/05/08 11:59:02 |track|
perkj_chrome 2014/05/08 13:36:25 Done.
47 // |track| has been added. It is ok to call RemoveCallback even if the |id|
48 // has not been added.
49 void RemoveCallback(const MediaStreamVideoTrack* track);
50
51 void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
52 const media::VideoCaptureFormat& format);
53
54 // Returns true if all arguments match with the output of this adapter.
55 bool ConstraintsMatch(int max_width,
56 int max_height,
57 double min_aspect_ratio,
58 double max_aspect_ratio) const;
59
60 bool IsEmpty() const { return callbacks_.empty(); }
tommi (sloooow) - chröme 2014/05/08 11:57:58 would like to have a thread check here
perkj_chrome 2014/05/08 13:36:25 Done.
61
62 private:
63 virtual ~VideoFrameResolutionAdapter();
64 friend class base::RefCountedThreadSafe<VideoFrameResolutionAdapter>;
65
66 virtual void DoDeliverFrame(
67 const scoped_refptr<media::VideoFrame>& frame,
68 const media::VideoCaptureFormat& format);
69
70 // Bound to the IO-thread.
71 base::ThreadChecker io_thread_checker_;
72
73 gfx::Size max_frame_size_;
74 double min_aspect_ratio_;
75 double max_aspect_ratio_;
76
77 typedef std::pair<const void*, VideoCaptureDeliverFrameCB>
78 VideoIdCallbackPair;
79 std::vector<VideoIdCallbackPair> callbacks_;
80
81 DISALLOW_COPY_AND_ASSIGN(VideoFrameResolutionAdapter);
82 };
83
84 VideoTrackAdapter::
85 VideoFrameResolutionAdapter::VideoFrameResolutionAdapter(
86 int max_width,
perkj_chrome 2014/05/08 11:59:02 why separate arguments?
perkj_chrome 2014/05/08 13:36:25 On 2014/05/08 11:59:02, perkj wrote: > why separat
87 int max_height,
88 double min_aspect_ratio,
89 double max_aspect_ratio)
90 : max_frame_size_(max_width, max_height),
91 min_aspect_ratio_(min_aspect_ratio),
92 max_aspect_ratio_(max_aspect_ratio) {
93 DCHECK_GE(max_aspect_ratio_, min_aspect_ratio_);
94 DVLOG(3) << "VideoFrameResolutionAdapter("
95 << "{ max_width =" << max_width << "}, "
96 << "{ max_height =" << max_height << "}, "
97 << "{ min_aspect_ratio =" << min_aspect_ratio << "}, "
98 << "{ max_aspect_ratio_ =" << max_aspect_ratio_ << "}) ";
99 }
100
101 VideoTrackAdapter::
102 VideoFrameResolutionAdapter::~VideoFrameResolutionAdapter() {
103 DCHECK(callbacks_.empty());
tommi (sloooow) - chröme 2014/05/08 11:57:58 thread check
perkj_chrome 2014/05/08 13:36:25 Done.
104 }
105
106 void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
107 const scoped_refptr<media::VideoFrame>& frame,
108 const media::VideoCaptureFormat& format) {
109 DCHECK(io_thread_checker_.CalledOnValidThread());
110 // TODO(perkj): Allow cropping / scaling of textures once
111 // http://crbug/362521 is fixed.
112 if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
113 DoDeliverFrame(frame, format);
114 return;
115 }
116 scoped_refptr<media::VideoFrame> video_frame(frame);
117 double input_ratio =
118 static_cast<double>(frame->natural_size().width()) /
119 frame->natural_size().height();
120
121 // If |frame| has larger width or height than requested, or the aspect ratio
122 // does not match the requested, we want to create a wrapped version of this
123 // frame with a size that fulfills the constraints.
124 if (frame->natural_size().width() > max_frame_size_.width() ||
125 frame->natural_size().height() > max_frame_size_.height() ||
126 input_ratio > max_aspect_ratio_ ||
127 input_ratio < min_aspect_ratio_) {
128 int desired_width = std::min(max_frame_size_.width(),
129 frame->natural_size().width());
130 int desired_height = std::min(max_frame_size_.height(),
131 frame->natural_size().height());
132
133 double resulting_ratio =
134 static_cast<double>(desired_width) / desired_height;
135 double requested_ratio = resulting_ratio;
136
137 if (requested_ratio > max_aspect_ratio_)
138 requested_ratio = max_aspect_ratio_;
139 else if (requested_ratio < min_aspect_ratio_)
140 requested_ratio = min_aspect_ratio_;
141
142 if (resulting_ratio < requested_ratio) {
143 desired_height = static_cast<int>((desired_height * resulting_ratio) /
144 requested_ratio) + 1 & ~1;
tommi (sloooow) - chröme 2014/05/08 11:57:58 why & ~1? can you add documentation?
perkj_chrome 2014/05/08 13:36:25 That is kind of a good question- I did it to avoid
145 } else if (resulting_ratio > requested_ratio) {
146 desired_width = static_cast<int>((desired_width * requested_ratio) /
147 resulting_ratio) + 1 & ~1;
148 }
149
150 gfx::Size desired_size(desired_width, desired_height);
151
152 // Get the largest centered rectangle with the same aspect ratio of
153 // |desired_size| that fits entirely inside of |frame->visible_rect()|.
154 // This will be the rect we need to crop the original frame to.
155 // From this rect, the original frame can be scaled down to |desired_size|.
156 gfx::Rect region_in_frame =
157 media::ComputeLetterboxRegion(frame->visible_rect(), desired_size);
tommi (sloooow) - chröme 2014/05/08 11:57:58 indent
perkj_chrome 2014/05/08 13:36:25 Done.
158
159 video_frame = media::VideoFrame::WrapVideoFrame(
160 frame,
161 region_in_frame,
162 desired_size,
163 base::Bind(&ReleaseOriginalFrame, frame));
164
165 DVLOG(3) << "desired size " << desired_size.ToString()
166 << " output natural size "
167 << video_frame->natural_size().ToString()
168 << " output visible rect "
169 << video_frame->visible_rect().ToString();
170 }
171 DoDeliverFrame(video_frame, format);
172 }
173
174 void VideoTrackAdapter::
175 VideoFrameResolutionAdapter::DoDeliverFrame(
176 const scoped_refptr<media::VideoFrame>& frame,
177 const media::VideoCaptureFormat& format) {
178 for (std::vector<VideoIdCallbackPair>::const_iterator it = callbacks_.begin();
tommi (sloooow) - chröme 2014/05/08 11:57:58 thread check here or at least a comment that expla
perkj_chrome 2014/05/08 13:36:25 Done.
179 it != callbacks_.end(); ++it) {
180 it->second.Run(frame, format);
181 }
182 }
183
184 void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallback(
185 const MediaStreamVideoTrack* track,
186 const VideoCaptureDeliverFrameCB& callback) {
187 DCHECK(io_thread_checker_.CalledOnValidThread());
188 callbacks_.push_back(std::make_pair(track, callback));
189 }
190
191 void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallback(
192 const MediaStreamVideoTrack* track) {
193 DCHECK(io_thread_checker_.CalledOnValidThread());
194 std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
195 for (; it != callbacks_.end(); ++it) {
196 if (it->first == track) {
197 callbacks_.erase(it);
198 return;
199 }
200 }
201 }
202
203 bool VideoTrackAdapter::VideoFrameResolutionAdapter::ConstraintsMatch(
204 int max_width,
205 int max_height,
206 double min_aspect_ratio,
207 double max_aspect_ratio) const {
208 return max_frame_size_.width() == max_width &&
tommi (sloooow) - chröme 2014/05/08 11:57:58 thread check
perkj_chrome 2014/05/08 13:36:25 Done.
209 max_frame_size_.height() == max_height &&
210 min_aspect_ratio_ == min_aspect_ratio &&
211 max_aspect_ratio_ == max_aspect_ratio;
212 }
213
214 VideoTrackAdapter::VideoTrackAdapter(
215 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
216 : io_message_loop_(io_message_loop) {
217 }
218
219 VideoTrackAdapter::~VideoTrackAdapter() {
tommi (sloooow) - chröme 2014/05/08 11:57:58 thread check
perkj_chrome 2014/05/08 13:36:25 Can I do that ? its thread safe recounted and boun
220 DCHECK(adapters_.empty());
221 }
222
223 void VideoTrackAdapter::AddTrack(MediaStreamVideoTrack* track,
perkj_chrome 2014/05/08 11:59:02 const * track
perkj_chrome 2014/05/08 13:36:25 Done.
224 VideoCaptureDeliverFrameCB frame_callback,
225 int max_width,
226 int max_height,
227 double min_aspect_ratio,
228 double max_aspect_ratio) {
229 DCHECK(thread_checker_.CalledOnValidThread());
230 io_message_loop_->PostTask(
231 FROM_HERE,
232 base::Bind(&VideoTrackAdapter::AddTrackOnIO,
233 this, track, frame_callback, max_width, max_height,
234 min_aspect_ratio, max_aspect_ratio));
235 }
236
237 void VideoTrackAdapter::AddTrackOnIO(MediaStreamVideoTrack* track,
238 VideoCaptureDeliverFrameCB frame_callback,
239 int max_width,
240 int max_height,
241 double min_aspect_ratio,
242 double max_aspect_ratio) {
243 DCHECK(io_message_loop_->BelongsToCurrentThread());
244 scoped_refptr<VideoFrameResolutionAdapter> adapter;
245 for (FrameAdapters::const_iterator it = adapters_.begin();
246 it != adapters_.end(); ++it) {
247 if ((*it)->ConstraintsMatch(max_width, max_height, min_aspect_ratio,
248 max_aspect_ratio)) {
249 adapter = it->get();
250 break;
251 }
252 }
253 if (!adapter) {
254 adapter = new VideoFrameResolutionAdapter(max_width,
255 max_height,
256 min_aspect_ratio,
257 max_aspect_ratio);
258 adapters_.push_back(adapter);
259 }
260
261 adapter->AddCallback(track, frame_callback);
262 }
263
264 void VideoTrackAdapter::RemoveTrack(MediaStreamVideoTrack* track) {
265 DCHECK(thread_checker_.CalledOnValidThread());
266 io_message_loop_->PostTask(
267 FROM_HERE,
268 base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track));
269 }
270
271 void VideoTrackAdapter::RemoveTrackOnIO(MediaStreamVideoTrack* track) {
272 DCHECK(io_message_loop_->BelongsToCurrentThread());
273 for (FrameAdapters::iterator it = adapters_.begin();
274 it != adapters_.end(); ++it) {
275 (*it)->RemoveCallback(track);
276 if ((*it)->IsEmpty()) {
277 adapters_.erase(it);
278 break;
279 }
280 }
281 }
282
283 void VideoTrackAdapter::DeliverFrameOnIO(
284 const scoped_refptr<media::VideoFrame>& frame,
285 const media::VideoCaptureFormat& format) {
286 DCHECK(io_message_loop_->BelongsToCurrentThread());
287 TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO");
288 for (FrameAdapters::iterator it = adapters_.begin();
289 it != adapters_.end(); ++it) {
290 (*it)->DeliverFrame(frame, format);
291 }
292 }
293
294 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698