0

I have a Button on a Page with the following method on the click event of the button:

StorageFile _sourceFile;    
private string _sourceToken;
private async void btnSelect_Click(object sender, RoutedEventArgs e)
{
    FileOpenPicker fop = new FileOpenPicker();
    fop.FileTypeFilter.Add(".mp4");

    StorageFile inFile = await fop.PickSingleFileAsync();
    _sourceToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(inFile);

    _sourceFile = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFileAsync(_sourceToken);
    mediaElement.AutoPlay = false;
    IRandomAccessStream stream = await _outFile.OpenAsync(FileAccessMode.ReadWrite);
    mediaElement.SetSource(stream, _outFile.ContentType);

}

If I click play on the MediaElement the video I select plays fine.

I also have another button which has the following code on its click event:

private async void btnExport_Click(object sender, RoutedEventArgs e)
{
    StorageFile outFile = await KnownFolders.VideosLibrary.CreateFileAsync("Outfie.mp4", CreationCollisionOption.ReplaceExisting);

    MediaEncodingProfile profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);

    MediaTranscoder transcoder = new MediaTranscoder();

    PrepareTranscodeResult prepareOp = await transcoder.PrepareFileTranscodeAsync(_sourceFile, outFile, profile);

    if (prepareOp.CanTranscode)
    {
        var transcodeOp = prepareOp.TranscodeAsync();

        transcodeOp.Progress += new AsyncActionProgressHandler<double>(TranscodeProgress);
        transcodeOp.Completed += new AsyncActionWithProgressCompletedHandler<double>(TranscodeComplete);
    }
    else
    {
        switch (prepareOp.FailureReason)
        {
            case TranscodeFailureReason.CodecNotFound:
                System.Diagnostics.Debug.WriteLine("Codec not found.");
                break;
            case TranscodeFailureReason.InvalidProfile:
                System.Diagnostics.Debug.WriteLine("Invalid profile.");
                break;
            default:
                System.Diagnostics.Debug.WriteLine("Unknown failure.");
                break;
        }
    }
}

Unfortunately the line transcoder.PrepareFileTranscodeAsync throws an UnauthorizedAccessException. But if I use the following instead of _sourceFile it works:

StorageFile sourceFile = await KnownFolders.VideosLibrary.GetFileAsync("sourceFile.mp4");

The error being thrown is:

System.UnauthorizedAccessException: 'Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))'

To be clear, I am selecting files OUTSIDE the KnownFolders Enumeration, hence I am using Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.

Can anyone explain why?

EDIT: If I change the source file to be the result of a FileOpenPicker then it works. So it begs the question, why is the FutureAccessList not working??

private async void btnExport_Click(object sender, RoutedEventArgs e)
{
    StorageFile outFile = await KnownFolders.VideosLibrary.CreateFileAsync("Outfie.mp4", CreationCollisionOption.ReplaceExisting);

    FileOpenPicker fop = new FileOpenPicker();
    fop.SuggestedStartLocation = PickerLocationId.ComputerFolder;
    fop.FileTypeFilter.Add(".mp4");

    StorageFile sourceFile = await fop.PickSingleFileAsync();

    MediaEncodingProfile profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);

    MediaTranscoder transcoder = new MediaTranscoder();

    PrepareTranscodeResult prepareOp = await transcoder.PrepareFileTranscodeAsync(sourceFile, outFile, profile);

    if (prepareOp.CanTranscode)
    {
        var transcodeOp = prepareOp.TranscodeAsync();

        transcodeOp.Progress += new AsyncActionProgressHandler<double>(TranscodeProgress);
        transcodeOp.Completed += new AsyncActionWithProgressCompletedHandler<double>(TranscodeComplete);
    }
    else
    {
        switch (prepareOp.FailureReason)
        {
            case TranscodeFailureReason.CodecNotFound:
                System.Diagnostics.Debug.WriteLine("Codec not found.");
                break;
            case TranscodeFailureReason.InvalidProfile:
                System.Diagnostics.Debug.WriteLine("Invalid profile.");
                break;
            default:
                System.Diagnostics.Debug.WriteLine("Unknown failure.");
                break;
        }
    }
}
Andrew Harris
  • 1,419
  • 2
  • 17
  • 29

2 Answers2

1

Do you have access to the file you're trying to write to? Maybe it's read-only or created by another user other than yourself? (Right click + Properties on the file in Explorer should give you a clearer picture of the file permissions)

Also, you might get that exception if you're trying to write to a folder whom you don't have access to.

Check your credentials, I would guess it's something related to that.

Jonathan Perry
  • 2,953
  • 2
  • 44
  • 51
  • Agree definitely a permissions issue, but note the following line: IRandomAccessStream stream = await _outFile.OpenAsync(FileAccessMode.ReadWrite); Which fails when I don't have permission in the first instance. – Andrew Harris Apr 23 '17 at 11:40
  • Why wouldn't it fail if you don't have permissions? You're asking access to Read/Write a file you're not allowed to modify it. – Jonathan Perry Apr 23 '17 at 11:47
  • My point was that I have permissions. I wouldn't be able to execute the OpenAsync demanding Read/Write in the first place if I didn't have the permissions. – Andrew Harris Apr 23 '17 at 11:56
  • @AndrewHarris Can you please post the full message thrown with the Exception? – Jonathan Perry Apr 23 '17 at 12:04
  • Just updated the Question with some more information. Seems the FutureAccessList isn't saving the permissions. – Andrew Harris Apr 24 '17 at 01:31
1

So it seems the fact I was opening the source file in ReadWrite mode

IRandomAccessStream stream = await _outFile.OpenAsync(FileAccessMode.ReadWrite);

Was the cause of the issues. According to this page

Use read/write mode only when you're ready to write immediately in order to avoid conflicts with other operations.

So I changed to this and all works well

IRandomAccessStream stream = await _outFile.OpenAsync(FileAccessMode.Read);
Andrew Harris
  • 1,419
  • 2
  • 17
  • 29