I have a youtube uploader, and I am generating a video from an audio file, which works fine, but when I am uploading to Youtube the program still runs when I am trying to wait for it to finish uploading before repeating
Here I generate a video:
private void button2_Click(object sender, EventArgs e)
{
if (status.Text == "Stopped")
{
if (!generatearticle.IsBusy)
{
// started
status.Text = "Started";
status.ForeColor = System.Drawing.Color.Green;
start.Text = "Stop Generating";
generatearticle.RunWorkerAsync();
}
}
else
{
if(generatearticle.IsBusy)
{
generatearticle.CancelAsync();
// started
status.Text = "Stopped";
status.ForeColor = System.Drawing.Color.Red;
start.Text = "Start Generating";
}
}
}
private void core()
{
// generate audio
int i = 0;
for (int n = 1; n < co; n++)
{
// generate video and upload to
// youtube, this generates, but
// when uploading to youtube this for
// loop carries on when I want it to
// upload to youtube first before carrying on
generatevideo(image, articlename);
}
}
private void generateVideo(string images, String articlename)
{
//generate the video here, once done upload
{code removed, this just generates a video, nothing important}
// now upload (but I want it to finish before repeating the core() function
try
{
new UploadVideo().Run(articlename, file);
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
ThreadSafe(() =>
{
this.Invoke((MethodInvoker)delegate
{
status.Text = e.Message;
status.ForeColor = System.Drawing.Color.Red;
});
});
}
}
}
How I am uploading to Youtube:
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
namespace articletoyoutube
{
/// <summary>
/// YouTube Data API v3 sample: upload a video.
/// Relies on the Google APIs Client Library for .NET, v1.7.0 or higher.
/// See https://code.google.com/p/google-api-dotnet-client/wiki/GettingStarted
/// </summary>
class UploadVideo
{
// to access form controlls
Form1 core = new Form1();
public async Task Run(string articlename, string filelocation)
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] {
YouTubeService.Scope.YoutubeUpload
},
"user",
CancellationToken.None
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = articlename;
video.Snippet.Description = "News story regarding" + articlename;
video.Snippet.Tags = new string[] {
"news",
"breaking",
"important"
};
video.Snippet.CategoryId = "25"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "public"; // or "private" or "public"
var filePath = filelocation; // Replace with path to actual movie file.
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
}
}
void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case UploadStatus.Uploading:
core.prog_up.Text = "{0} bytes sent." + progress.BytesSent;
break;
case UploadStatus.Failed:
core.status.Text = "An error prevented the upload from completing.\n{0}" + progress.Exception;
core.status.ForeColor = System.Drawing.Color.Red;
break;
}
}
void videosInsertRequest_ResponseReceived(Video video)
{
core.prog_up.Text = "Video id '{0}' was successfully uploaded." + video.Id;
}
}
}
The background worker just runs core();
When it reaches the function
new UploadVideo().Run(articlename, file);
It starts uploading but starts repeating the core function again thus generating another video before that video has uploaded.... If I use
new UploadVideo().Run(articlename, file).Wait();
Then the program just stops and waits indefintly until I close the program, how can I wait for the Upload class/method to finish before carrying on with the fore loop in the core method?
To the guy who answered, when I add await before the new Upload... it gives me:
Severity Code Description Project File Line Suppression State
Error CS4033 The 'await' operator can only be used within an async
method. Consider marking this method with the 'async' modifier and
changing its return type to
'Task'. articletoyoutube C:\Users\Laptop\Documents\Visual Studio
2017\Projects\articletoyoutube\articletoyoutube\Form1.cs 254 Active
Make sure the async keyword is used on your methods and use the await keyword for the Tasks.
For example:
private async Task core()
{
// generate audio
int i = 0;
for (int n = 1; n < co; n++)
{
await generatevideo(image, articlename);
}
}
private async Task generateVideo(string images, String articlename)
{
//generate the video here,
try
{
var uploadVideo = new UploadVideo();
await uploadVideo.Run(articlename, file);
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
ThreadSafe(() =>
{
this.Invoke((MethodInvoker)delegate
{
status.Text = e.Message;
status.ForeColor = System.Drawing.Color.Red;
});
});
}
}
}
You need to use await all the way up your call stack to where your event handler is, this will require changing many of your methods.
private async Task core()
{
// generate audio
int i = 0;
for (int n = 1; n < co; n++)
{
// generate video and upload to
// youtube, this generates, but
// when uploading to youtube this for
// loop carries on when I want it to
// upload to youtube first before carrying on
await generatevideo(image, articlename);
}
}
private async Task generateVideo(string images, String articlename)
{
//generate the video here, once done upload
{code removed, this just generates a video, nothing important}
// now upload (but I want it to finish before repeating the core() function
try
{
await new UploadVideo().Run(articlename, file);
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
ThreadSafe(() =>
{
this.Invoke((MethodInvoker)delegate
{
status.Text = e.Message;
status.ForeColor = System.Drawing.Color.Red;
});
});
}
}
}
Note, using async/await does not work with BackgroundWorker you will need to switch to using Task.Run and a CancellationToken to signal cancellation.
Task _backgroundWork;
CancellationTokenSource _cts;
private void button2_Click(object sender, EventArgs e)
{
if (status.Text == "Stopped")
{
if (!generatearticle.IsBusy)
{
// started
status.Text = "Started";
status.ForeColor = System.Drawing.Color.Green;
start.Text = "Stop Generating";
_cts = new CancellationTokenSource();
_backgroundWork = Task.Run(() => core(_cts.Token), _cts.Token);
}
}
else
{
if(!_backgroundWork.IsCompleted)
{
_cts.Cancel();
// started
status.Text = "Stopped";
status.ForeColor = System.Drawing.Color.Red;
start.Text = "Start Generating";
}
}
}
Related
private async Task Download()
{
FilesDownoads downloads = new FilesDownloads(#"d:\testfiles");
downloads.PrepareLinks();
using var client = new HttpClient();
for (int i = 0; i < files.Count; i++)
{
try
{
using var s = await client.GetStreamAsync(files[i]);
using var fs = new FileStream(#"e:\files1\file" + i.ToString() + ".txt", FileMode.OpenOrCreate);
await s.CopyToAsync(fs);
}
catch { }
}
}
private async void button1_Click(object sender, EventArgs e)
{
await Download();
}
the goal is to download each file and when the download is completed for each file to do something with the file in the completed event.
i tried to google but still not sure how to add the progress and completed events (mostly the completed ).
This question already has answers here:
Read/Write text file progressbar in C#
(1 answer)
How to show progress of reading from a file and writing to a database
(1 answer)
Closed 1 year ago.
I am trying to read a large txt file (>50MB) asynchronously and while it is being read, report the progress on the UI progressbar and have the option to cancel the process. So far I have read and processed the file async as I wanted but I could not solve the progressbar part.
public static async Task<string> ReadTxtAsync(string filePath)
{
try
{
using (var reader = File.OpenText(filePath))
{
var content = await reader.ReadToEndAsync();
return content;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
public static async Task<Dictionary<string, int>> OpenTxtAsync()
{
Dictionary<string, int> uniqueWords = new Dictionary<string, int>();
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Text Documents (*.txt)|*.txt";
string content = null;
try
{
if (openFileDialog.ShowDialog() == true)
{
string filePath = openFileDialog.FileName.ToString();
if (openFileDialog.CheckFileExists && new[] { ".txt" }.Contains(Path.GetExtension(filePath).ToLower()) && filePath != null)
{
Task<string> readText = ReadTxtAsync(filePath);
content = await readText;
uniqueWords = WordExtractor.CountWords(ref content);
}
else MessageBox.Show("Please use .txt format extension!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return uniqueWords;
}
private async void LoadFileButtonClick(object sender, RoutedEventArgs e)
{
Task<Dictionary<string, int>> dictionaryContent = TextFileLoader.OpenTxtAsync();
uniqueWords = await dictionaryContent;
UpdateListView();
}
How can I check where ReadToEndAsync() is currently? How can I get it to continously update the progressbar and how can I cancel it?
EDIT:
Thanks to #emoacht I managed to get the progressbar to update correctly and display its percentage. The only thing that remains is to cancel the task, which I tried according to a Tim Corey video, but it did not work on my code.
public static async Task<string> ReadTextAsync(string filePath, IProgress<(double current, double total)> progress, CancellationToken cancellationToken)
{
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new StreamReader(stream);
var readTask = reader.ReadToEndAsync();
cancellationToken.ThrowIfCancellationRequested();
var progressTask = Task.Run(async () =>
{
while (stream.Position < stream.Length)
{
await Task.Delay(TimeSpan.FromMilliseconds(100));
progress.Report((stream.Position, stream.Length));
}
});
await Task.WhenAll(readTask, progressTask);
return readTask.Result;
}
try
{
Task<string> readText = TextFileLoader.ReadTextAsync(filePath, progress, cts.Token);
content = await readText;
LabelProgress.Content = "Done Reading! Now creating wordlist...";
}
catch (OperationCanceledException)
{
LabelProgress.Content = "File laden wurde abgebrochen";
}
I have a buttonClick Event for cancel cts.Cancel(); but the only part where it works is the Dictionary creation. If I place the cancellationToken.ThrowIfCancellationRequested(); into the progressbar update part, it stops only the update, the stream reading still continues. If I place is right below var readTask = reader.ReadToEndAsync(); it does nothing.
You can get the current position while reading by checking Stream.Position property at regular interval. The following method will check the current position once per 100 milliseconds and report it by current value of progress parameter. To use this method, instantiate Progess<(double current, double total)> and subscribe to its ProgressChanged event.
public static async Task<string> ReadTextAsync(string filePath, IProgress<(double current, double total)> progress)
{
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new StreamReader(stream);
var readTask = reader.ReadToEndAsync();
var progressTask = Task.Run(async () =>
{
while (stream.Position < stream.Length)
{
await Task.Delay(TimeSpan.FromMilliseconds(100));
progress.Report((stream.Position, stream.Length));
}
});
await Task.WhenAll(readTask, progressTask);
return readTask.Result;
}
Error
System.InvalidOperationException: 'Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.'
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis;
using Google.Apis.Auth;
using Google.Apis.Drive.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Util.Store;
using Google.Apis.Services;
using System.Windows.Forms;
namespace GDrive_Sample
{
public partial class Form1 : Form{public Form1(
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog
{
InitialDirectory = #"D:\",
Title = "Browse Backup Files",
CheckFileExists = true,
CheckPathExists = true,
DefaultExt = "bak",
Filter = "bak files (*.bak)|*.bak",
FilterIndex = 2,
RestoreDirectory = true,
ReadOnlyChecked = true,
ShowReadOnly = true
};
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = openFileDialog1.FileName;
}
}
private static string GetMimeType(string fileName)
{
string mimeType = "application/unknown";
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}
public void Authorize()
{
string[] scopes = new string[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile,};
// var clientId = "{REDACTED}"; // From https://console.developers.google.com
//var clientSecret = "{REDACTED}"; // From https://console.developers.google.com
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
var clientId = "{REDACTED}";
var clientSecret = "{REDACTED}";
//var clientId = "{REDACTED}";
//var clientSecret = "{REDACTED}";
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
}, scopes,
Environment.UserName, CancellationToken.None, new FileDataStore("MyAppsToken")).Result;
//Once consent is recieved, your token will be stored locally on the AppData directory, so that next time you wont be prompted for consent.
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "uploadclient",
});
service.HttpClient.Timeout = TimeSpan.FromMinutes(100);
//Long Operations like file uploads might timeout. 100 is just precautionary value, can be set to any reasonable value depending on what you use your service for
// team drive root https://drive.google.com/drive/folders/0AAE83zjNwK-GUk9PVA
//string uploadfile = #"C:\Users\hp\Downloads\settings.png";
var responce = uploadFile(service, textBox1.Text, "");
//var respocne = uploadFile(service, uploadfile, "");
// Third parameter is empty it means it would upload to root directory, if you want to upload under a folder, pass folder's id here.
MessageBox.Show("Process completed--- Response--" + responce);
}
public Google.Apis.Drive.v3.Data.File uploadFile(DriveService _service, string _uploadFile, string _parent, string _descrp = "Uploaded with .NET!")
{
if (System.IO.File.Exists(_uploadFile))
{
Google.Apis.Drive.v3.Data.File body = new Google.Apis.Drive.v3.Data.File();
body.Name = System.IO.Path.GetFileName(_uploadFile);
body.Description = _descrp;
body.MimeType = GetMimeType(_uploadFile);
// body.Parents = new List<string> { _parent };// UN comment if you want to upload to a folder(ID of parent folder need to be send as paramter in above method)
byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.CreateMediaUpload request = _service.Files.Create(body, stream, GetMimeType(_uploadFile));
request.SupportsTeamDrives = true;
// You can bind event handler with progress changed event and response recieved(completed event)
request.ProgressChanged += Request_ProgressChanged;
request.ResponseReceived += Request_ResponseReceived;
request.Upload();
return request.ResponseBody;
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error Occured");
return null;
}
}
else
{
MessageBox.Show("The file does not exist.", "404");
return null;
}
}
private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
{
textBox1.Text += obj.Status + " " + obj.BytesSent;
}
private void Request_ResponseReceived(Google.Apis.Drive.v3.Data.File obj)
{
if (obj != null)
{
MessageBox.Show("File was uploaded sucessfully--" + obj.Id);
}
}
public void button2_Click(object sender, EventArgs e)
{
Authorize();
}
}
}
Your issue essentially boils down to a very simple problem. You can only update controls from the UI thread. Not from a background thread.
Your issue is this piece of code :
private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
{
textBox1.Text += obj.Status + " " + obj.BytesSent;
}
Request_ProgressChanged is being called async from a background thread. And yet you are trying to update the textBox1 text.
You can just change it to be :
private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
{
textBox1.BeginInvoke((Action)(() => textBox1.Text += obj.Status + " " + obj.BytesSent));
}
BeginInvoke tells your application to marshall the call back to the UI thread and make it do the work. You will need to do this anywhere you are trying to update the UI from a background thread.
This can become tedious so you can also use libraries such as PostSharp that allow you to add attributes to methods you want to run on the UI thread instead of constantly writing boilerplate https://dotnetcoretutorials.com/2020/12/10/simplifying-multithreaded-scenarios-with-postsharp-threading/
I'm using Google drive V3 api. I tried to updated progress when downloading file but it seems not working.
I used Dispatcher.BeginInvoke() to update progressbar value.
When I debug at progressBar.Value, it didn't jump into this line: progressBar.Value = Convert.ToDouble(progress.BytesDownloaded * 100 / fileSize);
I've searched in google and stackoverflow but I cannot find the solution.
Please help. Thank you in advanced!
MainWindow.xaml
<Window x:Class="DownloadProgress.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DownloadProgress"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="400">
<StackPanel>
<ProgressBar Height="30" Margin="10" Name="progressBar"/>
<Button Height="30" Content="Downloads" Margin="10" Click="StartDownload"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void StartDownload(object sender, RoutedEventArgs e)
{
string[] Scopes = { DriveService.Scope.DriveReadonly };
DriveService driveService = AuthenticateServiceAccount(#"C:\Users\210636\Downloads\licensemanage-cf129668e7ad.json", Scopes);
FilesResource.ListRequest listRequest = driveService.Files.List();
listRequest.Q = "'1Rl6E1sLkMdW0iRpfdrOzdF4C_U6lfZhu' in parents";
listRequest.PageSize = 10;
listRequest.Fields = "nextPageToken, files(id, name, size)";
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute().Files;
var fileId = "1QETWTnkIp9q6O35Rm99qC6LsJ4Gdg3I5";
var request = driveService.Files.Get(fileId);
request.Fields = "id, name, size";
var file = request.Execute();
long? fileSize = file.Size;
string f = driveService.Files.Get(fileId).Execute().Name;
var streamDownload = new MemoryStream();
progressBar.Minimum = 0;
progressBar.Maximum = 100;
progressBar.Value = 50;
request.MediaDownloader.ProgressChanged += (IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
Dispatcher.BeginInvoke(new Action(() =>
{
progressBar.Value = Convert.ToDouble(progress.BytesDownloaded * 100 / fileSize);
}));
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
using (FileStream fs = new FileStream("downloaded.zip", FileMode.OpenOrCreate))
{
streamDownload.WriteTo(fs);
fs.Flush();
}
break;
}
case DownloadStatus.Failed:
{
break;
}
}
};
request.Download(streamDownload);
}
public static DriveService AuthenticateServiceAccount(string serviceAccountCredentialFilePath, string[] scopes)
{
GoogleCredential credential;
using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(scopes);
}
// Create the Analytics service.
return new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive Service account Authentication Sample",
});
}
}
request.Download(streamDownload); is blocking the UI thread. The downloading should be async. I also highly recommend to use Progress<T> to report progress to the UI: Async in 4.5: Enabling Progress and Cancellation in Async APIs.
MainWindow.xaml.cs
// Asynchronous event handler
private async void StartDownloadAsync(object sender, RoutedEventArgs e)
{
...
var fileId = "1QETWTnkIp9q6O35Rm99qC6LsJ4Gdg3I5";
progressBar.Minimum = 0;
progressBar.Maximum = 100;
progressBar.Value = 50;
// Creating an instance of Progress<T> captures the current
// SynchronizationContext (UI context) to prevent cross threading when updating the ProgressBar
IProgress<double> progressReporter =
new Progress<double>(value => progressBar.Value = value);
await DownloadAsync(progressReporter, fileId);
}
private async Task DownloadAsync(progressReporter, string fileId)
{
var streamDownload = new MemoryStream();
var request = driveService.Files.Get(fileId);
var file = request.Execute();
long? fileSize = file.Size;
// Report progress to UI via the captured UI's SynchronizationContext using IProgress<T>
request.MediaDownloader.ProgressChanged +=
(progress) => ReportProgress(progress, progressReporter, fileSize, streamDownload);
// Execute download asynchronous
await Task.Run(() => request.Download(streamDownload));
}
private void ReportProgress(IDownloadProgress progress, IProgress<double> progressReporter, long? fileSize, MemoryStream streamDownload)
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
double progressValue = Convert.ToDouble(progress.BytesDownloaded * 100 / fileSize);
// Update the ProgressBar on the UI thread
progressReporter.Report(progressValue);
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
using (FileStream fs = new FileStream("downloaded.zip", FileMode.OpenOrCreate))
{
streamDownload.WriteTo(fs);
fs.Flush();
}
break;
}
case DownloadStatus.Failed:
{
break;
}
}
}
i have been working on a windows store project using c#
i have a method called
void TranscodeProgress(IAsyncActionWithProgress<double> asyncInfo, double percent)
{
pg1.Value=percent;
}
when i try to add a progress bar to this it gives me an error
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
please help me to correct this error
thanks
this is my entire code
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
Windows.Storage.StorageFile source;
Windows.Storage.StorageFile destination;
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
openPicker.FileTypeFilter.Add(".mp4");
openPicker.FileTypeFilter.Add(".wmv");
source = await openPicker.PickSingleFileAsync();
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation =
Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
savePicker.DefaultFileExtension = ".wmv";
savePicker.SuggestedFileName = "New Video";
savePicker.FileTypeChoices.Add("MPEG4", new string[] { ".wmv" });
destination = await savePicker.PickSaveFileAsync();
// Method to perform the transcoding.
TranscodeFile(source, destination);
}
async void TranscodeFile(StorageFile srcFile, StorageFile destFile)
{
MediaEncodingProfile profile =
MediaEncodingProfile.CreateWmv(VideoEncodingQuality.HD1080p);
MediaTranscoder transcoder = new MediaTranscoder();
PrepareTranscodeResult prepareOp = await
transcoder.PrepareFileTranscodeAsync(srcFile, destFile, profile);
if (prepareOp.CanTranscode)
{
var transcodeOp = prepareOp.TranscodeAsync();
transcodeOp.Progress +=
new AsyncActionProgressHandler<double>(TranscodeProgress);
// p1.Value = double.Parse(transcodeOp.Progress.ToString());
// txtProgress.Text = transcodeOp.Progress.ToString();
transcodeOp.Completed +=
new AsyncActionWithProgressCompletedHandler<double>(TranscodeComplete);
}
else
{
switch (prepareOp.FailureReason)
{
case TranscodeFailureReason.CodecNotFound:
MessageDialog md=new MessageDialog("Codec not found.");
await md.ShowAsync();
break;
case TranscodeFailureReason.InvalidProfile:
MessageDialog md1 = new MessageDialog("Invalid profile.");
await md1.ShowAsync();
break;
default:
MessageDialog md2 = new MessageDialog("Unknown failure.");
await md2.ShowAsync();
break;
}
}
//txtDisplay.Text = a;
}
void TranscodeProgress(IAsyncActionWithProgress<double> asyncInfo, double percent)
{
}
void TranscodeComplete(IAsyncActionWithProgress<double> asyncInfo, AsyncStatus status)
{
asyncInfo.GetResults();
if (asyncInfo.Status == AsyncStatus.Completed)
{
// Display or handle complete info.
}
else if (asyncInfo.Status == AsyncStatus.Canceled)
{
// Display or handle cancel info.
}
else
{
// Display or handle error info.
}
}
You should:
Avoid async void.
Use the TAP naming pattern (make your Task-returning methods end in "Async").
Use AsTask to do complex interop between TAP and WinRT asynchronous operations.
Something like this:
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
...
await TranscodeFileAsync(source, destination);
}
async Task TranscodeFileAsync(StorageFile srcFile, StorageFile destFile)
{
MediaEncodingProfile profile =
MediaEncodingProfile.CreateWmv(VideoEncodingQuality.HD1080p);
MediaTranscoder transcoder = new MediaTranscoder();
PrepareTranscodeResult prepareOp = await
transcoder.PrepareFileTranscodeAsync(srcFile, destFile, profile);
if (prepareOp.CanTranscode)
{
var progress = new Progress<double>(percent => { pg1.Value = percent; });
var result = await prepareOp.TranscodeAsync().AsTask(progress);
// Display result.
}
else
{
...
}
}
You are trying to access UI component from non UI Thread.
use:
void TranscodeProgress(IAsyncActionWithProgress<double> asyncInfo, double percent)
{
if(InvokeRequired)
{
Invoke(new MethodInvoker() => TranscodeProgress(asyncInfo, percent));
return;
}
pg1.Value=percent;
}
You cannot access UI components from non UI threads, Calling Invoke with a delegate passes the function call to thread that owns the component and than that thread call the passed delegate.