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

Side by Side Diff: content/renderer/media/webrtc/video_destination_handler.cc

Issue 212973002: Refactor VideoDestinationHandler to implement MediaStreamVideoSource. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 6 years, 8 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/video_destination_handler.h" 5 #include "content/renderer/media/webrtc/video_destination_handler.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/rand_util.h" 11 #include "base/rand_util.h"
12 #include "base/strings/utf_string_conversions.h"
12 #include "content/renderer/media/media_stream.h" 13 #include "content/renderer/media/media_stream.h"
13 #include "content/renderer/media/media_stream_dependency_factory.h" 14 #include "content/renderer/media/media_stream_dependency_factory.h"
14 #include "content/renderer/media/media_stream_registry_interface.h" 15 #include "content/renderer/media/media_stream_registry_interface.h"
16 #include "content/renderer/media/media_stream_video_track.h"
15 #include "content/renderer/pepper/ppb_image_data_impl.h" 17 #include "content/renderer/pepper/ppb_image_data_impl.h"
16 #include "content/renderer/render_thread_impl.h" 18 #include "content/renderer/render_thread_impl.h"
19 #include "media/video/capture/video_capture_types.h"
17 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 20 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
18 #include "third_party/WebKit/public/platform/WebURL.h" 21 #include "third_party/WebKit/public/platform/WebURL.h"
19 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" 22 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
23 #include "third_party/libyuv/include/libyuv/convert.h"
20 #include "url/gurl.h" 24 #include "url/gurl.h"
21 25
22 using cricket::CaptureState;
23 using cricket::VideoFormat;
24 using webrtc::VideoTrackInterface;
25 using webrtc::VideoTrackVector;
26
27 static const cricket::FourCC kEffectColorFormat = cricket::FOURCC_BGRA;
28
29 namespace content { 26 namespace content {
30 27
31 PpFrameWriter::PpFrameWriter() 28 PpFrameWriter::PpFrameWriter(MediaStreamDependencyFactory* factory)
32 : started_(false) {} 29 : MediaStreamVideoSource(factory), first_frame_received_(false) {
33 30 DVLOG(3) << "PpFrameWriter ctor";
34 PpFrameWriter::~PpFrameWriter() {}
35
36 CaptureState PpFrameWriter::Start(const VideoFormat& capture_format) {
37 base::AutoLock auto_lock(lock_);
38 if (started_) {
39 LOG(ERROR) << "PpFrameWriter::Start - "
40 << "Got a StartCapture when already started!";
41 return cricket::CS_FAILED;
42 }
43 started_ = true;
44 return cricket::CS_STARTING;
45 } 31 }
46 32
47 void PpFrameWriter::Stop() { 33 PpFrameWriter::~PpFrameWriter() {
48 base::AutoLock auto_lock(lock_); 34 DVLOG(3) << "PpFrameWriter dtor";
49 started_ = false;
50 SignalStateChange(this, cricket::CS_STOPPED);
51 } 35 }
52 36
53 bool PpFrameWriter::IsRunning() { 37 void PpFrameWriter::GetCurrentSupportedFormats(int max_requested_width,
54 return started_; 38 int max_requested_height) {
39 DCHECK(CalledOnValidThread());
40 DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
41 if (format_.IsValid()) {
42 media::VideoCaptureFormats formats;
43 formats.push_back(format_);
44 OnSupportedFormats(formats);
45 }
55 } 46 }
56 47
57 bool PpFrameWriter::GetPreferredFourccs(std::vector<uint32>* fourccs) { 48 void PpFrameWriter::StartSourceImpl(
58 if (!fourccs) { 49 const media::VideoCaptureParams& params) {
59 LOG(ERROR) << "PpFrameWriter::GetPreferredFourccs - " 50 DCHECK(CalledOnValidThread());
60 << "fourccs is NULL."; 51 DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
61 return false; 52 OnStartDone(true);
62 }
63 // The effects plugin output BGRA.
64 fourccs->push_back(kEffectColorFormat);
65 return true;
66 } 53 }
67 54
68 bool PpFrameWriter::GetBestCaptureFormat(const VideoFormat& desired, 55 void PpFrameWriter::StopSourceImpl() {
69 VideoFormat* best_format) { 56 DCHECK(CalledOnValidThread());
70 if (!best_format) {
71 LOG(ERROR) << "PpFrameWriter::GetBestCaptureFormat - "
72 << "best_format is NULL.";
73 return false;
74 }
75
76 // Use the desired format as the best format.
77 best_format->width = desired.width;
78 best_format->height = desired.height;
79 best_format->fourcc = kEffectColorFormat;
80 best_format->interval = desired.interval;
81 return true;
82 }
83
84 bool PpFrameWriter::IsScreencast() const {
85 return false;
86 } 57 }
87 58
88 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data, 59 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
89 int64 time_stamp_ns) { 60 int64 time_stamp_ns) {
90 base::AutoLock auto_lock(lock_); 61 DCHECK(CalledOnValidThread());
91 // This assumes the handler of the SignalFrameCaptured won't call Start/Stop. 62 DVLOG(3) << "PpFrameWriter::PutFrame()";
92 // TODO(ronghuawu): Avoid the using of lock. One way is to post this call to 63
93 // libjingle worker thread, which will require an extra copy of |image_data|.
94 // However if pepper host can hand over the ownership of |image_data|
95 // then we can avoid this extra copy.
96 if (!started_) {
97 LOG(ERROR) << "PpFrameWriter::PutFrame - "
98 << "Called when capturer is not started.";
99 return;
100 }
101 if (!image_data) { 64 if (!image_data) {
102 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data."; 65 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
103 return; 66 return;
104 } 67 }
105 ImageDataAutoMapper mapper(image_data); 68 ImageDataAutoMapper mapper(image_data);
106 if (!mapper.is_valid()) { 69 if (!mapper.is_valid()) {
107 LOG(ERROR) << "PpFrameWriter::PutFrame - " 70 LOG(ERROR) << "PpFrameWriter::PutFrame - "
108 << "The image could not be mapped and is unusable."; 71 << "The image could not be mapped and is unusable.";
109 return; 72 return;
110 } 73 }
111 const SkBitmap* bitmap = image_data->GetMappedBitmap(); 74 const SkBitmap* bitmap = image_data->GetMappedBitmap();
112 if (!bitmap) { 75 if (!bitmap) {
113 LOG(ERROR) << "PpFrameWriter::PutFrame - " 76 LOG(ERROR) << "PpFrameWriter::PutFrame - "
114 << "The image_data's mapped bitmap is NULL."; 77 << "The image_data's mapped bitmap is NULL.";
115 return; 78 return;
116 } 79 }
117 80
118 cricket::CapturedFrame frame; 81 const gfx::Size frame_size(bitmap->width(), bitmap->height());
119 frame.elapsed_time = 0; 82
120 frame.time_stamp = time_stamp_ns; 83 if (!first_frame_received_) {
121 frame.pixel_height = 1; 84 first_frame_received_ = true;
122 frame.pixel_width = 1; 85 format_ = media::VideoCaptureFormat(
123 frame.width = bitmap->width(); 86 frame_size,
124 frame.height = bitmap->height(); 87 MediaStreamVideoSource::kDefaultFrameRate,
125 if (image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL) { 88 media::PIXEL_FORMAT_I420);
126 frame.fourcc = cricket::FOURCC_BGRA; 89 if (state() == MediaStreamVideoSource::RETRIEVING_CAPABILITIES) {
127 } else { 90 media::VideoCaptureFormats formats;
128 LOG(ERROR) << "PpFrameWriter::PutFrame - Got RGBA which is not supported."; 91 formats.push_back(format_);
92 OnSupportedFormats(formats);
93 }
94 }
95
96 if (state() != MediaStreamVideoSource::STARTED)
129 return; 97 return;
130 }
131 frame.data_size = bitmap->getSize();
132 frame.data = bitmap->getPixels();
133 98
134 // This signals to libJingle that a new VideoFrame is available. 99 const base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(
135 // libJingle have no assumptions on what thread this signal come from. 100 time_stamp_ns / talk_base::kNumNanosecsPerMillisec);
136 SignalFrameCaptured(this, &frame); 101
102 scoped_refptr<media::VideoFrame> new_frame =
103 frame_pool_.CreateFrame(media::VideoFrame::I420, frame_size,
104 gfx::Rect(frame_size), frame_size, timestamp);
105
106 libyuv::BGRAToI420(reinterpret_cast<uint8*>(bitmap->getPixels()),
107 bitmap->rowBytes(),
108 new_frame->data(media::VideoFrame::kYPlane),
109 new_frame->stride(media::VideoFrame::kYPlane),
110 new_frame->data(media::VideoFrame::kUPlane),
111 new_frame->stride(media::VideoFrame::kUPlane),
112 new_frame->data(media::VideoFrame::kVPlane),
113 new_frame->stride(media::VideoFrame::kVPlane),
114 frame_size.width(), frame_size.height());
115
116 DeliverVideoFrame(new_frame);
137 } 117 }
138 118
139 // PpFrameWriterProxy is a helper class to make sure the user won't use 119 // PpFrameWriterProxy is a helper class to make sure the user won't use
140 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamTrack - 120 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
141 // is released). 121 // is released).
142 class PpFrameWriterProxy : public FrameWriterInterface { 122 class PpFrameWriterProxy : public FrameWriterInterface {
143 public: 123 public:
144 PpFrameWriterProxy(VideoTrackInterface* track, 124 explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
145 PpFrameWriter* writer) 125 : writer_(writer) {
146 : track_(track),
147 writer_(writer) {
148 DCHECK(writer_ != NULL); 126 DCHECK(writer_ != NULL);
149 } 127 }
150 128
151 virtual ~PpFrameWriterProxy() {} 129 virtual ~PpFrameWriterProxy() {}
152 130
153 virtual void PutFrame(PPB_ImageData_Impl* image_data, 131 virtual void PutFrame(PPB_ImageData_Impl* image_data,
154 int64 time_stamp_ns) OVERRIDE { 132 int64 time_stamp_ns) OVERRIDE {
155 writer_->PutFrame(image_data, time_stamp_ns); 133 writer_->PutFrame(image_data, time_stamp_ns);
156 } 134 }
157 135
158 private: 136 private:
159 scoped_refptr<VideoTrackInterface> track_; 137 base::WeakPtr<PpFrameWriter> writer_;
160 PpFrameWriter* writer_;
161 138
162 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy); 139 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
163 }; 140 };
164 141
165 bool VideoDestinationHandler::Open( 142 bool VideoDestinationHandler::Open(
166 MediaStreamDependencyFactory* factory, 143 MediaStreamDependencyFactory* factory,
167 MediaStreamRegistryInterface* registry, 144 MediaStreamRegistryInterface* registry,
168 const std::string& url, 145 const std::string& url,
169 FrameWriterInterface** frame_writer) { 146 FrameWriterInterface** frame_writer) {
147 DVLOG(3) << "VideoDestinationHandler::Open";
170 if (!factory) { 148 if (!factory) {
171 factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory(); 149 factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory();
172 DCHECK(factory != NULL); 150 DCHECK(factory != NULL);
173 } 151 }
174 blink::WebMediaStream stream; 152 blink::WebMediaStream stream;
175 if (registry) { 153 if (registry) {
176 stream = registry->GetMediaStream(url); 154 stream = registry->GetMediaStream(url);
177 } else { 155 } else {
178 stream = 156 stream =
179 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); 157 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
180 } 158 }
181 if (stream.isNull() || !stream.extraData()) { 159 if (stream.isNull()) {
182 LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url; 160 LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
183 return false; 161 return false;
184 } 162 }
185 163
186 // Create a new native video track and add it to |stream|. 164 // Create a new native video track and add it to |stream|.
187 std::string track_id; 165 std::string track_id;
188 // According to spec, a media stream track's id should be globally unique. 166 // According to spec, a media stream source's id should be unique per
189 // There's no easy way to strictly achieve that. The id generated with this 167 // application. There's no easy way to strictly achieve that. The id
190 // method should be unique for most of the cases but theoretically it's 168 // generated with this method should be unique for most of the cases but
191 // possible we can get an id that's duplicated with the existing tracks. 169 // theoretically it's possible we can get an id that's duplicated with the
170 // existing sources.
192 base::Base64Encode(base::RandBytesAsString(64), &track_id); 171 base::Base64Encode(base::RandBytesAsString(64), &track_id);
193 PpFrameWriter* writer = new PpFrameWriter(); 172 PpFrameWriter* writer = new PpFrameWriter(factory);
194 if (!factory->AddNativeVideoMediaTrack(track_id, &stream, writer)) {
195 delete writer;
196 return false;
197 }
198 173
199 // Gets a handler to the native video track, which owns the |writer|. 174 // Create a new webkit video track.
200 webrtc::MediaStreamInterface* native_stream = MediaStream::GetAdapter(stream); 175 blink::WebMediaStreamSource webkit_source;
201 DCHECK(native_stream); 176 blink::WebMediaStreamSource::Type type =
202 VideoTrackVector video_tracks = native_stream->GetVideoTracks(); 177 blink::WebMediaStreamSource::TypeVideo;
203 // Currently one supports one video track per media stream. 178 blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
204 DCHECK(video_tracks.size() == 1); 179 webkit_source.initialize(webkit_track_id, type, webkit_track_id);
180 webkit_source.setExtraData(writer);
205 181
206 *frame_writer = new PpFrameWriterProxy(video_tracks[0].get(), writer); 182 blink::WebMediaConstraints constraints;
183 constraints.initialize();
184 bool track_enabled = true;
185
186 stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
187 writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
188 track_enabled, factory));
189
190 *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
207 return true; 191 return true;
208 } 192 }
209 193
210 } // namespace content 194 } // namespace content
211 195
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698