blob: 538754c3e9e29739930ba75c740e05d17d1d8416 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "preview_handler.h"
#include <mfapi.h>
#include <mfcaptureengine.h>
#include <cassert>
#include "capture_engine_listener.h"
#include "string_utils.h"
namespace camera_windows {
using Microsoft::WRL::ComPtr;
// Initializes media type for video preview.
HRESULT BuildMediaTypeForVideoPreview(IMFMediaType* src_media_type,
IMFMediaType** preview_media_type) {
assert(src_media_type);
ComPtr<IMFMediaType> new_media_type;
HRESULT hr = MFCreateMediaType(&new_media_type);
if (FAILED(hr)) {
return hr;
}
// Clones everything from original media type.
hr = src_media_type->CopyAllItems(new_media_type.Get());
if (FAILED(hr)) {
return hr;
}
// Changes subtype to MFVideoFormat_RGB32.
hr = new_media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
if (FAILED(hr)) {
return hr;
}
hr = new_media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
if (FAILED(hr)) {
return hr;
}
new_media_type.CopyTo(preview_media_type);
return hr;
}
HRESULT PreviewHandler::InitPreviewSink(
IMFCaptureEngine* capture_engine, IMFMediaType* base_media_type,
CaptureEngineListener* sample_callback) {
assert(capture_engine);
assert(base_media_type);
assert(sample_callback);
HRESULT hr = S_OK;
if (preview_sink_) {
// Preview sink already initialized.
return hr;
}
ComPtr<IMFMediaType> preview_media_type;
ComPtr<IMFCaptureSink> capture_sink;
// Get sink with preview type.
hr = capture_engine->GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PREVIEW,
&capture_sink);
if (FAILED(hr)) {
return hr;
}
hr = capture_sink.As(&preview_sink_);
if (FAILED(hr)) {
preview_sink_ = nullptr;
return hr;
}
hr = preview_sink_->RemoveAllStreams();
if (FAILED(hr)) {
preview_sink_ = nullptr;
return hr;
}
hr = BuildMediaTypeForVideoPreview(base_media_type,
preview_media_type.GetAddressOf());
if (FAILED(hr)) {
preview_sink_ = nullptr;
return hr;
}
DWORD preview_sink_stream_index;
hr = preview_sink_->AddStream(
(DWORD)MF_CAPTURE_ENGINE_PREFERRED_SOURCE_STREAM_FOR_VIDEO_PREVIEW,
preview_media_type.Get(), nullptr, &preview_sink_stream_index);
if (FAILED(hr)) {
return hr;
}
hr = preview_sink_->SetSampleCallback(preview_sink_stream_index,
sample_callback);
if (FAILED(hr)) {
preview_sink_ = nullptr;
return hr;
}
return hr;
}
HRESULT PreviewHandler::StartPreview(IMFCaptureEngine* capture_engine,
IMFMediaType* base_media_type,
CaptureEngineListener* sample_callback) {
assert(capture_engine);
assert(base_media_type);
HRESULT hr =
InitPreviewSink(capture_engine, base_media_type, sample_callback);
if (FAILED(hr)) {
return hr;
}
preview_state_ = PreviewState::kStarting;
return capture_engine->StartPreview();
}
HRESULT PreviewHandler::StopPreview(IMFCaptureEngine* capture_engine) {
if (preview_state_ == PreviewState::kStarting ||
preview_state_ == PreviewState::kRunning ||
preview_state_ == PreviewState::kPaused) {
preview_state_ = PreviewState::kStopping;
return capture_engine->StopPreview();
}
return E_FAIL;
}
bool PreviewHandler::PausePreview() {
if (preview_state_ != PreviewState::kRunning) {
return false;
}
preview_state_ = PreviewState::kPaused;
return true;
}
bool PreviewHandler::ResumePreview() {
if (preview_state_ != PreviewState::kPaused) {
return false;
}
preview_state_ = PreviewState::kRunning;
return true;
}
void PreviewHandler::OnPreviewStarted() {
assert(preview_state_ == PreviewState::kStarting);
if (preview_state_ == PreviewState::kStarting) {
preview_state_ = PreviewState::kRunning;
}
}
} // namespace camera_windows