2

I'am taking a 5 minute duration video and try to upload it into the API, but the response from the API is false and the video is not present in the Database. I uploaded small sized video to the API.

I found that the size of the video is high it takes more time to upload and the API is time out after some time. How to reduce the size of the video with out reducing it's content or upload a long duration video into the API with in few seconds.

Please help me..

Here is my code

private async void TakeVideo_Clicked(object sender, EventArgs e)
{
    if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakeVideoSupported)
    {
        await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
        return;
    }

    var _file = await CrossMedia.Current.TakeVideoAsync(new Plugin.Media.Abstractions.StoreVideoOptions
    {
        Name = "video.mp4",
        Directory = "Videos",
    });

    if (_file == null)
    {
        return;
    }
    else
    {
        _path = _file.Path;

        using (var _streamReader = new StreamReader(_file.GetStream()))
        {
            var _array = default(byte[]);                 

            using (MemoryStream _memoryStream = new MemoryStream())
            {
                _streamReader.BaseStream.CopyTo(_memoryStream);

                _array = _memoryStream.ToArray();                        

                if (await DisplayAlert(App._confirmation, "Do you want to save the video?", "Yes", "Cancel"))
                {
                    FileUploadAsync(_array, false);
                    activity_Indicator.IsVisible = true;
                    activity_Indicator.IsRunning = true;
                }
                else
                {
                    return;
                }
            }
        }
    }
}

public async void FileUploadAsync(byte[] fileUpload, bool IsImage)
    {
        APIResponse _response = await App.DataManager.UpdateFilesAsync(ID, fileUpload, IsImage);

        if (_response != null)
        {
            activity_Indicator.IsRunning = false;

            if (IsImage)
            {
                DependencyService.Get<IAlertPlayer>().AlertMessege("Image upload successfully");
            }
            else
            {
                DependencyService.Get<IAlertPlayer>().AlertMessege("Video upload successfully");
            }
        }
        else
        {
            DisplayAlertMessage();
        }
    }      

  public async Task<APIResponse>UpdateFilesAsync(int id,byte[] file,bool IsImage)
    {
        Url _url = new Url(BaseURL).AppendPathSegment("sample/UploadFiles");

        _url.QueryParams["ID"] = id;

        return await Service.POSTFILE<APIResponse>(_url, file,IsImage);
    }

Here is my POST method

public async Task<T> POSTFILE<T>(Url url, byte[] uploadFile, bool IsImage)
    {
        try
        {
            using (MultipartFormDataContent content = new MultipartFormDataContent())
            {
                ByteArrayContent filecontent = new ByteArrayContent(uploadFile);

                if (IsImage)
                {
                    filecontent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                    {
                        FileName = Guid.NewGuid().ToString() + ".png"
                    };
                }
                else
                {
                    filecontent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                    {
                        FileName = Guid.NewGuid().ToString() + ".mp4"
                    };
                }

                content.Add(filecontent);

                using (HttpResponseMessage response = await Client.PostAsync(url, content))
                {
                    string result = await response.Content.ReadAsStringAsync();
                    return JsonConvert.DeserializeObject<T>(result);
                }
            }
        }
        catch (Exception ex)
        {

        }

        return default(T);
    }
}
Aswathy K R
  • 167
  • 2
  • 14

2 Answers2

2

So here is how i use video compression on Xamarin.iOS. You can make this into a service and then implement the proper compression logic based on the platform. Lastly if you are using IIS make sure you increase your video upload limit

        var asset = AVAsset.FromUrl(NSUrl.FromFilename(path));
        AVAssetExportSession exportSession = new AVAssetExportSession(asset, AVAssetExportSessionPreset.HighestQuality);

        exportSession.OutputUrl = NSUrl.FromFilename(pathService.GetCompressedPath());
        exportSession.OutputFileType = AVFileType.Mpeg4;
        exportSession.ShouldOptimizeForNetworkUse = true;

        await exportSession.ExportTaskAsync(); //This can cause an error so check the status

        Stream exportStream = File.OpenRead(path);

        return exportStream;

Android Implementation

        //create File from string.
        var file = new Java.IO.File(path);
        var outputFile = new Java.IO.File(pathService.GetCompressedPath());

        await Transcoder.For720pFormat().ConvertAsync(file, outputFile, null);

        Stream exportStream = File.OpenRead(outputFile.Path);

        System.Diagnostics.Debug.WriteLine("Stream read from file");

        return exportStream;
sedders123
  • 791
  • 1
  • 9
  • 19
KING
  • 938
  • 8
  • 26
  • dont have it for android – KING Apr 25 '18 at 14:16
  • @AswathyKR https://forums.xamarin.com/discussion/60041/is-there-possibility-to-compress-the-audio-and-video-file-programmatically – KING Apr 25 '18 at 20:11
  • Nop I didn't get a solution – Aswathy K R Jun 29 '18 at 05:43
  • @AswathyKR i updated the post with my Android implementation – KING Jul 01 '18 at 17:51
  • @sedders123 From where can I get Transcoder, and what is pathService for pathService.GetCompressedPath() ? – MShah May 13 '19 at 08:40
  • @MShah Transcoder comes from the Xamarin.MP4Transcoder namespace. The path service is application specific code, it just returns a path for the compressed file to be saved to – sedders123 May 13 '19 at 08:50
  • @sedders123 Thanks, but while installing plugin, I'm getting this error: Xamarin.Android.MP4Transcoder 1.0.9 is not compatible with monoandroid81 , do you have any idea regarding solution of it? – MShah May 13 '19 at 09:04
  • Sorry not sure, maybe you could open a new question if you can't find an existing solution – sedders123 May 13 '19 at 11:02
  • Its fine, no issues, Thanks for replying @sedders123. – MShah May 13 '19 at 12:30
0

Unfortunately, there are no cross-platform solutions for video compression, so you would have to implement this compression in a platform-specific manner. Each platform should have such solution available if you search for those.

Alternatively, you could tweak the HttpClient.Timeout to a larger value (default is 100 seconds) so that the upload does not time out if the file is large. Of course the value depends on the requirements you have. You can even set it to be virtually infinite (TimeSpan.MaxValue), but then you have the risk of creating requests which never end and you would have to add some kind of manual cancellation using CancellationTokenSource.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • Is there any way to reduce the byte array without losing its contents – Aswathy K R Feb 06 '18 at 09:43
  • No, unfortunately not, you can only reduce it by doing some kind of compression (there are some compression algorithms available), but compression is not very effective when the data is binary and you in any case need to transfer everything – Martin Zikmund Apr 23 '18 at 12:46
  • The thing is if you want to transfer a video, reducing the byte array would necessarily mean losing its content unless you do it using a compression that is lossless – Martin Zikmund Apr 23 '18 at 12:47
  • @AswathyKR I have resolved this issue in my project. I will update this with some sample code that may prove helpful but it will be a little later on – KING Apr 23 '18 at 18:09
  • @KING can you please share the code, now it's very urgent for me – Aswathy K R Apr 24 '18 at 03:45
  • @KING updoot incoming? – DisplayName May 22 '18 at 02:11
  • Btw I would use async Task in your code instead of async void so in case of error the thread returns and you can see it instead of a silent failure driving you crazy. Never use async void except for ui based handlers – DisplayName May 22 '18 at 02:16