public static int AddTask(Microsoft.Azure.WebJobs.ExecutionContext execContext, CloudMediaContext context, IJob job, IAsset sourceAsset, string value, string processor, string presetfilename, string stringtoreplace, ref int taskindex, int priority = 10, string specifiedStorageAccountName = null) { if (value != null) { // Get a media processor reference, and pass to it the name of the // processor to use for the specific task. IMediaProcessor mediaProcessor = MediaServicesHelper.GetLatestMediaProcessorByName(context, processor); string presetPath = Path.Combine(System.IO.Directory.GetParent(execContext.FunctionDirectory).FullName, "presets", presetfilename); string Configuration = File.ReadAllText(presetPath).Replace(stringtoreplace, value); // Create a task with the encoding details, using a string preset. var task = job.Tasks.AddNew(processor + " task", mediaProcessor, Configuration, TaskOptions.None); task.Priority = priority; // Specify the input asset to be indexed. task.InputAssets.Add(sourceAsset); // Add an output asset to contain the results of the job. // Use a non default storage account in case this was provided in 'AddTask' task.OutputAssets.AddNew(sourceAsset.Name + " " + processor + " Output", specifiedStorageAccountName, AssetCreationOptions.None); return(taskindex++); } else { return(-1); } }
public static IContentKey MakeContentKey(CloudMediaContext context, ContentKeyType contentKeyType, string contentKeyId = null, string contentKeySecret = null) { string contentKeyName; switch (contentKeyType) { case ContentKeyType.CommonEncryption: contentKeyName = "Common Encryption ContentKey"; return(MediaServicesHelper.CreateContentKey(context, contentKeyName, ContentKeyType.CommonEncryption, contentKeyId, contentKeySecret)); case ContentKeyType.CommonEncryptionCbcs: contentKeyName = "Common Encryption CBCS ContentKey"; return(MediaServicesHelper.CreateContentKey(context, contentKeyName, ContentKeyType.CommonEncryptionCbcs, contentKeyId, contentKeySecret)); case ContentKeyType.EnvelopeEncryption: contentKeyName = "Envelope Encryption ContentKey"; return(MediaServicesHelper.CreateContentKey(context, contentKeyName, ContentKeyType.EnvelopeEncryption, contentKeyId, contentKeySecret)); } throw new NotImplementedException(contentKeyType.ToString() + " is not supported"); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.ruCount == null && data.ruSpeed == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass ruCount and ruSpeed in the input object" })); } int targetNbRU = -1; int? nbunits = null; bool relative = false; string RUspeed = ""; ReservedUnitType?type = null; if (data.ruSpeed != null) { RUspeed = ((string)data.ruSpeed).ToUpper(); if (RUspeed == "S1") { type = ReservedUnitType.Basic; } else if (RUspeed == "S2") { type = ReservedUnitType.Standard; } else if (RUspeed == "S3") { type = ReservedUnitType.Premium; } else { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Error parsing ruSpeed" })); } } if (data.ruCount != null) { string RUcount = (string)data.ruCount; if (RUcount[0] == '+' || RUcount[0] == '-') { relative = true; try { nbunits = int.Parse(RUcount); } catch { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Error (1) parsing ruCount" })); } } else { try { nbunits = int.Parse(RUcount); } catch { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Error (2) parsing ruCount" })); } } } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } IEncodingReservedUnit EncResUnit = _context.EncodingReservedUnits.FirstOrDefault(); targetNbRU = EncResUnit.CurrentReservedUnits; ReservedUnitType targetType = EncResUnit.ReservedUnitType; log.Info("Current type of media RU: " + MediaServicesHelper.ReturnNewRUName(EncResUnit.ReservedUnitType)); log.Info("Current count of media RU: " + EncResUnit.CurrentReservedUnits); log.Info("Maximum reservable media RUs: " + EncResUnit.MaxReservableUnits); if (nbunits != null) { if (relative) { if (((int)nbunits) > 0) { log.Info($"Adding {nbunits} unit(s)"); } else { log.Info($"Removing {nbunits} unit(s)"); } targetNbRU = Math.Max(targetNbRU + (int)nbunits, 0); } else { log.Info($"Changing to {nbunits} unit(s)"); targetNbRU = (int)nbunits; } } if (type != null) { string sru = MediaServicesHelper.ReturnNewRUName((ReservedUnitType)type); log.Info($"Changing to {sru} speed"); targetType = (ReservedUnitType)type; } if (targetNbRU == 0 && targetType != ReservedUnitType.Basic) { targetType = ReservedUnitType.Basic; // 0 units so we switch to S1 } bool Error = false; try { EncResUnit.CurrentReservedUnits = targetNbRU; EncResUnit.ReservedUnitType = targetType; EncResUnit.Update(); EncResUnit = _context.EncodingReservedUnits.FirstOrDefault(); // Refresh } catch (Exception ex) { Error = true; } log.Info("Media RU unit(s) updated successfully."); log.Info("New current speed of media RU : " + MediaServicesHelper.ReturnNewRUName(EncResUnit.ReservedUnitType)); log.Info("New current count of media RU : " + EncResUnit.CurrentReservedUnits); return(req.CreateResponse(HttpStatusCode.OK, new { success = (!Error).ToString(), maxRu = EncResUnit.MaxReservableUnits, newRuCount = EncResUnit.CurrentReservedUnits, newRuSpeed = MediaServicesHelper.ReturnNewRUName(EncResUnit.ReservedUnitType) })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log, Microsoft.Azure.WebJobs.ExecutionContext execContext) { // Variables int taskindex = 0; int OutputMES = -1; int OutputPremium = -1; int OutputIndex1 = -1; int OutputIndex2 = -1; int OutputOCR = -1; int OutputFaceDetection = -1; int OutputFaceRedaction = -1; int OutputMotion = -1; int OutputSummarization = -1; int OutputHyperlapse = -1; int OutputMesThumbnails = -1; int OutputVideoAnnotation = -1; int OutputContentModeration = -1; int id = 0; string programid = ""; string programName = ""; string channelName = ""; string programUrl = ""; string programState = ""; string lastProgramState = ""; IJob job = null; ITask taskEncoding = null; int NumberJobsQueue = 0; int intervalsec = 60; // Interval for each subclip job (sec). Default is 60 TimeSpan starttime = TimeSpan.FromSeconds(0); TimeSpan duration = TimeSpan.FromSeconds(intervalsec); log.Info($"Webhook was triggered!"); string triggerStart = DateTime.UtcNow.ToString("o"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.channelName == null || data.programName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass channel name and program name in the input object (channelName, programName)" })); } if (data.intervalSec != null) { intervalsec = (int)data.intervalSec; } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // find the Channel, Program and Asset channelName = (string)data.channelName; var channel = _context.Channels.Where(c => c.Name == channelName).FirstOrDefault(); if (channel == null) { log.Info("Channel not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Channel not found" })); } programName = (string)data.programName; var program = channel.Programs.Where(p => p.Name == programName).FirstOrDefault(); if (program == null) { log.Info("Program not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Program not found" })); } programState = program.State.ToString(); programid = program.Id; var asset = ManifestHelpers.GetAssetFromProgram(_context, programid); if (asset == null) { log.Info($"Asset not found for program {programid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } log.Info($"Using asset Id : {asset.Id}"); // Table storage to store and real the last timestamp processed // Retrieve the storage account from the connection string. CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(amsCredentials.StorageAccountName, amsCredentials.StorageAccountKey), true); // Create the table client. CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); // Retrieve a reference to the table. CloudTable table = tableClient.GetTableReference("liveanalytics"); // Create the table if it doesn't exist. if (!table.CreateIfNotExists()) { log.Info($"Table {table.Name} already exists"); } else { log.Info($"Table {table.Name} created"); } var lastendtimeInTable = ManifestHelpers.RetrieveLastEndTime(table, programid); // Get the manifest data (timestamps) var assetmanifestdata = ManifestHelpers.GetManifestTimingData(_context, asset, log); log.Info("Timestamps: " + string.Join(",", assetmanifestdata.TimestampList.Select(n => n.ToString()).ToArray())); var livetime = TimeSpan.FromSeconds((double)assetmanifestdata.TimestampEndLastChunk / (double)assetmanifestdata.TimeScale); log.Info($"Livetime: {livetime}"); starttime = ManifestHelpers.ReturnTimeSpanOnGOP(assetmanifestdata, livetime.Subtract(TimeSpan.FromSeconds(intervalsec))); log.Info($"Value starttime : {starttime}"); if (lastendtimeInTable != null) { lastProgramState = lastendtimeInTable.ProgramState; log.Info($"Value ProgramState retrieved : {lastProgramState}"); var lastendtimeInTableValue = TimeSpan.Parse(lastendtimeInTable.LastEndTime); log.Info($"Value lastendtimeInTable retrieved : {lastendtimeInTableValue}"); id = int.Parse(lastendtimeInTable.Id); log.Info($"Value id retrieved : {id}"); if (lastendtimeInTableValue != null) { var delta = (livetime - lastendtimeInTableValue - TimeSpan.FromSeconds(intervalsec)).Duration(); log.Info($"Delta: {delta}"); //if (delta < (new TimeSpan(0, 0, 3*intervalsec))) // less than 3 times the normal duration (3*60s) if (delta < (TimeSpan.FromSeconds(3 * intervalsec))) // less than 3 times the normal duration (3*60s) { starttime = lastendtimeInTableValue; log.Info($"Value new starttime : {starttime}"); } } } duration = livetime - starttime; log.Info($"Value duration: {duration}"); // D:\home\site\wwwroot\Presets\LiveSubclip.json string ConfigurationSubclip = File.ReadAllText(Path.Combine(System.IO.Directory.GetParent(execContext.FunctionDirectory).FullName, "presets", "LiveSubclip.json")).Replace("0:00:00.000000", starttime.Subtract(TimeSpan.FromMilliseconds(100)).ToString()).Replace("0:00:30.000000", duration.Add(TimeSpan.FromMilliseconds(200)).ToString()); int priority = 10; if (data.priority != null) { priority = (int)data.priority; } // MES Subclipping TASK // Declare a new encoding job with the Standard encoder job = _context.Jobs.Create("Azure Function - Job for Live Analytics - " + programName, priority); // Get a media processor reference, and pass to it the name of the // processor to use for the specific task. IMediaProcessor processor = MediaServicesHelper.GetLatestMediaProcessorByName(_context, "Media Encoder Standard"); // Change or modify the custom preset JSON used here. // string preset = File.ReadAllText("D:\home\site\wwwroot\Presets\H264 Multiple Bitrate 720p.json"); // Create a task with the encoding details, using a string preset. // In this case "H264 Multiple Bitrate 720p" system defined preset is used. taskEncoding = job.Tasks.AddNew("Subclipping task", processor, ConfigurationSubclip, TaskOptions.None); // Specify the input asset to be encoded. taskEncoding.InputAssets.Add(asset); OutputMES = taskindex++; // Add an output asset to contain the results of the job. // This output is specified as AssetCreationOptions.None, which // means the output asset is not encrypted. var subclipasset = taskEncoding.OutputAssets.AddNew(asset.Name + " subclipped " + triggerStart, JobHelpers.OutputStorageFromParam(data.mesSubclip), AssetCreationOptions.None); log.Info($"Adding media analytics tasks"); /* * // Media Analytics * OutputIndex1 = JobHelpers.AddTask(job, subclipasset, (string)data.indexV1Language, "Azure Media Indexer", "IndexerV1.xml", "English", ref taskindex); * OutputIndex2 = JobHelpers.AddTask(job, subclipasset, (string)data.indexV2Language, "Azure Media Indexer 2 Preview", "IndexerV2.json", "EnUs", ref taskindex); * OutputOCR = JobHelpers.AddTask(job, subclipasset, (string)data.ocrLanguage, "Azure Media OCR", "OCR.json", "AutoDetect", ref taskindex); * OutputFaceDetection = JobHelpers.AddTask(job, subclipasset, (string)data.faceDetectionMode, "Azure Media Face Detector", "FaceDetection.json", "PerFaceEmotion", ref taskindex); * OutputFaceRedaction = JobHelpers.AddTask(job, subclipasset, (string)data.faceRedactionMode, "Azure Media Redactor", "FaceRedaction.json", "combined", ref taskindex, priority - 1); * OutputMotion = JobHelpers.AddTask(job, subclipasset, (string)data.motionDetectionLevel, "Azure Media Motion Detector", "MotionDetection.json", "medium", ref taskindex, priority - 1); * OutputSummarization = JobHelpers.AddTask(job, subclipasset, (string)data.summarizationDuration, "Azure Media Video Thumbnails", "Summarization.json", "0.0", ref taskindex); * OutputHyperlapse = JobHelpers.AddTask(job, subclipasset, (string)data.hyperlapseSpeed, "Azure Media Hyperlapse", "Hyperlapse.json", "8", ref taskindex); * OutputMesThumbnails = JobHelpers.AddTask(job, subclipasset, (string)data.mesThumbnailsStart, "Media Encoder Standard", "MesThumbnails.json", "{Best}", ref taskindex); */ //new OutputIndex1 = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.indexV1 == null) ? (string)data.indexV1Language : ((string)data.indexV1.language ?? "English"), "Azure Media Indexer", "IndexerV1.xml", "English", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.indexV1)); OutputIndex2 = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.indexV2 == null) ? (string)data.indexV2Language : ((string)data.indexV2.language ?? "EnUs"), "Azure Media Indexer 2 Preview", "IndexerV2.json", "EnUs", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.indexV2)); OutputOCR = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.ocr == null) ? (string)data.ocrLanguage : ((string)data.ocr.language ?? "AutoDetect"), "Azure Media OCR", "OCR.json", "AutoDetect", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.ocr)); OutputFaceDetection = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.faceDetection == null) ? (string)data.faceDetectionMode : ((string)data.faceDetection.mode ?? "PerFaceEmotion"), "Azure Media Face Detector", "FaceDetection.json", "PerFaceEmotion", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.faceDetection)); OutputFaceRedaction = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.faceRedaction == null) ? (string)data.faceRedactionMode : ((string)data.faceRedaction.mode ?? "comined"), "Azure Media Redactor", "FaceRedaction.json", "combined", ref taskindex, priority - 1, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.faceRedaction)); OutputMotion = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.motionDetection == null) ? (string)data.motionDetectionLevel : ((string)data.motionDetection.level ?? "medium"), "Azure Media Motion Detector", "MotionDetection.json", "medium", ref taskindex, priority - 1, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.motionDetection)); OutputSummarization = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.summarization == null) ? (string)data.summarizationDuration : ((string)data.summarization.duration ?? "0.0"), "Azure Media Video Thumbnails", "Summarization.json", "0.0", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.summarization)); OutputVideoAnnotation = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.videoAnnotation != null) ? "1.0" : null, "Azure Media Video Annotator", "VideoAnnotation.json", "1.0", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.videoAnnotation)); OutputContentModeration = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.contentModeration != null) ? "2.0" : null, "Azure Media Content Moderator", "ContentModeration.json", "2.0", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.contentModeration)); // MES Thumbnails OutputMesThumbnails = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.mesThumbnails != null) ? ((string)data.mesThumbnails.Start ?? "{Best}") : null, "Media Encoder Standard", "MesThumbnails.json", "{Best}", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.mesThumbnails)); // Hyperlapse OutputHyperlapse = JobHelpers.AddTask(execContext, _context, job, subclipasset, (data.hyperlapse == null) ? (string)data.hyperlapseSpeed : ((string)data.hyperlapse.speed ?? "8"), "Azure Media Hyperlapse", "Hyperlapse.json", "8", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.hyperlapse)); job.Submit(); log.Info("Job Submitted"); id++; ManifestHelpers.UpdateLastEndTime(table, starttime + duration, programid, id, program.State); log.Info($"Output MES index {OutputMES}"); // Let store some data in altid of subclipped asset var sid = JobHelpers.ReturnId(job, OutputMES); log.Info($"SID {sid}"); var subclipassetrefreshed = _context.Assets.Where(a => a.Id == sid).FirstOrDefault(); log.Info($"subclipassetrefreshed ID {subclipassetrefreshed.Id}"); subclipassetrefreshed.AlternateId = JsonConvert.SerializeObject(new ManifestHelpers.SubclipInfo() { programId = programid, subclipStart = starttime, subclipDuration = duration }); subclipassetrefreshed.Update(); // Let store some data in altid of index assets var index1sid = JobHelpers.ReturnId(job, OutputIndex1); if (index1sid != null) { var index1assetrefreshed = _context.Assets.Where(a => a.Id == index1sid).FirstOrDefault(); log.Info($"index1assetrefreshed ID {index1assetrefreshed.Id}"); index1assetrefreshed.AlternateId = JsonConvert.SerializeObject(new ManifestHelpers.SubclipInfo() { programId = programid, subclipStart = starttime, subclipDuration = duration }); index1assetrefreshed.Update(); } var index2sid = JobHelpers.ReturnId(job, OutputIndex2); if (index2sid != null) { var index2assetrefreshed = _context.Assets.Where(a => a.Id == index2sid).FirstOrDefault(); log.Info($"index2assetrefreshed ID {index2assetrefreshed.Id}"); index2assetrefreshed.AlternateId = JsonConvert.SerializeObject(new ManifestHelpers.SubclipInfo() { programId = programid, subclipStart = starttime, subclipDuration = duration }); index2assetrefreshed.Update(); } // Get program URL var publishurlsmooth = MediaServicesHelper.GetValidOnDemandURI(_context, asset); if (publishurlsmooth != null) { programUrl = publishurlsmooth.ToString(); } NumberJobsQueue = _context.Jobs.Where(j => j.State == JobState.Queued).Count(); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info("Job Id: " + job.Id); log.Info("Output asset Id: " + ((OutputMES > -1) ? JobHelpers.ReturnId(job, OutputMES) : JobHelpers.ReturnId(job, OutputPremium))); return(req.CreateResponse(HttpStatusCode.OK, new { triggerStart = triggerStart, jobId = job.Id, subclip = new { assetId = JobHelpers.ReturnId(job, OutputMES), taskId = JobHelpers.ReturnTaskId(job, OutputMES), start = starttime, duration = duration, }, mesThumbnails = new { assetId = JobHelpers.ReturnId(job, OutputMesThumbnails), taskId = JobHelpers.ReturnTaskId(job, OutputMesThumbnails) }, indexV1 = new { assetId = JobHelpers.ReturnId(job, OutputIndex1), taskId = JobHelpers.ReturnTaskId(job, OutputIndex1), language = (string)data.indexV1Language }, indexV2 = new { assetId = JobHelpers.ReturnId(job, OutputIndex2), taskId = JobHelpers.ReturnTaskId(job, OutputIndex2), language = (string)data.indexV2Language, }, ocr = new { assetId = JobHelpers.ReturnId(job, OutputOCR), taskId = JobHelpers.ReturnTaskId(job, OutputOCR) }, faceDetection = new { assetId = JobHelpers.ReturnId(job, OutputFaceDetection), taskId = JobHelpers.ReturnTaskId(job, OutputFaceDetection) }, faceRedaction = new { assetId = JobHelpers.ReturnId(job, OutputFaceRedaction), taskId = JobHelpers.ReturnTaskId(job, OutputFaceRedaction) }, motionDetection = new { assetId = JobHelpers.ReturnId(job, OutputMotion), taskId = JobHelpers.ReturnTaskId(job, OutputMotion) }, summarization = new { assetId = JobHelpers.ReturnId(job, OutputSummarization), taskId = JobHelpers.ReturnTaskId(job, OutputSummarization) }, hyperlapse = new { assetId = JobHelpers.ReturnId(job, OutputHyperlapse), taskId = JobHelpers.ReturnTaskId(job, OutputHyperlapse) }, videoAnnotation = new { assetId = JobHelpers.ReturnId(job, OutputVideoAnnotation), taskId = JobHelpers.ReturnTaskId(job, OutputVideoAnnotation) }, contentModeration = new { assetId = JobHelpers.ReturnId(job, OutputContentModeration), taskId = JobHelpers.ReturnTaskId(job, OutputContentModeration) }, channelName = channelName, programName = programName, programId = programid, programUrl = programUrl, programState = programState, programStateChanged = (lastProgramState != programState).ToString(), otherJobsQueue = NumberJobsQueue })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.assetId == null) { // for test // data.assetId = "nb:cid:UUID:c0d770b4-1a69-43c4-a4e6-bc60d20ab0b2"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (assetId)" })); } string playerUrl = ""; string smoothUrl = ""; string pathUrl = ""; string preferredSE = data.preferredSE; string serveType = data.serveType; MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the asset string assetid = data.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } // publish with a streaming locator (100 years) log.Info(serveType); if (serveType == "OnDemandOrigin") { IAccessPolicy readPolicy2 = _context.AccessPolicies.Create("readPolicy", TimeSpan.FromDays(365 * 100), AccessPermissions.Read); ILocator outputLocator2 = _context.Locators.CreateLocator(LocatorType.OnDemandOrigin, outputAsset, readPolicy2); var publishurlsmooth = MediaServicesHelper.GetValidOnDemandURI(_context, outputAsset, preferredSE); var publishurlpath = MediaServicesHelper.GetValidOnDemandPath(_context, outputAsset, preferredSE); if (outputLocator2 != null && publishurlsmooth != null) { smoothUrl = publishurlsmooth.ToString(); playerUrl = "https://ampdemo.azureedge.net/?url=" + HttpUtility.UrlEncode(smoothUrl); log.Info($"smooth url : {smoothUrl}"); } if (outputLocator2 != null && publishurlpath != null) { pathUrl = publishurlpath.ToString(); log.Info($"path url : {pathUrl}"); } } if (serveType == "sas") { IAccessPolicy readPolicy1 = _context.AccessPolicies.Create("readPolicy", TimeSpan.FromDays(365 * 100), AccessPermissions.Read); ILocator outputLocator1 = _context.Locators.CreateLocator(LocatorType.Sas, outputAsset, readPolicy1); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK, new { playerUrl = playerUrl, smoothUrl = smoothUrl, pathUrl = pathUrl })); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"AMS v2 Function - Add Authorization Policy was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(jsonContent)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass a JSON request body" })); } AuthorizationPolicyRequst data = JsonConvert.DeserializeObject <AuthorizationPolicyRequst>(jsonContent); // Validate input objects if (string.IsNullOrEmpty(data.b64Secret)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass a base 64 symetric secret" })); } if (string.IsNullOrEmpty(data.tokenType)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass the token type (SWT or JWT)" })); } if (string.IsNullOrEmpty(data.audience)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass the audience value" })); } if (string.IsNullOrEmpty(data.issuer)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass the issuer value" })); } if (data.config == null || data.config.Length < 1) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass the authorization option configuration" })); } IContentKeyAuthorizationPolicy result; try { result = GetTokenRestrictedAuthorizationPolicy(log, data); log.Info($"Out of auth policy code"); if (result != null) { log.Info($"Made auth policy"); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : "") + "\n" + ex.StackTrace; log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { authPolicyId = result.Id, })); }
public static string GetHexIV() { byte[] output = MediaServicesHelper.GetRandomBuffer(16); return(BitConverter.ToString(output).Replace("-", string.Empty)); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { { log.Info($"Webhook was triggered!"); // Init variables string vttUrl = ""; string pathUrl = ""; string ttmlUrl = ""; string vttContent = ""; string ttmlContent = ""; string ttmlContentTimeCorrected = ""; string vttContentTimeCorrected = ""; string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.assetId == null) { // for test // data.assetId = "nb:cid:UUID:d9496372-32f5-430d-a4c6-d21ec3e01525"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (AssetId)" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the asset string assetid = data.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var vttSubtitle = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".VTT")).FirstOrDefault(); var ttmlSubtitle = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".TTML")).FirstOrDefault(); Uri publishurl = MediaServicesHelper.GetValidOnDemandPath(_context, outputAsset); if (publishurl != null) { pathUrl = publishurl.ToString(); } else { log.Info($"Asset not published"); } if (vttSubtitle != null) { if (publishurl != null) { vttUrl = pathUrl + vttSubtitle.Name; log.Info($"vtt url : {vttUrl}"); } vttContent = MediaServicesHelper.ReturnContent(vttSubtitle); if (data.timeOffset != null) // let's update the ttml with new timecode { var tsoffset = TimeSpan.Parse((string)data.timeOffset); string arrow = " --> "; StringBuilder sb = new StringBuilder(); string[] delim = { Environment.NewLine, "\n" }; // "\n" added in case you manually appended a newline string[] vttlines = vttContent.Split(delim, StringSplitOptions.None); foreach (string vttline in vttlines) { string line = vttline; if (vttline.Contains(arrow)) { TimeSpan begin = TimeSpan.Parse(vttline.Substring(0, vttline.IndexOf(arrow))); TimeSpan end = TimeSpan.Parse(vttline.Substring(vttline.IndexOf(arrow) + 5)); line = (begin + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff") + arrow + (end + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff"); } sb.AppendLine(line); } vttContentTimeCorrected = sb.ToString(); } } if (ttmlSubtitle != null) { if (publishurl != null) { ttmlUrl = pathUrl + vttSubtitle.Name; log.Info($"ttml url : {ttmlUrl}"); } ttmlContent = MediaServicesHelper.ReturnContent(ttmlSubtitle); if (data.timeOffset != null) // let's update the vtt with new timecode { var tsoffset = TimeSpan.Parse((string)data.timeOffset); log.Info("tsoffset : " + tsoffset.ToString(@"d\.hh\:mm\:ss\.fff")); XNamespace xmlns = "http://www.w3.org/ns/ttml"; XDocument docXML = XDocument.Parse(ttmlContent); var tt = docXML.Element(xmlns + "tt"); var subtitles = docXML.Element(xmlns + "tt").Element(xmlns + "body").Element(xmlns + "div").Elements(xmlns + "p"); foreach (var sub in subtitles) { var begin = TimeSpan.Parse((string)sub.Attribute("begin")); var end = TimeSpan.Parse((string)sub.Attribute("end")); sub.SetAttributeValue("end", (end + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff")); sub.SetAttributeValue("begin", (begin + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff")); } ttmlContentTimeCorrected = docXML.Declaration.ToString() + Environment.NewLine + docXML.ToString(); } } if (ttmlContent != "" && vttContent != "" && data.deleteAsset != null && ((bool)data.deleteAsset)) // If asset deletion was asked { outputAsset.Delete(); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK, new { vttUrl = vttUrl, ttmlUrl = ttmlUrl, pathUrl = pathUrl, ttmlDocument = ttmlContent, ttmlDocumentWithOffset = ttmlContentTimeCorrected, vttDocument = vttContent, vttDocumentWithOffset = vttContentTimeCorrected })); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info("Request : " + jsonContent); // Validate input objects int delay = 5000; if (data.targetStorageAccountName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass targetStorageAccountName in the input object" })); } if (data.targetStorageAccountKey == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass targetStorageAccountKey in the input object" })); } if (data.targetContainer == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass targetContainer in the input object" })); } if (data.delay != null) { delay = data.delay; } log.Info("Input - DestinationContainer : " + data.targetContainer); //log.Info("delay : " + delay); log.Info($"Wait " + delay + "(ms)"); System.Threading.Thread.Sleep(delay); string targetStorageAccountName = data.targetStorageAccountName; string targetStorageAccountKey = data.targetStorageAccountKey; string targetContainer = data.targetContainer; CopyStatus copyStatus = CopyStatus.Success; try { CloudBlobContainer destinationBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(targetStorageAccountName, targetStorageAccountKey, targetContainer); string blobPrefix = null; if (!string.IsNullOrWhiteSpace((string)data.fileNamePrefix)) { blobPrefix = (string)data.fileNamePrefix; log.Info($"{blobPrefix}"); } bool useFlatBlobListing = true; var destBlobList = destinationBlobContainer.ListBlobs(blobPrefix, useFlatBlobListing, BlobListingDetails.Copy); foreach (var dest in destBlobList) { var destBlob = dest as CloudBlob; if (destBlob.CopyState.Status == CopyStatus.Aborted || destBlob.CopyState.Status == CopyStatus.Failed) { // Log the copy status description for diagnostics and restart copy destBlob.StartCopyAsync(destBlob.CopyState.Source); copyStatus = CopyStatus.Pending; } else if (destBlob.CopyState.Status == CopyStatus.Pending) { // We need to continue waiting for this pending copy // However, let us log copy state for diagnostics copyStatus = CopyStatus.Pending; } // else we completed this pending copy } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { copyStatus = copyStatus, isRunning = (copyStatus == CopyStatus.Pending).ToString(), isSuccessful = (copyStatus == CopyStatus.Success).ToString() })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info("Request : " + jsonContent); MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); // Validate input objects if (data.assetId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetId in the input object" })); } string startsWith = data.startsWith; string endsWith = data.endsWith; string assetId = data.assetId; IAsset asset = null; try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Find the Asset asset = _context.Assets.Where(a => a.Id == assetId).FirstOrDefault(); if (asset == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var files = asset.AssetFiles.ToList().Where(f => ((string.IsNullOrEmpty(endsWith) || f.Name.EndsWith(endsWith)) && (string.IsNullOrEmpty(startsWith) || f.Name.StartsWith(startsWith)))); foreach (var file in files) { file.Delete(); log.Info($"Deleted file: {file.Name}"); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK)); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"AMS v2 Function - Add Dynamic Encryption was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); // Validate input objects if (data.assetId == null && data.programId == null && data.channelName == null && data.programName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetId or programID or channelName/programName in the input object" })); } if (data.contentKeyAuthorizationPolicyId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass contentKeyAuthorizationPolicyId in the input object" })); } if (data.assetDeliveryPolicyId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetDeliveryPolicyId in the input object" })); } if (data.contentKeyType == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass contentKeyType in the input object" })); } string assetId = data.assetId; string programId = data.programId; string channelName = data.channelName; string programName = data.programName; string contentKeyAuthorizationPolicyId = data.contentKeyAuthorizationPolicyId; string assetDeliveryPolicyId = data.assetDeliveryPolicyId; string contentKeyTypeName = data.contentKeyType; string contentKeyId = data.keyId; string contentKeySecret = data.contentKey; if (!MediaServicesHelper.AMSContentKeyType.ContainsKey(contentKeyTypeName)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass a valid contentKeyType in the input object" })); } ContentKeyType contentKeyType = MediaServicesHelper.AMSContentKeyType[contentKeyTypeName]; if (contentKeyType != ContentKeyType.CommonEncryption && contentKeyType != ContentKeyType.CommonEncryptionCbcs && contentKeyType != ContentKeyType.EnvelopeEncryption) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass a valid contentKeyType in the input object" })); } string contentKeyName = null; if (data.contentKeyName != null) { contentKeyName = data.contentKeyName; } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); IAsset asset = null; IContentKeyAuthorizationPolicy ckaPolicy = null; IAssetDeliveryPolicy adPolicy = null; IContentKey contentKey = null; try { // Load AMS account context log.Info($"Using AMS v2 REST API Endpoint : {amsCredentials.AmsRestApiEndpoint.ToString()}"); AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Let's get the asset if (assetId != null) { // Get the Asset, ContentKeyAuthorizationPolicy, AssetDeliveryPolicy asset = _context.Assets.Where(a => a.Id == assetId).FirstOrDefault(); if (asset == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } } else if (programId != null) { var program = _context.Programs.Where(p => p.Id == programId).FirstOrDefault(); if (program == null) { log.Info("Program not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Program not found" })); } asset = program.Asset; } else // with channelName and programName { // find the Channel, Program and Asset var channel = _context.Channels.Where(c => c.Name == channelName).FirstOrDefault(); if (channel == null) { log.Info("Channel not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Channel not found" })); } var program = channel.Programs.Where(p => p.Name == programName).FirstOrDefault(); if (program == null) { log.Info("Program not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Program not found" })); } asset = program.Asset; } log.Info($"Using asset Id : {asset.Id}"); ckaPolicy = _context.ContentKeyAuthorizationPolicies.Where(p => p.Id == contentKeyAuthorizationPolicyId).Single(); if (ckaPolicy == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "ContentKeyAuthorizationPolicy not found" })); } adPolicy = _context.AssetDeliveryPolicies.Where(p => p.Id == assetDeliveryPolicyId).Single(); if (adPolicy == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "AssetDeliveryPolicy not found" })); } if (contentKeyId != null) { string keyiddwitprefix = ""; if (contentKeyId.StartsWith("nb:kid:UUID:")) { keyiddwitprefix = contentKeyId; contentKeyId = contentKeyId.Substring(12); } else { keyiddwitprefix = "nb:kid:UUID:" + contentKeyId; } // let's retrieve the key if it exists already contentKey = _context.ContentKeys.Where(k => k.Id == keyiddwitprefix).FirstOrDefault(); } if (contentKey == null) // let's create it as it was not found or delivered to the function { switch (contentKeyType) { case ContentKeyType.CommonEncryption: if (contentKeyName == null) { contentKeyName = "Common Encryption ContentKey"; } contentKey = MediaServicesHelper.CreateContentKey(_context, contentKeyName, ContentKeyType.CommonEncryption, contentKeyId, contentKeySecret); break; case ContentKeyType.CommonEncryptionCbcs: if (contentKeyName == null) { contentKeyName = "Common Encryption CBCS ContentKey"; } contentKey = MediaServicesHelper.CreateContentKey(_context, contentKeyName, ContentKeyType.CommonEncryptionCbcs, contentKeyId, contentKeySecret); break; case ContentKeyType.EnvelopeEncryption: if (contentKeyName == null) { contentKeyName = "Envelope Encryption ContentKey"; } contentKey = MediaServicesHelper.CreateContentKey(_context, contentKeyName, ContentKeyType.EnvelopeEncryption, contentKeyId, contentKeySecret); break; } } asset.ContentKeys.Add(contentKey); contentKey.AuthorizationPolicyId = ckaPolicy.Id; contentKey = contentKey.UpdateAsync().Result; asset.DeliveryPolicies.Add(adPolicy); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { contentKeyId = contentKey.Id, assetId = asset.Id })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); if (data.assetId == null) { // for test // data.Path = "/input/WP_20121015_081924Z.mp4"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetId in the input object" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Step 1: Copy the Blob into a new Input Asset for the Job // ***NOTE: Ideally we would have a method to ingest a Blob directly here somehow. // using code from this sample - https://azure.microsoft.com/en-us/documentation/articles/media-services-copying-existing-blob/ // Get the asset string assetid = data.assetId; var asset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (asset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } log.Info("Asset found, ID: " + asset.Id); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (asset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(asset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = asset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"Face redaction Asset is in {asset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } CloudBlobContainer assetContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, asset.Uri.Segments[1]); foreach (String seg in asset.Uri.Segments) { log.Info($"> asset.Uri.Segments :" + seg); } /*IEnumerable<CloudBlobContainer> containers = blobClient.ListContainers(); * foreach (CloudBlobContainer item in containers) * { * foreach (IListBlobItem blob in item.ListBlobs()) * { * blobs.Add(string.Format("{0}", blob.Uri.Segments[2])); * } * } */ /* * //Get a reference to the storage account that is associated with the Media Services account. * StorageCredentials mediaServicesStorageCredentials = * new StorageCredentials(_storageAccountName, _storageAccountKey); * var _destinationStorageAccount = new CloudStorageAccount(mediaServicesStorageCredentials, false); * * CloudBlobClient destBlobStorage = _destinationStorageAccount.CreateCloudBlobClient(); * * // Get the destination asset container reference * string destinationContainerName = asset.Uri.Segments[1]; * log.Info($"destinationContainerName : {destinationContainerName}"); * * CloudBlobContainer assetContainer = destBlobStorage.GetContainerReference(destinationContainerName); */ log.Info($"assetContainer retrieved"); // Get hold of the destination blobs var blobsPseudo = assetContainer.ListBlobs(); log.Info($"blobsPseudo retrieved"); log.Info($"blobsPseudo count : {blobsPseudo.Count()}"); var aflist = asset.AssetFiles.ToList().Select(af => af.Name); /* OLD WAY * foreach (CloudBlockBlob blob in blobs) * { * if (aflist.Contains(blob.Name)) * { * var assetFile = asset.AssetFiles.Where(af => af.Name == blob.Name).FirstOrDefault(); * assetFile.ContentFileSize = blob.Properties.Length; * assetFile.Update(); * log.Info($"Asset file updated : {assetFile.Name}"); * } * else * { * var assetFile = asset.AssetFiles.Create(blob.Name); * assetFile.ContentFileSize = blob.Properties.Length; * assetFile.Update(); * log.Info($"Asset file created : {assetFile.Name}"); * } * } */ log.Info($"Witness 3 "); //Adding mecanic to list all sub dir (original just lists elements in given folder and consider them as blob even if they are subdirs) //var folders = blobs.Where(b => b as CloudBlobDirectory != null).ToList(); //this is supposedly a 2 levels scenario... might not suits our case yet (one more level?) foreach (IListBlobItem blobItem in blobsPseudo) { log.Info($"blobItem found : "); if (blobItem is CloudBlobDirectory) { CloudBlobDirectory directory = (CloudBlobDirectory)blobItem; IEnumerable <IListBlobItem> blobs = directory.ListBlobs(); //ICloudBlob bi; foreach (var item in blobs) { log.Info($"item StorageUri : " + item.StorageUri); CloudBlockBlob blob = (CloudBlockBlob)item; blob.FetchAttributes(); log.Info($"Blob found uri : " + blob.Uri); log.Info($"Blob found Name : " + blob.Name); String potentialName = Path.GetFileName(blob.Name); log.Info($"Blob potentialName : " + potentialName); String normalizedName = potentialName; if (aflist.Contains(normalizedName)) { log.Info($" aflist.Contains Blob found Name : " + normalizedName); var assetFile = asset.AssetFiles.Where(af => af.Name == normalizedName).FirstOrDefault(); assetFile.ContentFileSize = blob.Properties.Length; assetFile.Update(); log.Info($"Asset file updated : {normalizedName}"); } else { log.Info($"Create Blob found Name : " + normalizedName); var assetFile = asset.AssetFiles.Create(normalizedName); assetFile.ContentFileSize = blob.Properties.Length; assetFile.Update(); log.Info($"Asset file created : {normalizedName}"); } } } else { //TODO redefine ! CloudBlockBlob blob = (CloudBlockBlob)blobItem; blob.FetchAttributes(); log.Info($"Blob2 found uri : " + blob.Uri); log.Info($"Blob2 found Name : " + blob.Name); if (aflist.Contains(blob.Name)) { var assetFile = asset.AssetFiles.Where(af => af.Name == blob.Name).FirstOrDefault(); assetFile.ContentFileSize = blob.Properties.Length; assetFile.Update(); log.Info($"Asset2 file updated : {assetFile.Name}"); } else { var assetFile = asset.AssetFiles.Create(blob.Name); assetFile.ContentFileSize = blob.Properties.Length; assetFile.Update(); log.Info($"Asset2 file created : {assetFile.Name}"); } } } asset.Update(); MediaServicesHelper.SetAFileAsPrimary(asset); log.Info("Asset updated"); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK)); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.jobId == null && data.assetId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass job Id and/or asset Id of the objects to delete" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); } catch (Exception ex) { log.Info($"Exception {ex}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { Error = ex.ToString() })); } try { if (data.jobId != null) { var jobids = (string)data.jobId; foreach (string jobi in jobids.Split(',')) { log.Info($"Using job Id : {jobi}"); var job = _context.Jobs.Where(j => j.Id == jobi).FirstOrDefault(); if (job != null) { job.Delete(); log.Info("Job deleted."); } else { log.Info("Job not found!"); } } } if (data.assetId != null) { var assetids = (string)data.assetId; foreach (string asseti in assetids.Split(',')) { log.Info($"Using asset Id : {asseti}"); var asset = _context.Assets.Where(a => a.Id == asseti).FirstOrDefault(); if (asset != null) { asset.Delete(); log.Info("Asset deleted."); } else { log.Info("Asset not found!"); } } } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); if (data.assetId == null) { // for test // data.Path = "/input/WP_20121015_081924Z.mp4"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetId in the input object" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Step 1: Copy the Blob into a new Input Asset for the Job // ***NOTE: Ideally we would have a method to ingest a Blob directly here somehow. // using code from this sample - https://azure.microsoft.com/en-us/documentation/articles/media-services-copying-existing-blob/ // Get the asset string assetid = data.assetId; var asset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (asset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } log.Info("Asset found, ID: " + asset.Id); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (asset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(asset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = asset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"Face redaction Asset is in {asset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } CloudBlobContainer assetContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, asset.Uri.Segments[1]); /* * //Get a reference to the storage account that is associated with the Media Services account. * StorageCredentials mediaServicesStorageCredentials = * new StorageCredentials(_storageAccountName, _storageAccountKey); * var _destinationStorageAccount = new CloudStorageAccount(mediaServicesStorageCredentials, false); * * CloudBlobClient destBlobStorage = _destinationStorageAccount.CreateCloudBlobClient(); * * // Get the destination asset container reference * string destinationContainerName = asset.Uri.Segments[1]; * log.Info($"destinationContainerName : {destinationContainerName}"); * * CloudBlobContainer assetContainer = destBlobStorage.GetContainerReference(destinationContainerName); */ log.Info($"assetContainer retrieved"); // Get hold of the destination blobs var blobs = assetContainer.ListBlobs(); log.Info($"blobs retrieved"); log.Info($"blobs count : {blobs.Count()}"); var aflist = asset.AssetFiles.ToList().Select(af => af.Name); foreach (CloudBlockBlob blob in blobs) { if (aflist.Contains(blob.Name)) { var assetFile = asset.AssetFiles.Where(af => af.Name == blob.Name).FirstOrDefault(); assetFile.ContentFileSize = blob.Properties.Length; assetFile.Update(); log.Info($"Asset file updated : {assetFile.Name}"); } else { var assetFile = asset.AssetFiles.Create(blob.Name); assetFile.ContentFileSize = blob.Properties.Length; assetFile.Update(); log.Info($"Asset file created : {assetFile.Name}"); } } asset.Update(); MediaServicesHelper.SetAFileAsPrimary(asset); log.Info("Asset updated"); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK)); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log, Microsoft.Azure.WebJobs.ExecutionContext execContext) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); string startsWith = data.startsWith; string endsWith = data.endsWith; IAsset asset = null; if (data.assetId == null) { // for test // data.assetId = "nb:cid:UUID:c0d770b4-1a69-43c4-a4e6-bc60d20ab0b2"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (assetId)" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the asset string assetid = data.assetId; asset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (asset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } // set alternate id if (data.alternateId != null) { asset.AlternateId = (string)data.alternateId; asset.Update(); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK, new { })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info("Request : " + jsonContent); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); // Validate input objects if (data.assetId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetId in the input object" })); } if (data.fileName == null && data.fileNames == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass fileName or fileNames in the input object" })); } if (data.sourceStorageAccountName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass sourceStorageAccountName in the input object" })); } if (data.sourceStorageAccountKey == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass sourceStorageAccountKey in the input object" })); } if (data.sourceContainer == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass sourceContainer in the input object" })); } log.Info("Input - sourceStorageAccountName : " + data.sourceStorageAccountName); log.Info("Input - sourceStorageAccountKey : " + data.sourceStorageAccountKey); log.Info("Input - sourceContainer : " + data.sourceContainer); string _sourceStorageAccountName = data.sourceStorageAccountName; string _sourceStorageAccountKey = data.sourceStorageAccountKey; string assetId = data.assetId; bool missingBlob = false; IAsset newAsset = null; IIngestManifest manifest = null; MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Find the Asset newAsset = _context.Assets.Where(a => a.Id == assetId).FirstOrDefault(); if (newAsset == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } // Setup blob container CloudBlobContainer sourceBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(_sourceStorageAccountName, _sourceStorageAccountKey, (string)data.sourceContainer); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (newAsset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(newAsset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = newAsset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"Face redaction Asset is in {newAsset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } CloudBlobContainer destinationBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, newAsset.Uri.Segments[1]); sourceBlobContainer.CreateIfNotExists(); if (data.fileName != null) { string fileName = (string)data.fileName; CloudBlob sourceBlob = sourceBlobContainer.GetBlockBlobReference(fileName); if (data.wait != null && (bool)data.wait) { for (int i = 1; i <= 3; i++) // let's wait 3 times 5 seconds (15 seconds) { if (sourceBlob.Exists()) { break; } log.Info("Waiting 5 s..."); System.Threading.Thread.Sleep(5 * 1000); sourceBlob = sourceBlobContainer.GetBlockBlobReference(fileName); } } if (sourceBlob.Exists()) { CloudBlob destinationBlob = destinationBlobContainer.GetBlockBlobReference(fileName); if (destinationBlobContainer.CreateIfNotExists()) { log.Info("container created"); destinationBlobContainer.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }); } CopyBlobHelpers.CopyBlobAsync(sourceBlob, destinationBlob); } else { missingBlob = true; } } if (data.fileNames != null) { foreach (var file in data.fileNames) { string fileName = (string)file; CloudBlob sourceBlob = sourceBlobContainer.GetBlockBlobReference(fileName); if (sourceBlob.Exists()) { CloudBlob destinationBlob = destinationBlobContainer.GetBlockBlobReference(fileName); if (destinationBlobContainer.CreateIfNotExists()) { log.Info("container created"); destinationBlobContainer.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }); } CopyBlobHelpers.CopyBlobAsync(sourceBlob, destinationBlob); } else { missingBlob = true; } } } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { destinationContainer = newAsset.Uri.Segments[1], missingBlob = missingBlob.ToString() })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); // Init variables string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.assetId == null) { // for test // data.assetId = "nb:cid:UUID:d9496372-32f5-430d-a4c6-d21ec3e01525"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (assetId)" })); } if (data.document == null) { // for test // data.assetId = "nb:cid:UUID:d9496372-32f5-430d-a4c6-d21ec3e01525"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass document data in the input object (document)" })); } if (data.fileName == null) { // for test // data.assetId = "nb:cid:UUID:d9496372-32f5-430d-a4c6-d21ec3e01525"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass the file name data in the input object (fileName)" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { string document = (string)data.document; string fileName = (string)data.fileName; AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the asset string assetid = data.assetId; var destAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (destAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } log.Info(@"creation of file {fileName}"); var filetocreate = destAsset.AssetFiles.Create(fileName); using (Stream s = GenerateStreamFromString(document)) { filetocreate.Upload(s); } if (data.convertTtml != null && ((bool)data.convertTtml == true)) { // let's convert the ttml to vtt log.Info("ttml to vtt convert process..."); XNamespace xmlns = "http://www.w3.org/ns/ttml"; XDocument docXML = XDocument.Parse(document); var tt = docXML.Element(xmlns + "tt"); var subtitles = docXML.Element(xmlns + "tt").Element(xmlns + "body").Element(xmlns + "div").Elements(xmlns + "p"); StringBuilder sbuild = new StringBuilder(); string vttarrow = " --> "; sbuild.AppendLine("WEBVTT"); sbuild.AppendLine(); foreach (var sub in subtitles) { var begin = (string)sub.Attribute("begin"); var end = (string)sub.Attribute("end"); var text = (string)sub.Value; sbuild.AppendLine(begin + vttarrow + end); sbuild.AppendLine(text); sbuild.AppendLine(); } string vttfilename = Path.GetFileNameWithoutExtension(fileName) + ".vtt"; log.Info(@"creation of file {vttfilename}"); var filetocreate2 = destAsset.AssetFiles.Create(vttfilename); using (Stream s2 = GenerateStreamFromString(sbuild.ToString())) { filetocreate2.Upload(s2); } } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK)); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.channelName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass channelName in the input object" })); } if (data.programName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass programName in the input object" })); } string channelName = data.channelName; string programName = data.programName; string assetName = data.assetName; IProgram program = null; TimeSpan archiveLength = new TimeSpan(0, data.archiveWindowLength != null ? (int)data.archiveWindowLength : 5, 0); // default 5 min MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); IAsset newAsset = null; try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); log.Info("Context object created."); var channel = _context.Channels.Where(c => c.Name == channelName).FirstOrDefault(); if (channel == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = string.Format("Channel {0} not found", channelName) })); } newAsset = _context.Assets.Create(assetName, (string)data.assetStorage, AssetCreationOptions.None); log.Info("new asset created."); if (data.alternateId != null) { newAsset.AlternateId = (string)data.alternateId; newAsset.Update(); } ProgramCreationOptions options = new ProgramCreationOptions() { Name = programName, ManifestName = data.manifestName, Description = data.description, AssetId = newAsset.Id, ArchiveWindowLength = archiveLength }; program = channel.Programs.Create(options); log.Info("new program created."); if (data.startProgram == null || (data.startProgram != null && (bool)data.startProgram)) { log.Info("starting program..."); program.Start(); log.Info("Program started."); } program = _context.Programs.Where(p => p.Id == program.Id).FirstOrDefault(); // refresh } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info("asset Id: " + newAsset.Id); log.Info("container Path: " + newAsset.Uri.Segments[1]); return(req.CreateResponse(HttpStatusCode.OK, new { containerPath = newAsset.Uri.Segments[1], assetId = newAsset.Id, manifestName = program.ManifestName, id = program.Id, state = program.State })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log, Microsoft.Azure.WebJobs.ExecutionContext execContext) { log.Info($"Webhook was triggered!"); // Init variables string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); string fileName = null; var manifestInfo = new ManifestHelpers.ManifestGenerated(); log.Info(jsonContent); if (data.assetId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (assetId)" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); bool checkStreamingEndpointResponse = false; bool checkStreamingEndpointResponseSuccess = true; try { fileName = (string)data.fileName; AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the asset string assetid = data.assetId; var destAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (destAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } log.Info($"creation of file {fileName}"); // Manifest generate manifestInfo = ManifestHelpers.LoadAndUpdateManifestTemplate(destAsset, execContext); // if not file name passed, then we use the one generated based on mp4 files names if (fileName == null) { fileName = manifestInfo.FileName; } var filetocreate = destAsset.AssetFiles.Create(fileName); using (Stream s = ManifestHelpers.GenerateStreamFromString(manifestInfo.Content)) { filetocreate.Upload(s); } log.Info("Manifest file created."); // let's make the manifest the primary file of the asset MediaServicesHelper.SetFileAsPrimary(destAsset, fileName); log.Info("Manifest file set as primary."); if (data.checkStreamingEndpointResponse != null && (bool)data.checkStreamingEndpointResponse) { checkStreamingEndpointResponse = true; // testing streaming // publish with a streaming locator (1 hour) IAccessPolicy readPolicy = _context.AccessPolicies.Create("readPolicy", TimeSpan.FromHours(1), AccessPermissions.Read); ILocator outputLocator = _context.Locators.CreateLocator(LocatorType.OnDemandOrigin, destAsset, readPolicy); var publishurlsmooth = MediaServicesHelper.GetValidOnDemandURI(_context, destAsset); try { WebRequest request = WebRequest.Create(publishurlsmooth.ToString()); WebResponse response = request.GetResponse(); response.Close(); } catch (Exception ex) { checkStreamingEndpointResponseSuccess = false; } outputLocator.Delete(); readPolicy.Delete(); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); if (checkStreamingEndpointResponse) { return(req.CreateResponse(HttpStatusCode.OK, new { fileName = fileName, manifestContent = manifestInfo.Content, checkStreamingEndpointResponseSuccess = checkStreamingEndpointResponseSuccess })); } else { return(req.CreateResponse(HttpStatusCode.OK, new { fileName = fileName, manifestContent = manifestInfo.Content })); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"AMS v2 Function - Add Asset Delivery Policy was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); if (string.IsNullOrEmpty(jsonContent)) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass a JSON request body" })); } object data = JsonConvert.DeserializeObject(jsonContent); string hexIv = GetHexIV(); IAssetDeliveryPolicy result; IContentKey contentKey; try { result = CreateFairplayAssetDeliveryPolicy(hexIv, out contentKey); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : "") + "\n" + ex.StackTrace; log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { assetDeliveryPolicyId = result.Id, contentKeyId = contentKey.Id, hexIv = hexIv, })); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.assetName == null) { // for test // data.Path = "/input/WP_20121015_081924Z.mp4"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetName in the input object" })); } string assetName = data.assetName; MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); IAsset newAsset = null; try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); log.Info("Context object created."); newAsset = _context.Assets.Create(assetName, (string)data.assetStorage, AssetCreationOptions.None); log.Info("new asset created."); if (data.alternateId != null) { newAsset.AlternateId = (string)data.alternateId; newAsset.Update(); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info("asset Id: " + newAsset.Id); log.Info("container Path: " + newAsset.Uri.Segments[1]); return(req.CreateResponse(HttpStatusCode.OK, new { containerPath = newAsset.Uri.Segments[1], assetId = newAsset.Id })); }
public static async Task<object> Run([HttpTrigger(WebHookType = "genericJson")]HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info("Request : " + jsonContent); MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); // Validate input objects int delay = 5000; if (data.destinationContainer == null) return req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass DestinationContainer in the input object" }); if (data.delay != null) delay = data.delay; log.Info("Input - DestinationContainer : " + data.destinationContainer); //log.Info("delay : " + delay); log.Info($"Wait " + delay + "(ms)"); System.Threading.Thread.Sleep(delay); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (data.assetStorage != null) { string assetstor = (string)data.assetStorage; if (assetstor != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(assetstor)) // asset is using another storage than default but we have the key { storname = assetstor; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"Face redaction Asset is in {assetstor} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" }); } } } string destinationContainerName = data.destinationContainer; CloudBlobContainer destinationBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, destinationContainerName); CopyStatus copyStatus = CopyStatus.Success; try { string blobPrefix = null; bool useFlatBlobListing = true; var destBlobList = destinationBlobContainer.ListBlobs(blobPrefix, useFlatBlobListing, BlobListingDetails.Copy); foreach (var dest in destBlobList) { var destBlob = dest as CloudBlob; if (destBlob.CopyState.Status == CopyStatus.Aborted || destBlob.CopyState.Status == CopyStatus.Failed) { // Log the copy status description for diagnostics and restart copy destBlob.StartCopyAsync(destBlob.CopyState.Source); copyStatus = CopyStatus.Pending; } else if (destBlob.CopyState.Status == CopyStatus.Pending) { // We need to continue waiting for this pending copy // However, let us log copy state for diagnostics copyStatus = CopyStatus.Pending; } // else we completed this pending copy } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message }); } return req.CreateResponse(HttpStatusCode.OK, new { copyStatus = copyStatus, isRunning = (copyStatus == CopyStatus.Pending).ToString(), isSuccessful = (copyStatus == CopyStatus.Success).ToString() }); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { { log.Info($"Webhook was triggered!"); // Init variables string pathUrl = ""; dynamic pngThumbnails = new JArray() as dynamic; string prefixpng = ""; string copyToContainer = ""; string targetContainerUri = ""; TimeSpan timeOffset = new TimeSpan(0); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); log.Info(jsonContent); MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // // MES Thumbnails // if (data.mesThumbnails != null && data.mesThumbnails.assetId != null) { List <CloudBlob> listPNGCopies = new List <CloudBlob>(); // Get the asset string assetid = data.mesThumbnails.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var pngFiles = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".PNG")); Uri publishurl = MediaServicesHelper.GetValidOnDemandPath(_context, outputAsset); if (publishurl != null) { pathUrl = publishurl.ToString(); } else { log.Info($"Asset not published"); } // Let's copy the PNG Thumbnails if (data.mesThumbnails.copyToContainer != null) { copyToContainer = data.mesThumbnails.copyToContainer + DateTime.UtcNow.ToString("yyyyMMdd"); // let's copy PNG to a container prefixpng = outputAsset.Uri.Segments[1] + "-"; log.Info($"prefixpng {prefixpng}"); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (outputAsset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(outputAsset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = outputAsset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"MES Thumbnails Asset is in {outputAsset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } var sourceContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, outputAsset.Uri.Segments[1]); CloudBlobContainer targetContainer; if (data.mesThumbnails.copyToContainerAccountName != null) { // copy to a specific storage account targetContainer = CopyBlobHelpers.GetCloudBlobContainer((string)data.mesThumbnails.copyToContainerAccountName, (string)data.mesThumbnails.copyToContainerAccountKey, copyToContainer); } else { // copy to ams storage account targetContainer = CopyBlobHelpers.GetCloudBlobContainer(amsCredentials.StorageAccountName, amsCredentials.StorageAccountKey, copyToContainer); } listPNGCopies = await CopyBlobHelpers.CopyFilesAsync(sourceContainer, targetContainer, prefixpng, "png", log); targetContainerUri = targetContainer.Uri.ToString(); } foreach (IAssetFile file in pngFiles) { string index = file.Name.Substring(file.Name.Length - 10, 6); int index_i = 0; if (int.TryParse(index, out index_i)) { dynamic entry = new JObject(); entry.id = index_i; entry.fileId = file.Id; entry.fileName = file.Name; if (copyToContainer != "") { entry.url = targetContainerUri + "/" + prefixpng + file.Name; } else if (!string.IsNullOrEmpty(pathUrl)) { entry.url = pathUrl + file.Name; } pngThumbnails.Add(entry); } } if (data.mesThumbnails.deleteAsset != null && ((bool)data.mesThumbnails.deleteAsset)) { // If asset deletion was asked // let's wait for the copy to finish before deleting the asset.. if (listPNGCopies.Count > 0) { log.Info("PNG Copy with asset deletion was asked. Checking copy status..."); bool continueLoop = true; while (continueLoop) { listPNGCopies = listPNGCopies.Where(r => r.CopyState.Status == CopyStatus.Pending).ToList(); if (listPNGCopies.Count == 0) { continueLoop = false; } else { log.Info("PNG Copy not finished. Waiting 3s..."); Task.Delay(TimeSpan.FromSeconds(3d)).Wait(); listPNGCopies.ForEach(r => r.FetchAttributes()); } } } outputAsset.Delete(); } } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK, new { mesThumbnail = new { pngThumbnails = Newtonsoft.Json.JsonConvert.SerializeObject(pngThumbnails) } })); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.jobId == null || data.taskId == null) { // used to test the function //data.jobId = "nb:jid:UUID:acf38b8a-aef9-4789-9f0f-f69bf6ccb8e5"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass the job and task ID in the input object (jobId, taskId)" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); IJob job = null; ITask task = null; string startTime = ""; string endTime = ""; StringBuilder sberror = new StringBuilder(); string runningDuration = ""; bool isRunning = true; bool isSuccessful = true; bool extendedInfo = false; if (data.extendedInfo != null && ((bool)data.extendedInfo) == true) { extendedInfo = true; } try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the job string jobid = (string)data.jobId; job = _context.Jobs.Where(j => j.Id == jobid).FirstOrDefault(); if (job == null) { log.Info($"Job not found {jobid}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = "Job not found" })); } // Get the task string taskid = (string)data.taskId; task = job.Tasks.Where(j => j.Id == taskid).FirstOrDefault(); if (task == null) { log.Info($"Task not found {taskid}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = "Task not found" })); } if (data.noWait != null && (bool)data.noWait) { // No wait } else { for (int i = 1; i <= 3; i++) // let's wait 3 times 5 seconds (15 seconds) { log.Info($"Task {task.Id} status is {task.State}"); if (task.State == JobState.Finished || task.State == JobState.Canceled || task.State == JobState.Error) { break; } log.Info("Waiting 5 s..."); System.Threading.Thread.Sleep(5 * 1000); task = job.Tasks.Where(j => j.Id == taskid).FirstOrDefault(); } } if (task.State == JobState.Error || task.State == JobState.Canceled) { foreach (var details in task.ErrorDetails) { sberror.AppendLine(task.Name + " : " + details.Message); } } if (task.StartTime != null) { startTime = ((DateTime)task.StartTime).ToString("o"); } if (task.EndTime != null) { endTime = ((DateTime)task.EndTime).ToString("o"); } if (task.RunningDuration != null) { runningDuration = task.RunningDuration.ToString(); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } isRunning = !(task.State == JobState.Finished || task.State == JobState.Canceled || task.State == JobState.Error); isSuccessful = (task.State == JobState.Finished); if (extendedInfo && (task.State == JobState.Finished || task.State == JobState.Canceled || task.State == JobState.Error)) { dynamic stats = new JObject(); stats.mediaUnitNumber = _context.EncodingReservedUnits.FirstOrDefault().CurrentReservedUnits; stats.mediaUnitSize = MediaServicesHelper.ReturnMediaReservedUnitName(_context.EncodingReservedUnits.FirstOrDefault().ReservedUnitType);; stats.otherJobsProcessing = _context.Jobs.Where(j => j.State == JobState.Processing).Count(); stats.otherJobsScheduled = _context.Jobs.Where(j => j.State == JobState.Scheduled).Count(); stats.otherJobsQueue = _context.Jobs.Where(j => j.State == JobState.Queued).Count(); stats.amsRESTAPIEndpoint = amsCredentials.AmsRestApiEndpoint; return(req.CreateResponse(HttpStatusCode.OK, new { taskState = task.State, errorText = sberror.ToString(), startTime = startTime, endTime = endTime, runningDuration = runningDuration, extendedInfo = stats.ToString(), isRunning = isRunning.ToString(), isSuccessful = isSuccessful.ToString(), progress = task.Progress })); } else { return(req.CreateResponse(HttpStatusCode.OK, new { taskState = task.State, errorText = sberror.ToString(), startTime = startTime, endTime = endTime, runningDuration = runningDuration, isRunning = isRunning.ToString(), isSuccessful = isSuccessful.ToString(), progress = task.Progress })); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log, Microsoft.Azure.WebJobs.ExecutionContext execContext) { int taskindex = 0; bool useEncoderOutputForAnalytics = false; IAsset outputEncoding = null; log.Info($"Webhook was triggered!"); string triggerStart = DateTime.UtcNow.ToString("o"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); log.Info($"asset id : {data.assetId}"); if (data.assetId == null) { // for test // data.assetId = "nb:cid:UUID:2d0d78a2-685a-4b14-9cf0-9afb0bb5dbfc"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (assetId)" })); } IJob job = null; ITask taskEncoding = null; int OutputMES = -1; int OutputMEPW = -1; int OutputIndex1 = -1; int OutputIndex2 = -1; int OutputOCR = -1; int OutputFaceDetection = -1; int OutputMotion = -1; int OutputSummarization = -1; int OutputFaceRedaction = -1; int OutputMesThumbnails = -1; int OutputVideoAnnotation = -1; int NumberJobsQueue = 0; MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // find the Asset string assetid = (string)data.assetId; IAsset asset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (asset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } if (data.useEncoderOutputForAnalytics != null && ((bool)data.useEncoderOutputForAnalytics) && (data.mesPreset != null || data.mes != null)) // User wants to use encoder output for media analytics { useEncoderOutputForAnalytics = (bool)data.useEncoderOutputForAnalytics; } // Declare a new encoding job with the Standard encoder int priority = 10; if (data.priority != null) { priority = (int)data.priority; } job = _context.Jobs.Create(((string)data.jobName) ?? "Azure Functions Job", priority); if (data.mes != null || data.mesPreset != null) // MES Task { // Get a media processor reference, and pass to it the name of the // processor to use for the specific task. IMediaProcessor processorMES = MediaServicesHelper.GetLatestMediaProcessorByName(_context, "Media Encoder Standard"); string preset = null; if (data.mes != null) { preset = (string)data.mes.preset; } else { preset = (string)data.mesPreset; // Compatibility mode } if (preset == null) { preset = "Content Adaptive Multiple Bitrate MP4"; // the default preset } if (preset.ToUpper().EndsWith(".JSON")) { // Build the folder path to the preset string presetPath = Path.Combine(System.IO.Directory.GetParent(execContext.FunctionDirectory).FullName, "presets", preset); log.Info("presetPath= " + presetPath); preset = File.ReadAllText(presetPath); } // Create a task with the encoding details, using a string preset. // In this case "H264 Multiple Bitrate 720p" system defined preset is used. taskEncoding = job.Tasks.AddNew("MES encoding task", processorMES, preset, TaskOptions.None); // Specify the input asset to be encoded. taskEncoding.InputAssets.Add(asset); OutputMES = taskindex++; // Add an output asset to contain the results of the job. // This output is specified as AssetCreationOptions.None, which // means the output asset is not encrypted. outputEncoding = taskEncoding.OutputAssets.AddNew(asset.Name + " MES encoded", JobHelpers.OutputStorageFromParam(data.mes), AssetCreationOptions.None); } if (data.mepw != null || data.workflowAssetId != null) // Premium Encoder Task { //find the workflow asset string workflowassetid = null; if (data.mepw != null) { workflowassetid = (string)data.mepw.workflowAssetId; } else { workflowassetid = (string)data.workflowAssetId; // compatibility mode } IAsset workflowAsset = _context.Assets.Where(a => a.Id == workflowassetid).FirstOrDefault(); if (workflowAsset == null) { log.Info($"Workflow not found {workflowassetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Workflow not found" })); } // Get a media processor reference, and pass to it the name of the // processor to use for the specific task. IMediaProcessor processorMEPW = MediaServicesHelper.GetLatestMediaProcessorByName(_context, "Media Encoder Premium Workflow"); string premiumConfiguration = ""; if (data.mepw != null && data.mepw.workflowConfig != null) { premiumConfiguration = (string)data.mepw.workflowConfig; } else if (data.workflowConfig != null) { premiumConfiguration = (string)data.workflowConfig; // compatibility mode } // In some cases, a configuration can be loaded and passed it to the task to tuned the workflow // premiumConfiguration=File.ReadAllText(Path.Combine(System.IO.Directory.GetParent(execContext.FunctionDirectory).FullName, "presets", "SetRuntime.xml")).Replace("VideoFileName", VideoFile.Name).Replace("AudioFileName", AudioFile.Name); // Create a task taskEncoding = job.Tasks.AddNew("Premium Workflow encoding task", processorMEPW, premiumConfiguration, TaskOptions.None); log.Info("task created"); // Specify the input asset to be encoded. taskEncoding.InputAssets.Add(workflowAsset); // first add the Workflow taskEncoding.InputAssets.Add(asset); // Then add the video asset OutputMEPW = taskindex++; // Add an output asset to contain the results of the job. // This output is specified as AssetCreationOptions.None, which // means the output asset is not encrypted. outputEncoding = taskEncoding.OutputAssets.AddNew(asset.Name + " Premium encoded", JobHelpers.OutputStorageFromParam(data.mepw), AssetCreationOptions.None); } IAsset an_asset = useEncoderOutputForAnalytics ? outputEncoding : asset; // Media Analytics OutputIndex1 = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.indexV1 == null) ? (string)data.indexV1Language : ((string)data.indexV1.language ?? "English"), "Azure Media Indexer", "IndexerV1.xml", "English", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.indexV1)); OutputIndex2 = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.indexV2 == null) ? (string)data.indexV2Language : ((string)data.indexV2.language ?? "EnUs"), "Azure Media Indexer 2 Preview", "IndexerV2.json", "EnUs", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.indexV2)); OutputOCR = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.ocr == null) ? (string)data.ocrLanguage : ((string)data.ocr.language ?? "AutoDetect"), "Azure Media OCR", "OCR.json", "AutoDetect", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.ocr)); OutputFaceDetection = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.faceDetection == null) ? (string)data.faceDetectionMode : ((string)data.faceDetection.mode ?? "PerFaceEmotion"), "Azure Media Face Detector", "FaceDetection.json", "PerFaceEmotion", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.faceDetection)); OutputFaceRedaction = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.faceRedaction == null) ? (string)data.faceRedactionMode : ((string)data.faceRedaction.mode ?? "comined"), "Azure Media Redactor", "FaceRedaction.json", "combined", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.faceRedaction)); OutputMotion = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.motionDetection == null) ? (string)data.motionDetectionLevel : ((string)data.motionDetection.level ?? "medium"), "Azure Media Motion Detector", "MotionDetection.json", "medium", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.motionDetection)); OutputSummarization = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.summarization == null) ? (string)data.summarizationDuration : ((string)data.summarization.duration ?? "0.0"), "Azure Media Video Thumbnails", "Summarization.json", "0.0", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.summarization)); OutputVideoAnnotation = JobHelpers.AddTask(execContext, _context, job, an_asset, (data.videoAnnotation != null) ? "1.0" : null, "Azure Media Video Annotator", "VideoAnnotation.json", "1.0", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.videoAnnotation)); // MES Thumbnails OutputMesThumbnails = JobHelpers.AddTask(execContext, _context, job, asset, (data.mesThumbnails != null) ? ((string)data.mesThumbnails.Start ?? "{Best}") : null, "Media Encoder Standard", "MesThumbnails.json", "{Best}", ref taskindex, specifiedStorageAccountName: JobHelpers.OutputStorageFromParam(data.mesThumbnails)); job.Submit(); log.Info("Job Submitted"); NumberJobsQueue = _context.Jobs.Where(j => j.State == JobState.Queued).Count(); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } job = _context.Jobs.Where(j => j.Id == job.Id).FirstOrDefault(); // Let's refresh the job log.Info("Job Id: " + job.Id); log.Info("OutputAssetMESId: " + JobHelpers.ReturnId(job, OutputMES)); log.Info("OutputAssetMEPWId: " + JobHelpers.ReturnId(job, OutputMEPW)); log.Info("OutputAssetIndexV1Id: " + JobHelpers.ReturnId(job, OutputIndex1)); log.Info("OutputAssetIndexV2Id: " + JobHelpers.ReturnId(job, OutputIndex2)); log.Info("OutputAssetOCRId: " + JobHelpers.ReturnId(job, OutputOCR)); log.Info("OutputAssetFaceDetectionId: " + JobHelpers.ReturnId(job, OutputFaceDetection)); log.Info("OutputAssetFaceRedactionId: " + JobHelpers.ReturnId(job, OutputFaceRedaction)); log.Info("OutputAssetMotionDetectionId: " + JobHelpers.ReturnId(job, OutputMotion)); log.Info("OutputAssetSummarizationId: " + JobHelpers.ReturnId(job, OutputSummarization)); log.Info("OutputMesThumbnailsId: " + JobHelpers.ReturnId(job, OutputMesThumbnails)); log.Info("OutputAssetVideoAnnotationId: " + JobHelpers.ReturnId(job, OutputVideoAnnotation)); return(req.CreateResponse(HttpStatusCode.OK, new { jobId = job.Id, otherJobsQueue = NumberJobsQueue, mes = new { assetId = JobHelpers.ReturnId(job, OutputMES), taskId = JobHelpers.ReturnTaskId(job, OutputMES) }, mepw = new { assetId = JobHelpers.ReturnId(job, OutputMEPW), taskId = JobHelpers.ReturnTaskId(job, OutputMEPW) }, indexV1 = new { assetId = JobHelpers.ReturnId(job, OutputIndex1), taskId = JobHelpers.ReturnTaskId(job, OutputIndex1), language = (string)data.indexV1Language }, indexV2 = new { assetId = JobHelpers.ReturnId(job, OutputIndex2), taskId = JobHelpers.ReturnTaskId(job, OutputIndex2), language = (string)data.indexV2Language }, ocr = new { assetId = JobHelpers.ReturnId(job, OutputOCR), taskId = JobHelpers.ReturnTaskId(job, OutputOCR) }, faceDetection = new { assetId = JobHelpers.ReturnId(job, OutputFaceDetection), taskId = JobHelpers.ReturnTaskId(job, OutputFaceDetection) }, faceRedaction = new { assetId = JobHelpers.ReturnId(job, OutputFaceRedaction), taskId = JobHelpers.ReturnTaskId(job, OutputFaceRedaction) }, motionDetection = new { assetId = JobHelpers.ReturnId(job, OutputMotion), taskId = JobHelpers.ReturnTaskId(job, OutputMotion) }, summarization = new { assetId = JobHelpers.ReturnId(job, OutputSummarization), taskId = JobHelpers.ReturnTaskId(job, OutputSummarization) }, mesThumbnails = new { assetId = JobHelpers.ReturnId(job, OutputMesThumbnails), taskId = JobHelpers.ReturnTaskId(job, OutputMesThumbnails) }, videoAnnotation = new { assetId = JobHelpers.ReturnId(job, OutputVideoAnnotation), taskId = JobHelpers.ReturnTaskId(job, OutputVideoAnnotation) } })); }
static public ManifestTimingData GetManifestTimingData(CloudMediaContext context, IAsset asset, TraceWriter log) // Parse the manifest and get data from it { ManifestTimingData response = new ManifestTimingData() { IsLive = false, Error = false, TimestampOffset = 0, TimestampList = new List <ulong>(), DiscontinuityDetected = false }; try { ILocator mytemplocator = null; Uri myuri = MediaServicesHelper.GetValidOnDemandURI(context, asset); if (myuri == null) { mytemplocator = MediaServicesHelper.CreatedTemporaryOnDemandLocator(asset); myuri = MediaServicesHelper.GetValidOnDemandURI(context, asset); } if (myuri != null) { log.Info($"Asset URI {myuri.ToString()}"); XDocument manifest = XDocument.Load(myuri.ToString()); //log.Info($"manifest {manifest}"); var smoothmedia = manifest.Element("SmoothStreamingMedia"); var videotrack = smoothmedia.Elements("StreamIndex").Where(a => a.Attribute("Type").Value == "video"); // TIMESCALE string timescalefrommanifest = smoothmedia.Attribute("TimeScale").Value; if (videotrack.FirstOrDefault().Attribute("TimeScale") != null) // there is timescale value in the video track. Let's take this one. { timescalefrommanifest = videotrack.FirstOrDefault().Attribute("TimeScale").Value; } ulong timescale = ulong.Parse(timescalefrommanifest); response.TimeScale = (ulong?)timescale; // Timestamp offset if (videotrack.FirstOrDefault().Element("c").Attribute("t") != null) { response.TimestampOffset = ulong.Parse(videotrack.FirstOrDefault().Element("c").Attribute("t").Value); } else { response.TimestampOffset = 0; // no timestamp, so it should be 0 } ulong totalduration = 0; ulong durationpreviouschunk = 0; ulong durationchunk; int repeatchunk; foreach (var chunk in videotrack.Elements("c")) { durationchunk = chunk.Attribute("d") != null?ulong.Parse(chunk.Attribute("d").Value) : 0; log.Info($"duration d {durationchunk}"); repeatchunk = chunk.Attribute("r") != null?int.Parse(chunk.Attribute("r").Value) : 1; log.Info($"repeat r {repeatchunk}"); if (chunk.Attribute("t") != null) { ulong tvalue = ulong.Parse(chunk.Attribute("t").Value); response.TimestampList.Add(tvalue); if (tvalue != response.TimestampOffset) { totalduration = tvalue - response.TimestampOffset; // Discountinuity ? We calculate the duration from the offset response.DiscontinuityDetected = true; // let's flag it } } else { response.TimestampList.Add(response.TimestampList[response.TimestampList.Count() - 1] + durationpreviouschunk); } totalduration += durationchunk * (ulong)repeatchunk; for (int i = 1; i < repeatchunk; i++) { response.TimestampList.Add(response.TimestampList[response.TimestampList.Count() - 1] + durationchunk); } durationpreviouschunk = durationchunk; } response.TimestampEndLastChunk = response.TimestampList[response.TimestampList.Count() - 1] + durationpreviouschunk; if (smoothmedia.Attribute("IsLive") != null && smoothmedia.Attribute("IsLive").Value == "TRUE") { // Live asset.... No duration to read (but we can read scaling and compute duration if no gap) response.IsLive = true; response.AssetDuration = TimeSpan.FromSeconds((double)totalduration / ((double)timescale)); } else { totalduration = ulong.Parse(smoothmedia.Attribute("Duration").Value); response.AssetDuration = TimeSpan.FromSeconds((double)totalduration / ((double)timescale)); } } else { response.Error = true; } if (mytemplocator != null) { mytemplocator.Delete(); } } catch (Exception ex) { response.Error = true; } return(response); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info("Request : " + jsonContent); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); // Validate input objects if (data.assetId == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass assetId in the input object" })); } if (data.targetStorageAccountName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass targetStorageAccountName in the input object" })); } if (data.targetStorageAccountKey == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass targetStorageAccountKey in the input object" })); } if (data.targetContainer == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass targetContainer in the input object" })); } string targetStorageAccountName = data.targetStorageAccountName; string targetStorageAccountKey = data.targetStorageAccountKey; string targetContainer = data.targetContainer; string startsWith = data.startsWith; string endsWith = data.endsWith; log.Info("Input - targetStorageAccountName : " + targetStorageAccountName); log.Info("Input - targetStorageAccountKey : " + targetStorageAccountKey); log.Info("Input - targetContainer : " + targetContainer); string assetId = data.assetId; IAsset asset = null; IIngestManifest manifest = null; MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Find the Asset asset = _context.Assets.Where(a => a.Id == assetId).FirstOrDefault(); if (asset == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (asset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(asset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = asset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"Face redaction Asset is in {asset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } // Setup blob container CloudBlobContainer sourceBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, asset.Uri.Segments[1]); CloudBlobContainer destinationBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(targetStorageAccountName, targetStorageAccountKey, targetContainer); destinationBlobContainer.CreateIfNotExists(); var files = asset.AssetFiles.ToList().Where(f => ((string.IsNullOrEmpty(endsWith) || f.Name.EndsWith(endsWith)) && (string.IsNullOrEmpty(startsWith) || f.Name.StartsWith(startsWith)))); foreach (var file in files) { CloudBlob sourceBlob = sourceBlobContainer.GetBlockBlobReference(file.Name); CloudBlob destinationBlob = destinationBlobContainer.GetBlockBlobReference(file.Name); CopyBlobHelpers.CopyBlobAsync(sourceBlob, destinationBlob); log.Info($"Start copy of file : {file.Name}"); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK)); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.channelName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass channelName in the input object" })); } if (data.programName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass programName in the input object" })); } string channelName = data.channelName; string programName = data.programName; IProgram program = null; MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); log.Info("Context object created."); var channel = _context.Channels.Where(c => c.Name == channelName).FirstOrDefault(); if (channel == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = string.Format("Channel {0} not found", channelName) })); } program = channel.Programs.Where(p => p.Name.Equals(programName)).FirstOrDefault(); if (program == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = string.Format("Program {0} not found", programName) })); } log.Info("Stoping program..."); program.Stop(); log.Info("Program stopped."); } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } return(req.CreateResponse(HttpStatusCode.OK, new { success = true, state = program.State.ToString() })); }