Commit e8471f23 authored by Jesse McKenna's avatar Jesse McKenna Committed by Commit Bot

Refactor buffer lock into ScopedBufferLock class

This change simplifies MFVideoCallback::OnSample by extracting the
code that locks and unlocks the buffer containing the sample data to a
new class called ScopedBufferLock.

ScopedBufferLock takes an IMFMediaBuffer object upon creation and
locks it in its constructor, allowing the caller to use the buffer,
then automatically unlocks the buffer in its destructor. This not only
simplifies the calling code, but ensures that a buffer is unlocked
after use.

Change-Id: Iba98f3fef8f15f03d5929e7c23b93ab53ab5e90c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2218484
Commit-Queue: Jesse McKenna <jessemckenna@google.com>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773947}
parent 295a4f32
......@@ -125,6 +125,76 @@ class MFPhotoCallback final
DISALLOW_COPY_AND_ASSIGN(MFPhotoCallback);
};
// Locks the given buffer using the fastest supported method when constructed,
// and automatically unlocks the buffer when destroyed.
class ScopedBufferLock {
public:
ScopedBufferLock(ComPtr<IMFMediaBuffer> buffer) : buffer_(std::move(buffer)) {
if (FAILED(buffer_.As(&buffer_2d_))) {
LockSlow();
return;
}
// Try lock methods from fastest to slowest: Lock2DSize(), then Lock2D(),
// then finally LockSlow().
if ((Lock2DSize() || Lock2D()) && !UnlockedNoncontiguousBuffer())
return;
// Fall back to LockSlow() if 2D buffer was unsupported or noncontiguous.
buffer_2d_ = nullptr;
LockSlow();
}
// Unlocks |buffer_2d_| and returns true if |buffer_2d_| is non-contiguous or
// has negative pitch. If |buffer_2d_| is contiguous with positive pitch,
// i.e., the buffer format that the surrounding code expects, returns false.
bool UnlockedNoncontiguousBuffer() {
BOOL is_contiguous;
if (pitch_ > 0 &&
SUCCEEDED(buffer_2d_->IsContiguousFormat(&is_contiguous)) &&
is_contiguous &&
(length_ || SUCCEEDED(buffer_2d_->GetContiguousLength(&length_)))) {
return false;
}
buffer_2d_->Unlock2D();
return true;
}
bool Lock2DSize() {
ComPtr<IMF2DBuffer2> buffer_2d_2;
if (FAILED(buffer_.As(&buffer_2d_2)))
return false;
BYTE* data_start;
return SUCCEEDED(buffer_2d_2->Lock2DSize(MF2DBuffer_LockFlags_Read, &data_,
&pitch_, &data_start, &length_));
}
bool Lock2D() { return SUCCEEDED(buffer_2d_->Lock2D(&data_, &pitch_)); }
void LockSlow() {
DWORD max_length = 0;
buffer_->Lock(&data_, &max_length, &length_);
}
~ScopedBufferLock() {
if (buffer_2d_)
buffer_2d_->Unlock2D();
else
buffer_->Unlock();
}
ScopedBufferLock(const ScopedBufferLock&) = delete;
ScopedBufferLock& operator=(const ScopedBufferLock&) = delete;
BYTE* data() const { return data_; }
DWORD length() const { return length_; }
private:
ComPtr<IMFMediaBuffer> buffer_;
ComPtr<IMF2DBuffer> buffer_2d_;
BYTE* data_ = nullptr;
DWORD length_ = 0;
LONG pitch_ = 0;
};
scoped_refptr<IMFCaptureEngineOnSampleCallback> CreateMFPhotoCallback(
VideoCaptureDevice::TakePhotoCallback callback,
VideoCaptureFormat format) {
......@@ -438,60 +508,16 @@ class MFVideoCallback final
ComPtr<IMFMediaBuffer> buffer;
sample->GetBufferByIndex(i, &buffer);
if (buffer) {
// Lock the buffer using the fastest method that it supports. The
// Lock2DSize() method is faster than Lock2D(), which is faster than
// Lock().
DWORD length = 0;
BYTE* data = nullptr;
ComPtr<IMF2DBuffer> buffer_2d;
if (SUCCEEDED(buffer.As(&buffer_2d))) {
HRESULT lock_result;
BYTE* scanline_0 = nullptr;
LONG pitch = 0;
ComPtr<IMF2DBuffer2> buffer_2d_2;
if (SUCCEEDED(buffer.As(&buffer_2d_2))) {
BYTE* data_start;
lock_result =
buffer_2d_2->Lock2DSize(MF2DBuffer_LockFlags_Read, &scanline_0,
&pitch, &data_start, &length);
} else {
lock_result = buffer_2d->Lock2D(&scanline_0, &pitch);
}
if (SUCCEEDED(lock_result)) {
// Use |buffer_2d| only if it is contiguous and has positive pitch.
BOOL is_contiguous;
if (pitch > 0 &&
SUCCEEDED(buffer_2d->IsContiguousFormat(&is_contiguous)) &&
is_contiguous &&
(length ||
SUCCEEDED(buffer_2d->GetContiguousLength(&length)))) {
data = scanline_0;
} else {
buffer_2d->Unlock2D();
}
}
}
if (!data) {
// If the faster methods fail, fall back to Lock to lock the buffer.
buffer_2d = nullptr;
DWORD max_length = 0;
buffer->Lock(&data, &max_length, &length);
}
if (data) {
observer_->OnIncomingCapturedData(data, length, reference_time,
timestamp);
ScopedBufferLock locked_buffer(buffer);
if (locked_buffer.data()) {
observer_->OnIncomingCapturedData(locked_buffer.data(),
locked_buffer.length(),
reference_time, timestamp);
} else {
observer_->OnFrameDropped(
VideoCaptureFrameDropReason::
kWinMediaFoundationLockingBufferDelieveredNullptr);
}
if (buffer_2d)
buffer_2d->Unlock2D();
else
buffer->Unlock();
} else {
observer_->OnFrameDropped(
VideoCaptureFrameDropReason::
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment