Невозможно сохранить данные размера файлов в активах службы мультимедиа Azure - PullRequest
0 голосов
/ 17 марта 2019

В настоящее время создается веб-интерфейс API для существующих веб-служб мультимедиа для кодирования загруженных видео.

Цель моего решения - создать вызов API, куда я буду отправлятьссылка mp4 и выполнение обработки (кодирование и потоковая передача заданной ссылки mp4).Мне удалось получить mp4 и загрузить на сервер и повторно загрузить в собственное хранилище больших двоичных объектов.Однако, если я проверю проводник AMS, все параметры, которые я передал, существуют, за исключением размера файла.Вот мой вызов WEB API, который я создал (полная копия существующего метода формы медиа-сервиса. (https://tiltestingstreaming.azurewebsites.net/)

    [HttpPost]
    public JsonResult UploadApi(String video_url)
    {
        var id = 1;
        WebClient client = new WebClient();
        var videoStream = new MemoryStream(client.DownloadData(video_url));

        var container = CloudStorageAccount.Parse(mediaServiceStorageConnectionString).CreateCloudBlobClient().GetContainerReference(mediaServiceStorageContainerReference);

        container.CreateIfNotExists();
        var fileName = Path.GetFileName(video_url);

        var fileToUpload = new CloudFile()
        {
            BlockCount = 1,
            FileName = fileName,
            Size = videoStream.Length,
            BlockBlob = container.GetBlockBlobReference(fileName),
            StartTime = DateTime.Now,
            IsUploadCompleted = false,
            UploadStatusMessage = string.Empty
        };

        Session.Add("CurrentFile", fileToUpload);

        byte[] chunk = new byte[videoStream.Length];
        //request.InputStream.Read(chunk, 0, Convert.ToInt32(request.Length));
        //JsonResult returnData = null;
        string fileSession = "CurrentFile";
        CloudFile model = (CloudFile)Session[fileSession];    
        var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(
                string.Format(CultureInfo.InvariantCulture, "{0:D4}", id)));
        try
        {
            model.BlockBlob.PutBlock(
                blockId,
                videoStream, null, null,
                new BlobRequestOptions()
                {
                    RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(10), 3)
                },
                null);
        }
        catch (StorageException e)
        {
            model.IsUploadCompleted = true;
            model.UploadStatusMessage = "Failed to Upload file. Exception - " + e.Message;
            return Json(new { error = true, isLastBlock = false, message = model.UploadStatusMessage });
        }

        var blockList = Enumerable.Range(1, (int)model.BlockCount).ToList<int>().ConvertAll(rangeElement => Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0:D4}", rangeElement))));
        model.BlockBlob.PutBlockList(blockList);
        var duration = DateTime.Now - model.StartTime;
        float fileSizeInKb = model.Size / 1024;
        string fileSizeMessage = fileSizeInKb > 1024 ? string.Concat((fileSizeInKb / 1024).ToString(CultureInfo.CurrentCulture), " MB") : string.Concat(fileSizeInKb.ToString(CultureInfo.CurrentCulture), " KB");
        model.UploadStatusMessage = string.Format(CultureInfo.CurrentCulture, "File of size {0} took {1} seconds to upload.", fileSizeMessage, duration.TotalSeconds);

        IAsset mediaServiceAsset = CreateMediaAsset(model);
        model.AssetId = mediaServiceAsset.Id;

        //if (id == model.BlockCount){CommitAllChunks(model);}
        return Json(new { error = false, isLastBlock = false, message = string.Empty, filename = fileName,filesize = videoStream.Length });
    }

Функции, используемые в решении с помощью метода форм.

