From ce8468f9de3947cde319c7e63d9b027278a790d5 Mon Sep 17 00:00:00 2001 From: Austin Diviness Date: Thu, 21 Jul 2016 15:30:47 -0700 Subject: [PATCH 1/2] video upload support --- .../winsdkfb/winsdkfb.Shared/FBVideo.cpp.tt | 3 + .../winsdkfb/winsdkfb.Shared/FBVideo.h.tt | 3 + winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.xml | 10 + .../winsdkfb.Shared/FBVideoContentStream.cpp | 126 ++++++++++ .../winsdkfb.Shared/FBVideoContentStream.h | 101 ++++++++ .../winsdkfb.Shared/FBVideoUploader.cpp | 217 ++++++++++++++++++ .../winsdkfb.Shared/FBVideoUploader.h | 102 ++++++++ winsdkfb/winsdkfb/winsdkfb.Shared/codegen.cmd | 2 + .../winsdkfb.Shared/winsdkfb.Shared.vcxitems | 11 + .../winsdkfb.Shared.vcxitems.filters | 37 ++- 10 files changed, 610 insertions(+), 2 deletions(-) create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.cpp.tt create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.h.tt create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.xml create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.cpp create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.h create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp create mode 100644 winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.cpp.tt b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.cpp.tt new file mode 100644 index 0000000..b510317 --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.cpp.tt @@ -0,0 +1,3 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<# string classDefFile = "..\\winsdkfb.Shared\\FBVideo.xml"; #> +<#@ include file="FBGraphObjectImplementation.ttinclude" #> diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.h.tt b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.h.tt new file mode 100644 index 0000000..d9111c2 --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.h.tt @@ -0,0 +1,3 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<# string classDefFile = "..\\winsdkfb.Shared\\FBVideo.xml"; #> +<#@ include file="FBGraphObjectHeader.ttinclude" #> diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.xml b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.xml new file mode 100644 index 0000000..f8cd982 --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideo.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.cpp b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.cpp new file mode 100644 index 0000000..000be57 --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.cpp @@ -0,0 +1,126 @@ +//****************************************************************************** +// +// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "pch.h" +#include "FBVideoContentStream.h" + +using namespace concurrency; +using namespace Windows::Storage::Streams; +using namespace Windows::Foundation; + +FBVideoContentStream::FBVideoContentStream( + IRandomAccessStream^ stream, + Platform::String^ contentType + ) : + _contentType{contentType}, + _stream{stream} +{ +} + +IAsyncOperationWithProgress^ FBVideoContentStream::ReadAsync( + Windows::Storage::Streams::IBuffer^ buffer, + unsigned int count, + Windows::Storage::Streams::InputStreamOptions options + ) +{ + return _stream->ReadAsync(buffer, count, options); +} + +IAsyncOperationWithProgress^ FBVideoContentStream::WriteAsync(Windows::Storage::Streams::IBuffer^ buffer) +{ + return _stream->WriteAsync(buffer); +} + +IAsyncOperation^ FBVideoContentStream::FlushAsync() +{ + return _stream->FlushAsync(); +} + +bool FBVideoContentStream::CanRead::get() +{ + return _stream->CanRead; +} + +bool FBVideoContentStream::CanWrite::get() +{ + return _stream->CanWrite; +} + +unsigned long long FBVideoContentStream::Position::get() +{ + return _stream->Position; +} + +unsigned long long FBVideoContentStream::Size::get() +{ + return _stream->Size; +} + +void FBVideoContentStream::Size::set(unsigned long long value) +{ + _stream->Size = value; +} + +IInputStream^ FBVideoContentStream::GetInputStreamAt(unsigned long long position) +{ + return _stream->GetInputStreamAt(position); +} + +IOutputStream^ FBVideoContentStream::GetOutputStreamAt(unsigned long long position) +{ + return _stream->GetOutputStreamAt(position); +} + +void FBVideoContentStream::Seek(unsigned long long position) +{ + _stream->Seek(position); +} + +IRandomAccessStream^ FBVideoContentStream::CloneStream() +{ + return ref new FBVideoContentStream(_stream->CloneStream(), _contentType); +} + +Platform::String^ FBVideoContentStream::ContentType::get() +{ + return _contentType; +} + +FBVideoContentStream::~FBVideoContentStream() +{ +} + +IAsyncOperation^ FBVideoContentStream::TruncateCloneStreamAsync(unsigned long long position, unsigned int size) +{ + unsigned long long oldPosition = _stream->Position; + _stream->Seek(position); + IBuffer^ buffer = ref new Buffer(size); + + task workTask = create_task(_stream->ReadAsync(buffer, size, InputStreamOptions::None)).then([=](IBuffer^ filledBuffer) + { + _stream->Seek(oldPosition); + InMemoryRandomAccessStream^ memoryStream = ref new InMemoryRandomAccessStream(); + return create_task(memoryStream->WriteAsync(filledBuffer)).then([=](unsigned int count) + { + memoryStream->Seek(0); + return ref new FBVideoContentStream(memoryStream, _contentType); + }); + }); + return create_async([=]() + { + return workTask; + }); +} diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.h b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.h new file mode 100644 index 0000000..0d21c82 --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoContentStream.h @@ -0,0 +1,101 @@ +//****************************************************************************** +// +// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#pragma once + +using namespace Windows::Storage::Streams; + +ref class FBVideoContentStream sealed : IRandomAccessStreamWithContentType +{ +public: + + FBVideoContentStream( + IRandomAccessStream^ stream, + Platform::String^ contentType + ); + + // Inherited via IRandomAccessStream + virtual Windows::Foundation::IAsyncOperationWithProgress^ + ReadAsync( + Windows::Storage::Streams::IBuffer^buffer, + unsigned int count, + Windows::Storage::Streams::InputStreamOptions options + ); + + virtual Windows::Foundation::IAsyncOperationWithProgress^ + WriteAsync( + Windows::Storage::Streams::IBuffer^buffer + ); + + virtual Windows::Foundation::IAsyncOperation^ FlushAsync(); + + virtual property bool CanRead + { + bool get(); + } + + virtual property bool CanWrite + { + bool get(); + } + + virtual property unsigned long long Position + { + unsigned long long get(); + } + + virtual property unsigned long long Size + { + unsigned long long get(); + void set(unsigned long long); + } + + virtual Windows::Storage::Streams::IInputStream^ GetInputStreamAt( + unsigned long long position + ); + + virtual Windows::Storage::Streams::IOutputStream^ GetOutputStreamAt( + unsigned long long position + ); + + virtual void Seek( + unsigned long long position + ); + + virtual Windows::Storage::Streams::IRandomAccessStream^ CloneStream(); + + // Inherited via IContentTypeProvider + virtual property Platform::String^ ContentType + { + Platform::String^ get(); + } + + virtual ~FBVideoContentStream(); + + /** + * Clones a portion of the stream into another object. + * @param position The position in the stream to start the clone at + * @param size The amount of bytes to clone + * @return The cloned, truncated FBVideoContentStream + */ + Windows::Foundation::IAsyncOperation^ TruncateCloneStreamAsync( + unsigned long long position, + unsigned int size + ); +private: + Platform::String^ _contentType; + IRandomAccessStream^ _stream; +}; diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp new file mode 100644 index 0000000..ec0089a --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp @@ -0,0 +1,217 @@ +//****************************************************************************** +// +// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include + +#include "pch.h" +#include "FBVideoUploader.h" +#include "FacebookClient.h" +#include "FacebookSession.h" +#include "FacebookMediaObject.h" +#include "FacebookMediaStream.h" +#include "FBSingleValue.h" +#include "FBVideo.h" + +using namespace concurrency; +using namespace winsdkfb; +using namespace winsdkfb::Graph; +using namespace Platform; +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::Security::Cryptography; +using namespace Windows::Security::Cryptography::DataProtection; + +// Facebook Video upload doesn't specify whether their video threshold for small vs. large upload +// is 1 gigabyte or 1 gibibyte. We have put down the 1 gigabyte just to be safe. +#define VIDEO_THRESHOLD_SIZE 1000000000L + +namespace winsdkfb +{ + IAsyncOperation^ FBVideoUploader::UploadVideoAsync(StorageFile^ videoFile) + { + task workTask = create_task(videoFile->GetBasicPropertiesAsync()).then([=](BasicProperties^ properties) + { + unsigned long long fileSize = properties->Size; + FBSession^ sess = FBSession::ActiveSession; + if (sess->LoggedIn) + { + // Facebook expects a file size of < 1 GB for small video upload and between 1 GB and 1.5 GB for large + // video upload. We are only validating the file size portion before upload. + if (fileSize < VIDEO_THRESHOLD_SIZE) + { + return UploadSmallVideo(videoFile); + } + else + { + return UploadLargeVideo(videoFile, fileSize); + } + } + return create_task([=]() -> FBResult^ + { + return ref new FBResult(ref new FBError(0, L"Not logged in", L"Need to be logged in to upload a video")); + }); + }); + + return create_async([=]() + { + return workTask; + }); + } + + task FBVideoUploader::UploadSmallVideo(StorageFile^ videoFile) + { + return create_task(videoFile->OpenReadAsync()).then([=](IRandomAccessStreamWithContentType^ fileStream) + { + FBMediaStream^ videoMediaStream = ref new FBMediaStream(videoFile->Name, fileStream); + FBSession^ sess = FBSession::ActiveSession; + PropertySet^ parameters = ref new PropertySet(); + parameters->Insert(L"title", videoFile->Name); + parameters->Insert(L"source", videoMediaStream); + + String^ path = sess->User->Id + L"/videos"; + FBJsonClassFactory^ factory = ref new FBJsonClassFactory(FBVideo::FromJson); + + FBSingleValue^ request = ref new FBSingleValue(path, parameters, factory); + return request->PostAsync(); + }); + } + + task FBVideoUploader::UploadLargeVideo(StorageFile^ videoFile, unsigned long long fileSize) + { + return StartRequest(fileSize).then([=](FBResult^ result) + { + if (!result->Succeeded) + { + return create_task([=]() + { + return result; + }); + } + else + { + FBVideo^ video = static_cast(result->Object); + return create_task(videoFile->OpenAsync(FileAccessMode::Read)).then([=](IRandomAccessStream^ stream) + { + FBVideoContentStream^ contentStream = ref new FBVideoContentStream(stream, videoFile->ContentType); + return std::make_pair(video, contentStream); + }).then([=](std::pair videoData) + { + FBVideo^ video = videoData.first; + FBVideoContentStream^ stream = videoData.second; + return TransferRequest(stream, video, videoFile->Name); + }).then([=](FBResult^ result) { + if (result->Succeeded) + { + FBVideo^ video = static_cast(result->Object); + return FinishRequest(video->UploadSessionId); + } + else + { + return create_task([=]() + { + return result; + }); + } + }); + } + }); + } + + task FBVideoUploader::StartRequest(unsigned long long fileSize) + { + PropertySet^ parameters = ref new PropertySet(); + parameters->Insert(L"upload_phase", L"start"); + parameters->Insert(L"file_size", fileSize.ToString()); + + FBSession^ sess = FBSession::ActiveSession; + String^ path = sess->User->Id + L"/videos"; + FBJsonClassFactory^ factory = ref new FBJsonClassFactory(FBVideo::FromJson); + FBSingleValue^ request = ref new FBSingleValue(path, parameters, factory); + return create_task(request->PostAsync()); + } + + task FBVideoUploader::TransferRequest( + FBVideoContentStream^ stream, + FBVideo^ video, + String^ title + ) + { + return create_task([=]() + { + FBJsonClassFactory^ factory = ref new FBJsonClassFactory(FBVideo::FromJson); + int start = _wtoi(video->StartOffset->Data()); + int count = _wtoi(video->EndOffset->Data()) - start; + FBResult^ result; + while (count > 0) + { + task workTask = create_task(stream->TruncateCloneStreamAsync(start, count)).then([=](FBVideoContentStream^ truncatedStream) + { + FBMediaStream^ chunkMediaStream = ref new FBMediaStream(title, truncatedStream); + PropertySet^ parameters = ref new PropertySet(); + parameters->Insert(L"upload_phase", L"transfer"); + parameters->Insert(L"start_offset", start.ToString()); + parameters->Insert(L"upload_session_id", video->UploadSessionId); + parameters->Insert(L"video_file_chunk", chunkMediaStream); + + FBSession^ sess = FBSession::ActiveSession; + String^ path = sess->User->Id + L"/videos"; + FBSingleValue^ request = ref new FBSingleValue(path, parameters, factory); + return request->PostAsync(); + }); + workTask.wait(); + result = workTask.get(); + if (result->Succeeded) + { + FBVideo^ v = static_cast(result->Object); + // need to set UploadSessionId so that the next stage after + // the transfer can refer to it + v->UploadSessionId = video->UploadSessionId; + start = _wtoi(v->StartOffset->Data()); + count = _wtoi(v->EndOffset->Data()) - start; + } + else + { + break; + } + } + if (count < 0) + { + result = ref new FBResult( + ref new FBError( + 0, + L"Video upload error", + "transfer step reached an invalid byte range")); + } + return result; + }); + } + + task FBVideoUploader::FinishRequest(Platform::String^ uploadSessionId) + { + PropertySet^ parameters = ref new PropertySet(); + parameters->Insert(L"upload_phase", L"finish"); + parameters->Insert(L"upload_session_id", uploadSessionId); + + FBSession^ sess = FBSession::ActiveSession; + String^ path = sess->User->Id + L"/videos"; + FBJsonClassFactory^ factory = ref new FBJsonClassFactory(FBVideo::FromJson); + FBSingleValue^ request = ref new FBSingleValue(path, parameters, factory); + return create_task(request->PostAsync()); + } +} diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h new file mode 100644 index 0000000..08ccde5 --- /dev/null +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h @@ -0,0 +1,102 @@ +//****************************************************************************** +// +// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#pragma once + +#include "FacebookResult.h" +#include "FBVideoContentStream.h" +#include "FBVideo.h" + +namespace winsdkfb +{ + /** + * @brief Provides video uploading from a local file to Facebook. + */ + public ref class FBVideoUploader sealed + { + public: + /** + * Uploads a video from a local file to Facebook. + * @param videoFile The video file to upload + * @return FBResult indicating the result of the operation. On success, + * it will contain an FBVideo object and on failure it will contain an + * FBError object. + */ + static Windows::Foundation::IAsyncOperation^ UploadVideoAsync( + Windows::Storage::StorageFile^ videoFile + ); + + private: + /** + * Uploads a video in one HTTP request. For videos that are small enough + * to meet Facebook's guidelines on small video uploading. + * @param videoFile The video file to upload + * @return FBResult indicating the result of the operation, will contain + * an FBVideo object on success and and FBError object on error. + */ + static Concurrency::task UploadSmallVideo( + Windows::Storage::StorageFile^ videoFile + ); + + /** + * Uploads a video with multiple HTTP requests. For videos that are too + * big to be uploading with UploadSmallVideo(). + * @param videoFile The video file to upload + * @param fileSize The size of the video file, in bytes + * @return FBResult indicating the result of the operation, will contain + * an FBVideo object on success and and FBError object on error. + */ + static Concurrency::task UploadLargeVideo( + Windows::Storage::StorageFile^ videoFile, + unsigned long long fileSize + ); + + /** + * Starts the large video uploading process. + * @param fileSize The size of the video file to upload, in bytes + * @return FBResult indicating the result of the operation, will contain + * an FBVideo object on success and and FBError object on error. + */ + static Concurrency::task StartRequest( + unsigned long long fileSize + ); + + /** + * Portions the video file into chunks and uploads them to sequentially. + * @param stream The stream of the video file data + * @param video The FBVideo object containing the upload process data + * from previous operations + * @param title The name of the video file to upload + * @return FBResult indicating the result of the operation, will contain + * an FBVideo object on success and and FBError object on error. + */ + static Concurrency::task TransferRequest( + FBVideoContentStream^ stream, + Graph::FBVideo^ video, + Platform::String^ title + ); + + /** + * Signals to Facebook the end of the large video upload process + * @param uploadSessionId The session ID of the video upload + * @return FBResult indicating the result of the operation, will contain + * an FBVideo object on success and and FBError object on error. + */ + static Concurrency::task FinishRequest( + Platform::String^ uploadSessionId + ); + }; +} \ No newline at end of file diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/codegen.cmd b/winsdkfb/winsdkfb/winsdkfb.Shared/codegen.cmd index 9f16981..0b8d429 100644 --- a/winsdkfb/winsdkfb/winsdkfb.Shared/codegen.cmd +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/codegen.cmd @@ -31,6 +31,7 @@ call :GenFile FBProfilePicture.cpp FBProfilePicture.cpp.tt call :GenFile FBProfilePictureData.cpp FBProfilePictureData.cpp.tt call :GenFile FBAppRequest.cpp FBAppRequest.cpp.tt call :GenFile FBObject.cpp FBObject.cpp.tt +call :GenFile FBVideo.cpp FBVideo.cpp.tt REM header files call :GenFile FBCursors.h FBCursors.h.tt call :GenFile FBGroup.h FBGroup.h.tt @@ -43,6 +44,7 @@ call :GenFile FBProfilePicture.h FBProfilePicture.h.tt call :GenFile FBProfilePictureData.h FBProfilePictureData.h.tt call :GenFile FBAppRequest.h FBAppRequest.h.tt call :GenFile FBObject.h FBObject.h.tt +call :GenFile FBVideo.h FBVideo.h.tt goto End diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems b/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems index e385d9c..4d52b6e 100644 --- a/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems @@ -38,6 +38,7 @@ + @@ -48,11 +49,13 @@ + + @@ -75,6 +78,7 @@ + @@ -90,8 +94,10 @@ + + Create @@ -129,6 +135,8 @@ + + @@ -148,4 +156,7 @@ false + + + \ No newline at end of file diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems.filters b/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems.filters index 6cf1e5d..f1a979f 100644 --- a/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems.filters +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/winsdkfb.Shared.vcxitems.filters @@ -81,10 +81,21 @@ Source Files - Source Files + + Source Files + + + Source Files + + + Generated code + + + Source Files + @@ -179,7 +190,6 @@ Header Files - Header Files @@ -189,6 +199,18 @@ Header Files + + Header Files + + + Header Files + + + Generated code + + + Header Files + @@ -290,6 +312,12 @@ Object Templates + + Object Templates + + + Object Templates + @@ -312,4 +340,9 @@ {aa3295ea-aec9-432a-92b9-a5cfba6e5fc7} + + + Object Templates + + \ No newline at end of file From a2533b8231e92271629b4c6d0e0583e3fcc7d910 Mon Sep 17 00:00:00 2001 From: Austin Diviness Date: Fri, 27 Jan 2017 14:40:07 -0800 Subject: [PATCH 2/2] added a way for a user to specify in what manner to upload a video --- .../winsdkfb.Shared/FBVideoUploader.cpp | 27 ++++++++++++++++--- .../winsdkfb.Shared/FBVideoUploader.h | 20 ++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp index ec0089a..2591240 100644 --- a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.cpp @@ -43,7 +43,30 @@ using namespace Windows::Security::Cryptography::DataProtection; namespace winsdkfb { + IAsyncOperation^ FBVideoUploader::UploadVideoAsync(StorageFile^ videoFile) + { + task workTask = create_task(videoFile->GetBasicPropertiesAsync()).then([=](BasicProperties^ properties) + { + unsigned long long fileSize = properties->Size; + // Facebook expects a file size of < 1 GB for small video upload and between 1 GB and 1.5 GB for large + // video upload. We are only validating the file size portion before upload. + if (fileSize < VIDEO_THRESHOLD_SIZE) + { + return UploadVideoAsync(videoFile, VideoUploadBehavior::SingleRequest); + } + else + { + return UploadVideoAsync(videoFile, VideoUploadBehavior::MultiRequest); + } + }); + return create_async([=]() + { + return workTask; + }); + } + + IAsyncOperation^ FBVideoUploader::UploadVideoAsync(StorageFile^ videoFile, VideoUploadBehavior uploadBehavior) { task workTask = create_task(videoFile->GetBasicPropertiesAsync()).then([=](BasicProperties^ properties) { @@ -51,9 +74,7 @@ namespace winsdkfb FBSession^ sess = FBSession::ActiveSession; if (sess->LoggedIn) { - // Facebook expects a file size of < 1 GB for small video upload and between 1 GB and 1.5 GB for large - // video upload. We are only validating the file size portion before upload. - if (fileSize < VIDEO_THRESHOLD_SIZE) + if (uploadBehavior == VideoUploadBehavior::SingleRequest) { return UploadSmallVideo(videoFile); } diff --git a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h index 08ccde5..a827e25 100644 --- a/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h +++ b/winsdkfb/winsdkfb/winsdkfb.Shared/FBVideoUploader.h @@ -22,6 +22,13 @@ namespace winsdkfb { + //! Specifies which graph api method to use to upload the video. + public enum class VideoUploadBehavior + { + SingleRequest, // one http request is made + MultiRequest // video is uploaded in chunks + }; + /** * @brief Provides video uploading from a local file to Facebook. */ @@ -39,6 +46,19 @@ namespace winsdkfb Windows::Storage::StorageFile^ videoFile ); + /** + * Uploads a video from a local file to Facebook. + * @param videoFile The video file to upload + * @param uploadBehavior The way the video should be uploaded + * @return FBResult indicating the result of the operation. On success, + * it will contain an FBVideo object and on failure it will contain an + * FBError object. + */ + static Windows::Foundation::IAsyncOperation^ UploadVideoAsync( + Windows::Storage::StorageFile^ videoFile, + VideoUploadBehavior uploadBehavior + ); + private: /** * Uploads a video in one HTTP request. For videos that are small enough