From 49903367608af0a89adb5ff83f61e2d7b9b7c514 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 6 Jun 2013 01:34:57 -0700 Subject: [PATCH] Base camera access sample for Windows RT added. Microsoft Media Foundation Camera Sample for Windows RT added. --- .../ImageManipulations/C++/AdvancedCapture.xaml | 81 + .../C++/AdvancedCapture.xaml.cpp | 1034 ++++++ .../ImageManipulations/C++/AdvancedCapture.xaml.h | 103 + samples/winrt/ImageManipulations/C++/App.xaml | 30 + samples/winrt/ImageManipulations/C++/App.xaml.cpp | 114 + samples/winrt/ImageManipulations/C++/App.xaml.h | 35 + .../winrt/ImageManipulations/C++/AudioCapture.xaml | 62 + .../ImageManipulations/C++/AudioCapture.xaml.cpp | 366 ++ .../ImageManipulations/C++/AudioCapture.xaml.h | 70 + .../winrt/ImageManipulations/C++/BasicCapture.xaml | 87 + .../ImageManipulations/C++/BasicCapture.xaml.cpp | 535 +++ .../ImageManipulations/C++/BasicCapture.xaml.h | 88 + samples/winrt/ImageManipulations/C++/Constants.cpp | 24 + samples/winrt/ImageManipulations/C++/Constants.h | 45 + samples/winrt/ImageManipulations/C++/MainPage.xaml | 166 + .../winrt/ImageManipulations/C++/MainPage.xaml.cpp | 315 ++ .../winrt/ImageManipulations/C++/MainPage.xaml.h | 105 + .../winrt/ImageManipulations/C++/MediaCapture.sln | 52 + .../ImageManipulations/C++/MediaCapture.vcxproj | 200 ++ .../C++/MediaCapture.vcxproj.filters | 88 + .../C++/MediaExtensions/Common/AsyncCB.h | 81 + .../C++/MediaExtensions/Common/BufferLock.h | 102 + .../C++/MediaExtensions/Common/CritSec.h | 62 + .../C++/MediaExtensions/Common/LinkList.h | 516 +++ .../C++/MediaExtensions/Common/OpQueue.h | 222 ++ .../C++/MediaExtensions/Grayscale/Grayscale.cpp | 1783 ++++++++++ .../C++/MediaExtensions/Grayscale/Grayscale.def | 4 + .../C++/MediaExtensions/Grayscale/Grayscale.h | 266 ++ .../MediaExtensions/Grayscale/Grayscale.vcxproj | 313 ++ .../Grayscale/Grayscale.vcxproj.filters | 22 + .../Grayscale/GrayscaleTransform.idl | 11 + .../C++/MediaExtensions/Grayscale/dllmain.cpp | 58 + .../ImageManipulations/C++/Package.appxmanifest | 39 + .../C++/assets/microsoft-sdk.png | Bin 0 -> 1583 bytes .../C++/assets/placeholder-sdk.png | Bin 0 -> 8991 bytes .../C++/assets/smallTile-sdk.png | Bin 0 -> 1248 bytes .../ImageManipulations/C++/assets/splash-sdk.png | Bin 0 -> 5068 bytes .../C++/assets/squareTile-sdk.png | Bin 0 -> 2482 bytes .../C++/assets/storeLogo-sdk.png | Bin 0 -> 1550 bytes .../ImageManipulations/C++/assets/tile-sdk.png | Bin 0 -> 2665 bytes .../ImageManipulations/C++/assets/windows-sdk.png | Bin 0 -> 2997 bytes .../C++/common/LayoutAwarePage.cpp | 452 +++ .../C++/common/LayoutAwarePage.h | 88 + .../C++/common/StandardStyles.xaml | 978 ++++++ .../C++/common/suspensionmanager.cpp | 481 +++ .../C++/common/suspensionmanager.h | 50 + samples/winrt/ImageManipulations/C++/pch.cpp | 16 + samples/winrt/ImageManipulations/C++/pch.h | 23 + .../C++/sample-utils/SampleTemplateStyles.xaml | 51 + samples/winrt/ImageManipulations/description.html | 238 ++ ...ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css | 0 .../winrt/ImageManipulations/description/Brand.css | 3629 ++++++++++++++++++++ .../ImageManipulations/description/Combined.css | 0 .../ImageManipulations/description/Galleries.css | 418 +++ .../ImageManipulations/description/Layout.css | 147 + .../c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css | 303 ++ .../description/iframedescription.css | 179 + .../ImageManipulations/description/offline.js | 52 + samples/winrt/ImageManipulations/license.rtf | 25 + 59 files changed, 14209 insertions(+) create mode 100644 samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml create mode 100644 samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/App.xaml create mode 100644 samples/winrt/ImageManipulations/C++/App.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/App.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml create mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml create mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/Constants.cpp create mode 100644 samples/winrt/ImageManipulations/C++/Constants.h create mode 100644 samples/winrt/ImageManipulations/C++/MainPage.xaml create mode 100644 samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp create mode 100644 samples/winrt/ImageManipulations/C++/MainPage.xaml.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaCapture.sln create mode 100644 samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj create mode 100644 samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl create mode 100644 samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp create mode 100644 samples/winrt/ImageManipulations/C++/Package.appxmanifest create mode 100644 samples/winrt/ImageManipulations/C++/assets/microsoft-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/placeholder-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/smallTile-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/splash-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/squareTile-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/storeLogo-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/tile-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/assets/windows-sdk.png create mode 100644 samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp create mode 100644 samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h create mode 100644 samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml create mode 100644 samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp create mode 100644 samples/winrt/ImageManipulations/C++/common/suspensionmanager.h create mode 100644 samples/winrt/ImageManipulations/C++/pch.cpp create mode 100644 samples/winrt/ImageManipulations/C++/pch.h create mode 100644 samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml create mode 100644 samples/winrt/ImageManipulations/description.html create mode 100644 samples/winrt/ImageManipulations/description/4ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css create mode 100644 samples/winrt/ImageManipulations/description/Brand.css create mode 100644 samples/winrt/ImageManipulations/description/Combined.css create mode 100644 samples/winrt/ImageManipulations/description/Galleries.css create mode 100644 samples/winrt/ImageManipulations/description/Layout.css create mode 100644 samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css create mode 100644 samples/winrt/ImageManipulations/description/iframedescription.css create mode 100644 samples/winrt/ImageManipulations/description/offline.js create mode 100644 samples/winrt/ImageManipulations/license.rtf diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml new file mode 100644 index 0000000..4e6ebfd --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp new file mode 100644 index 0000000..dc59acc --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.cpp @@ -0,0 +1,1034 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AdvancedCapture.xaml.cpp +// Implementation of the AdvancedCapture class +// + +#include "pch.h" +#include "AdvancedCapture.xaml.h" + +using namespace SDKSample::MediaCapture; + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Storage; +using namespace Windows::Media::MediaProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::System; +using namespace Windows::UI::Xaml::Media::Imaging; +using namespace Windows::Devices::Enumeration; + +ref class ReencodeState sealed +{ +public: + ReencodeState() + { + } + + virtual ~ReencodeState() + { + if (InputStream != nullptr) + { + delete InputStream; + } + if (OutputStream != nullptr) + { + delete OutputStream; + } + } + +internal: + Windows::Storage::Streams::IRandomAccessStream ^InputStream; + Windows::Storage::Streams::IRandomAccessStream ^OutputStream; + Windows::Storage::StorageFile ^PhotoStorage; + Windows::Graphics::Imaging::BitmapDecoder ^Decoder; + Windows::Graphics::Imaging::BitmapEncoder ^Encoder; +}; + +AdvancedCapture::AdvancedCapture() +{ + InitializeComponent(); + ScenarioInit(); +} + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property is typically used to configure the page. +void AdvancedCapture::OnNavigatedTo(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + rootPage = MainPage::Current; + m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &AdvancedCapture::SoundLevelChanged); + + m_orientationChangedEventToken = Windows::Graphics::Display::DisplayProperties::OrientationChanged += ref new Windows::Graphics::Display::DisplayPropertiesEventHandler(this, &AdvancedCapture::DisplayProperties_OrientationChanged); +} + +void AdvancedCapture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; + Windows::Graphics::Display::DisplayProperties::OrientationChanged -= m_orientationChangedEventToken; +} + +void AdvancedCapture::ScenarioInit() +{ + rootPage = MainPage::Current; + btnStartDevice2->IsEnabled = true; + btnStartPreview2->IsEnabled = false; + btnStartStopRecord2->IsEnabled = false; + m_bRecording = false; + m_bPreviewing = false; + m_bEffectAdded = false; + btnStartStopRecord2->Content = "StartRecord"; + btnTakePhoto2->IsEnabled = false; + previewElement2->Source = nullptr; + playbackElement2->Source = nullptr; + imageElement2->Source= nullptr; + ShowStatusMessage(""); + chkAddRemoveEffect->IsChecked = false; + chkAddRemoveEffect->IsEnabled = false; + previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + EnumerateWebcamsAsync(); + m_bSuspended = false; +} + +void AdvancedCapture::ScenarioReset() +{ + previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + ScenarioInit(); +} + +void AdvancedCapture::SoundLevelChanged(Object^ sender, Object^ e) +{ + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) + { + ScenarioReset(); + } + else + { + if (m_bRecording) + { + ShowStatusMessage("Stopping Record on invisibility"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + if (m_bPreviewing) + { + ShowStatusMessage("Stopping Preview on invisibility"); + + create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = false; + + }catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + } + }))); +} + +void AdvancedCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) +{ + try + { + if (m_bRecording) + { + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + try + { + ShowStatusMessage("Stopping Record on exceeding max record duration"); + EnableButton(false, "StartStopRecord"); + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }))); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) +{ + String ^message = "Fatal error" + currentFailure->Message; + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + ref new Windows::UI::Core::DispatchedHandler([this, message]() + { + ShowStatusMessage(message); + }))); +} + +void AdvancedCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + EnableButton(false, "StartDevice"); + ShowStatusMessage("Starting device"); + auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); + m_mediaCaptureMgr = mediaCapture; + auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); + auto chosenDevInfo = m_devInfoCollection->GetAt(EnumedDeviceList2->SelectedIndex); + settings->VideoDeviceId = chosenDevInfo->Id; + if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Back) + { + m_bRotateVideoOnOrientationChange = true; + m_bReversePreviewRotation = false; + } + else if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Front) + { + m_bRotateVideoOnOrientationChange = true; + m_bReversePreviewRotation = true; + } + else + { + m_bRotateVideoOnOrientationChange = false; + } + + create_task(mediaCapture->InitializeAsync(settings)).then([this](task initTask) + { + try + { + initTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + + DisplayProperties_OrientationChanged(nullptr); + + EnableButton(true, "StartPreview"); + EnableButton(true, "StartStopRecord"); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Device initialized successful"); + chkAddRemoveEffect->IsEnabled = true; + mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &AdvancedCapture::RecordLimitationExceeded); + mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AdvancedCapture::Failed); + } + catch (Exception ^ e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + m_bPreviewing = false; + try + { + ShowStatusMessage("Starting preview"); + EnableButton(false, "StartPreview"); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Visible; + previewElement2->Source = mediaCapture; + create_task(mediaCapture->StartPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = true; + ShowStatusMessage("Start preview successful"); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + m_bPreviewing = false; + previewElement2->Source = nullptr; + EnableButton(true, "StartPreview"); + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + ShowStatusMessage("Taking photo"); + EnableButton(false, "TakePhoto"); + auto currentRotation = GetCurrentPhotoRotation(); + + task(KnownFolders::PicturesLibrary->CreateFileAsync(TEMP_PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this, currentRotation](task getFileTask) + { + try + { + auto tempPhotoStorageFile = getFileTask.get(); + ShowStatusMessage("Create photo file successful"); + ImageEncodingProperties^ imageProperties = ImageEncodingProperties::CreateJpeg(); + + create_task(m_mediaCaptureMgr->CapturePhotoToStorageFileAsync(imageProperties, tempPhotoStorageFile)).then([this,tempPhotoStorageFile,currentRotation](task photoTask) + { + try + { + photoTask.get(); + + ReencodePhotoAsync(tempPhotoStorageFile, currentRotation).then([this] (task reencodeImageTask) + { + try + { + auto photoStorageFile = reencodeImageTask.get(); + + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Photo taken"); + + task(photoStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task getStreamTask) + { + try + { + auto photoStream = getStreamTask.get(); + ShowStatusMessage("File open successful"); + auto bmpimg = ref new BitmapImage(); + + bmpimg->SetSource(photoStream); + imageElement2->Source = bmpimg; + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception ^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception ^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } +} + +void AdvancedCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + String ^fileName; + EnableButton(false, "StartStopRecord"); + + if (!m_bRecording) + { + ShowStatusMessage("Starting Record"); + + fileName = VIDEO_FILE_NAME; + + PrepareForVideoRecording(); + + task(KnownFolders::VideosLibrary->CreateFileAsync(fileName, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task fileTask) + { + try + { + this->m_recordStorageFile = fileTask.get(); + ShowStatusMessage("Create record file successful"); + + MediaEncodingProfile^ recordProfile= nullptr; + recordProfile = MediaEncodingProfile::CreateMp4(Windows::Media::MediaProperties::VideoEncodingQuality::Auto); + + create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + + ShowStatusMessage("Start Record successful"); + } + catch (Exception ^e) + { + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }); + } + else + { + ShowStatusMessage("Stopping Record"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + + ShowStatusMessage("Stop record successful"); + if (!m_bSuspended) + { + task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) + { + try + { + auto stream = streamTask.get(); + ShowStatusMessage("Record file opened"); + ShowStatusMessage(this->m_recordStorageFile->Path); + playbackElement2->AutoPlay = true; + playbackElement2->SetSource(stream, this->m_recordStorageFile->FileType); + playbackElement2->Play(); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + } + }); + } + } + catch (Exception ^e) + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + ShowExceptionMessage(e); + } + }); + } + } + catch (Platform::Exception^ e) + { + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + } +} +void AdvancedCapture::lstEnumedDevices_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e) +{ + if ( m_bPreviewing ) + { + create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = false; + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + + btnStartDevice2->IsEnabled = true; + btnStartPreview2->IsEnabled = false; + btnStartStopRecord2->IsEnabled = false; + m_bRecording = false; + btnStartStopRecord2->Content = "StartRecord"; + btnTakePhoto2->IsEnabled = false; + previewElement2->Source = nullptr; + playbackElement2->Source = nullptr; + imageElement2->Source= nullptr; + chkAddRemoveEffect->IsEnabled = false; + chkAddRemoveEffect->IsChecked = false; + m_bEffectAdded = false; + m_bEffectAddedToRecord = false; + m_bEffectAddedToPhoto = false; + ShowStatusMessage(""); +} + +void AdvancedCapture::EnumerateWebcamsAsync() +{ + try + { + ShowStatusMessage("Enumerating Webcams..."); + m_devInfoCollection = nullptr; + + EnumedDeviceList2->Items->Clear(); + + task(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture)).then([this](task findTask) + { + try + { + m_devInfoCollection = findTask.get(); + if (m_devInfoCollection == nullptr || m_devInfoCollection->Size == 0) + { + ShowStatusMessage("No WebCams found."); + } + else + { + for(unsigned int i = 0; i < m_devInfoCollection->Size; i++) + { + auto devInfo = m_devInfoCollection->GetAt(i); + EnumedDeviceList2->Items->Append(devInfo->Name); + } + EnumedDeviceList2->SelectedIndex = 0; + ShowStatusMessage("Enumerating Webcams completed successfully."); + btnStartDevice2->IsEnabled = true; + } + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void AdvancedCapture::AddEffectToImageStream() +{ + auto mediaCapture = m_mediaCaptureMgr.Get(); + Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; + + if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewPhotoStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::RecordPhotoStreamsIdentical)) + { + Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); + if(props->Type->Equals("Image")) + { + //Switch to a video media type instead since we cant add an effect to a image media type + Windows::Foundation::Collections::IVectorView^ supportedPropsList = mediaCapture->VideoDeviceController->GetAvailableMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); + { + unsigned int i = 0; + while (i< supportedPropsList->Size) + { + Windows::Media::MediaProperties::IMediaEncodingProperties^ props = supportedPropsList->GetAt(i); + + String^ s = props->Type; + if(props->Type->Equals("Video")) + { + task(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(Windows::Media::Capture::MediaStreamType::Photo,props)).then([this](task changeTypeTask) + { + try + { + changeTypeTask.get(); + ShowStatusMessage("Change type on photo stream successful"); + //Now add the effect on the image pin + task(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask3) + { + try + { + effectTask3.get(); + m_bEffectAddedToPhoto = true; + ShowStatusMessage("Adding effect to photo stream successful"); + chkAddRemoveEffect->IsEnabled = true; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + + } + + }); + break; + + } + i++; + } + } + } + else + { + //Add the effect to the image pin if the type is already "Video" + task(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask3) + { + try + { + effectTask3.get(); + m_bEffectAddedToPhoto = true; + ShowStatusMessage("Adding effect to photo stream successful"); + chkAddRemoveEffect->IsEnabled = true; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + } + } +} + + + +void AdvancedCapture::chkAddRemoveEffect_Checked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + chkAddRemoveEffect->IsEnabled = false; + m_bEffectAdded = true; + create_task(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoPreview,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask) + { + try + { + effectTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; + + ShowStatusMessage("Add effect successful to preview stream successful"); + if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && + (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewRecordStreamsIdentical)) + { + Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::VideoRecord); + Windows::Media::MediaProperties::VideoEncodingProperties ^videoEncodingProperties = static_cast(props); + if(!videoEncodingProperties->Subtype->Equals("H264")) //Cant add an effect to an H264 stream + { + task(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoRecord,"GrayscaleTransform.GrayscaleEffect", nullptr)).then([this](task effectTask2) + { + try + { + effectTask2.get(); + ShowStatusMessage("Add effect successful to record stream successful"); + m_bEffectAddedToRecord = true; + AddEffectToImageStream(); + chkAddRemoveEffect->IsEnabled = true; + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + } + else + { + AddEffectToImageStream(); + chkAddRemoveEffect->IsEnabled = true; + } + + } + else + { + AddEffectToImageStream(); + chkAddRemoveEffect->IsEnabled = true; + } + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } + }); + } + catch (Platform::Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = false; + } +} + +void AdvancedCapture::chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + chkAddRemoveEffect->IsEnabled = false; + m_bEffectAdded = false; + create_task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::VideoPreview)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from video preview stream successful"); + if(m_bEffectAddedToRecord) + { + task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::VideoRecord)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from video record stream successful"); + m_bEffectAddedToRecord = false; + if(m_bEffectAddedToPhoto) + { + task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::Photo)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from Photo stream successful"); + m_bEffectAddedToPhoto = false; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + + }); + } + else + { + } + chkAddRemoveEffect->IsEnabled = true; + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + + } + + }); + + } + else if(m_bEffectAddedToPhoto) + { + task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::Photo)).then([this](task effectTask) + { + try + { + effectTask.get(); + ShowStatusMessage("Remove effect from Photo stream successful"); + m_bEffectAddedToPhoto = false; + + } + catch(Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + + }); + } + else + { + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } + }); + } + catch (Platform::Exception ^e) + { + ShowExceptionMessage(e); + chkAddRemoveEffect->IsEnabled = true; + chkAddRemoveEffect->IsChecked = true; + } +} + +void AdvancedCapture::ShowStatusMessage(Platform::String^ text) +{ + rootPage->NotifyUser(text, NotifyType::StatusMessage); +} + +void AdvancedCapture::ShowExceptionMessage(Platform::Exception^ ex) +{ + rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); +} + +void AdvancedCapture::SwitchRecordButtonContent() +{ + if (m_bRecording) + { + btnStartStopRecord2->Content="StopRecord"; + } + else + { + btnStartStopRecord2->Content="StartRecord"; + } +} + +void AdvancedCapture::EnableButton(bool enabled, String^ name) +{ + if (name->Equals("StartDevice")) + { + btnStartDevice2->IsEnabled = enabled; + } + else if (name->Equals("StartPreview")) + { + btnStartPreview2->IsEnabled = enabled; + } + else if (name->Equals("StartStopRecord")) + { + btnStartStopRecord2->IsEnabled = enabled; + } + else if (name->Equals("TakePhoto")) + { + btnTakePhoto2->IsEnabled = enabled; + } +} + +task AdvancedCapture::ReencodePhotoAsync( + Windows::Storage::StorageFile ^tempStorageFile, + Windows::Storage::FileProperties::PhotoOrientation photoRotation) +{ + ReencodeState ^state = ref new ReencodeState(); + + return create_task(tempStorageFile->OpenAsync(Windows::Storage::FileAccessMode::Read)).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) + { + state->InputStream = stream; + return Windows::Graphics::Imaging::BitmapDecoder::CreateAsync(state->InputStream); + }).then([state](Windows::Graphics::Imaging::BitmapDecoder ^decoder) + { + state->Decoder = decoder; + return Windows::Storage::KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName); + }).then([state](Windows::Storage::StorageFile ^storageFile) + { + state->PhotoStorage = storageFile; + return state->PhotoStorage->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite); + }).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) + { + state->OutputStream = stream; + state->OutputStream->Size = 0; + return Windows::Graphics::Imaging::BitmapEncoder::CreateForTranscodingAsync(state->OutputStream, state->Decoder); + }).then([state, photoRotation](Windows::Graphics::Imaging::BitmapEncoder ^encoder) + { + state->Encoder = encoder; + auto properties = ref new Windows::Graphics::Imaging::BitmapPropertySet(); + properties->Insert("System.Photo.Orientation", + ref new Windows::Graphics::Imaging::BitmapTypedValue((unsigned short)photoRotation, Windows::Foundation::PropertyType::UInt16)); + return create_task(state->Encoder->BitmapProperties->SetPropertiesAsync(properties)); + }).then([state]() + { + return state->Encoder->FlushAsync(); + }).then([tempStorageFile, state](task previousTask) + { + auto result = state->PhotoStorage; + delete state; + + tempStorageFile->DeleteAsync(Windows::Storage::StorageDeleteOption::PermanentDelete); + + previousTask.get(); + + return result; + }); +} + +Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::GetCurrentPhotoRotation() +{ + bool counterclockwiseRotation = m_bReversePreviewRotation; + + if (m_bRotateVideoOnOrientationChange) + { + return PhotoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation); + } + else + { + return Windows::Storage::FileProperties::PhotoOrientation::Normal; + } +} + +void AdvancedCapture::PrepareForVideoRecording() +{ + Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); + if (mediaCapture == nullptr) + { + return; + } + + bool counterclockwiseRotation = m_bReversePreviewRotation; + + if (m_bRotateVideoOnOrientationChange) + { + mediaCapture->SetRecordRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); + } + else + { + mediaCapture->SetRecordRotation(Windows::Media::Capture::VideoRotation::None); + } +} + +void AdvancedCapture::DisplayProperties_OrientationChanged(Platform::Object^ sender) +{ + Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); + if (mediaCapture == nullptr) + { + return; + } + + bool previewMirroring = mediaCapture->GetPreviewMirroring(); + bool counterclockwiseRotation = (previewMirroring && !m_bReversePreviewRotation) || + (!previewMirroring && m_bReversePreviewRotation); + + if (m_bRotateVideoOnOrientationChange) + { + mediaCapture->SetPreviewRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); + } + else + { + mediaCapture->SetPreviewRotation(Windows::Media::Capture::VideoRotation::None); + } +} + +Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::PhotoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) +{ + switch (displayOrientation) + { + case Windows::Graphics::Display::DisplayOrientations::Landscape: + return Windows::Storage::FileProperties::PhotoOrientation::Normal; + + case Windows::Graphics::Display::DisplayOrientations::Portrait: + return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate270: + Windows::Storage::FileProperties::PhotoOrientation::Rotate90; + + case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: + return Windows::Storage::FileProperties::PhotoOrientation::Rotate180; + + case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: + return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate90 : + Windows::Storage::FileProperties::PhotoOrientation::Rotate270; + + default: + return Windows::Storage::FileProperties::PhotoOrientation::Unspecified; + } +} + +Windows::Media::Capture::VideoRotation AdvancedCapture::VideoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) +{ + switch (displayOrientation) + { + case Windows::Graphics::Display::DisplayOrientations::Landscape: + return Windows::Media::Capture::VideoRotation::None; + + case Windows::Graphics::Display::DisplayOrientations::Portrait: + return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise270Degrees : + Windows::Media::Capture::VideoRotation::Clockwise90Degrees; + + case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: + return Windows::Media::Capture::VideoRotation::Clockwise180Degrees; + + case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: + return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise90Degrees: + Windows::Media::Capture::VideoRotation::Clockwise270Degrees ; + + default: + return Windows::Media::Capture::VideoRotation::None; + } +} + diff --git a/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h new file mode 100644 index 0000000..83556b9 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AdvancedCapture.xaml.h @@ -0,0 +1,103 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AdvancedCapture.xaml.h +// Declaration of the AdvancedCapture class +// + +#pragma once + +#include "pch.h" +#include "AdvancedCapture.g.h" +#include "MainPage.xaml.h" +#include + +#define VIDEO_FILE_NAME "video.mp4" +#define PHOTO_FILE_NAME "photo.jpg" +#define TEMP_PHOTO_FILE_NAME "photoTmp.jpg" + +using namespace concurrency; +using namespace Windows::Devices::Enumeration; + +namespace SDKSample +{ + namespace MediaCapture + { + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class AdvancedCapture sealed + { + public: + AdvancedCapture(); + + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + + private: + MainPage^ rootPage; + void ScenarioInit(); + void ScenarioReset(); + + void SoundLevelChanged(Object^ sender, Object^ e); + void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); + void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); + + void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void lstEnumedDevices_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e); + void EnumerateWebcamsAsync(); + + void chkAddRemoveEffect_Checked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void chkAddRemoveEffect_Unchecked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void AddEffectToImageStream(); + + void ShowStatusMessage(Platform::String^ text); + void ShowExceptionMessage(Platform::Exception^ ex); + + void EnableButton(bool enabled, Platform::String ^name); + void SwitchRecordButtonContent(); + + task ReencodePhotoAsync( + Windows::Storage::StorageFile ^tempStorageFile, + Windows::Storage::FileProperties::PhotoOrientation photoRotation); + Windows::Storage::FileProperties::PhotoOrientation GetCurrentPhotoRotation(); + void PrepareForVideoRecording(); + void DisplayProperties_OrientationChanged(Platform::Object^ sender); + Windows::Storage::FileProperties::PhotoOrientation PhotoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise); + Windows::Media::Capture::VideoRotation VideoRotationLookup( + Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise); + + Platform::Agile m_mediaCaptureMgr; + Windows::Storage::StorageFile^ m_recordStorageFile; + bool m_bRecording; + bool m_bEffectAdded; + bool m_bEffectAddedToRecord; + bool m_bEffectAddedToPhoto; + bool m_bSuspended; + bool m_bPreviewing; + DeviceInformationCollection^ m_devInfoCollection; + Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; + bool m_bRotateVideoOnOrientationChange; + bool m_bReversePreviewRotation; + Windows::Foundation::EventRegistrationToken m_orientationChangedEventToken; + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/App.xaml b/samples/winrt/ImageManipulations/C++/App.xaml new file mode 100644 index 0000000..2edfd77 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/App.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/App.xaml.cpp b/samples/winrt/ImageManipulations/C++/App.xaml.cpp new file mode 100644 index 0000000..ef733a1 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/App.xaml.cpp @@ -0,0 +1,114 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// App.xaml.cpp +// Implementation of the App.xaml class. +// + +#include "pch.h" +#include "MainPage.xaml.h" +#include "Common\SuspensionManager.h" + +using namespace SDKSample; +using namespace SDKSample::Common; + +using namespace Concurrency; +using namespace Platform; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + this->Suspending += ref new SuspendingEventHandler(this, &SDKSample::App::OnSuspending); +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points will +/// be used when the application is launched to open a specific file, to display search results, +/// and so forth. +/// +/// Details about the launch request and process. +void App::OnLaunched(LaunchActivatedEventArgs^ pArgs) +{ + this->LaunchArgs = pArgs; + + // Do not repeat app initialization when already running, just ensure that + // the window is active + if (pArgs->PreviousExecutionState == ApplicationExecutionState::Running) + { + Window::Current->Activate(); + return; + } + + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + auto rootFrame = ref new Frame(); + SuspensionManager::RegisterFrame(rootFrame, "AppFrame"); + + auto prerequisite = task([](){}); + if (pArgs->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + prerequisite = SuspensionManager::RestoreAsync(); + } + prerequisite.then([=]() + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + if (rootFrame->Content == nullptr) + { + if (!rootFrame->Navigate(TypeName(MainPage::typeid))) + { + throw ref new FailureException("Failed to create initial page"); + } + } + + // Place the frame in the current Window and ensure that it is active + Window::Current->Content = rootFrame; + Window::Current->Activate(); + }, task_continuation_context::use_current()); +} + +/// +/// Invoked when application execution is being suspended. Application state is saved +/// without knowing whether the application will be terminated or resumed with the contents +/// of memory still intact. +/// +/// The source of the suspend request. +/// Details about the suspend request. +void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +{ + (void) sender; // Unused parameter + + auto deferral = e->SuspendingOperation->GetDeferral(); + SuspensionManager::SaveAsync().then([=]() + { + deferral->Complete(); + }); +} diff --git a/samples/winrt/ImageManipulations/C++/App.xaml.h b/samples/winrt/ImageManipulations/C++/App.xaml.h new file mode 100644 index 0000000..a8b6064 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/App.xaml.h @@ -0,0 +1,35 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// App.xaml.h +// Declaration of the App.xaml class. +// + +#pragma once + +#include "pch.h" +#include "App.g.h" +#include "MainPage.g.h" + +namespace SDKSample +{ + ref class App + { + internal: + App(); + virtual void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ pArgs); + Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ LaunchArgs; + protected: + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ pArgs) override; + private: + Windows::UI::Xaml::Controls::Frame^ rootFrame; + }; +} diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml new file mode 100644 index 0000000..be65bcd --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + This scenario shows how to do an audio only capture using the default microphone. Click on StartRecord to start recording. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp new file mode 100644 index 0000000..37fc379 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.cpp @@ -0,0 +1,366 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AudioCapture.xaml.cpp +// Implementation of the AudioCapture class +// + +#include "pch.h" +#include "AudioCapture.xaml.h" +#include +using namespace concurrency; + +using namespace SDKSample::MediaCapture; + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Storage; +using namespace Windows::Media::MediaProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::System; +using namespace Windows::UI::Xaml::Media::Imaging; + + +AudioCapture::AudioCapture() +{ + InitializeComponent(); + ScenarioInit(); +} + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property is typically used to configure the page. +void AudioCapture::OnNavigatedTo(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + rootPage = MainPage::Current; + m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &AudioCapture::SoundLevelChanged); +} + +void AudioCapture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; +} + +void AudioCapture::ScenarioInit() +{ + try + { + rootPage = MainPage::Current; + btnStartDevice3->IsEnabled = true; + btnStartStopRecord3->IsEnabled = false; + m_bRecording = false; + playbackElement3->Source = nullptr; + m_bSuspended = false; + ShowStatusMessage(""); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + +} + +void AudioCapture::ScenarioReset() +{ + ScenarioInit(); +} + + +void AudioCapture::SoundLevelChanged(Object^ sender, Object^ e) +{ + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) + { + ScenarioReset(); + } + else + { + if (m_bRecording) + { + ShowStatusMessage("Stopping Record on invisibility"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + }catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + } + }))); +} + +void AudioCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) +{ + try + { + if (m_bRecording) + { + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this](){ + try + { + ShowStatusMessage("Stopping Record on exceeding max record duration"); + EnableButton(false, "StartStopRecord"); + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + + }))); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } +} + +void AudioCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) +{ + String ^message = "Fatal error: " + currentFailure->Message; + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + ref new Windows::UI::Core::DispatchedHandler([this, message]() + { + ShowStatusMessage(message); + }))); +} + +void AudioCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + EnableButton(false, "StartDevice"); + ShowStatusMessage("Starting device"); + auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); + m_mediaCaptureMgr = mediaCapture; + auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); + settings->StreamingCaptureMode = Windows::Media::Capture::StreamingCaptureMode::Audio; + create_task(mediaCapture->InitializeAsync()).then([this](task initTask) + { + try + { + initTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + EnableButton(true, "StartPreview"); + EnableButton(true, "StartStopRecord"); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Device initialized successful"); + mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &AudioCapture::RecordLimitationExceeded); + mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AudioCapture::Failed); + } + catch (Exception ^ e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void AudioCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + String ^fileName; + EnableButton(false, "StartStopRecord"); + + if (!m_bRecording) + { + ShowStatusMessage("Starting Record"); + + fileName = AUDIO_FILE_NAME; + + task(KnownFolders::VideosLibrary->CreateFileAsync(fileName, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task fileTask) + { + try + { + this->m_recordStorageFile = fileTask.get(); + ShowStatusMessage("Create record file successful"); + + MediaEncodingProfile^ recordProfile= nullptr; + recordProfile = MediaEncodingProfile::CreateM4a(Windows::Media::MediaProperties::AudioEncodingQuality::Auto); + + create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + + ShowStatusMessage("Start Record successful"); + + + }catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + } + ); + } + else + { + ShowStatusMessage("Stopping Record"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task) + { + try + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + + ShowStatusMessage("Stop record successful"); + if (!m_bSuspended) + { + task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) + { + try + { + ShowStatusMessage("Record file opened"); + auto stream = streamTask.get(); + ShowStatusMessage(this->m_recordStorageFile->Path); + playbackElement3->AutoPlay = true; + playbackElement3->SetSource(stream, this->m_recordStorageFile->FileType); + playbackElement3->Play(); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + }); + } + } + catch (Platform::Exception^ e) + { + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + } +} + + +void AudioCapture::ShowStatusMessage(Platform::String^ text) +{ + rootPage->NotifyUser(text, NotifyType::StatusMessage); +} + +void AudioCapture::ShowExceptionMessage(Platform::Exception^ ex) +{ + rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); +} + +void AudioCapture::SwitchRecordButtonContent() +{ + { + if (m_bRecording) + { + btnStartStopRecord3->Content="StopRecord"; + } + else + { + btnStartStopRecord3->Content="StartRecord"; + } + } +} +void AudioCapture::EnableButton(bool enabled, String^ name) +{ + if (name->Equals("StartDevice")) + { + btnStartDevice3->IsEnabled = enabled; + } + + else if (name->Equals("StartStopRecord")) + { + btnStartStopRecord3->IsEnabled = enabled; + } + +} + diff --git a/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h new file mode 100644 index 0000000..b75efdc --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/AudioCapture.xaml.h @@ -0,0 +1,70 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// AudioCapture.xaml.h +// Declaration of the AudioCapture class +// + +#pragma once + +#include "pch.h" +#include "AudioCapture.g.h" +#include "MainPage.xaml.h" + +#define AUDIO_FILE_NAME "audio.mp4" + +namespace SDKSample +{ + namespace MediaCapture + { + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class AudioCapture sealed + { + public: + AudioCapture(); + + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + private: + MainPage^ rootPage; + + void ScenarioInit(); + void ScenarioReset(); + + void SoundLevelChanged(Object^ sender, Object^ e); + void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); + void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); + + void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void ShowStatusMessage(Platform::String^ text); + void ShowExceptionMessage(Platform::Exception^ ex); + + void EnableButton(bool enabled, Platform::String ^name); + void SwitchRecordButtonContent(); + + Platform::Agile m_mediaCaptureMgr; + Windows::Storage::StorageFile^ m_photoStorageFile; + Windows::Storage::StorageFile^ m_recordStorageFile; + bool m_bRecording; + bool m_bSuspended; + Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml new file mode 100644 index 0000000..2cc0b0a --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + This scenario demonstrates how to use the MediaCapture API to preview the camera stream, record a video, and take a picture using default initialization settings. + You can also adjust the brightness and contrast. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp new file mode 100644 index 0000000..f385fa9 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.cpp @@ -0,0 +1,535 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// BasicCapture.xaml.cpp +// Implementation of the BasicCapture class +// + +#include "pch.h" +#include "BasicCapture.xaml.h" +#include "ppl.h" + +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Storage; +using namespace Windows::Media::MediaProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::System; +using namespace Windows::UI::Xaml::Media::Imaging; + +using namespace SDKSample::MediaCapture; +using namespace concurrency; + + +BasicCapture::BasicCapture() +{ + InitializeComponent(); + ScenarioInit(); +} + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property is typically used to configure the page. +void BasicCapture::OnNavigatedTo(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + rootPage = MainPage::Current; + m_eventRegistrationToken = Windows::Media::MediaControl::SoundLevelChanged += ref new EventHandler(this, &BasicCapture::SoundLevelChanged); +} + +void BasicCapture::OnNavigatedFrom(NavigationEventArgs^ e) +{ + // A pointer back to the main page. This is needed if you want to call methods in MainPage such + // as NotifyUser() + + Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; + m_currentScenarioLoaded = false; +} + + +void BasicCapture::ScenarioInit() +{ + try + { + btnStartDevice1->IsEnabled = true; + btnStartPreview1->IsEnabled = false; + btnStartStopRecord1->IsEnabled = false; + m_bRecording = false; + m_bPreviewing = false; + btnStartStopRecord1->Content = "StartRecord"; + btnTakePhoto1->IsEnabled = false; + previewElement1->Source = nullptr; + playbackElement1->Source = nullptr; + imageElement1->Source= nullptr; + sldBrightness->IsEnabled = false; + sldContrast->IsEnabled = false; + m_bSuspended = false; + previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + +} + +void BasicCapture::ScenarioReset() +{ + previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + ScenarioInit(); +} + +void BasicCapture::SoundLevelChanged(Object^ sender, Object^ e) +{ + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this]() + { + if(Windows::Media::MediaControl::SoundLevel != Windows::Media::SoundLevel::Muted) + { + ScenarioReset(); + } + else + { + if (m_bRecording) + { + ShowStatusMessage("Stopping Record on invisibility"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + m_bRecording = false; + }); + } + if (m_bPreviewing) + { + ShowStatusMessage("Stopping Preview on invisibility"); + + create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + m_bPreviewing = false; + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + } + }))); +} + +void BasicCapture::RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^currentCaptureObject) +{ + try + { + if (m_bRecording) + { + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([this](){ + try + { + ShowStatusMessage("Stopping Record on exceeding max record duration"); + EnableButton(false, "StartStopRecord"); + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowStatusMessage("Stopped record on exceeding max record duration:" + m_recordStorageFile->Path); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + } + }); + + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + + }))); + } + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } +} + +void BasicCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) +{ + String ^message = "Fatal error: " + currentFailure->Message; + create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, + ref new Windows::UI::Core::DispatchedHandler([this, message]() + { + ShowStatusMessage(message); + }))); +} + +void BasicCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + EnableButton(false, "StartDevice"); + ShowStatusMessage("Starting device"); + auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); + m_mediaCaptureMgr = mediaCapture; + create_task(mediaCapture->InitializeAsync()).then([this](task initTask) + { + try + { + initTask.get(); + + auto mediaCapture = m_mediaCaptureMgr.Get(); + EnableButton(true, "StartPreview"); + EnableButton(true, "StartStopRecord"); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Device initialized successful"); + mediaCapture->RecordLimitationExceeded += ref new Windows::Media::Capture::RecordLimitationExceededEventHandler(this, &BasicCapture::RecordLimitationExceeded); + mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &BasicCapture::Failed); + } + catch (Exception ^ e) + { + ShowExceptionMessage(e); + } + } + ); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +void BasicCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + m_bPreviewing = false; + try + { + ShowStatusMessage("Starting preview"); + EnableButton(false, "StartPreview"); + auto mediaCapture = m_mediaCaptureMgr.Get(); + + previewCanvas1->Visibility = Windows::UI::Xaml::Visibility::Visible; + previewElement1->Source = mediaCapture; + create_task(mediaCapture->StartPreviewAsync()).then([this](task previewTask) + { + try + { + previewTask.get(); + auto mediaCapture = m_mediaCaptureMgr.Get(); + m_bPreviewing = true; + ShowStatusMessage("Start preview successful"); + if(mediaCapture->VideoDeviceController->Brightness) + { + SetupVideoDeviceControl(mediaCapture->VideoDeviceController->Brightness, sldBrightness); + } + if(mediaCapture->VideoDeviceController->Contrast) + { + SetupVideoDeviceControl(mediaCapture->VideoDeviceController->Contrast, sldContrast); + } + + }catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Platform::Exception^ e) + { + m_bPreviewing = false; + previewElement1->Source = nullptr; + EnableButton(true, "StartPreview"); + ShowExceptionMessage(e); + } +} + +void BasicCapture::btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + ShowStatusMessage("Taking photo"); + EnableButton(false, "TakePhoto"); + + task(KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName)).then([this](task getFileTask) + { + try + { + this->m_photoStorageFile = getFileTask.get(); + ShowStatusMessage("Create photo file successful"); + ImageEncodingProperties^ imageProperties = ImageEncodingProperties::CreateJpeg(); + + create_task(m_mediaCaptureMgr->CapturePhotoToStorageFileAsync(imageProperties, this->m_photoStorageFile)).then([this](task photoTask) + { + try + { + photoTask.get(); + EnableButton(true, "TakePhoto"); + ShowStatusMessage("Photo taken"); + + task(this->m_photoStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task getStreamTask) + { + try + { + auto photoStream = getStreamTask.get(); + ShowStatusMessage("File open successful"); + auto bmpimg = ref new BitmapImage(); + + bmpimg->SetSource(photoStream); + imageElement1->Source = bmpimg; + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception ^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } + }); + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + EnableButton(true, "TakePhoto"); + } +} + +void BasicCapture::btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + try + { + String ^fileName; + EnableButton(false, "StartStopRecord"); + + if (!m_bRecording) + { + ShowStatusMessage("Starting Record"); + + fileName = VIDEO_FILE_NAME; + + task(KnownFolders::VideosLibrary->CreateFileAsync(fileName,Windows::Storage::CreationCollisionOption::GenerateUniqueName )).then([this](task fileTask) + { + try + { + this->m_recordStorageFile = fileTask.get(); + ShowStatusMessage("Create record file successful"); + + MediaEncodingProfile^ recordProfile= nullptr; + recordProfile = MediaEncodingProfile::CreateMp4(Windows::Media::MediaProperties::VideoEncodingQuality::Auto); + + create_task(m_mediaCaptureMgr->StartRecordToStorageFileAsync(recordProfile, this->m_recordStorageFile)).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = true; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + + ShowStatusMessage("Start Record successful"); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + } + }); + } + catch (Exception ^e) + { + m_bRecording = false; + SwitchRecordButtonContent(); + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + } + } + ); + } + else + { + ShowStatusMessage("Stopping Record"); + + create_task(m_mediaCaptureMgr->StopRecordAsync()).then([this](task recordTask) + { + try + { + recordTask.get(); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + + ShowStatusMessage("Stop record successful"); + if (!m_bSuspended) + { + task(this->m_recordStorageFile->OpenAsync(FileAccessMode::Read)).then([this](task streamTask) + { + try + { + auto stream = streamTask.get(); + ShowStatusMessage("Record file opened"); + ShowStatusMessage(this->m_recordStorageFile->Path); + playbackElement1->AutoPlay = true; + playbackElement1->SetSource(stream, this->m_recordStorageFile->FileType); + playbackElement1->Play(); + } + catch (Exception ^e) + { + ShowExceptionMessage(e); + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + } + }); + } + } + catch (Exception ^e) + { + m_bRecording = false; + EnableButton(true, "StartStopRecord"); + SwitchRecordButtonContent(); + ShowExceptionMessage(e); + } + }); + } + } + catch (Platform::Exception^ e) + { + EnableButton(true, "StartStopRecord"); + ShowExceptionMessage(e); + SwitchRecordButtonContent(); + m_bRecording = false; + } +} + +void BasicCapture::SetupVideoDeviceControl(Windows::Media::Devices::MediaDeviceControl^ videoDeviceControl, Slider^ slider) +{ + try + { + if ((videoDeviceControl->Capabilities)->Supported) + { + slider->IsEnabled = true; + slider->Maximum = videoDeviceControl->Capabilities->Max; + slider->Minimum = videoDeviceControl->Capabilities->Min; + slider->StepFrequency = videoDeviceControl->Capabilities->Step; + double controlValue = 0; + if (videoDeviceControl->TryGetValue(&controlValue)) + { + slider->Value = controlValue; + } + } + else + { + slider->IsEnabled = false; + } + } + catch (Platform::Exception^ e) + { + ShowExceptionMessage(e); + } +} + +// VideoDeviceControllers +void BasicCapture::sldBrightness_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e) +{ + bool succeeded = m_mediaCaptureMgr->VideoDeviceController->Brightness->TrySetValue(sldBrightness->Value); + if (!succeeded) + { + ShowStatusMessage("Set Brightness failed"); + } +} + +void BasicCapture::sldContrast_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs ^e) +{ + bool succeeded = m_mediaCaptureMgr->VideoDeviceController->Contrast->TrySetValue(sldContrast->Value); + if (!succeeded) + { + ShowStatusMessage("Set Contrast failed"); + } +} + +void BasicCapture::ShowStatusMessage(Platform::String^ text) +{ + rootPage->NotifyUser(text, NotifyType::StatusMessage); +} + +void BasicCapture::ShowExceptionMessage(Platform::Exception^ ex) +{ + rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); +} + +void BasicCapture::SwitchRecordButtonContent() +{ + if (m_bRecording) + { + btnStartStopRecord1->Content="StopRecord"; + } + else + { + btnStartStopRecord1->Content="StartRecord"; + } +} +void BasicCapture::EnableButton(bool enabled, String^ name) +{ + if (name->Equals("StartDevice")) + { + btnStartDevice1->IsEnabled = enabled; + } + else if (name->Equals("StartPreview")) + { + btnStartPreview1->IsEnabled = enabled; + } + else if (name->Equals("StartStopRecord")) + { + btnStartStopRecord1->IsEnabled = enabled; + } + else if (name->Equals("TakePhoto")) + { + btnTakePhoto1->IsEnabled = enabled; + } +} + diff --git a/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h new file mode 100644 index 0000000..28129ef --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/BasicCapture.xaml.h @@ -0,0 +1,88 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// BasicCapture.xaml.h +// Declaration of the BasicCapture class +// + +#pragma once + +#include "pch.h" +#include "BasicCapture.g.h" +#include "MainPage.xaml.h" + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::Graphics::Display; +using namespace Windows::UI::ViewManagement; +using namespace Windows::Devices::Enumeration; +#define VIDEO_FILE_NAME "video.mp4" +#define PHOTO_FILE_NAME "photo.jpg" +namespace SDKSample +{ + namespace MediaCapture + { + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class BasicCapture sealed + { + public: + BasicCapture(); + + protected: + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + + private: + MainPage^ rootPage; + void ScenarioInit(); + void ScenarioReset(); + + void Suspending(Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); + void Resuming(Object^ sender, Object^ e); + + void btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void SoundLevelChanged(Object^ sender, Object^ e); + void RecordLimitationExceeded(Windows::Media::Capture::MediaCapture ^ mediaCapture); + void Failed(Windows::Media::Capture::MediaCapture ^ mediaCapture, Windows::Media::Capture::MediaCaptureFailedEventArgs ^ args); + + + void btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnStartStopRecord_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void btnTakePhoto_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void SetupVideoDeviceControl(Windows::Media::Devices::MediaDeviceControl^ videoDeviceControl, Slider^ slider); + void sldBrightness_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e); + void sldContrast_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e); + + void ShowStatusMessage(Platform::String^ text); + void ShowExceptionMessage(Platform::Exception^ ex); + + void EnableButton(bool enabled, Platform::String ^name); + void SwitchRecordButtonContent(); + + Platform::Agile m_mediaCaptureMgr; + Windows::Storage::StorageFile^ m_photoStorageFile; + Windows::Storage::StorageFile^ m_recordStorageFile; + bool m_bRecording; + bool m_bEffectAdded; + bool m_bSuspended; + bool m_bPreviewing; + Windows::UI::Xaml::WindowVisibilityChangedEventHandler ^m_visbilityHandler; + Windows::Foundation::EventRegistrationToken m_eventRegistrationToken; + bool m_currentScenarioLoaded; + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/Constants.cpp b/samples/winrt/ImageManipulations/C++/Constants.cpp new file mode 100644 index 0000000..873b983 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/Constants.cpp @@ -0,0 +1,24 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#include "pch.h" +#include "MainPage.xaml.h" +#include "Constants.h" + +using namespace SDKSample; + +Platform::Array^ MainPage::scenariosInner = ref new Platform::Array +{ + // The format here is the following: + // { "Description for the sample", "Fully quaified name for the class that implements the scenario" } + { "Video preview, record and take pictures", "SDKSample.MediaCapture.BasicCapture" }, + { "Enumerate cameras and add a video effect", "SDKSample.MediaCapture.AdvancedCapture" }, + { "Audio Capture", "SDKSample.MediaCapture.AudioCapture" } +}; diff --git a/samples/winrt/ImageManipulations/C++/Constants.h b/samples/winrt/ImageManipulations/C++/Constants.h new file mode 100644 index 0000000..917f664 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/Constants.h @@ -0,0 +1,45 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#pragma once + +#include +namespace SDKSample +{ + public value struct Scenario + { + Platform::String^ Title; + Platform::String^ ClassName; + }; + + partial ref class MainPage + { + public: + static property Platform::String^ FEATURE_NAME + { + Platform::String^ get() + { + return ref new Platform::String(L"MediaCapture CPP sample"); + } + } + + static property Platform::Array^ scenarios + { + Platform::Array^ get() + { + return scenariosInner; + } + } + private: + static Platform::Array^ scenariosInner; + }; + + +} diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml b/samples/winrt/ImageManipulations/C++/MainPage.xaml new file mode 100644 index 0000000..d830e3c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20,20,20,20 + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp b/samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp new file mode 100644 index 0000000..0702781 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml.cpp @@ -0,0 +1,315 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// MainPage.xaml.cpp +// Implementation of the MainPage.xaml class. +// + +#include "pch.h" +#include "MainPage.xaml.h" +#include "App.xaml.h" + +#include + +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Platform; +using namespace SDKSample; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::Graphics::Display; +using namespace Windows::UI::ViewManagement; + +MainPage^ MainPage::Current = nullptr; + +MainPage::MainPage() +{ + InitializeComponent(); + + // This frame is hidden, meaning it is never shown. It is simply used to load + // each scenario page and then pluck out the input and output sections and + // place them into the UserControls on the main page. + HiddenFrame = ref new Windows::UI::Xaml::Controls::Frame(); + HiddenFrame->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + ContentRoot->Children->Append(HiddenFrame); + + FeatureName->Text = FEATURE_NAME; + + this->SizeChanged += ref new SizeChangedEventHandler(this, &MainPage::MainPage_SizeChanged); + Scenarios->SelectionChanged += ref new SelectionChangedEventHandler(this, &MainPage::Scenarios_SelectionChanged); + + MainPage::Current = this; + autoSizeInputSectionWhenSnapped = true; +} + +/// +/// We need to handle SizeChanged so that we can make the sample layout property +/// in the various layouts. +/// +/// +/// +void MainPage::MainPage_SizeChanged(Object^ sender, SizeChangedEventArgs^ e) +{ + InvalidateSize(); + MainPageSizeChangedEventArgs^ args = ref new MainPageSizeChangedEventArgs(); + args->ViewState = ApplicationView::Value; + MainPageResized(this, args); + +} + +void MainPage::InvalidateSize() +{ + // Get the window width + double windowWidth = this->ActualWidth; + + if (windowWidth != 0.0) + { + // Get the width of the ListBox. + double listBoxWidth = Scenarios->ActualWidth; + + // Is the ListBox using any margins that we need to consider? + double listBoxMarginLeft = Scenarios->Margin.Left; + double listBoxMarginRight = Scenarios->Margin.Right; + + // Figure out how much room is left after considering the list box width + double availableWidth = windowWidth - listBoxWidth; + + // Is the top most child using margins? + double layoutRootMarginLeft = ContentRoot->Margin.Left; + double layoutRootMarginRight = ContentRoot->Margin.Right; + + // We have different widths to use depending on the view state + if (ApplicationView::Value != ApplicationViewState::Snapped) + { + // Make us as big as the the left over space, factoring in the ListBox width, the ListBox margins. + // and the LayoutRoot's margins + InputSection->Width = ((availableWidth) - + (layoutRootMarginLeft + layoutRootMarginRight + listBoxMarginLeft + listBoxMarginRight)); + } + else + { + // Make us as big as the left over space, factoring in just the LayoutRoot's margins. + if (autoSizeInputSectionWhenSnapped) + { + InputSection->Width = (windowWidth - (layoutRootMarginLeft + layoutRootMarginRight)); + } + } + } + InvalidateViewState(); +} + +void MainPage::InvalidateViewState() +{ + // Are we going to snapped mode? + if (ApplicationView::Value == ApplicationViewState::Snapped) + { + Grid::SetRow(DescriptionText, 3); + Grid::SetColumn(DescriptionText, 0); + + Grid::SetRow(InputSection, 4); + Grid::SetColumn(InputSection, 0); + + Grid::SetRow(FooterPanel, 2); + Grid::SetColumn(FooterPanel, 0); + } + else + { + Grid::SetRow(DescriptionText, 1); + Grid::SetColumn(DescriptionText, 1); + + Grid::SetRow(InputSection, 2); + Grid::SetColumn(InputSection, 1); + + Grid::SetRow(FooterPanel, 1); + Grid::SetColumn(FooterPanel, 1); + } + + // Since we don't load the scenario page in the traditional manner (we just pluck out the + // input and output sections from the page) we need to ensure that any VSM code used + // by the scenario's input and output sections is fired. + VisualStateManager::GoToState(InputSection, "Input" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false); + VisualStateManager::GoToState(OutputSection, "Output" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false); +} + +void MainPage::PopulateScenarios() +{ + ScenarioList = ref new Platform::Collections::Vector(); + + // Populate the ListBox with the list of scenarios as defined in Constants.cpp. + for (unsigned int i = 0; i < scenarios->Length; ++i) + { + Scenario s = scenarios[i]; + ListBoxItem^ item = ref new ListBoxItem(); + item->Name = s.ClassName; + item->Content = (i + 1).ToString() + ") " + s.Title; + ScenarioList->Append(item); + } + + // Bind the ListBox to the scenario list. + Scenarios->ItemsSource = ScenarioList; + Scenarios->ScrollIntoView(Scenarios->SelectedItem); +} + +/// +/// This method is responsible for loading the individual input and output sections for each scenario. This +/// is based on navigating a hidden Frame to the ScenarioX.xaml page and then extracting out the input +/// and output sections into the respective UserControl on the main page. +/// +/// +void MainPage::LoadScenario(String^ scenarioName) +{ + autoSizeInputSectionWhenSnapped = true; + + // Load the ScenarioX.xaml file into the Frame. + TypeName scenarioType = {scenarioName, TypeKind::Custom}; + HiddenFrame->Navigate(scenarioType, this); + + // Get the top element, the Page, so we can look up the elements + // that represent the input and output sections of the ScenarioX file. + Page^ hiddenPage = safe_cast(HiddenFrame->Content); + + // Get each element. + UIElement^ input = safe_cast(hiddenPage->FindName("Input")); + UIElement^ output = safe_cast(hiddenPage->FindName("Output")); + + if (input == nullptr) + { + // Malformed input section. + NotifyUser("Cannot load scenario input section for " + scenarioName + + " Make sure root of input section markup has x:Name of 'Input'", NotifyType::ErrorMessage); + return; + } + + if (output == nullptr) + { + // Malformed output section. + NotifyUser("Cannot load scenario output section for " + scenarioName + + " Make sure root of output section markup has x:Name of 'Output'", NotifyType::ErrorMessage); + return; + } + + // Find the LayoutRoot which parents the input and output sections in the main page. + Panel^ panel = safe_cast(hiddenPage->FindName("LayoutRoot")); + + if (panel != nullptr) + { + unsigned int index = 0; + UIElementCollection^ collection = panel->Children; + + // Get rid of the content that is currently in the intput and output sections. + collection->IndexOf(input, &index); + collection->RemoveAt(index); + + collection->IndexOf(output, &index); + collection->RemoveAt(index); + + // Populate the input and output sections with the newly loaded content. + InputSection->Content = input; + OutputSection->Content = output; + + ScenarioLoaded(this, nullptr); + } + else + { + // Malformed Scenario file. + NotifyUser("Cannot load scenario: " + scenarioName + ". Make sure root tag in the '" + + scenarioName + "' file has an x:Name of 'LayoutRoot'", NotifyType::ErrorMessage); + } +} + +void MainPage::Scenarios_SelectionChanged(Object^ sender, SelectionChangedEventArgs^ e) +{ + if (Scenarios->SelectedItem != nullptr) + { + NotifyUser("", NotifyType::StatusMessage); + + LoadScenario((safe_cast(Scenarios->SelectedItem))->Name); + InvalidateSize(); + } +} + +void MainPage::NotifyUser(String^ strMessage, NotifyType type) +{ + switch (type) + { + case NotifyType::StatusMessage: + // Use the status message style. + StatusBlock->Style = safe_cast(this->Resources->Lookup("StatusStyle")); + break; + case NotifyType::ErrorMessage: + // Use the error message style. + StatusBlock->Style = safe_cast(this->Resources->Lookup("ErrorStyle")); + break; + default: + break; + } + StatusBlock->Text = strMessage; + + // Collapsed the StatusBlock if it has no text to conserve real estate. + if (StatusBlock->Text != "") + { + StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Visible; + } + else + { + StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + } +} + +void MainPage::Footer_Click(Object^ sender, RoutedEventArgs^ e) +{ + auto uri = ref new Uri((String^)((HyperlinkButton^)sender)->Tag); + Windows::System::Launcher::LaunchUriAsync(uri); +} + + +/// +/// Populates the page with content passed during navigation. Any saved state is also +/// provided when recreating a page from a prior session. +/// +/// The parameter value passed to +/// when this page was initially requested. +/// +/// A map of state preserved by this page during an earlier +/// session. This will be null the first time a page is visited. +void MainPage::LoadState(Object^ navigationParameter, IMap^ pageState) +{ + (void) navigationParameter; // Unused parameter + + PopulateScenarios(); + + // Starting scenario is the first or based upon a previous state. + ListBoxItem^ startingScenario = nullptr; + int startingScenarioIndex = -1; + + if (pageState != nullptr && pageState->HasKey("SelectedScenarioIndex")) + { + startingScenarioIndex = safe_cast(pageState->Lookup("SelectedScenarioIndex")); + } + + Scenarios->SelectedIndex = startingScenarioIndex != -1 ? startingScenarioIndex : 0; + + InvalidateViewState(); +} + +/// +/// Preserves state associated with this page in case the application is suspended or the +/// page is discarded from the navigation cache. Values must conform to the serialization +/// requirements of . +/// +/// An empty map to be populated with serializable state. +void MainPage::SaveState(IMap^ pageState) +{ + int selectedListBoxItemIndex = Scenarios->SelectedIndex; + pageState->Insert("SelectedScenarioIndex", selectedListBoxItemIndex); +} diff --git a/samples/winrt/ImageManipulations/C++/MainPage.xaml.h b/samples/winrt/ImageManipulations/C++/MainPage.xaml.h new file mode 100644 index 0000000..36fb779 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MainPage.xaml.h @@ -0,0 +1,105 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// MainPage.xaml.h +// Declaration of the MainPage.xaml class. +// + +#pragma once + +#include "pch.h" +#include "MainPage.g.h" +#include "Common\LayoutAwarePage.h" // Required by generated header +#include "Constants.h" + +namespace SDKSample +{ + public enum class NotifyType + { + StatusMessage, + ErrorMessage + }; + + public ref class MainPageSizeChangedEventArgs sealed + { + public: + property Windows::UI::ViewManagement::ApplicationViewState ViewState + { + Windows::UI::ViewManagement::ApplicationViewState get() + { + return viewState; + } + + void set(Windows::UI::ViewManagement::ApplicationViewState value) + { + viewState = value; + } + } + + private: + Windows::UI::ViewManagement::ApplicationViewState viewState; + }; + + public ref class MainPage sealed + { + public: + MainPage(); + + protected: + virtual void LoadState(Platform::Object^ navigationParameter, + Windows::Foundation::Collections::IMap^ pageState) override; + virtual void SaveState(Windows::Foundation::Collections::IMap^ pageState) override; + + internal: + property bool AutoSizeInputSectionWhenSnapped + { + bool get() + { + return autoSizeInputSectionWhenSnapped; + } + + void set(bool value) + { + autoSizeInputSectionWhenSnapped = value; + } + } + + property Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ LaunchArgs + { + Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ get() + { + return safe_cast(App::Current)->LaunchArgs; + } + } + + void NotifyUser(Platform::String^ strMessage, NotifyType type); + void LoadScenario(Platform::String^ scenarioName); + event Windows::Foundation::EventHandler^ ScenarioLoaded; + event Windows::Foundation::EventHandler^ MainPageResized; + + private: + void PopulateScenarios(); + void InvalidateSize(); + void InvalidateViewState(); + + Platform::Collections::Vector^ ScenarioList; + Windows::UI::Xaml::Controls::Frame^ HiddenFrame; + void Footer_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + bool autoSizeInputSectionWhenSnapped; + + void MainPage_SizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e); + void Scenarios_SelectionChanged(Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e); + + internal: + static MainPage^ Current; + + }; +} diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.sln b/samples/winrt/ImageManipulations/C++/MediaCapture.sln new file mode 100644 index 0000000..7b99bce --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 11 Express for Windows 8 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MediaCapture", "MediaCapture.vcxproj", "{C5B886A7-8300-46FF-B533-9613DE2AF637}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GrayscaleTransform", "MediaExtensions\Grayscale\Grayscale.vcxproj", "{BA69218F-DA5C-4D14-A78D-21A9E4DEC669}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|ARM.ActiveCfg = Debug|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|ARM.Build.0 = Debug|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|Win32.ActiveCfg = Debug|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|Win32.Build.0 = Debug|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|x64.ActiveCfg = Debug|x64 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Debug|x64.Build.0 = Debug|x64 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|ARM.ActiveCfg = Release|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|ARM.Build.0 = Release|ARM + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|Win32.ActiveCfg = Release|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|Win32.Build.0 = Release|Win32 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|x64.ActiveCfg = Release|x64 + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669}.Release|x64.Build.0 = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.ActiveCfg = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.Build.0 = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|ARM.Deploy.0 = Debug|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|Win32.ActiveCfg = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|Win32.Build.0 = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|Win32.Deploy.0 = Debug|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.ActiveCfg = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.Build.0 = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Debug|x64.Deploy.0 = Debug|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.ActiveCfg = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.Build.0 = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|ARM.Deploy.0 = Release|ARM + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|Win32.ActiveCfg = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|Win32.Build.0 = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|Win32.Deploy.0 = Release|Win32 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.ActiveCfg = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.Build.0 = Release|x64 + {C5B886A7-8300-46FF-B533-9613DE2AF637}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj new file mode 100644 index 0000000..d2f255d --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {C5B886A7-8300-46FF-B533-9613DE2AF637} + SDKSample + en-US + $(VCTargetsPath11) + 11.0 + true + MediaCapture + + + + Application + true + v110 + + + Application + true + v110 + + + Application + true + v110 + + + Application + false + true + v110 + + + Application + false + true + v110 + + + Application + false + true + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + pch.h + + + + + AdvancedCapture.xaml + Code + + + AudioCapture.xaml + Code + + + BasicCapture.xaml + Code + + + + MainPage.xaml + + + + + + App.xaml + + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + + Designer + + + + + AdvancedCapture.xaml + Code + + + App.xaml + + + AudioCapture.xaml + Code + + + BasicCapture.xaml + Code + + + + + + MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + {ba69218f-da5c-4d14-a78d-21a9e4dec669} + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters new file mode 100644 index 0000000..5f6124c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaCapture.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + + + + + + + + Common + + + Sample-Utils + + + + + + + + + + + Common + + + Common + + + + + + + + + + + + Common + + + Common + + + + + + + + + {132eec18-b164-4b15-a746-643880e9c5d9} + + + {476b4177-f316-4458-8e13-cab3dc2381c5} + + + {54f287f8-e4cb-4f47-97d0-4c469de6992e} + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h new file mode 100644 index 0000000..04ff69e --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/AsyncCB.h @@ -0,0 +1,81 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// +// AsyncCallback [template] +// +// Description: +// Helper class that routes IMFAsyncCallback::Invoke calls to a class +// method on the parent class. +// +// Usage: +// Add this class as a member variable. In the parent class constructor, +// initialize the AsyncCallback class like this: +// m_cb(this, &CYourClass::OnInvoke) +// where +// m_cb = AsyncCallback object +// CYourClass = parent class +// OnInvoke = Method in the parent class to receive Invoke calls. +// +// The parent's OnInvoke method (you can name it anything you like) must +// have a signature that matches the InvokeFn typedef below. +////////////////////////////////////////////////////////////////////////// + +// T: Type of the parent object +template +class AsyncCallback : public IMFAsyncCallback +{ +public: + typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult); + + AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn) + { + } + + // IUnknown + STDMETHODIMP_(ULONG) AddRef() { + // Delegate to parent class. + return m_pParent->AddRef(); + } + STDMETHODIMP_(ULONG) Release() { + // Delegate to parent class. + return m_pParent->Release(); + } + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if (!ppv) + { + return E_POINTER; + } + if (iid == __uuidof(IUnknown)) + { + *ppv = static_cast(static_cast(this)); + } + else if (iid == __uuidof(IMFAsyncCallback)) + { + *ppv = static_cast(this); + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + AddRef(); + return S_OK; + } + + + // IMFAsyncCallback methods + STDMETHODIMP GetParameters(DWORD*, DWORD*) + { + // Implementation of this method is optional. + return E_NOTIMPL; + } + + STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult) + { + return (m_pParent->*m_pInvokeFn)(pAsyncResult); + } + + T *m_pParent; + InvokeFn m_pInvokeFn; +}; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h new file mode 100644 index 0000000..92de15e --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/BufferLock.h @@ -0,0 +1,102 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + + +#pragma once + + +////////////////////////////////////////////////////////////////////////// +// VideoBufferLock +// +// Description: +// Locks a video buffer that might or might not support IMF2DBuffer. +// +////////////////////////////////////////////////////////////////////////// + +class VideoBufferLock +{ +public: + VideoBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL) + { + m_pBuffer = pBuffer; + m_pBuffer->AddRef(); + + // Query for the 2-D buffer interface. OK if this fails. + m_pBuffer->QueryInterface(IID_PPV_ARGS(&m_p2DBuffer)); + } + + ~VideoBufferLock() + { + UnlockBuffer(); + SafeRelease(&m_pBuffer); + SafeRelease(&m_p2DBuffer); + } + + // LockBuffer: + // Locks the buffer. Returns a pointer to scan line 0 and returns the stride. + + // The caller must provide the default stride as an input parameter, in case + // the buffer does not expose IMF2DBuffer. You can calculate the default stride + // from the media type. + + HRESULT LockBuffer( + LONG lDefaultStride, // Minimum stride (with no padding). + DWORD dwHeightInPixels, // Height of the image, in pixels. + BYTE **ppbScanLine0, // Receives a pointer to the start of scan line 0. + LONG *plStride // Receives the actual stride. + ) + { + HRESULT hr = S_OK; + + // Use the 2-D version if available. + if (m_p2DBuffer) + { + hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride); + } + else + { + // Use non-2D version. + BYTE *pData = NULL; + + hr = m_pBuffer->Lock(&pData, NULL, NULL); + if (SUCCEEDED(hr)) + { + *plStride = lDefaultStride; + if (lDefaultStride < 0) + { + // Bottom-up orientation. Return a pointer to the start of the + // last row *in memory* which is the top row of the image. + *ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1); + } + else + { + // Top-down orientation. Return a pointer to the start of the + // buffer. + *ppbScanLine0 = pData; + } + } + } + return hr; + } + + HRESULT UnlockBuffer() + { + if (m_p2DBuffer) + { + return m_p2DBuffer->Unlock2D(); + } + else + { + return m_pBuffer->Unlock(); + } + } + +private: + IMFMediaBuffer *m_pBuffer; + IMF2DBuffer *m_p2DBuffer; +}; + diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h new file mode 100644 index 0000000..d5ea05b --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/CritSec.h @@ -0,0 +1,62 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// +// CritSec +// Description: Wraps a critical section. +////////////////////////////////////////////////////////////////////////// + +class CritSec +{ +public: + CRITICAL_SECTION m_criticalSection; +public: + CritSec() + { + InitializeCriticalSectionEx(&m_criticalSection, 100, 0); + } + + ~CritSec() + { + DeleteCriticalSection(&m_criticalSection); + } + + _Acquires_lock_(m_criticalSection) + void Lock() + { + EnterCriticalSection(&m_criticalSection); + } + + _Releases_lock_(m_criticalSection) + void Unlock() + { + LeaveCriticalSection(&m_criticalSection); + } +}; + + +////////////////////////////////////////////////////////////////////////// +// AutoLock +// Description: Provides automatic locking and unlocking of a +// of a critical section. +// +// Note: The AutoLock object must go out of scope before the CritSec. +////////////////////////////////////////////////////////////////////////// + +class AutoLock +{ +private: + CritSec *m_pCriticalSection; +public: + _Acquires_lock_(m_pCriticalSection) + AutoLock(CritSec& crit) + { + m_pCriticalSection = &crit; + m_pCriticalSection->Lock(); + } + + _Releases_lock_(m_pCriticalSection) + ~AutoLock() + { + m_pCriticalSection->Unlock(); + } +}; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h new file mode 100644 index 0000000..c67c0f2 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/LinkList.h @@ -0,0 +1,516 @@ +//----------------------------------------------------------------------------- +// File: Linklist.h +// Desc: Linked list class. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (C) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#pragma once + +// Notes: +// +// The List class template implements a simple double-linked list. +// It uses STL's copy semantics. + +// There are two versions of the Clear() method: +// Clear(void) clears the list w/out cleaning up the object. +// Clear(FN fn) takes a functor object that releases the objects, if they need cleanup. + +// The List class supports enumeration. Example of usage: +// +// List::POSIITON pos = list.GetFrontPosition(); +// while (pos != list.GetEndPosition()) +// { +// T item; +// hr = list.GetItemPos(&item); +// pos = list.Next(pos); +// } + +// The ComPtrList class template derives from List<> and implements a list of COM pointers. + +template +struct NoOp +{ + void operator()(T& t) + { + } +}; + +template +class List +{ +protected: + + // Nodes in the linked list + struct Node + { + Node *prev; + Node *next; + T item; + + Node() : prev(nullptr), next(nullptr) + { + } + + Node(T item) : prev(nullptr), next(nullptr) + { + this->item = item; + } + + T Item() const { return item; } + }; + +public: + + // Object for enumerating the list. + class POSITION + { + friend class List; + + public: + POSITION() : pNode(nullptr) + { + } + + bool operator==(const POSITION &p) const + { + return pNode == p.pNode; + } + + bool operator!=(const POSITION &p) const + { + return pNode != p.pNode; + } + + private: + const Node *pNode; + + POSITION(Node *p) : pNode(p) + { + } + }; + +protected: + Node m_anchor; // Anchor node for the linked list. + DWORD m_count; // Number of items in the list. + + Node* Front() const + { + return m_anchor.next; + } + + Node* Back() const + { + return m_anchor.prev; + } + + virtual HRESULT InsertAfter(T item, Node *pBefore) + { + if (pBefore == nullptr) + { + return E_POINTER; + } + + Node *pNode = new Node(item); + if (pNode == nullptr) + { + return E_OUTOFMEMORY; + } + + Node *pAfter = pBefore->next; + + pBefore->next = pNode; + pAfter->prev = pNode; + + pNode->prev = pBefore; + pNode->next = pAfter; + + m_count++; + + return S_OK; + } + + virtual HRESULT GetItem(const Node *pNode, T* ppItem) + { + if (pNode == nullptr || ppItem == nullptr) + { + return E_POINTER; + } + + *ppItem = pNode->item; + return S_OK; + } + + // RemoveItem: + // Removes a node and optionally returns the item. + // ppItem can be nullptr. + virtual HRESULT RemoveItem(Node *pNode, T *ppItem) + { + if (pNode == nullptr) + { + return E_POINTER; + } + + assert(pNode != &m_anchor); // We should never try to remove the anchor node. + if (pNode == &m_anchor) + { + return E_INVALIDARG; + } + + + T item; + + // The next node's previous is this node's previous. + pNode->next->prev = pNode->prev; + + // The previous node's next is this node's next. + pNode->prev->next = pNode->next; + + item = pNode->item; + delete pNode; + + m_count--; + + if (ppItem) + { + *ppItem = item; + } + + return S_OK; + } + +public: + + List() + { + m_anchor.next = &m_anchor; + m_anchor.prev = &m_anchor; + + m_count = 0; + } + + virtual ~List() + { + Clear(); + } + + // Insertion functions + HRESULT InsertBack(T item) + { + return InsertAfter(item, m_anchor.prev); + } + + + HRESULT InsertFront(T item) + { + return InsertAfter(item, &m_anchor); + } + + HRESULT InsertPos(POSITION pos, T item) + { + if (pos.pNode == nullptr) + { + return InsertBack(item); + } + + return InsertAfter(item, pos.pNode->prev); + } + + // RemoveBack: Removes the tail of the list and returns the value. + // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) + HRESULT RemoveBack(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return RemoveItem(Back(), ppItem); + } + } + + // RemoveFront: Removes the head of the list and returns the value. + // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) + HRESULT RemoveFront(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return RemoveItem(Front(), ppItem); + } + } + + // GetBack: Gets the tail item. + HRESULT GetBack(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return GetItem(Back(), ppItem); + } + } + + // GetFront: Gets the front item. + HRESULT GetFront(T *ppItem) + { + if (IsEmpty()) + { + return E_FAIL; + } + else + { + return GetItem(Front(), ppItem); + } + } + + + // GetCount: Returns the number of items in the list. + DWORD GetCount() const { return m_count; } + + bool IsEmpty() const + { + return (GetCount() == 0); + } + + // Clear: Takes a functor object whose operator() + // frees the object on the list. + template + void Clear(FN& clear_fn) + { + Node *n = m_anchor.next; + + // Delete the nodes + while (n != &m_anchor) + { + clear_fn(n->item); + + Node *tmp = n->next; + delete n; + n = tmp; + } + + // Reset the anchor to point at itself + m_anchor.next = &m_anchor; + m_anchor.prev = &m_anchor; + + m_count = 0; + } + + // Clear: Clears the list. (Does not delete or release the list items.) + virtual void Clear() + { + NoOp clearOp; + Clear<>(clearOp); + } + + + // Enumerator functions + + POSITION FrontPosition() + { + if (IsEmpty()) + { + return POSITION(nullptr); + } + else + { + return POSITION(Front()); + } + } + + POSITION EndPosition() const + { + return POSITION(); + } + + HRESULT GetItemPos(POSITION pos, T *ppItem) + { + if (pos.pNode) + { + return GetItem(pos.pNode, ppItem); + } + else + { + return E_FAIL; + } + } + + POSITION Next(const POSITION pos) + { + if (pos.pNode && (pos.pNode->next != &m_anchor)) + { + return POSITION(pos.pNode->next); + } + else + { + return POSITION(nullptr); + } + } + + // Remove an item at a position. + // The item is returns in ppItem, unless ppItem is nullptr. + // NOTE: This method invalidates the POSITION object. + HRESULT Remove(POSITION& pos, T *ppItem) + { + if (pos.pNode) + { + // Remove const-ness temporarily... + Node *pNode = const_cast(pos.pNode); + + pos = POSITION(); + + return RemoveItem(pNode, ppItem); + } + else + { + return E_INVALIDARG; + } + } + +}; + + + +// Typical functors for Clear method. + +// ComAutoRelease: Releases COM pointers. +// MemDelete: Deletes pointers to new'd memory. + +class ComAutoRelease +{ +public: + void operator()(IUnknown *p) + { + if (p) + { + p->Release(); + } + } +}; + +class MemDelete +{ +public: + void operator()(void *p) + { + if (p) + { + delete p; + } + } +}; + + +// ComPtrList class +// Derived class that makes it safer to store COM pointers in the List<> class. +// It automatically AddRef's the pointers that are inserted onto the list +// (unless the insertion method fails). +// +// T must be a COM interface type. +// example: ComPtrList +// +// NULLABLE: If true, client can insert nullptr pointers. This means GetItem can +// succeed but return a nullptr pointer. By default, the list does not allow nullptr +// pointers. + +template +class ComPtrList : public List +{ +public: + + typedef T* Ptr; + + void Clear() + { + ComAutoRelease car; + List::Clear(car); + } + + ~ComPtrList() + { + Clear(); + } + +protected: + HRESULT InsertAfter(Ptr item, Node *pBefore) + { + // Do not allow nullptr item pointers unless NULLABLE is true. + if (item == nullptr && !NULLABLE) + { + return E_POINTER; + } + + if (item) + { + item->AddRef(); + } + + HRESULT hr = List::InsertAfter(item, pBefore); + if (FAILED(hr) && item != nullptr) + { + item->Release(); + } + return hr; + } + + HRESULT GetItem(const Node *pNode, Ptr* ppItem) + { + Ptr pItem = nullptr; + + // The base class gives us the pointer without AddRef'ing it. + // If we return the pointer to the caller, we must AddRef(). + HRESULT hr = List::GetItem(pNode, &pItem); + if (SUCCEEDED(hr)) + { + assert(pItem || NULLABLE); + if (pItem) + { + *ppItem = pItem; + (*ppItem)->AddRef(); + } + } + return hr; + } + + HRESULT RemoveItem(Node *pNode, Ptr *ppItem) + { + // ppItem can be nullptr, but we need to get the + // item so that we can release it. + + // If ppItem is not nullptr, we will AddRef it on the way out. + + Ptr pItem = nullptr; + + HRESULT hr = List::RemoveItem(pNode, &pItem); + + if (SUCCEEDED(hr)) + { + assert(pItem || NULLABLE); + if (ppItem && pItem) + { + *ppItem = pItem; + (*ppItem)->AddRef(); + } + + if (pItem) + { + pItem->Release(); + pItem = nullptr; + } + } + + return hr; + } +}; diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h new file mode 100644 index 0000000..dd0813b --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Common/OpQueue.h @@ -0,0 +1,222 @@ +////////////////////////////////////////////////////////////////////////// +// +// OpQueue.h +// Async operation queue. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +////////////////////////////////////////////////////////////////////////// + +#pragma once + +#pragma warning( push ) +#pragma warning( disable : 4355 ) // 'this' used in base member initializer list + +/* + This header file defines an object to help queue and serialize + asynchronous operations. + + Background: + + To perform an operation asynchronously in Media Foundation, an object + does one of the following: + + 1. Calls MFPutWorkItem(Ex), using either a standard work queue + identifier or a caller-allocated work queue. The work-queue + thread invokes the object's callback. + + 2. Creates an async result object (IMFAsyncResult) and calls + MFInvokeCallback to invoke the object's callback. + + Ultimately, either of these cause the object's callback to be invoked + from a work-queue thread. The object can then complete the operation + inside the callback. + + However, the Media Foundation platform may dispatch async callbacks in + parallel on several threads. Putting an item on a work queue does NOT + guarantee that one operation will complete before the next one starts, + or even that work items will be dispatched in the same order they were + called. + + To serialize async operations that should not overlap, an object should + use a queue. While one operation is pending, subsequent operations are + put on the queue, and only dispatched after the previous operation is + complete. + + The granularity of a single "operation" depends on the requirements of + that particular object. A single operation might involve several + asynchronous calls before the object dispatches the next operation on + the queue. + + +*/ + + + +//------------------------------------------------------------------- +// OpQueue class template +// +// Base class for an async operation queue. +// +// TOperation: The class used to describe operations. This class must +// implement IUnknown. +// +// The OpQueue class is an abstract class. The derived class must +// implement the following pure-virtual methods: +// +// - IUnknown methods (AddRef, Release, QI) +// +// - DispatchOperation: +// +// Performs the asynchronous operation specified by pOp. +// +// At the end of each operation, the derived class must call +// ProcessQueue to process the next operation in the queue. +// +// NOTE: An operation is not required to complete inside the +// DispatchOperation method. A single operation might consist +// of several asynchronous method calls. +// +// - ValidateOperation: +// +// Checks whether the object can perform the operation specified +// by pOp at this time. +// +// If the object cannot perform the operation now (e.g., because +// another operation is still in progress) the method should +// return MF_E_NOTACCEPTING. +// +//------------------------------------------------------------------- +#include "linklist.h" +#include "AsyncCB.h" + +template +class OpQueue //: public IUnknown +{ +public: + + typedef ComPtrList OpList; + + HRESULT QueueOperation(TOperation *pOp); + +protected: + + HRESULT ProcessQueue(); + HRESULT ProcessQueueAsync(IMFAsyncResult *pResult); + + virtual HRESULT DispatchOperation(TOperation *pOp) = 0; + virtual HRESULT ValidateOperation(TOperation *pOp) = 0; + + OpQueue(CRITICAL_SECTION& critsec) + : m_OnProcessQueue(static_cast(this), &OpQueue::ProcessQueueAsync), + m_critsec(critsec) + { + } + + virtual ~OpQueue() + { + } + +protected: + OpList m_OpQueue; // Queue of operations. + CRITICAL_SECTION& m_critsec; // Protects the queue state. + AsyncCallback m_OnProcessQueue; // ProcessQueueAsync callback. +}; + + + +//------------------------------------------------------------------- +// Place an operation on the queue. +// Public method. +//------------------------------------------------------------------- + +template +HRESULT OpQueue::QueueOperation(TOperation *pOp) +{ + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critsec); + + hr = m_OpQueue.InsertBack(pOp); + if (SUCCEEDED(hr)) + { + hr = ProcessQueue(); + } + + LeaveCriticalSection(&m_critsec); + return hr; +} + + +//------------------------------------------------------------------- +// Process the next operation on the queue. +// Protected method. +// +// Note: This method dispatches the operation to a work queue. +//------------------------------------------------------------------- + +template +HRESULT OpQueue::ProcessQueue() +{ + HRESULT hr = S_OK; + if (m_OpQueue.GetCount() > 0) + { + hr = MFPutWorkItem2( + MFASYNC_CALLBACK_QUEUE_STANDARD, // Use the standard work queue. + 0, // Default priority + &m_OnProcessQueue, // Callback method. + nullptr // State object. + ); + } + return hr; +} + + +//------------------------------------------------------------------- +// Process the next operation on the queue. +// Protected method. +// +// Note: This method is called from a work-queue thread. +//------------------------------------------------------------------- + +template +HRESULT OpQueue::ProcessQueueAsync(IMFAsyncResult *pResult) +{ + HRESULT hr = S_OK; + TOperation *pOp = nullptr; + + EnterCriticalSection(&m_critsec); + + if (m_OpQueue.GetCount() > 0) + { + hr = m_OpQueue.GetFront(&pOp); + + if (SUCCEEDED(hr)) + { + hr = ValidateOperation(pOp); + } + if (SUCCEEDED(hr)) + { + hr = m_OpQueue.RemoveFront(nullptr); + } + if (SUCCEEDED(hr)) + { + (void)DispatchOperation(pOp); + } + } + + if (pOp != nullptr) + { + pOp->Release(); + } + + LeaveCriticalSection(&m_critsec); + return hr; +} + +#pragma warning( pop ) \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp new file mode 100644 index 0000000..687386e --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.cpp @@ -0,0 +1,1783 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. + +#include "Grayscale.h" +#include "bufferlock.h" + +#pragma comment(lib, "d2d1") + +using namespace Microsoft::WRL; + +/* + +This sample implements a video effect as a Media Foundation transform (MFT). + +The video effect manipulates chroma values in a YUV image. In the default setting, +the entire image is converted to grayscale. Optionally, the application may set any +of the following attributes: + +MFT_GRAYSCALE_DESTINATION_RECT (type = blob, UINT32[4] array) + + Sets the destination rectangle for the effect. Pixels outside the destination + rectangle are not altered. + +MFT_GRAYSCALE_SATURATION (type = double) + + Sets the saturation level. The nominal range is [0...1]. Values beyond 1.0f + result in supersaturated colors. Values below 0.0f create inverted colors. + +MFT_GRAYSCALE_CHROMA_ROTATION (type = double) + + Rotates the chroma values of each pixel. The attribue value is the angle of + rotation in degrees. The result is a shift in hue. + +The effect is implemented by treating the chroma value of each pixel as a vector [u,v], +and applying a transformation matrix to the vector. The saturation parameter is applied +as a scaling transform. + + +NOTES ON THE MFT IMPLEMENTATION + +1. The MFT has fixed streams: One input stream and one output stream. + +2. The MFT supports the following formats: UYVY, YUY2, NV12. + +3. If the MFT is holding an input sample, SetInputType and SetOutputType both fail. + +4. The input and output types must be identical. + +5. If both types are set, no type can be set until the current type is cleared. + +6. Preferred input types: + + (a) If the output type is set, that's the preferred type. + (b) Otherwise, the preferred types are partial types, constructed from the + list of supported subtypes. + +7. Preferred output types: As above. + +8. Streaming: + + The private BeingStreaming() method is called in response to the + MFT_MESSAGE_NOTIFY_BEGIN_STREAMING message. + + If the client does not send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, the MFT calls + BeginStreaming inside the first call to ProcessInput or ProcessOutput. + + This is a good approach for allocating resources that your MFT requires for + streaming. + +9. The configuration attributes are applied in the BeginStreaming method. If the + client changes the attributes during streaming, the change is ignored until + streaming is stopped (either by changing the media types or by sending the + MFT_MESSAGE_NOTIFY_END_STREAMING message) and then restarted. + +*/ + + +// Video FOURCC codes. +const DWORD FOURCC_YUY2 = '2YUY'; +const DWORD FOURCC_UYVY = 'YVYU'; +const DWORD FOURCC_NV12 = '21VN'; + +// Static array of media types (preferred and accepted). +const GUID g_MediaSubtypes[] = +{ + MFVideoFormat_NV12, + MFVideoFormat_YUY2, + MFVideoFormat_UYVY +}; + +HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage); +HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride); +bool ValidateRect(const RECT& rc); + +template +inline T clamp(const T& val, const T& minVal, const T& maxVal) +{ + return (val < minVal ? minVal : (val > maxVal ? maxVal : val)); +} + + +// TransformChroma: +// Apply the transforms to calculate the output chroma values. + +void TransformChroma(const D2D1::Matrix3x2F& mat, BYTE *pu, BYTE *pv) +{ + // Normalize the chroma values to [-112, 112] range + + D2D1_POINT_2F pt = { static_cast(*pu) - 128, static_cast(*pv) - 128 }; + + pt = mat.TransformPoint(pt); + + // Clamp to valid range. + clamp(pt.x, -112.0f, 112.0f); + clamp(pt.y, -112.0f, 112.0f); + + // Map back to [16...240] range. + *pu = static_cast(pt.x + 128.0f); + *pv = static_cast(pt.y + 128.0f); +} + +//------------------------------------------------------------------- +// Functions to convert a YUV images to grayscale. +// +// In all cases, the same transformation is applied to the 8-bit +// chroma values, but the pixel layout in memory differs. +// +// The image conversion functions take the following parameters: +// +// mat Transfomation matrix for chroma values. +// rcDest Destination rectangle. +// pDest Pointer to the destination buffer. +// lDestStride Stride of the destination buffer, in bytes. +// pSrc Pointer to the source buffer. +// lSrcStride Stride of the source buffer, in bytes. +// dwWidthInPixels Frame width in pixels. +// dwHeightInPixels Frame height, in pixels. +//------------------------------------------------------------------- + +// Convert UYVY image. + +void TransformImage_UYVY( + const D2D1::Matrix3x2F& mat, + const D2D_RECT_U& rcDest, + _Inout_updates_(_Inexpressible_(lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, + _In_reads_(_Inexpressible_(lSrcStride * dwHeightInPixels)) const BYTE* pSrc, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, + _In_ DWORD dwHeightInPixels) +{ + DWORD y = 0; + const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + // Lines above the destination rectangle. + for ( ; y < rcDest.top; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } + + // Lines within the destination rectangle. + for ( ; y < y0; y++) + { + WORD *pSrc_Pixel = (WORD*)pSrc; + WORD *pDest_Pixel = (WORD*)pDest; + + for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) + { + // Byte order is U0 Y0 V0 Y1 + // Each WORD is a byte pair (U/V, Y) + // Windows is little-endian so the order appears reversed. + + if (x >= rcDest.left && x < rcDest.right) + { + BYTE u = pSrc_Pixel[x] & 0x00FF; + BYTE v = pSrc_Pixel[x+1] & 0x00FF; + + TransformChroma(mat, &u, &v); + + pDest_Pixel[x] = (pSrc_Pixel[x] & 0xFF00) | u; + pDest_Pixel[x+1] = (pSrc_Pixel[x+1] & 0xFF00) | v; + } + else + { +#pragma warning(push) +#pragma warning(disable: 6385) +#pragma warning(disable: 6386) + pDest_Pixel[x] = pSrc_Pixel[x]; + pDest_Pixel[x+1] = pSrc_Pixel[x+1]; +#pragma warning(pop) + } + } + + pDest += lDestStride; + pSrc += lSrcStride; + } + + // Lines below the destination rectangle. + for ( ; y < dwHeightInPixels; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } +} + + +// Convert YUY2 image. + +void TransformImage_YUY2( + const D2D1::Matrix3x2F& mat, + const D2D_RECT_U& rcDest, + _Inout_updates_(_Inexpressible_(lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, + _In_reads_(_Inexpressible_(lSrcStride * dwHeightInPixels)) const BYTE* pSrc, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, + _In_ DWORD dwHeightInPixels) +{ + DWORD y = 0; + const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + // Lines above the destination rectangle. + for ( ; y < rcDest.top; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } + + // Lines within the destination rectangle. + for ( ; y < y0; y++) + { + WORD *pSrc_Pixel = (WORD*)pSrc; + WORD *pDest_Pixel = (WORD*)pDest; + + for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) + { + // Byte order is Y0 U0 Y1 V0 + // Each WORD is a byte pair (Y, U/V) + // Windows is little-endian so the order appears reversed. + + if (x >= rcDest.left && x < rcDest.right) + { + BYTE u = pSrc_Pixel[x] >> 8; + BYTE v = pSrc_Pixel[x+1] >> 8; + + TransformChroma(mat, &u, &v); + + pDest_Pixel[x] = (pSrc_Pixel[x] & 0x00FF) | (u<<8); + pDest_Pixel[x+1] = (pSrc_Pixel[x+1] & 0x00FF) | (v<<8); + } + else + { +#pragma warning(push) +#pragma warning(disable: 6385) +#pragma warning(disable: 6386) + pDest_Pixel[x] = pSrc_Pixel[x]; + pDest_Pixel[x+1] = pSrc_Pixel[x+1]; +#pragma warning(pop) + } + } + pDest += lDestStride; + pSrc += lSrcStride; + } + + // Lines below the destination rectangle. + for ( ; y < dwHeightInPixels; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels * 2); + pSrc += lSrcStride; + pDest += lDestStride; + } +} + +// Convert NV12 image + +void TransformImage_NV12( + const D2D1::Matrix3x2F& mat, + const D2D_RECT_U& rcDest, + _Inout_updates_(_Inexpressible_(2 * lDestStride * dwHeightInPixels)) BYTE *pDest, + _In_ LONG lDestStride, + _In_reads_(_Inexpressible_(2 * lSrcStride * dwHeightInPixels)) const BYTE* pSrc, + _In_ LONG lSrcStride, + _In_ DWORD dwWidthInPixels, + _In_ DWORD dwHeightInPixels) +{ + // NV12 is planar: Y plane, followed by packed U-V plane. + + // Y plane + for (DWORD y = 0; y < dwHeightInPixels; y++) + { + CopyMemory(pDest, pSrc, dwWidthInPixels); + pDest += lDestStride; + pSrc += lSrcStride; + } + + // U-V plane + + // NOTE: The U-V plane has 1/2 the number of lines as the Y plane. + + // Lines above the destination rectangle. + DWORD y = 0; + const DWORD y0 = min(rcDest.bottom, dwHeightInPixels); + + for ( ; y < rcDest.top/2; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels); + pSrc += lSrcStride; + pDest += lDestStride; + } + + // Lines within the destination rectangle. + for ( ; y < y0/2; y++) + { + for (DWORD x = 0; (x + 1) < dwWidthInPixels; x += 2) + { + if (x >= rcDest.left && x < rcDest.right) + { + BYTE u = pSrc[x]; + BYTE v = pSrc[x+1]; + + TransformChroma(mat, &u, &v); + + pDest[x] = u; + pDest[x+1] = v; + } + else + { + pDest[x] = pSrc[x]; + pDest[x+1] = pSrc[x+1]; + } + } + pDest += lDestStride; + pSrc += lSrcStride; + } + + // Lines below the destination rectangle. + for ( ; y < dwHeightInPixels/2; y++) + { + memcpy(pDest, pSrc, dwWidthInPixels); + pSrc += lSrcStride; + pDest += lDestStride; + } +} + +CGrayscale::CGrayscale() : + m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL), m_pTransformFn(NULL), + m_imageWidthInPixels(0), m_imageHeightInPixels(0), m_cbImageSize(0), + m_transform(D2D1::Matrix3x2F::Identity()), m_rcDest(D2D1::RectU()), m_bStreamingInitialized(false), + m_pAttributes(NULL) +{ + InitializeCriticalSectionEx(&m_critSec, 3000, 0); +} + +CGrayscale::~CGrayscale() +{ + SafeRelease(&m_pInputType); + SafeRelease(&m_pOutputType); + SafeRelease(&m_pSample); + SafeRelease(&m_pAttributes); + DeleteCriticalSection(&m_critSec); +} + +// Initialize the instance. +STDMETHODIMP CGrayscale::RuntimeClassInitialize() +{ + // Create the attribute store. + return MFCreateAttributes(&m_pAttributes, 3); +} + +// IMediaExtension methods + +//------------------------------------------------------------------- +// SetProperties +// Sets the configuration of the effect +//------------------------------------------------------------------- +HRESULT CGrayscale::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration) +{ + return S_OK; +} + +// IMFTransform methods. Refer to the Media Foundation SDK documentation for details. + +//------------------------------------------------------------------- +// GetStreamLimits +// Returns the minimum and maximum number of streams. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetStreamLimits( + DWORD *pdwInputMinimum, + DWORD *pdwInputMaximum, + DWORD *pdwOutputMinimum, + DWORD *pdwOutputMaximum +) +{ + if ((pdwInputMinimum == NULL) || + (pdwInputMaximum == NULL) || + (pdwOutputMinimum == NULL) || + (pdwOutputMaximum == NULL)) + { + return E_POINTER; + } + + // This MFT has a fixed number of streams. + *pdwInputMinimum = 1; + *pdwInputMaximum = 1; + *pdwOutputMinimum = 1; + *pdwOutputMaximum = 1; + return S_OK; +} + + +//------------------------------------------------------------------- +// GetStreamCount +// Returns the actual number of streams. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetStreamCount( + DWORD *pcInputStreams, + DWORD *pcOutputStreams +) +{ + if ((pcInputStreams == NULL) || (pcOutputStreams == NULL)) + + { + return E_POINTER; + } + + // This MFT has a fixed number of streams. + *pcInputStreams = 1; + *pcOutputStreams = 1; + return S_OK; +} + + + +//------------------------------------------------------------------- +// GetStreamIDs +// Returns stream IDs for the input and output streams. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetStreamIDs( + DWORD dwInputIDArraySize, + DWORD *pdwInputIDs, + DWORD dwOutputIDArraySize, + DWORD *pdwOutputIDs +) +{ + // It is not required to implement this method if the MFT has a fixed number of + // streams AND the stream IDs are numbered sequentially from zero (that is, the + // stream IDs match the stream indexes). + + // In that case, it is OK to return E_NOTIMPL. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// GetInputStreamInfo +// Returns information about an input stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputStreamInfo( + DWORD dwInputStreamID, + MFT_INPUT_STREAM_INFO * pStreamInfo +) +{ + if (pStreamInfo == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + // NOTE: This method should succeed even when there is no media type on the + // stream. If there is no media type, we only need to fill in the dwFlags + // member of MFT_INPUT_STREAM_INFO. The other members depend on having a + // a valid media type. + + pStreamInfo->hnsMaxLatency = 0; + pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER; + + if (m_pInputType == NULL) + { + pStreamInfo->cbSize = 0; + } + else + { + pStreamInfo->cbSize = m_cbImageSize; + } + + pStreamInfo->cbMaxLookahead = 0; + pStreamInfo->cbAlignment = 0; + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + +//------------------------------------------------------------------- +// GetOutputStreamInfo +// Returns information about an output stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputStreamInfo( + DWORD dwOutputStreamID, + MFT_OUTPUT_STREAM_INFO * pStreamInfo +) +{ + if (pStreamInfo == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + // NOTE: This method should succeed even when there is no media type on the + // stream. If there is no media type, we only need to fill in the dwFlags + // member of MFT_OUTPUT_STREAM_INFO. The other members depend on having a + // a valid media type. + + pStreamInfo->dwFlags = + MFT_OUTPUT_STREAM_WHOLE_SAMPLES | + MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | + MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE ; + + if (m_pOutputType == NULL) + { + pStreamInfo->cbSize = 0; + } + else + { + pStreamInfo->cbSize = m_cbImageSize; + } + + pStreamInfo->cbAlignment = 0; + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + +//------------------------------------------------------------------- +// GetAttributes +// Returns the attributes for the MFT. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetAttributes(IMFAttributes** ppAttributes) +{ + if (ppAttributes == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + *ppAttributes = m_pAttributes; + (*ppAttributes)->AddRef(); + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + +//------------------------------------------------------------------- +// GetInputStreamAttributes +// Returns stream-level attributes for an input stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputStreamAttributes( + DWORD dwInputStreamID, + IMFAttributes **ppAttributes +) +{ + // This MFT does not support any stream-level attributes, so the method is not implemented. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// GetOutputStreamAttributes +// Returns stream-level attributes for an output stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputStreamAttributes( + DWORD dwOutputStreamID, + IMFAttributes **ppAttributes +) +{ + // This MFT does not support any stream-level attributes, so the method is not implemented. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// DeleteInputStream +//------------------------------------------------------------------- + +HRESULT CGrayscale::DeleteInputStream(DWORD dwStreamID) +{ + // This MFT has a fixed number of input streams, so the method is not supported. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// AddInputStreams +//------------------------------------------------------------------- + +HRESULT CGrayscale::AddInputStreams( + DWORD cStreams, + DWORD *adwStreamIDs +) +{ + // This MFT has a fixed number of output streams, so the method is not supported. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// GetInputAvailableType +// Returns a preferred input type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputAvailableType( + DWORD dwInputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + // If the output type is set, return that type as our preferred input type. + if (m_pOutputType == NULL) + { + // The output type is not set. Create a partial media type. + hr = OnGetPartialType(dwTypeIndex, ppType); + } + else if (dwTypeIndex > 0) + { + hr = MF_E_NO_MORE_TYPES; + } + else + { + *ppType = m_pOutputType; + (*ppType)->AddRef(); + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + + +//------------------------------------------------------------------- +// GetOutputAvailableType +// Returns a preferred output type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputAvailableType( + DWORD dwOutputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + if (m_pInputType == NULL) + { + // The input type is not set. Create a partial media type. + hr = OnGetPartialType(dwTypeIndex, ppType); + } + else if (dwTypeIndex > 0) + { + hr = MF_E_NO_MORE_TYPES; + } + else + { + *ppType = m_pInputType; + (*ppType)->AddRef(); + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// SetInputType +//------------------------------------------------------------------- + +HRESULT CGrayscale::SetInputType( + DWORD dwInputStreamID, + IMFMediaType *pType, // Can be NULL to clear the input type. + DWORD dwFlags +) +{ + // Validate flags. + if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + // Does the caller want us to set the type, or just test it? + BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0); + + // If we have an input sample, the client cannot change the type now. + if (HasPendingOutput()) + { + hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING; + goto done; + } + + // Validate the type, if non-NULL. + if (pType) + { + hr = OnCheckInputType(pType); + if (FAILED(hr)) + { + goto done; + } + } + + // The type is OK. Set the type, unless the caller was just testing. + if (bReallySet) + { + OnSetInputType(pType); + + // When the type changes, end streaming. + hr = EndStreaming(); + } + +done: + LeaveCriticalSection(&m_critSec); + return hr; +} + + + +//------------------------------------------------------------------- +// SetOutputType +//------------------------------------------------------------------- + +HRESULT CGrayscale::SetOutputType( + DWORD dwOutputStreamID, + IMFMediaType *pType, // Can be NULL to clear the output type. + DWORD dwFlags +) +{ + // Validate flags. + if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY) + { + return E_INVALIDARG; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + HRESULT hr = S_OK; + + // Does the caller want us to set the type, or just test it? + BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0); + + // If we have an input sample, the client cannot change the type now. + if (HasPendingOutput()) + { + hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING; + goto done; + } + + // Validate the type, if non-NULL. + if (pType) + { + hr = OnCheckOutputType(pType); + if (FAILED(hr)) + { + goto done; + } + } + + // The type is OK. Set the type, unless the caller was just testing. + if (bReallySet) + { + OnSetOutputType(pType); + + // When the type changes, end streaming. + hr = EndStreaming(); + } + +done: + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// GetInputCurrentType +// Returns the current input type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputCurrentType( + DWORD dwInputStreamID, + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_POINTER; + } + + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + hr = MF_E_INVALIDSTREAMNUMBER; + } + else if (!m_pInputType) + { + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + } + else + { + *ppType = m_pInputType; + (*ppType)->AddRef(); + } + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// GetOutputCurrentType +// Returns the current output type. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputCurrentType( + DWORD dwOutputStreamID, + IMFMediaType **ppType +) +{ + if (ppType == NULL) + { + return E_POINTER; + } + + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critSec); + + if (!IsValidOutputStream(dwOutputStreamID)) + { + hr = MF_E_INVALIDSTREAMNUMBER; + } + else if (!m_pOutputType) + { + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + } + else + { + *ppType = m_pOutputType; + (*ppType)->AddRef(); + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// GetInputStatus +// Query if the MFT is accepting more input. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetInputStatus( + DWORD dwInputStreamID, + DWORD *pdwFlags +) +{ + if (pdwFlags == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + if (!IsValidInputStream(dwInputStreamID)) + { + LeaveCriticalSection(&m_critSec); + return MF_E_INVALIDSTREAMNUMBER; + } + + // If an input sample is already queued, do not accept another sample until the + // client calls ProcessOutput or Flush. + + // NOTE: It is possible for an MFT to accept more than one input sample. For + // example, this might be required in a video decoder if the frames do not + // arrive in temporal order. In the case, the decoder must hold a queue of + // samples. For the video effect, each sample is transformed independently, so + // there is no reason to queue multiple input samples. + + if (m_pSample == NULL) + { + *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA; + } + else + { + *pdwFlags = 0; + } + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + + +//------------------------------------------------------------------- +// GetOutputStatus +// Query if the MFT can produce output. +//------------------------------------------------------------------- + +HRESULT CGrayscale::GetOutputStatus(DWORD *pdwFlags) +{ + if (pdwFlags == NULL) + { + return E_POINTER; + } + + EnterCriticalSection(&m_critSec); + + // The MFT can produce an output sample if (and only if) there an input sample. + if (m_pSample != NULL) + { + *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY; + } + else + { + *pdwFlags = 0; + } + + LeaveCriticalSection(&m_critSec); + return S_OK; +} + + +//------------------------------------------------------------------- +// SetOutputBounds +// Sets the range of time stamps that the MFT will output. +//------------------------------------------------------------------- + +HRESULT CGrayscale::SetOutputBounds( + LONGLONG hnsLowerBound, + LONGLONG hnsUpperBound +) +{ + // Implementation of this method is optional. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// ProcessEvent +// Sends an event to an input stream. +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessEvent( + DWORD dwInputStreamID, + IMFMediaEvent *pEvent +) +{ + // This MFT does not handle any stream events, so the method can + // return E_NOTIMPL. This tells the pipeline that it can stop + // sending any more events to this MFT. + return E_NOTIMPL; +} + + +//------------------------------------------------------------------- +// ProcessMessage +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessMessage( + MFT_MESSAGE_TYPE eMessage, + ULONG_PTR ulParam +) +{ + EnterCriticalSection(&m_critSec); + + HRESULT hr = S_OK; + + switch (eMessage) + { + case MFT_MESSAGE_COMMAND_FLUSH: + // Flush the MFT. + hr = OnFlush(); + break; + + case MFT_MESSAGE_COMMAND_DRAIN: + // Drain: Tells the MFT to reject further input until all pending samples are + // processed. That is our default behavior already, so there is nothing to do. + // + // For a decoder that accepts a queue of samples, the MFT might need to drain + // the queue in response to this command. + break; + + case MFT_MESSAGE_SET_D3D_MANAGER: + // Sets a pointer to the IDirect3DDeviceManager9 interface. + + // The pipeline should never send this message unless the MFT sets the MF_SA_D3D_AWARE + // attribute set to TRUE. Because this MFT does not set MF_SA_D3D_AWARE, it is an error + // to send the MFT_MESSAGE_SET_D3D_MANAGER message to the MFT. Return an error code in + // this case. + + // NOTE: If this MFT were D3D-enabled, it would cache the IDirect3DDeviceManager9 + // pointer for use during streaming. + + hr = E_NOTIMPL; + break; + + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + hr = BeginStreaming(); + break; + + case MFT_MESSAGE_NOTIFY_END_STREAMING: + hr = EndStreaming(); + break; + + // The next two messages do not require any action from this MFT. + + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + break; + + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + break; + } + + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// ProcessInput +// Process an input sample. +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessInput( + DWORD dwInputStreamID, + IMFSample *pSample, + DWORD dwFlags +) +{ + // Check input parameters. + if (pSample == NULL) + { + return E_POINTER; + } + + if (dwFlags != 0) + { + return E_INVALIDARG; // dwFlags is reserved and must be zero. + } + + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critSec); + + // Validate the input stream number. + if (!IsValidInputStream(dwInputStreamID)) + { + hr = MF_E_INVALIDSTREAMNUMBER; + goto done; + } + + // Check for valid media types. + // The client must set input and output types before calling ProcessInput. + if (!m_pInputType || !m_pOutputType) + { + hr = MF_E_NOTACCEPTING; + goto done; + } + + // Check if an input sample is already queued. + if (m_pSample != NULL) + { + hr = MF_E_NOTACCEPTING; // We already have an input sample. + goto done; + } + + // Initialize streaming. + hr = BeginStreaming(); + if (FAILED(hr)) + { + goto done; + } + + // Cache the sample. We do the actual work in ProcessOutput. + m_pSample = pSample; + pSample->AddRef(); // Hold a reference count on the sample. + +done: + LeaveCriticalSection(&m_critSec); + return hr; +} + + +//------------------------------------------------------------------- +// ProcessOutput +// Process an output sample. +//------------------------------------------------------------------- + +HRESULT CGrayscale::ProcessOutput( + DWORD dwFlags, + DWORD cOutputBufferCount, + MFT_OUTPUT_DATA_BUFFER *pOutputSamples, // one per stream + DWORD *pdwStatus +) +{ + // Check input parameters... + + // This MFT does not accept any flags for the dwFlags parameter. + + // The only defined flag is MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER. This flag + // applies only when the MFT marks an output stream as lazy or optional. But this + // MFT has no lazy or optional streams, so the flag is not valid. + + if (dwFlags != 0) + { + return E_INVALIDARG; + } + + if (pOutputSamples == NULL || pdwStatus == NULL) + { + return E_POINTER; + } + + // There must be exactly one output buffer. + if (cOutputBufferCount != 1) + { + return E_INVALIDARG; + } + + // It must contain a sample. + if (pOutputSamples[0].pSample == NULL) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + + IMFMediaBuffer *pInput = NULL; + IMFMediaBuffer *pOutput = NULL; + + EnterCriticalSection(&m_critSec); + + // There must be an input sample available for processing. + if (m_pSample == NULL) + { + hr = MF_E_TRANSFORM_NEED_MORE_INPUT; + goto done; + } + + // Initialize streaming. + + hr = BeginStreaming(); + if (FAILED(hr)) + { + goto done; + } + + // Get the input buffer. + hr = m_pSample->ConvertToContiguousBuffer(&pInput); + if (FAILED(hr)) + { + goto done; + } + + // Get the output buffer. + hr = pOutputSamples[0].pSample->ConvertToContiguousBuffer(&pOutput); + if (FAILED(hr)) + { + goto done; + } + + hr = OnProcessOutput(pInput, pOutput); + if (FAILED(hr)) + { + goto done; + } + + // Set status flags. + pOutputSamples[0].dwStatus = 0; + *pdwStatus = 0; + + + // Copy the duration and time stamp from the input sample, if present. + + LONGLONG hnsDuration = 0; + LONGLONG hnsTime = 0; + + if (SUCCEEDED(m_pSample->GetSampleDuration(&hnsDuration))) + { + hr = pOutputSamples[0].pSample->SetSampleDuration(hnsDuration); + if (FAILED(hr)) + { + goto done; + } + } + + if (SUCCEEDED(m_pSample->GetSampleTime(&hnsTime))) + { + hr = pOutputSamples[0].pSample->SetSampleTime(hnsTime); + } + +done: + SafeRelease(&m_pSample); // Release our input sample. + SafeRelease(&pInput); + SafeRelease(&pOutput); + LeaveCriticalSection(&m_critSec); + return hr; +} + +// PRIVATE METHODS + +// All methods that follow are private to this MFT and are not part of the IMFTransform interface. + +// Create a partial media type from our list. +// +// dwTypeIndex: Index into the list of peferred media types. +// ppmt: Receives a pointer to the media type. + +HRESULT CGrayscale::OnGetPartialType(DWORD dwTypeIndex, IMFMediaType **ppmt) +{ + if (dwTypeIndex >= ARRAYSIZE(g_MediaSubtypes)) + { + return MF_E_NO_MORE_TYPES; + } + + IMFMediaType *pmt = NULL; + + HRESULT hr = MFCreateMediaType(&pmt); + if (FAILED(hr)) + { + goto done; + } + + hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + if (FAILED(hr)) + { + goto done; + } + + hr = pmt->SetGUID(MF_MT_SUBTYPE, g_MediaSubtypes[dwTypeIndex]); + if (FAILED(hr)) + { + goto done; + } + + *ppmt = pmt; + (*ppmt)->AddRef(); + +done: + SafeRelease(&pmt); + return hr; +} + + +// Validate an input media type. + +HRESULT CGrayscale::OnCheckInputType(IMFMediaType *pmt) +{ + assert(pmt != NULL); + + HRESULT hr = S_OK; + + // If the output type is set, see if they match. + if (m_pOutputType != NULL) + { + DWORD flags = 0; + hr = pmt->IsEqual(m_pOutputType, &flags); + + // IsEqual can return S_FALSE. Treat this as failure. + if (hr != S_OK) + { + hr = MF_E_INVALIDMEDIATYPE; + } + } + else + { + // Output type is not set. Just check this type. + hr = OnCheckMediaType(pmt); + } + return hr; +} + + +// Validate an output media type. + +HRESULT CGrayscale::OnCheckOutputType(IMFMediaType *pmt) +{ + assert(pmt != NULL); + + HRESULT hr = S_OK; + + // If the input type is set, see if they match. + if (m_pInputType != NULL) + { + DWORD flags = 0; + hr = pmt->IsEqual(m_pInputType, &flags); + + // IsEqual can return S_FALSE. Treat this as failure. + if (hr != S_OK) + { + hr = MF_E_INVALIDMEDIATYPE; + } + + } + else + { + // Input type is not set. Just check this type. + hr = OnCheckMediaType(pmt); + } + return hr; +} + + +// Validate a media type (input or output) + +HRESULT CGrayscale::OnCheckMediaType(IMFMediaType *pmt) +{ + BOOL bFoundMatchingSubtype = FALSE; + + // Major type must be video. + GUID major_type; + HRESULT hr = pmt->GetGUID(MF_MT_MAJOR_TYPE, &major_type); + if (FAILED(hr)) + { + goto done; + } + + if (major_type != MFMediaType_Video) + { + hr = MF_E_INVALIDMEDIATYPE; + goto done; + } + + // Subtype must be one of the subtypes in our global list. + + // Get the subtype GUID. + GUID subtype; + hr = pmt->GetGUID(MF_MT_SUBTYPE, &subtype); + if (FAILED(hr)) + { + goto done; + } + + // Look for the subtype in our list of accepted types. + for (DWORD i = 0; i < ARRAYSIZE(g_MediaSubtypes); i++) + { + if (subtype == g_MediaSubtypes[i]) + { + bFoundMatchingSubtype = TRUE; + break; + } + } + + if (!bFoundMatchingSubtype) + { + hr = MF_E_INVALIDMEDIATYPE; // The MFT does not support this subtype. + goto done; + } + + // Reject single-field media types. + UINT32 interlace = MFGetAttributeUINT32(pmt, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); + if (interlace == MFVideoInterlace_FieldSingleUpper || interlace == MFVideoInterlace_FieldSingleLower) + { + hr = MF_E_INVALIDMEDIATYPE; + } + +done: + return hr; +} + + +// Set or clear the input media type. +// +// Prerequisite: The input type was already validated. + +void CGrayscale::OnSetInputType(IMFMediaType *pmt) +{ + // if pmt is NULL, clear the type. + // if pmt is non-NULL, set the type. + + SafeRelease(&m_pInputType); + m_pInputType = pmt; + if (m_pInputType) + { + m_pInputType->AddRef(); + } + + // Update the format information. + UpdateFormatInfo(); +} + + +// Set or clears the output media type. +// +// Prerequisite: The output type was already validated. + +void CGrayscale::OnSetOutputType(IMFMediaType *pmt) +{ + // If pmt is NULL, clear the type. Otherwise, set the type. + + SafeRelease(&m_pOutputType); + m_pOutputType = pmt; + if (m_pOutputType) + { + m_pOutputType->AddRef(); + } +} + + +// Initialize streaming parameters. +// +// This method is called if the client sends the MFT_MESSAGE_NOTIFY_BEGIN_STREAMING +// message, or when the client processes a sample, whichever happens first. + +HRESULT CGrayscale::BeginStreaming() +{ + HRESULT hr = S_OK; + + if (!m_bStreamingInitialized) + { + // Get the configuration attributes. + + // Get the destination rectangle. + + RECT rcDest; + hr = m_pAttributes->GetBlob(MFT_GRAYSCALE_DESTINATION_RECT, (UINT8*)&rcDest, sizeof(rcDest), NULL); + if (hr == MF_E_ATTRIBUTENOTFOUND || !ValidateRect(rcDest)) + { + // The client did not set this attribute, or the client provided an invalid rectangle. + // Default to the entire image. + + m_rcDest = D2D1::RectU(0, 0, m_imageWidthInPixels, m_imageHeightInPixels); + hr = S_OK; + } + else if (SUCCEEDED(hr)) + { + m_rcDest = D2D1::RectU(rcDest.left, rcDest.top, rcDest.right, rcDest.bottom); + } + else + { + goto done; + } + + // Get the chroma transformations. + + float scale = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_SATURATION, 0.0f); + float angle = (float)MFGetAttributeDouble(m_pAttributes, MFT_GRAYSCALE_CHROMA_ROTATION, 0.0f); + + m_transform = D2D1::Matrix3x2F::Scale(scale, scale) * D2D1::Matrix3x2F::Rotation(angle); + + m_bStreamingInitialized = true; + } + +done: + return hr; +} + + +// End streaming. + +// This method is called if the client sends an MFT_MESSAGE_NOTIFY_END_STREAMING +// message, or when the media type changes. In general, it should be called whenever +// the streaming parameters need to be reset. + +HRESULT CGrayscale::EndStreaming() +{ + m_bStreamingInitialized = false; + return S_OK; +} + + + +// Generate output data. + +HRESULT CGrayscale::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut) +{ + BYTE *pDest = NULL; // Destination buffer. + LONG lDestStride = 0; // Destination stride. + + BYTE *pSrc = NULL; // Source buffer. + LONG lSrcStride = 0; // Source stride. + + // Helper objects to lock the buffers. + VideoBufferLock inputLock(pIn); + VideoBufferLock outputLock(pOut); + + // Stride if the buffer does not support IMF2DBuffer + LONG lDefaultStride = 0; + + HRESULT hr = GetDefaultStride(m_pInputType, &lDefaultStride); + if (FAILED(hr)) + { + goto done; + } + + // Lock the input buffer. + hr = inputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pSrc, &lSrcStride); + if (FAILED(hr)) + { + goto done; + } + + // Lock the output buffer. + hr = outputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pDest, &lDestStride); + if (FAILED(hr)) + { + goto done; + } + + // Invoke the image transform function. + assert (m_pTransformFn != NULL); + if (m_pTransformFn) + { + (*m_pTransformFn)(m_transform, m_rcDest, pDest, lDestStride, pSrc, lSrcStride, + m_imageWidthInPixels, m_imageHeightInPixels); + } + else + { + hr = E_UNEXPECTED; + goto done; + } + + + // Set the data size on the output buffer. + hr = pOut->SetCurrentLength(m_cbImageSize); + + // The VideoBufferLock class automatically unlocks the buffers. +done: + return hr; +} + + +// Flush the MFT. + +HRESULT CGrayscale::OnFlush() +{ + // For this MFT, flushing just means releasing the input sample. + SafeRelease(&m_pSample); + return S_OK; +} + + +// Update the format information. This method is called whenever the +// input type is set. + +HRESULT CGrayscale::UpdateFormatInfo() +{ + HRESULT hr = S_OK; + + GUID subtype = GUID_NULL; + + m_imageWidthInPixels = 0; + m_imageHeightInPixels = 0; + m_cbImageSize = 0; + + m_pTransformFn = NULL; + + if (m_pInputType != NULL) + { + hr = m_pInputType->GetGUID(MF_MT_SUBTYPE, &subtype); + if (FAILED(hr)) + { + goto done; + } + if (subtype == MFVideoFormat_YUY2) + { + m_pTransformFn = TransformImage_YUY2; + } + else if (subtype == MFVideoFormat_UYVY) + { + m_pTransformFn = TransformImage_UYVY; + } + else if (subtype == MFVideoFormat_NV12) + { + m_pTransformFn = TransformImage_NV12; + } + else + { + hr = E_UNEXPECTED; + goto done; + } + + hr = MFGetAttributeSize(m_pInputType, MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels); + if (FAILED(hr)) + { + goto done; + } + + // Calculate the image size (not including padding) + hr = GetImageSize(subtype.Data1, m_imageWidthInPixels, m_imageHeightInPixels, &m_cbImageSize); + } + +done: + return hr; +} + + +// Calculate the size of the buffer needed to store the image. + +// fcc: The FOURCC code of the video format. + +HRESULT GetImageSize(DWORD fcc, UINT32 width, UINT32 height, DWORD* pcbImage) +{ + HRESULT hr = S_OK; + + switch (fcc) + { + case FOURCC_YUY2: + case FOURCC_UYVY: + // check overflow + if ((width > MAXDWORD / 2) || (width * 2 > MAXDWORD / height)) + { + hr = E_INVALIDARG; + } + else + { + // 16 bpp + *pcbImage = width * height * 2; + } + break; + + case FOURCC_NV12: + // check overflow + if ((height/2 > MAXDWORD - height) || ((height + height/2) > MAXDWORD / width)) + { + hr = E_INVALIDARG; + } + else + { + // 12 bpp + *pcbImage = width * (height + (height/2)); + } + break; + + default: + hr = E_FAIL; // Unsupported type. + } + return hr; +} + +// Get the default stride for a video format. +HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride) +{ + LONG lStride = 0; + + // Try to get the default stride from the media type. + HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride); + if (FAILED(hr)) + { + // Attribute not set. Try to calculate the default stride. + GUID subtype = GUID_NULL; + + UINT32 width = 0; + UINT32 height = 0; + + // Get the subtype and the image size. + hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); + if (SUCCEEDED(hr)) + { + hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height); + } + if (SUCCEEDED(hr)) + { + if (subtype == MFVideoFormat_NV12) + { + lStride = width; + } + else if (subtype == MFVideoFormat_YUY2 || subtype == MFVideoFormat_UYVY) + { + lStride = ((width * 2) + 3) & ~3; + } + else + { + hr = E_INVALIDARG; + } + } + + // Set the attribute for later reference. + if (SUCCEEDED(hr)) + { + (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride)); + } + } + if (SUCCEEDED(hr)) + { + *plStride = lStride; + } + return hr; +} + + +// Validate that a rectangle meets the following criteria: +// +// - All coordinates are non-negative. +// - The rectangle is not flipped (top > bottom, left > right) +// +// These are the requirements for the destination rectangle. + +bool ValidateRect(const RECT& rc) +{ + if (rc.left < 0 || rc.top < 0) + { + return false; + } + if (rc.left > rc.right || rc.top > rc.bottom) + { + return false; + } + return true; +} diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def new file mode 100644 index 0000000..0b80190 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.def @@ -0,0 +1,4 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllGetActivationFactory PRIVATE + DllGetClassObject PRIVATE \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h new file mode 100644 index 0000000..b83223b --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.h @@ -0,0 +1,266 @@ +// Defines the transform class. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. + +#ifndef GRAYSCALE_H +#define GRAYSCALE_H + +#include +#include +#include +#include +#include +#include +#include + +// Note: The Direct2D helper library is included for its 2D matrix operations. +#include + +#include +#include +#include + +#include "GrayscaleTransform.h" + +// CLSID of the MFT. +DEFINE_GUID(CLSID_GrayscaleMFT, +0x2f3dbc05, 0xc011, 0x4a8f, 0xb2, 0x64, 0xe4, 0x2e, 0x35, 0xc6, 0x7b, 0xf4); + +// +// * IMPORTANT: If you implement your own MFT, create a new GUID for the CLSID. * +// + + +// Configuration attributes + +// {7BBBB051-133B-41F5-B6AA-5AFF9B33A2CB} +DEFINE_GUID(MFT_GRAYSCALE_DESTINATION_RECT, +0x7bbbb051, 0x133b, 0x41f5, 0xb6, 0xaa, 0x5a, 0xff, 0x9b, 0x33, 0xa2, 0xcb); + + +// {14782342-93E8-4565-872C-D9A2973D5CBF} +DEFINE_GUID(MFT_GRAYSCALE_SATURATION, +0x14782342, 0x93e8, 0x4565, 0x87, 0x2c, 0xd9, 0xa2, 0x97, 0x3d, 0x5c, 0xbf); + +// {E0BADE5D-E4B9-4689-9DBA-E2F00D9CED0E} +DEFINE_GUID(MFT_GRAYSCALE_CHROMA_ROTATION, +0xe0bade5d, 0xe4b9, 0x4689, 0x9d, 0xba, 0xe2, 0xf0, 0xd, 0x9c, 0xed, 0xe); + + +template void SafeRelease(T **ppT) +{ + if (*ppT) + { + (*ppT)->Release(); + *ppT = NULL; + } +} + +// Function pointer for the function that transforms the image. +typedef void (*IMAGE_TRANSFORM_FN)( + const D2D1::Matrix3x2F& mat, // Chroma transform matrix. + const D2D_RECT_U& rcDest, // Destination rectangle for the transformation. + BYTE* pDest, // Destination buffer. + LONG lDestStride, // Destination stride. + const BYTE* pSrc, // Source buffer. + LONG lSrcStride, // Source stride. + DWORD dwWidthInPixels, // Image width in pixels. + DWORD dwHeightInPixels // Image height in pixels. + ); + +// CGrayscale class: +// Implements a grayscale video effect. + +class CGrayscale + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >, + ABI::Windows::Media::IMediaExtension, + IMFTransform > +{ + InspectableClass(RuntimeClass_GrayscaleTransform_GrayscaleEffect, BaseTrust) + +public: + CGrayscale(); + + ~CGrayscale(); + + STDMETHOD(RuntimeClassInitialize)(); + + // IMediaExtension + STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration); + + // IMFTransform + STDMETHODIMP GetStreamLimits( + DWORD *pdwInputMinimum, + DWORD *pdwInputMaximum, + DWORD *pdwOutputMinimum, + DWORD *pdwOutputMaximum + ); + + STDMETHODIMP GetStreamCount( + DWORD *pcInputStreams, + DWORD *pcOutputStreams + ); + + STDMETHODIMP GetStreamIDs( + DWORD dwInputIDArraySize, + DWORD *pdwInputIDs, + DWORD dwOutputIDArraySize, + DWORD *pdwOutputIDs + ); + + STDMETHODIMP GetInputStreamInfo( + DWORD dwInputStreamID, + MFT_INPUT_STREAM_INFO * pStreamInfo + ); + + STDMETHODIMP GetOutputStreamInfo( + DWORD dwOutputStreamID, + MFT_OUTPUT_STREAM_INFO * pStreamInfo + ); + + STDMETHODIMP GetAttributes(IMFAttributes** pAttributes); + + STDMETHODIMP GetInputStreamAttributes( + DWORD dwInputStreamID, + IMFAttributes **ppAttributes + ); + + STDMETHODIMP GetOutputStreamAttributes( + DWORD dwOutputStreamID, + IMFAttributes **ppAttributes + ); + + STDMETHODIMP DeleteInputStream(DWORD dwStreamID); + + STDMETHODIMP AddInputStreams( + DWORD cStreams, + DWORD *adwStreamIDs + ); + + STDMETHODIMP GetInputAvailableType( + DWORD dwInputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType + ); + + STDMETHODIMP GetOutputAvailableType( + DWORD dwOutputStreamID, + DWORD dwTypeIndex, // 0-based + IMFMediaType **ppType + ); + + STDMETHODIMP SetInputType( + DWORD dwInputStreamID, + IMFMediaType *pType, + DWORD dwFlags + ); + + STDMETHODIMP SetOutputType( + DWORD dwOutputStreamID, + IMFMediaType *pType, + DWORD dwFlags + ); + + STDMETHODIMP GetInputCurrentType( + DWORD dwInputStreamID, + IMFMediaType **ppType + ); + + STDMETHODIMP GetOutputCurrentType( + DWORD dwOutputStreamID, + IMFMediaType **ppType + ); + + STDMETHODIMP GetInputStatus( + DWORD dwInputStreamID, + DWORD *pdwFlags + ); + + STDMETHODIMP GetOutputStatus(DWORD *pdwFlags); + + STDMETHODIMP SetOutputBounds( + LONGLONG hnsLowerBound, + LONGLONG hnsUpperBound + ); + + STDMETHODIMP ProcessEvent( + DWORD dwInputStreamID, + IMFMediaEvent *pEvent + ); + + STDMETHODIMP ProcessMessage( + MFT_MESSAGE_TYPE eMessage, + ULONG_PTR ulParam + ); + + STDMETHODIMP ProcessInput( + DWORD dwInputStreamID, + IMFSample *pSample, + DWORD dwFlags + ); + + STDMETHODIMP ProcessOutput( + DWORD dwFlags, + DWORD cOutputBufferCount, + MFT_OUTPUT_DATA_BUFFER *pOutputSamples, // one per stream + DWORD *pdwStatus + ); + + +private: + // HasPendingOutput: Returns TRUE if the MFT is holding an input sample. + BOOL HasPendingOutput() const { return m_pSample != NULL; } + + // IsValidInputStream: Returns TRUE if dwInputStreamID is a valid input stream identifier. + BOOL IsValidInputStream(DWORD dwInputStreamID) const + { + return dwInputStreamID == 0; + } + + // IsValidOutputStream: Returns TRUE if dwOutputStreamID is a valid output stream identifier. + BOOL IsValidOutputStream(DWORD dwOutputStreamID) const + { + return dwOutputStreamID == 0; + } + + HRESULT OnGetPartialType(DWORD dwTypeIndex, IMFMediaType **ppmt); + HRESULT OnCheckInputType(IMFMediaType *pmt); + HRESULT OnCheckOutputType(IMFMediaType *pmt); + HRESULT OnCheckMediaType(IMFMediaType *pmt); + void OnSetInputType(IMFMediaType *pmt); + void OnSetOutputType(IMFMediaType *pmt); + HRESULT BeginStreaming(); + HRESULT EndStreaming(); + HRESULT OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut); + HRESULT OnFlush(); + HRESULT UpdateFormatInfo(); + + CRITICAL_SECTION m_critSec; + + // Transformation parameters + D2D1::Matrix3x2F m_transform; // Chroma transform matrix. + D2D_RECT_U m_rcDest; // Destination rectangle for the effect. + + // Streaming + bool m_bStreamingInitialized; + IMFSample *m_pSample; // Input sample. + IMFMediaType *m_pInputType; // Input media type. + IMFMediaType *m_pOutputType; // Output media type. + + // Fomat information + UINT32 m_imageWidthInPixels; + UINT32 m_imageHeightInPixels; + DWORD m_cbImageSize; // Image size, in bytes. + + IMFAttributes *m_pAttributes; + + // Image transform function. (Changes based on the media type.) + IMAGE_TRANSFORM_FN m_pTransformFn; +}; +#endif \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj new file mode 100644 index 0000000..8af8f2c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj @@ -0,0 +1,313 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + $(VCTargetsPath11) + {BA69218F-DA5C-4D14-A78D-21A9E4DEC669} + Win32Proj + GrayscaleTransform + GrayscaleTransform + 11.0 + true + + + + DynamicLibrary + true + v110 + + + DynamicLibrary + true + v110 + + + DynamicLibrary + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + + en-US + + + + + + + + + + + + + + + + + + + + + + + false + $(Configuration)\$(MSBuildProjectName)\ + + + false + + + false + + + false + $(Configuration)\$(MSBuildProjectName)\ + + + false + + + false + + + + NotUsing + _WINRT_DLL;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(ProjectDir)$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(ProjectDir)$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(ProjectDir)$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(ProjectDir)$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + NotUsing + _WINRT_DLL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + + + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + false + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories);$(ProjectDir)\..\Common; + + + Console + runtimeobject.lib;%(AdditionalDependencies);mf.lib;mfuuid.lib;mfplat.lib + false + Grayscale.def + + + mdmerge -metadata_dir "$(WindowsSDK_MetadataPath)" -o "$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)" -i "$(MSBuildProjectDirectory)" -v -partial + $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd + + + + + + + + + + + + + + + + + + + + + + + + + + + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + $(WindowsSDK_MetadataPath) + true + true + true + true + true + true + %(Filename).h + %(Filename).h + %(Filename).h + %(Filename).h + %(Filename).h + %(Filename).h + + + + + <_MdMergeOutput Condition="'$(Platform)' == 'Win32'" Include="$(ProjectDir)$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd" /> + <_MdMergeOutput Condition="'$(Platform)' != 'Win32'" Include="$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\$(ProjectName).winmd" /> + + + + + $(ProjectName).winmd + $(TargetName)$(TargetExt) + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters new file mode 100644 index 0000000..92c2c9c --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/Grayscale.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + bdc52ff6-58cb-464b-bf4f-0c1804b135ff + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl new file mode 100644 index 0000000..de81380 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/GrayscaleTransform.idl @@ -0,0 +1,11 @@ +import "Windows.Media.idl"; + +#include + +namespace GrayscaleTransform +{ + [version(NTDDI_WIN8)] + runtimeclass GrayscaleEffect + { + } +} \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp new file mode 100644 index 0000000..ad67670 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/MediaExtensions/Grayscale/dllmain.cpp @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////// +// +// dllmain.cpp +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +////////////////////////////////////////////////////////////////////////// + +#include +#include "Grayscale.h" + +using namespace Microsoft::WRL; + +namespace Microsoft { namespace Samples { + ActivatableClass(CGrayscale); +}} + +BOOL WINAPI DllMain( _In_ HINSTANCE hInstance, _In_ DWORD dwReason, _In_opt_ LPVOID lpReserved ) +{ + if( DLL_PROCESS_ATTACH == dwReason ) + { + // + // Don't need per-thread callbacks + // + DisableThreadLibraryCalls( hInstance ); + + Module::GetModule().Create(); + } + else if( DLL_PROCESS_DETACH == dwReason ) + { + Module::GetModule().Terminate(); + } + + return TRUE; +} + +HRESULT WINAPI DllGetActivationFactory( _In_ HSTRING activatibleClassId, _Outptr_ IActivationFactory** factory ) +{ + auto &module = Microsoft::WRL::Module< Microsoft::WRL::InProc >::GetModule(); + return module.GetActivationFactory( activatibleClassId, factory ); +} + +HRESULT WINAPI DllCanUnloadNow() +{ + auto &module = Microsoft::WRL::Module::GetModule(); + return (module.Terminate()) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject( _In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv ) +{ + auto &module = Microsoft::WRL::Module::GetModule(); + return module.GetClassObject( rclsid, riid, ppv ); +} diff --git a/samples/winrt/ImageManipulations/C++/Package.appxmanifest b/samples/winrt/ImageManipulations/C++/Package.appxmanifest new file mode 100644 index 0000000..c72258b --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/Package.appxmanifest @@ -0,0 +1,39 @@ + + + + + MediaCapture CPP sample + Microsoft Corporation + Assets\storeLogo-sdk.png + + + 6.2.1 + 6.2.1 + + + + + + + + + + + + + + + + + + + + + + + GrayscaleTransform.dll + + + + + \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/C++/assets/microsoft-sdk.png b/samples/winrt/ImageManipulations/C++/assets/microsoft-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..1a1aec25b67aa1dc55663bdc58da2083107eac0d GIT binary patch literal 1583 zcmV+~2GIG5P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02y>eSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+-&gq_R)00o~(L_t(oN9~visFhU^$9--EX8GC_#TFqg zGsMa^)1tx*B!f1x#mt4MtcW-#S%BUan9FL&TqXX@G&Z||Ep!@D z+1O23l5Bln^t!^c!t;TdO&cXe2h?ylf!crt^xI$fp@!Vy;*S+hGz@8aWB)@1vTyg~ zg9k;A3j6(FPi%VoQhH%YUEk&vBGx6E9r@~hvn7zcm zKq$ItKZo&^0P6b#)BmWx9|;=%U;$py`oD{Rsn9L-4AS=tCHDNPvE$9*eMR4%_V4T5 zsIi_xM~Tj&eZhNN*g=>sOl>GIn!stK=+{!dmBwb5jNhxV{nPl>qSq0gsl%8llA)>a z^*zWhX^i0e_;;cStn+3?V4gBQdhQgs0lyd@ds~G80!@$W;ShbFc;}1$qz+rM56Lq4 zZ<4T2qk*BD$_m{vyJ`IMl1-6Law?oE-mPg4H(sJx zY@GFWO6#KYHG%w3Iw2+Y5V{K!l5Y0c%TgSjrtfK_XimQK=7voK&G}>N4nQqIDZC{q zT_l>mytaQf)?T3v{;*Hu4qnguZuS$@n05AtLU<{ zk6wHU?4~6LqqoL?G9AnHO;<(1^`-%X*Rm5$V?kPCZ4Ssi0ylwqrwOFCY(tf%GkhbB z4>jFgHHN)@IH^Z38jm3Ni@-R4MN>fug+&ibYRb|AqqwfLsctOSowtkg+LBQi;Ez;t z?_@)+FV*ybyO}l!OkPqMe;=Pyl-Pd%FPh;HZwFPfD z-V)t{ZHeFhZv-ZHQ=Cv7vN&yw)5U3Ak@y7bj>H=$+H*fat8^s#Jwou*NTGPMzd~Vl$Y0Tv~?T3WHpPF3dVVdelQCh9)!ilHE znj`f6Mai1X;V_&P^3;)=OXQKAC-e;Yg-Lc~@cA!CKCsLFaZo}jZ7Ox5iV?v-#(3j{ z$0>7JYRmA%n{G~}2p=cVO5=QrF-~q1`iD;546buZHb~=iP`rKk5BAprL8a-Swyg5+ z717j~a|LPww}cyt(^d+c{Lv}!1m{qJw8mSFhb0G*zfnncPTFfFU}48-jq#YI2J>Dz hxT(Obp8Vf?;4d8suiatp%?AJg002ovPDHLkV1jTD8!rF= literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/placeholder-sdk.png b/samples/winrt/ImageManipulations/C++/assets/placeholder-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..01b3138cf8c040c54f3a200b2052f94a10240ded GIT binary patch literal 8991 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 LTB?Ottseaktfbe2 literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/smallTile-sdk.png b/samples/winrt/ImageManipulations/C++/assets/smallTile-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..5546e8b24a69738114bc17b2b2d493a6872d67ad GIT binary patch literal 1248 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m{T%CB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTse|n3$Sa zTDmy9nj4$D8X6i}IGH%PI2*Va8n{>*8k#!7%)qAC)y34v)Xdz{*vZAn(9qS;($vJl z)xyQx%*e^f(b2>Zrq?sCxFj(zITdDaCeU7}UJJZ>t(=Qe6HD@oLh|!-U@0IVBfliS zI3vG6!8zDeAv`lLCBM8F6gd#Tx}+9mmZhe+73JqDfJ4_R6N~M}u1=N)CT<3nuErMF zeGSo@LQaV310ACeN*YK>1ttVce;_72;R8AFtdp7t%r8a2jPa$hZ3Y7aqmZYIV@SoV zH(|GVn+U)puN1)>GjWDYb(7@t?Y2iuo7SC^e(wK3>@~xg zMI8?7PRhyOSNeDN&u*(nlZ&MfRzH8rq}_NqyH&<=^8B|I4LQ+k9H%eLW)>+)vZ|V=`jsDXVcc>oTy0n3v?M%&Q3sa2+aW|74&4eCtU0$WI7BOyoPGRM@CzI)G{Td{9My9)pICP(!TIQd&%E34(}N-e_yy&h_tq=Dpr8?}sTnpr6>ge0Hke>!%qVM5&;0f2Jn_m;*}^(UWfQgfpiQ(a>V(NLXiYC;HWpw3k|fv zB7M=P(Mazw{BLLz06@|k}+8u999Rp=A%Q#28p8q026a^5EA8&CIP+BzL-E$ z5U;WZ1jKlof}9QPAa+5PXg|zx3IXj%v3EjI{87fAFNQ9A1 zK_78p;`_B_T@di23(4OU^obP0?j+C>M?eD&bRgO&h#>@M2-Sfe(l;_P0t59RP>3!> zPZz4E4K;!t(t|-Dz|S9$I2*y+2X-26^*NW=G6ngONI@`N-O$ibozO!%ID)S()Y#Z~ z4MR^)TkN4t3=1S7$=ZQLjdcV#nusD`f=C!#AaD&4>4gg>nS#VjKb3$Dva|aWIFR_c zQR0^Al955WP#uUa7Q0s0M{gqOH2S}3eAS!i6c&WmJ&h*ff(a<`JbX0PgT=l3`$TJw zVm2@b0!BO(WB?q83dW)XNj7j(kobv?H^v*LZ)BivYz((NW^~Bt7!(RUY@u%fw}il< z5V$cEYH)NN<7=@7`bK)jhI)pF;D&lo=rQO~OSpjr#K6GP$k4#T0197^wFxAWkbx-l zdR~k;@8?*9zm0`i63|Ezj^KpD1+4FYlYTf7j_8LA0$Ms60G%;`-ndZW+HgMA3P%$# zA!u(a0uBrO*j*UrE7||K>QAxW|C^5Kipl7%ZH+Is%KDOc|E=Brx$(uupGOBBC_XO) z@xhS4pqLB*>{zjZA9W&g#@{61hY*Sv+m5)T0+b}=Bvd41E{U%VaThHi>Y1|RvbI|+ zw@k=ZJvsko2$u+`1`HY(#4C0`53{LTETb$>3x&4;fIUU4nHvFs7-;~Yb`t>D0|3a1 ze+9M}el#z7O8#kXR06D-KRn&=(MxQu1+ANFLH`+J&1((ve~j^EVll1t#Qz!NOY)z2 z{5{5(2tgdVsvny!d+2N)KOgOxdVkw-BraF?;GNO za9OEniGGuBu)16 z$>uEcspvWKb+0@@sF06pX&NeVHU5rX6F5-wvIBVp@ zXDRl~j_4e_Tl^-YaYilOeAiD*|K{A7WFK{->m?vKBL~rCZb32)S%{f#^HRvUdFrq( zF0A_!TEVVQ%bto6a@0<*o(eD9Z+(q`Yx}O|?v9-S398A59#s`S^kVXz!=CBA<#efc zsh*F5mcKvl*k8a87xt2+cFx_95oNe*csmMV5oS9BAV0eeD^a=;)cksx&SxE1;xJex z3wOC8&0-3NQYL47c*lZlZ|>N#8YC}AlMrn;e9b7ds0 zO=3?fGo`f!A>THu9iij=VC8rhBir(2m&*Q)G18kB4f{i%{Q-Im3^7&J+DvUTXz<&` z$QthwWf3$J|BwodRn6LgnC8PlO<8#n^%8z&Sb8y zQU82iy-(NBbaZCNYb9~*MYZXxKbI;D#^-uf&J@SvUb9JulO3szm|X#>5Xw)KrOB$j zVE(B{%LyRk{LX3n_Y3se%3-NtmJ9(j84SmsymYJRBCNpecmXlOe>fn z-V&UdsI)Q4u0Qn{UlT7kT2cO{cVd~p>h99dE2$bdxKxv4u*!QqQC`(5x;5Yup=t|T z37oE2SurUjFOR9RY2?BTh)Pn})*}D*p~z0tfyL(V#qIpi{waKAbK?*l%qvy(Jom7F zWKfVKtgQDB0WPQ8z+!qJ)-vc1zPo#b)TZssqlgaQ8mv> zNr(42u_MpFy7LOPAHSLV!OylId_>z?Ha@2>J1_EFl8J4SiM6syQ!Z{G{5t(i4zEWu zeq=C=A7LDtROB`+=u4`2wHc9~l=z{ey0vP_o`pFwyW&KJJjvji$(Y=aY7iyS=^|vLO=7Bu6BRl!*};Rl)2P-*Ypn~=+y3I%H7uAD&Encu{-I9<0~hp z6!VcCa|I~|rA0x+-!}+gb#$Du9$_4KX`v;uZ3u6sbGVKU#!*Qt+sE;H{f*v7FSZ!RZKar(0Rb1AwH~z2Bvw?@iEVL%fBVvE5Pr(^8w6 zqDY5&m9Q{vb~?+YN;%_%y?W2v22NH#Y9|BR{lvR8O&*_`HmB(&$0lW?ORD@txg7$}W<9QLg5|L$UsO*#y?2d=r0jJkz76iRoo$<`Ze(f9^@2+< zkRs}<#-+pJ!@_fxsUx!5hni{nXODp!C9UEG)1en?!or(t4Y%=m2g)V3#z_f4 zUzU6NS2(yTyH&pb!zN=-&zZBX1)w}!kYVC)!xt}6of)aJm)u5CO9Je$>7B}fa=RhX zcOKstJ|PzkwDWemc%%)|7eLW+W)~Q)mpm^k`4etER6a0TDD3@yWkizMc=G7Ck-zXY z5SHKgvQuc>ifW|H*prLq>r9QV^A{{eSPX!Xj& zjbjL_{JknQo-Z^K62j)Qet25D|DLwWIR(SsD`!gUvIU59+vu0Mi4xPVM_N#uWwJOg z%xoqMuZ{9s&Nw`nzR^%xgMda48S@$-dh$E6xq3s&J79=-!;MO>-CcjPcYt>>hEbhN zj|`j$6<=be^{Y;+QTY(RByl0KrOHH}g8zli6&;A;-MxNyPoVI*B0EJ}!-4zM7$5cS zscT1b20hB@9yU$PswIGp+~|u3^>7*n9@B294gJyNvUq&L0UYko>g=}n^y2dE9J};u z%BWO1L0?FOY4G5Dc9PmOMJsuqnL~HSJge)0AB!EK&5;cVatYQzv1MvQ0&>dok5E@# zUSIHdoKGb=xXrzFC95c*m4>8tLthj2m?c9v{edPqzL*{jT20(A(zK2%9g`THSn=|F z2OL37>n!%H^i@;$iQ7`3!$)5|8K7rgnl=oyT6!R9o%D_9c|DEvp(OGV{6*$?{cHuZ zcJretn4zS$V8>wO6ZYX9fDN?`8M~9GvYgLOVr%X?TkqcMvA-u)(HNr`fxqbw`;|!F zO0S4iqPph&JUOeHQKo#Z%BlMSyM3t-T>qS`Or}KZt|}E7NySJPnt)EKC~y_e;Rcfz z@6l)s!Pu?_xz>4wxeJQB3+8pl7qjei6XkcvAe_>#P27?f^`)RO;g^K?N6SmM84UkP ziIcXMO*m!czt2Y9hg0RoKs|4phJLK!Gy5y8&MMz2Z(#NpX-@w7CfGdtSVGy=>1X5R z1lL&kunb|Q^}ncD*1DTqOdifoc+8xOA62dzAu?iHCz7{W`Kgx6VYe8Tow~kV{#>Vg z$fAYTnBA5ldagS&9(#wASn*!&rM;sdvLu^5IOFA@GK!)m(7UxyWMrND8P7r>gX zoo!?PdTi=Ccu2O@c;DLmj^X8cXrodE6iRY3siuH`pCZNM85^i+vvPN`I|2vpB~OXm z>^&=_`21otc*Kr|t>3SE!cE7z%jbK%LVnxttnPy)1I@5)eBbavbkuE`-Ps;L{zN(6 z-Md|>)!697yCYMQ8lr(mRs4^O3qx3yUWzl0xQ{$ec11uVRs|-cAvhA z714Q^UzNf3b6XKHA{c7i3Q;o?-P9?&r`p_3g7K5OhCg+3^~0vd_iW{=*t9vlWxfe9 ztfmNqs5Q+Cq$U$?K5lBvDyTP$?Mx%R{&xA4f;5+A3x47Psqt0!#Uky*9y$Z61r$hz=1>QzG{9d0Z^ zW;>GYm&C3>T=2&Vb?eonS=roU>(8h^m6LA`gpjizS!|0;ZqDalbgDVS5OZxH) z7xqdS3rAA(= z2C_=Yb1{1xy*PSgpEKpjnjB+*HmiIRWM2r7wFjS7%U2ZG-z%SWG4%z;KPaDnS73ip zK7Y|2ANAr_^v@UMzowr49b?VwbK-SH`u7mp!LQZc9$K@p>LCn)az@bsMBUpvp4neYAPeV_OG zoin*nt3zyNI?cr4a5kJ!kc+(!ns3YL*wg>BjSsQc0u?(}6$2-!G-3q8F{N-Kgy+b` z>me>AmZopK4*BD77E&26Ruvl&&XB-zlGv<6N|P%wYm6o^O(~Y7LMnVBv|gqNAPhD% z67Vu<0D<)tejG8aN&H6p?Kk>oOIjMeVX9hnueXc&=*3~P#b0|-mha!8@# zfB^*T3rQ-IGAK;84@jZ2*iPVL;(Q`NCyBP<|N0bY-zzv7By%&(~AXq z0RS6d0>M;_jYbLb@ecM{?mcPCQJ^ZZLIO?tm0^BA*wX*hmJx(NVik<=V0gpi1Vkmn zDi}?MmH40-A3R^Ckir_&+?@Bhf)FCx1WAJtSdO2lE<^SS?<|TJ)0@p^(y=fHktOG8PQkJR1KoDwA8-{F#>@2OkqY9vw)5ofiZ<81CJbt~lJZJ`Tv_rFA|n&f8e# zZ@W@WORzY%u6mJLVvFA)i~7r>AmGH>_)+3VyyBxWv!Q_^*Yg+TjCkuY*?EXJ%C&ZLc_TFUhB@tlPKZ ztuQIYLNMqid6%PJV$8LS%K7SL_)v88<3F-zz=d?{D?YBDk z(@kr0US82Vnfi$6EjP7mr9NXVqdWecyFu9bQ+-vz8~*Jvx9S@}PI#nNetuSS!i8wk z+2%t+i}JEQOZ7g#c_LBGC{o4ST9^^)NT7?J5)0N#T*h;_Wx;TqK{z%zf-s~q+YwB9u^OgKBG`gUUdml{92j!Tihu~5eK)(TydZIShZuokRiT}2N0 zcDc2}bHhff=9HgJPtLf-jEF`G_WFA6JJQ)tb$hmVhTVW;aR_-}cG$zM?sa9##irpc z<&R9Eq<CAi4DOoQ%=KG!OUUvWW#nHkpQ#kO{GHv}x)0)lUe%p1v zL%`CXz;=(464l$UN(Pd~u6Y!+_QyDFdT=0p(Y!NmdYhq;8m)2hzSOXmU)tVLhkyGc zF~;%vBmOe}1}F9bBmR~m!XbgLKWR8P+QBib-tiabEv)6`w%^YW{6}_dhW_G+^FC7K zkvB!3J8O+ct8^=>yBb0}b`Ge|l+VpAZvSFftI+ibddotU*X!`{FA_jPVWDxa^xdUq zq+T0wnf!A6Rlfo5wU>UwtMlr*`CVPU#q2q2kjo0e5r6pT543r02EiydC0Asaw!_BW zB(j9N38zY zVSnnVYg@*N=YGSlDqVZC^-JyRY6^JHUNANN_oKml)nKDbi%`78&Lwkq>3n8lOaK(M z%XIY)`(*v_R>j{Wk6lNV(-IeGdy{*z&OsHogMSnZ|3Tg#&#R$#Tys~HmZY1|0$u&~ z8{Z!cZXd0F3%?F04BZXB^SFofI5YqCEdel3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8Xy|HaX=q~T zXkuhyoy6KF3~uM1wiR?bDKi6!|(A^G_^uoMuGkzbNu zoRMFk;2dnK5T2Qrl3!j7iX4bvT~doO%TiO^it=+6z@clEiN$tTLlY-cQ*#SPb7Kqa zzJ};cAt%K2fsWA!B@Lvc0uutJKM)h1@PQn7)=A9+=9eO1#>h2t<6vN5a`1F<45_&F zCgNglvw^_UQ1K63?>IoPgvE$SQc9`RFR@5oEMEQcuh2HP zp6FYXzh@K|KXK{P|2wZ_Iz!UOKY}UZOO97`J6F2O-)1bnXSiIfU8r#i)0E?L&d-t2 z)c7~uKsr%c^Nr5aQ$j_iEzTP2CUULicAD~e(?KcrHI`iRGF9`Xqr9aHn7pUHd@)Un zYj5;f1(o7sYHzMT6tnTW>+t@;Wxnk!*_3;D;aQ7@>=7RYwcvWU3HaL8rD zamEmP#-v^oIY;GJrcGr_YyWP$|7PL>Nd~R3E+*rLwl`M(?ya};313mc{QT!#{=kD~ z*_z*~*>3GM0X=d#Wzp$P!Xu`&Pv literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/tile-sdk.png b/samples/winrt/ImageManipulations/C++/assets/tile-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..cdec0dbdccad7ae5dd0e92e3c3015449fffb7450 GIT binary patch literal 2665 zcma)8dpwj`AD^(gN@_z1&pSR_@0Ph|CX;bDv1_Dpuf%xfF$Ocwm>HL$5^q~u7S+3& zTD-Ok5}6Q6nB-Pe79nQGbi)dHH^jK^u&Le8=e6%Xf1Kx>^ZS0kzu!6M_xYW3%GG6$ z)~d~`5D0{plcPNyfmlXV_0O-+RJHCMS4UL8O+p86p&J}1jAZa3gbfo8fB+{Bg9Xtc z22&LF5VAlZ)B(1;x6qsBOa@^NnlX<-M{#&6HUeQ`6~$wKA&?LVfLLrU1vz|IiUin9 z3ewArhNbcBpdhwmG#_${c5w%zLqKyT(#jIBh$5>5IFOJ5L~%m70&)}uxu8o{_2;KC zNMHdX451)@56YY73fRGX2rxrqQ6QFx1&BB_j|#1#k`To7`yryx~)G@H#N6A9)HW;k;^k$|?KuS)BlTqYX-%Ae=h|P1LEg9mWlnv{$CwipSRw5W!7=Gl{Lv|$c&&wI(fkRs zU|z&5m=`hsM?z)(;O1{jWK<1uq7yUx#%3OaYE=>Oc0k_VAnz%Ys)BE!w}l;RWk)8z z(VENsO!gwpvfivAyHe0KY8rXrP=K=c_{hkX#>B^dA*a(?jrF?TX05mq{A2T$rv-;I z$g)GLQthe-50+`?nAorF8~K&f1xcDT?^m3L8awoS^t+|B+_)o2M|S0bvx#3RHK)Q97{jhg}3G8uH@@X&CJqU`E#W{P30#``^{%(OwJD-=-tyauopL0;VGqI3c5q4 zr*$ObhOaD=K;y>j@OB(*Y&F$>fHn1Sym(M#EK#3=slAk%n1|!amZGMfQyrkraP~!> z)-W|mGF&kTS}6x41?jgc3I-VXbg1n0kWp%YDJoLz5y0_884jFCy2t_@V*^{WqK&Vj z#j#K7hFadS*9^0nR!#e8^3SKrl7nC8{Bpi&c{jLWmq)wKWPA5!c}o(GC~7L-m_Cc3yhuqVprfBOTg1$Tmq++%`0NgQG)Qb0okCcS zk9B*@D2`=mr`HE}>8<&1fBcQj`m7M-x`@t+M|s|8?Qg!+3NgcXlQ8jD%v&B1)xof_ zvtup#a{1X2R~F;h=%WFHf!+0#aD@pljC}qB!EZ!qJ$7e9@Zl7H8MCd!Rj(*Pv;3cG z%mXw7edEMLDMZOdby>zc2ah&@JVyxK?m{O#8snd zB#U9q_hK$7E?2vRqqBV^4jt&zytD1ruf;jKdWR&rv&!4_1MZjmDJ7le!AZhu7>vQR ziRvEGNi$i|(y(#Xj$-A#llvm;X70rrh34!dIf$7uw@y^y^HeXtkYnZ^naWn(qCtz- zRfkyezQXmBx(s)(K7(yCY7o(?6Gf}9*p%~{3*O1hsxMwH+d6PUivpeTLWS#Ui1`h) zOGVoG;&%DQ#y)xL)3(9rUc+2ZFQ0p;CVlP^Kc4g1q`SM{{bQW6-Q`7Hn^&lZr_L>t z#!LgqOV2XP*X;0WYFjJkQF7Q(Tf|d!5BC1jHIkC(IW;IO;F=`B;PJKz%Ko~rjCVcv zvZ7<@FI+af-v2L@hhJkH+H-cbpZ4+lUtE7MhDOPlqpA&Q6Tso6^`10k( zB-VRlVRfHXfnwSz-fc%$z3I=vkI#gxDJkFIxg}>XP@`eQuV@r|{P(a>u6% zbshAL;`_fWk*`fVne`@i^!iZ$+wJrA7$N>k51Z_K`RLmbsqYJ5Ae zpDHirz501}!eNS?kO8L1^C!)ktV)`Jj^`)VJh@*TSEK%sN(#lz}UAsoG zRciR3+%kN&g+^=xSy?_x3snMB(~e+cy^QWP;%#Cq>n)f`f3<94`odnN$+D3+?MvMI zW0MyJYI6zx>iRu%7OIN=he92%^@l>eWF=PB=s(r^zbEmR*TvEjf4XsIX4m^8zOJ*{ V^V80WL-UV6CkGe%d|Utc-vFTWTn+#L literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/assets/windows-sdk.png b/samples/winrt/ImageManipulations/C++/assets/windows-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..67268021df6fbd0dfdd5220f669db5e07d83f620 GIT binary patch literal 2997 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 literal 0 HcmV?d00001 diff --git a/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp new file mode 100644 index 0000000..9449fbe --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.cpp @@ -0,0 +1,452 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#include "pch.h" +#include "LayoutAwarePage.h" +#include "SuspensionManager.h" + +using namespace SDKSample::Common; + +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::System; +using namespace Windows::UI::Core; +using namespace Windows::UI::ViewManagement; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Navigation; + +/// +/// Initializes a new instance of the class. +/// +LayoutAwarePage::LayoutAwarePage() +{ + if (Windows::ApplicationModel::DesignMode::DesignModeEnabled) + { + return; + } + + // Create an empty default view model + DefaultViewModel = ref new Map(std::less()); + + // When this page is part of the visual tree make two changes: + // 1) Map application view state to visual state for the page + // 2) Handle keyboard and mouse navigation requests + Loaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnLoaded); + + // Undo the same changes when the page is no longer visible + Unloaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnUnloaded); +} + +static DependencyProperty^ _defaultViewModelProperty = + DependencyProperty::Register("DefaultViewModel", + TypeName(IObservableMap::typeid), TypeName(LayoutAwarePage::typeid), nullptr); + +/// +/// Identifies the dependency property. +/// +DependencyProperty^ LayoutAwarePage::DefaultViewModelProperty::get() +{ + return _defaultViewModelProperty; +} + +/// +/// Gets an implementation of designed to be +/// used as a trivial view model. +/// +IObservableMap^ LayoutAwarePage::DefaultViewModel::get() +{ + return safe_cast^>(GetValue(DefaultViewModelProperty)); +} + +/// +/// Sets an implementation of designed to be +/// used as a trivial view model. +/// +void LayoutAwarePage::DefaultViewModel::set(IObservableMap^ value) +{ + SetValue(DefaultViewModelProperty, value); +} + +/// +/// Invoked when the page is part of the visual tree +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + this->StartLayoutUpdates(sender, e); + + // Keyboard and mouse navigation only apply when occupying the entire window + if (this->ActualHeight == Window::Current->Bounds.Height && + this->ActualWidth == Window::Current->Bounds.Width) + { + // Listen to the window directly so focus isn't required + _acceleratorKeyEventToken = Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated += + ref new TypedEventHandler(this, + &LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated); + _pointerPressedEventToken = Window::Current->CoreWindow->PointerPressed += + ref new TypedEventHandler(this, + &LayoutAwarePage::CoreWindow_PointerPressed); + _navigationShortcutsRegistered = true; + } +} + +/// +/// Invoked when the page is removed from visual tree +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) +{ + if (_navigationShortcutsRegistered) + { + Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated -= _acceleratorKeyEventToken; + Window::Current->CoreWindow->PointerPressed -= _pointerPressedEventToken; + _navigationShortcutsRegistered = false; + } + StopLayoutUpdates(sender, e); +} + +#pragma region Navigation support + +/// +/// Invoked as an event handler to navigate backward in the page's associated +/// until it reaches the top of the navigation stack. +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::GoHome(Object^ sender, RoutedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + // Use the navigation frame to return to the topmost page + if (Frame != nullptr) + { + while (Frame->CanGoBack) + { + Frame->GoBack(); + } + } +} + +/// +/// Invoked as an event handler to navigate backward in the navigation stack +/// associated with this page's . +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::GoBack(Object^ sender, RoutedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + // Use the navigation frame to return to the previous page + if (Frame != nullptr && Frame->CanGoBack) + { + Frame->GoBack(); + } +} + +/// +/// Invoked as an event handler to navigate forward in the navigation stack +/// associated with this page's . +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::GoForward(Object^ sender, RoutedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + // Use the navigation frame to advance to the next page + if (Frame != nullptr && Frame->CanGoForward) + { + Frame->GoForward(); + } +} + +/// +/// Invoked on every keystroke, including system keys such as Alt key combinations, when +/// this page is active and occupies the entire window. Used to detect keyboard navigation +/// between pages even when the page itself doesn't have focus. +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher^ sender, AcceleratorKeyEventArgs^ args) +{ + auto virtualKey = args->VirtualKey; + + // Only investigate further when Left, Right, or the dedicated Previous or Next keys + // are pressed + if ((args->EventType == CoreAcceleratorKeyEventType::SystemKeyDown || + args->EventType == CoreAcceleratorKeyEventType::KeyDown) && + (virtualKey == VirtualKey::Left || virtualKey == VirtualKey::Right || + (int)virtualKey == 166 || (int)virtualKey == 167)) + { + auto coreWindow = Window::Current->CoreWindow; + auto downState = Windows::UI::Core::CoreVirtualKeyStates::Down; + bool menuKey = (coreWindow->GetKeyState(VirtualKey::Menu) & downState) == downState; + bool controlKey = (coreWindow->GetKeyState(VirtualKey::Control) & downState) == downState; + bool shiftKey = (coreWindow->GetKeyState(VirtualKey::Shift) & downState) == downState; + bool noModifiers = !menuKey && !controlKey && !shiftKey; + bool onlyAlt = menuKey && !controlKey && !shiftKey; + + if (((int)virtualKey == 166 && noModifiers) || + (virtualKey == VirtualKey::Left && onlyAlt)) + { + // When the previous key or Alt+Left are pressed navigate back + args->Handled = true; + GoBack(this, ref new RoutedEventArgs()); + } + else if (((int)virtualKey == 167 && noModifiers) || + (virtualKey == VirtualKey::Right && onlyAlt)) + { + // When the next key or Alt+Right are pressed navigate forward + args->Handled = true; + GoForward(this, ref new RoutedEventArgs()); + } + } +} + +/// +/// Invoked on every mouse click, touch screen tap, or equivalent interaction when this +/// page is active and occupies the entire window. Used to detect browser-style next and +/// previous mouse button clicks to navigate between pages. +/// +/// Instance that triggered the event. +/// Event data describing the conditions that led to the event. +void LayoutAwarePage::CoreWindow_PointerPressed(CoreWindow^ sender, PointerEventArgs^ args) +{ + auto properties = args->CurrentPoint->Properties; + + // Ignore button chords with the left, right, and middle buttons + if (properties->IsLeftButtonPressed || properties->IsRightButtonPressed || + properties->IsMiddleButtonPressed) return; + + // If back or foward are pressed (but not both) navigate appropriately + bool backPressed = properties->IsXButton1Pressed; + bool forwardPressed = properties->IsXButton2Pressed; + if (backPressed ^ forwardPressed) + { + args->Handled = true; + if (backPressed) GoBack(this, ref new RoutedEventArgs()); + if (forwardPressed) GoForward(this, ref new RoutedEventArgs()); + } +} + +#pragma endregion + +#pragma region Visual state switching + +/// +/// Invoked as an event handler, typically on the event of a +/// within the page, to indicate that the sender should start receiving +/// visual state management changes that correspond to application view state changes. +/// +/// Instance of that supports visual state management +/// corresponding to view states. +/// Event data that describes how the request was made. +/// The current view state will immediately be used to set the corresponding visual state +/// when layout updates are requested. A corresponding event handler +/// connected to is strongly encouraged. Instances of +/// automatically invoke these handlers in their Loaded and Unloaded +/// events. +/// +/// +void LayoutAwarePage::StartLayoutUpdates(Object^ sender, RoutedEventArgs^ e) +{ + (void) e; // Unused parameter + + auto control = safe_cast(sender); + if (_layoutAwareControls == nullptr) + { + // Start listening to view state changes when there are controls interested in updates + _layoutAwareControls = ref new Vector(); + _windowSizeEventToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &LayoutAwarePage::WindowSizeChanged); + + // Page receives notifications for children. Protect the page until we stopped layout updates for all controls. + _this = this; + } + _layoutAwareControls->Append(control); + + // Set the initial visual state of the control + VisualStateManager::GoToState(control, DetermineVisualState(ApplicationView::Value), false); +} + +void LayoutAwarePage::WindowSizeChanged(Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + InvalidateVisualState(); +} + +/// +/// Invoked as an event handler, typically on the event of a +/// , to indicate that the sender should start receiving visual state +/// management changes that correspond to application view state changes. +/// +/// Instance of that supports visual state management +/// corresponding to view states. +/// Event data that describes how the request was made. +/// The current view state will immediately be used to set the corresponding visual state +/// when layout updates are requested. +/// +void LayoutAwarePage::StopLayoutUpdates(Object^ sender, RoutedEventArgs^ e) +{ + (void) e; // Unused parameter + + auto control = safe_cast(sender); + unsigned int index; + if (_layoutAwareControls != nullptr && _layoutAwareControls->IndexOf(control, &index)) + { + _layoutAwareControls->RemoveAt(index); + if (_layoutAwareControls->Size == 0) + { + // Stop listening to view state changes when no controls are interested in updates + Window::Current->SizeChanged -= _windowSizeEventToken; + _layoutAwareControls = nullptr; + // Last control has received the Unload notification. + _this = nullptr; + } + } +} + +/// +/// Translates values into strings for visual state management +/// within the page. The default implementation uses the names of enum values. Subclasses may +/// override this method to control the mapping scheme used. +/// +/// View state for which a visual state is desired. +/// Visual state name used to drive the +/// +String^ LayoutAwarePage::DetermineVisualState(ApplicationViewState viewState) +{ + switch (viewState) + { + case ApplicationViewState::Filled: + return "Filled"; + case ApplicationViewState::Snapped: + return "Snapped"; + case ApplicationViewState::FullScreenPortrait: + return "FullScreenPortrait"; + case ApplicationViewState::FullScreenLandscape: + default: + return "FullScreenLandscape"; + } +} + +/// +/// Updates all controls that are listening for visual state changes with the correct visual +/// state. +/// +/// +/// Typically used in conjunction with overriding to +/// signal that a different value may be returned even though the view state has not changed. +/// +void LayoutAwarePage::InvalidateVisualState() +{ + if (_layoutAwareControls != nullptr) + { + String^ visualState = DetermineVisualState(ApplicationView::Value); + auto controlIterator = _layoutAwareControls->First(); + while (controlIterator->HasCurrent) + { + auto control = controlIterator->Current; + VisualStateManager::GoToState(control, visualState, false); + controlIterator->MoveNext(); + } + } +} + +#pragma endregion + +#pragma region Process lifetime management + +/// +/// Invoked when this page is about to be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property provides the group to be displayed. +void LayoutAwarePage::OnNavigatedTo(NavigationEventArgs^ e) +{ + // Returning to a cached page through navigation shouldn't trigger state loading + if (_pageKey != nullptr) return; + + auto frameState = SuspensionManager::SessionStateForFrame(Frame); + _pageKey = "Page-" + Frame->BackStackDepth; + + if (e->NavigationMode == NavigationMode::New) + { + // Clear existing state for forward navigation when adding a new page to the + // navigation stack + auto nextPageKey = _pageKey; + int nextPageIndex = Frame->BackStackDepth; + while (frameState->HasKey(nextPageKey)) + { + frameState->Remove(nextPageKey); + nextPageIndex++; + nextPageKey = "Page-" + nextPageIndex; + } + + // Pass the navigation parameter to the new page + LoadState(e->Parameter, nullptr); + } + else + { + // Pass the navigation parameter and preserved page state to the page, using + // the same strategy for loading suspended state and recreating pages discarded + // from cache + LoadState(e->Parameter, safe_cast^>(frameState->Lookup(_pageKey))); + } +} + +/// +/// Invoked when this page will no longer be displayed in a Frame. +/// +/// Event data that describes how this page was reached. The Parameter +/// property provides the group to be displayed. +void LayoutAwarePage::OnNavigatedFrom(NavigationEventArgs^ e) +{ + auto frameState = SuspensionManager::SessionStateForFrame(Frame); + auto pageState = ref new Map(); + SaveState(pageState); + frameState->Insert(_pageKey, pageState); +} + +/// +/// Populates the page with content passed during navigation. Any saved state is also +/// provided when recreating a page from a prior session. +/// +/// The parameter value passed to +/// when this page was initially requested. +/// +/// A map of state preserved by this page during an earlier +/// session. This will be null the first time a page is visited. +void LayoutAwarePage::LoadState(Object^ navigationParameter, IMap^ pageState) +{ +} + +/// +/// Preserves state associated with this page in case the application is suspended or the +/// page is discarded from the navigation cache. Values must conform to the serialization +/// requirements of . +/// +/// An empty map to be populated with serializable state. +void LayoutAwarePage::SaveState(IMap^ pageState) +{ +} + +#pragma endregion diff --git a/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h new file mode 100644 index 0000000..bd71062 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/LayoutAwarePage.h @@ -0,0 +1,88 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#pragma once + +#include + +namespace SDKSample +{ + namespace Common + { + /// + /// Typical implementation of Page that provides several important conveniences: + /// + /// + /// Application view state to visual state mapping + /// + /// + /// GoBack, GoForward, and GoHome event handlers + /// + /// + /// Mouse and keyboard shortcuts for navigation + /// + /// + /// State management for navigation and process lifetime management + /// + /// + /// A default view model + /// + /// + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class LayoutAwarePage : Windows::UI::Xaml::Controls::Page + { + internal: + LayoutAwarePage(); + + public: + void StartLayoutUpdates(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void StopLayoutUpdates(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void InvalidateVisualState(); + static property Windows::UI::Xaml::DependencyProperty^ DefaultViewModelProperty + { + Windows::UI::Xaml::DependencyProperty^ get(); + }; + property Windows::Foundation::Collections::IObservableMap^ DefaultViewModel + { + Windows::Foundation::Collections::IObservableMap^ get(); + void set(Windows::Foundation::Collections::IObservableMap^ value); + } + + protected: + virtual void GoHome(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + virtual void GoBack(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + virtual void GoForward(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + virtual Platform::String^ DetermineVisualState(Windows::UI::ViewManagement::ApplicationViewState viewState); + virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; + virtual void LoadState(Platform::Object^ navigationParameter, + Windows::Foundation::Collections::IMap^ pageState); + virtual void SaveState(Windows::Foundation::Collections::IMap^ pageState); + + private: + Platform::String^ _pageKey; + bool _navigationShortcutsRegistered; + Platform::Collections::Map^ _defaultViewModel; + Windows::Foundation::EventRegistrationToken _windowSizeEventToken, + _acceleratorKeyEventToken, _pointerPressedEventToken; + Platform::Collections::Vector^ _layoutAwareControls; + void WindowSizeChanged(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e); + void OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + void OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); + + void CoreDispatcher_AcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher^ sender, + Windows::UI::Core::AcceleratorKeyEventArgs^ args); + void CoreWindow_PointerPressed(Windows::UI::Core::CoreWindow^ sender, + Windows::UI::Core::PointerEventArgs^ args); + LayoutAwarePage^ _this; // Strong reference to self, cleaned up in OnUnload + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml b/samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml new file mode 100644 index 0000000..7c3d238 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/StandardStyles.xaml @@ -0,0 +1,978 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mouse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp new file mode 100644 index 0000000..c1ecf11 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.cpp @@ -0,0 +1,481 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// SuspensionManager.cpp +// Implementation of the SuspensionManager class +// + +#include "pch.h" +#include "SuspensionManager.h" + +#include +#include + +using namespace SDKSample::Common; + +using namespace Concurrency; +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Storage; +using namespace Windows::Storage::FileProperties; +using namespace Windows::Storage::Streams; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Interop; + +namespace +{ + Map^ _sessionState = ref new Map(); + String^ sessionStateFilename = "_sessionState.dat"; + + // Forward declarations for object object read / write support + void WriteObject(Windows::Storage::Streams::DataWriter^ writer, Platform::Object^ object); + Platform::Object^ ReadObject(Windows::Storage::Streams::DataReader^ reader); +} + +/// +/// Provides access to global session state for the current session. This state is serialized by +/// and restored by which require values to be +/// one of the following: boxed values including integers, floating-point singles and doubles, +/// wide characters, boolean, Strings and Guids, or Map where map values are +/// subject to the same constraints. Session state should be as compact as possible. +/// +IMap^ SuspensionManager::SessionState::get(void) +{ + return _sessionState; +} + +/// +/// Wrap a WeakReference as a reference object for use in a collection. +/// +private ref class WeakFrame sealed +{ +private: + WeakReference _frameReference; + +internal: + WeakFrame(Frame^ frame) { _frameReference = frame; } + property Frame^ ResolvedFrame + { + Frame^ get(void) { return _frameReference.Resolve(); } + }; +}; + +namespace +{ + std::vector _registeredFrames; + DependencyProperty^ FrameSessionStateKeyProperty = + DependencyProperty::RegisterAttached("_FrameSessionStateKeyProperty", + TypeName(String::typeid), TypeName(SuspensionManager::typeid), nullptr); + DependencyProperty^ FrameSessionStateProperty = + DependencyProperty::RegisterAttached("_FrameSessionStateProperty", + TypeName(IMap::typeid), TypeName(SuspensionManager::typeid), nullptr); +} + +/// +/// Registers a instance to allow its navigation history to be saved to +/// and restored from . Frames should be registered once +/// immediately after creation if they will participate in session state management. Upon +/// registration if state has already been restored for the specified key +/// the navigation history will immediately be restored. Subsequent invocations of +/// will also restore navigation history. +/// +/// An instance whose navigation history should be managed by +/// +/// A unique key into used to +/// store navigation-related information. +void SuspensionManager::RegisterFrame(Frame^ frame, String^ sessionStateKey) +{ + if (frame->GetValue(FrameSessionStateKeyProperty) != nullptr) + { + throw ref new FailureException("Frames can only be registered to one session state key"); + } + + if (frame->GetValue(FrameSessionStateProperty) != nullptr) + { + throw ref new FailureException("Frames must be either be registered before accessing frame session state, or not registered at all"); + } + + // Use a dependency property to associate the session key with a frame, and keep a list of frames whose + // navigation state should be managed + frame->SetValue(FrameSessionStateKeyProperty, sessionStateKey); + _registeredFrames.insert(_registeredFrames.begin(), ref new WeakFrame(frame)); + + // Check to see if navigation state can be restored + RestoreFrameNavigationState(frame); +} + +/// +/// Disassociates a previously registered by +/// from . Any navigation state previously captured will be +/// removed. +/// +/// An instance whose navigation history should no longer be +/// managed. +void SuspensionManager::UnregisterFrame(Frame^ frame) +{ + // Remove session state and remove the frame from the list of frames whose navigation + // state will be saved (along with any weak references that are no longer reachable) + auto key = safe_cast(frame->GetValue(FrameSessionStateKeyProperty)); + if (SessionState->HasKey(key)) SessionState->Remove(key); + _registeredFrames.erase( + std::remove_if(_registeredFrames.begin(), _registeredFrames.end(), [=](WeakFrame^& e) + { + auto testFrame = e->ResolvedFrame; + return testFrame == nullptr || testFrame == frame; + }), + _registeredFrames.end() + ); +} + +/// +/// Provides storage for session state associated with the specified . +/// Frames that have been previously registered with have +/// their session state saved and restored automatically as a part of the global +/// . Frames that are not registered have transient state +/// that can still be useful when restoring pages that have been discarded from the +/// navigation cache. +/// +/// Apps may choose to rely on to manage +/// page-specific state instead of working with frame session state directly. +/// The instance for which session state is desired. +/// A collection of state subject to the same serialization mechanism as +/// . +IMap^ SuspensionManager::SessionStateForFrame(Frame^ frame) +{ + auto frameState = safe_cast^>(frame->GetValue(FrameSessionStateProperty)); + + if (frameState == nullptr) + { + auto frameSessionKey = safe_cast(frame->GetValue(FrameSessionStateKeyProperty)); + if (frameSessionKey != nullptr) + { + // Registered frames reflect the corresponding session state + if (!_sessionState->HasKey(frameSessionKey)) + { + _sessionState->Insert(frameSessionKey, ref new Map()); + } + frameState = safe_cast^>(_sessionState->Lookup(frameSessionKey)); + } + else + { + // Frames that aren't registered have transient state + frameState = ref new Map(); + } + frame->SetValue(FrameSessionStateProperty, frameState); + } + return frameState; +} + +void SuspensionManager::RestoreFrameNavigationState(Frame^ frame) +{ + auto frameState = SessionStateForFrame(frame); + if (frameState->HasKey("Navigation")) + { + frame->SetNavigationState(safe_cast(frameState->Lookup("Navigation"))); + } +} + +void SuspensionManager::SaveFrameNavigationState(Frame^ frame) +{ + auto frameState = SessionStateForFrame(frame); + frameState->Insert("Navigation", frame->GetNavigationState()); +} + +/// +/// Save the current . Any instances +/// registered with will also preserve their current +/// navigation stack, which in turn gives their active an opportunity +/// to save its state. +/// +/// An asynchronous task that reflects when session state has been saved. +task SuspensionManager::SaveAsync(void) +{ + // Save the navigation state for all registered frames + for (auto&& weakFrame : _registeredFrames) + { + auto frame = weakFrame->ResolvedFrame; + if (frame != nullptr) SaveFrameNavigationState(frame); + } + + // Serialize the session state synchronously to avoid asynchronous access to shared + // state + auto sessionData = ref new InMemoryRandomAccessStream(); + auto sessionDataWriter = ref new DataWriter(sessionData->GetOutputStreamAt(0)); + WriteObject(sessionDataWriter, _sessionState); + + // Once session state has been captured synchronously, begin the asynchronous process + // of writing the result to disk + return task(sessionDataWriter->StoreAsync()).then([=](unsigned int) + { + return sessionDataWriter->FlushAsync(); + }).then([=](bool flushSucceeded) + { + (void)flushSucceeded; // Unused parameter + return ApplicationData::Current->LocalFolder->CreateFileAsync(sessionStateFilename, + CreationCollisionOption::ReplaceExisting); + }).then([=](StorageFile^ createdFile) + { + return createdFile->OpenAsync(FileAccessMode::ReadWrite); + }).then([=](IRandomAccessStream^ newStream) + { + return RandomAccessStream::CopyAndCloseAsync( + sessionData->GetInputStreamAt(0), newStream->GetOutputStreamAt(0)); + }).then([=](UINT64 copiedBytes) + { + (void)copiedBytes; // Unused parameter + return; + }); +} + +/// +/// Restores previously saved . Any instances +/// registered with will also restore their prior navigation +/// state, which in turn gives their active an opportunity restore its +/// state. +/// +/// A version identifer compared to the session state to prevent +/// incompatible versions of session state from reaching app code. Saved state with a +/// different version will be ignored, resulting in an empty +/// dictionary. +/// An asynchronous task that reflects when session state has been read. The +/// content of should not be relied upon until this task +/// completes. +task SuspensionManager::RestoreAsync(void) +{ + _sessionState->Clear(); + + task getFileTask(ApplicationData::Current->LocalFolder->GetFileAsync(sessionStateFilename)); + return getFileTask.then([=](StorageFile^ stateFile) + { + task getBasicPropertiesTask(stateFile->GetBasicPropertiesAsync()); + return getBasicPropertiesTask.then([=](BasicProperties^ stateFileProperties) + { + auto size = unsigned int(stateFileProperties->Size); + if (size != stateFileProperties->Size) throw ref new FailureException("Session state larger than 4GB"); + task openReadTask(stateFile->OpenReadAsync()); + return openReadTask.then([=](IRandomAccessStreamWithContentType^ stateFileStream) + { + auto stateReader = ref new DataReader(stateFileStream); + return task(stateReader->LoadAsync(size)).then([=](unsigned int bytesRead) + { + (void)bytesRead; // Unused parameter + // Deserialize the Session State + Object^ content = ReadObject(stateReader); + _sessionState = (Map^)content; + + // Restore any registered frames to their saved state + for (auto&& weakFrame : _registeredFrames) + { + auto frame = weakFrame->ResolvedFrame; + if (frame != nullptr) + { + frame->ClearValue(FrameSessionStateProperty); + RestoreFrameNavigationState(frame); + } + } + }, task_continuation_context::use_current()); + }); + }); + }); +} + +#pragma region Object serialization for a known set of types + +namespace +{ + // Codes used for identifying serialized types + enum StreamTypes { + NullPtrType = 0, + + // Supported IPropertyValue types + UInt8Type, UInt16Type, UInt32Type, UInt64Type, Int16Type, Int32Type, Int64Type, + SingleType, DoubleType, BooleanType, Char16Type, GuidType, StringType, + + // Additional supported types + StringToObjectMapType, + + // Marker values used to ensure stream integrity + MapEndMarker + }; + + void WriteString(DataWriter^ writer, String^ string) + { + writer->WriteByte(StringType); + writer->WriteUInt32(writer->MeasureString(string)); + writer->WriteString(string); + } + + void WriteProperty(DataWriter^ writer, IPropertyValue^ propertyValue) + { + switch (propertyValue->Type) + { + case PropertyType::UInt8: + writer->WriteByte(UInt8Type); + writer->WriteByte(propertyValue->GetUInt8()); + return; + case PropertyType::UInt16: + writer->WriteByte(UInt16Type); + writer->WriteUInt16(propertyValue->GetUInt16()); + return; + case PropertyType::UInt32: + writer->WriteByte(UInt32Type); + writer->WriteUInt32(propertyValue->GetUInt32()); + return; + case PropertyType::UInt64: + writer->WriteByte(UInt64Type); + writer->WriteUInt64(propertyValue->GetUInt64()); + return; + case PropertyType::Int16: + writer->WriteByte(Int16Type); + writer->WriteUInt16(propertyValue->GetInt16()); + return; + case PropertyType::Int32: + writer->WriteByte(Int32Type); + writer->WriteUInt32(propertyValue->GetInt32()); + return; + case PropertyType::Int64: + writer->WriteByte(Int64Type); + writer->WriteUInt64(propertyValue->GetInt64()); + return; + case PropertyType::Single: + writer->WriteByte(SingleType); + writer->WriteSingle(propertyValue->GetSingle()); + return; + case PropertyType::Double: + writer->WriteByte(DoubleType); + writer->WriteDouble(propertyValue->GetDouble()); + return; + case PropertyType::Boolean: + writer->WriteByte(BooleanType); + writer->WriteBoolean(propertyValue->GetBoolean()); + return; + case PropertyType::Char16: + writer->WriteByte(Char16Type); + writer->WriteUInt16(propertyValue->GetChar16()); + return; + case PropertyType::Guid: + writer->WriteByte(GuidType); + writer->WriteGuid(propertyValue->GetGuid()); + return; + case PropertyType::String: + WriteString(writer, propertyValue->GetString()); + return; + default: + throw ref new InvalidArgumentException("Unsupported property type"); + } + } + + void WriteStringToObjectMap(DataWriter^ writer, IMap^ map) + { + writer->WriteByte(StringToObjectMapType); + writer->WriteUInt32(map->Size); + for (auto&& pair : map) + { + WriteObject(writer, pair->Key); + WriteObject(writer, pair->Value); + } + writer->WriteByte(MapEndMarker); + } + + void WriteObject(DataWriter^ writer, Object^ object) + { + if (object == nullptr) + { + writer->WriteByte(NullPtrType); + return; + } + + auto propertyObject = dynamic_cast(object); + if (propertyObject != nullptr) + { + WriteProperty(writer, propertyObject); + return; + } + + auto mapObject = dynamic_cast^>(object); + if (mapObject != nullptr) + { + WriteStringToObjectMap(writer, mapObject); + return; + } + + throw ref new InvalidArgumentException("Unsupported data type"); + } + + String^ ReadString(DataReader^ reader) + { + int length = reader->ReadUInt32(); + String^ string = reader->ReadString(length); + return string; + } + + IMap^ ReadStringToObjectMap(DataReader^ reader) + { + auto map = ref new Map(); + auto size = reader->ReadUInt32(); + for (unsigned int index = 0; index < size; index++) + { + auto key = safe_cast(ReadObject(reader)); + auto value = ReadObject(reader); + map->Insert(key, value); + } + if (reader->ReadByte() != MapEndMarker) + { + throw ref new InvalidArgumentException("Invalid stream"); + } + return map; + } + + Object^ ReadObject(DataReader^ reader) + { + auto type = reader->ReadByte(); + switch (type) + { + case NullPtrType: + return nullptr; + case UInt8Type: + return reader->ReadByte(); + case UInt16Type: + return reader->ReadUInt16(); + case UInt32Type: + return reader->ReadUInt32(); + case UInt64Type: + return reader->ReadUInt64(); + case Int16Type: + return reader->ReadInt16(); + case Int32Type: + return reader->ReadInt32(); + case Int64Type: + return reader->ReadInt64(); + case SingleType: + return reader->ReadSingle(); + case DoubleType: + return reader->ReadDouble(); + case BooleanType: + return reader->ReadBoolean(); + case Char16Type: + return (char16_t)reader->ReadUInt16(); + case GuidType: + return reader->ReadGuid(); + case StringType: + return ReadString(reader); + case StringToObjectMapType: + return ReadStringToObjectMap(reader); + default: + throw ref new InvalidArgumentException("Unsupported property type"); + } + } +} + +#pragma endregion diff --git a/samples/winrt/ImageManipulations/C++/common/suspensionmanager.h b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.h new file mode 100644 index 0000000..65e1180 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/common/suspensionmanager.h @@ -0,0 +1,50 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// SuspensionManager.h +// Declaration of the SuspensionManager class +// + +#pragma once + +#include + +namespace SDKSample +{ + namespace Common + { + /// + /// SuspensionManager captures global session state to simplify process lifetime management + /// for an application. Note that session state will be automatically cleared under a variety + /// of conditions and should only be used to store information that would be convenient to + /// carry across sessions, but that should be disacarded when an application crashes or is + /// upgraded. + /// + ref class SuspensionManager sealed + { + internal: + static void RegisterFrame(Windows::UI::Xaml::Controls::Frame^ frame, Platform::String^ sessionStateKey); + static void UnregisterFrame(Windows::UI::Xaml::Controls::Frame^ frame); + static Concurrency::task SaveAsync(void); + static Concurrency::task RestoreAsync(void); + static property Windows::Foundation::Collections::IMap^ SessionState + { + Windows::Foundation::Collections::IMap^ get(void); + }; + static Windows::Foundation::Collections::IMap^ SessionStateForFrame( + Windows::UI::Xaml::Controls::Frame^ frame); + + private: + static void RestoreFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame); + static void SaveFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame); + }; + } +} diff --git a/samples/winrt/ImageManipulations/C++/pch.cpp b/samples/winrt/ImageManipulations/C++/pch.cpp new file mode 100644 index 0000000..97389d9 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/pch.cpp @@ -0,0 +1,16 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/samples/winrt/ImageManipulations/C++/pch.h b/samples/winrt/ImageManipulations/C++/pch.h new file mode 100644 index 0000000..13f9bc3 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/pch.h @@ -0,0 +1,23 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include +#include +#include +#include "Common\LayoutAwarePage.h" +#include "Common\SuspensionManager.h" +#include "App.xaml.h" diff --git a/samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml b/samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml new file mode 100644 index 0000000..ec2c1a7 --- /dev/null +++ b/samples/winrt/ImageManipulations/C++/sample-utils/SampleTemplateStyles.xaml @@ -0,0 +1,51 @@ + + + + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/description.html b/samples/winrt/ImageManipulations/description.html new file mode 100644 index 0000000..ad1df7d --- /dev/null +++ b/samples/winrt/ImageManipulations/description.html @@ -0,0 +1,238 @@ + + + + + + + Media capture using capture device sample + + + + + + + + + diff --git a/samples/winrt/ImageManipulations/description/4ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css b/samples/winrt/ImageManipulations/description/4ee0dda0-3e7e-46df-b80b-1692acc1c812Combined.css new file mode 100644 index 0000000..e69de29 diff --git a/samples/winrt/ImageManipulations/description/Brand.css b/samples/winrt/ImageManipulations/description/Brand.css new file mode 100644 index 0000000..9841556 --- /dev/null +++ b/samples/winrt/ImageManipulations/description/Brand.css @@ -0,0 +1,3629 @@ +#BodyBackground +{ + min-width:0px; +} + +#JelloExpander, .IE7 #JelloExpander, .IE8 #JelloExpander, .IE9 #JelloExpander +{ + padding-left:0px; + padding-right:0px; +} + +#JelloSizer +{ + margin: 0 auto; + max-width: 0px; + padding: 0; + width: 100%; +} + +/* Global Styles */ +body +{ + font-size:0.75em; +} + +h1 +{ + font-size: 3em; + font-family: 'Segoe UI Light','Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; + color: #707070; + font-weight: normal; + padding-top:4px; + margin-bottom: 17px; + line-height: 1.3; + font-weight:100; +} + +h2, h3, h4, h5, h6 +{ + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; + color:#2a2a2a; + font-weight:normal; +} + +a, a:link, a:visited { + color: #00749E; +} +a:hover { + color: #0095c4; + text-decoration:none; +} + +/*---------- Masthead -----------*/ + +.NetworkLogo a { + display: none; +} + +/*-------- Start Advertisment --------*/ + +.advertisment { + padding-top:5px; +} + +/*-------- End Advertisment --------*/ + + +/*-------- Start LocalTabs Page --------*/ +#GalleriesNavigation { + float: right; +} + +.LocalNavigation +{ + display:block; + overflow: auto; + width: auto; +} + .LocalNavigation .HeaderTabs { + width: auto; + } + .LocalNavigation .TabOff a { + color:#333; + } + + .LocalNavigation .TabOff a:hover { + background-color:#E0E7EC; + margin-top: 1px; + padding: 4px 6px; + } + + .LocalNavigation #notificationLink span { + color:Red; + font-weight:bold; + } + + +/*-------- End LocalTabs Page --------*/ + +/*-------- Start SubMenu Page --------*/ + +.subMenu +{ + margin: 0 0 10px 0; + color: #FFFFFF; + overflow: hidden; +} + +.subMenu a, .subMenu span +{ + margin: 5px 5px 0 5px; +} + +.subMenu > h2 +{ + float: left; + margin: 7px 15px 0 0; + vertical-align: middle; + color: #666; + padding-bottom: 5px; +} + +.subMenu .advancedSearchLink +{ + float: left; + margin: 9px 0 0 15px; +} + + + +.subMenu .uploadLink +{ + float: right; + margin: 5px 5px 0 0; + padding: 0 0 0 30px; + height: 24px; + background: url('../Common/smalluploadicon.png') no-repeat 10px 0; + color: #0066E1; + cursor: pointer; +} + +.subMenu #searchBoxContainer +{ + float: left; + width: 400px; + padding: 3px 50px; +} + +/*-------- End SubMenu Page --------*/ + +/*-------- Start SearchBox --------*/ + +div.searchbox +{ + overflow:auto; + width:450px; + margin:26px 0 14px 0; +} + +.srchbox +{ + width: 100%; + background: #FFFFFF; + padding: 0px 2px; + height: 25px; + border: 1px solid #ccc; + table-layout: auto; + margin-bottom:5px; +} + + + +.srchbox #searchImageCell input +{ + background: transparent url('searchButton.png') no-repeat 0 0; + width: 20px; + height: 20px; + padding-left: 1px; + margin-top: 3px; +} + + +.srchbox #searchImageCell +{ + text-align: right; + padding: 0px; + vertical-align: middle; +} + +.IE7 .srchbox #searchImageCell +{ + padding:2px 2px 0 0; +} + +.srchbox #searchImageCell input +{ +} + + +table.srchbox +{ + table-layout: fixed; +} + +.srchbox .stxtcell +{ + padding-right: 4px; + width:90%; +} + +.srchbox .stxtcell > input +{ + margin-right: 4px; + height: 26px; + line-height:26px; + width: 100%; + padding: 0px; + padding-left: 4px; + padding-top: 2px; + border: none; + font-style: normal !important; + outline: none; +} + +.IE7 .srchbox .stxtcell > input +{ + height: 20px; +} + +.srchbox .stxtcell > input.stxtinptpassive +{ + color: #AAA; + font-style: normal !important; +} + +/*-------- End SearchBox --------*/ + + +/*-------- Start Search Page --------*/ + + +#searchPage #mainContentContainer +{ + margin: 0 0 0 243px; +} + +#searchPage .browseFilterBar, #dashboardPage .browseFilterBar +{ + padding: 5px 0 6px 0; + +} + + #searchPage .browseFilterBar a, #dashboardPage .browseFilterBar a + { + font-weight:normal; + } + + #searchPage .browseFilterBar .browseSort, #dashboardPage .browseFilterBar .browseSort + { + float:right; + } + + #searchPage .browseBreadcrumb + { + padding-top:3px; + } + + #searchPage .browseFilterBar .browseSort select, #dashboardPage .browseFilterBar .browseSort select + { + height:20px; + } + + #searchPage .browseFilterBar .browseSort img, #dashboardPage .browseFilterBar .browseSort img + { + vertical-align:text-top; + } + +#searchPage h2, #searchPage h3 +{ + font-size: 1.25em; + padding: 2px 0 3px 3px; +} + +#searchPage h2 +{ + display:inline; + clear:none; +} + + #dashboardsearchbox + { + width:420px; + margin:0; + float:left; + } + +/*-------- End Search Page --------*/ + +/*-------- Begin Requests Page --------*/ + +#requestsPage { + color:#666; +} + + #requestsPage h1 { + clear:none; + } + #requestsPage h2, #requestsPage h3 + { + font-size: 1.25em; + } + + #requestsPage h2 + { + display:inline; + clear:none; + } + + #requestsPage h3 + { + padding: 2px 0 3px 3px; + } + + #requestsPage #mainContentContainer + { + margin: 0 0 0 243px; + } + + #requestsPage #mainContentWrapper { + float:left; + width:100%; + } + #requestsPage #mainContent { + position:relative; + } + + #requestsPage #mainContent .subtitle{ + margin-bottom:5px; + } + + #requestsPage #requestsFilterBar { + margin-top: 10px; + overflow: auto; + } + + #requestsPage #requestsFilterBar .requestsCrumb { + float: left; + margin:10px 0 10px 10px; + } + #requestsPage #requestsFilterBar .requestsSort { + float: right; + margin:10px 0 10px 0; + } + + #requestsPage #Pager { + text-align: center; + padding-top: .75em; + padding-bottom: .75em; + } + + #requestsPage #requestsRss { + float: right; + margin: 2px 0 0 3px; + cursor: pointer; + } + + .IE7 #requestsPage #requestsList { + padding-top: 10px; + margin-top:5px; + } + + #requestsPage #requestsList .noResults { + padding: 10px 0; + } + + +/*-------- End Requests Page --------*/ + +/*-------- Begin Request List Item --------*/ +.requestlistitem td +{ + padding: .9em 0 .9em .5em; +} + .requestlistitem .votebox + { + + text-align:center; + } + + .requestlistitem .voteboxcontainer + { + vertical-align:top; + width: 75px; + } + + .requestlistitem #votelabel + { + border-width:1px; + border-bottom-style:solid; + } + + #myRequestsTab #votenumber, + #requestsPage #votenumber + { + background-color: #777; + padding: 6px 10px; + color: #fff; + margin-bottom: 5px; + font-size: 1.6em; + } + + #myRequestsTab .votelink, + #requestsPage .votelink + { + font-weight:bold; + background-color: #eee; + padding: 5px 0; + width: 75px; + float: left; + } + + #myRequestsTab .needvote, + #requestsPage .needvote + { + font-weight:bold; + } + + #myRequestsTab .alreadyvoted, #myRequestsTab .resolved + #requestsPage .alreadyvoted, #requestsPage .resolved + { + font-weight:bold; + color: #666; + } + + .requestlistitem .linkform + { + width:100%; + float:right; + margin-top:15px; + } + + .requestlistitem .requesttitle + { + font-weight:600; + margin-bottom:3px; + } + + .requestlistitem .requester + { + margin-bottom:3px; + } + + .requestlistitem .hidden + { + display:none; + } + + .requestlistitem .requestSummary div + { + margin-bottom:0.25em; + } + + .requestlistitem .requestSummary + { + line-height: 1.45em; + width: 80%; + } + .requestlistitem .requestInfo + { + padding:1.2em 0 0 2.5em; + vertical-align:top; + width:15%; + line-height: 1.45em; + } + + .requestlinks > td + { + padding-bottom: 16px; + } + + .requestlinks div + { + float:right; + } + + .requestlistitem .textbox + { + width:95%; + } + + + +/*-------- End Request List Item --------*/ + + +/*-------- Begin New Request Form --------*/ +#newrequest { + margin-top:5px; + background:#F8F8F8; + border-width:1px; + border-style:solid; + border-color:#E8E8E8; + padding:5px; +} + +#newrequest > div:first-child { + font-weight:bold; +} + +#newrequest .itemheading { + margin-top:5px; +} + +#newrequest textarea { + width:95%; +} + +#newrequest .field-validation-error { + display:block; + color:Red; + font-weight:bold; +} +#newrequest #submit { + margin-top:5px; +} + +/*-------- End New Request Form --------*/ + +/*-------- Request Description Page ------*/ + +.reqDescPage #mainContent { + overflow: auto; +} +.reqDescPage #header { + float: left; + width: 100%; +} + +.reqDescPage { + color: #000 !important; +} + +.reqDescPage #sideNav { + background-color: #fff; +} + +.reqDescPage #header td { + vertical-align: bottom; +} + +.reqDescPage #header #votenumber { + width: 50px; + padding: 6px 12px; + text-align: center; + float: left; +} + +.reqDescPage #header .requestTitle { + margin: 0 0 5px 10px; + width: 85%; +} + +.reqDescPage #header .requestTitle h1 { + margin-bottom: 0px; + font-size: 2em; +} + +.reqDescPage #headerLinks { + +} + +.reqDescPage .votelink +{ + text-align: center; + float: left; +} + +#requestsPage #headerLinks .assignlink +{ + font-weight:bold; + background-color: #eee; + padding: 5px 10px; + float: left; + margin-left: 10px; +} + +.reqDescPage #projectInfo { + clear: both; +} + +.reqDescPage #solutions { + clear: both; + padding-top: 30px; +} + +.reqDescPage .solutionItems { + clear: both; +} + +.reqDescPage .solutionHeader { + border-bottom: 1px solid #ccc; +} + +.reqDescPage .solutionAddContainer { + padding-top: 15px; + float: left; +} + +.reqDescPage #SubmittedProjectLinkUrl { + width: 400px; +} + +.reqDescPage .solutionItem { + margin-top: 25px; + padding: 0 5px 5px 0; + float: left; +} +.reqDescPage .solutionItemDetails { + float: left; + width: 535px; +} + +.reqDescPage .solutionItemLinks { + margin-top: 10px; + clear: both; + float: left; + width: 100%; +} + +.reqDescPage .solutionItemLinks a { + float: left; + margin-right: 10px; + font-weight:bold; + background-color: #eee; + padding: 5px 10px; +} + +.reqDescPage .solutionItem .itemTitle { + font-size: 1.2em; + padding-bottom: 5px; +} + +.reqDescPage .tagsContainer label { + display: none; +} + +.reqDescPage .solutionItem .summaryBox { + padding: .25em 0 .25em 0; + clear: both; + line-height: 1.45; +} + +.reqDescPage .solutionsection { + float: left; + margin-left: 20px; +} +.reqDescPage .completedSolution { + font-size: 1.25em; + padding-top: 4px; +} + +.reqDescPage .requestDescriptionCont, .reqDescPage .requestDicussions { + padding-top: 30px; + clear: both; + overflow: auto; +} + +.reqDescPage .requestDescription { + padding-top: 10px; + line-height: 1.45; +} + +.reqDescPage .requestDicussionsAsk { + padding: 10px 0; +} + +.reqDescPage .watermark { + color:Gray; + } + + +/*-------- Begin Extra Actions Section --------*/ +#extraActions +{ + float: right; + width: 300px; + vertical-align: top; +} + + #extraActions .section + { + padding: 0 0 10px 0; + overflow:auto; + } + + #extraActions .section a + { + font-weight:bold; + } +/*-------- End Extra Actions Section --------*/ + +/*-------- Begin Contribute --------*/ + + +#contributeSection a +{ + font-size:1.1em; +} + +#contributeSection, #sideNav #contributeSection h3, .sidebar #contributeSection h3, #contributeSection h3 +{ + background-color:#fff; + margin: 0 0 9px 0; + padding-left: 0px; +} + +#sideNav #contributeSection h3, .sidebar #contributeSection h3, #contributeSection h3 +{ + font-size:1.65em; + margin-top:42px; +} + +#sideNav #contributeSection, #contributeSection +{ + padding:0 0 41px 0; +} + +#projectPage .sidebar #contributeSection +{ + margin: 10px 0 10px 0; + padding:0 0 5px 0; + +} + +#sideNav #contributeSection > div, .sidebar #contributeSection > div, #contributeSection > div +{ + padding: 0 0 2px 0; + overflow:auto; +} + +#sideNav #contributeSection img, #contributeSection img +{ + float: left; + width: 25px; +} + +#sideNav #contributeSection .contributeAction, .sidebar #contributeSection .contributeAction, #contributeSection .contributeAction +{ + padding:17px 0 0 0; +} + + #contributeSection .contributeAction img + { + background-color:#00749e; + margin-right:9px; + } + + #contributeSection .contributeAction img:hover + { + background-color:#0095C4; + } + + #contributeSection .contributeAction a + { + display:block; + line-height: 1.8; + } + +#uploadLink, #exclamationLink, #myContributionsLink +{ + display:block; + line-height: 1.8; +} + +#myContributionsLink span +{ + color: red; +} + +#feedbackLink +{ + background: url("FeedbackIcon.png") no-repeat; + width: 40px; + height: 40px; +} + +.itemRow .affiliationLink, #editorPicksSection .affiliationLink +{ + background: url("../common/MicrosoftLogo.png") no-repeat; + width: 82px; + height: 18px; +} + + +#contributeSection a+div +{ + +} + +.IE7 #contributeSection a+div +{ + float:left; +} +/*-------- End Contribute --------*/ + + +/*-------- Begin Directory List Footer --------*/ + +#directoryListFooter { + padding:5px; + margin-top:10px; + margin-bottom:10px; + border:1px solid #E6E6E6; + background-color:#F8F8F8; + width:438px; +} + +#directoryListFooter h4 +{ + font-size:1em; +} + +/*-------- End Directory List Footer --------*/ + +/*-------- Begin Editors Picks --------*/ +#editorPicksSection ul +{ + padding-left:0px; + line-height:135%; +} + + #editorPicksSection ul li + { + clear: left; + padding-top: 10px; + list-style:none; + } + #editorPicksSection ul li:first-child { + padding-top: 0; + } + + #editorPicksSection a { + font-weight: normal !important; + } + + #editorPicksSection ul li .thumbnail + { + float: left; + padding: 3px; + max-width: 60px; + } + + #editorPicksSection ul li .thumbnail img { + max-width: 60px; + } +/*-------- End Editors Picks --------*/ + +/*-------- Begin Side Nav Section --------*/ + +#sideNav +{ + width: 215px; + margin-left: 0; + vertical-align: top; + float: left; +} + + #sideNav #sideNavHeader + { + margin-bottom: 10px; + padding-left: 12px; + } + + #sideNav #sideNavHeader a + { + margin-right:3px; + } + + #sideNav .section + { + padding: 0 10px 18px 10px; + } + #sideNav .section h3 + { + + padding: 2px 0 3px 3px; + } + + #sideNav .section ul + { + } + + #sideNav .section ul li + { + padding: 4px 0 2px; + margin-left: 3px; + margin-right: 3px; + } + + + #sideNav .section form > div + { + padding: 4px 0 0 0; + border-bottom: none; + margin: 0 3px 0 3px; + color: #3A3E43; + } + .IE8 #sideNav .section ul li > div.itemText + { + word-wrap: break-word; + width: 225px; + } + #sideNav .section ul li > div.itemCount + { + color: #3A3E43; + } + #sideNav .section a + { + font-weight: normal; + } + + #sideNav .section a:hover + { + text-decoration: underline; + } + +/*-------- End Side Nav Section --------*/ + + + +/*-------- Start Dashboard Page --------*/ + +#dashboardPage { + padding-top:5px; + clear:both; +} +#dashboardPage .contributions .tabContents { + padding: 5px 5px 10px 0; + clear:both; +} + #dashboardPage .contributions .noContributions { + clear:both; + } +#dashboardPage #mainContentWrapper { + float:left; + width:100%; +} + +#dashboardPage #detailsSection { + float:left; + margin-left:-100%; + width:240px; + padding: 0 0 18px 10px; +} + +.IE7 #dashboardPage #detailsSection { + width:auto; + min-width: 300px; + max-width: 300px; +} +.IE7 #dashboardPage #detailsSection .itemBar { + width: 270px; +} + +#dashboardPage #detailsSection h3 { + word-wrap:break-word; +} + +#dashboardPage #mainContent { + margin:0 0 0 250px; + position:relative; +} + +#dashboardPage .dashboardEvenRow +{ + background-color: #ececec; +} +#dashboardPage .dashboardPadding +{ + padding-bottom: 4px; +} +#dashboardPage .dashboardCell +{ + width: 100%; + vertical-align: top; + padding: 1em 0.5em 0.5em 0.5em; + word-wrap: break-word; +} +#dashboardPage .projectManagement +{ + width: 24em; + padding: 0em 1em 0em 1em; + vertical-align: top; + text-align: right; + float: right; +} + +#dashboardPage #subscriptionsLink +{ + position:absolute; + right:5px; +} + +#dashboardPage .itemDelete +{ + vertical-align:top; + padding-top:.8em; + width:30px; +} + +#dashboardPage .itemDeleteText +{ + border-style:solid; + border-width:thin; + border-collapse:collapse; + padding-bottom:2px; + padding-left:4px; + padding-right:4px; + color:Gray +} + +#dashboardPage #myRequestsTab .requestTabHeaders +{ + font-weight:normal; + border-bottom: solid 1px #CCC; + padding-bottom: 10px; + padding-top: 10px; + float: left; + width: 100%; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div:first-child +{ + border: 0; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div +{ + padding: 2px 9px 3px 9px; + font-size: 0.9em; + line-height: 125%; + color:#00749E; + border-left: solid 1px #555; + cursor: pointer; + float: left; + text-align: center; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div.currentRequest +{ + background-color:#fff; + cursor: default; + border-bottom:none; + margin-bottom:-2px; + color:#000; +} + +#dashboardPage #myRequestsTab .requestTabHeaders div.currentRequest a { + color: #000; +} + + +#dashboardPage #myRequestsTab .requestTabHeaders div a +{ + text-decoration:none; +} + +#dashboardPage #myRequestsTab .requestTabContents +{ + clear: both; +} + +#dashboardPage #myRequestsTab .requestTabContents .noResults { + padding-top: 20px; +} + +/*-------- End Dashboard Page --------*/ + +/*-------- Start Upload Page --------*/ + +#UploadPage +{ + margin-left:10px; + max-width:925px; +} + + #UploadPage .watermark { + color:Gray; + } + + #UploadPage .projectTypeChoice { + } + + #UploadPage .projectTypeChoice > div { + padding: 20px 10px 20px 10px; + border: 1px solid darkgrey; + cursor: pointer; + height: 200px; + float: left; + } + + #UploadPage .projectTypeChoice > div + div + { + margin: 0 0 0 5px; + } + + #UploadPage .projectTypeChoice div.current + { + background-color: #E9E9E9; + cursor: default; + } + + #UploadPage .projectTypeChoice div.choice { + font-size: large; + font-weight: bold; + padding: 0 0 10px 0; + } + + #UploadPage .projectTypeChoice div.description { + padding: 0 0 0 17px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription { + padding-top: 5px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .logos { + overflow: auto; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .vslogo { + background: url(../samples/vslogo.png) no-repeat; + width: 125px; + height: 18px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .javalogo { + background: url(../samples/javalogo.png) no-repeat; + width: 33px; + height: 60px; + float: left; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .phplogo { + background: url(../samples/phplogo.png) no-repeat; + width: 65px; + height: 35px; + float: left; + margin: 15px 0 0 10px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription .nodejslogo { + background: url(../samples/nodejslogo.png) no-repeat; + width: 90px; + height: 25px; + float: left; + margin: 18px 0 0 10px; + } + + #UploadPage .projectTypeChoice #genericSampleUploadDescription > div+div { + margin-top: 10px; + } + + #UploadPage .projectTypeContents { + clear: left; + padding: 10px 0 0 0; + } + + #UploadPage .projectTypeContents .instruction > div+div { + padding-top: 5px; + } + #UploadPage #libraryContainer { + margin: 5px 0 0 0; + display: none; + } + #UploadPage fieldset + { + margin: 10px 0 30px 5px; + } + + #UploadPage fieldset > * + { + margin-left:10px; + } + + #UploadPage .fieldsetStyleContainer { + margin: 10px 0 0 5px; + } + + #UploadPage fieldset h2, + #UploadPage .fieldsetStyleContainer h2 + { + font-family: 'Segoe UI Semibold','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; + font-size: 17px; + font-weight: bold; + color: #3A3E43; + border-bottom: 2px solid #EFEFEF; + width: 100%; + padding-bottom: 3px; + margin-left:0px; + margin-bottom:8px; + } + + .IE7 #UploadPage fieldset h2, + .IE7 #UploadPage .fieldsetStyleContainer h2 + { + margin-left:-10px; + } + + #UploadPage fieldset .field-validation-error + { + clear:left; + display:block; + margin-top:4px; + } + + #UploadPage fieldset .required + { + margin-left: 3px; + } + + #UploadPage fieldset .instruction, + #UploadPage .fieldsetStyleContainer .description, + #UploadPage .fieldsetStyleContainer .instruction + { + color: #3A3E43; + margin:0 0 10px 0; + } + + #UploadPage fieldset .faqLink + { + margin: 0 0 10px 0; + } + + #UploadPage fieldset label + { + display:block; + } + + #UploadPage fieldset input[type=text] + { + width:60%; + } + + #UploadPage fieldset input[type=checkbox] + { + float:left; + clear:left; + margin-right:5px; + } + + #UploadPage fieldset input[type=radio] + { + float:left; + clear:left; + margin-right:5px; + } + + #UploadPage fieldset#richDescription textarea + { + width:70%; + height:600px; + } + + #UploadPage fieldset#summary textarea + { + width:60%; + height:100px; + margin-top: 10px; + margin-left: -30px; + } + + .IE #UploadPage fieldset#summary textarea, .IE9 #UploadPage fieldset#summary textarea + { + margin-left: -30px; + overflow: auto; + } + + .FF #UploadPage fieldset#summary textarea + { + margin-left: -30px; + } + + #UploadPage fieldset#summary #SummaryReadOnly + { + width:60%; + margin-top: 10px; + padding-top: 5px; + color: #909082; + } + + #UploadPage fieldset#summary #SummaryCharCount + { + width:60%; + text-align: right; + } + + #UploadPage fieldset#options label + { + margin-bottom:10px; + } + + #UploadPage fieldset#license label + { + margin-bottom:10px; + } + + #UploadPage input[type="text"].tagInput, #UploadPage input[type="text"].listInput + { + width:40%; + float:left; + } + + #UploadPage .addedTags, #UploadPage .addedProjects + { + margin-bottom:15px; + width: 500px; + + } + #UploadPage .addedTags .tag, #UploadPage .addedProjects .projectTitle + { + position:relative; + overflow:hidden; + } + + #UploadPage .addedTags .tag label, #UploadPage .addedProjects .projectTitle label + { + float:left; + width: 450px; + } + + #UploadPage .addedTags .tag a, #UploadPage .addedProjects .projectTitle a + { + position:absolute; + text-align:right; + right:0px; + } + + .fileManager .fileUploadProgressIndicator + { + width: 500px; + } + + .fileManager .uploadProcessingWarning { + margin-top: 5px; + } + + .fileManager .fileUploadProgressIndicator .throbber + { + font-weight: bold; + background: url('./progressIndicatorWhite.gif') no-repeat 10px 0; + padding: 7px 10px 5px 60px; + height: 25px; + margin-left: -10px; + } + + .fileManager #uploadFrame, .fileManager .uploadFrame + { + width:100%; + } + + .fileManager .addLabel + a + { + margin-left:25px; + } + + .fileManager fieldset label { + display: block; + } + + .fileManager .unlocalizedFiles { + color:#808080; + } + + .fileManager .filesContainer + { + margin-bottom:15px; + width: 500px; + + } + + .fileManager .filesContainer .file + { + position:relative; + overflow:hidden; + } + + .fileManager .filesContainer .file .title { + border-bottom: 1px solid #000000; + padding-bottom: 3px; + margin-top: 10px; + margin-bottom: 10px; + } + + .fileManager .filesContainer .file .title .manageLinks + { + float: right; + } + + .fileManager .filesContainer .file .version { + padding: 0 0 20px 10px; + } + + .fileManager .filesContainer .file .version label { + float: left; + font-weight: bold; + } + + .fileManager .filesContainer .file .version span { + float: left; + margin-left: 5px; + } + + .fileManager .filesContainer .file .language { + clear: left; + padding: 0 0 5px 10px; + } + + .fileManager .filesContainer .file .language label { + font-weight: bold; + } + + .fileManager .filesContainer .file .language label + label { + font-weight: normal; + padding-left: 10px; + } + + .fileManager .filesContainer .file .language div { + padding-left: 20px; + } + + .file .requirements { + clear: left; + padding: 0 0 0 10px; + } + + .file .requirements label { + font-weight: bold; + } + + .file .requirements > div { + padding-left: 20px; + } + + .file .requirements .requirementsContent { + padding-top: 5px; + padding-bottom: 10px; + } + + .file .requirements .requirementsContent label { + font-style: italic; + font-weight: normal; + } + + .file .requirements .requirementsContent > div + { + margin-bottom:4px; + position:relative; + } + + .requirementsContent .requirementsRemove { + float:right; + position:absolute; + right:0px; + } + + .requirements .requirementsAddError { + color:#ff0000; + } + + .requirements .reqBrowseButton { + margin-left : 10px; + } + + #UploadPage fieldset .requirements input[type="text"] { + margin-right: 10px; + width: 70%; + } + + .reqBrowsefade + { + position: absolute; + background-color: #aaaaaa; + } + .reqBrowse + { + background-color: #f4f4f4; + border:1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding:15px; + position: absolute; + display: block; + } + + .reqBrowsebuttons + { + text-align:right; + position:absolute; + right:10px; + bottom:5px; + } + .reqBrowsebuttons > button + { + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor:pointer; + } + + .reqBrowseclose + { + display:none; + } + + .reqBrowseDialog + { + width: 700px; + clear:both; + overflow:hidden; + padding-bottom: 20px; + } + + .reqBrowseDialog > h2 + { + border-bottom: 1px solid #000000; + padding-bottom: 5px; + } + .reqBrowseDialog > p + { + margin: 15px 0 15px 0; + } + + .reqBrowseSearchCont + { + width: 100%; + background: white; + padding: 0px 2px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid #888; + margin-bottom: 5px; + height: 29px; + } + .reqBrowseSearchCont .rbboxcont + { + width:90%; + float:left; + margin-top: 2px; + } + + .reqBrowseSearchCont input + { + border:none; + outline:none; + border-color: transparent; + } + .reqBrowseSearchBox + { + margin-right: 4px; + height: 20px; + line-height: 20px; + width: 100%; + padding-left: 4px; + padding-top: 2px; + } + + .reqBrowseSearchBoxDefault + { + color: #AAA; + } + .reqBrowseSearchCont .rbbtncont + { + float: right; + margin-top: 4px; + } + .reqBrowseSearchBtn + { + background: transparent url('searchButton.png') no-repeat 0 0; + width: 22px; + height: 22px; + float:left; + cursor:pointer; + } + + .reqBrowseTabs + { + border-bottom: 5px solid #E8E8E8; + margin:3px 0; + overflow:auto; + } + + .reqBrowseTabs .reqBrowseTabsR + { + color:#fff !important; + } + + .reqBrowseTabs .reqBrowseTabsHighlight + { + color:#000 !important; + background-color:#E8E8E8; + } + + .reqBrowseTabs a + { + padding:5px 12px; + color:#fff; + background-color:#888; + font-weight:bold; + float:left; + margin: 0 4px 0px 0; + } + + .reqBrowsePager td + { + text-align:center; + } + .reqBrowseDialog #Pager + { + margin: 5px 0 15px 0; + } + + .reqBrowseContent + { + height:310px; + overflow:auto; + clear:both; + position:relative; + } + + .reqBrowsePager + { + width:700px; + margin:0 auto; + } + + .reqBrowseContentError + { + color:#ff0000; + margin:5px; + } + .reqBrowseContent .requirementItem + { + border-bottom: 2px solid #E8E8E8; + padding: 4px 0 6px 0; + overflow:auto; + } + .reqBrowseContent .section1 + { + float:left; + width:75%; + padding-left:25px; + position:relative; + } + + .reqBrowseContent .section1 input + { + position:absolute; + left:0px; + } + + .reqBrowseContent .title + { + font-weight:bold; + } + .reqBrowseContent .section2 + { + float:right; + } + + + .progressIndicatorfade + { + position: absolute; + background-color: #FFFFFF; + } + .progressIndicator + { + background-color: #f4f4f4; + border: 1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 15px; + position: absolute; + display: block; + max-width: 70%; + max-height: 70%; + } + #progressIndicator .progressIndicatorclose + { + display: none; + } + + #progressIndicatorContent + { + font-weight: bold; + padding: 7px 10px 0 10px; + height: 25px; + } + + +/*-------- End Upload Page --------*/ + +/* --- + --- Homepage --- + --- */ +p +{ + margin: 0 0 1px 0; +} +#homePageHeader +{ + float: left; + margin-bottom: 1em; + width: 100%; +} + +.tagline { + font-size: x-small; + position: relative; + top: -11px; +} + +.logo +{ + float: left; + width: 455px; + height: 70px; + font-weight: bold; + font-size: 22px; + margin: 0 10px 0 0; + color: #3A3E43; +} +.logo > img +{ + float: right; +} +.logo > div +{ + color: #3A3E43; + font-weight: bold; + font-size: 22px; +} + +.welcomeInfo +{ + float: left; + width: 700px; +} +.welcomeInfo h2 +{ + font-size: 16px; +} +.welcomeInfo p +{ + margin: 5px 0 0 0; +} + +#siteActions > div +{ + border: 1px solid #BBBBBB; + padding: 15px 5px 0 65px; + height: 55px; + background-repeat: no-repeat; + background-position: 10px 10px; +} +#siteActions a, #siteActions p +{ + margin-top: 5px; +} + +#siteActions .label a +{ + font-size: 1.25em; + font-weight: bold; + margin-bottom: 3px; +} + +#myGalleryBox +{ + background-image: url("MyGalleryIcon.png"); +} + +#findActions +{ + float: right; + padding: 10px; + width: 225px; + height: 50px; + border: 1px solid #BBBBBB; + margin: 0 10px 0 0; +} + +#findBox div:first-child +{ + margin: 0 0 5px 0; + font-weight: bold; +} + +#legalDisclaimer +{ + margin: 0 0 10px; + color: #798072; + font-size: 0.8em; +} + +#siteActions +{ + float: right; + width: 200px; +} +#siteActions > div +{ + margin-bottom: 10px; +} +.homePageProjects +{ + width: 100%; + float: left; +} +.homePageProjects > div +{ + padding-left: 1.5em; +} +.homePageProjects > div:first-child +{ + padding-left: 0; +} + +.homePageProjects .projectList ul +{ + padding: 0; + margin: 0; +} +.homePageProjects li +{ + margin-top: .5em; + padding-bottom: 0.5em; + list-style-type: none; +} +.homePageProjects .itemRow a, .homePageProjects .itemRow a:hover +{ + color: #0054A6; +} + +.projectList > a:first-child +{ + margin-left: 1px; + float: right; +} +.projectList > a, .projectList > a:hover +{ + color: #5BAEDB; +} +.projectListTitle +{ + height: 27px; + font-size: 16px; + font-weight: bold; + line-height: 125%; + background: #E8E8E8; + padding: 5px 5px 5px 25px; +} +.homePageListPager +{ + text-align: right; + margin-bottom: -.5em; +} + +.recentlyAddedProjects +{ + float: left; + width: 32%; +} +.mostPopularProjects +{ + float: right; + width: 32%; +} +.highestRankedProjects +{ + overflow: hidden; +} +* html .highestRankedProjects +{ + float: left; +} +* html .highestRankedProjects > div +{ + width: 100%; +} + +#Pager +{ + text-align:left; +} + +/* Impromptu warning style */ +.ipWarningfade +{ + position: absolute; + background-color: #aaaaaa; +} +div.ipWarning +{ + width: 400px; + position: absolute; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + padding: 20px 0 20px 20px; + background-color: #FCE5E6; + border: solid 2px #EE1F25; +} +.ipWarningcontainer +{ + font-weight: bold; +} +.ipWarningclose +{ + display: none; +} +.ipWarningmessage div +{ + position: relative; +} +.ipWarningmessage div div + div +{ + text-align: center; + padding-right: 20px; +} +.ipWarningmessage div div:first-child div +{ + margin-left: 50px; +} +.ipWarningmessage div div:first-child img +{ + position: absolute; + margin: -20px 0 0 0; + top: 35%; +} +.ipWarningbuttons +{ + text-align: center; + margin: 20px 0 0 0; +} +.ipWarning button +{ + padding: 4px 8px 4px 8px; + margin: 2px; + font-weight: bold; + border: solid 1px #A6A3A6; + color: #FFFFFF; + background: #B8BABC; + filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#B8BABC',EndColorStr='#949699'); +} + +#eyebrow +{ + width: 100%; +} +#siteMessage .unsupportedLocale { + margin: 10px 0 0 243px; + border: solid 1px #CCC; + background: #FCFEC5; + padding: 5px; +} + +#Footer +{ + width: 100%; + height: auto; +} + +.clear +{ + clear: both; +} + +#buildVersion +{ + clear: both; + margin-left: auto; + margin-right: auto; + padding-right: 26px; + padding-top: 8px; + text-align: right; +} + +#page +{ + clear: both; + padding-top: 10px; +} + +#page h1 +{ + padding: 10px 0px; +} + +#ownerBar +{ + background: #EFEFEF; + border: 2px solid #7FCBF5; + text-align: left; + color: Black; + margin: 10px 0 20px 0; + padding: 5px; + word-spacing: 0px; + font-size: medium; +} + +#ownerBar a +{ + color: Blue; + padding: 0 5px 0 5px; +} + + + + +/*-------- Start Tab Control --------*/ + +.tabHeaders +{ + font-weight:normal; + text-transform: uppercase; + border-bottom: solid 1px #CCC; + float: left; + width: 100%; +} + +.tabHeaders div +{ + padding: 7px 19px 8px 19px; + font-size: 0.9em; + line-height: 125%; + color:#00749E; + cursor: pointer; + float: left; + text-align: center; +} + +.tabHeaders div.current +{ + background-color:#fff; + cursor: default; + border: 1px solid #CCC; + border-bottom:none; + margin-bottom:-2px; + color:#000; +} + +.tabHeaders div a +{ + text-decoration:none; +} + +.tabContents +{ + clear: both; +} + +#MainContent .tabHeaders div.current a +{ + color:#000; +} + +.tabContents div.current +{ + display: block; +} +/*-------- End Tab Control --------*/ + +.itemContainer +{ + width: 100%; +} +.itemRow .itemTitle +{ + padding-bottom: 5px; + font-size:1.1em; +} + +.itemRow .itemBody, .itemRow .itemInfo +{ + padding:15px 17px 16px 0; +} +.itemRow .itemDescription +{ + overflow: hidden; + max-height: 80px; +} +.itemRow .itemBody +{ + vertical-align: top; + line-height: 1.4; +} +.itemRow .itemBody a.officialMicrosoftLabel +{ + color: #ACACAC; +} +.itemRow .itemInfo +{ + vertical-align: top; + padding-left: .5em; + line-height: 1.4; + width: 10em; + text-align:right; +} + +.IE7 .itemRow .itemInfo +{ + width:11em; +} + +.itemRow .itemInfo .ratingStars +{ + float: left; +} +.itemRow .itemInfo .ratingCount +{ + padding: 0 0 0 5px; + float: left; +} +.itemRow .ratingInfo +{ + text-align: center; +} + +.itemRow .affiliationLink, #editorPicksSection .affiliationLink +{ + position: relative; + top: 3px; +} + +#editorPicksSection a.officialMicrosoftLabel +{ + color: #ACACAC; +} + +.itemRow .tagsContainer label { + display:none; +} + +.editorPickedItem +{ + background-color:#F8F8F8; +} + +.editorPickedText +{ + font-size:1.25em; + padding-bottom:2px; +} +.editorPickedItem > td +{ + border-top:6px solid #fff; +} + +.dirSubHeading +{ + margin-bottom:15px; +} + +#searchPage .dirSubHeading h2 +{ + line-height:1.4; + font-size:1.1em; +} + +#searchPage .dirSubHeading h2 span +{ + padding-top:5px; + display:block; +} + +#searchPage .dirSubHeading h1, #searchPage .dirSubHeading h2 +{ + clear:none; + padding-left:0px; +} + +.dirSubHeading .dirSubLinks +{ + font-size:1.2em; + padding-top:5px; +} + + +.summaryBox +{ + padding: .25em 0 .25em 0; + clear: both; + line-height:1.45; +} + +/*-------- Start Rating Stars --------*/ + +.RatingStar +{ + width: 11px; + height: 11px; + padding: 0 8px 0 0; + background-position: center; + float: left; +} + +.FilledRatingStar, .HalfRatingStar, .EmptyRatingStar, .FilledRatingStarHover +{ + width: 11px; + height: 11px; + padding: 0px 1px 0px 0px; + margin-top: 2px; +} + +.FilledRatingStar +{ + background: url(../samples/fullStar.png) no-repeat; +} + +.ownerRating .FilledRatingStar +{ + background: url(../samples/fullStar.png) no-repeat; +} + +.FilledRatingStarHover +{ + background: url(../samples/fullStarHover.png) no-repeat; + +} + +.HalfRatingStar +{ + background: url(../samples/halfStar.png) no-repeat; + +} + +.EmptyRatingStar +{ + background: url(../samples/emptyStar.png) no-repeat; + +} + +.EditStarMode .RatingStar +{ + cursor: pointer; +} + + + +/*-------- End Rating Stars --------*/ + +.discussionFormTable +{ + width: 100%; + table-layout: fixed; +} + + +#ReviewsTabPane .seeAllLink, #DiscussionsTabPane .seeAllLink +{ + margin-top: 10px; + text-align: center; +} + +/*-------- Start DiscussionsTab --------*/ + +.threadActions +{ + text-align: right; + margin-top: 10px; + float: right; +} + +#DiscussionsTabPane .reply, #DiscussionsTabPane .toggleDiscussion +{ + cursor: pointer; +} + + +#defaultDicussionText, #newDiscussion +{ + padding-top: 10px; +} +#DiscussionsTabPane .posts +{ + display: block; +} +#DiscussionsTabPane .threadHeader .left +{ + float: left; +} +#DiscussionsTabPane .threadHeader .right +{ + float: right; +} +#DiscussionsTabPane .normal +{ + font-weight: normal; +} + +#DiscussionsTabPane .threadHeader +{ + position: relative; + background-color: #ECECEC; + padding: 4px 10px 4px 10px; +} + +#DiscussionsTabPane .threadHeader .title +{ + color: #000000; + font-weight: bold; + margin-bottom: .7em; +} +#DiscussionsTabPane .threadHeader .label +{ + color: #000000; +} +#DiscussionsTabPane .postMeta +{ + color: #666666; +} +#DiscussionsTabPane .threadHeader .value +{ + font-weight: bold; + color: #000000; +} + +#DiscussionsTabPane .reply +{ + font-weight: normal; + cursor: hand; +} + +#DiscussionsTabPane ul li +{ + list-style-type: none; + list-style-image: none; + padding-bottom: 10px; +} + +#DiscussionsTabPane ul +{ + padding-left: 0px; + margin-left: 0px; + padding-right: 2px; +} + +.IE #reviewList .right +{ + margin-right: -1em; +} + +#newDiscussion +{ + margin: 0 0 15px 0; +} +#newDiscussion #Title +{ + width: 50%; +} +#newDiscussion textarea +{ + width: 99%; + height: 10em; +} + +#DiscussionsTabPane +{ + margin-left: 0px; + padding: 0 1em 1em 1em; +} + + +.postMeta +{ + float: right; +} + +.postReply +{ + cursor: hand; + float: right; + font-weight: bold; +} + +.postSaveReply +{ + display: none; +} + +.postSaveReply textarea +{ + width: 99%; + margin-bottom: 4px; + height: 8em; +} + +.toggleDiscussion +{ + cursor: hand; +} + +.saveReplyErrorMessage +{ + display: none; + margin: 0 0 4px 0; + color: Red; + font-weight: bold; +} + +#discussionListItem .avatar +{ + float: left; + padding: 5px; + vertical-align: middle; +} + +#discussionListItem .discussion +{ + margin-left: 55px; + padding: 0 5px 5px 5px; + vertical-align: top; +} + +.IE7 #discussionListItem .avatar +{ + margin-top: 15px; +} + + +/*-------- End DiscussionsTab --------*/ + + +.flotChart +{ + height: 300px; +} + +#projectMenuBarTop +{ + padding: 10px 0 20px 0; + font-weight: bold; + font-size: 25px; +} +.dayHeader +{ + font-weight: bold; +} + +/*-------- Start StatsPage --------*/ +#statsPage +{ + border: none; + background-color: Transparent; + margin-top: 1em; +} + +#statsPage .rangeBox +{ + padding: 5px; + background-color: #ECECEC; + border: solid 1px #C2C2C2; + float: left; +} +#statsPage .statBox +{ + margin-top: 1em; + margin-bottom: 10px; + overflow: hidden; + display: none; +} +#statsPage .statBox h3 +{ + font-size: 1.1em; + display: inline; +} + +#statsPage #statMessage +{ + margin-top: 1em; + display: none; +} + +#statsPage #statDownloadBox img { + float: left; +} + +#statsPage .statDownloadLink { + padding-left: 5px; + vertical-align: middle; +} + +#pointTooltip +{ + border: solid #000000 1px; + height: 35px; + background-color: #EEEEEE; + position: absolute; + display: none; + text-align: center; + padding: 9px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + z-index: 1000; + white-space: nowrap; +} + +.flotChart +{ + height: 300px; +} + +/*-------- End StatsPage --------*/ + + +/***************************************************************/ +/* TagAutoComplete Styles */ +/***************************************************************/ +.AutoCompletePanel +{ + font-size: 95%; + border: solid .1em #999; + background-color: #f0f0f0; + padding: .15em; +} + +.AutoCompletePanel div.Row +{ + color: #000; + cursor: pointer; + background-color: transparent; + padding: .15em .25em; + text-align: left; +} + +.AutoCompletePanel div.Selected +{ + color: #fff; + background-color: #6D6D6D; +} + + +/*-------- Start Subscription Form --------*/ + +#subscribeForm +{ + background-color: #D3D3D1; + border: 1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 15px; + position: absolute; + display: block; +} + +#subscribeForm .subscribeFormbuttons +{ + text-align: right; + margin-top: 10px; +} +#subscribeForm .subscribeFormbuttons > button +{ + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor: pointer; +} + +#subscribeForm .subscribeFormclose +{ + display: none; +} + +#subscribeForm table +{ + margin-bottom: 15px; +} + +#subscribeForm table th +{ + text-align: left; + font-weight: bold; + border-bottom: 1px solid #000000; +} + +#subscribeForm table td +{ + padding: 5px 10px 5px 20px; +} + +#subscribeForm .rowHeading td +{ + font-weight: bold; + border-bottom: 1px solid #FFFFFF; +} + +#subscribeForm table tr td:first-child +{ + padding: 5px 40px 5px 0; +} + + +/*-------- End Subscription Form --------*/ + +/*-------- Start Tag Browser --------*/ + +.tagBrowserfade +{ + position: absolute; + background-color: #aaaaaa; +} +#tagBrowser +{ + background-color: #f4f4f4; + border:1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding:15px; + position: absolute; + display: block; +} + +#tagBrowser .tagBrowserbuttons +{ + text-align:right; + margin-top: 10px; +} +#tagBrowser .tagBrowserbuttons > button +{ + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor:pointer; +} + +#tagBrowser .tagBrowserclose +{ + display:none; +} + +.tagBrowserContainer { + width: 450px; +} + +.tagBrowserContainer h2 { + border-bottom: 1px solid #000000; + padding-bottom: 5px; +} +.tagBrowserContainer > p { + margin: 15px 0 15px 0; +} + +.tagBrowserContainer .tags { + margin: 5px; + height: 225px; + overflow-y: scroll; +} + + +/*-------- End Tag Browser --------*/ + +/*-------- Start List Filter Box --------*/ + +div#filterInputBox +{ + overflow:auto; + min-width:225px; +} + +.filterBox +{ + width: 100%; + background: #FFFFFF; + padding: 0px 2px; + height: 25px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid #888888; + table-layout: auto; + margin-bottom:5px; +} + + .filterBox #filterImageCell + { + text-align: right; + padding: 0px; + vertical-align: middle; + } + + .IE7 .filterBox #filterImageCell + { + padding:2px 2px 0 0; + } + + .filterBox #filterImg + { + background: transparent url('searchButton.png') no-repeat 0 0; + width: 22px; + height: 22px; + } + +table.filterBox +{ + table-layout: fixed; +} + + .filterBox .stxtcell + { + padding-right: 4px; + width:90%; + } + + .filterBox .stxtcell > input + { + margin-right: 4px; + height: 26px; + line-height:26px; + width: 100%; + padding: 0px; + padding-left: 4px; + padding-top: 2px; + border: none; + } + + .IE7 .filterBox .stxtcell > input + { + height: 20px; + } + + .filterBox .stxtcell > input.stxtinptpassive + { + color: #ACACAC; + } + +/*-------- End List Filter Box --------*/ + +/*-------- Start Notifications --------*/ + +#notificationsSummaryBox +{ + font-weight: bold; + padding: .5em; +} + + +.notificationsByDay, .notifications +{ + /*list-style: none;*/ +} + +.dayHeader +{ + border-bottom: 1px solid silver; + margin-top: 1em; + padding-bottom: .5em; +} + +.notifications +{ + margin-top: .5em; +} + +ul.notifications li +{ + line-height: 1.5em; +} + +ul.notifications li.unread +{ + font-weight: bold; +} + +ul.notifications li ol, ul.notifications li ul +{ + margin-left: 1.5em; +} + +/*-------- End Notifications --------*/ + +/*-------- Start ProjectDetailsPage --------*/ + +#projectPage #projectInfo +{ + position: relative; + margin-top: 5px; + height: 100%; +} +#projectInfo .section +{ + float: left; + margin-bottom: 0px; + height: 100%; +} + + #projectInfo .section .itemBar, #projectInfo .section .itemBarLong + { + clear: both; + padding: 7px 0 7px 0; + overflow:auto; + } + + #projectInfo .section .itemBarLong:first-child + { + padding-top:3px; + } + + .IE7 #projectInfo .section .itemBar, .IE7 #projectInfo .section .itemBarLong + { + padding-top: 5px; + } + + #projectInfo .section .itemBar > label, #projectInfo .section .itemBarLong > label + { + width: 130px; + float: left; + text-transform: capitalize; + } + + #projectInfo .section .itemBar div#yourRating { + float:left; + } + + #projectInfo .section .itemBar div.RatingStar { + margin:2px 1px 0 0; + } + + #projectInfo .section .itemBar div#RatingCount { + padding: 0 0 0 3px; + } + + #projectInfo .section .itemBar .ratingsWithCountContainer img { + vertical-align:top; + float:left; + padding-right: 4px; + } + + #projectInfo .section .itemBar > span, #projectInfo .section .itemBarLong > span, #projectPage .section .itemBar > div + { + float: left; + } + + #projectInfo .section .itemBar, #projectInfo .section .itemBarLong { + width: 100%; + } + + #projectInfo .section .itemBar > span { + float: none; + } + + #projectInfo .section .itemBar > span .shareThisItem { + white-space: nowrap; + } + + #projectInfo .section .itemBarLong div + { + margin-left: 130px; + padding: 0; + } + + #projectInfo .section .viewonlinecont + { + background-color:#d3d3d3; + padding:5px 10px; + margin-top:10px; + float:left; + font-weight:bold; + } + +#projectInfo #sectionLeft +{ + width: 50%; +} +#projectInfo #sectionRight +{ + width: 50%; +} +.IE7 #projectInfo #sectionRight +{ + width: auto; +} + +#projectPage h2.projectSummary +{ + font-weight:normal; + font-size: 1.1em; + margin-bottom: 11px; + line-height:1.4; + word-wrap: break-word; +} + +.IE7 #projectPage h2.projectSummary +{ + font-family: 'Segoe UI' , 'Lucida Grande' ,Verdana,Arial,Helvetica,sans-serif; +} + +.IE #projectPage .projectTitle, .IE9 #projectPage .projectTitle +{ + width: 100%; +} + +#projectPage #reportAbuse +{ + float: left; + font-size: x-small; +} + +#projectPage .hiddenSidebar { + display: none; +} + +#projectPage .fullProjectBody { + margin-left:-275px; +} + +.IE8 #projectPage #userCard { + float: left; + height: auto; +} + +#projectPage #userCard .avatar img { + max-width: 100px; + max-height: 100px; +} + +#projectDetails +{ + overflow:hidden; +} + +#projectBody +{ + width: 100%; + overflow:hidden; +} + + #projectDetails > div:first-child + { + margin: 5px 0 0 260px; + } + + #projectBody > div:first-child + { + margin: 20px 0 0 260px; + } + + .IE7 #projectContent .tabHeaders + { + overflow:hidden; + margin-bottom:-20px; + } + +#projectPage .sidebar +{ + float: left; + width: 215px; + margin-right: -250px; +} + + #projectPage .sidebar .section + { + margin: 20px 0 10px 0; + } + + #projectPage .sidebar .section .titleBar h3 + { + padding: 0 0 2px 0; + } + + #projectPage .sidebar .section .itemBarRight + { + min-height: 21px; + position: relative; + padding-top: 5px; + } + + #projectPage .sidebar .section .titleBar + { + margin-bottom: 5px; + } + + #projectPage .sidebar .section .authorItem + { + padding: 0 0 5px 10px; + } + + #projectPage .sidebar .section .authorItem a + { + display:block; + float:left; + max-width:170px; + } + + #projectPage .sidebar .section .authorItem > div + { + float:right; + } + + #projectPage .sidebar #advertisement + { + margin-top: 20px; + } + + #projectPage .sidebar #advertisement .label + { + text-align: center; + } + + #projectPage .sidebar #moreFromAuthor + { + width:225px; + margin: 20px 0 10px 0; + float:left; + } + + #projectPage .sidebar #moreFromAuthor .bottomBar { + padding: 5px 0px 5px 25px; + text-align: right; + } + +#projectPage #Collections { + min-height:22px; + min-width:169px; +} + +#projectPage #Collections .bevelButton { + background-color: #8CC63F; +} + +#projectPage .bevelButton +{ + font-weight: bold; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + color: white; + padding: 2px 10px 3px; + text-align: center; +} + +#projectPage #DiscussionsTabPane .bevelButton +{ + font-weight: normal; + color: black; + padding: 1px 10px 1px; +} + +#projectPage #Downloads { + padding: 0 0 8px 0; + float: left; +} + #projectPage #Downloads > div:first-child { + float: left; + margin: 15px 0 0 0; + height:35px; + line-height:1.6; + width: 130px; + } + #projectPage #Downloads label + { + font-size:1.25em; + } + #projectPage #Downloads input + { + min-width: 100px; + padding: 3px 10px 3px 10px; + margin: 3px 10px 0 10px; + font-weight: bold; + float: left; + } + + #projectPage #Downloads .button + { + background-color:#007494; + color:#fff; + padding:5px 15px; + margin: 15px 15px 0 0; + float:left; + } + + #projectPage #Downloads .button:hover + { + background-color:#0095c4; + text-decoration:none; + } + +#projectPage #projectBody .attachments { + margin: 0 0 15px 0; +} + + #projectPage #projectBody .attachments label { + float: left; + } + + #projectPage #projectBody .attachments .files a, #projectPage #projectBody .attachments .files span { + float: left; + padding: 0 5px 0 5px; + } + +#publishBar +{ + border: 1px solid #707070; + background-color: #F8F8F8; + margin-top: 10px; +} + +#sourceItem { + height: 610px; +} + #sourceItem > div:first-child { + padding: 20px 5px 0 15px; + font-weight: bold; + } + #sourceItem > div+div { + height: 560px; + padding: 10px; + overflow: auto; + } + #sourceItem .copyCode { + font-weight: normal; + margin: 0 15px 0 0; + float: right; + } + +.sourceList { + height: 600px; + padding: 5px; + border-top: 1px solid #CCC; + margin-top: -1px; +} + + .sourceList .sourceListTabHeader + { + margin:20px 10px; + } + .sourceList .sourceListTabs + { + margin-bottom:20px; + border-bottom: 1px solid #CCC; + float:left; + width:100%; + } + .sourceList .sourceListTabs .languageTab { + padding:5px 10px 5px 10px; + font-weight: bold; + float: left; + margin: 0 3px 0px 0; + color:#00749E; + } + .sourceList .sourceListTabs .languageTab:hover + { + color: #0095C4; + } + + .sourceList .sourceListTabs .selectedLanguage { + background-color: #fff; + color: #000; + border: 1px solid #ccc; + border-bottom:none; + margin-bottom:-2px; + } + + .sourceList .sourceListTabs .unselectedLanguage { + cursor: pointer; + } + + .sourceList .endTabs { + clear: both; + } + + .sourceList .sourceListContent { + padding-top: 5px; + } + + +.sbfc, +.sbfe +{ + white-space: nowrap; + text-indent: 20px; + cursor: pointer; + padding: .2em 0em .2em 0em; + background-repeat: no-repeat; + background-position: left center; + font-weight: bold; + text-decoration: none !important; +} + +.sbfc +{ + background-image: url(../samples/node_closed.gif); +} + +.sbfe +{ + white-space: nowrap; + background-image: url(../samples/node_opened.gif); +} + +.ndbf +{ + white-space: nowrap; + text-indent:20px; +} + +.sbf +{ + white-space: nowrap; + background: url(../samples/bullet.gif) no-repeat 4px -1px; + cursor: pointer; + text-indent: 20px; + white-space: nowrap; + padding: .1em 0em .1em 0em; +} + +.sbsf, +.sbf:hover +{ + color: #000; + text-decoration: none !important; + +} + +.sbsf +{ + color: #000 !important; + background-color: rgb(232, 232, 232); +} + +.sbf:hover +{ + color: #ce8b10; +} + +/*-------- Translate --------*/ +.translatePage { + width: 900px; +} +.translatePage .fileManager { + margin-bottom:20px; +} +.translatePage .fileManager h4 { + margin-top:10px; +} +.translatePage #formContainer { + width: 100%; +} +.translatePage .formLabel { + width: 300px; + padding: 5px; +} + .translatePage .textInput { + width: 425px; +} +.translatePage TEXTAREA.richText { + height: 600px; + width: 620px; +} +.translatePage TEXTAREA.unadornedEditor { + height: 600px; +} +.translatePage .formWideLabel, .translatePage .richText { + padding: 5px; +} +.translatePage .formWideLabel, .translatePage .unadornedEditor { + width: 750px; + padding: 5px; +} +.translatePage #languageSelection { + margin: 15px; + display: inline-block; +} + +.translateTab, .translateTabSelected { + font-weight: bold; + float: left; + text-align: center; + margin: 10px; + padding: 7px; + background: #E8E8E8; + white-space: nowrap; + cursor: pointer; +} + +.translateTabSelected +{ + color: White; + background: Gray; +} + +.translateTabSelected .translateLabel, .translateTab .translateLabel +{ + white-space: nowrap; + float: left; + padding: 0 5px 0 5px; +} + +.translateTab #deleteLanguage, .translateTab #moreLanguages +{ + padding-left: 10px; +} + +.translateLabel #deleteLanguage { + color: #FFFFFF; +} +/*-------- End Translate --------*/ +/*-------- Begin Eula --------*/ + + +#eulaPagefade +{ + position: absolute; + background-color: #FFFFFF; +} + +#eulaPage +{ + background-color: #f4f4f4; + border: 1px solid #000000; + -border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 15px; + display: block; + max-width: 70%; +} + +#eulaPage .eulaPageclose +{ + text-align: right; +} + +#eulaPage .eulaPagemessage +{ + overflow: auto; + max-height: 350px; +} + + #eulaPage .eulaPagemessage h1 + { + margin: 0 0 5px 0; + } + +#eulaPage .eulaPagebuttons +{ + text-align: right; + margin-top: 10px; +} +#eulaPage .eulaPagebuttons > button +{ + color: Blue; + border: none; + background: none; + font-weight: bold; + cursor: pointer; +} + + + #eulaPage #eula #documentText + { + line-height: normal; + } + +/*-------- End DocumentView --------*/ +/*-------- Begin FAQ --------*/ + +#FAQPage #TableOfContents h2 +{ + padding: 5px; + border-bottom: 2px solid #EFEFEF; + margin: 0 0 10px 0; + max-width: 70%; +} + +#FAQPage .FAQSection +{ + padding: 10px 0px; + width: 70%; +} + + #FAQPage .FAQSection h2 + { + padding: 5px; + border-bottom: 2px solid #EFEFEF; + } + + #FAQPage .FAQSection h3 + { + padding: 5px; + } + + #FAQPage .FAQSection ul, #FAQPage .FAQSection ol + { + margin: 0; + } + + #FAQPage .FAQSection #description > div + { + overflow: auto; + padding-left: 10px; + } + + #FAQPage .FAQSection #description img + { + float: left; + } + + #FAQPage .FAQSection #description div > div + { + padding-top: 10px; + float: left; + } + + #FAQPage .FAQSection > div > div + { + padding: 0 15px; + } + + #FAQPage #Reputation th, #FAQPage #Reputation td + { + padding-left: 20px; + } + +/*-------- End FAQ --------*/ +/*-------- Begin DocumentView --------*/ + +#documentView #documentText +{ + line-height: normal; +} + +/*-------- End DocumentView --------*/ + +.Opera wbr:after +{ + content: "\00200B"; +} + + +.IE9 wbr:after +{ + content: "\00200B"; +} + +.IE8 wbr { + width: 0px; + display: inline-block; + overflow: hidden; +} + +/*-------- Begin FileManager --------*/ + +.uploadControlNoError + { + height:30px + } +.uploadControlWithError + { + height:80px; + } +/*-------- End FileManager --------*/ + +/*-------- Begin User Card --------*/ +#userCard .titleBar { + border-bottom: solid 5px #E8E8E8; + margin: 10px 0 5px 0; +} + #userCard .titleBar h3 + { + font-size: 1.0em; + font-weight: bold; + line-height: 125%; + padding: 0 0 2px 0; + } + +#userCard .userFeed { + float: right; +} + +#userCard .bio { + max-width:300px; + white-space: normal; +} + +#userCard .avatar +{ + padding: 5px 5px 10px 5px; + margin: 0 0 3px 0; + text-align: center; +} + +#userCard .itemBar { + padding: 5px; +} + + #userCard .itemBar label + { + float: left; + text-transform: capitalize; + } + + #userCard .itemBar label+span { + display: block; + margin-left: 100px; + } + +#userCard .collapsableSidebar { + clear:both; + width:100%; + margin-top: 5px; +} + +/* Profile Overrides */ +#userCard +{ + padding: 0 0 10px 0 +} + +#userCard .profile-usercard +{ + width:225px; +} + +#userCard .profile-usercard, #userCard .profile-inline, #userCard .profile-inline-header +{ + border:0px; + background-color:#fff; +} + +#userCard .profile-userimage-large +{ + margin-bottom:10px; + border:none; + width:auto; + height:auto; +} + +#userCard .profile-inline .profile-inline-header-details +{ + width:100%; + display:block; + clear:both; + margin-left:0px; +} + + + +/*-------- End User Card --------*/ +/*-------- Begin Description Progress Meter --------*/ + +#descriptionProgressMeter { + float: right; + border-top: 1px solid #DADADA; + border-left: 1px solid #DADADA; + width: 210px; + padding-left: 7px; +} + + #descriptionProgressMeter h4 { + font-weight: bold; + } + + #descriptionProgressMeter #progressGraphic { + border: 1px solid #888888; + width: 205px; + margin: 10px 0; + background-color: #E9E9E9; + padding: 1px 0 0 1px; + } + + #descriptionProgressMeter #progressGraphic div { + background-image: url("../common/progress_meter.png"); + padding-left: 5px; + } + + #descriptionProgressMeter #progressText { + font-weight: bold; + margin: 5px 0; + + } + + #descriptionProgressMeter #goodDescriptionText p+p { + padding: 5px 0; + } + + #descriptionProgressMeter #goodDescriptionText > div { + margin-top: 5px; + width: 150px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + overflow: auto; + } + + #descriptionProgressMeter #goodDescriptionText div img { + float: left; + } + + #descriptionProgressMeter #goodDescriptionText div div { + margin: 7px 0 5px 10px; + } + +/*-------- End Description Progress Indicator --------*/ + +/*-------- Start Sample Pack Tab View --------*/ +.SamplePackTab #headerBar +{ + padding: 15px 5px 20px 5px; + font-weight: bold +} + .SamplePackTab #headerBar .reportCount + { + padding-top: 2px; + } + .SamplePackTab #headerBar .samplePackSort + { + float: right; + color: #666; + } +/*-------- End Sample Pack Tab View --------*/ \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/description/Combined.css b/samples/winrt/ImageManipulations/description/Combined.css new file mode 100644 index 0000000..e69de29 diff --git a/samples/winrt/ImageManipulations/description/Galleries.css b/samples/winrt/ImageManipulations/description/Galleries.css new file mode 100644 index 0000000..ac2e94e --- /dev/null +++ b/samples/winrt/ImageManipulations/description/Galleries.css @@ -0,0 +1,418 @@ +/* *************************************************** +Galleries.css - Common Structure + +This is where we define common layout for structures that are truly close to common across the different +Galleries sites. To make sure this works we need to follow certain conventions. + +1. Define each logical structure in its own section with its own comment block that gives the section +a Name, Description and defines the root element if one exists (i.e #someElement). Also, mark the closing block. + +2. Indent styles in a section to represent if it is a child of a previous element. +i.e. #someDiv{ + } + #someDiv ul { + } + +3. Do not include brand specific information here like colors and fonts unless they are *really* common. + +4. If there is an element that you know will be overridden in each brand stylesheet still include it here with an empty definition. +This will aid in knowing what section to override and what selectors to use. + +i.e. #someSction a { + } + +5. When you add a new section also update the Table of Contents below so that we have a quick overview of the sections + + *****************************************************/ + +/**************************************************** +Table of Contents + + Global - global classes + + FileAttachmentDisplay - The list of attached files under the editor + Eyebrow - The breadcrumb control at the top of the master page + Pager - The common paging control, used for browsing pages of search results + Profile User Card - Elements in the profile usercard control + SideNav - The navigation side bar that contains the search filters + + +*****************************************************/ + +/******************************** +Name: Global +Root: none +Description: truly global classes +********************************/ +body { + text-align: left; + direction: ltr; +} + +img.rss { + background: url(../../../GlobalResources/Images/Rss.png) no-repeat; + background-position: 0px 0px; + height: 17px; + width: 17px; +} +/* End Global Section */ + +/******************************** +Name: FileAttachmentDisplay +Root: #fileAttachmentDisplay +Description: The list of attached files under the editor +********************************/ +#fileAttachmentDisplay { +} + #fileAttachmentDisplay .attachment { + margin-right: 10px; + float: left; + } + + #fileAttachmentDisplay .attachment .displayAttachment { + padding: 0px 0 13px 0; + float: left; + } + + #fileAttachmentDisplay .attachment .removeAttachment { + background-image: url('/Content/Common/delete.png'); + display: block; + width: 16px; + height: 16px; + float: left; + } +/* End FileAttachmentDisplay Section */ + + +/******************************** +Name: Eyebrow +Root: .EyebrowContainer +Description: The breadcrumb control at the top of the master page +********************************/ +.EyebrowContainer { +} + .EyebrowContainer div.EyebrowElement{ + display:inline; + } + + .EyebrowContainer .EyebrowElement{ + font-weight:normal + } + .EyebrowContainer .EyebrowLeafLink{ + color:#000; + } +/* End Eyebrow Section */ + +/******************************** +Name: Pager +Root: #Pager +Description: The common paging control, used for browsing pages of search results +********************************/ +#Pager { +} + #Pager div{ + display:inline; + } +/* End Pager Section */ + +/******************************** + +Name: Profile User Card +Root: #dashboardPage #userCard +Description: Elements in the profile usercard control + +********************************/ + #dashboardPage #userCard .profile-usercard-inline { + margin: 5px 0 10px 0; + } + + /* #dashboardPage #userCard .profile-usercard { + width: 288px; + } +/* End Profile User Card Section */ + +/******************************** + +Name: Discussion +Root: #DiscussionsTabPane +Description: Defines the layout of the dicussion + + +********************************/ +#DiscussionsTabPane { +} + + #DiscussionsTabPane .itemHidden + { + background: lightgrey; + } + + #discussionListItem { + } + + .discussion .postActions + { + float: right; + } + + #discussionListItem .postItem + { + white-space: pre-wrap; + word-wrap: break-word; + font-size:1em; + } + +/* End Discussion Section */ + + +/******************************** + +Name: SearchDefaultLocale +Root: .searchDefaultLocale +Description: Defines the layout of the include english result checkbox on the Browse Page + + +********************************/ +.searchDefaultLocale +{ + float: right; + margin: 20px 0 0 5px; +} + .searchDefaultLocale input + { + vertical-align:top; + } + .searchDefaultLocale span + { + margin-left: -3px; + } +/*-------- End SearchDefaultLocale --------*/ + + +/******************************** + +Name: SideNav +Root: #sideNav +Description: Defines the layout of the naviation elements on the side of the Browse Page + These represent the different filters like Code Language, Category and Tag + + +********************************/ + +#sideNav { + width: 250px; + vertical-align:top; + background-color:#eee; +} + #sideNav h3 { + } + + #sideNav .section { + padding: 0 0 10px 0; + position: relative; + } + + #sideNav .section a { + } + + #sideNav .section a:hover { + } + + #sideNav .section > div { + padding:5px 5px 5px 0; + line-height:150%; + } + + #sideNav .section ul { + list-style-type:none; + padding:0px; + margin:0px; + } + + #sideNav .section ul li { + position: relative; + padding: 5px 5px 5px 0; + } + + #sideNav .section ul li .selectedFilter { + float: left; + padding-right: 5px; + } + + #sideNav .section div.itemCount { + float: right; + } + + #sideNav .section form input[ type = "checkbox"] { + margin: 0px 4px 0px 0px; + vertical-align: middle; + } +/* End SideNav Section */ + +/*----------- Contribution Logos *******/ +.contributionLogo { + float: left; + position: relative; + margin-right: 6px; +} + +.logo_visualstudio { + background: transparent url('../common/logos/visualstudio.png') no-repeat; + width: 23px; + height: 12px; + margin-top: 3px; +} +.logo_allinonecode { + background: transparent url('../common/logos/1code.png') no-repeat; + width: 14px; + height: 16px; +} +.logo_exchange { + background: transparent url('../common/logos/exchange.png') no-repeat; + width: 14px; + height: 16px; +} +.logo_ie { + background: transparent url('../common/logos/ie.png') no-repeat; + width: 16px; + height: 16px; +} +.logo_office { + background: transparent url('../common/logos/office.png') no-repeat; + width: 17px; + height: 16px; +} +.logo_windows { + background: transparent url('../common/logos/windows.png') no-repeat; + width: 17px; + height: 16px; + } +.logo_azure { + background: transparent url('../common/logos/windowsazuredark.png') no-repeat; + width: 16px; + height: 16px; +} + +.logo_windowsphone { + background: transparent url('../common/logos/windowsphone.png') no-repeat; + width: 16px; + height: 16px; + } + + .contributionLogoTip { + position: absolute; + display: none; + border: solid 1px #CCC; + color: #333; + background-color: #F0F0F0; + font-size: 11px; + font-family: "Segoe UI",Sans-Serif; + box-shadow: 3px 3px 5px #888; + -moz-box-shadow: 3px 3px 5px #888; + z-index: 1003; + padding: 5px; + min-width: 250px; + } + +/*----------- End Contribution Logos *******/ + +.clear +{ + clear: both; +} + +.customcontributionLogoTip { + position: absolute; + display: none; + border: solid 1px #CCC; + background-color: white; + color: #333; + font-size: 11px; + font-family: "Segoe UI",Sans-Serif; + box-shadow: 3px 3px 5px #888; + -moz-box-shadow: 3px 3px 5px #888; + z-index: 1004; + padding: 5px; + min-width: 250px; +} + +.customcontributionTittle { + font-size: 14px; + margin-left: 90px; +} + +.customcontributionDiscription { + font-size: 13px; + margin: 10px 5px; + text-align: justify; +} + +.customcontribution { + float: left; + position: relative; + margin-right: 6px; +} + +.customcontributionLink { + margin-left: 5px; +} + +.customcontributionlogo { + float: left; + padding: 0 10px; + margin: 0; + width: 70px; + height: 70px; + background-repeat: no-repeat; +} + + +.logo_azure_large { + background-image: url('../common/logos/windowsazure_large.png'); +} +.logo_visualstudio_large { + background-image: url('../common/logos/visualstudio_large.png'); +} +.logo_exchange_large { + background-image: url('../common/logos/exchange_large.png'); +} +.logo_ie_large { + background-image: url('../common/logos/ie_large.png'); +} +.logo_office_large { + background-image: url('../common/logos/office_large.png'); +} +.logo_windows_large { + background-image: url('../common/logos/windows_large.png'); +} +.logo_windowsphone_large { + background-image: url('../common/logos/windowsphone_large.png'); +} + +/* Custome Header */ +.dirSubHeading .windowssdk .container +{ + background: #FF3300 url('wpappsbackground.png') no-repeat; + color: white; + padding: 8px 10px 18px 170px; +} + +.dirSubHeading .windowssdk .container h1, .dirSubHeading .windowssdk .container h2 { + color: white !important; +} + +.dirSubHeading .windowssdk .container p { + margin: 20px 0 0 0 !important; +} + +.dirSubHeading .windowssdk .container a { + background-color:#ffd800; + color: #2a2a2a !important; + cursor:pointer; + font-size:13px; + font-family:'Segoe UI Semibold','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; + padding:4px 12px 6px; +} + + + diff --git a/samples/winrt/ImageManipulations/description/Layout.css b/samples/winrt/ImageManipulations/description/Layout.css new file mode 100644 index 0000000..625f777 --- /dev/null +++ b/samples/winrt/ImageManipulations/description/Layout.css @@ -0,0 +1,147 @@ +#container { + min-height: 768px; +} + +#leftSubHeaderContainer +{ + margin-top:20px; +} + +#title h1 +{ + font-size:25px; +} + +#subtitle h2 +{ + font-size:15px; +} + +#subtitle +{ + margin-left:10px; +} + + +#formContainer +{ + margin-left:10px; + margin-top:30px; +} + +.formLabel +{ + float:left; + width: 250px; +} + +.formRow +{ + clear:both; + padding: 10px 0 10px 10px; +} + + +.formRecaptchaRow +{ + clear:both; + float:left; + margin-top:20px; + margin-left:10px; + margin-bottom:20px; +} + +.formSubmitRow +{ + clear:both; + margin-top:20px; + margin-left:300px; + margin-bottom:20px; +} + +.formControl { + width:300px; + float:left; +} +.formControl .textInput +{ + width:300px; +} + +.formControl textarea +{ + width:425px; + height:100px; +} + +.formControl .tag +{ + width:425px; +} + +.formControl .richText +{ + margin-top:10px; + width:500px; + height:440px; +} + +.formWideLabel +{ + width:500px; +} + +.formBigLabel +{ + margin-top:20px; + font-size:20px; +} + +.formControlBelow +{ + clear:both; + margin-top:10px; + width:500px; +} + +.required +{ + color: Red; +} +.helpText +{ + color: #9D9D9D; + font-style: italic; +} + +#agreementSummary +{ + clear:both; + margin-top:10px; + width:800px; +} + +.field-validation-error, .validation-summary-errors +{ + color: #FF0000; + font-weight: bold; +} + +.tinyMCETemplate { + position: relative; + left: 400px; + width: 300px; + max-height: 300px; + overflow: auto; +} + +.IE6 .tinyMCETemplate { + left: 25px; +} + +.ownerBar { + padding: 5px; +} +.ownerBar .ownerBarOptions { + float: right; +} diff --git a/samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css b/samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css new file mode 100644 index 0000000..e3f039d --- /dev/null +++ b/samples/winrt/ImageManipulations/description/c2e69f54-1c43-4037-b90b-5f775f1d945fBrand.css @@ -0,0 +1,303 @@ +/*Global*/ +h1 { + font-size: 36px; + font-family: 'Segoe UI Light'; + color: #707070; + font-weight: normal; + margin-bottom: 17px !important; +} + +h2, h3, h4, h5, h6, #searchPage h3 { + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + font-weight:normal; + color: #2A2A2A !important; +} + +a, a:link, a:visited { + color: #0095c4; +} + +body { + color:#707070; +} + +.profile-usercard { + color:#707070 !important; +} + +/*temporary setting to override msdn_windows.css +can remove once conflicting settings are removed from that file*/ + + +.LocalNavigation, .LocalNavigation .TabOn, .LocalNavigation .TabOn:hover, .LocalNavigation .TabOff, .LocalNavigation .TabOff a:hover { + display: block; + background-color:transparent !important; + color: #0095c4; +} + +.LocalNavigation .TabOff a { +color:#707070 ; +} + +/*End Global*/ + +.EyebrowContainer +{ + margin-bottom: 0 !important; +} + +#sideNav +{ + width: 215px !important; +} + +#searchPage #mainContentContainer +{ + margin-right:0 !important; + margin-left:243px !important; +} + +#searchPage .dirSubHeading h2 +{ + font-size: 14px !important; + font-weight: normal !important; + color: #454545 !important; + line-height: 1.45; +} + +#searchPage #directoryListFooter, #searchPage #Pager { + font-size: 14px; +} + +#searchPage h2, #searchPage h3 +{ + font-size: 1.25em !important; +} + +#sideNav #contributeSection h3, .sidebar #contributeSection h3, #contributeSection h3 +{ + font-size: 1.65em !important; +} + +.subMenu > h2 +{ + font-family: 'Segoe UI Light','Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + font-weight:normal; + font-size:30px; + margin: 15px 10px 5px 0; + padding-bottom:0px; +} + +.itemRow { +} + .itemRow .itemBody, .itemRow .itemInfo { + padding: 18px 17px 20px 0; + font-size: 14px; + line-height: 1.45em; + } + + .itemRow .itemTitle { + font-weight: normal; + } + + .itemRow .summaryBox{ + color: #454545; + } + + .Samples #MainContent .itemRow .itemTitle a { + font-weight: 600 !important; + line-height: 1.45; + } + #MainContent a.officialMicrosoftLabel + { + color: #ACACAC; + } + + +.tabContents { + border-top-width:0px; +} + +#UploadPage { + margin: 0px 0px 0px 10px; +} + #UploadPage h1 { + padding: 0; + font-size: 22px; + } + #UploadPage h2 { + color:#F39700 !important; + } + + #UploadPage #uploadPageInstruction { + margin-top:10px; + } + + #UploadPage fieldset { + margin-left:0px; + } + + #UploadPage fieldset h2 { + font-weight:normal; + } + + #UploadPage fieldset#uploadsForm{ + margin-top:25px; + } + + #UploadPage fieldset#summary textarea { + margin-left:0px; + } + + #UploadPage .projectTypeChoice > div { + height: 250px; + } + +#sideNav { +} + + #sideNav .section h3 { + background-color: transparent; + + } + + #sideNav .section UL LI { + border-bottom-width: 0px; + } + + #sideNav .section form > div { + border-bottom: none; + color: #707070; + } + #sideNav .section ul li > div.itemCount + { + color: #707070; + } + + +#searchPage { +} + + #searchPage h2, #searchPage h3 { + text-transform:none; + background-color:transparent; + font-weight:normal; + font-size:1.2em; + } + + #searchPage .browseFilterBar { + background-color:transparent; + border-width:0px; + font-weight:normal; + } + +#requestsPage { + padding-top:15px; +} + #requestsPage .tabHeaders { + overflow: visible; + } + + #requestsPage #requestsList { + border: none; + } + + + #requestsPage h2, #requestsPage h3 { + text-transform:none; + background-color:transparent; + font-weight:normal; + font-size:1.2em; + } + + .reqBrowseContent .title { + font-weight: bold !important; + color:#000 !important; + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + } + + .reqDescPage #header #votenumber { + height: 30px; + padding: 9px 12px 3px 12px; + } + +#extraActions { +} + #extraActions .section + { + margin-bottom: 10px; + } + #extraActions .section a + { + font-weight:normal; + } + + #extraActions #contributeSection div img { + width:0px; + } + + + +#projectPage { +} + + #projectPage .projectTitle { + color: #707070; + margin: 5px 0px 15px 0px; + } + + #projectPage h2.projectSummary, #projectPage #projectInfo, #projectPage .tabHeaders { + font-size: 14px !important; + line-height: 1.45em; + color: #454545 !important; + font-weight: normal !important; + } + + #projectPage #projectInfo a { + color: #00749e; + } + + #projectPage #Downloads a, #projectPage #Downloads label { + font-size: 14px; + } + + #projectPage #reportAbuse { + font-size: 1em; + } + + #projectPage #publishBar a, #projectPage #publishBar a:visited { + color: #0095c4; + font-weight: normal; + } + + #projectPage #Collections .bevelButton{ + background-color: #F8F8F8; + color: #0095C4; + border: 1px solid #707070; + } + + #projectPage #DiscussionsTabPane .threadHeader .title { + font-weight:bold !important; + color:Black !important;#F8F8F8; + font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif !important; + } + + #projectPage .sidebar .section .titleBar h3 { + font-weight:normal; + font-size:1.2em; + } + +#LocalNav { +} + + #LocalNav.HeaderTabs { + margin-left:11px; + } + + +#searchPage .dirSubHeading h1 +{ + margin-bottom:17px !important; +} + + diff --git a/samples/winrt/ImageManipulations/description/iframedescription.css b/samples/winrt/ImageManipulations/description/iframedescription.css new file mode 100644 index 0000000..9abc9cd --- /dev/null +++ b/samples/winrt/ImageManipulations/description/iframedescription.css @@ -0,0 +1,179 @@ +body { + color: #000000; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 0.813em; + font-style: normal; + word-wrap: break-word; +} + +/*BEGIN HEADERS*/ +.h1, h1 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.4em; + font-weight: bold; + margin: 0; +} + +.h2, h2 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.2em; + font-weight: bold; +} +.h3, h3 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.077em; + font-weight: bold; +} +.h4, h4 { + color: #3A3E43; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1em; + font-weight: bold; +} +h4.subHeading { + margin-bottom: 7px; + margin-top: 13px; +} +/*END HEADERS*/ + +/*BEGIN LINKS*/ +a:link { + color: #00749E; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +a:visited { + color: #960BB4; + text-decoration: none; +} +a:focus { + outline: 1px dotted #000000; +} + +a.libraryLink:link { + text-decoration:none; + border-bottom:1px dotted; +} + +/*END LINKS*/ + +/*BEGIN IMAGES*/ +img { + border: 0 none; +} +/*END IMAGES*/ + +/*BEGIN TABLE*/ +.title table { + color: #000000; + font-family: 'Segoe UI',Verdana,Arial; + font-size: 1.077em; + font-style: normal; +} +table { + border-collapse: collapse; +} + +table, table th, table td { + border:1px solid #BBBBBB; +} +/*END TABLE*/ + +/*BEGIN LIST*/ +ul { + list-style-type: disc; + margin-left:40px; + padding-left: 0; +} +ul li { + padding-bottom: 10px; +} +ol { + margin-left:40px; + padding-left: 0; +} +ol li { + padding-bottom: 10px; +} +/*END LIST*/ + +.scriptcode { + position: relative; + padding: 8px 8px 8px 8px; + background: #FFFFFF; + font-size: 12px; + line-height: 125%; + font-weight:normal; +} +.scriptcode pre +{ + white-space: pre-wrap !important; /* css-3 */ + word-wrap: break-word !important; /* Internet Explorer 5.5+ */ + margin:0 0 10px 0 !important; + padding: 10px; + border-top: solid 2px #D0D2D2; + border-bottom: solid 2px #D0D2D2; + border-left: solid 1px #D0D2D2; + border-right: solid 1px #D0D2D2; +} + +.scriptcode .title { + color:#E66A38; + font-size: 12px; + font-weight:bold; + margin: 0; + min-height: 23px; +} +.scriptcode .title > span:first-child { + border-left: solid 1px #D0D2D2; +} +.scriptcode .title > span { + padding: 4px 8px 4px 8px; + display: inline-block; + border-top: 1px solid #D0D2D2; + border-right: 1px solid #D0D2D2; + border-collapse: collapse; + text-align: center; + background: white; +} +.scriptcode .title > span.otherTab { + color: #1364C4; + background: #EFF5FF; + cursor: pointer; +} + +.scriptcode .hidden { + display: none !important; + visibility: hidden !important; +} + +.scriptcode .copyCode { + padding: 8px 2px 0 2px !important; + margin-right: 15px; + position: absolute !important; + right: 0 !important; + top: 17px; + display:block !important; + background: #FFFFFF; +} +.scriptcode .pluginLinkHolder { + display: none; +} +.scriptcode .pluginEditHolderLink { + display: none; +} + +.Opera wbr +{ + display: inline-block; +} + +.IE9 wbr:after +{ +content: "\00200B"; +} diff --git a/samples/winrt/ImageManipulations/description/offline.js b/samples/winrt/ImageManipulations/description/offline.js new file mode 100644 index 0000000..f5d07c8 --- /dev/null +++ b/samples/winrt/ImageManipulations/description/offline.js @@ -0,0 +1,52 @@ +var Galleries = Galleries || { }; + +(function() { + + function findElem(parent, tagName, className) { + var elemToSearch = (parent) ? parent : document.body; + var tagMatch = elemToSearch.getElementsByTagName(tagName); + var evaluator = function(elem) { + return (className) ? (elem.className.indexOf(className) > -1) : true; + }; + + return findArrayElem(tagMatch, evaluator); + } + + function findArrayElem(array, evaluator) { + var newArray = new Array(); + for (var count = 0; count < array.length; count++) { + if (evaluator(array[count])) { + newArray.push(array[count]); + } + } + return newArray; + } + + function iterateElem(elems, delegate) { + for(var count = 0; count < elems.length; count++) { + delegate(count, elems[count]); + } + } + + function isHidden(elem) { + return (elem.offsetHeight === 0 && elem.offsetWidth === 0) || elem.style && elem.style.display === "none"; + } + + function onWindowLoad(callback) { + attachEventHandler(null, 'load', callback); + } + + function attachEventHandler(elem, event, callback) { + var elemToAttach = (elem) ? elem : window; + if (document.addEventListener) { + elemToAttach.addEventListener(event, callback, false); + } else if ( document.attachEvent ) { + elemToAttach.attachEvent('on' + event, callback); + } + } + + Galleries.findElem = findElem; + Galleries.iterateElem = iterateElem; + Galleries.attachEventHandler = attachEventHandler; + Galleries.onWindowLoad = onWindowLoad; +})(); \ No newline at end of file diff --git a/samples/winrt/ImageManipulations/license.rtf b/samples/winrt/ImageManipulations/license.rtf new file mode 100644 index 0000000..690a7ad --- /dev/null +++ b/samples/winrt/ImageManipulations/license.rtf @@ -0,0 +1,25 @@ +{\rtf1\ansi\ansicpg1252\uc1\htmautsp\deff2{\fonttbl{\f0\fcharset0 Times New Roman;}{\f2\fcharset0 MS Shell Dlg;}}{\colortbl\red0\green0\blue0;\red255\green255\blue255;}\loch\hich\dbch\pard\plain\ltrpar\itap0{\lang1033\fs16\f2\cf0 \cf0\ql{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\fs40\f2 {\ltrch MICROSOFT LIMITED PUBLIC LICENSE version 1.1}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line {\ltrch ----------------------}\line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch This license governs use of code marked as \ldblquote sample\rdblquote or \ldblquote example\rdblquote available on this web site without a license agreement, as provided under the section above titled \ldblquote NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.\rdblquote If you use such code (the \ldblquote software\rdblquote ), you accept this license. If you do not accept the license, do not use the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch 1. Definitions}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch The terms \ldblquote reproduce,\rdblquote \ldblquote reproduction,\rdblquote \ldblquote derivative works,\rdblquote and \ldblquote distribution\rdblquote have the same meaning here as under U.S. copyright law. }\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch A \ldblquote contribution\rdblquote is the original software, or any additions or changes to the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch A \ldblquote contributor\rdblquote is any person that distributes its contribution under this license.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch \ldblquote Licensed patents\rdblquote are a contributor\rquote s patent claims that read directly on its contribution.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch 2. Grant of Rights}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (A) Copyright Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (B) Patent Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch 3. Conditions and Limitations}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (A) No Trademark License- This license does not grant you rights to use any contributors\rquote name, logo, or trademarks.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (E) The software is licensed \ldblquote as-is.\rdblquote You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 {\ltrch (F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) extend only to the software or derivative works that you create that run directly on a Microsoft Windows operating system product, Microsoft run-time technology (such as the .NET Framework or Silverlight), or Microsoft application platform (such as Microsoft Office or Microsoft Dynamics).}\li0\ri0\sa0\sb0\fi0\ql\par} +{\f2 \line \li0\ri0\sa0\sb0\fi0\ql\par} +} +} \ No newline at end of file -- 2.7.4
+

