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

Side by Side Diff: content/renderer/media_recorder/vea_encoder.cc

Issue 2793303003: Refactor VideoTrackRecorder into smaller classes (Closed)
Patch Set: Rebase Created 3 years, 8 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 "content/renderer/media_recorder/vea_encoder.h"
6
7 #include <string>
8
9 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
10 #include "content/renderer/render_thread_impl.h"
11 #include "media/base/bind_to_current_loop.h"
12 #include "media/base/video_frame.h"
13 #include "third_party/libyuv/include/libyuv.h"
14 #include "ui/gfx/geometry/size.h"
15
16 using media::VideoFrame;
17 using video_track_recorder::kVEAEncoderMinResolutionWidth;
18 using video_track_recorder::kVEAEncoderMinResolutionHeight;
19
20 namespace content {
21
22 namespace {
23
24 // HW encoders expect a nonzero bitrate, so |kVEADefaultBitratePerPixel| is used
25 // to estimate bits per second for ~30 fps with ~1/16 compression rate.
26 const int kVEADefaultBitratePerPixel = 2;
27 // Number of output buffers used to copy the encoded data coming from HW
28 // encoders.
29 const int kVEAEncoderOutputBufferCount = 4;
30
31 } // anonymous namespace
32
33 VEAEncoder::VEAEncoder(
34 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
35 const VideoTrackRecorder::OnErrorCB& on_error_callback,
36 int32_t bits_per_second,
37 media::VideoCodecProfile codec,
38 const gfx::Size& size)
39 : Encoder(on_encoded_video_callback,
40 bits_per_second > 0 ? bits_per_second
41 : size.GetArea() * kVEADefaultBitratePerPixel,
42 RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()),
43 gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()),
44 codec_(codec),
45 error_notified_(false),
46 on_error_callback_(on_error_callback) {
47 DCHECK(gpu_factories_);
48 DCHECK_GE(size.width(), kVEAEncoderMinResolutionWidth);
49 DCHECK_GE(size.height(), kVEAEncoderMinResolutionHeight);
50
51 encoding_task_runner_->PostTask(
52 FROM_HERE, base::Bind(&VEAEncoder::ConfigureEncoderOnEncodingTaskRunner,
53 this, size));
54 }
55
56 VEAEncoder::~VEAEncoder() {
57 base::WaitableEvent release_waiter(
58 base::WaitableEvent::ResetPolicy::MANUAL,
59 base::WaitableEvent::InitialState::NOT_SIGNALED);
60 // base::Unretained is safe because the class will be alive until
61 // |release_waiter| is signaled.
62 // TODO(emircan): Consider refactoring media::VideoEncodeAccelerator to avoid
63 // using naked pointers and using DeleteSoon() here, see
64 // http://crbug.com/701627.
65 // It is currently unsafe because |video_encoder_| might be in use on another
66 // function on |encoding_task_runner_|, see http://crbug.com/701030.
67 encoding_task_runner_->PostTask(
68 FROM_HERE, base::Bind(&VEAEncoder::DestroyOnEncodingTaskRunner,
69 base::Unretained(this), &release_waiter));
70 release_waiter.Wait();
71 }
72
73 void VEAEncoder::RequireBitstreamBuffers(unsigned int /*input_count*/,
74 const gfx::Size& input_coded_size,
75 size_t output_buffer_size) {
76 DVLOG(3) << __func__;
77 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
78
79 vea_requested_input_coded_size_ = input_coded_size;
80 output_buffers_.clear();
81 std::queue<std::unique_ptr<base::SharedMemory>>().swap(input_buffers_);
82
83 for (int i = 0; i < kVEAEncoderOutputBufferCount; ++i) {
84 std::unique_ptr<base::SharedMemory> shm =
85 gpu_factories_->CreateSharedMemory(output_buffer_size);
86 if (shm)
87 output_buffers_.push_back(base::WrapUnique(shm.release()));
88 }
89
90 for (size_t i = 0; i < output_buffers_.size(); ++i)
91 UseOutputBitstreamBufferId(i);
92 }
93
94 void VEAEncoder::BitstreamBufferReady(int32_t bitstream_buffer_id,
95 size_t payload_size,
96 bool keyframe,
97 base::TimeDelta timestamp) {
98 DVLOG(3) << __func__;
99 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
100
101 base::SharedMemory* output_buffer =
102 output_buffers_[bitstream_buffer_id].get();
103
104 std::unique_ptr<std::string> data(new std::string);
105 data->append(reinterpret_cast<char*>(output_buffer->memory()), payload_size);
106
107 const auto front_frame = frames_in_encode_.front();
108 frames_in_encode_.pop();
109 origin_task_runner_->PostTask(
110 FROM_HERE, base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_,
111 front_frame.first, base::Passed(&data), nullptr,
112 front_frame.second, keyframe));
113 UseOutputBitstreamBufferId(bitstream_buffer_id);
114 }
115
116 void VEAEncoder::NotifyError(media::VideoEncodeAccelerator::Error error) {
117 DVLOG(3) << __func__;
118 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
119 on_error_callback_.Run();
120 error_notified_ = true;
121 }
122
123 void VEAEncoder::UseOutputBitstreamBufferId(int32_t bitstream_buffer_id) {
124 DVLOG(3) << __func__;
125 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
126
127 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
128 bitstream_buffer_id, output_buffers_[bitstream_buffer_id]->handle(),
129 output_buffers_[bitstream_buffer_id]->mapped_size()));
130 }
131
132 void VEAEncoder::FrameFinished(std::unique_ptr<base::SharedMemory> shm) {
133 DVLOG(3) << __func__;
134 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
135 input_buffers_.push(std::move(shm));
136 }
137
138 void VEAEncoder::EncodeOnEncodingTaskRunner(scoped_refptr<VideoFrame> frame,
139 base::TimeTicks capture_timestamp) {
140 DVLOG(3) << __func__;
141 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
142
143 if (input_visible_size_ != frame->visible_rect().size() && video_encoder_)
144 video_encoder_.reset();
145
146 if (!video_encoder_)
147 ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size());
148
149 if (error_notified_) {
150 DVLOG(3) << "An error occurred in VEA encoder";
151 return;
152 }
153
154 // Drop frames if there is no output buffers available.
155 if (output_buffers_.empty()) {
156 // TODO(emircan): Investigate if resetting encoder would help.
157 DVLOG(3) << "Might drop frame.";
158 last_frame_.reset(new std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>(
159 frame, capture_timestamp));
160 return;
161 }
162
163 // If first frame hasn't been encoded, do it first.
164 if (last_frame_) {
165 std::unique_ptr<VideoFrameAndTimestamp> last_frame(last_frame_.release());
166 EncodeOnEncodingTaskRunner(last_frame->first, last_frame->second);
167 }
168
169 // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac.
170 // In that case, the encoder expects more frames before returning result.
171 // Therefore, a copy is necessary to release the current frame.
172 // Only STORAGE_SHMEM backed frames can be shared with GPU process, therefore
173 // a copy is required for other storage types.
174 scoped_refptr<media::VideoFrame> video_frame = frame;
175 if (video_frame->storage_type() != VideoFrame::STORAGE_SHMEM ||
176 vea_requested_input_coded_size_ != frame->coded_size() ||
177 input_visible_size_.width() < kVEAEncoderMinResolutionWidth ||
178 input_visible_size_.height() < kVEAEncoderMinResolutionHeight) {
179 // Create SharedMemory backed input buffers as necessary. These SharedMemory
180 // instances will be shared with GPU process.
181 std::unique_ptr<base::SharedMemory> input_buffer;
182 const size_t desired_mapped_size = media::VideoFrame::AllocationSize(
183 media::PIXEL_FORMAT_I420, vea_requested_input_coded_size_);
184 if (input_buffers_.empty()) {
185 input_buffer = gpu_factories_->CreateSharedMemory(desired_mapped_size);
186 } else {
187 do {
188 input_buffer = std::move(input_buffers_.front());
189 input_buffers_.pop();
190 } while (!input_buffers_.empty() &&
191 input_buffer->mapped_size() < desired_mapped_size);
192 if (!input_buffer || input_buffer->mapped_size() < desired_mapped_size)
193 return;
194 }
195
196 video_frame = media::VideoFrame::WrapExternalSharedMemory(
197 media::PIXEL_FORMAT_I420, vea_requested_input_coded_size_,
198 gfx::Rect(input_visible_size_), input_visible_size_,
199 reinterpret_cast<uint8_t*>(input_buffer->memory()),
200 input_buffer->mapped_size(), input_buffer->handle(), 0,
201 frame->timestamp());
202 video_frame->AddDestructionObserver(media::BindToCurrentLoop(
203 base::Bind(&VEAEncoder::FrameFinished, this,
204 base::Passed(std::move(input_buffer)))));
205 libyuv::I420Copy(frame->visible_data(media::VideoFrame::kYPlane),
206 frame->stride(media::VideoFrame::kYPlane),
207 frame->visible_data(media::VideoFrame::kUPlane),
208 frame->stride(media::VideoFrame::kUPlane),
209 frame->visible_data(media::VideoFrame::kVPlane),
210 frame->stride(media::VideoFrame::kVPlane),
211 video_frame->visible_data(media::VideoFrame::kYPlane),
212 video_frame->stride(media::VideoFrame::kYPlane),
213 video_frame->visible_data(media::VideoFrame::kUPlane),
214 video_frame->stride(media::VideoFrame::kUPlane),
215 video_frame->visible_data(media::VideoFrame::kVPlane),
216 video_frame->stride(media::VideoFrame::kVPlane),
217 input_visible_size_.width(), input_visible_size_.height());
218 }
219 frames_in_encode_.push(std::make_pair(
220 media::WebmMuxer::VideoParameters(frame), capture_timestamp));
221
222 video_encoder_->Encode(video_frame, false);
223 }
224
225 void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) {
226 DVLOG(3) << __func__;
227 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
228 DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread());
229 DCHECK_GT(bits_per_second_, 0);
230
231 input_visible_size_ = size;
232 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator();
233 if (!video_encoder_ ||
234 !video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_visible_size_,
235 codec_, bits_per_second_, this)) {
236 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
237 }
238 }
239
240 void VEAEncoder::DestroyOnEncodingTaskRunner(
241 base::WaitableEvent* async_waiter) {
242 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
243 video_encoder_.reset();
244 async_waiter->Signal();
245 }
246
247 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media_recorder/vea_encoder.h ('k') | content/renderer/media_recorder/video_track_recorder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698