blob: 479f0d3c5ac280ad74deee00752be1c7ac11da47 [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 "photo_handler.h"
#include <mfapi.h>
#include <mfcaptureengine.h>
#include <wincodec.h>
#include <cassert>
#include "capture_engine_listener.h"
#include "string_utils.h"
namespace camera_windows {
using Microsoft::WRL::ComPtr;
// Initializes media type for photo capture for jpeg images.
HRESULT BuildMediaTypeForPhotoCapture(IMFMediaType* src_media_type,
IMFMediaType** photo_media_type,
GUID image_format) {
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;
}
hr = new_media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Image);
if (FAILED(hr)) {
return hr;
}
hr = new_media_type->SetGUID(MF_MT_SUBTYPE, image_format);
if (FAILED(hr)) {
return hr;
}
new_media_type.CopyTo(photo_media_type);
return hr;
}
HRESULT PhotoHandler::InitPhotoSink(IMFCaptureEngine* capture_engine,
IMFMediaType* base_media_type) {
assert(capture_engine);
assert(base_media_type);
HRESULT hr = S_OK;
if (photo_sink_) {
// If photo sink already exists, only update output filename.
hr = photo_sink_->SetOutputFileName(Utf16FromUtf8(file_path_).c_str());
if (FAILED(hr)) {
photo_sink_ = nullptr;
}
return hr;
}
ComPtr<IMFMediaType> photo_media_type;
ComPtr<IMFCaptureSink> capture_sink;
// Get sink with photo type.
hr =
capture_engine->GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PHOTO, &capture_sink);
if (FAILED(hr)) {
return hr;
}
hr = capture_sink.As(&photo_sink_);
if (FAILED(hr)) {
photo_sink_ = nullptr;
return hr;
}
hr = photo_sink_->RemoveAllStreams();
if (FAILED(hr)) {
photo_sink_ = nullptr;
return hr;
}
hr = BuildMediaTypeForPhotoCapture(base_media_type,
photo_media_type.GetAddressOf(),
GUID_ContainerFormatJpeg);
if (FAILED(hr)) {
photo_sink_ = nullptr;
return hr;
}
DWORD photo_sink_stream_index;
hr = photo_sink_->AddStream(
(DWORD)MF_CAPTURE_ENGINE_PREFERRED_SOURCE_STREAM_FOR_PHOTO,
photo_media_type.Get(), nullptr, &photo_sink_stream_index);
if (FAILED(hr)) {
photo_sink_ = nullptr;
return hr;
}
hr = photo_sink_->SetOutputFileName(Utf16FromUtf8(file_path_).c_str());
if (FAILED(hr)) {
photo_sink_ = nullptr;
return hr;
}
return hr;
}
HRESULT PhotoHandler::TakePhoto(const std::string& file_path,
IMFCaptureEngine* capture_engine,
IMFMediaType* base_media_type) {
assert(!file_path.empty());
assert(capture_engine);
assert(base_media_type);
file_path_ = file_path;
HRESULT hr = InitPhotoSink(capture_engine, base_media_type);
if (FAILED(hr)) {
return hr;
}
photo_state_ = PhotoState::kTakingPhoto;
return capture_engine->TakePhoto();
}
void PhotoHandler::OnPhotoTaken() {
assert(photo_state_ == PhotoState::kTakingPhoto);
photo_state_ = PhotoState::kIdle;
}
} // namespace camera_windows