[HttpPost]
    public ActionResult SetMetadata(int blocksCount, string fileName, long fileSize)
    {
        var container = CloudStorageAccount.Parse(mediaServiceStorageConnectionString).CreateCloudBlobClient().GetContainerReference(mediaServiceStorageContainerReference);

        container.CreateIfNotExists();

        var fileToUpload = new CloudFile()
        {
            BlockCount = blocksCount,
            FileName = fileName,
            Size = fileSize,
            BlockBlob = container.GetBlockBlobReference(fileName),
            StartTime = DateTime.Now,
            IsUploadCompleted = false,
            UploadStatusMessage = string.Empty
        };

        Session.Add("CurrentFile", fileToUpload);

        return Json(true);
    }

    [HttpPost]
    [ValidateInput(false)]
    public ActionResult UploadChunk(int id)
    {
        HttpPostedFileBase request = Request.Files["Slice"];
        byte[] chunk = new byte[request.ContentLength];
        request.InputStream.Read(chunk, 0, Convert.ToInt32(request.ContentLength));
        JsonResult returnData = null;
        string fileSession = "CurrentFile";
        if (Session[fileSession] != null)
        {
            CloudFile model = (CloudFile)Session[fileSession];
            returnData = UploadCurrentChunk(model, chunk, id);
            if (returnData != null)
            {
                return returnData;
            }
            if (id == model.BlockCount)
            {
                return CommitAllChunks(model);
            }
        }
        else
        {
            returnData = Json(new
            {
                error = true,
                isLastBlock = false,
                message = string.Format(CultureInfo.CurrentCulture, "Failed to Upload file.", "Session Timed out")
            });
            return returnData;
        }
        return Json(new { error = false, isLastBlock = false, message = string.Empty });
    }

    private JsonResult UploadCurrentChunk(CloudFile model, byte[] chunk, int id)
    {
        using (var chunkStream = new MemoryStream(chunk))
        {
            var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(
                    string.Format(CultureInfo.InvariantCulture, "{0:D4}", id)));
            try
            {
                model.BlockBlob.PutBlock(
                    blockId,
                    chunkStream, null, null,
                    new BlobRequestOptions()
                    {
                        RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(10), 3)
                    },
                    null);
                return null;
            }
            catch (StorageException e)
            {
                model.IsUploadCompleted = true;
                model.UploadStatusMessage = "Failed to Upload file. Exception - " + e.Message;
                return Json(new { error = true, isLastBlock = false, message = model.UploadStatusMessage });
            }
        }
    }

    private ActionResult CommitAllChunks(CloudFile model)
    {
        model.IsUploadCompleted = true;
        bool errorInOperation = false;
        try
        {
            var blockList = Enumerable.Range(1, (int)model.BlockCount).ToList<int>().ConvertAll(rangeElement => Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0:D4}", rangeElement))));
            model.BlockBlob.PutBlockList(blockList);
            var duration = DateTime.Now - model.StartTime;
            float fileSizeInKb = model.Size / 1024;
            string fileSizeMessage = fileSizeInKb > 1024 ? string.Concat((fileSizeInKb / 1024).ToString(CultureInfo.CurrentCulture), " MB") : string.Concat(fileSizeInKb.ToString(CultureInfo.CurrentCulture), " KB");
            model.UploadStatusMessage = string.Format(CultureInfo.CurrentCulture, "File of size {0} took {1} seconds to upload.", fileSizeMessage, duration.TotalSeconds);

            IAsset mediaServiceAsset = CreateMediaAsset(model);
            model.AssetId = mediaServiceAsset.Id;
        }
        catch (StorageException e)
        {
            model.UploadStatusMessage = "Failed to upload file. Exception - " + e.Message;
            errorInOperation = true;
        }
        return Json(new
        {
            error = errorInOperation,
            isLastBlock = model.IsUploadCompleted,
            message = model.UploadStatusMessage,
            assetId = model.AssetId
        });
    }

    private IAsset CreateMediaAsset(CloudFile model)
    {
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(mediaServiceStorageConnectionString);
        CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer mediaBlobContainer = cloudBlobClient.GetContainerReference(mediaServiceStorageContainerReference);

        mediaBlobContainer.CreateIfNotExists();

        // Create a new asset.
        IAsset asset = context.Assets.Create("UploadedVideo-" + Guid.NewGuid().ToString().ToLower(), AssetCreationOptions.None);
        IAccessPolicy writePolicy = context.AccessPolicies.Create("writePolicy", TimeSpan.FromMinutes(120), AccessPermissions.Write);
        ILocator destinationLocator = context.Locators.CreateLocator(LocatorType.Sas, asset, writePolicy);

        // Get the asset container URI and copy blobs from mediaContainer to assetContainer.
        Uri uploadUri = new Uri(destinationLocator.Path);
        string assetContainerName = uploadUri.Segments[1];
        CloudBlobContainer assetContainer = cloudBlobClient.GetContainerReference(assetContainerName);
        string fileName = HttpUtility.UrlDecode(Path.GetFileName(model.BlockBlob.Uri.AbsoluteUri));

        var sourceCloudBlob = mediaBlobContainer.GetBlockBlobReference(fileName);
        sourceCloudBlob.FetchAttributes();

        if (sourceCloudBlob.Properties.Length > 0)
        {
            IAssetFile assetFile = asset.AssetFiles.Create(fileName);
            var destinationBlob = assetContainer.GetBlockBlobReference(fileName);

            destinationBlob.DeleteIfExists();
            destinationBlob.StartCopy(sourceCloudBlob);
            destinationBlob.FetchAttributes();
            if (sourceCloudBlob.Properties.Length != destinationBlob.Properties.Length)
                model.UploadStatusMessage += "Failed to copy as Media Asset!";
        }
        destinationLocator.Delete();
        writePolicy.Delete();
        sourceCloudBlob.Delete();  //delete temp blob

        // Refresh the asset.
        asset = context.Assets.Where(a => a.Id == asset.Id).FirstOrDefault();

        var ismAssetFiles = asset.AssetFiles.FirstOrDefault();
        ismAssetFiles.IsPrimary = true;
        ismAssetFiles.Update();

        model.UploadStatusMessage += " Media file uploaded successfully by id: " + asset.Id;
        model.AssetId = asset.Id;

        return asset;
    }

    [HttpPost]
    public ActionResult EncodeToAdaptiveBitrateMP4s(string assetId)
    {
        // Note: You need atleast 1 reserve streaming unit for dynamic packaging of encoded media. If you don't have that, you can't see video file playing.

        IAsset inputAsset = GetAssetById(assetId);
        string token = string.Empty;
        string uploadFileOriginalName = string.Empty;

        ////// Without preset (say default preset), works very well
        //IJob job = context.Jobs.CreateWithSingleTask(MediaProcessorNames.AzureMediaEncoder,
        //    MediaEncoderTaskPresetStrings.H264AdaptiveBitrateMP4Set720p,
        //    inputAsset,
        //    "UploadedVideo-" + Guid.NewGuid().ToString().ToLower() + "-Adaptive-Bitrate-MP4",
        //    AssetCreationOptions.None);
        //job.Submit();
        //IAsset encodedOutputAsset = job.OutputMediaAssets[0];


        //// XML Preset
        IJob job = context.Jobs.Create(inputAsset.Name);
        IMediaProcessor processor = GetLatestMediaProcessorByName("Media Encoder Standard");
        string configuration = System.IO.File.ReadAllText(HttpContext.Server.MapPath("~/MediaServicesCustomPreset.xml"));
        ITask task = job.Tasks.AddNew(inputAsset.Name + "- encoding task", processor, configuration, TaskOptions.None);
        task.InputAssets.Add(inputAsset);
        task.OutputAssets.AddNew(inputAsset.Name + "-Adaptive-Bitrate-MP4", AssetCreationOptions.None);
        job.Submit();
        IAsset encodedAsset = job.OutputMediaAssets[0];

        // process policy & encryption
        ProcessPolicyAndEncryption(encodedAsset);

        // Get file name
        string fileSession = "CurrentFile";
        if (Session[fileSession] != null)
        {
            CloudFile model = (CloudFile)Session[fileSession];
            uploadFileOriginalName = model.FileName;
        }

        // Generate Streaming URL
        string smoothStreamingUri = GetStreamingOriginLocator(encodedAsset, uploadFileOriginalName);

        // add jobid and output asset id in database
        AzureMediaServicesContext db = new AzureMediaServicesContext();
        var video = new Video();
        video.RowAssetId = assetId;
        video.EncodingJobId = job.Id;
        video.EncodedAssetId = encodedAsset.Id;
        video.LocatorUri = smoothStreamingUri;
        video.IsEncrypted = useAESRestriction;
        db.Videos.Add(video);
        db.SaveChanges();

        if (useAESRestriction)
        {
            token = AzureMediaAsset.GetTestToken(encodedAsset.Id, encodedAsset);
        }

        // Remove session
        Session.Remove("CurrentFile");

        // return success response
        return Json(new
        {
            error = false,
            message = "Congratulations! Video is uploaded and pipelined for encoding, check console log for after encoding playback details.",
            assetId = assetId,
            jobId = job.Id,
            locator = smoothStreamingUri,
            encrypted = useAESRestriction,
            token = token
        });

    }