Media capture using capture device sample

+
+
+ + + +
+ +
+

This sample demonstrates how to use the +MediaCapture API to capture video, audio, and pictures from a capture device, such as a webcam. +

+

Specifically, this sample covers:

+
    +
  • Previewing video from a capture device, such as a webcam, connected to the computer. +
  • Capturing video from a capture device, such as a webcam, connected to the computer. +
  • Taking a picture from a capture device, such as a webcam, connected to the computer. +
  • Enumerating cameras connected to the computer.
  • Adding a video effect to a video.
  • Recording audio from a capture device connected to the computer.
+

+

For more information on capturing video in your app, see +Quickstart: capturing a photo or video using the camera dialog and +Quickstart: capturing video using the MediaCapture API.

+

Important  

+

This sample uses the Media Extension feature of Windows 8 to add functionality to the Microsoft Media Foundation pipeline. A Media Extension consists of a hybrid object that implements both Component Object Model (COM) and Windows Runtime + interfaces. The COM interfaces interact with the Media Foundation pipeline. The Windows Runtime interfaces activate the component and interact with the Windows Store app. +

+

In most situations, it is recommended that you use Visual C++ with Component Extensions (C++/CX ) to interact with the Windows Runtime. But in the case of hybrid components that implement both COM and Windows Runtime interfaces, such as Media + Extensions, this is not possible. C++/CX can only create Windows Runtime objects. So, for hybrid objects it is recommended that you use +Windows Runtime C++ Template Library to interact with the Windows Runtime. Be aware that Windows Runtime C++ Template Library has limited support for implementing COM interfaces.

