OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "media/gpu/media_foundation_video_encode_accelerator_win.h" | |
6 | |
7 #if !defined(OS_WIN) | |
8 // #error This file should only be built on Windows. | |
ananta
2016/06/28 22:50:01
Don't think we need this. The _win suffix should b
emircan
2016/07/02 00:07:38
Done.
| |
9 #else | |
10 #pragma warning(push) | |
11 #pragma warning(disable : 4800) // Disable warning for added padding. | |
12 #endif // !defined(OS_WIN) | |
13 | |
14 #include <codecapi.h> | |
15 #include <mferror.h> | |
16 #include <mftransform.h> | |
17 | |
18 #include "base/threading/thread_task_runner_handle.h" | |
19 #include "base/win/scoped_co_mem.h" | |
20 #include "base/win/scoped_variant.h" | |
21 #include "media/base/win/mf_helpers.h" | |
22 #include "media/base/win/mf_initializer.h" | |
23 #include "third_party/libyuv/include/libyuv.h" | |
24 | |
25 using base::win::ScopedComPtr; | |
26 using media::mf::MediaBufferScopedPointer; | |
27 | |
28 namespace media { | |
29 | |
30 namespace { | |
31 | |
32 const size_t kMaxFrameRateNumerator = 30; | |
33 const size_t kMaxFrameRateDenominator = 1; | |
34 const size_t kMaxResolutionWidth = 4096; | |
35 const size_t kMaxResolutionHeight = 2160; | |
36 const size_t kNumInputBuffers = 3; | |
37 const size_t kOneSecondInMicroseconds = 1000000; | |
38 const size_t kOutputSampleBufferSizeRatio = 4; | |
39 | |
40 static const wchar_t* const kMediaFoundationVideoEncoderDLLs[] = { | |
41 L"mf.dll", L"mfplat.dll", | |
42 }; | |
43 | |
44 } // namespace | |
45 | |
46 struct MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef { | |
47 BitstreamBufferRef(int32_t id, | |
48 std::unique_ptr<base::SharedMemory> shm, | |
49 size_t size) | |
50 : id(id), shm(std::move(shm)), size(size) {} | |
51 const int32_t id; | |
52 const std::unique_ptr<base::SharedMemory> shm; | |
53 const size_t size; | |
54 | |
55 private: | |
56 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); | |
57 }; | |
58 | |
59 MediaFoundationVideoEncodeAccelerator::MediaFoundationVideoEncodeAccelerator() | |
60 : win_version_(base::win::GetVersion()), | |
61 client_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
62 encoder_thread_("MFEncoderThread"), | |
63 encoder_task_weak_factory_(this) { | |
64 DVLOG(3) << __FUNCTION__; | |
65 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); | |
66 } | |
67 | |
68 MediaFoundationVideoEncodeAccelerator:: | |
69 ~MediaFoundationVideoEncodeAccelerator() { | |
70 DVLOG(3) << __FUNCTION__; | |
71 DCHECK(thread_checker_.CalledOnValidThread()); | |
72 | |
73 Destroy(); | |
74 DCHECK(!encoder_thread_.IsRunning()); | |
75 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); | |
76 } | |
77 | |
78 media::VideoEncodeAccelerator::SupportedProfiles | |
79 MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles() { | |
80 DVLOG(3) << __FUNCTION__; | |
81 DCHECK(thread_checker_.CalledOnValidThread()); | |
82 | |
83 SupportedProfiles profiles; | |
84 if (base::win::GetVersion() < base::win::VERSION_WIN8) { | |
85 DLOG(ERROR) << "Windows versions earlier than 8 are not supported."; | |
86 return profiles; | |
87 } | |
88 | |
89 SupportedProfile profile; | |
90 profile.profile = media::H264PROFILE_BASELINE; | |
ananta
2016/06/28 22:50:01
Does this always have to be the baseline profile?.
emircan
2016/07/02 00:07:37
OpenH264 SW only supports baseline right now. In c
| |
91 profile.max_framerate_numerator = kMaxFrameRateNumerator; | |
92 profile.max_framerate_denominator = kMaxFrameRateDenominator; | |
93 profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight); | |
94 profiles.push_back(profile); | |
95 return profiles; | |
96 } | |
97 | |
98 bool MediaFoundationVideoEncodeAccelerator::Initialize( | |
99 media::VideoPixelFormat format, | |
100 const gfx::Size& input_visible_size, | |
101 media::VideoCodecProfile output_profile, | |
102 uint32_t initial_bitrate, | |
ananta
2016/06/28 22:50:01
The Initialize function is very big. Please split
emircan
2016/07/02 00:07:37
Done.
| |
103 Client* client) { | |
104 DVLOG(3) << __FUNCTION__ | |
105 << ": input_format=" << media::VideoPixelFormatToString(format) | |
106 << ", input_visible_size=" << input_visible_size.ToString() | |
107 << ", output_profile=" << output_profile | |
108 << ", initial_bitrate=" << initial_bitrate; | |
109 DCHECK(thread_checker_.CalledOnValidThread()); | |
110 | |
111 if (media::PIXEL_FORMAT_I420 != format) { | |
112 DLOG(ERROR) << "Input format not supported= " | |
113 << media::VideoPixelFormatToString(format); | |
114 return false; | |
115 } | |
ananta
2016/06/28 22:50:01
newline here.
emircan
2016/07/02 00:07:37
Done.
| |
116 if (media::H264PROFILE_BASELINE != output_profile) { | |
117 DLOG(ERROR) << "Output profile not supported= " << output_profile; | |
118 return false; | |
119 } | |
120 | |
121 for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) { | |
122 HMODULE dll = ::GetModuleHandle(mfdll); | |
123 if (!dll) { | |
124 DLOG(ERROR) << mfdll << " is required for encoding"; | |
125 return false; | |
126 } | |
127 } | |
128 media::InitializeMediaFoundation(); | |
ananta
2016/06/28 22:50:00
newline here.
emircan
2016/07/02 00:07:37
Done.
| |
129 | |
130 uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER; | |
131 MFT_REGISTER_TYPE_INFO input_info; | |
132 input_info.guidMajorType = MFMediaType_Video; | |
133 input_info.guidSubtype = MFVideoFormat_NV12; | |
134 MFT_REGISTER_TYPE_INFO output_info; | |
135 output_info.guidMajorType = MFMediaType_Video; | |
136 output_info.guidSubtype = MFVideoFormat_H264; | |
137 | |
138 base::win::ScopedCoMem<CLSID> CLSIDs; | |
139 uint32_t count = 0; | |
140 HRESULT hr = MFTEnum(MFT_CATEGORY_VIDEO_ENCODER, flags, NULL, &output_info, | |
141 NULL, &CLSIDs, &count); | |
142 RETURN_ON_HR_FAILURE(hr, "Couldn't enumerate hardware encoder", false); | |
143 RETURN_ON_FAILURE((count > 0), "No HW encoder found", false); | |
144 DVLOG(3) << "HW encoder(s) found: " << count; | |
145 hr = encoder_.CreateInstance(CLSIDs[0]); | |
146 RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false); | |
147 | |
148 if (!encoder_thread_.Start()) { | |
149 DLOG(ERROR) << "Failed spawning encoder thread."; | |
150 return false; | |
151 } | |
152 encoder_thread_task_runner_ = encoder_thread_.task_runner(); | |
ananta
2016/06/28 22:50:01
newline
emircan
2016/07/02 00:07:38
Done.
| |
153 | |
154 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | |
155 client_ = client_ptr_factory_->GetWeakPtr(); | |
156 input_visible_size_ = input_visible_size; | |
157 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; | |
158 target_bitrate_ = initial_bitrate; | |
159 bitstream_buffer_size_ = input_visible_size.GetArea(); | |
160 | |
161 u_plane_offset_ = | |
162 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, | |
163 input_visible_size_) | |
164 .GetArea(); | |
165 v_plane_offset_ = | |
166 u_plane_offset_ + | |
167 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kUPlane, | |
168 input_visible_size_) | |
169 .GetArea(); | |
170 | |
171 hr = encoder_->GetStreamLimits( | |
172 &input_stream_count_min_, &input_stream_count_max_, | |
173 &output_stream_count_min_, &output_stream_count_max_); | |
174 RETURN_ON_HR_FAILURE(hr, "Couldn't query stream limits", false); | |
175 DVLOG(3) << "Stream limits: " << input_stream_count_min_ << "," | |
176 << input_stream_count_max_ << "," << output_stream_count_min_ << "," | |
177 << output_stream_count_max_; | |
178 | |
179 base::win::ScopedComPtr<IMFMediaType> imf_output_media_type; | |
180 hr = MFCreateMediaType(imf_output_media_type.Receive()); | |
181 hr &= imf_output_media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); | |
ananta
2016/06/28 22:50:01
what happens if MFCreateMediaType fails?. Addition
emircan
2016/07/02 00:07:38
I will add a return there if fails.
| |
182 hr &= imf_output_media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); | |
183 hr &= imf_output_media_type->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); | |
184 hr &= MFSetAttributeRatio(imf_output_media_type.get(), MF_MT_FRAME_RATE, | |
185 frame_rate_, kMaxFrameRateDenominator); | |
186 hr &= MFSetAttributeSize(imf_output_media_type.get(), MF_MT_FRAME_SIZE, | |
ananta
2016/06/28 22:50:01
Move this to the next line for consistency
emircan
2016/07/02 00:07:37
Done.
| |
187 input_visible_size_.width(), | |
188 input_visible_size_.height()); | |
189 hr &= imf_output_media_type->SetUINT32(MF_MT_INTERLACE_MODE, | |
190 MFVideoInterlace_Progressive); | |
191 hr &= imf_output_media_type->SetUINT32(MF_MT_MPEG2_PROFILE, | |
192 eAVEncH264VProfile_Base); | |
193 RETURN_ON_HR_FAILURE(hr, "Couldn't set output params", false); | |
194 hr = encoder_->SetOutputType(0, imf_output_media_type.get(), 0); | |
195 RETURN_ON_HR_FAILURE(hr, "Couldn't set output media type", false); | |
196 | |
197 base::win::ScopedComPtr<IMFMediaType> imf_input_media_type; | |
198 hr = MFCreateMediaType(imf_input_media_type.Receive()); | |
199 hr &= imf_input_media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); | |
ananta
2016/06/28 22:50:01
Ditto for MFCreateMediaType and the other Set oper
emircan
2016/07/02 00:07:38
Done.
| |
200 hr &= imf_input_media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12); | |
201 hr &= MFSetAttributeRatio(imf_input_media_type.get(), MF_MT_FRAME_RATE, | |
202 frame_rate_, kMaxFrameRateDenominator); | |
203 hr &= MFSetAttributeSize(imf_input_media_type.get(), MF_MT_FRAME_SIZE, | |
204 input_visible_size_.width(), | |
205 input_visible_size_.height()); | |
206 hr &= imf_input_media_type->SetUINT32(MF_MT_INTERLACE_MODE, | |
207 MFVideoInterlace_Progressive); | |
208 RETURN_ON_HR_FAILURE(hr, "Couldn't set input params", false); | |
209 hr = encoder_->SetInputType(0, imf_input_media_type.get(), 0); | |
210 RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", false); | |
211 | |
212 hr = encoder_.QueryInterface(IID_ICodecAPI, codec_api_.ReceiveVoid()); | |
213 RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false); | |
214 VARIANT var; | |
215 var.vt = VT_UI4; | |
216 var.ulVal = eAVEncCommonRateControlMode_CBR; | |
217 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var); | |
218 RETURN_ON_HR_FAILURE(hr, "Couldn't set CommonRateControlMode", false); | |
219 var.ulVal = target_bitrate_; | |
220 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); | |
221 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); | |
222 var.ulVal = eAVEncAdaptiveMode_FrameRate; | |
223 hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var); | |
224 RETURN_ON_HR_FAILURE(hr, "Couldn't set FrameRate", false); | |
225 var.vt = VT_BOOL; | |
226 var.boolVal = VARIANT_TRUE; | |
227 hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var); | |
228 RETURN_ON_HR_FAILURE(hr, "Couldn't set LowLatencyMode", false); | |
229 | |
230 input_sample_.Attach(mf::CreateEmptySampleWithBuffer( | |
231 VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size), 2)); | |
232 output_sample_.Attach(mf::CreateEmptySampleWithBuffer( | |
233 bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, 2)); | |
234 | |
235 hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL); | |
236 RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false); | |
237 | |
238 client_task_runner_->PostTask( | |
239 FROM_HERE, | |
240 base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers, | |
241 input_visible_size_, bitstream_buffer_size_)); | |
242 return SUCCEEDED(hr); | |
243 } | |
244 | |
245 void MediaFoundationVideoEncodeAccelerator::Encode( | |
246 const scoped_refptr<media::VideoFrame>& frame, | |
247 bool force_keyframe) { | |
248 DVLOG(3) << __FUNCTION__; | |
249 DCHECK(thread_checker_.CalledOnValidThread()); | |
250 | |
251 encoder_thread_task_runner_->PostTask( | |
252 FROM_HERE, base::Bind(&MediaFoundationVideoEncodeAccelerator::EncodeTask, | |
253 encoder_weak_ptr_, frame, force_keyframe)); | |
254 } | |
255 | |
256 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer( | |
257 const media::BitstreamBuffer& buffer) { | |
258 DVLOG(3) << __FUNCTION__ << ": buffer size=" << buffer.size(); | |
259 DCHECK(thread_checker_.CalledOnValidThread()); | |
260 | |
261 if (buffer.size() < bitstream_buffer_size_) { | |
262 DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size() | |
263 << " vs. " << bitstream_buffer_size_; | |
264 client_->NotifyError(kInvalidArgumentError); | |
265 return; | |
266 } | |
267 | |
268 std::unique_ptr<base::SharedMemory> shm( | |
269 new base::SharedMemory(buffer.handle(), false)); | |
270 if (!shm->Map(buffer.size())) { | |
271 DLOG(ERROR) << "Failed mapping shared memory."; | |
272 client_->NotifyError(kPlatformFailureError); | |
273 return; | |
274 } | |
275 | |
276 std::unique_ptr<BitstreamBufferRef> buffer_ref( | |
277 new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); | |
278 encoder_thread_task_runner_->PostTask( | |
279 FROM_HERE, | |
280 base::Bind( | |
281 &MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask, | |
282 encoder_weak_ptr_, base::Passed(&buffer_ref))); | |
283 } | |
284 | |
285 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange( | |
286 uint32_t bitrate, | |
287 uint32_t framerate) { | |
288 DVLOG(3) << __FUNCTION__ << ": bitrate=" << bitrate | |
289 << ": framerate=" << framerate; | |
290 DCHECK(thread_checker_.CalledOnValidThread()); | |
291 | |
292 encoder_thread_task_runner_->PostTask( | |
293 FROM_HERE, base::Bind(&MediaFoundationVideoEncodeAccelerator:: | |
294 RequestEncodingParametersChangeTask, | |
295 encoder_weak_ptr_, bitrate, framerate)); | |
296 } | |
297 | |
298 void MediaFoundationVideoEncodeAccelerator::Destroy() { | |
299 DVLOG(3) << __FUNCTION__; | |
300 DCHECK(thread_checker_.CalledOnValidThread()); | |
301 | |
302 // Cancel all callbacks. | |
303 client_ptr_factory_.reset(); | |
304 | |
305 if (encoder_thread_.IsRunning()) { | |
306 encoder_thread_task_runner_->PostTask( | |
307 FROM_HERE, | |
308 base::Bind(&MediaFoundationVideoEncodeAccelerator::DestroyTask, | |
309 encoder_weak_ptr_)); | |
310 encoder_thread_.Stop(); | |
311 } else { | |
312 DestroyTask(); | |
313 } | |
314 } | |
315 | |
316 void MediaFoundationVideoEncodeAccelerator::EncodeTask( | |
317 const scoped_refptr<media::VideoFrame>& frame, | |
318 bool force_keyframe) { | |
319 DVLOG(3) << __FUNCTION__; | |
320 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | |
321 | |
322 base::win::ScopedComPtr<IMFMediaBuffer> input_buffer; | |
323 input_sample_->GetBufferByIndex(0, input_buffer.Receive()); | |
324 { | |
ananta
2016/06/28 22:50:01
newline here.
emircan
2016/07/02 00:07:37
Done.
| |
325 MediaBufferScopedPointer scoped_buffer(input_buffer.get()); | |
326 DCHECK(scoped_buffer.get()); | |
327 libyuv::I420Copy(frame->visible_data(media::VideoFrame::kYPlane), | |
328 frame->stride(media::VideoFrame::kYPlane), | |
329 frame->visible_data(media::VideoFrame::kVPlane), | |
330 frame->stride(media::VideoFrame::kVPlane), | |
331 frame->visible_data(media::VideoFrame::kUPlane), | |
332 frame->stride(media::VideoFrame::kUPlane), | |
333 scoped_buffer.get(), | |
334 frame->stride(media::VideoFrame::kYPlane), | |
335 scoped_buffer.get() + u_plane_offset_, | |
336 frame->stride(media::VideoFrame::kUPlane), | |
337 scoped_buffer.get() + v_plane_offset_, | |
338 frame->stride(media::VideoFrame::kVPlane), | |
339 input_visible_size_.width(), input_visible_size_.height()); | |
340 } | |
341 input_sample_->SetSampleTime(frame->timestamp().InMicroseconds() * 10); | |
ananta
2016/06/28 22:50:00
newline here.
emircan
2016/07/02 00:07:37
Done.
| |
342 input_sample_->SetSampleDuration(kOneSecondInMicroseconds / frame_rate_); | |
343 HRESULT hr = encoder_->ProcessInput(0, input_sample_.get(), 0); | |
344 RETURN_ON_HR_FAILURE(hr, "Couldn't encode", ); | |
345 DVLOG(3) << "Sent for encode " << hr; | |
346 | |
347 ProcessOutput(); | |
ananta
2016/06/28 22:50:01
Perhaps we need to check if ProcessOutput succeeds
emircan
2016/07/02 00:07:37
I answered below.
| |
348 } | |
349 | |
350 void MediaFoundationVideoEncodeAccelerator::ProcessOutput() { | |
ananta
2016/06/28 22:50:00
Should this function be returning void?. What happ
emircan
2016/07/02 00:07:37
We are fine if it fails.
- If it says MF_E_TRANSF
| |
351 DVLOG(3) << __FUNCTION__; | |
352 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | |
353 | |
354 if (bitstream_buffer_queue_.empty()) { | |
355 DVLOG(3) << "No bitstream buffers."; | |
356 return; | |
357 } | |
358 | |
359 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; | |
360 output_data_buffer.dwStreamID = 0; | |
361 output_data_buffer.dwStatus = 0; | |
362 output_data_buffer.pEvents = NULL; | |
363 output_data_buffer.pSample = output_sample_.get(); | |
364 DWORD status = 0; | |
365 HRESULT hr = encoder_->ProcessOutput(0, 1, &output_data_buffer, &status); | |
366 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { | |
367 DVLOG(3) << "MF_E_TRANSFORM_NEED_MORE_INPUT"; | |
368 return; | |
369 } | |
370 RETURN_ON_HR_FAILURE(hr, "Couldn't get encoded data", ); | |
371 DVLOG(3) << "Got encoded data " << hr; | |
372 | |
373 std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef> | |
374 buffer_ref = std::move(bitstream_buffer_queue_.front()); | |
375 bitstream_buffer_queue_.pop_front(); | |
376 | |
377 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | |
378 output_sample_->GetBufferByIndex(0, output_buffer.Receive()); | |
379 DWORD size = 0; | |
ananta
2016/06/28 22:50:01
What happens if GetBufferByIndex fails
emircan
2016/07/02 00:07:37
Adding hr checks.
| |
380 output_buffer->GetCurrentLength(&size); | |
381 { | |
382 MediaBufferScopedPointer scoped_buffer(output_buffer.get()); | |
383 memcpy(buffer_ref->shm->memory(), scoped_buffer.get(), size); | |
384 } | |
385 | |
386 const bool keyframe = MFGetAttributeUINT32( | |
387 output_sample_.get(), MFSampleExtension_CleanPoint, false); | |
388 DVLOG(3) << "We HAVE encoded data with size:" << size << " keyframe " | |
389 << keyframe; | |
390 | |
391 client_task_runner_->PostTask( | |
392 FROM_HERE, | |
393 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, size, | |
394 keyframe, base::Time::Now() - base::Time())); | |
395 ProcessOutput(); | |
396 } | |
397 | |
398 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask( | |
399 std::unique_ptr<BitstreamBufferRef> buffer_ref) { | |
400 DVLOG(3) << __FUNCTION__; | |
401 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | |
402 | |
403 bitstream_buffer_queue_.push_back(std::move(buffer_ref)); | |
404 } | |
405 | |
406 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask( | |
407 uint32_t bitrate, | |
408 uint32_t framerate) { | |
409 DVLOG(3) << __FUNCTION__; | |
410 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | |
411 | |
412 frame_rate_ = framerate > 1 ? framerate : 1; | |
413 target_bitrate_ = bitrate > 1 ? bitrate : 1; | |
414 | |
415 VARIANT var; | |
416 var.vt = VT_UI4; | |
417 var.ulVal = target_bitrate_; | |
418 HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); | |
419 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", ); | |
420 | |
421 base::win::ScopedComPtr<IMFMediaType> imf_output_media_type; | |
422 hr = MFCreateMediaType(imf_output_media_type.Receive()); | |
423 hr &= imf_output_media_type->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); | |
424 hr &= MFSetAttributeRatio(imf_output_media_type.get(), MF_MT_FRAME_RATE, | |
425 framerate, kMaxFrameRateDenominator); | |
426 } | |
427 | |
428 void MediaFoundationVideoEncodeAccelerator::DestroyTask() { | |
429 DVLOG(3) << __FUNCTION__; | |
430 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | |
431 | |
432 encoder_.Release(); | |
433 } | |
434 | |
435 } // namespace content | |
OLD | NEW |