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

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: 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.
mcasas 2014/05/07 14:10:43 This threading detail should go in the header file
perkj_chrome 2014/05/08 11:29:47 This class only exist as an internal class. So doc
mcasas 2014/05/09 07:46:24 After offline discussion, I buy the classes' divis
32 // All method calls except creation, must be on the IO-thread.
mcasas 2014/05/07 14:10:43 nit: double space after "must be"
perkj_chrome 2014/05/08 11:29:47 Done.
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(MediaStreamVideoTrack* track,
44 const VideoCaptureDeliverFrameCB& callback);
45
46 // Removes |callback| associated with |id| from receiving video frames if
47 // |track| has been added. It is ok to call RemoveCallback even if the |id|
48 // has not been added.
49 void RemoveCallback(MediaStreamVideoTrack* track);
50
51 virtual void DeliverFrame(
52 const scoped_refptr<media::VideoFrame>& frame,
53 const media::VideoCaptureFormat& format);
54
55 // Returns true if all arguments match with the output of this adapter.
56 bool ConstraintsMatch(int max_width,
57 int max_height,
58 double min_aspect_ratio,
59 double max_aspect_ratio) const;
60
61 bool IsEmpty() const { return callbacks_.empty(); }
62
63 private:
64 virtual ~VideoFrameResolutionAdapter();
65 friend class base::RefCountedThreadSafe<VideoFrameResolutionAdapter>;
66
67 virtual void DoDeliverFrame(
68 const scoped_refptr<media::VideoFrame>& frame,
69 const media::VideoCaptureFormat& format);
70
71 // Bound to the IO-thread.
72 base::ThreadChecker io_thread_checker_;
73
74 gfx::Size max_frame_size_;
75 double min_aspect_ratio_;
76 double max_aspect_ratio_;
77
78 typedef std::pair<void*, VideoCaptureDeliverFrameCB> VideoIdCallbackPair;
79 std::vector<VideoIdCallbackPair> callbacks_;
mcasas 2014/05/07 14:10:43 std::list? Only used for push_back() and iterator-
perkj_chrome 2014/05/08 11:29:47 dito.
80
81 DISALLOW_COPY_AND_ASSIGN(VideoFrameResolutionAdapter);
82 };
83
84 VideoTrackAdapter::
85 VideoFrameResolutionAdapter::VideoFrameResolutionAdapter(
86 int max_width,
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
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());
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);
mcasas 2014/05/07 14:10:43 Move to l.152?
perkj_chrome 2014/05/08 11:29:47 line 169 DoDeliverFrame(video_frame, format) shou
117 double input_ratio =
118 static_cast<double>(frame->natural_size().width()) /
119 frame->natural_size().height();
120
121 if (frame->natural_size().width() > max_frame_size_.width() ||
mcasas 2014/05/07 14:10:43 Perhaps add comment here? Like: "If the input |fra
perkj_chrome 2014/05/08 11:29:47 Done.
122 frame->natural_size().height() > max_frame_size_.height() ||
123 input_ratio > max_aspect_ratio_ ||
124 input_ratio < min_aspect_ratio_) {
125 int desired_width = std::min(max_frame_size_.width(),
mcasas 2014/05/07 14:10:43 I'd love to see some human-parseable comment on th
perkj_chrome 2014/05/08 11:29:47 Done.
126 frame->natural_size().width());
127 int desired_height = std::min(max_frame_size_.height(),
128 frame->natural_size().height());
129
130 double resulting_ratio =
131 static_cast<double>(desired_width) / desired_height;
132 double requested_ratio = resulting_ratio;
133
134 if (requested_ratio > max_aspect_ratio_)
135 requested_ratio = max_aspect_ratio_;
136
137 if (requested_ratio < min_aspect_ratio_)
mcasas 2014/05/07 14:10:43 else if? |requested_ratio_| should not be larger t
perkj_chrome 2014/05/08 11:29:47 done in ctor
138 requested_ratio = min_aspect_ratio_;
139
140 if (resulting_ratio < requested_ratio) {
141 desired_height = static_cast<int>((desired_height * resulting_ratio) /
142 requested_ratio) + 1 & ~1;
143 } else if (resulting_ratio > requested_ratio) {
144 desired_width = static_cast<int>((desired_width * requested_ratio) /
145 resulting_ratio) + 1 & ~1;
146 }
147
148 gfx::Size desired_size(desired_width, desired_height);
149 gfx::Rect region_in_frame =
150 media::ComputeLetterboxRegion(frame->visible_rect(), desired_size);
151
152 video_frame = media::VideoFrame::WrapVideoFrame(
153 frame,
154 region_in_frame,
155 desired_size,
156 base::Bind(&ReleaseOriginalFrame, frame));
157
158 DVLOG(3) << "desired width " << desired_width
159 << " desired height " << desired_height
160 << " output natural width "
161 << video_frame->natural_size().width()
mcasas 2014/05/07 14:10:43 nit: video_frame->natural_size() has a ToString()
perkj_chrome 2014/05/08 11:29:47 Done.
162 << " output natural height "
163 << video_frame->natural_size().height()
164 << " output visible rect width "
165 << video_frame->visible_rect().width()
166 << " output visible rect height "
167 << video_frame->visible_rect().height();
168 }
169 DoDeliverFrame(video_frame, format);
170 }
171
172 void VideoTrackAdapter::
173 VideoFrameResolutionAdapter::DoDeliverFrame(
174 const scoped_refptr<media::VideoFrame>& frame,
175 const media::VideoCaptureFormat& format) {
176 for (std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
mcasas 2014/05/07 14:10:43 const_iterator?
perkj_chrome 2014/05/08 11:29:47 Done.
177 it != callbacks_.end(); ++it) {
178 it->second.Run(frame, format);
179 }
180 }
181
182 void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallback(
183 MediaStreamVideoTrack* track,
184 const VideoCaptureDeliverFrameCB& callback) {
185 DCHECK(io_thread_checker_.CalledOnValidThread());
186 callbacks_.push_back(std::make_pair(track, callback));
187 }
188
189 void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallback(
190 MediaStreamVideoTrack* track) {
191 DCHECK(io_thread_checker_.CalledOnValidThread());
192 std::vector<VideoIdCallbackPair>::iterator it = callbacks_.begin();
193 for (; it != callbacks_.end(); ++it) {
194 if (it->first == track) {
195 callbacks_.erase(it);
196 return;
197 }
198 }
199 }
200
201 bool VideoTrackAdapter::VideoFrameResolutionAdapter::ConstraintsMatch(
202 int max_width,
203 int max_height,
204 double min_aspect_ratio,
205 double max_aspect_ratio) const {
206 return max_frame_size_.width() == max_width &&
207 max_frame_size_.height() == max_height &&
208 min_aspect_ratio_ == min_aspect_ratio &&
209 max_aspect_ratio_ == max_aspect_ratio;
210 }
211
212 VideoTrackAdapter::VideoTrackAdapter(
213 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
214 : io_message_loop_(io_message_loop) {
215 }
216
217 VideoTrackAdapter::~VideoTrackAdapter() {
218 DCHECK(adapters_.empty());
219 }
220
221 void VideoTrackAdapter::AddTrack(MediaStreamVideoTrack* track,
mcasas 2014/05/07 14:10:43 The naked pointer stands out. Could we at least qu
perkj_chrome 2014/05/08 11:29:47 Done.
222 VideoCaptureDeliverFrameCB frame_callback,
223 int max_width,
224 int max_height,
225 double min_aspect_ratio,
226 double max_aspect_ratio) {
227 DCHECK(thread_checker_.CalledOnValidThread());
228 io_message_loop_->PostTask(
229 FROM_HERE,
230 base::Bind(&VideoTrackAdapter::AddTrackOnIO,
231 this, track, frame_callback, max_width, max_height,
232 min_aspect_ratio, max_aspect_ratio));
233 }
234
235 void VideoTrackAdapter::AddTrackOnIO(MediaStreamVideoTrack* track,
236 VideoCaptureDeliverFrameCB frame_callback,
237 int max_width,
238 int max_height,
239 double min_aspect_ratio,
240 double max_aspect_ratio) {
241 DCHECK(io_message_loop_->BelongsToCurrentThread());
242 scoped_refptr<VideoFrameResolutionAdapter> adapter;
243 for (FrameAdapters::iterator it = adapters_.begin(); it != adapters_.end();
mcasas 2014/05/07 14:10:43 const_iterator?
perkj_chrome 2014/05/08 11:29:47 Done.
perkj_chrome 2014/05/08 11:29:47 Done.
244 ++it) {
245 if ((*it)->ConstraintsMatch(max_width, max_height, min_aspect_ratio,
246 max_aspect_ratio)) {
247 adapter = it->get();
248 break;
249 }
250 }
251 if (!adapter) {
252 adapter = new VideoFrameResolutionAdapter(max_width,
253 max_height,
254 min_aspect_ratio,
255 max_aspect_ratio);
256 adapters_.push_back(adapter);
257 }
258
259 adapter->AddCallback(track, frame_callback);
260 }
261
262 void VideoTrackAdapter::RemoveTrack(MediaStreamVideoTrack* track) {
263 DCHECK(thread_checker_.CalledOnValidThread());
264 io_message_loop_->PostTask(
265 FROM_HERE,
266 base::Bind(&VideoTrackAdapter::RemoveTrackOnIO, this, track));
267 }
268
269 void VideoTrackAdapter::RemoveTrackOnIO(MediaStreamVideoTrack* track) {
270 DCHECK(io_message_loop_->BelongsToCurrentThread());
271 for (FrameAdapters::iterator it = adapters_.begin();
272 it != adapters_.end(); ++it) {
273 (*it)->RemoveCallback(track);
274 if ((*it)->IsEmpty()) {
275 adapters_.erase(it);
276 break;
277 }
278 }
279 }
280
281 void VideoTrackAdapter::DeliverFrameOnIO(
282 const scoped_refptr<media::VideoFrame>& frame,
283 const media::VideoCaptureFormat& format) {
284 DCHECK(io_message_loop_->BelongsToCurrentThread());
285 TRACE_EVENT0("video", "VideoTrackAdapter::DeliverFrameOnIO");
286 for (FrameAdapters::iterator it = adapters_.begin();
287 it != adapters_.end(); ++it) {
288 (*it)->DeliverFrame(frame, format);
289 }
290 }
291
292 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698