OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/renderer/media/video_destination_handler.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/base64.h" | |
10 #include "base/logging.h" | |
11 #include "base/rand_util.h" | |
12 #include "content/renderer/media/media_stream.h" | |
13 #include "content/renderer/media/media_stream_dependency_factory.h" | |
14 #include "content/renderer/media/media_stream_registry_interface.h" | |
15 #include "content/renderer/pepper/ppb_image_data_impl.h" | |
16 #include "content/renderer/render_thread_impl.h" | |
17 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" | |
18 #include "third_party/WebKit/public/platform/WebURL.h" | |
19 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" | |
20 #include "url/gurl.h" | |
21 | |
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 { | |
30 | |
31 PpFrameWriter::PpFrameWriter() | |
32 : started_(false) {} | |
33 | |
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 } | |
46 | |
47 void PpFrameWriter::Stop() { | |
48 base::AutoLock auto_lock(lock_); | |
49 started_ = false; | |
50 SignalStateChange(this, cricket::CS_STOPPED); | |
51 } | |
52 | |
53 bool PpFrameWriter::IsRunning() { | |
54 return started_; | |
55 } | |
56 | |
57 bool PpFrameWriter::GetPreferredFourccs(std::vector<uint32>* fourccs) { | |
58 if (!fourccs) { | |
59 LOG(ERROR) << "PpFrameWriter::GetPreferredFourccs - " | |
60 << "fourccs is NULL."; | |
61 return false; | |
62 } | |
63 // The effects plugin output BGRA. | |
64 fourccs->push_back(kEffectColorFormat); | |
65 return true; | |
66 } | |
67 | |
68 bool PpFrameWriter::GetBestCaptureFormat(const VideoFormat& desired, | |
69 VideoFormat* best_format) { | |
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 } | |
87 | |
88 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data, | |
89 int64 time_stamp_ns) { | |
90 base::AutoLock auto_lock(lock_); | |
91 // This assumes the handler of the SignalFrameCaptured won't call Start/Stop. | |
92 // TODO(ronghuawu): Avoid the using of lock. One way is to post this call to | |
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) { | |
102 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data."; | |
103 return; | |
104 } | |
105 ImageDataAutoMapper mapper(image_data); | |
106 if (!mapper.is_valid()) { | |
107 LOG(ERROR) << "PpFrameWriter::PutFrame - " | |
108 << "The image could not be mapped and is unusable."; | |
109 return; | |
110 } | |
111 const SkBitmap* bitmap = image_data->GetMappedBitmap(); | |
112 if (!bitmap) { | |
113 LOG(ERROR) << "PpFrameWriter::PutFrame - " | |
114 << "The image_data's mapped bitmap is NULL."; | |
115 return; | |
116 } | |
117 | |
118 cricket::CapturedFrame frame; | |
119 frame.elapsed_time = 0; | |
120 frame.time_stamp = time_stamp_ns; | |
121 frame.pixel_height = 1; | |
122 frame.pixel_width = 1; | |
123 frame.width = bitmap->width(); | |
124 frame.height = bitmap->height(); | |
125 if (image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL) { | |
126 frame.fourcc = cricket::FOURCC_BGRA; | |
127 } else { | |
128 LOG(ERROR) << "PpFrameWriter::PutFrame - Got RGBA which is not supported."; | |
129 return; | |
130 } | |
131 frame.data_size = bitmap->getSize(); | |
132 frame.data = bitmap->getPixels(); | |
133 | |
134 // This signals to libJingle that a new VideoFrame is available. | |
135 // libJingle have no assumptions on what thread this signal come from. | |
136 SignalFrameCaptured(this, &frame); | |
137 } | |
138 | |
139 // PpFrameWriterProxy is a helper class to make sure the user won't use | |
140 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamTrack - | |
141 // is released). | |
142 class PpFrameWriterProxy : public FrameWriterInterface { | |
143 public: | |
144 PpFrameWriterProxy(VideoTrackInterface* track, | |
145 PpFrameWriter* writer) | |
146 : track_(track), | |
147 writer_(writer) { | |
148 DCHECK(writer_ != NULL); | |
149 } | |
150 | |
151 virtual ~PpFrameWriterProxy() {} | |
152 | |
153 virtual void PutFrame(PPB_ImageData_Impl* image_data, | |
154 int64 time_stamp_ns) OVERRIDE { | |
155 writer_->PutFrame(image_data, time_stamp_ns); | |
156 } | |
157 | |
158 private: | |
159 scoped_refptr<VideoTrackInterface> track_; | |
160 PpFrameWriter* writer_; | |
161 | |
162 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy); | |
163 }; | |
164 | |
165 bool VideoDestinationHandler::Open( | |
166 MediaStreamDependencyFactory* factory, | |
167 MediaStreamRegistryInterface* registry, | |
168 const std::string& url, | |
169 FrameWriterInterface** frame_writer) { | |
170 if (!factory) { | |
171 factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory(); | |
172 DCHECK(factory != NULL); | |
173 } | |
174 blink::WebMediaStream stream; | |
175 if (registry) { | |
176 stream = registry->GetMediaStream(url); | |
177 } else { | |
178 stream = | |
179 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); | |
180 } | |
181 if (stream.isNull() || !stream.extraData()) { | |
182 LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url; | |
183 return false; | |
184 } | |
185 | |
186 // Create a new native video track and add it to |stream|. | |
187 std::string track_id; | |
188 // According to spec, a media stream track's id should be globally unique. | |
189 // There's no easy way to strictly achieve that. The id generated with this | |
190 // method should be unique for most of the cases but theoretically it's | |
191 // possible we can get an id that's duplicated with the existing tracks. | |
192 base::Base64Encode(base::RandBytesAsString(64), &track_id); | |
193 PpFrameWriter* writer = new PpFrameWriter(); | |
194 if (!factory->AddNativeVideoMediaTrack(track_id, &stream, writer)) { | |
195 delete writer; | |
196 return false; | |
197 } | |
198 | |
199 // Gets a handler to the native video track, which owns the |writer|. | |
200 webrtc::MediaStreamInterface* native_stream = MediaStream::GetAdapter(stream); | |
201 DCHECK(native_stream); | |
202 VideoTrackVector video_tracks = native_stream->GetVideoTracks(); | |
203 // Currently one supports one video track per media stream. | |
204 DCHECK(video_tracks.size() == 1); | |
205 | |
206 *frame_writer = new PpFrameWriterProxy(video_tracks[0].get(), writer); | |
207 return true; | |
208 } | |
209 | |
210 } // namespace content | |
211 | |
OLD | NEW |