1//********************************************************* 2// 3// Copyright (c) Microsoft. All rights reserved. 4// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8// 9//********************************************************* 10 11// 12// AdvancedCapture.xaml.cpp 13// Implementation of the AdvancedCapture class 14// 15 16#include "pch.h" 17#include "AdvancedCapture.xaml.h" 18 19using namespace SDKSample::MediaCapture; 20 21using namespace Windows::UI::Xaml; 22using namespace Windows::UI::Xaml::Navigation; 23using namespace Windows::UI::Xaml::Data; 24using namespace Windows::System; 25using namespace Windows::Foundation; 26using namespace Windows::Foundation::Collections; 27using namespace Platform; 28using namespace Windows::UI; 29using namespace Windows::UI::Core; 30using namespace Windows::UI::Xaml; 31using namespace Windows::UI::Xaml::Controls; 32using namespace Windows::UI::Xaml::Data; 33using namespace Windows::UI::Xaml::Media; 34using namespace Windows::Storage; 35using namespace Windows::Media::MediaProperties; 36using namespace Windows::Storage::Streams; 37using namespace Windows::System; 38using namespace Windows::UI::Xaml::Media::Imaging; 39using namespace Windows::Devices::Enumeration; 40 41ref class ReencodeState sealed 42{ 43public: 44 ReencodeState() 45 { 46 } 47 48 virtual ~ReencodeState() 49 { 50 if (InputStream != nullptr) 51 { 52 delete InputStream; 53 } 54 if (OutputStream != nullptr) 55 { 56 delete OutputStream; 57 } 58 } 59 60internal: 61 Windows::Storage::Streams::IRandomAccessStream ^InputStream; 62 Windows::Storage::Streams::IRandomAccessStream ^OutputStream; 63 Windows::Storage::StorageFile ^PhotoStorage; 64 Windows::Graphics::Imaging::BitmapDecoder ^Decoder; 65 Windows::Graphics::Imaging::BitmapEncoder ^Encoder; 66}; 67 68AdvancedCapture::AdvancedCapture() 69{ 70 InitializeComponent(); 71 ScenarioInit(); 72} 73 74/// <summary> 75/// Invoked when this page is about to be displayed in a Frame. 76/// </summary> 77/// <param name="e">Event data that describes how this page was reached. The Parameter 78/// property is typically used to configure the page.</param> 79void AdvancedCapture::OnNavigatedTo(NavigationEventArgs^ e) 80{ 81 // A pointer back to the main page. This is needed if you want to call methods in MainPage such 82 // as NotifyUser() 83 rootPage = MainPage::Current; 84 85 m_orientationChangedEventToken = Windows::Graphics::Display::DisplayProperties::OrientationChanged += ref new Windows::Graphics::Display::DisplayPropertiesEventHandler(this, &AdvancedCapture::DisplayProperties_OrientationChanged); 86} 87 88void AdvancedCapture::OnNavigatedFrom(NavigationEventArgs^ e) 89{ 90 Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; 91 Windows::Graphics::Display::DisplayProperties::OrientationChanged -= m_orientationChangedEventToken; 92} 93 94void AdvancedCapture::ScenarioInit() 95{ 96 rootPage = MainPage::Current; 97 btnStartDevice2->IsEnabled = true; 98 btnStartPreview2->IsEnabled = false; 99 m_bRecording = false; 100 m_bPreviewing = false; 101 m_bEffectAdded = false; 102 previewElement2->Source = nullptr; 103 ShowStatusMessage(""); 104 EffectTypeCombo->IsEnabled = false; 105 previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; 106 EnumerateWebcamsAsync(); 107 m_bSuspended = false; 108} 109 110void AdvancedCapture::ScenarioReset() 111{ 112 previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; 113 ScenarioInit(); 114} 115 116void AdvancedCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) 117{ 118 String ^message = "Fatal error" + currentFailure->Message; 119 create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, 120 ref new Windows::UI::Core::DispatchedHandler([this, message]() 121 { 122 ShowStatusMessage(message); 123 }))); 124} 125 126void AdvancedCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 127{ 128 try 129 { 130 EnableButton(false, "StartDevice"); 131 ShowStatusMessage("Starting device"); 132 auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); 133 m_mediaCaptureMgr = mediaCapture; 134 auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); 135 auto chosenDevInfo = m_devInfoCollection->GetAt(EnumedDeviceList2->SelectedIndex); 136 settings->VideoDeviceId = chosenDevInfo->Id; 137 if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Back) 138 { 139 m_bRotateVideoOnOrientationChange = true; 140 m_bReversePreviewRotation = false; 141 } 142 else if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Front) 143 { 144 m_bRotateVideoOnOrientationChange = true; 145 m_bReversePreviewRotation = true; 146 } 147 else 148 { 149 m_bRotateVideoOnOrientationChange = false; 150 } 151 152 create_task(mediaCapture->InitializeAsync(settings)).then([this](task<void> initTask) 153 { 154 try 155 { 156 initTask.get(); 157 158 auto mediaCapture = m_mediaCaptureMgr.Get(); 159 160 DisplayProperties_OrientationChanged(nullptr); 161 162 EnableButton(true, "StartPreview"); 163 EnableButton(true, "StartStopRecord"); 164 EnableButton(true, "TakePhoto"); 165 ShowStatusMessage("Device initialized successful"); 166 EffectTypeCombo->IsEnabled = true; 167 mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AdvancedCapture::Failed); 168 } 169 catch (Exception ^ e) 170 { 171 ShowExceptionMessage(e); 172 } 173 }); 174 } 175 catch (Platform::Exception^ e) 176 { 177 ShowExceptionMessage(e); 178 } 179} 180 181void AdvancedCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 182{ 183 m_bPreviewing = false; 184 try 185 { 186 ShowStatusMessage("Starting preview"); 187 EnableButton(false, "StartPreview"); 188 189 auto mediaCapture = m_mediaCaptureMgr.Get(); 190 previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Visible; 191 previewElement2->Source = mediaCapture; 192 create_task(mediaCapture->StartPreviewAsync()).then([this](task<void> previewTask) 193 { 194 try 195 { 196 previewTask.get(); 197 m_bPreviewing = true; 198 ShowStatusMessage("Start preview successful"); 199 } 200 catch (Exception ^e) 201 { 202 ShowExceptionMessage(e); 203 } 204 }); 205 } 206 catch (Platform::Exception^ e) 207 { 208 m_bPreviewing = false; 209 previewElement2->Source = nullptr; 210 EnableButton(true, "StartPreview"); 211 ShowExceptionMessage(e); 212 } 213} 214 215void AdvancedCapture::lstEnumedDevices_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e) 216{ 217 if ( m_bPreviewing ) 218 { 219 create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task<void> previewTask) 220 { 221 try 222 { 223 previewTask.get(); 224 m_bPreviewing = false; 225 } 226 catch (Exception ^e) 227 { 228 ShowExceptionMessage(e); 229 } 230 }); 231 } 232 233 btnStartDevice2->IsEnabled = true; 234 btnStartPreview2->IsEnabled = false; 235 m_bRecording = false; 236 previewElement2->Source = nullptr; 237 EffectTypeCombo->IsEnabled = false; 238 m_bEffectAdded = false; 239 m_bEffectAddedToRecord = false; 240 m_bEffectAddedToPhoto = false; 241 ShowStatusMessage(""); 242} 243 244void AdvancedCapture::EnumerateWebcamsAsync() 245{ 246 try 247 { 248 ShowStatusMessage("Enumerating Webcams..."); 249 m_devInfoCollection = nullptr; 250 251 EnumedDeviceList2->Items->Clear(); 252 253 task<DeviceInformationCollection^>(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture)).then([this](task<DeviceInformationCollection^> findTask) 254 { 255 try 256 { 257 m_devInfoCollection = findTask.get(); 258 if (m_devInfoCollection == nullptr || m_devInfoCollection->Size == 0) 259 { 260 ShowStatusMessage("No WebCams found."); 261 } 262 else 263 { 264 for(unsigned int i = 0; i < m_devInfoCollection->Size; i++) 265 { 266 auto devInfo = m_devInfoCollection->GetAt(i); 267 EnumedDeviceList2->Items->Append(devInfo->Name); 268 } 269 EnumedDeviceList2->SelectedIndex = 0; 270 ShowStatusMessage("Enumerating Webcams completed successfully."); 271 btnStartDevice2->IsEnabled = true; 272 } 273 } 274 catch (Exception ^e) 275 { 276 ShowExceptionMessage(e); 277 } 278 }); 279 } 280 catch (Platform::Exception^ e) 281 { 282 ShowExceptionMessage(e); 283 } 284} 285 286void AdvancedCapture::AddEffectToImageStream() 287{ 288 auto mediaCapture = m_mediaCaptureMgr.Get(); 289 Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; 290 291 if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && 292 (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewPhotoStreamsIdentical) && 293 (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::RecordPhotoStreamsIdentical)) 294 { 295 Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); 296 if(props->Type->Equals("Image")) 297 { 298 //Switch to a video media type instead since we cant add an effect to a image media type 299 Windows::Foundation::Collections::IVectorView<Windows::Media::MediaProperties::IMediaEncodingProperties^>^ supportedPropsList = mediaCapture->VideoDeviceController->GetAvailableMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); 300 { 301 unsigned int i = 0; 302 while (i < supportedPropsList->Size) 303 { 304 Windows::Media::MediaProperties::IMediaEncodingProperties^ props = supportedPropsList->GetAt(i); 305 306 String^ s = props->Type; 307 if(props->Type->Equals("Video")) 308 { 309 task<void>(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(Windows::Media::Capture::MediaStreamType::Photo,props)).then([this](task<void> changeTypeTask) 310 { 311 try 312 { 313 changeTypeTask.get(); 314 ShowStatusMessage("Change type on photo stream successful"); 315 //Now add the effect on the image pin 316 task<void>(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"OcvTransform.OcvImageManipulations", nullptr)).then([this](task<void> effectTask3) 317 { 318 try 319 { 320 effectTask3.get(); 321 m_bEffectAddedToPhoto = true; 322 ShowStatusMessage("Adding effect to photo stream successful"); 323 EffectTypeCombo->IsEnabled = true; 324 325 } 326 catch(Exception ^e) 327 { 328 ShowExceptionMessage(e); 329 EffectTypeCombo->IsEnabled = true; 330 } 331 }); 332 333 } 334 catch(Exception ^e) 335 { 336 ShowExceptionMessage(e); 337 EffectTypeCombo->IsEnabled = true; 338 } 339 340 }); 341 break; 342 343 } 344 i++; 345 } 346 } 347 } 348 else 349 { 350 //Add the effect to the image pin if the type is already "Video" 351 task<void>(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"OcvTransform.OcvImageManipulations", nullptr)).then([this](task<void> effectTask3) 352 { 353 try 354 { 355 effectTask3.get(); 356 m_bEffectAddedToPhoto = true; 357 ShowStatusMessage("Adding effect to photo stream successful"); 358 EffectTypeCombo->IsEnabled = true; 359 360 } 361 catch(Exception ^e) 362 { 363 ShowExceptionMessage(e); 364 EffectTypeCombo->IsEnabled = true; 365 } 366 }); 367 } 368 } 369} 370 371void AdvancedCapture::ShowStatusMessage(Platform::String^ text) 372{ 373 rootPage->NotifyUser(text, NotifyType::StatusMessage); 374} 375 376void AdvancedCapture::ShowExceptionMessage(Platform::Exception^ ex) 377{ 378 rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); 379} 380 381void AdvancedCapture::EnableButton(bool enabled, String^ name) 382{ 383 if (name->Equals("StartDevice")) 384 { 385 btnStartDevice2->IsEnabled = enabled; 386 } 387 else if (name->Equals("StartPreview")) 388 { 389 btnStartPreview2->IsEnabled = enabled; 390 } 391} 392 393task<Windows::Storage::StorageFile^> AdvancedCapture::ReencodePhotoAsync( 394 Windows::Storage::StorageFile ^tempStorageFile, 395 Windows::Storage::FileProperties::PhotoOrientation photoRotation) 396{ 397 ReencodeState ^state = ref new ReencodeState(); 398 399 return create_task(tempStorageFile->OpenAsync(Windows::Storage::FileAccessMode::Read)).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) 400 { 401 state->InputStream = stream; 402 return Windows::Graphics::Imaging::BitmapDecoder::CreateAsync(state->InputStream); 403 }).then([state](Windows::Graphics::Imaging::BitmapDecoder ^decoder) 404 { 405 state->Decoder = decoder; 406 return Windows::Storage::KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName); 407 }).then([state](Windows::Storage::StorageFile ^storageFile) 408 { 409 state->PhotoStorage = storageFile; 410 return state->PhotoStorage->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite); 411 }).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) 412 { 413 state->OutputStream = stream; 414 state->OutputStream->Size = 0; 415 return Windows::Graphics::Imaging::BitmapEncoder::CreateForTranscodingAsync(state->OutputStream, state->Decoder); 416 }).then([state, photoRotation](Windows::Graphics::Imaging::BitmapEncoder ^encoder) 417 { 418 state->Encoder = encoder; 419 auto properties = ref new Windows::Graphics::Imaging::BitmapPropertySet(); 420 properties->Insert("System.Photo.Orientation", 421 ref new Windows::Graphics::Imaging::BitmapTypedValue((unsigned short)photoRotation, Windows::Foundation::PropertyType::UInt16)); 422 return create_task(state->Encoder->BitmapProperties->SetPropertiesAsync(properties)); 423 }).then([state]() 424 { 425 return state->Encoder->FlushAsync(); 426 }).then([tempStorageFile, state](task<void> previousTask) 427 { 428 auto result = state->PhotoStorage; 429 delete state; 430 431 tempStorageFile->DeleteAsync(Windows::Storage::StorageDeleteOption::PermanentDelete); 432 433 previousTask.get(); 434 435 return result; 436 }); 437} 438 439Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::GetCurrentPhotoRotation() 440{ 441 bool counterclockwiseRotation = m_bReversePreviewRotation; 442 443 if (m_bRotateVideoOnOrientationChange) 444 { 445 return PhotoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation); 446 } 447 else 448 { 449 return Windows::Storage::FileProperties::PhotoOrientation::Normal; 450 } 451} 452 453void AdvancedCapture::PrepareForVideoRecording() 454{ 455 Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); 456 if (mediaCapture == nullptr) 457 { 458 return; 459 } 460 461 bool counterclockwiseRotation = m_bReversePreviewRotation; 462 463 if (m_bRotateVideoOnOrientationChange) 464 { 465 mediaCapture->SetRecordRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); 466 } 467 else 468 { 469 mediaCapture->SetRecordRotation(Windows::Media::Capture::VideoRotation::None); 470 } 471} 472 473void AdvancedCapture::DisplayProperties_OrientationChanged(Platform::Object^ sender) 474{ 475 Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); 476 if (mediaCapture == nullptr) 477 { 478 return; 479 } 480 481 bool previewMirroring = mediaCapture->GetPreviewMirroring(); 482 bool counterclockwiseRotation = (previewMirroring && !m_bReversePreviewRotation) || 483 (!previewMirroring && m_bReversePreviewRotation); 484 485 if (m_bRotateVideoOnOrientationChange) 486 { 487 mediaCapture->SetPreviewRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); 488 } 489 else 490 { 491 mediaCapture->SetPreviewRotation(Windows::Media::Capture::VideoRotation::None); 492 } 493} 494 495Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::PhotoRotationLookup( 496 Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) 497{ 498 switch (displayOrientation) 499 { 500 case Windows::Graphics::Display::DisplayOrientations::Landscape: 501 return Windows::Storage::FileProperties::PhotoOrientation::Normal; 502 503 case Windows::Graphics::Display::DisplayOrientations::Portrait: 504 return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate270: 505 Windows::Storage::FileProperties::PhotoOrientation::Rotate90; 506 507 case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: 508 return Windows::Storage::FileProperties::PhotoOrientation::Rotate180; 509 510 case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: 511 return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate90 : 512 Windows::Storage::FileProperties::PhotoOrientation::Rotate270; 513 514 default: 515 return Windows::Storage::FileProperties::PhotoOrientation::Unspecified; 516 } 517} 518 519Windows::Media::Capture::VideoRotation AdvancedCapture::VideoRotationLookup( 520 Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) 521{ 522 switch (displayOrientation) 523 { 524 case Windows::Graphics::Display::DisplayOrientations::Landscape: 525 return Windows::Media::Capture::VideoRotation::None; 526 527 case Windows::Graphics::Display::DisplayOrientations::Portrait: 528 return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise270Degrees : 529 Windows::Media::Capture::VideoRotation::Clockwise90Degrees; 530 531 case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: 532 return Windows::Media::Capture::VideoRotation::Clockwise180Degrees; 533 534 case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: 535 return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise90Degrees: 536 Windows::Media::Capture::VideoRotation::Clockwise270Degrees ; 537 538 default: 539 return Windows::Media::Capture::VideoRotation::None; 540 } 541} 542 543void SDKSample::MediaCapture::AdvancedCapture::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 544{ 545 try 546 { 547 create_task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::VideoPreview)).then([this](task<void> cleanTask) 548 { 549 m_bEffectAdded = true; 550 int index = EffectTypeCombo->SelectedIndex; 551 PropertySet^ props = ref new PropertySet(); 552 props->Insert(L"{698649BE-8EAE-4551-A4CB-3EC98FBD3D86}", index); 553 create_task(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoPreview,"OcvTransform.OcvImageManipulations", props)).then([this](task<void> effectTask) 554 { 555 try 556 { 557 effectTask.get(); 558 559 auto mediaCapture = m_mediaCaptureMgr.Get(); 560 Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; 561 562 ShowStatusMessage("Add effect successful to preview stream successful"); 563 if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && 564 (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewRecordStreamsIdentical)) 565 { 566 Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::VideoRecord); 567 Windows::Media::MediaProperties::VideoEncodingProperties ^videoEncodingProperties = static_cast<Windows::Media::MediaProperties::VideoEncodingProperties ^>(props); 568 if(!videoEncodingProperties->Subtype->Equals("H264")) //Cant add an effect to an H264 stream 569 { 570 task<void>(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoRecord,"OcvTransform.OcvImageManipulations", nullptr)).then([this](task<void> effectTask2) 571 { 572 try 573 { 574 effectTask2.get(); 575 ShowStatusMessage("Add effect successful to record stream successful"); 576 m_bEffectAddedToRecord = true; 577 AddEffectToImageStream(); 578 EffectTypeCombo->IsEnabled = true; 579 } 580 catch(Exception ^e) 581 { 582 ShowExceptionMessage(e); 583 EffectTypeCombo->IsEnabled = true; 584 } 585 }); 586 } 587 else 588 { 589 AddEffectToImageStream(); 590 EffectTypeCombo->IsEnabled = true; 591 } 592 593 } 594 else 595 { 596 AddEffectToImageStream(); 597 EffectTypeCombo->IsEnabled = true; 598 } 599 } 600 catch (Exception ^e) 601 { 602 ShowExceptionMessage(e); 603 EffectTypeCombo->IsEnabled = true; 604 } 605 }); 606 }); 607 } 608 catch (Platform::Exception ^e) 609 { 610 ShowExceptionMessage(e); 611 EffectTypeCombo->IsEnabled = true; 612 } 613} 614