OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "media/gpu/ipc/service/gpu_video_encode_accelerator.h" | 5 #include "media/gpu/ipc/service/gpu_video_encode_accelerator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 } | 52 } |
53 | 53 |
54 if (!stub->decoder()->MakeCurrent()) { | 54 if (!stub->decoder()->MakeCurrent()) { |
55 DLOG(ERROR) << "Failed to MakeCurrent()"; | 55 DLOG(ERROR) << "Failed to MakeCurrent()"; |
56 return false; | 56 return false; |
57 } | 57 } |
58 | 58 |
59 return true; | 59 return true; |
60 } | 60 } |
61 | 61 |
| 62 void DropSharedMemory(std::unique_ptr<base::SharedMemory> shm) { |
| 63 // Just let |shm| fall out of scope. |
| 64 } |
| 65 |
62 #if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) | 66 #if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) |
63 std::unique_ptr<VideoEncodeAccelerator> CreateV4L2VEA() { | 67 std::unique_ptr<VideoEncodeAccelerator> CreateV4L2VEA() { |
64 scoped_refptr<V4L2Device> device = V4L2Device::Create(); | 68 scoped_refptr<V4L2Device> device = V4L2Device::Create(); |
65 if (!device) | 69 if (!device) |
66 return nullptr; | 70 return nullptr; |
67 return base::WrapUnique<VideoEncodeAccelerator>( | 71 return base::WrapUnique<VideoEncodeAccelerator>( |
68 new V4L2VideoEncodeAccelerator(device)); | 72 new V4L2VideoEncodeAccelerator(device)); |
69 } | 73 } |
70 #endif | 74 #endif |
71 | 75 |
(...skipping 20 matching lines...) Expand all Loading... |
92 | 96 |
93 #if defined(OS_WIN) | 97 #if defined(OS_WIN) |
94 std::unique_ptr<VideoEncodeAccelerator> CreateMediaFoundationVEA() { | 98 std::unique_ptr<VideoEncodeAccelerator> CreateMediaFoundationVEA() { |
95 return base::WrapUnique<media::VideoEncodeAccelerator>( | 99 return base::WrapUnique<media::VideoEncodeAccelerator>( |
96 new MediaFoundationVideoEncodeAccelerator()); | 100 new MediaFoundationVideoEncodeAccelerator()); |
97 } | 101 } |
98 #endif | 102 #endif |
99 | 103 |
100 } // anonymous namespace | 104 } // anonymous namespace |
101 | 105 |
| 106 class GpuVideoEncodeAccelerator::MessageFilter : public IPC::MessageFilter { |
| 107 public: |
| 108 MessageFilter(GpuVideoEncodeAccelerator* owner, int32_t host_route_id) |
| 109 : owner_(owner), host_route_id_(host_route_id) {} |
| 110 |
| 111 void OnChannelError() override { sender_ = nullptr; } |
| 112 |
| 113 void OnChannelClosing() override { sender_ = nullptr; } |
| 114 |
| 115 void OnFilterAdded(IPC::Channel* channel) override { sender_ = channel; } |
| 116 |
| 117 void OnFilterRemoved() override { owner_->OnFilterRemoved(); } |
| 118 |
| 119 bool OnMessageReceived(const IPC::Message& msg) override { |
| 120 if (msg.routing_id() != host_route_id_) |
| 121 return false; |
| 122 |
| 123 IPC_BEGIN_MESSAGE_MAP(MessageFilter, msg) |
| 124 IPC_MESSAGE_FORWARD(AcceleratedVideoEncoderMsg_Encode, owner_, |
| 125 GpuVideoEncodeAccelerator::OnEncode) |
| 126 IPC_MESSAGE_FORWARD(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer, |
| 127 owner_, |
| 128 GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer) |
| 129 IPC_MESSAGE_FORWARD( |
| 130 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange, owner_, |
| 131 GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange) |
| 132 IPC_MESSAGE_UNHANDLED(return false) |
| 133 IPC_END_MESSAGE_MAP() |
| 134 return true; |
| 135 } |
| 136 |
| 137 bool SendOnIOThread(IPC::Message* message) { |
| 138 if (!sender_ || message->is_sync()) { |
| 139 DCHECK(!message->is_sync()); |
| 140 delete message; |
| 141 return false; |
| 142 } |
| 143 return sender_->Send(message); |
| 144 } |
| 145 |
| 146 protected: |
| 147 ~MessageFilter() override {} |
| 148 |
| 149 private: |
| 150 GpuVideoEncodeAccelerator* const owner_; |
| 151 const int32_t host_route_id_; |
| 152 // The sender to which this filter was added. |
| 153 IPC::Sender* sender_ = nullptr; |
| 154 |
| 155 DISALLOW_COPY_AND_ASSIGN(MessageFilter); |
| 156 }; |
| 157 |
102 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator( | 158 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator( |
103 int32_t host_route_id, | 159 int32_t host_route_id, |
104 gpu::GpuCommandBufferStub* stub) | 160 gpu::GpuCommandBufferStub* stub, |
| 161 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
105 : host_route_id_(host_route_id), | 162 : host_route_id_(host_route_id), |
106 stub_(stub), | 163 stub_(stub), |
107 input_format_(PIXEL_FORMAT_UNKNOWN), | 164 input_format_(PIXEL_FORMAT_UNKNOWN), |
108 output_buffer_size_(0), | 165 output_buffer_size_(0), |
| 166 filter_removed_(base::WaitableEvent::ResetPolicy::MANUAL, |
| 167 base::WaitableEvent::InitialState::NOT_SIGNALED), |
| 168 encoder_worker_thread_("EncoderWorkerThread"), |
| 169 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 170 io_task_runner_(io_task_runner), |
| 171 encode_task_runner_(main_task_runner_), |
| 172 weak_this_factory_for_encoder_worker_(this), |
109 weak_this_factory_(this) { | 173 weak_this_factory_(this) { |
110 stub_->AddDestructionObserver(this); | 174 stub_->AddDestructionObserver(this); |
111 make_context_current_ = | 175 make_context_current_ = |
112 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); | 176 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); |
113 } | 177 } |
114 | 178 |
115 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() { | 179 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() { |
116 // This class can only be self-deleted from OnWillDestroyStub(), which means | 180 // This class can only be self-deleted from OnWillDestroyStub(), which means |
117 // the VEA has already been destroyed in there. | 181 // the VEA has already been destroyed in there. |
118 DCHECK(!encoder_); | 182 DCHECK(!encoder_); |
| 183 if (encoder_worker_thread_.IsRunning()) { |
| 184 encoder_worker_task_runner_->PostTask( |
| 185 FROM_HERE, |
| 186 base::Bind(&GpuVideoEncodeAccelerator::DestroyOnEncoderWorker, |
| 187 weak_this_factory_for_encoder_worker_.GetWeakPtr())); |
| 188 encoder_worker_thread_.Stop(); |
| 189 } |
119 } | 190 } |
120 | 191 |
121 bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format, | 192 bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format, |
122 const gfx::Size& input_visible_size, | 193 const gfx::Size& input_visible_size, |
123 VideoCodecProfile output_profile, | 194 VideoCodecProfile output_profile, |
124 uint32_t initial_bitrate) { | 195 uint32_t initial_bitrate) { |
125 DVLOG(1) << __FUNCTION__ | 196 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 197 DVLOG(1) << __func__ |
126 << " input_format=" << VideoPixelFormatToString(input_format) | 198 << " input_format=" << VideoPixelFormatToString(input_format) |
127 << ", input_visible_size=" << input_visible_size.ToString() | 199 << ", input_visible_size=" << input_visible_size.ToString() |
128 << ", output_profile=" << GetProfileName(output_profile) | 200 << ", output_profile=" << GetProfileName(output_profile) |
129 << ", initial_bitrate=" << initial_bitrate; | 201 << ", initial_bitrate=" << initial_bitrate; |
130 DCHECK(!encoder_); | 202 DCHECK(!encoder_); |
131 | 203 |
132 if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { | 204 if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { |
133 DLOG(ERROR) << __FUNCTION__ << " failed to add route"; | 205 DLOG(ERROR) << __func__ << " failed to add route"; |
134 return false; | 206 return false; |
135 } | 207 } |
136 | 208 |
137 if (input_visible_size.width() > limits::kMaxDimension || | 209 if (input_visible_size.width() > limits::kMaxDimension || |
138 input_visible_size.height() > limits::kMaxDimension || | 210 input_visible_size.height() > limits::kMaxDimension || |
139 input_visible_size.GetArea() > limits::kMaxCanvas) { | 211 input_visible_size.GetArea() > limits::kMaxCanvas) { |
140 DLOG(ERROR) << __FUNCTION__ << "too large input_visible_size " | 212 DLOG(ERROR) << __func__ << "too large input_visible_size " |
141 << input_visible_size.ToString(); | 213 << input_visible_size.ToString(); |
142 return false; | 214 return false; |
143 } | 215 } |
144 | 216 |
145 const gpu::GpuPreferences& gpu_preferences = | 217 const gpu::GpuPreferences& gpu_preferences = |
146 stub_->channel()->gpu_channel_manager()->gpu_preferences(); | 218 stub_->channel()->gpu_channel_manager()->gpu_preferences(); |
147 | 219 |
148 // Try all possible encoders and use the first successful encoder. | 220 // Try all possible encoders and use the first successful encoder. |
149 for (const auto& factory_function : GetVEAFactoryFunctions(gpu_preferences)) { | 221 for (const auto& factory_function : GetVEAFactoryFunctions(gpu_preferences)) { |
150 encoder_ = factory_function.Run(); | 222 encoder_ = factory_function.Run(); |
151 if (encoder_ && | 223 if (encoder_ && |
152 encoder_->Initialize(input_format, input_visible_size, output_profile, | 224 encoder_->Initialize(input_format, input_visible_size, output_profile, |
153 initial_bitrate, this)) { | 225 initial_bitrate, this)) { |
154 input_format_ = input_format; | 226 input_format_ = input_format; |
155 input_visible_size_ = input_visible_size; | 227 input_visible_size_ = input_visible_size; |
| 228 // Attempt to set up performing encoding tasks on IO thread, if supported |
| 229 // by the VEA. |
| 230 if (encoder_->TryToSetupEncodeOnSeparateThread( |
| 231 weak_this_factory_.GetWeakPtr(), io_task_runner_)) { |
| 232 filter_ = new MessageFilter(this, host_route_id_); |
| 233 stub_->channel()->AddFilter(filter_.get()); |
| 234 encode_task_runner_ = io_task_runner_; |
| 235 } |
| 236 |
| 237 if (!encoder_worker_thread_.Start()) { |
| 238 DLOG(ERROR) << "Failed spawning encoder worker thread."; |
| 239 return false; |
| 240 } |
| 241 encoder_worker_task_runner_ = encoder_worker_thread_.task_runner(); |
| 242 |
156 return true; | 243 return true; |
157 } | 244 } |
158 } | 245 } |
159 encoder_.reset(); | 246 encoder_.reset(); |
160 DLOG(ERROR) << __FUNCTION__ << " VEA initialization failed"; | 247 DLOG(ERROR) << __func__ << " VEA initialization failed"; |
161 return false; | 248 return false; |
162 } | 249 } |
163 | 250 |
164 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) { | 251 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) { |
165 bool handled = true; | 252 bool handled = true; |
166 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message) | 253 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message) |
167 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode) | 254 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode) |
168 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer, | 255 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer, |
169 OnUseOutputBitstreamBuffer) | 256 OnUseOutputBitstreamBuffer) |
170 IPC_MESSAGE_HANDLER( | 257 IPC_MESSAGE_HANDLER( |
171 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange, | 258 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange, |
172 OnRequestEncodingParametersChange) | 259 OnRequestEncodingParametersChange) |
173 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy) | 260 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy) |
174 IPC_MESSAGE_UNHANDLED(handled = false) | 261 IPC_MESSAGE_UNHANDLED(handled = false) |
175 IPC_END_MESSAGE_MAP() | 262 IPC_END_MESSAGE_MAP() |
176 return handled; | 263 return handled; |
177 } | 264 } |
178 | 265 |
| 266 bool GpuVideoEncodeAccelerator::Send(IPC::Message* message) { |
| 267 if (filter_ && io_task_runner_->BelongsToCurrentThread()) { |
| 268 return filter_->SendOnIOThread(message); |
| 269 } |
| 270 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 271 return stub_->channel()->Send(message); |
| 272 } |
| 273 |
179 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers( | 274 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers( |
180 unsigned int input_count, | 275 unsigned int input_count, |
181 const gfx::Size& input_coded_size, | 276 const gfx::Size& input_coded_size, |
182 size_t output_buffer_size) { | 277 size_t output_buffer_size) { |
183 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers( | 278 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
184 host_route_id_, input_count, input_coded_size, output_buffer_size)); | 279 if (!Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers( |
| 280 host_route_id_, input_count, input_coded_size, output_buffer_size))) { |
| 281 DLOG(ERROR) << __func__ << " failed."; |
| 282 return; |
| 283 } |
185 input_coded_size_ = input_coded_size; | 284 input_coded_size_ = input_coded_size; |
186 output_buffer_size_ = output_buffer_size; | 285 output_buffer_size_ = output_buffer_size; |
187 } | 286 } |
188 | 287 |
189 void GpuVideoEncodeAccelerator::BitstreamBufferReady( | 288 void GpuVideoEncodeAccelerator::BitstreamBufferReady( |
190 int32_t bitstream_buffer_id, | 289 int32_t bitstream_buffer_id, |
191 size_t payload_size, | 290 size_t payload_size, |
192 bool key_frame, | 291 bool key_frame, |
193 base::TimeDelta timestamp) { | 292 base::TimeDelta timestamp) { |
194 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady( | 293 DCHECK(CheckIfCalledOnCorrectThread()); |
195 host_route_id_, bitstream_buffer_id, payload_size, key_frame, timestamp)); | 294 if (!Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady( |
| 295 host_route_id_, bitstream_buffer_id, payload_size, key_frame, |
| 296 timestamp))) { |
| 297 DLOG(ERROR) << __func__ << " failed."; |
| 298 } |
196 } | 299 } |
197 | 300 |
198 void GpuVideoEncodeAccelerator::NotifyError( | 301 void GpuVideoEncodeAccelerator::NotifyError( |
199 VideoEncodeAccelerator::Error error) { | 302 VideoEncodeAccelerator::Error error) { |
200 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error)); | 303 if (!Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, |
| 304 error))) { |
| 305 DLOG(ERROR) << __func__ << " failed."; |
| 306 } |
201 } | 307 } |
202 | 308 |
203 void GpuVideoEncodeAccelerator::OnWillDestroyStub() { | 309 void GpuVideoEncodeAccelerator::OnWillDestroyStub() { |
| 310 DVLOG(2) << __func__; |
| 311 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
204 DCHECK(stub_); | 312 DCHECK(stub_); |
| 313 |
| 314 // The stub is going away, so we have to stop and destroy VEA here before |
| 315 // returning. We cannot destroy the VEA before the IO thread message filter is |
| 316 // removed however, since we cannot service incoming messages with VEA gone. |
| 317 // We cannot simply check for existence of VEA on IO thread though, because |
| 318 // we don't want to synchronize the IO thread with the ChildThread. |
| 319 // So we have to wait for the RemoveFilter callback here instead and remove |
| 320 // the VEA after it arrives and before returning. |
| 321 if (filter_) { |
| 322 stub_->channel()->RemoveFilter(filter_.get()); |
| 323 filter_removed_.Wait(); |
| 324 } |
| 325 |
205 stub_->channel()->RemoveRoute(host_route_id_); | 326 stub_->channel()->RemoveRoute(host_route_id_); |
206 stub_->RemoveDestructionObserver(this); | 327 stub_->RemoveDestructionObserver(this); |
207 encoder_.reset(); | 328 encoder_.reset(); |
208 delete this; | 329 delete this; |
209 } | 330 } |
210 | 331 |
211 // static | 332 // static |
212 gpu::VideoEncodeAcceleratorSupportedProfiles | 333 gpu::VideoEncodeAcceleratorSupportedProfiles |
213 GpuVideoEncodeAccelerator::GetSupportedProfiles( | 334 GpuVideoEncodeAccelerator::GetSupportedProfiles( |
214 const gpu::GpuPreferences& gpu_preferences) { | 335 const gpu::GpuPreferences& gpu_preferences) { |
(...skipping 30 matching lines...) Expand all Loading... |
245 #if defined(OS_MACOSX) | 366 #if defined(OS_MACOSX) |
246 vea_factory_functions.push_back(base::Bind(&CreateVTVEA)); | 367 vea_factory_functions.push_back(base::Bind(&CreateVTVEA)); |
247 #endif | 368 #endif |
248 #if defined(OS_WIN) | 369 #if defined(OS_WIN) |
249 if (base::FeatureList::IsEnabled(kMediaFoundationH264Encoding)) | 370 if (base::FeatureList::IsEnabled(kMediaFoundationH264Encoding)) |
250 vea_factory_functions.push_back(base::Bind(&CreateMediaFoundationVEA)); | 371 vea_factory_functions.push_back(base::Bind(&CreateMediaFoundationVEA)); |
251 #endif | 372 #endif |
252 return vea_factory_functions; | 373 return vea_factory_functions; |
253 } | 374 } |
254 | 375 |
| 376 void GpuVideoEncodeAccelerator::OnFilterRemoved() { |
| 377 DVLOG(2) << __func__; |
| 378 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 379 |
| 380 // We're destroying; cancel all callbacks. |
| 381 weak_this_factory_.InvalidateWeakPtrs(); |
| 382 filter_removed_.Signal(); |
| 383 } |
| 384 |
255 void GpuVideoEncodeAccelerator::OnEncode( | 385 void GpuVideoEncodeAccelerator::OnEncode( |
256 const AcceleratedVideoEncoderMsg_Encode_Params& params) { | 386 const AcceleratedVideoEncoderMsg_Encode_Params& params) { |
257 DVLOG(3) << __FUNCTION__ << " frame_id = " << params.frame_id | 387 DVLOG(3) << __func__ << " frame_id = " << params.frame_id |
258 << ", buffer_size=" << params.buffer_size | 388 << ", buffer_size=" << params.buffer_size |
259 << ", force_keyframe=" << params.force_keyframe; | 389 << ", force_keyframe=" << params.force_keyframe; |
| 390 DCHECK(CheckIfCalledOnCorrectThread()); |
260 DCHECK_EQ(PIXEL_FORMAT_I420, input_format_); | 391 DCHECK_EQ(PIXEL_FORMAT_I420, input_format_); |
261 | 392 |
262 // Wrap into a SharedMemory in the beginning, so that |params.buffer_handle| | |
263 // is cleaned properly in case of an early return. | |
264 std::unique_ptr<base::SharedMemory> shm( | |
265 new base::SharedMemory(params.buffer_handle, true)); | |
266 | |
267 if (!encoder_) | 393 if (!encoder_) |
268 return; | 394 return; |
269 | 395 |
270 if (params.frame_id < 0) { | 396 if (params.frame_id < 0) { |
271 DLOG(ERROR) << __FUNCTION__ << " invalid frame_id=" << params.frame_id; | 397 DLOG(ERROR) << __func__ << " invalid frame_id=" << params.frame_id; |
272 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); | 398 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); |
273 return; | 399 return; |
274 } | 400 } |
275 | 401 |
276 const uint32_t aligned_offset = | 402 encoder_worker_task_runner_->PostTask( |
277 params.buffer_offset % base::SysInfo::VMAllocationGranularity(); | 403 FROM_HERE, |
278 base::CheckedNumeric<off_t> map_offset = params.buffer_offset; | 404 base::Bind(&GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker, |
279 map_offset -= aligned_offset; | 405 weak_this_factory_for_encoder_worker_.GetWeakPtr(), params)); |
280 base::CheckedNumeric<size_t> map_size = params.buffer_size; | |
281 map_size += aligned_offset; | |
282 | |
283 if (!map_offset.IsValid() || !map_size.IsValid()) { | |
284 DLOG(ERROR) << __FUNCTION__ << " invalid map_offset or map_size"; | |
285 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); | |
286 return; | |
287 } | |
288 | |
289 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) { | |
290 DLOG(ERROR) << __FUNCTION__ | |
291 << " could not map frame_id=" << params.frame_id; | |
292 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); | |
293 return; | |
294 } | |
295 | |
296 uint8_t* shm_memory = | |
297 reinterpret_cast<uint8_t*>(shm->memory()) + aligned_offset; | |
298 scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalSharedMemory( | |
299 input_format_, input_coded_size_, gfx::Rect(input_visible_size_), | |
300 input_visible_size_, shm_memory, params.buffer_size, params.buffer_handle, | |
301 params.buffer_offset, params.timestamp); | |
302 if (!frame) { | |
303 DLOG(ERROR) << __FUNCTION__ << " could not create a frame"; | |
304 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); | |
305 return; | |
306 } | |
307 frame->AddDestructionObserver(BindToCurrentLoop(base::Bind( | |
308 &GpuVideoEncodeAccelerator::EncodeFrameFinished, | |
309 weak_this_factory_.GetWeakPtr(), params.frame_id, base::Passed(&shm)))); | |
310 encoder_->Encode(frame, params.force_keyframe); | |
311 } | 406 } |
312 | 407 |
313 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( | 408 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( |
314 int32_t buffer_id, | 409 int32_t buffer_id, |
315 base::SharedMemoryHandle buffer_handle, | 410 base::SharedMemoryHandle buffer_handle, |
316 uint32_t buffer_size) { | 411 uint32_t buffer_size) { |
317 DVLOG(3) << __FUNCTION__ << " buffer_id=" << buffer_id | 412 DVLOG(3) << __func__ << " buffer_id=" << buffer_id |
318 << ", buffer_size=" << buffer_size; | 413 << ", buffer_size=" << buffer_size; |
| 414 DCHECK(CheckIfCalledOnCorrectThread()); |
319 if (!encoder_) | 415 if (!encoder_) |
320 return; | 416 return; |
321 if (buffer_id < 0) { | 417 if (buffer_id < 0) { |
322 DLOG(ERROR) << __FUNCTION__ << " invalid buffer_id=" << buffer_id; | 418 DLOG(ERROR) << __func__ << " invalid buffer_id=" << buffer_id; |
323 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); | 419 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); |
324 return; | 420 return; |
325 } | 421 } |
326 if (buffer_size < output_buffer_size_) { | 422 if (buffer_size < output_buffer_size_) { |
327 DLOG(ERROR) << __FUNCTION__ | 423 DLOG(ERROR) << __func__ << " buffer too small for buffer_id=" << buffer_id; |
328 << " buffer too small for buffer_id=" << buffer_id; | |
329 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); | 424 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); |
330 return; | 425 return; |
331 } | 426 } |
332 encoder_->UseOutputBitstreamBuffer( | 427 encoder_->UseOutputBitstreamBuffer( |
333 BitstreamBuffer(buffer_id, buffer_handle, buffer_size)); | 428 BitstreamBuffer(buffer_id, buffer_handle, buffer_size)); |
334 } | 429 } |
335 | 430 |
336 void GpuVideoEncodeAccelerator::OnDestroy() { | 431 void GpuVideoEncodeAccelerator::OnDestroy() { |
337 DVLOG(2) << __FUNCTION__; | 432 DVLOG(2) << __func__; |
| 433 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
338 OnWillDestroyStub(); | 434 OnWillDestroyStub(); |
339 } | 435 } |
340 | 436 |
341 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange( | 437 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange( |
342 uint32_t bitrate, | 438 uint32_t bitrate, |
343 uint32_t framerate) { | 439 uint32_t framerate) { |
344 DVLOG(2) << __FUNCTION__ << " bitrate=" << bitrate | 440 DVLOG(2) << __func__ << " bitrate=" << bitrate << ", framerate=" << framerate; |
345 << ", framerate=" << framerate; | 441 DCHECK(CheckIfCalledOnCorrectThread()); |
346 if (!encoder_) | 442 if (!encoder_) |
347 return; | 443 return; |
348 encoder_->RequestEncodingParametersChange(bitrate, framerate); | 444 encoder_->RequestEncodingParametersChange(bitrate, framerate); |
349 } | 445 } |
350 | 446 |
351 void GpuVideoEncodeAccelerator::EncodeFrameFinished( | 447 void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker( |
352 int32_t frame_id, | 448 const AcceleratedVideoEncoderMsg_Encode_Params& params) { |
353 std::unique_ptr<base::SharedMemory> shm) { | 449 DVLOG(3) << __func__; |
354 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_, | 450 DCHECK(encoder_worker_task_runner_->BelongsToCurrentThread()); |
355 frame_id)); | 451 |
356 // Just let |shm| fall out of scope. | 452 // Wrap into a SharedMemory in the beginning, so that |params.buffer_handle| |
| 453 // is cleaned properly in case of an early return. |
| 454 std::unique_ptr<base::SharedMemory> shm( |
| 455 new base::SharedMemory(params.buffer_handle, true)); |
| 456 const uint32_t aligned_offset = |
| 457 params.buffer_offset % base::SysInfo::VMAllocationGranularity(); |
| 458 base::CheckedNumeric<off_t> map_offset = params.buffer_offset; |
| 459 map_offset -= aligned_offset; |
| 460 base::CheckedNumeric<size_t> map_size = params.buffer_size; |
| 461 map_size += aligned_offset; |
| 462 |
| 463 if (!map_offset.IsValid() || !map_size.IsValid()) { |
| 464 DLOG(ERROR) << __func__ << " invalid map_offset or map_size"; |
| 465 encode_task_runner_->PostTask( |
| 466 FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError, |
| 467 weak_this_factory_.GetWeakPtr(), |
| 468 VideoEncodeAccelerator::kPlatformFailureError)); |
| 469 return; |
| 470 } |
| 471 |
| 472 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) { |
| 473 DLOG(ERROR) << __func__ << " could not map frame_id=" << params.frame_id; |
| 474 encode_task_runner_->PostTask( |
| 475 FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError, |
| 476 weak_this_factory_.GetWeakPtr(), |
| 477 VideoEncodeAccelerator::kPlatformFailureError)); |
| 478 return; |
| 479 } |
| 480 |
| 481 uint8_t* shm_memory = |
| 482 reinterpret_cast<uint8_t*>(shm->memory()) + aligned_offset; |
| 483 scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalSharedMemory( |
| 484 input_format_, input_coded_size_, gfx::Rect(input_visible_size_), |
| 485 input_visible_size_, shm_memory, params.buffer_size, params.buffer_handle, |
| 486 params.buffer_offset, params.timestamp); |
| 487 if (!frame) { |
| 488 DLOG(ERROR) << __func__ << " could not create a frame"; |
| 489 encode_task_runner_->PostTask( |
| 490 FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError, |
| 491 weak_this_factory_.GetWeakPtr(), |
| 492 VideoEncodeAccelerator::kPlatformFailureError)); |
| 493 return; |
| 494 } |
| 495 |
| 496 // We wrap |shm| in a callback and add it as a destruction observer, so it |
| 497 // stays alive and mapped until |frame| goes out of scope. |
| 498 frame->AddDestructionObserver( |
| 499 base::Bind(&DropSharedMemory, base::Passed(&shm))); |
| 500 encode_task_runner_->PostTask( |
| 501 FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::OnEncodeFrameCreated, |
| 502 weak_this_factory_.GetWeakPtr(), params.frame_id, |
| 503 params.force_keyframe, frame)); |
357 } | 504 } |
358 | 505 |
359 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) { | 506 void GpuVideoEncodeAccelerator::DestroyOnEncoderWorker() { |
360 stub_->channel()->Send(message); | 507 DCHECK(encoder_worker_task_runner_->BelongsToCurrentThread()); |
| 508 weak_this_factory_for_encoder_worker_.InvalidateWeakPtrs(); |
| 509 } |
| 510 |
| 511 void GpuVideoEncodeAccelerator::OnEncodeFrameCreated( |
| 512 int32_t frame_id, |
| 513 bool force_keyframe, |
| 514 const scoped_refptr<media::VideoFrame>& frame) { |
| 515 DVLOG(3) << __func__; |
| 516 DCHECK(CheckIfCalledOnCorrectThread()); |
| 517 |
| 518 if (!frame) { |
| 519 DLOG(ERROR) << __func__ << " could not create a frame"; |
| 520 NotifyError(VideoEncodeAccelerator::kPlatformFailureError); |
| 521 return; |
| 522 } |
| 523 |
| 524 frame->AddDestructionObserver(BindToCurrentLoop( |
| 525 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished, |
| 526 weak_this_factory_.GetWeakPtr(), frame_id))); |
| 527 encoder_->Encode(frame, force_keyframe); |
| 528 } |
| 529 |
| 530 void GpuVideoEncodeAccelerator::EncodeFrameFinished(int32_t frame_id) { |
| 531 DCHECK(CheckIfCalledOnCorrectThread()); |
| 532 if (!Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_, |
| 533 frame_id))) { |
| 534 DLOG(ERROR) << __func__ << " failed."; |
| 535 } |
| 536 } |
| 537 |
| 538 bool GpuVideoEncodeAccelerator::CheckIfCalledOnCorrectThread() { |
| 539 return (filter_ && io_task_runner_->BelongsToCurrentThread()) || |
| 540 (!filter_ && main_task_runner_->BelongsToCurrentThread()); |
361 } | 541 } |
362 | 542 |
363 } // namespace media | 543 } // namespace media |
OLD | NEW |