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

Side by Side Diff: chrome/gpu/gpu_arc_video_encode_accelerator.cc

Issue 2892863002: ArcBridge: Add VideoEncodeAccelerator implementation. (Closed)
Patch Set: Rebase Created 3 years, 6 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
(Empty)
1 // Copyright 2017 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 "chrome/gpu/gpu_arc_video_encode_accelerator.h"
6
7 #include <utility>
8
9 #include "base/logging.h"
10 #include "base/sys_info.h"
11 #include "media/base/video_types.h"
12 #include "media/gpu/gpu_video_encode_accelerator_factory.h"
13 #include "mojo/public/cpp/bindings/strong_binding.h"
14 #include "mojo/public/cpp/bindings/type_converter.h"
15 #include "mojo/public/cpp/system/platform_handle.h"
16
17 #define DVLOGF(x) DVLOG(x) << __func__ << "(): "
18
19 namespace chromeos {
20 namespace arc {
21
22 GpuArcVideoEncodeAccelerator::GpuArcVideoEncodeAccelerator(
23 const gpu::GpuPreferences& gpu_preferences)
24 : gpu_preferences_(gpu_preferences) {}
25
26 GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() = default;
27
28 // VideoEncodeAccelerator::Client implementation.
29 void GpuArcVideoEncodeAccelerator::RequireBitstreamBuffers(
30 unsigned int input_count,
31 const gfx::Size& coded_size,
32 size_t output_buffer_size) {
33 DVLOGF(2) << "input_count=" << input_count
34 << ", coded_size=" << coded_size.ToString()
35 << ", output_buffer_size=" << output_buffer_size;
36 DCHECK(client_);
37 coded_size_ = coded_size;
38 client_->RequireBitstreamBuffers(input_count, coded_size, output_buffer_size);
39 }
40
41 void GpuArcVideoEncodeAccelerator::BitstreamBufferReady(
42 int32_t bitstream_buffer_id,
43 size_t payload_size,
44 bool key_frame,
45 base::TimeDelta timestamp) {
46 DVLOGF(2) << "id=" << bitstream_buffer_id;
47 DCHECK(client_);
48 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame,
49 timestamp.InMicroseconds());
50 }
51
52 void GpuArcVideoEncodeAccelerator::NotifyError(Error error) {
53 DVLOGF(2) << "error=" << error;
54 DCHECK(client_);
55 client_->NotifyError(error);
56 }
57
58 // ::arc::mojom::VideoEncodeAccelerator implementation.
59 void GpuArcVideoEncodeAccelerator::GetSupportedProfiles(
60 const GetSupportedProfilesCallback& callback) {
61 callback.Run(media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles(
62 gpu_preferences_));
63 }
64
65 void GpuArcVideoEncodeAccelerator::Initialize(
66 VideoPixelFormat input_format,
67 const gfx::Size& visible_size,
68 VideoEncodeAccelerator::StorageType input_storage,
69 VideoCodecProfile output_profile,
70 uint32_t initial_bitrate,
71 VideoEncodeClientPtr client,
72 const InitializeCallback& callback) {
73 DVLOGF(2) << "visible_size=" << visible_size.ToString()
74 << ", profile=" << output_profile;
75 if (!client) {
dcheng 2017/06/21 09:42:29 Does Mojo actually allow a null interface pointer
Owen Lin 2017/06/22 07:43:14 You're right. I tested it, it failed in the IPC me
76 LOG(ERROR) << "Invalid client";
77 callback.Run(false);
78 return;
79 }
80
81 input_pixel_format_ = static_cast<media::VideoPixelFormat>(input_format);
dcheng 2017/06/21 09:42:28 Do we need these casts? Seems like they're the sam
Owen Lin 2017/06/22 07:43:14 Removed. It should be removed after we type mappin
82 visible_size_ = visible_size;
83 accelerator_ = media::GpuVideoEncodeAcceleratorFactory::CreateVEA(
84 input_pixel_format_, visible_size_,
85 static_cast<media::VideoCodecProfile>(output_profile), initial_bitrate,
dcheng 2017/06/21 09:42:29 Similarly, I'm not sure why this requires a cast.
Owen Lin 2017/06/22 07:43:14 Done.
86 this, gpu_preferences_);
87 if (accelerator_ == nullptr) {
88 LOG(ERROR) << "Failed to create a VideoEncodeAccelerator.";
dcheng 2017/06/21 09:42:29 Would personally suggest DLOG for everything that
Owen Lin 2017/06/22 07:43:14 Those messages should only be logged when errors h
dcheng 2017/06/22 20:05:13 Right, but is it useful to non-developers? Using L
Owen Lin 2017/06/23 01:37:54 OK. I got your point. We would like to use LOG sim
dcheng 2017/06/23 07:38:44 I don't think we should be bloating official build
89 callback.Run(false);
90 return;
91 }
92 client_ = std::move(client);
93 callback.Run(true);
94 }
95
96 static void DropSharedMemory(std::unique_ptr<base::SharedMemory> shm) {
97 // Just let |shm| fall out of scope.
98 }
99
100 void GpuArcVideoEncodeAccelerator::Encode(
101 mojo::ScopedHandle handle,
102 std::vector<::arc::VideoFramePlane> planes,
103 int64_t timestamp,
104 bool force_keyframe) {
105 DVLOGF(2) << "timestamp=" << timestamp;
106 if (!accelerator_) {
107 LOG(ERROR) << "Accelerator is not initialized.";
108 return;
109 }
110
111 if (planes.empty()) { // EOS
112 accelerator_->Encode(media::VideoFrame::CreateEOSFrame(), force_keyframe);
113 return;
114 }
115
116 base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(handle));
117 if (!fd.is_valid())
118 return;
119
120 size_t allocation_size =
121 media::VideoFrame::AllocationSize(input_pixel_format_, coded_size_);
122
123 // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
124 // TODO(rockot): This fd comes from a mojo::ScopedHandle in
125 // GpuArcVideoService::BindSharedMemory. That should be passed through,
126 // rather than pulling out the fd. https://crbug.com/713763.
127 // TODO(rockot): Pass through a real size rather than |0|.
128 base::UnguessableToken guid = base::UnguessableToken::Create();
129 base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true),
130 0u, guid);
131 auto shm = base::MakeUnique<base::SharedMemory>(shm_handle, true);
132
133 base::CheckedNumeric<off_t> map_offset = planes[0].offset;
134 base::CheckedNumeric<size_t> map_size = allocation_size;
135 const uint32_t aligned_offset =
136 planes[0].offset % base::SysInfo::VMAllocationGranularity();
137 map_offset -= aligned_offset;
138 map_size += aligned_offset;
139
140 if (!map_offset.IsValid() || !map_size.IsValid()) {
141 LOG(ERROR) << "Invalid map_offset or map_size";
142 client_->NotifyError(Error::kInvalidArgumentError);
143 return;
144 }
145 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
146 LOG(ERROR) << "Failed to map memory.";
147 client_->NotifyError(Error::kPlatformFailureError);
148 return;
149 }
150
151 uint8_t* shm_memory = reinterpret_cast<uint8_t*>(shm->memory());
152 auto frame = media::VideoFrame::WrapExternalSharedMemory(
153 input_pixel_format_, coded_size_, gfx::Rect(visible_size_), visible_size_,
154 shm_memory + aligned_offset, allocation_size, shm_handle,
155 planes[0].offset, base::TimeDelta::FromMicroseconds(timestamp));
156
157 // Wrap |shm| in a callback and add it as a destruction observer, so it
158 // stays alive and mapped until |frame| goes out of scope.
159 frame->AddDestructionObserver(
160 base::Bind(&DropSharedMemory, base::Passed(&shm)));
161 accelerator_->Encode(frame, force_keyframe);
162 }
163
164 void GpuArcVideoEncodeAccelerator::UseOutputBitstreamBuffer(
165 int32_t bitstream_buffer_id,
166 mojo::ScopedHandle shmem_fd,
167 uint32_t offset,
168 uint32_t size) {
169 DVLOGF(2) << "id=" << bitstream_buffer_id;
170 if (!accelerator_) {
171 LOG(ERROR) << "Accelerator is not initialized.";
172 return;
173 }
174
175 base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(shmem_fd));
176 if (!fd.is_valid())
177 return;
178
179 // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
180 // TODO(rockot): This fd comes from a mojo::ScopedHandle in
181 // GpuArcVideoService::BindSharedMemory. That should be passed through,
182 // rather than pulling out the fd. https://crbug.com/713763.
183 // TODO(rockot): Pass through a real size rather than |0|.
184 base::UnguessableToken guid = base::UnguessableToken::Create();
185 base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true),
186 0u, guid);
dcheng 2017/06/21 09:42:29 What is the behavior if we just pass 0 here? Does
Owen Lin 2017/06/22 07:43:14 AFAIK, this argument is not used yet. rockot@ shou
187 accelerator_->UseOutputBitstreamBuffer(
188 media::BitstreamBuffer(bitstream_buffer_id, shm_handle, size, offset));
189 }
190
191 void GpuArcVideoEncodeAccelerator::RequestEncodingParametersChange(
192 uint32_t bitrate,
193 uint32_t framerate) {
194 DVLOGF(2) << "bitrate=" << bitrate << ", framerate=" << framerate;
195 if (!accelerator_) {
196 LOG(ERROR) << "Accelerator is not initialized.";
197 return;
198 }
199 accelerator_->RequestEncodingParametersChange(bitrate, framerate);
200 }
201
202 base::ScopedFD GpuArcVideoEncodeAccelerator::UnwrapFdFromMojoHandle(
203 mojo::ScopedHandle handle) {
204 DCHECK(client_);
205 if (!handle.is_valid()) {
206 LOG(ERROR) << "handle is invalid.";
207 client_->NotifyError(Error::kInvalidArgumentError);
208 return base::ScopedFD();
209 }
210
211 base::PlatformFile platform_file;
212 MojoResult mojo_result =
213 mojo::UnwrapPlatformFile(std::move(handle), &platform_file);
214 if (mojo_result != MOJO_RESULT_OK) {
215 LOG(ERROR) << "UnwrapPlatformFile failed: " << mojo_result;
216 client_->NotifyError(Error::kPlatformFailureError);
217 return base::ScopedFD();
218 }
219
220 return base::ScopedFD(platform_file);
221 }
222
223 } // namespace arc
224 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698