+

+

To obtain an evaluation copy of Windows 8, go to +Windows 8.

+

To obtain an evaluation copy of Microsoft Visual Studio 2012, go to +Visual Studio 2012.

+

Related topics

+
Windows 8 app samples +
Roadmaps
Adding multimedia +
Capturing or rendering audio, video, and images +
Designing UX for apps +
Roadmap for apps using C# and Visual Basic +
Roadmap for apps using C++ +
Roadmap for apps using JavaScript +
Tasks
Quickstart: capturing a photo or video using the camera dialog +
Quickstart: capturing video using the MediaCapture API +
Reference
AddEffectAsync +
ClearEffectsAsync +
MediaCapture +
MediaCaptureSettings +
MediaEncodingProfile +
StartRecordToStorageFileAsync +
Windows.Media.Capture
+

Operating system requirements

+ + + + + + + + + + + +
Client
Windows 8
Server
Windows Server 2012
+

Build the sample

+

+
    +
  1. Start Visual Studio Express 2012 for Windows 8 and select File > +Open > Project/Solution.
  2. Go to the directory in which you unzipped the sample. Go to the directory named for the sample, and double-click the Visual Studio Express 2012 for Windows 8 Solution (.sln) file. +
  3. Press F7 or use Build > Build Solution to build the sample.
+

+

Run the sample

+

To debug the app and then run it, press F5 or use Debug > Start Debugging. To run the app without debugging, press Ctrl+F5 or use +Debug > Start Without Debugging.

+
+ +
+ + +