Реальная проблема, с которой я столкнулся, заключалась в том, что я не уверен, почему размер файла загруженного удаленного файла mp4 не сохраняется в файле ресурсов медиа-сервисов, но я смог вернуть значение через jsonответ на мой вызов API. Проверьте прикрепленный снимок экрана с ответом API. enter image description hereenter image description here

1 Ответ

0 голосов
/ 17 марта 2019

смог разобраться в собственной проблеме.Все, что мне нужно сделать, это скопировать функцию моей функции кодирования, которая была привязана к типу данных ActionResult.Я думаю, что ActionResult является частью решения метода формы, и я строю решение для вызова WebAPI рабочего метода формы.

Из исходной функции вызова

[HttpPost] publicActionResult EncodeToAdaptiveBitrateMP4s (string assetId)

Я копирую всю функцию в мою функцию вызова WebApi, например:

[HttpPost]
    public JsonResult UploadApi(String video_url)
    {
        var id = 1;
        WebClient client = new WebClient();
        var videoStream = new MemoryStream(client.DownloadData(video_url));

        var container = CloudStorageAccount.Parse(mediaServiceStorageConnectionString).CreateCloudBlobClient().GetContainerReference(mediaServiceStorageContainerReference);

        container.CreateIfNotExists();
        var fileName = Path.GetFileName(video_url);

        var fileToUpload = new CloudFile()
        {
            BlockCount = 1,
            FileName = fileName,
            Size = videoStream.Length,
            BlockBlob = container.GetBlockBlobReference(fileName),
            StartTime = DateTime.Now,
            IsUploadCompleted = false,
            UploadStatusMessage = string.Empty
        };

        Session.Add("CurrentFile", fileToUpload);

        byte[] chunk = new byte[videoStream.Length];
        //request.InputStream.Read(chunk, 0, Convert.ToInt32(request.Length));
        //JsonResult returnData = null;
        string fileSession = "CurrentFile";
        CloudFile model = (CloudFile)Session[fileSession];    
        var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(
                string.Format(CultureInfo.InvariantCulture, "{0:D4}", id)));
        try
        {
            model.BlockBlob.PutBlock(
                blockId,
                videoStream, null, null,
                new BlobRequestOptions()
                {
                    RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(10), 3)
                },
                null);
        }
        catch (StorageException e)
        {
            model.IsUploadCompleted = true;
            model.UploadStatusMessage = "Failed to Upload file. Exception - " + e.Message;
            return Json(new { error = true, isLastBlock = false, message = model.UploadStatusMessage });
        }

        var blockList = Enumerable.Range(1, (int)model.BlockCount).ToList<int>().ConvertAll(rangeElement => Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0:D4}", rangeElement))));
        model.BlockBlob.PutBlockList(blockList);
        var duration = DateTime.Now - model.StartTime;
        float fileSizeInKb = model.Size / 1024;
        string fileSizeMessage = fileSizeInKb > 1024 ? string.Concat((fileSizeInKb / 1024).ToString(CultureInfo.CurrentCulture), " MB") : string.Concat(fileSizeInKb.ToString(CultureInfo.CurrentCulture), " KB");
        model.UploadStatusMessage = string.Format(CultureInfo.CurrentCulture, "File of size {0} took {1} seconds to upload.", fileSizeMessage, duration.TotalSeconds);

        IAsset mediaServiceAsset = CreateMediaAsset(model);
        model.AssetId = mediaServiceAsset.Id;

        // Note: You need atleast 1 reserve streaming unit for dynamic packaging of encoded media. If you don't have that, you can't see video file playing.
        var assetId = model.AssetId;
        IAsset inputAsset = GetAssetById(assetId);
        string token = string.Empty;
        string uploadFileOriginalName = string.Empty;

        ////// Without preset (say default preset), works very well
        //IJob job = context.Jobs.CreateWithSingleTask(MediaProcessorNames.AzureMediaEncoder,
        //    MediaEncoderTaskPresetStrings.H264AdaptiveBitrateMP4Set720p,
        //    inputAsset,
        //    "UploadedVideo-" + Guid.NewGuid().ToString().ToLower() + "-Adaptive-Bitrate-MP4",
        //    AssetCreationOptions.None);
        //job.Submit();
        //IAsset encodedOutputAsset = job.OutputMediaAssets[0];


        //// XML Preset
        IJob job = context.Jobs.Create(inputAsset.Name);
        IMediaProcessor processor = GetLatestMediaProcessorByName("Media Encoder Standard");
        string configuration = System.IO.File.ReadAllText(HttpContext.Server.MapPath("~/MediaServicesCustomPreset.xml"));
        ITask task = job.Tasks.AddNew(inputAsset.Name + "- encoding task", processor, configuration, TaskOptions.None);
        task.InputAssets.Add(inputAsset);
        task.OutputAssets.AddNew(inputAsset.Name + "-Adaptive-Bitrate-MP4", AssetCreationOptions.None);
        job.Submit();
        IAsset encodedAsset = job.OutputMediaAssets[0];

        // process policy & encryption
        ProcessPolicyAndEncryption(encodedAsset);

        // Get file name
        uploadFileOriginalName = model.FileName;

        // Generate Streaming URL
        string smoothStreamingUri = GetStreamingOriginLocator(encodedAsset, uploadFileOriginalName);

        // add jobid and output asset id in database
        AzureMediaServicesContext db = new AzureMediaServicesContext();
        var video = new Video();
        video.RowAssetId = assetId;
        video.EncodingJobId = job.Id;
        video.EncodedAssetId = encodedAsset.Id;
        video.LocatorUri = smoothStreamingUri;
        video.IsEncrypted = useAESRestriction;
        db.Videos.Add(video);
        db.SaveChanges();

        if (useAESRestriction)
        {
            token = AzureMediaAsset.GetTestToken(encodedAsset.Id, encodedAsset);
        }

        // Remove session
        Session.Remove("CurrentFile");

        // return success response
        return Json(new
        {
            error = false,
            message = "Congratulations! Video is uploaded and pipelined for encoding, check console log for after encoding playback details.",
            assetId = assetId,
            jobId = job.Id,
            locator = smoothStreamingUri,
            encrypted = useAESRestriction,
            token = token
        });

        //if (id == model.BlockCount){CommitAllChunks(model);}
        //return Json(new { error = false, isLastBlock = false, message = string.Empty, filename = fileName,filesize = videoStream.Length });
    }

Однако этот вид решения является жестким, а не длядолгосрочное решение, но концепция была там и в состоянии достичь моей целиЯ просто переделаю свой код и заново создам более гибкое решение.

ПРИМЕЧАНИЕ. Я не являюсь разработчиком на C #.Уважение к начинающему, как я.

...