| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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_jpeg_decode_accelerator.h" | 5 #include "media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/containers/hash_tables.h" | 13 #include "base/containers/hash_tables.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/ptr_util.h" |
| 15 #include "base/memory/shared_memory.h" | 16 #include "base/memory/shared_memory.h" |
| 16 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
| 17 #include "base/stl_util.h" | |
| 18 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
| 20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 21 #include "gpu/ipc/service/gpu_channel.h" | 21 #include "gpu/ipc/service/gpu_channel.h" |
| 22 #include "ipc/ipc_message_macros.h" | 22 #include "ipc/ipc_message_macros.h" |
| 23 #include "ipc/message_filter.h" | 23 #include "ipc/message_filter.h" |
| 24 #include "media/filters/jpeg_parser.h" | 24 #include "media/filters/jpeg_parser.h" |
| 25 #include "media/gpu/ipc/common/media_messages.h" | 25 #include "media/gpu/ipc/common/media_messages.h" |
| 26 #include "ui/gfx/geometry/size.h" | 26 #include "ui/gfx/geometry/size.h" |
| 27 | 27 |
| 28 #if defined(OS_CHROMEOS) | 28 #if defined(OS_CHROMEOS) |
| 29 #if defined(ARCH_CPU_X86_FAMILY) | 29 #if defined(ARCH_CPU_X86_FAMILY) |
| 30 #include "media/gpu/vaapi_jpeg_decode_accelerator.h" | 30 #include "media/gpu/vaapi_jpeg_decode_accelerator.h" |
| 31 #endif | 31 #endif |
| 32 #if defined(USE_V4L2_CODEC) | 32 #if defined(USE_V4L2_CODEC) |
| 33 #include "media/gpu/v4l2_device.h" | 33 #include "media/gpu/v4l2_device.h" |
| 34 #include "media/gpu/v4l2_jpeg_decode_accelerator.h" | 34 #include "media/gpu/v4l2_jpeg_decode_accelerator.h" |
| 35 #endif | 35 #endif |
| 36 #endif | 36 #endif |
| 37 | 37 |
| 38 namespace { | 38 namespace { |
| 39 | 39 |
| 40 void DecodeFinished(std::unique_ptr<base::SharedMemory> shm) { | 40 void DecodeFinished(std::unique_ptr<base::SharedMemory> shm) { |
| 41 // Do nothing. Because VideoFrame is backed by |shm|, the purpose of this | 41 // Do nothing. Because VideoFrame is backed by |shm|, the purpose of this |
| 42 // function is to just keep reference of |shm| to make sure it lives util | 42 // function is to just keep reference of |shm| to make sure it lives until |
| 43 // decode finishes. | 43 // decode finishes. |
| 44 } | 44 } |
| 45 | 45 |
| 46 bool VerifyDecodeParams(const AcceleratedJpegDecoderMsg_Decode_Params& params) { | 46 bool VerifyDecodeParams(const AcceleratedJpegDecoderMsg_Decode_Params& params) { |
| 47 const int kJpegMaxDimension = UINT16_MAX; | 47 const int kJpegMaxDimension = UINT16_MAX; |
| 48 if (params.coded_size.IsEmpty() || | 48 if (params.coded_size.IsEmpty() || |
| 49 params.coded_size.width() > kJpegMaxDimension || | 49 params.coded_size.width() > kJpegMaxDimension || |
| 50 params.coded_size.height() > kJpegMaxDimension) { | 50 params.coded_size.height() > kJpegMaxDimension) { |
| 51 LOG(ERROR) << "invalid coded_size " << params.coded_size.ToString(); | 51 LOG(ERROR) << "invalid coded_size " << params.coded_size.ToString(); |
| 52 return false; | 52 return false; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 } | 151 } |
| 152 return sender_->Send(message); | 152 return sender_->Send(message); |
| 153 } | 153 } |
| 154 | 154 |
| 155 void AddClientOnIOThread(int32_t route_id, | 155 void AddClientOnIOThread(int32_t route_id, |
| 156 Client* client, | 156 Client* client, |
| 157 base::Callback<void(bool)> response) { | 157 base::Callback<void(bool)> response) { |
| 158 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 158 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 159 DCHECK(client_map_.count(route_id) == 0); | 159 DCHECK(client_map_.count(route_id) == 0); |
| 160 | 160 |
| 161 client_map_[route_id] = client; | 161 // See the comment on GpuJpegDecodeAccelerator::AddClient. |
| 162 client_map_[route_id] = base::WrapUnique(client); |
| 162 response.Run(true); | 163 response.Run(true); |
| 163 } | 164 } |
| 164 | 165 |
| 165 void OnDestroyOnIOThread(const int32_t* route_id) { | 166 void OnDestroyOnIOThread(const int32_t* route_id) { |
| 166 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 167 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 167 const auto& it = client_map_.find(*route_id); | 168 const auto& it = client_map_.find(*route_id); |
| 168 DCHECK(it != client_map_.end()); | 169 DCHECK(it != client_map_.end()); |
| 169 Client* client = it->second; | 170 std::unique_ptr<Client> client = std::move(it->second); |
| 170 DCHECK(client); | 171 DCHECK(client); |
| 171 client_map_.erase(it); | 172 client_map_.erase(it); |
| 172 | 173 |
| 173 child_task_runner_->PostTask( | 174 child_task_runner_->PostTask( |
| 174 FROM_HERE, base::Bind(&MessageFilter::DestroyClient, this, client)); | 175 FROM_HERE, |
| 176 base::Bind(&MessageFilter::DestroyClient, this, base::Passed(&client))); |
| 175 } | 177 } |
| 176 | 178 |
| 177 void DestroyClient(Client* client) { | 179 void DestroyClient(std::unique_ptr<Client> client) { |
| 178 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 180 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 179 delete client; | |
| 180 if (owner_) | 181 if (owner_) |
| 181 owner_->ClientRemoved(); | 182 owner_->ClientRemoved(); |
| 183 // |client| is destroyed when the scope of this function is left. |
| 182 } | 184 } |
| 183 | 185 |
| 184 void NotifyDecodeStatusOnIOThread(int32_t route_id, | 186 void NotifyDecodeStatusOnIOThread(int32_t route_id, |
| 185 int32_t buffer_id, | 187 int32_t buffer_id, |
| 186 JpegDecodeAccelerator::Error error) { | 188 JpegDecodeAccelerator::Error error) { |
| 187 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 189 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 188 SendOnIOThread(new AcceleratedJpegDecoderHostMsg_DecodeAck( | 190 SendOnIOThread(new AcceleratedJpegDecoderHostMsg_DecodeAck( |
| 189 route_id, buffer_id, error)); | 191 route_id, buffer_id, error)); |
| 190 } | 192 } |
| 191 | 193 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 << params.input_buffer.id(); | 236 << params.input_buffer.id(); |
| 235 NotifyDecodeStatusOnIOThread(*route_id, params.input_buffer.id(), | 237 NotifyDecodeStatusOnIOThread(*route_id, params.input_buffer.id(), |
| 236 JpegDecodeAccelerator::PLATFORM_FAILURE); | 238 JpegDecodeAccelerator::PLATFORM_FAILURE); |
| 237 base::SharedMemory::CloseHandle(params.input_buffer.handle()); | 239 base::SharedMemory::CloseHandle(params.input_buffer.handle()); |
| 238 return; | 240 return; |
| 239 } | 241 } |
| 240 frame->AddDestructionObserver( | 242 frame->AddDestructionObserver( |
| 241 base::Bind(DecodeFinished, base::Passed(&output_shm))); | 243 base::Bind(DecodeFinished, base::Passed(&output_shm))); |
| 242 | 244 |
| 243 DCHECK_GT(client_map_.count(*route_id), 0u); | 245 DCHECK_GT(client_map_.count(*route_id), 0u); |
| 244 Client* client = client_map_[*route_id]; | 246 Client* client = client_map_[*route_id].get(); |
| 245 client->Decode(params.input_buffer, frame); | 247 client->Decode(params.input_buffer, frame); |
| 246 } | 248 } |
| 247 | 249 |
| 248 protected: | 250 protected: |
| 249 ~MessageFilter() override { | 251 ~MessageFilter() override { |
| 250 if (client_map_.empty()) | 252 if (client_map_.empty()) |
| 251 return; | 253 return; |
| 252 | 254 |
| 253 if (child_task_runner_->BelongsToCurrentThread()) { | 255 if (child_task_runner_->BelongsToCurrentThread()) { |
| 254 base::STLDeleteValues(&client_map_); | 256 client_map_.clear(); |
| 255 } else { | 257 } else { |
| 256 // Make sure |Client| are deleted on child thread. | 258 // Make sure |Client| are deleted on child thread. |
| 257 std::unique_ptr<ClientMap> client_map(new ClientMap); | 259 std::unique_ptr<ClientMap> client_map(new ClientMap); |
| 258 client_map->swap(client_map_); | 260 client_map->swap(client_map_); |
| 259 | 261 |
| 260 child_task_runner_->PostTask( | 262 child_task_runner_->PostTask( |
| 261 FROM_HERE, | 263 FROM_HERE, |
| 262 base::Bind(&DeleteClientMapOnChildThread, base::Passed(&client_map))); | 264 base::Bind(&DeleteClientMapOnChildThread, base::Passed(&client_map))); |
| 263 } | 265 } |
| 264 } | 266 } |
| 265 | 267 |
| 266 private: | 268 private: |
| 267 using ClientMap = base::hash_map<int32_t, Client*>; | 269 using ClientMap = base::hash_map<int32_t, std::unique_ptr<Client>>; |
| 268 | 270 |
| 269 // Must be static because this method runs after destructor. | 271 // Must be static because this method runs after destructor. |
| 270 static void DeleteClientMapOnChildThread( | 272 static void DeleteClientMapOnChildThread( |
| 271 std::unique_ptr<ClientMap> client_map) { | 273 std::unique_ptr<ClientMap> client_map) { |
| 272 base::STLDeleteValues(client_map.get()); | 274 // |client_map| is cleared when the scope of this function is left. |
| 273 } | 275 } |
| 274 | 276 |
| 275 base::WeakPtr<GpuJpegDecodeAccelerator> owner_; | 277 base::WeakPtr<GpuJpegDecodeAccelerator> owner_; |
| 276 | 278 |
| 277 // GPU child task runner. | 279 // GPU child task runner. |
| 278 scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_; | 280 scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_; |
| 279 | 281 |
| 280 // GPU IO task runner. | 282 // GPU IO task runner. |
| 281 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 283 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
| 282 | 284 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 // This should be before AddClientOnIOThread. | 343 // This should be before AddClientOnIOThread. |
| 342 channel_->AddFilter(filter_.get()); | 344 channel_->AddFilter(filter_.get()); |
| 343 } | 345 } |
| 344 client_number_++; | 346 client_number_++; |
| 345 | 347 |
| 346 // In this PostTask, |client| may leak if |io_task_runner_| is destroyed | 348 // In this PostTask, |client| may leak if |io_task_runner_| is destroyed |
| 347 // before |client| reached AddClientOnIOThread. However we cannot use scoper | 349 // before |client| reached AddClientOnIOThread. However we cannot use scoper |
| 348 // to protect it because |client| can only be deleted on child thread. The IO | 350 // to protect it because |client| can only be deleted on child thread. The IO |
| 349 // thread is destroyed at termination, at which point it's ok to leak since | 351 // thread is destroyed at termination, at which point it's ok to leak since |
| 350 // we're going to tear down the process anyway. So we just crossed fingers | 352 // we're going to tear down the process anyway. So we just crossed fingers |
| 351 // here instead of making the code unnecessary complicated. | 353 // here instead of making the code unnecessarily complicated. |
| 352 io_task_runner_->PostTask( | 354 io_task_runner_->PostTask( |
| 353 FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_, | 355 FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_, |
| 354 route_id, client.release(), response)); | 356 route_id, client.release(), response)); |
| 355 } | 357 } |
| 356 | 358 |
| 357 void GpuJpegDecodeAccelerator::NotifyDecodeStatus( | 359 void GpuJpegDecodeAccelerator::NotifyDecodeStatus( |
| 358 int32_t route_id, | 360 int32_t route_id, |
| 359 int32_t buffer_id, | 361 int32_t buffer_id, |
| 360 JpegDecodeAccelerator::Error error) { | 362 JpegDecodeAccelerator::Error error) { |
| 361 DCHECK(CalledOnValidThread()); | 363 DCHECK(CalledOnValidThread()); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 for (const auto& create_jda_function : create_jda_fps) { | 411 for (const auto& create_jda_function : create_jda_fps) { |
| 410 std::unique_ptr<JpegDecodeAccelerator> accelerator = | 412 std::unique_ptr<JpegDecodeAccelerator> accelerator = |
| 411 (*create_jda_function)(base::ThreadTaskRunnerHandle::Get()); | 413 (*create_jda_function)(base::ThreadTaskRunnerHandle::Get()); |
| 412 if (accelerator && accelerator->IsSupported()) | 414 if (accelerator && accelerator->IsSupported()) |
| 413 return true; | 415 return true; |
| 414 } | 416 } |
| 415 return false; | 417 return false; |
| 416 } | 418 } |
| 417 | 419 |
| 418 } // namespace media | 420 } // namespace media |
| OLD | NEW |