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

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 namespace mojo {
18
19 // Make sure arc::mojom::VideoEncodeAccelerator::Error and
20 // media::VideoEncodeAccelerator::Error match.
21 #define CHECK_ERROR_ENUM(value) \
22 static_assert( \
23 static_cast<int>(arc::mojom::VideoEncodeAccelerator::Error::value) == \
24 media::VideoEncodeAccelerator::Error::value, \
25 "enum ##value mismatch")
26
27 CHECK_ERROR_ENUM(kIllegalStateError);
28 CHECK_ERROR_ENUM(kInvalidArgumentError);
29 CHECK_ERROR_ENUM(kPlatformFailureError);
30 CHECK_ERROR_ENUM(kErrorMax);
31
32 #undef CHECK_ERROR_ENUM
33
34 // Make sure values in arc::mojom::VideoPixelFormat match to the values in
35 // media::VideoPixelFormat. The former is a subset of the later.
36 #define CHECK_PIXEL_FORMAT_ENUM(value) \
37 static_assert( \
38 static_cast<int>(arc::mojom::VideoPixelFormat::value) == media::value, \
39 "enum ##value mismatch")
40
41 CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_I420);
42
43 #undef CHECK_PXIEL_FORMAT_ENUM
44
45 // Make sure values in arc::mojom::VideoCodecProfile match to the values in
46 // media::VideoCodecProfile.
47 #define CHECK_PROFILE_ENUM(value) \
48 static_assert( \
49 static_cast<int>(arc::mojom::VideoCodecProfile::value) == media::value, \
50 "enum ##value mismatch")
51
52 CHECK_PROFILE_ENUM(H264PROFILE_BASELINE);
53 CHECK_PROFILE_ENUM(H264PROFILE_MAIN);
54 CHECK_PROFILE_ENUM(H264PROFILE_EXTENDED);
55 CHECK_PROFILE_ENUM(H264PROFILE_HIGH);
56 CHECK_PROFILE_ENUM(H264PROFILE_HIGH10PROFILE);
57 CHECK_PROFILE_ENUM(H264PROFILE_HIGH422PROFILE);
58 CHECK_PROFILE_ENUM(H264PROFILE_HIGH444PREDICTIVEPROFILE);
59 CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEBASELINE);
60 CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEHIGH);
61 CHECK_PROFILE_ENUM(H264PROFILE_STEREOHIGH);
62 CHECK_PROFILE_ENUM(H264PROFILE_MULTIVIEWHIGH);
63 CHECK_PROFILE_ENUM(VP8PROFILE_ANY);
64 CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE0);
65 CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE1);
66 CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE2);
67 CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE3);
68
69 #undef CHECK_PROFILE_ENUM
70
71 template <>
72 struct TypeConverter<arc::mojom::VideoEncodeProfilePtr,
73 media::VideoEncodeAccelerator::SupportedProfile> {
74 static arc::mojom::VideoEncodeProfilePtr Convert(
75 media::VideoEncodeAccelerator::SupportedProfile input) {
76 auto result = arc::mojom::VideoEncodeProfile::New();
77 result->profile = static_cast<arc::mojom::VideoCodecProfile>(input.profile);
78 result->max_resolution = input.max_resolution;
79 result->max_framerate_numerator = input.max_framerate_numerator;
80 result->max_framerate_denominator = input.max_framerate_denominator;
81 return result;
82 }
83 };
84
85 } // namespace mojo
86
87 namespace chromeos {
88 namespace arc {
89
90 GpuArcVideoEncodeAccelerator::GpuArcVideoEncodeAccelerator(
91 const gpu::GpuPreferences& gpu_preferences)
92 : gpu_preferences_(gpu_preferences) {}
93
94 GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() = default;
95
96 // VideoEncodeAccelerator::Client implementation.
97 void GpuArcVideoEncodeAccelerator::RequireBitstreamBuffers(
98 unsigned int input_count,
99 const gfx::Size& coded_size,
100 size_t output_buffer_size) {
101 DVLOG(2) << "RequireBitstreamBuffers(input_count=" << input_count
102 << ", coded_size=" << coded_size.ToString()
103 << ", output_buffer_size=" << output_buffer_size << ")";
104 DCHECK(client_);
105 coded_size_ = coded_size;
106 client_->RequireBitstreamBuffers(input_count, coded_size, output_buffer_size);
107 }
108
109 void GpuArcVideoEncodeAccelerator::BitstreamBufferReady(
110 int32_t bitstream_buffer_id,
111 size_t payload_size,
112 bool key_frame,
113 base::TimeDelta timestamp) {
114 DVLOG(2) << "BitstreamBufferReady(id=" << bitstream_buffer_id << ")";
115 DCHECK(client_);
116 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame,
117 timestamp.InMicroseconds());
118 }
119
120 void GpuArcVideoEncodeAccelerator::NotifyError(
121 media::VideoEncodeAccelerator::Error error) {
122 DVLOG(2) << "NotifyError(" << error << ")";
123 DCHECK(client_);
124 client_->NotifyError(static_cast<VideoEncodeAccelerator::Error>(error));
125 }
126
127 // ::arc::mojom::VideoEncodeAccelerator implementation.
128 void GpuArcVideoEncodeAccelerator::GetSupportedProfiles(
129 const GetSupportedProfilesCallback& callback) {
130 std::vector<::arc::mojom::VideoEncodeProfilePtr> profiles;
131 for (auto p : media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles(
132 gpu_preferences_))
133 profiles.push_back(::arc::mojom::VideoEncodeProfile::From(p));
134 callback.Run(std::move(profiles));
135 }
136
137 void GpuArcVideoEncodeAccelerator::Initialize(
138 VideoPixelFormat input_format,
139 const gfx::Size& visible_size,
140 VideoEncodeAccelerator::StorageType input_storage,
141 VideoCodecProfile output_profile,
142 uint32_t initial_bitrate,
143 VideoEncodeClientPtr client,
144 const InitializeCallback& callback) {
145 DVLOG(2) << "Initialize()";
146
147 if (!::arc::mojom::IsKnownEnumValue(input_format)) {
148 DLOG(ERROR) << "Invalid input_format: " << input_format;
149 callback.Run(false);
150 return;
151 }
152 if (!::arc::mojom::IsKnownEnumValue(output_profile)) {
153 DLOG(ERROR) << "Invalid codec profile: " << output_profile;
154 callback.Run(false);
155 return;
156 }
157 if (!client) {
158 DLOG(ERROR) << "Invalid client";
159 callback.Run(false);
160 return;
161 }
162
163 input_pixel_format_ = static_cast<media::VideoPixelFormat>(input_format);
164 visible_size_ = visible_size;
165 accelerator_ = media::GpuVideoEncodeAcceleratorFactory::CreateVEA(
166 input_pixel_format_, visible_size_,
167 static_cast<media::VideoCodecProfile>(output_profile), initial_bitrate,
168 this, gpu_preferences_);
169 if (accelerator_ == nullptr) {
170 DLOG(ERROR) << "failed to create vea.";
171 callback.Run(false);
172 return;
173 }
174 client_ = std::move(client);
175 callback.Run(true);
176 }
177
178 static void DropSharedMemory(std::unique_ptr<base::SharedMemory> shm) {
179 // Just let |shm| fall out of scope.
180 }
181
182 void GpuArcVideoEncodeAccelerator::Encode(
183 mojo::ScopedHandle handle,
184 std::vector<::arc::VideoFramePlane> planes,
185 int64_t timestamp,
186 bool force_keyframe) {
187 DVLOG(2) << "Encode(timestamp=" << timestamp << ")";
188 if (!accelerator_) {
189 DLOG(ERROR) << "Accelerator not initialized";
190 return;
191 }
192
193 scoped_refptr<media::VideoFrame> frame;
194 if (planes.empty()) { // EOS
195 frame = media::VideoFrame::CreateEOSFrame();
196 } else {
197 base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(handle));
198 if (!fd.is_valid())
199 return;
200
201 size_t allocation_size =
202 media::VideoFrame::AllocationSize(input_pixel_format_, coded_size_);
203
204 // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
205 // TODO(rockot): This fd comes from a mojo::ScopedHandle in
206 // GpuArcVideoService::BindSharedMemory. That should be passed through,
207 // rather than pulling out the fd. https://crbug.com/713763.
208 // TODO(rockot): Pass through a real size rather than |0|.
209 base::UnguessableToken guid = base::UnguessableToken::Create();
210 base::SharedMemoryHandle shm_handle(
211 base::FileDescriptor(fd.release(), true), 0u, guid);
212 auto shm = base::MakeUnique<base::SharedMemory>(shm_handle, true);
213
214 base::CheckedNumeric<off_t> map_offset = planes[0].offset;
215 base::CheckedNumeric<size_t> map_size = allocation_size;
216 const uint32_t aligned_offset =
217 planes[0].offset % base::SysInfo::VMAllocationGranularity();
218 map_offset -= aligned_offset;
219 map_size += aligned_offset;
220
221 if (!map_offset.IsValid() || !map_size.IsValid()) {
222 DLOG(ERROR) << "Invalid map_offset or map_size";
223 client_->NotifyError(Error::kInvalidArgumentError);
224 return;
225 }
226 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
227 DLOG(ERROR) << "Could not map memroy";
228 client_->NotifyError(Error::kPlatformFailureError);
229 return;
230 }
231
232 uint8_t* shm_memory = reinterpret_cast<uint8_t*>(shm->memory());
233 frame = media::VideoFrame::WrapExternalSharedMemory(
234 input_pixel_format_, coded_size_, gfx::Rect(visible_size_),
235 visible_size_, shm_memory + aligned_offset, allocation_size, shm_handle,
236 planes[0].offset, base::TimeDelta::FromMicroseconds(timestamp));
237
238 // Wrap |shm| in a callback and add it as a destruction observer, so it
239 // stays alive and mapped until |frame| goes out of scope.
240 frame->AddDestructionObserver(
241 base::Bind(&DropSharedMemory, base::Passed(&shm)));
242 }
243 accelerator_->Encode(frame, force_keyframe);
244 }
245
246 void GpuArcVideoEncodeAccelerator::UseOutputBitstreamBuffer(
247 int32_t bitstream_buffer_id,
248 mojo::ScopedHandle shmem_fd,
249 uint32_t offset,
250 uint32_t size) {
251 DVLOG(2) << "UseOutputBitstreamBuffer(id=" << bitstream_buffer_id << ")";
252 if (!accelerator_) {
253 DLOG(ERROR) << "Accelerator not initialized";
254 return;
255 }
256
257 base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(shmem_fd));
258 if (!fd.is_valid())
259 return;
260
261 // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
262 // TODO(rockot): This fd comes from a mojo::ScopedHandle in
263 // GpuArcVideoService::BindSharedMemory. That should be passed through,
264 // rather than pulling out the fd. https://crbug.com/713763.
265 // TODO(rockot): Pass through a real size rather than |0|.
266 base::UnguessableToken guid = base::UnguessableToken::Create();
267 base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true),
268 0u, guid);
269 accelerator_->UseOutputBitstreamBuffer(
270 media::BitstreamBuffer(bitstream_buffer_id, shm_handle, size, offset));
271 }
272
273 void GpuArcVideoEncodeAccelerator::RequestEncodingParametersChange(
274 uint32_t bitrate,
275 uint32_t framerate) {
276 DVLOG(2) << "RequestEncodingParametersChange(" << bitrate << ", " << framerate
277 << ")";
278 if (!accelerator_) {
279 DLOG(ERROR) << "Accelerator not initialized";
280 return;
281 }
282 accelerator_->RequestEncodingParametersChange(bitrate, framerate);
283 }
284
285 base::ScopedFD GpuArcVideoEncodeAccelerator::UnwrapFdFromMojoHandle(
286 mojo::ScopedHandle handle) {
287 DCHECK(client_);
288 if (!handle.is_valid()) {
289 DLOG(ERROR) << "handle is invalid";
290 client_->NotifyError(Error::kInvalidArgumentError);
291 return base::ScopedFD();
292 }
293
294 base::PlatformFile platform_file;
295 MojoResult mojo_result =
296 mojo::UnwrapPlatformFile(std::move(handle), &platform_file);
297 if (mojo_result != MOJO_RESULT_OK) {
298 DLOG(ERROR) << "UnwrapPlatformFile failed: " << mojo_result;
299 client_->NotifyError(Error::kPlatformFailureError);
300 return base::ScopedFD();
301 }
302
303 return base::ScopedFD(platform_file);
304 }
305
306 } // namespace arc
307 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698