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

Side by Side Diff: media/cast/sender/external_video_encoder.cc

Issue 868803007: [Cast] Refactor ExternalVideoEncoder for cleaner/simpler encapsulation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: No need to have create_vea_cb_ member. Created 5 years, 10 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 "media/cast/sender/external_video_encoder.h" 5 #include "media/cast/sender/external_video_encoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_vector.h" 9 #include "base/memory/scoped_vector.h"
10 #include "base/memory/shared_memory.h" 10 #include "base/memory/shared_memory.h"
11 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "media/base/video_frame.h" 13 #include "media/base/video_frame.h"
14 #include "media/base/video_util.h" 14 #include "media/base/video_util.h"
15 #include "media/cast/cast_defines.h" 15 #include "media/cast/cast_defines.h"
16 #include "media/cast/logging/logging_defines.h" 16 #include "media/cast/logging/logging_defines.h"
17 #include "media/cast/net/cast_transport_config.h" 17 #include "media/cast/net/cast_transport_config.h"
18 #include "media/video/video_encode_accelerator.h" 18 #include "media/video/video_encode_accelerator.h"
19 19
20 namespace media { 20 namespace {
21 namespace cast {
22 class LocalVideoEncodeAcceleratorClient;
23 } // namespace cast
24 } // namespace media
25 21
26 namespace {
27 static const size_t kOutputBufferCount = 3; 22 static const size_t kOutputBufferCount = 3;
28 23
29 void LogFrameEncodedEvent( 24 void LogFrameEncodedEvent(
30 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, 25 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
31 base::TimeTicks event_time, 26 base::TimeTicks event_time,
32 media::cast::RtpTimestamp rtp_timestamp, 27 media::cast::RtpTimestamp rtp_timestamp,
33 uint32 frame_id) { 28 uint32 frame_id) {
34 cast_environment->Logging()->InsertFrameEvent( 29 cast_environment->Logging()->InsertFrameEvent(
35 event_time, media::cast::FRAME_ENCODED, media::cast::VIDEO_EVENT, 30 event_time, media::cast::FRAME_ENCODED, media::cast::VIDEO_EVENT,
36 rtp_timestamp, frame_id); 31 rtp_timestamp, frame_id);
37 } 32 }
33
38 } // namespace 34 } // namespace
39 35
40 namespace media { 36 namespace media {
41 namespace cast { 37 namespace cast {
42 38
43 // Container for the associated data of a video frame being processed. 39 // Container for the associated data of a video frame being processed.
44 struct InProgressFrameEncode { 40 struct InProgressFrameEncode {
45 const RtpTimestamp rtp_timestamp; 41 const RtpTimestamp rtp_timestamp;
46 const base::TimeTicks reference_time; 42 const base::TimeTicks reference_time;
47 const VideoEncoder::FrameEncodedCallback frame_encoded_callback; 43 const VideoEncoder::FrameEncodedCallback frame_encoded_callback;
48 44
49 InProgressFrameEncode(RtpTimestamp rtp, 45 InProgressFrameEncode(RtpTimestamp rtp,
50 base::TimeTicks r_time, 46 base::TimeTicks r_time,
51 VideoEncoder::FrameEncodedCallback callback) 47 VideoEncoder::FrameEncodedCallback callback)
52 : rtp_timestamp(rtp), 48 : rtp_timestamp(rtp),
53 reference_time(r_time), 49 reference_time(r_time),
54 frame_encoded_callback(callback) {} 50 frame_encoded_callback(callback) {}
55 }; 51 };
56 52
57 // The ExternalVideoEncoder class can be deleted directly by cast, while 53 // Owns a VideoEncoderAccelerator instance and provides the necessary adapters
58 // LocalVideoEncodeAcceleratorClient stays around long enough to properly shut 54 // to encode media::VideoFrames and emit media::cast::EncodedFrames. All
59 // down the VideoEncodeAccelerator. 55 // methods must be called on the thread associated with the given
60 class LocalVideoEncodeAcceleratorClient 56 // SingleThreadTaskRunner, except for the task_runner() accessor.
57 class ExternalVideoEncoder::VEAClientImpl
61 : public VideoEncodeAccelerator::Client, 58 : public VideoEncodeAccelerator::Client,
62 public base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient> { 59 public base::RefCountedThreadSafe<VEAClientImpl> {
63 public: 60 public:
64 // Create an instance of this class and post a task to create 61 VEAClientImpl(
65 // video_encode_accelerator_. A ref to |this| will be kept, awaiting reply 62 const scoped_refptr<CastEnvironment>& cast_environment,
66 // via ProxyCreateVideoEncodeAccelerator, which will provide us with the 63 const scoped_refptr<base::SingleThreadTaskRunner>& encoder_task_runner,
67 // encoder task runner and vea instance. We cannot be destroyed until we 64 scoped_ptr<media::VideoEncodeAccelerator> vea,
68 // receive the reply, otherwise the VEA object created may leak. 65 int max_frame_rate,
69 static scoped_refptr<LocalVideoEncodeAcceleratorClient> Create( 66 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb)
70 scoped_refptr<CastEnvironment> cast_environment, 67 : cast_environment_(cast_environment),
71 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, 68 task_runner_(encoder_task_runner),
72 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, 69 max_frame_rate_(max_frame_rate),
73 const base::WeakPtr<ExternalVideoEncoder>& weak_owner) { 70 create_video_encode_memory_cb_(create_video_encode_memory_cb),
74 scoped_refptr<LocalVideoEncodeAcceleratorClient> client( 71 video_encode_accelerator_(vea.Pass()),
75 new LocalVideoEncodeAcceleratorClient( 72 encoder_active_(false),
76 cast_environment, create_video_encode_mem_cb, weak_owner)); 73 last_encoded_frame_id_(kStartFrameId),
77 74 key_frame_encountered_(false) {
78 // This will keep a ref to |client|, if weak_owner is destroyed before
79 // ProxyCreateVideoEncodeAccelerator is called, we will stay alive until
80 // we can properly destroy the VEA.
81 create_vea_cb.Run(base::Bind(
82 &LocalVideoEncodeAcceleratorClient::OnCreateVideoEncodeAcceleratorProxy,
83 client));
84
85 return client;
86 } 75 }
87 76
88 // Initialize the real HW encoder. 77 base::SingleThreadTaskRunner* task_runner() const {
89 void Initialize(const VideoSenderConfig& video_config) { 78 return task_runner_.get();
90 DCHECK(encoder_task_runner_.get()); 79 }
91 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
92 80
93 VideoCodecProfile output_profile = media::VIDEO_CODEC_PROFILE_UNKNOWN; 81 void Initialize(const gfx::Size& frame_size,
94 switch (video_config.codec) { 82 VideoCodecProfile codec_profile,
95 case CODEC_VIDEO_VP8: 83 int start_bit_rate,
96 output_profile = media::VP8PROFILE_ANY; 84 const CastInitializationCallback& initialization_cb) {
97 break; 85 DCHECK(task_runner_->RunsTasksOnCurrentThread());
98 case CODEC_VIDEO_H264: 86 DCHECK(!frame_size.IsEmpty());
99 output_profile = media::H264PROFILE_MAIN;
100 break;
101 case CODEC_VIDEO_FAKE:
102 NOTREACHED() << "Fake software video encoder cannot be external";
103 break;
104 default:
105 NOTREACHED() << "Video codec not specified or not supported";
106 break;
107 }
108 max_frame_rate_ = video_config.max_frame_rate;
109 87
110 bool result = video_encode_accelerator_->Initialize( 88 encoder_active_ = video_encode_accelerator_->Initialize(
111 media::VideoFrame::I420, 89 media::VideoFrame::I420,
112 gfx::Size(video_config.width, video_config.height), 90 frame_size,
113 output_profile, 91 codec_profile,
114 video_config.start_bitrate, 92 start_bit_rate,
115 this); 93 this);
116 94
117 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess", 95 UMA_HISTOGRAM_BOOLEAN("Cast.Sender.VideoEncodeAcceleratorInitializeSuccess",
118 result); 96 encoder_active_);
119 if (!result) { 97
98 if (!initialization_cb.is_null()) {
120 cast_environment_->PostTask( 99 cast_environment_->PostTask(
121 CastEnvironment::MAIN, 100 CastEnvironment::MAIN,
122 FROM_HERE, 101 FROM_HERE,
123 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_, 102 base::Bind(initialization_cb,
hubbe 2015/01/29 23:29:15 Looks like there is a change in behavior when the
miu 2015/01/30 00:20:47 I looked at the code. It's safe, since the impl w
124 false)); 103 encoder_active_ ? STATUS_VIDEO_INITIALIZED :
125 return; 104 STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED));
126 }
127
128 // Wait until shared memory is allocated to indicate that encoder is
129 // initialized.
130 }
131
132 // Destroy the VEA on the correct thread.
133 void Destroy() {
134 DCHECK(encoder_task_runner_.get());
135 if (!video_encode_accelerator_)
136 return;
137
138 if (encoder_task_runner_->RunsTasksOnCurrentThread()) {
139 video_encode_accelerator_.reset();
140 } else {
141 // We do this instead of just reposting to encoder_task_runner_, because
142 // we are called from the destructor.
143 encoder_task_runner_->PostTask(
144 FROM_HERE,
145 base::Bind(&DestroyVideoEncodeAcceleratorOnEncoderThread,
146 base::Passed(&video_encode_accelerator_)));
147 } 105 }
148 } 106 }
149 107
150 void SetBitRate(uint32 bit_rate) { 108 void SetBitRate(int bit_rate) {
151 DCHECK(encoder_task_runner_.get()); 109 DCHECK(task_runner_->RunsTasksOnCurrentThread());
152 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
153 110
154 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate, 111 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate,
155 max_frame_rate_); 112 max_frame_rate_);
156 } 113 }
157 114
158 void EncodeVideoFrame( 115 void EncodeVideoFrame(
159 const scoped_refptr<media::VideoFrame>& video_frame, 116 const scoped_refptr<media::VideoFrame>& video_frame,
160 const base::TimeTicks& reference_time, 117 const base::TimeTicks& reference_time,
161 bool key_frame_requested, 118 bool key_frame_requested,
162 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) { 119 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
163 DCHECK(encoder_task_runner_.get()); 120 DCHECK(task_runner_->RunsTasksOnCurrentThread());
164 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread()); 121
122 if (!encoder_active_)
123 return;
165 124
166 in_progress_frame_encodes_.push_back(InProgressFrameEncode( 125 in_progress_frame_encodes_.push_back(InProgressFrameEncode(
167 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency), 126 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency),
168 reference_time, 127 reference_time,
169 frame_encoded_callback)); 128 frame_encoded_callback));
170 129
171 // BitstreamBufferReady will be called once the encoder is done. 130 // BitstreamBufferReady will be called once the encoder is done.
172 video_encode_accelerator_->Encode(video_frame, key_frame_requested); 131 video_encode_accelerator_->Encode(video_frame, key_frame_requested);
173 } 132 }
174 133
175 protected: 134 protected:
176 void NotifyError(VideoEncodeAccelerator::Error error) override { 135 void NotifyError(VideoEncodeAccelerator::Error error) override {
177 DCHECK(encoder_task_runner_.get()); 136 DCHECK(task_runner_->RunsTasksOnCurrentThread());
178 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
179 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error; 137 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error;
180 138
181 cast_environment_->PostTask( 139 encoder_active_ = false;
182 CastEnvironment::MAIN, 140 // TODO(miu): Plumbing is required to bubble this up to the CastSession and
183 FROM_HERE, 141 // beyond.
184 base::Bind(&ExternalVideoEncoder::EncoderError, weak_owner_));
185 } 142 }
186 143
187 // Called to allocate the input and output buffers. 144 // Called to allocate the input and output buffers.
188 void RequireBitstreamBuffers(unsigned int input_count, 145 void RequireBitstreamBuffers(unsigned int input_count,
189 const gfx::Size& input_coded_size, 146 const gfx::Size& input_coded_size,
190 size_t output_buffer_size) override { 147 size_t output_buffer_size) override {
191 DCHECK(encoder_task_runner_.get()); 148 DCHECK(task_runner_->RunsTasksOnCurrentThread());
192 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
193 DCHECK(video_encode_accelerator_);
194 149
195 for (size_t j = 0; j < kOutputBufferCount; ++j) { 150 for (size_t j = 0; j < kOutputBufferCount; ++j) {
196 create_video_encode_memory_cb_.Run( 151 create_video_encode_memory_cb_.Run(
197 output_buffer_size, 152 output_buffer_size,
198 base::Bind(&LocalVideoEncodeAcceleratorClient::OnCreateSharedMemory, 153 base::Bind(&VEAClientImpl::OnCreateSharedMemory, this));
199 this));
200 } 154 }
201 } 155 }
202 156
203 // Encoder has encoded a frame and it's available in one of out output 157 // Encoder has encoded a frame and it's available in one of the output
204 // buffers. 158 // buffers. Package the result in a media::cast::EncodedFrame and post it
159 // to the Cast MAIN thread via the supplied callback.
205 void BitstreamBufferReady(int32 bitstream_buffer_id, 160 void BitstreamBufferReady(int32 bitstream_buffer_id,
206 size_t payload_size, 161 size_t payload_size,
207 bool key_frame) override { 162 bool key_frame) override {
208 DCHECK(encoder_task_runner_.get()); 163 DCHECK(task_runner_->RunsTasksOnCurrentThread());
209 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
210 if (bitstream_buffer_id < 0 || 164 if (bitstream_buffer_id < 0 ||
211 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) { 165 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) {
212 NOTREACHED(); 166 NOTREACHED();
213 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id=" 167 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id="
214 << bitstream_buffer_id; 168 << bitstream_buffer_id;
215 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); 169 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
216 return; 170 return;
217 } 171 }
218 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; 172 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
219 if (payload_size > output_buffer->mapped_size()) { 173 if (payload_size > output_buffer->mapped_size()) {
220 NOTREACHED(); 174 NOTREACHED();
221 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = " 175 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = "
222 << payload_size; 176 << payload_size;
223 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); 177 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
224 return; 178 return;
225 } 179 }
226 if (key_frame) 180 if (key_frame)
227 key_frame_encountered_ = true; 181 key_frame_encountered_ = true;
228 if (!key_frame_encountered_) { 182 if (!key_frame_encountered_) {
229 // Do not send video until we have encountered the first key frame. 183 // Do not send video until we have encountered the first key frame.
230 // Save the bitstream buffer in |stream_header_| to be sent later along 184 // Save the bitstream buffer in |stream_header_| to be sent later along
231 // with the first key frame. 185 // with the first key frame.
186 //
187 // TODO(miu): Should |stream_header_| be an std::ostringstream for
188 // performance reasons?
232 stream_header_.append(static_cast<const char*>(output_buffer->memory()), 189 stream_header_.append(static_cast<const char*>(output_buffer->memory()),
233 payload_size); 190 payload_size);
234 } else if (!in_progress_frame_encodes_.empty()) { 191 } else if (!in_progress_frame_encodes_.empty()) {
235 const InProgressFrameEncode& request = in_progress_frame_encodes_.front(); 192 const InProgressFrameEncode& request = in_progress_frame_encodes_.front();
236 193
237 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); 194 scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame());
238 encoded_frame->dependency = key_frame ? EncodedFrame::KEY : 195 encoded_frame->dependency = key_frame ? EncodedFrame::KEY :
239 EncodedFrame::DEPENDENT; 196 EncodedFrame::DEPENDENT;
240 encoded_frame->frame_id = ++last_encoded_frame_id_; 197 encoded_frame->frame_id = ++last_encoded_frame_id_;
241 if (key_frame) 198 if (key_frame)
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 230
274 // We need to re-add the output buffer to the encoder after we are done 231 // We need to re-add the output buffer to the encoder after we are done
275 // with it. 232 // with it.
276 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( 233 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
277 bitstream_buffer_id, 234 bitstream_buffer_id,
278 output_buffers_[bitstream_buffer_id]->handle(), 235 output_buffers_[bitstream_buffer_id]->handle(),
279 output_buffers_[bitstream_buffer_id]->mapped_size())); 236 output_buffers_[bitstream_buffer_id]->mapped_size()));
280 } 237 }
281 238
282 private: 239 private:
283 LocalVideoEncodeAcceleratorClient( 240 friend class base::RefCountedThreadSafe<VEAClientImpl>;
284 scoped_refptr<CastEnvironment> cast_environment,
285 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
286 const base::WeakPtr<ExternalVideoEncoder>& weak_owner)
287 : cast_environment_(cast_environment),
288 create_video_encode_memory_cb_(create_video_encode_mem_cb),
289 weak_owner_(weak_owner),
290 last_encoded_frame_id_(kStartFrameId),
291 key_frame_encountered_(false) {}
292 241
293 // Trampoline VEA creation callback to OnCreateVideoEncodeAccelerator() 242 ~VEAClientImpl() override {
294 // on encoder_task_runner. Normally we would just repost the same method to 243 // According to the media::VideoEncodeAccelerator interface, Destroy()
295 // it, and would not need a separate proxy method, but we can't 244 // should be called instead of invoking its private destructor.
296 // ThreadTaskRunnerHandle::Get() in unittests just yet. 245 task_runner_->PostTask(
297 void OnCreateVideoEncodeAcceleratorProxy(
298 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
299 scoped_ptr<media::VideoEncodeAccelerator> vea) {
300 encoder_task_runner->PostTask(
301 FROM_HERE, 246 FROM_HERE,
302 base::Bind(&media::cast::LocalVideoEncodeAcceleratorClient:: 247 base::Bind(&media::VideoEncodeAccelerator::Destroy,
303 OnCreateVideoEncodeAccelerator, 248 base::Unretained(video_encode_accelerator_.release())));
304 this,
305 encoder_task_runner,
306 base::Passed(&vea)));
307 }
308
309 void OnCreateVideoEncodeAccelerator(
310 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
311 scoped_ptr<media::VideoEncodeAccelerator> vea) {
312 encoder_task_runner_ = encoder_task_runner;
313 video_encode_accelerator_.reset(vea.release());
314
315 cast_environment_->PostTask(
316 CastEnvironment::MAIN,
317 FROM_HERE,
318 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator,
319 weak_owner_,
320 encoder_task_runner_));
321 } 249 }
322 250
323 // Note: This method can be called on any thread. 251 // Note: This method can be called on any thread.
324 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) { 252 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) {
325 encoder_task_runner_->PostTask( 253 task_runner_->PostTask(FROM_HERE,
326 FROM_HERE, 254 base::Bind(&VEAClientImpl::OnReceivedSharedMemory,
327 base::Bind(&LocalVideoEncodeAcceleratorClient::ReceivedSharedMemory, 255 this,
328 this, 256 base::Passed(&memory)));
329 base::Passed(&memory)));
330 } 257 }
331 258
332 void ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) { 259 void OnReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) {
333 DCHECK(encoder_task_runner_.get()); 260 DCHECK(task_runner_->RunsTasksOnCurrentThread());
334 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
335 261
336 output_buffers_.push_back(memory.release()); 262 output_buffers_.push_back(memory.release());
337 263
338 // Wait until all requested buffers are received. 264 // Wait until all requested buffers are received.
339 if (output_buffers_.size() < kOutputBufferCount) 265 if (output_buffers_.size() < kOutputBufferCount)
340 return; 266 return;
341 267
342 // Immediately provide all output buffers to the VEA. 268 // Immediately provide all output buffers to the VEA.
343 for (size_t i = 0; i < output_buffers_.size(); ++i) { 269 for (size_t i = 0; i < output_buffers_.size(); ++i) {
344 video_encode_accelerator_->UseOutputBitstreamBuffer( 270 video_encode_accelerator_->UseOutputBitstreamBuffer(
345 media::BitstreamBuffer(static_cast<int32>(i), 271 media::BitstreamBuffer(static_cast<int32>(i),
346 output_buffers_[i]->handle(), 272 output_buffers_[i]->handle(),
347 output_buffers_[i]->mapped_size())); 273 output_buffers_[i]->mapped_size()));
348 } 274 }
349
350 cast_environment_->PostTask(
351 CastEnvironment::MAIN,
352 FROM_HERE,
353 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_,
354 true));
355 }
356
357 static void DestroyVideoEncodeAcceleratorOnEncoderThread(
358 scoped_ptr<media::VideoEncodeAccelerator> vea) {
359 // VEA::~VEA specialization takes care of calling Destroy() on the VEA impl.
360 }
361
362 friend class base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient>;
363
364 ~LocalVideoEncodeAcceleratorClient() override {
365 Destroy();
366 DCHECK(!video_encode_accelerator_);
367 } 275 }
368 276
369 const scoped_refptr<CastEnvironment> cast_environment_; 277 const scoped_refptr<CastEnvironment> cast_environment_;
370 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_; 278 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
279 const int max_frame_rate_;
280 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_;
371 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; 281 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
372 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; 282 bool encoder_active_;
373 const base::WeakPtr<ExternalVideoEncoder> weak_owner_;
374 int max_frame_rate_;
375 uint32 last_encoded_frame_id_; 283 uint32 last_encoded_frame_id_;
376 bool key_frame_encountered_; 284 bool key_frame_encountered_;
377 std::string stream_header_; 285 std::string stream_header_;
378 286
379 // Shared memory buffers for output with the VideoAccelerator. 287 // Shared memory buffers for output with the VideoAccelerator.
380 ScopedVector<base::SharedMemory> output_buffers_; 288 ScopedVector<base::SharedMemory> output_buffers_;
381 289
382 // FIFO list. 290 // FIFO list.
383 std::list<InProgressFrameEncode> in_progress_frame_encodes_; 291 std::list<InProgressFrameEncode> in_progress_frame_encodes_;
384 292
385 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient); 293 DISALLOW_COPY_AND_ASSIGN(VEAClientImpl);
386 }; 294 };
387 295
388 ExternalVideoEncoder::ExternalVideoEncoder( 296 ExternalVideoEncoder::ExternalVideoEncoder(
389 scoped_refptr<CastEnvironment> cast_environment, 297 const scoped_refptr<CastEnvironment>& cast_environment,
390 const VideoSenderConfig& video_config, 298 const VideoSenderConfig& video_config,
299 const gfx::Size& frame_size,
391 const CastInitializationCallback& initialization_cb, 300 const CastInitializationCallback& initialization_cb,
392 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, 301 const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
393 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) 302 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb)
394 : video_config_(video_config), 303 : cast_environment_(cast_environment),
395 cast_environment_(cast_environment), 304 create_video_encode_memory_cb_(create_video_encode_memory_cb),
396 encoder_active_(false), 305 bit_rate_(video_config.start_bitrate),
397 key_frame_requested_(false), 306 key_frame_requested_(false),
398 initialization_cb_(initialization_cb),
399 weak_factory_(this) { 307 weak_factory_(this) {
400 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 308 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
309 DCHECK_GT(video_config.max_frame_rate, 0);
310 DCHECK(!frame_size.IsEmpty());
311 DCHECK(!create_vea_cb.is_null());
312 DCHECK(!create_video_encode_memory_cb_.is_null());
313 DCHECK_GT(bit_rate_, 0);
401 314
402 video_accelerator_client_ = 315 VideoCodecProfile codec_profile;
403 LocalVideoEncodeAcceleratorClient::Create(cast_environment_, 316 switch (video_config.codec) {
404 create_vea_cb, 317 case CODEC_VIDEO_VP8:
405 create_video_encode_mem_cb, 318 codec_profile = media::VP8PROFILE_ANY;
406 weak_factory_.GetWeakPtr()); 319 break;
407 DCHECK(video_accelerator_client_.get()); 320 case CODEC_VIDEO_H264:
321 codec_profile = media::H264PROFILE_MAIN;
322 break;
323 case CODEC_VIDEO_FAKE:
324 NOTREACHED() << "Fake software video encoder cannot be external";
325 // ...flow through to next case...
326 default:
327 cast_environment_->PostTask(
328 CastEnvironment::MAIN,
329 FROM_HERE,
330 base::Bind(initialization_cb, STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED));
331 return;
332 }
333
334 create_vea_cb.Run(
335 base::Bind(&ExternalVideoEncoder::OnCreateVideoEncodeAccelerator,
336 weak_factory_.GetWeakPtr(),
337 frame_size,
338 codec_profile,
339 video_config.max_frame_rate,
340 initialization_cb));
408 } 341 }
409 342
410 ExternalVideoEncoder::~ExternalVideoEncoder() { 343 ExternalVideoEncoder::~ExternalVideoEncoder() {
411 } 344 }
412 345
413 void ExternalVideoEncoder::EncoderInitialized(bool success) {
414 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
415 encoder_active_ = success;
416 DCHECK(!initialization_cb_.is_null());
417 initialization_cb_.Run(
418 success ?
419 STATUS_VIDEO_INITIALIZED : STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED);
420 initialization_cb_.Reset();
421 }
422
423 void ExternalVideoEncoder::EncoderError() {
424 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
425 encoder_active_ = false;
426 }
427
428 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator(
429 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner) {
430 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
431 encoder_task_runner_ = encoder_task_runner;
432
433 encoder_task_runner_->PostTask(
434 FROM_HERE,
435 base::Bind(&LocalVideoEncodeAcceleratorClient::Initialize,
436 video_accelerator_client_,
437 video_config_));
438 }
439
440 bool ExternalVideoEncoder::EncodeVideoFrame( 346 bool ExternalVideoEncoder::EncodeVideoFrame(
441 const scoped_refptr<media::VideoFrame>& video_frame, 347 const scoped_refptr<media::VideoFrame>& video_frame,
442 const base::TimeTicks& reference_time, 348 const base::TimeTicks& reference_time,
443 const FrameEncodedCallback& frame_encoded_callback) { 349 const FrameEncodedCallback& frame_encoded_callback) {
444 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 350 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
351 DCHECK(!video_frame->visible_rect().IsEmpty());
352 DCHECK(!frame_encoded_callback.is_null());
445 353
446 if (!encoder_active_) 354 if (!client_)
447 return false; 355 return false; // Not ready.
448 356
449 encoder_task_runner_->PostTask( 357 client_->task_runner()->PostTask(FROM_HERE,
450 FROM_HERE, 358 base::Bind(&VEAClientImpl::EncodeVideoFrame,
451 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame, 359 client_,
452 video_accelerator_client_, 360 video_frame,
453 video_frame, 361 reference_time,
454 reference_time, 362 key_frame_requested_,
455 key_frame_requested_, 363 frame_encoded_callback));
456 frame_encoded_callback));
457
458 key_frame_requested_ = false; 364 key_frame_requested_ = false;
459 return true; 365 return true;
460 } 366 }
461 367
462 // Inform the encoder about the new target bit rate.
463 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) { 368 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) {
464 if (!encoder_active_) { 369 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
465 // If we receive SetBitRate() before VEA creation callback is invoked, 370 DCHECK_GT(new_bit_rate, 0);
466 // cache the new bit rate in the encoder config and use the new settings 371
467 // to initialize VEA. 372 bit_rate_ = new_bit_rate;
468 video_config_.start_bitrate = new_bit_rate; 373 if (!client_)
469 return; 374 return;
470 } 375 client_->task_runner()->PostTask(
471 376 FROM_HERE, base::Bind(&VEAClientImpl::SetBitRate, client_, bit_rate_));
472 encoder_task_runner_->PostTask(
473 FROM_HERE,
474 base::Bind(&LocalVideoEncodeAcceleratorClient::SetBitRate,
475 video_accelerator_client_,
476 new_bit_rate));
477 } 377 }
478 378
479 // Inform the encoder to encode the next frame as a key frame.
480 void ExternalVideoEncoder::GenerateKeyFrame() { 379 void ExternalVideoEncoder::GenerateKeyFrame() {
481 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 380 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
482 key_frame_requested_ = true; 381 key_frame_requested_ = true;
483 } 382 }
484 383
485 // Inform the encoder to only reference frames older or equal to frame_id;
486 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) { 384 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) {
487 // Do nothing not supported. 385 // Do nothing. Not supported.
488 } 386 }
387
388 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator(
389 const gfx::Size& frame_size,
390 VideoCodecProfile codec_profile,
391 int max_frame_rate,
392 const CastInitializationCallback& initialization_cb,
393 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
394 scoped_ptr<media::VideoEncodeAccelerator> vea) {
395 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
396
397 if (!encoder_task_runner || !vea) {
hubbe 2015/01/29 23:29:15 Seems like these should be CHECK/DCHECKs? (At leas
miu 2015/01/30 00:20:47 The implementation can return nulls when support i
398 if (!initialization_cb.is_null()) {
399 cast_environment_->PostTask(
400 CastEnvironment::MAIN,
401 FROM_HERE,
402 base::Bind(initialization_cb, STATUS_INVALID_VIDEO_CONFIGURATION));
403 }
404 return;
405 }
406
407 DCHECK(!client_);
408 client_ = new VEAClientImpl(cast_environment_,
409 encoder_task_runner,
410 vea.Pass(),
411 max_frame_rate,
412 create_video_encode_memory_cb_);
413 client_->task_runner()->PostTask(FROM_HERE,
414 base::Bind(&VEAClientImpl::Initialize,
415 client_,
416 frame_size,
417 codec_profile,
418 bit_rate_,
419 initialization_cb));
420 }
421
489 } // namespace cast 422 } // namespace cast
490 } // namespace media 423 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/external_video_encoder.h ('k') | media/cast/sender/external_video_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698