├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── deploy-functions.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Encoding
├── .gitattributes
├── .gitignore
├── Encoding.sln
├── Encoding
│ ├── .gitignore
│ ├── Encoding.csproj
│ ├── Helpers
│ │ ├── ConfigWrapper.cs
│ │ ├── HelpersBasic.cs
│ │ └── copyBlobHelpers.cs
│ ├── VodFunctions
│ │ └── ffmpeg-encoding.cs
│ ├── host.json
│ └── local.settings.json
└── README.md
├── Functions
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── Common_Utils
│ ├── AssetUtils.cs
│ ├── Authentication.cs
│ ├── ConfigUtils.cs
│ ├── ConfigWrapper.cs
│ ├── HttpRequest.cs
│ ├── JobUtils.cs
│ ├── LiveManifest.cs
│ ├── LogUtils.cs
│ ├── MediaServicesHelperJsonConverter.cs
│ └── TransformUtils.cs
├── CreateEmptyAsset.cs
├── DeleteAsset.cs
├── Functions.csproj
├── Functions.sln
├── Models
│ ├── ManifestSegmentData.cs
│ └── ManifestTimingData.cs
├── Program.cs
├── PublishAsset.cs
├── README.md
├── SubmitEncodingJob.cs
├── SubmitSubclipJob.cs
├── azuredeploy2.json
├── azuredeploy2.parameter.json
├── azuredeploy2mi.json
├── azuredeploy2mi.parameter.json
├── host.json
└── local.settings.json
├── Images
├── DrawingAzureFunctionsNet5.png
├── DrawingAzureFunctionsNet5.vsdx
├── azfunc5appinstance.png
├── azfunc5deploy.png
├── azfunc5deployappsettings.png
├── azfunc5geturl.png
├── azfunc5geturlportal.png
├── azfunc5githubactions.png
├── azfunc5postman.png
├── azfunc5postmandeployed.png
├── azfunc5roleassignment.png
└── azfunc5runvscode.png
├── LICENSE.md
├── LiveAndVodDRMOperationsV3
├── .gitattributes
├── .gitignore
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── Images
│ └── overview.png
├── LiveAndVodDRMOperationsV3.sln
├── LiveAndVodDRMOperationsV3
│ ├── .gitignore
│ ├── Helpers
│ │ ├── ConfigWrapper.cs
│ │ ├── CosmosHelpers.cs
│ │ ├── GenerateAssetInfoHelpers.cs
│ │ ├── GenerateInfoHelpers.cs
│ │ ├── IrdetoHelpers.cs
│ │ ├── ManifestHelpers.cs
│ │ ├── MediaServicesHelpers.cs
│ │ └── copyBlobHelpers.cs
│ ├── LiveAndVodDRMOperationsV3.csproj
│ ├── LiveFunctions
│ │ ├── check-all-live-event-output.cs
│ │ ├── create-clear-streaming-locator.cs
│ │ ├── create-live-event-output.cs
│ │ ├── delete-live-event-output.cs
│ │ ├── delete-streaming-locator.cs
│ │ ├── ping.cs
│ │ ├── redirector.cs
│ │ ├── reset-live-event-output.cs
│ │ ├── start-live-event.cs
│ │ ├── stop-live-event.cs
│ │ └── update-settings.cs
│ ├── ManifestTemplate
│ │ └── manifest.ism
│ ├── Models
│ │ ├── BaseModel.cs
│ │ ├── GeneralOutputInfo.cs
│ │ ├── LiveEventSettingsInfo.cs
│ │ ├── StreamingPolicy.cs
│ │ ├── VodAssetInfo.cs
│ │ ├── VodResource.cs
│ │ └── VodSemaphore.cs
│ ├── VodFunctions
│ │ ├── check-blob-copy-to-asset-status.cs
│ │ ├── create-empty-asset.cs
│ │ ├── create-vtt-to-asset.cs
│ │ ├── generate-ism-manifest.cs
│ │ ├── generate-resource.cs
│ │ ├── get-asset-info.cs
│ │ ├── list-assets-startwith.cs
│ │ ├── publish-asset-simple.cs
│ │ ├── publish-asset.cs
│ │ ├── start-blob-copy-to-asset.cs
│ │ └── submit-job.cs
│ ├── host.json
│ └── local.settings.json
├── LogicApps
│ ├── preencodedasset-workflow-deploy.json
│ └── semaphore-sample.json
└── README.md
├── README.md
├── Tutorial
├── HttpTriggerEncode.cs
├── Program.cs
├── README.md
├── TestFuncVS.csproj
└── host.json
├── advanced-vod-workflow
├── .gitignore
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── DemoScript.md
├── Functions-documentation.md
├── Functions
│ ├── ConvertMesPresetJson.cs
│ ├── CreateContentKeyPolicy.cs
│ ├── CreateEmptyAsset.cs
│ ├── CreateJwtToken.cs
│ ├── CreatePlayReadyLicenseTemplate.cs
│ ├── CreateStreamingPolicy.cs
│ ├── CreateTransform.cs
│ ├── CreateWidevineLicenseTemplate.cs
│ ├── DeleteAsset.cs
│ ├── DeleteContentKeyPolicy.cs
│ ├── DeleteStreamingPolicy.cs
│ ├── GetAssetUrls.cs
│ ├── GetTransform.cs
│ ├── MonitorBlobContainerCopyStatus.cs
│ ├── MonitorMediaJob.cs
│ ├── PublishAsset.cs
│ ├── StartBlobContainerCopyToAsset.cs
│ ├── SubmitMediaJob.cs
│ └── UnpublishAsset.cs
├── README.md
├── SharedLibs
│ ├── BlobStorageHelper.cs
│ ├── GenericHelper.cs
│ ├── MESPresetSchema.cs
│ ├── MediaServiceClientCredentials.cs
│ ├── MediaServicesConfigWrapper.cs
│ ├── MediaServicesHelper.cs
│ ├── MediaServicesHelperJsonConverter.cs
│ ├── MediaServicesHelperMES.cs
│ └── WidevineLicenseTemplate.cs
├── advanced_vod_functions_v3.csproj
├── advanced_vod_functions_v3.sln
├── host.json
└── local.settings.json
├── azuredeploy.json
├── azuredeploy.parameters.json
├── logic-app-using-workflow-functions
├── .gitignore
├── README.md
├── publish-logicapp
│ ├── Deploy-AzureResourceGroup.ps1
│ ├── Deployment.targets
│ ├── LogicApp.json
│ ├── LogicApp.parameters.json
│ └── publish-logicapp.deployproj
├── publish-streaming.sln
├── upload-and-encode-logicapp
│ ├── Deploy-AzureResourceGroup.ps1
│ ├── Deployment.targets
│ ├── LogicApp.json
│ ├── LogicApp.parameters.json
│ └── upload-and-encode-logicapp.deployproj
└── upload-and-encode.sln
└── sample.env
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 | > Please provide us with the following information:
5 | > ---------------------------------------------------------------
6 |
7 | ### This issue is for a: (mark with an `x`)
8 | ```
9 | - [ ] bug report -> please search issues before submitting
10 | - [ ] feature request
11 | - [ ] documentation issue or request
12 | - [ ] regression (a behavior that used to work and stopped in a new release)
13 | ```
14 |
15 | ### Minimal steps to reproduce
16 | >
17 |
18 | ### Any log messages given by the failure
19 | >
20 |
21 | ### Expected/desired behavior
22 | >
23 |
24 | ### OS and Version?
25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?)
26 |
27 | ### Versions
28 | >
29 |
30 | ### Mention any other details that might be useful
31 |
32 | > ---------------------------------------------------------------
33 | > Thanks! We'll be in touch soon.
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 |
3 | * ...
4 |
5 | ## Does this introduce a breaking change?
6 |
7 | ```
8 | [ ] Yes
9 | [ ] No
10 | ```
11 |
12 | ## Pull Request Type
13 | What kind of change does this Pull Request introduce?
14 |
15 |
16 | ```
17 | [ ] Bugfix
18 | [ ] Feature
19 | [ ] Code style update (formatting, local variables)
20 | [ ] Refactoring (no functional changes, no api changes)
21 | [ ] Documentation content changes
22 | [ ] Other... Please describe:
23 | ```
24 |
25 | ## How to Test
26 | * Get the code
27 |
28 | ```
29 | git clone [repo-address]
30 | cd [repo-name]
31 | git checkout [branch-name]
32 | npm install
33 | ```
34 |
35 | * Test the code
36 |
37 | ```
38 | ```
39 |
40 | ## What to Check
41 | Verify that the following are valid
42 | * ...
43 |
44 | ## Other Information
45 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-functions.yml:
--------------------------------------------------------------------------------
1 | name: Build and deploy dotnet 7 app to Azure Function App
2 |
3 | on:
4 | push:
5 | # branches:
6 | # - main
7 | # workflow_dispatch:
8 |
9 | # CONFIGURATION
10 | # For help, go to https://github.com/Azure/Actions
11 | #
12 | # 1. Set up the following secrets in your repository:
13 | # AZURE_FUNCTIONAPP_PUBLISH_PROFILE
14 | #
15 | # 2. Change these variables for your configuration:
16 | env:
17 | AZURE_FUNCTIONAPP_NAME: amsv3functionsxxxxxxxxxxxxx # set this to your application's name
18 | AZURE_FUNCTIONAPP_PACKAGE_PATH: 'Functions' # set this to the path to your web app project, set to '.' to use repository root
19 | DOTNET_VERSION: '7.0.x' # set this to the dotnet version to use
20 |
21 | jobs:
22 | build-and-deploy:
23 | runs-on: windows-latest
24 | environment: dev
25 | steps:
26 | - name: 'Checkout GitHub Action'
27 | uses: actions/checkout@v3
28 |
29 | - name: Setup DotNet ${{ env.DOTNET_VERSION }} Environment
30 | uses: actions/setup-dotnet@v3
31 | with:
32 | dotnet-version: ${{ env.DOTNET_VERSION }}
33 |
34 | - name: 'Resolve Project Dependencies Using Dotnet'
35 | shell: pwsh
36 | run: |
37 | pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}'
38 | dotnet build --configuration Release --p:OutputPath=./output
39 | popd
40 |
41 | - name: 'Run Azure Functions Action'
42 | uses: Azure/functions-action@v1
43 | id: fa
44 | with:
45 | app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
46 | package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/output'
47 | publish-profile: ${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }}
48 |
49 | # For more samples to get started with GitHub Action workflows to deploy to Azure, refer to https://github.com/Azure/actions-workflow-samples
50 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Media Services v3 Functions for .NET Core Changelog
2 |
3 |
4 | # x.y.z (yyyy-mm-dd)
5 |
6 | *Features*
7 | * ...
8 |
9 | *Bug Fixes*
10 | * ...
11 |
12 | *Breaking Changes*
13 | * ...
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Media Services v3 Functions for .NET Core
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
6 |
7 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
8 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
9 | provided by the bot. You will only need to do this once across all repos using our CLA.
10 |
11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
14 |
15 | - [Code of Conduct](#coc)
16 | - [Issues and Bugs](#issue)
17 | - [Feature Requests](#feature)
18 | - [Submission Guidelines](#submit)
19 |
20 | ## Code of Conduct
21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
22 |
23 | ## Found an Issue?
24 | If you find a bug in the source code or a mistake in the documentation, you can help us by
25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can
26 | [submit a Pull Request](#submit-pr) with a fix.
27 |
28 | ## Want a Feature?
29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub
30 | Repository. If you would like to *implement* a new feature, please submit an issue with
31 | a proposal for your work first, to be sure that we can use it.
32 |
33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
34 |
35 | ## Submission Guidelines
36 |
37 | ### Submitting an Issue
38 | Before you submit an issue, search the archive, maybe your question was already answered.
39 |
40 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
41 | Help us to maximize the effort we can spend fixing issues and adding new
42 | features, by not reporting duplicate issues. Providing the following information will increase the
43 | chances of your issue being dealt with quickly:
44 |
45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
46 | * **Version** - what version is affected (e.g. 0.1.2)
47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
48 | * **Browsers and Operating System** - is this a problem with all browsers?
49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps
50 | * **Related Issues** - has a similar issue been reported before?
51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
52 | causing the problem (line of code or commit)
53 |
54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new].
55 |
56 | ### Submitting a Pull Request (PR)
57 | Before you submit your Pull Request (PR) consider the following guidelines:
58 |
59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR
60 | that relates to your submission. You don't want to duplicate effort.
61 |
62 | * Make your changes in a new git fork:
63 |
64 | * Commit your changes using a descriptive commit message
65 | * Push your fork to GitHub:
66 | * In GitHub, create a pull request
67 | * If we suggest changes then:
68 | * Make the required updates.
69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
70 |
71 | ```shell
72 | git rebase master -i
73 | git push -f
74 | ```
75 |
76 | That's it! Thank you for your contribution!
77 |
--------------------------------------------------------------------------------
/Encoding/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/Encoding/Encoding.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2035
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Encoding", "Encoding\Encoding.csproj", "{3C581F91-6B42-4B8F-BD24-63BCF6E38088}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {9DD4FB65-B89B-466F-82C7-F83CE3BF1085}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Encoding/Encoding/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/Encoding/Encoding/Encoding.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp3.1
4 | v3
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | PreserveNewest
13 |
14 |
15 | PreserveNewest
16 | Never
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | PreserveNewest
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Encoding/Encoding/Helpers/ConfigWrapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Configuration;
3 |
4 | namespace Encoding.Helpers
5 | {
6 | public class ConfigWrapper
7 | {
8 | private readonly IConfiguration _config;
9 |
10 | public ConfigWrapper(IConfiguration config, string azureRegion = null)
11 | {
12 | _config = config;
13 | AzureRegionCode = azureRegion ?? _config["AzureRegion"];
14 | }
15 |
16 | public string SubscriptionId => _config["SubscriptionId"];
17 |
18 | public string ResourceGroupFinalName => _config["ResourceGroupFinalName"];
19 |
20 | public string ResourceGroup => _config["ResourceGroup"] + (string.IsNullOrEmpty(ResourceGroupFinalName) ? AzureRegionCode : "");
21 |
22 | public string AccountName => _config["AccountName"] + AzureRegionCode;
23 |
24 | public string AadTenantId => _config["AadTenantId"];
25 |
26 | public string AadClientId => _config["AadClientId"];
27 |
28 | public string AadSecret => _config["AadSecret"];
29 |
30 | public Uri ArmAadAudience => _config["ArmAadAudience"] != null ? new Uri(_config["ArmAadAudience"]) : null;
31 |
32 | public Uri AadEndpoint => _config["AadEndpoint"] != null ? new Uri(_config["AadEndpoint"]) : null;
33 |
34 | public Uri ArmEndpoint => _config["ArmEndpoint"] != null ? new Uri(_config["ArmEndpoint"]) : null;
35 |
36 | public string Region
37 | {
38 | get
39 | {
40 | if (AzureRegionCode == null)
41 | return _config["Region"];
42 | switch (AzureRegionCode) // codes as defined in AMS Streaming Endpoint hostname - to be completed
43 | {
44 | case "euno":
45 | case "no":
46 | return "North Europe";
47 |
48 | case "euwe":
49 | case "we":
50 | return "West Europe";
51 |
52 | default:
53 | return _config["Region"];
54 | }
55 | }
56 | }
57 |
58 | public string AzureRegionCode { get; }
59 |
60 | public string LiveIngestAccessToken => _config["LiveIngestAccessToken"];
61 |
62 | public string IrdetoUserName => _config["IrdetoUserName"];
63 |
64 | public string IrdetoPassword => _config["IrdetoPassword"];
65 |
66 | public string IrdetoAccountId => _config["IrdetoAccountId"];
67 |
68 | public string IrdetoSoapService => _config["IrdetoSoapService"];
69 |
70 | public string IrdetoPlayReadyLAURL => _config["IrdetoPlayReadyLAURL"];
71 |
72 | public string IrdetoWidevineLAURL => _config["IrdetoWidevineLAURL"];
73 |
74 | public string IrdetoFairPlayLAURL => _config["IrdetoFairPlayLAURL"];
75 |
76 | public string IrdetoFairPlayCertificateUrl => _config["IrdetoFairPlayCertificateUrl"];
77 |
78 | }
79 | }
--------------------------------------------------------------------------------
/Encoding/Encoding/Helpers/HelpersBasic.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.Extensions.Logging;
5 | using Newtonsoft.Json.Linq;
6 |
7 | namespace Encoding.Helpers
8 | {
9 | internal class HelpersBasic
10 | {
11 | public static IActionResult ReturnErrorException(ILogger log, Exception ex, string prefixMessage = null)
12 | {
13 | var message = "";
14 |
15 | return ReturnErrorException(log,
16 | (prefixMessage == null ? string.Empty : prefixMessage + " : ") + ex.Message + message);
17 | }
18 |
19 | public static IActionResult ReturnErrorException(ILogger log, string message, string region = null)
20 | {
21 | LogError(log, message, region);
22 | return new BadRequestObjectResult(
23 | new JObject
24 | {
25 | {"success", false},
26 | {"errorMessage", message},
27 | {
28 | "operationsVersion",
29 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString()
30 | }
31 | }.ToString());
32 | }
33 |
34 | public static void LogError(ILogger log, string message, string azureRegion = null)
35 | {
36 | log.LogError((azureRegion != null ? "[" + azureRegion + "] " : "") + message);
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/Encoding/Encoding/Helpers/copyBlobHelpers.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v2 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using System;
8 | using System.Threading;
9 | using System.IO;
10 | using Microsoft.WindowsAzure.Storage;
11 | using Microsoft.WindowsAzure.Storage.Blob;
12 | using Microsoft.WindowsAzure.Storage.Auth;
13 | using Microsoft.Azure.WebJobs.Host;
14 | using System.Threading.Tasks;
15 | using System.Collections.Generic;
16 | using Microsoft.Extensions.Logging;
17 |
18 | namespace Encoding.Helpers
19 | {
20 | public class CopyBlobHelpers
21 | {
22 |
23 | static public async void CopyBlobAsync(CloudBlob sourceBlob, CloudBlob destinationBlob)
24 | {
25 | var signature = sourceBlob.GetSharedAccessSignature(new SharedAccessBlobPolicy
26 | {
27 | Permissions = SharedAccessBlobPermissions.Read,
28 | SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24)
29 | });
30 | await destinationBlob.StartCopyAsync(new Uri(sourceBlob.Uri.AbsoluteUri + signature));
31 | }
32 |
33 | static public CloudBlobContainer GetCloudBlobContainer(string storageAccountName, string storageAccountKey, string containerName)
34 | {
35 |
36 | CloudStorageAccount sourceStorageAccount = new CloudStorageAccount(new StorageCredentials(storageAccountName, storageAccountKey), true);
37 |
38 | CloudBlobClient sourceCloudBlobClient = sourceStorageAccount.CreateCloudBlobClient();
39 |
40 | return sourceCloudBlobClient.GetContainerReference(containerName);
41 |
42 | }
43 |
44 | }
45 |
46 | }
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Encoding/Encoding/host.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/Encoding/Encoding/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true",
5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet"
6 | }
7 | }
--------------------------------------------------------------------------------
/Encoding/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | services: media-services,functions
3 | platforms: dotnetcore
4 | author: xpouyat
5 | ---
6 |
7 | # Ffmpeg encoding with an Azure function
8 |
9 | This Visual Studio 2019 Solution exposes an Azure Function that encodes an Azure Storage blob with ffmpeg. [Azure Functions Premium plan](https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan
10 | ) is recommended.
11 |
12 | This Functions code is based on Azure Functions v3.
13 |
14 | ## Fork and download a copy
15 |
16 | If not already done : fork the repo, download a local copy.
17 |
18 | ## Ffmpeg
19 |
20 | Download ffmpeg from the Internet and copy ffmpeg.exe in \Encoding\Encoding\ffmpeg folder.
21 | In Visual Studio, open the file properties, "Build action" should be "Content", with "Copy to Output Direcotry" set to "Copy if newer".
22 |
23 | ## Publish the function to Azure
24 |
25 | Open the solution with Visual Studio and publish the functions to Azure.
26 | It is recommended to use a **premium plan** to avoid functions timeout (Premium gives you 30 min and a more powerfull host).
27 | It is possible to [unbound run duration](https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan#longer-run-duration).
28 |
29 | JSON input body of the function :
30 |
31 | ```json
32 | {
33 | "sasInputUrl":"https://mysasurlofthesourceblob",
34 | "sasOutputUrl":"https://mysasurlofthedestinationblob",
35 | "ffmpegArguments" : " -i {input} {output} -y"
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/Functions/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-dotnettools.csharp"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/Functions/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Attach to .NET Functions",
6 | "type": "coreclr",
7 | "request": "attach",
8 | "processId": "${command:azureFunctions.pickProcess}",
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/Functions/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": "bin/Release/net7.0/publish",
3 | "azureFunctions.projectLanguage": "C#",
4 | "azureFunctions.projectRuntime": "~4",
5 | "debug.internalConsoleOptions": "neverOpen",
6 | "azureFunctions.preDeployTask": "publish (functions)"
7 | }
--------------------------------------------------------------------------------
/Functions/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "clean (functions)",
6 | "command": "dotnet",
7 | "args": [
8 | "clean",
9 | "/property:GenerateFullPaths=true",
10 | "/consoleloggerparameters:NoSummary"
11 | ],
12 | "type": "process",
13 | "problemMatcher": "$msCompile"
14 | },
15 | {
16 | "label": "build (functions)",
17 | "command": "dotnet",
18 | "args": [
19 | "build",
20 | "/property:GenerateFullPaths=true",
21 | "/consoleloggerparameters:NoSummary"
22 | ],
23 | "type": "process",
24 | "dependsOn": "clean (functions)",
25 | "group": {
26 | "kind": "build",
27 | "isDefault": true
28 | },
29 | "problemMatcher": "$msCompile"
30 | },
31 | {
32 | "label": "clean release (functions)",
33 | "command": "dotnet",
34 | "args": [
35 | "clean",
36 | "--configuration",
37 | "Release",
38 | "/property:GenerateFullPaths=true",
39 | "/consoleloggerparameters:NoSummary"
40 | ],
41 | "type": "process",
42 | "problemMatcher": "$msCompile"
43 | },
44 | {
45 | "label": "publish (functions)",
46 | "command": "dotnet",
47 | "args": [
48 | "publish",
49 | "--configuration",
50 | "Release",
51 | "/property:GenerateFullPaths=true",
52 | "/consoleloggerparameters:NoSummary"
53 | ],
54 | "type": "process",
55 | "dependsOn": "clean release (functions)",
56 | "problemMatcher": "$msCompile"
57 | },
58 | {
59 | "type": "func",
60 | "dependsOn": "build (functions)",
61 | "options": {
62 | "cwd": "${workspaceFolder}/bin/Debug/net7.0"
63 | },
64 | "command": "host start",
65 | "isBackground": true,
66 | "problemMatcher": "$func-dotnet-watch"
67 | }
68 | ]
69 | }
--------------------------------------------------------------------------------
/Functions/Common_Utils/AssetUtils.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Microsoft.Azure.Management.Media;
5 | using Microsoft.Azure.Management.Media.Models;
6 | using Microsoft.Extensions.Logging;
7 | using System.Threading.Tasks;
8 |
9 | namespace Common_Utils
10 | {
11 | public class AssetUtils
12 | {
13 | ///
14 | /// Creates an asset.
15 | ///
16 | /// The Media Services client.
17 | /// The name of the resource group within the Azure subscription.
18 | /// The Media Services account name.
19 | /// The asset name.
20 | /// The asset storage name.
21 | ///
22 | public static async Task CreateAssetAsync(IAzureMediaServicesClient client, ILogger log, string resourceGroupName, string accountName, string assetName, string storageAccountName = null, string description = null)
23 | {
24 | Asset asset;
25 | try
26 | {
27 | // Check if an Asset already exists
28 | asset = await client.Assets.GetAsync(resourceGroupName, accountName, assetName);
29 |
30 | // The asset already exists and we are going to overwrite it. In your application, if you don't want to overwrite
31 | // an existing asset, use an unique name.
32 | log.LogInformation($"Warning: The asset named {assetName} already exists. It will be overwritten by the function.");
33 |
34 | }
35 | catch (ErrorResponseException ex) when (ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
36 | {
37 | log.LogInformation("Creating an asset...");
38 | asset = new Asset(storageAccountName: storageAccountName);
39 | }
40 |
41 | if (description != null)
42 | {
43 | asset.Description = description;
44 | }
45 |
46 | return await client.Assets.CreateOrUpdateAsync(resourceGroupName, accountName, assetName, asset);
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/Functions/Common_Utils/Authentication.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Azure.Core;
5 | using Azure.Identity;
6 | using Microsoft.Azure.Management.Media;
7 | using Microsoft.Rest;
8 | using System;
9 | using System.Threading.Tasks;
10 |
11 | namespace Common_Utils
12 | {
13 | public class Authentication
14 | {
15 | public static readonly string TokenType = "Bearer";
16 |
17 | private static readonly Lazy _msiCredential = new(() =>
18 | {
19 | // https://docs.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet
20 | // Using DefaultAzureCredential allows for local dev by setting environment variables for the current user, provided said user
21 | // has the necessary credentials to perform the operations the MSI of the Function app needs in order to do its work. Including
22 | // interactive credentials will allow browser-based login when developing locally.
23 |
24 | return new DefaultAzureCredential(includeInteractiveCredentials: true);
25 | });
26 |
27 | ///
28 | /// Creates the AzureMediaServicesClient object based on the credentials
29 | /// supplied in local configuration file or from other types of authentication.
30 | ///
31 | /// The param is of type ConfigWrapper, which reads values from local configuration file.
32 | /// A task.
33 | //
34 | public static async Task CreateMediaServicesClientAsync(ConfigWrapper config)
35 | {
36 | string[] scopes = new[] { config.ArmAadAudience + "/.default" };
37 | TokenCredential tokenCred = _msiCredential.Value;
38 | AccessToken accesToken = await tokenCred.GetTokenAsync(new TokenRequestContext(scopes), new System.Threading.CancellationToken());
39 | ServiceClientCredentials credentials = new TokenCredentials(accesToken.Token, TokenType);
40 | return new AzureMediaServicesClient(config.ArmEndpoint, credentials)
41 | {
42 | SubscriptionId = config.SubscriptionId
43 | };
44 | }
45 | //
46 | }
47 | }
--------------------------------------------------------------------------------
/Functions/Common_Utils/ConfigUtils.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Microsoft.Extensions.Configuration;
5 | using System;
6 | using System.IO;
7 |
8 | namespace Common_Utils
9 | {
10 | ///
11 | /// This class is used to load the configuration and settings
12 | ///
13 | public static class ConfigUtils
14 | {
15 | public static ConfigWrapper GetConfig()
16 | {
17 | // If Visual Studio is used, let's read the .env file which should be in the root folder (same folder than the solution .sln file).
18 | // Same code will work in VS Code, but VS Code uses also launch.json to get the .env file.
19 | // You can create this ".env" file by saving the "sample.env" file as ".env" file and fill it with the right values.
20 | try
21 | {
22 | Load(".env");
23 | }
24 | catch
25 | {
26 |
27 | }
28 |
29 | ConfigWrapper config = new(new ConfigurationBuilder()
30 | .SetBasePath(Directory.GetCurrentDirectory())
31 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
32 | .AddEnvironmentVariables() // parses the values from the optional .env file at the solution root
33 | .Build());
34 |
35 | // For Azure.Identity environment credential
36 | // see https://docs.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet
37 | Environment.SetEnvironmentVariable("AZURE_TENANT_ID", config.AadTenantId);
38 | Environment.SetEnvironmentVariable("AZURE_CLIENT_ID", config.AadClientId);
39 | Environment.SetEnvironmentVariable("AZURE_CLIENT_SECRET", config.AadSecret);
40 |
41 | return config;
42 | }
43 |
44 |
45 | ///
46 | /// Loads the .env file and stores the values as variables
47 | ///
48 | ///
49 | private static void Load(string envFileName)
50 | {
51 | // let's find the root folder where the .env file can be found
52 | var rootPath = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)))));
53 | var filePath = Path.Combine(rootPath, envFileName);
54 | // let's remove file://
55 | filePath = new Uri(filePath).LocalPath;
56 |
57 | if (!File.Exists(filePath))
58 | return;
59 |
60 | foreach (var line in File.ReadAllLines(filePath))
61 | {
62 | if (line.StartsWith("#"))
63 | {
64 | // It's a comment
65 | continue;
66 | }
67 |
68 | var parts = line.Split(
69 | '=',
70 | 2,
71 | StringSplitOptions.RemoveEmptyEntries);
72 |
73 | if (parts.Length != 2)
74 | continue;
75 |
76 | var p0 = parts[0].Trim();
77 | var p1 = parts[1].Trim();
78 |
79 | if (p1.StartsWith("\""))
80 | {
81 | p1 = p1[1..^1];
82 | }
83 |
84 | Environment.SetEnvironmentVariable(p0, p1);
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Functions/Common_Utils/ConfigWrapper.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Microsoft.Extensions.Configuration;
5 | using System;
6 |
7 | namespace Common_Utils
8 | {
9 | ///
10 | /// This class reads values from local configuration file resources/conf/appsettings.json.
11 | /// Please change the configuration using your account information. For more information, see
12 | /// https://docs.microsoft.com/azure/media-services/latest/access-api-cli-how-to. For security
13 | /// reasons, do not check in the configuration file to source control.
14 | ///
15 | public class ConfigWrapper
16 | {
17 | private readonly IConfiguration _config;
18 |
19 | public ConfigWrapper(IConfiguration config)
20 | {
21 | _config = config;
22 | }
23 |
24 | public string SubscriptionId
25 | {
26 | get { return _config["AZURE_SUBSCRIPTION_ID"]; }
27 | }
28 |
29 | public string ResourceGroup
30 | {
31 | get { return _config["AZURE_RESOURCE_GROUP"]; }
32 | }
33 |
34 | public string AccountName
35 | {
36 | get { return _config["AZURE_MEDIA_SERVICES_ACCOUNT_NAME"]; }
37 | }
38 |
39 | public string AadTenantId
40 | {
41 | get { return _config["AZURE_TENANT_ID"]; }
42 | }
43 |
44 | public string AadClientId
45 | {
46 | get { return _config["AZURE_CLIENT_ID"]; }
47 | }
48 |
49 | public string AadSecret
50 | {
51 | get { return _config["AZURE_CLIENT_SECRET"]; }
52 | }
53 |
54 | public Uri ArmAadAudience
55 | {
56 | get { return new Uri(_config["AZURE_ARM_TOKEN_AUDIENCE"]); }
57 | }
58 |
59 | public Uri AadEndpoint
60 | {
61 | get { return new Uri(_config["AZURE_AAD_ENDPOINT"]); }
62 | }
63 |
64 | public Uri ArmEndpoint
65 | {
66 | get { return new Uri(_config["AZURE_ARM_ENDPOINT"]); }
67 | }
68 | }
69 | }
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Functions/Common_Utils/HttpRequest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.Functions.Worker.Http;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System.Net;
5 |
6 | namespace Common_Utils
7 | {
8 | class HttpRequest
9 | {
10 | private static readonly JsonSerializerSettings SerializerSettings = new() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.Indented };
11 |
12 | ///
13 | /// Generates the response with HttpStatusCode.OK and JSON body
14 | ///
15 | /// HttpRequestData object
16 | /// Object to serialize
17 | ///
18 | public static HttpResponseData ResponseOk(HttpRequestData req, object data, HttpStatusCode statuscode = HttpStatusCode.OK)
19 | {
20 | var response = req.CreateResponse(statuscode);
21 | response.Headers.Add("Content-Type", "application/json");
22 | if (data != null)
23 | {
24 | response.WriteString(JsonConvert.SerializeObject(data, SerializerSettings));
25 | }
26 | return response;
27 | }
28 |
29 | ///
30 | /// Generates the response with HttpStatusCode.BadRequest and JSON body
31 | ///
32 | /// HttpRequestData object
33 | /// Error message
34 | ///
35 | public static HttpResponseData ResponseBadRequest(HttpRequestData req, string message)
36 | {
37 | dynamic dataNotOk = new JObject();
38 | dataNotOk.errorMessage = message;
39 |
40 | var response = req.CreateResponse(HttpStatusCode.BadRequest);
41 | response.Headers.Add("Content-Type", "application/json");
42 | var stringJson = JsonConvert.SerializeObject(dataNotOk, SerializerSettings);
43 | response.WriteString((string)stringJson);
44 | return response;
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/Functions/Common_Utils/JobUtils.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Microsoft.Azure.Management.Media;
5 | using Microsoft.Azure.Management.Media.Models;
6 | using Microsoft.Extensions.Logging;
7 | using System.Threading.Tasks;
8 |
9 | namespace Common_Utils
10 | {
11 | public class JobUtils
12 | {
13 | ///
14 | /// Submits a request to Media Services to apply the specified Transform to a given input video.
15 | ///
16 | /// The Media Services client.
17 | /// Function logger.
18 | /// The name of the resource group within the Azure subscription.
19 | /// The Media Services account name.
20 | /// The name of the transform.
21 | /// The (unique) name of the job.
22 | /// The input of the job
23 | /// The (unique) name of the output asset that will store the result of the encoding job.
24 | public static async Task SubmitJobAsync(
25 | IAzureMediaServicesClient client,
26 | ILogger log,
27 | string resourceGroupName,
28 | string accountName,
29 | string transformName,
30 | string jobName,
31 | JobInput jobInput,
32 | string outputAssetName
33 | )
34 | {
35 | JobOutput[] jobOutputs =
36 | {
37 | new JobOutputAsset(outputAssetName),
38 | };
39 |
40 | // In this example, we are assuming that the job name is unique.
41 | //
42 | // If you already have a job with the desired name, use the Jobs.Get method
43 | // to get the existing job. In Media Services v3, Get methods on entities returns null
44 | // if the entity doesn't exist (a case-insensitive check on the name).
45 | Job job;
46 | try
47 | {
48 | log.LogInformation("Creating a job...");
49 | job = await client.Jobs.CreateAsync(
50 | resourceGroupName,
51 | accountName,
52 | transformName,
53 | jobName,
54 | new Job
55 | {
56 | Input = jobInput,
57 | Outputs = jobOutputs,
58 | });
59 |
60 | }
61 | catch (ErrorResponseException ex)
62 | {
63 | log.LogError(
64 | $"ERROR: API call failed with error code '{ex.Body.Error.Code}' and message '{ex.Body.Error.Message}'.");
65 |
66 | throw;
67 | }
68 |
69 | return job;
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/Functions/Common_Utils/LogUtils.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System;
3 |
4 | namespace Common_Utils
5 | {
6 | class LogUtils
7 | {
8 | public static string LogError(ILogger log, Exception ex, string err)
9 | {
10 | log.LogError(err);
11 | log.LogError($"{ex.Message}");
12 | return err.TrimEnd() + " " + ex.Message;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Functions/DeleteAsset.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using System;
5 | using System.IO;
6 | using System.Text.Json;
7 | using System.Threading.Tasks;
8 | using Common_Utils;
9 | using Microsoft.Azure.Functions.Worker;
10 | using Microsoft.Azure.Functions.Worker.Http;
11 | using Microsoft.Azure.Management.Media;
12 | using Microsoft.Azure.Management.Media.Models;
13 | using Microsoft.Extensions.Logging;
14 | using Newtonsoft.Json;
15 |
16 | namespace Functions
17 | {
18 | public static class DeleteAsset
19 | {
20 | ///
21 | /// Data to pass as an input to the function
22 | ///
23 | private class RequestBodyModel
24 | {
25 | ///
26 | /// Name of the asset to delete.
27 | /// Mandatory.
28 | ///
29 | [JsonProperty("assetName")]
30 | public string AssetName { get; set; }
31 | }
32 |
33 | ///
34 | /// Function which deletes an asset.
35 | ///
36 | ///
37 | ///
38 | ///
39 | [Function("DeleteAsset")]
40 | public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext)
41 | {
42 | var log = executionContext.GetLogger("DeleteAsset");
43 | log.LogInformation("C# HTTP trigger function processed a request.");
44 |
45 | // Get request body data.
46 | string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
47 | var data = (RequestBodyModel)JsonConvert.DeserializeObject(requestBody, typeof(RequestBodyModel));
48 |
49 | // Return bad request if asset name is not passed in
50 | if (data.AssetName == null)
51 | {
52 | return HttpRequest.ResponseBadRequest(req, "Please pass asset name in the request body");
53 | }
54 |
55 | ConfigWrapper config = ConfigUtils.GetConfig();
56 |
57 | IAzureMediaServicesClient client;
58 | try
59 | {
60 | client = await Authentication.CreateMediaServicesClientAsync(config);
61 | log.LogInformation("AMS Client created.");
62 | }
63 | catch (Exception e)
64 | {
65 | if (e.Source.Contains("ActiveDirectory"))
66 | {
67 | log.LogError("TIP: Make sure that you have filled out the appsettings.json file before running this sample.");
68 | }
69 | log.LogError($"{e.Message}");
70 |
71 | return HttpRequest.ResponseBadRequest(req, e.Message);
72 | }
73 |
74 | // Set the polling interval for long running operations to 2 seconds.
75 | // The default value is 30 seconds for the .NET client SDK
76 | client.LongRunningOperationRetryTimeout = 2;
77 |
78 | try
79 | {
80 | // let's delete the asset
81 | await client.Assets.DeleteAsync(config.ResourceGroup, config.AccountName, data.AssetName);
82 | log.LogInformation($"Asset '{data.AssetName}' deleted.");
83 | }
84 | catch (ErrorResponseException ex)
85 | {
86 | return HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when deleting the asset."));
87 | }
88 |
89 | return HttpRequest.ResponseOk(req, null);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Functions/Functions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | v4
5 | Exe
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | PreserveNewest
20 |
21 |
22 | PreserveNewest
23 | Never
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Functions/Functions.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31424.327
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Functions", "Functions.csproj", "{DAEB4FF5-CA3E-4106-8060-F6999174B92E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {DAEB4FF5-CA3E-4106-8060-F6999174B92E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {DAEB4FF5-CA3E-4106-8060-F6999174B92E}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {DAEB4FF5-CA3E-4106-8060-F6999174B92E}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {DAEB4FF5-CA3E-4106-8060-F6999174B92E}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {CC03063C-062A-490A-9868-F61EBD404F44}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Functions/Models/ManifestSegmentData.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | namespace Common_Utils
5 | {
6 | public class ManifestSegmentData
7 | {
8 | public ulong timestamp;
9 | public bool calculated; // it means the timestamp has been calculated from previous
10 | public bool timestamp_mismatch; // if there is a mismatch
11 | }
12 | }
--------------------------------------------------------------------------------
/Functions/Models/ManifestTimingData.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace Common_Utils
8 | {
9 | public class ManifestTimingData
10 | {
11 | public TimeSpan AssetDuration { get; set; }
12 | public ulong TimestampOffset { get; set; }
13 | public long? TimeScale { get; set; }
14 | public bool IsLive { get; set; }
15 | public bool Error { get; set; }
16 | public List TimestampList { get; set; }
17 | public ulong TimestampEndLastChunk { get; set; }
18 | public bool DiscontinuityDetected { get; set; }
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/Functions/Program.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Microsoft.Extensions.Hosting;
5 |
6 | namespace Functions
7 | {
8 | public class Program
9 | {
10 | public static void Main()
11 | {
12 | var host = new HostBuilder()
13 | .ConfigureFunctionsWorkerDefaults()
14 | .Build();
15 |
16 | host.Run();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Functions/azuredeploy2.parameter.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "appName": {
6 | "value": "GEN-UNIQUE"
7 | },
8 | "functionKey": {
9 | "value" : "GEN-UNIQUE"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Functions/azuredeploy2mi.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "appName": {
6 | "type": "string",
7 | "defaultValue": "[concat('amsv3functions', uniqueString(resourceGroup().id))]",
8 | "metadata": {
9 | "description": "The name of the Function application to be deployed. The name will automatically be made unique on deployment, all lowercase letters or numbers with no spaces."
10 | }
11 | },
12 | "mediaServicesAccountSubscriptionId": {
13 | "type": "string",
14 | "defaultValue": "[subscription().subscriptionId]",
15 | "metadata": {
16 | "description": "Subscription Id for your Media Services account."
17 | }
18 | },
19 | "mediaServicesAccountResourceGroup": {
20 | "type": "string",
21 | "defaultValue": "",
22 | "metadata": {
23 | "description": "Resource Group Name of your Media Services account."
24 | }
25 | },
26 | "mediaServicesAccountName": {
27 | "type": "string",
28 | "defaultValue": "",
29 | "metadata": {
30 | "description": "Your Media Services account name."
31 | }
32 | },
33 | "mediaServicesAccountAzureActiveDirectoryTenantId": {
34 | "type": "string",
35 | "defaultValue": "",
36 | "metadata": {
37 | "description": "Azure Active Directory tenant Id or domain of your Media Services account."
38 | }
39 | }
40 | },
41 | "variables": {
42 | "functionAppName": "[parameters('appName')]",
43 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]",
44 | "hostingPlanName": "[parameters('appName')]"
45 | },
46 | "resources": [
47 | {
48 | "type": "Microsoft.Storage/storageAccounts",
49 | "name": "[variables('storageAccountName')]",
50 | "apiVersion": "2021-04-01",
51 | "location": "[resourceGroup().location]",
52 | "comments": "This storage account is used by the functions.",
53 | "sku": {
54 | "name": "Standard_LRS"
55 | },
56 | "kind": "Storage"
57 | },
58 | {
59 | "type": "Microsoft.Web/serverfarms",
60 | "name": "[variables('hostingPlanName')]",
61 | "apiVersion": "2020-12-01",
62 | "location": "[resourceGroup().location]",
63 | "comments": "This hosting plan is created to deploy the function app and set the billing sku tier",
64 | "sku": {
65 | "name": "Y1",
66 | "tier": "Dynamic"
67 | },
68 | "properties": {
69 | "name": "[variables('hostingPlanName')]",
70 | "computeMode": "Dynamic"
71 | }
72 | },
73 | {
74 | "type": "Microsoft.Web/sites",
75 | "name": "[variables('functionAppName')]",
76 | "apiVersion": "2020-12-01",
77 | "location": "[resourceGroup().location]",
78 | "identity": {
79 | "type": "SystemAssigned"
80 | },
81 | "comments": "This function app depends on the Media Services account and storage account",
82 | "dependsOn": [
83 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
84 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
85 | ],
86 | "kind": "functionapp",
87 | "properties": {
88 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
89 | "siteConfig": {
90 | "appSettings": [
91 | {
92 | "name": "AzureWebJobsStorage",
93 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value)]"
94 | },
95 | {
96 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
97 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value)]"
98 | },
99 | {
100 | "name": "WEBSITE_CONTENTSHARE",
101 | "value": "[toLower(variables('functionAppName'))]"
102 | },
103 | {
104 | "name": "FUNCTIONS_EXTENSION_VERSION",
105 | "value": "~4"
106 | },
107 | {
108 | "name": "FUNCTIONS_WORKER_RUNTIME",
109 | "value": "dotnet-isolated"
110 | },
111 | {
112 | "name": "WEBSITE_RUN_FROM_PACKAGE",
113 | "value": "1"
114 | },
115 | {
116 | "name": "AZURE_SUBSCRIPTION_ID",
117 | "value": "[parameters('mediaServicesAccountSubscriptionId')]"
118 | },
119 | {
120 | "name": "AZURE_RESOURCE_GROUP",
121 | "value": "[parameters('mediaServicesAccountResourceGroup')]"
122 | },
123 | {
124 | "name": "AZURE_MEDIA_SERVICES_ACCOUNT_NAME",
125 | "value": "[parameters('mediaServicesAccountName')]"
126 | },
127 | {
128 | "name": "AZURE_TENANT_ID",
129 | "value": "[parameters('mediaServicesAccountAzureActiveDirectoryTenantId')]"
130 | },
131 | {
132 | "name": "AZURE_AAD_ENDPOINT",
133 | "value": "https://login.microsoftonline.com"
134 | },
135 | {
136 | "name": "AZURE_ARM_ENDPOINT",
137 | "value": "https://management.azure.com/"
138 | },
139 | {
140 | "name": "AZURE_ARM_TOKEN_AUDIENCE",
141 | "value": "https://management.core.windows.net/"
142 | }
143 | ]
144 | }
145 | }
146 | }
147 | ],
148 | "outputs": {}
149 | }
--------------------------------------------------------------------------------
/Functions/azuredeploy2mi.parameter.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "appName": {
6 | "value": "GEN-UNIQUE"
7 | },
8 | "functionKey": {
9 | "value" : "GEN-UNIQUE"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Functions/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingSettings": {
6 | "isEnabled": true,
7 | "excludedTypes": "Request"
8 | }
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/Functions/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "",
5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
6 | }
7 | }
--------------------------------------------------------------------------------
/Images/DrawingAzureFunctionsNet5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/DrawingAzureFunctionsNet5.png
--------------------------------------------------------------------------------
/Images/DrawingAzureFunctionsNet5.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/DrawingAzureFunctionsNet5.vsdx
--------------------------------------------------------------------------------
/Images/azfunc5appinstance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5appinstance.png
--------------------------------------------------------------------------------
/Images/azfunc5deploy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5deploy.png
--------------------------------------------------------------------------------
/Images/azfunc5deployappsettings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5deployappsettings.png
--------------------------------------------------------------------------------
/Images/azfunc5geturl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5geturl.png
--------------------------------------------------------------------------------
/Images/azfunc5geturlportal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5geturlportal.png
--------------------------------------------------------------------------------
/Images/azfunc5githubactions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5githubactions.png
--------------------------------------------------------------------------------
/Images/azfunc5postman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5postman.png
--------------------------------------------------------------------------------
/Images/azfunc5postmandeployed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5postmandeployed.png
--------------------------------------------------------------------------------
/Images/azfunc5roleassignment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5roleassignment.png
--------------------------------------------------------------------------------
/Images/azfunc5runvscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/Images/azfunc5runvscode.png
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-dotnettools.csharp"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Attach to .NET Functions",
6 | "type": "coreclr",
7 | "request": "attach",
8 | "processId": "${command:azureFunctions.pickProcess}"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": "LiveAndVodDRMOperationsV3/bin/Release/net5.0/publish",
3 | "azureFunctions.projectLanguage": "C#",
4 | "azureFunctions.projectRuntime": "~3",
5 | "debug.internalConsoleOptions": "neverOpen",
6 | "azureFunctions.preDeployTask": "publish (functions)"
7 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "clean (functions)",
6 | "command": "dotnet",
7 | "args": [
8 | "clean",
9 | "/property:GenerateFullPaths=true",
10 | "/consoleloggerparameters:NoSummary"
11 | ],
12 | "type": "process",
13 | "problemMatcher": "$msCompile",
14 | "options": {
15 | "cwd": "${workspaceFolder}/LiveAndVodDRMOperationsV3"
16 | }
17 | },
18 | {
19 | "label": "build (functions)",
20 | "command": "dotnet",
21 | "args": [
22 | "build",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "type": "process",
27 | "dependsOn": "clean (functions)",
28 | "group": {
29 | "kind": "build",
30 | "isDefault": true
31 | },
32 | "problemMatcher": "$msCompile",
33 | "options": {
34 | "cwd": "${workspaceFolder}/LiveAndVodDRMOperationsV3"
35 | }
36 | },
37 | {
38 | "label": "clean release (functions)",
39 | "command": "dotnet",
40 | "args": [
41 | "clean",
42 | "--configuration",
43 | "Release",
44 | "/property:GenerateFullPaths=true",
45 | "/consoleloggerparameters:NoSummary"
46 | ],
47 | "type": "process",
48 | "problemMatcher": "$msCompile",
49 | "options": {
50 | "cwd": "${workspaceFolder}/LiveAndVodDRMOperationsV3"
51 | }
52 | },
53 | {
54 | "label": "publish (functions)",
55 | "command": "dotnet",
56 | "args": [
57 | "publish",
58 | "--configuration",
59 | "Release",
60 | "/property:GenerateFullPaths=true",
61 | "/consoleloggerparameters:NoSummary"
62 | ],
63 | "type": "process",
64 | "dependsOn": "clean release (functions)",
65 | "problemMatcher": "$msCompile",
66 | "options": {
67 | "cwd": "${workspaceFolder}/LiveAndVodDRMOperationsV3"
68 | }
69 | },
70 | {
71 | "type": "func",
72 | "dependsOn": "build (functions)",
73 | "options": {
74 | "cwd": "${workspaceFolder}/LiveAndVodDRMOperationsV3/bin/Debug/net5.0"
75 | },
76 | "command": "host start",
77 | "isBackground": true,
78 | "problemMatcher": "$func-dotnet-watch"
79 | }
80 | ]
81 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/Images/overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/LiveAndVodDRMOperationsV3/Images/overview.png
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2035
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveAndVodDRMOperationsV3", "LiveAndVodDRMOperationsV3\LiveAndVodDRMOperationsV3.csproj", "{3C581F91-6B42-4B8F-BD24-63BCF6E38088}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {3C581F91-6B42-4B8F-BD24-63BCF6E38088}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {9DD4FB65-B89B-466F-82C7-F83CE3BF1085}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Helpers/ConfigWrapper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using System;
3 |
4 | namespace LiveDrmOperationsV3.Helpers
5 | {
6 | public class ConfigWrapper
7 | {
8 | private readonly IConfiguration _config;
9 |
10 | public ConfigWrapper(IConfiguration config, string azureRegion = null)
11 | {
12 | _config = config;
13 | AzureRegionCode = azureRegion ?? _config["AzureRegion"];
14 | }
15 |
16 | public string SubscriptionId => _config["SubscriptionId"];
17 |
18 | public string ResourceGroupFinalName => _config["ResourceGroupFinalName"];
19 |
20 | public string ResourceGroup => _config["ResourceGroup"] + (string.IsNullOrEmpty(ResourceGroupFinalName) ? AzureRegionCode : "");
21 |
22 | public string AccountName => _config["AccountName"] + AzureRegionCode;
23 |
24 | public string AadTenantId => _config["AadTenantId"];
25 |
26 | public string AadClientId => _config["AadClientId"];
27 |
28 | public string AadClientSecret => _config["AadClientSecret"] ?? _config["AadSecret"];
29 |
30 | public Uri ArmAadAudience => _config["ArmAadAudience"] != null ? new Uri(_config["ArmAadAudience"]) : null;
31 |
32 | public Uri AadEndpoint => _config["AadEndpoint"] != null ? new Uri(_config["AadEndpoint"]) : null;
33 |
34 | public Uri ArmEndpoint => _config["ArmEndpoint"] != null ? new Uri(_config["ArmEndpoint"]) : null;
35 |
36 | public string Region
37 | {
38 | get
39 | {
40 | if (AzureRegionCode == null)
41 | return _config["Region"];
42 | switch (AzureRegionCode) // codes as defined in AMS Streaming Endpoint hostname - to be completed
43 | {
44 | case "euno":
45 | case "no":
46 | return "North Europe";
47 |
48 | case "euwe":
49 | case "we":
50 | return "West Europe";
51 |
52 | default:
53 | return _config["Region"];
54 | }
55 | }
56 | }
57 |
58 | public string AzureRegionCode { get; }
59 |
60 | public string LiveIngestAccessToken => _config["LiveIngestAccessToken"];
61 |
62 | public string IrdetoUserName => _config["IrdetoUserName"];
63 |
64 | public string IrdetoPassword => _config["IrdetoPassword"];
65 |
66 | public string IrdetoAccountId => _config["IrdetoAccountId"];
67 |
68 | public string IrdetoSoapService => _config["IrdetoSoapService"];
69 |
70 | public string IrdetoPlayReadyLAURL => _config["IrdetoPlayReadyLAURL"];
71 |
72 | public string IrdetoWidevineLAURL => _config["IrdetoWidevineLAURL"];
73 |
74 | public string IrdetoFairPlayLAURL => _config["IrdetoFairPlayLAURL"];
75 |
76 | public string IrdetoFairPlayCertificateUrl => _config["IrdetoFairPlayCertificateUrl"];
77 |
78 | }
79 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Helpers/copyBlobHelpers.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v2 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using Microsoft.Azure.Storage;
8 | using Microsoft.Azure.Storage.Auth;
9 | using Microsoft.Azure.Storage.Blob;
10 | using System;
11 |
12 | namespace LiveDrmOperationsV3.Helpers
13 | {
14 | public class CopyBlobHelpers
15 | {
16 |
17 | static public async void CopyBlobAsync(CloudBlob sourceBlob, CloudBlob destinationBlob)
18 | {
19 | var signature = sourceBlob.GetSharedAccessSignature(new SharedAccessBlobPolicy
20 | {
21 | Permissions = SharedAccessBlobPermissions.Read,
22 | SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24)
23 | });
24 | await destinationBlob.StartCopyAsync(new Uri(sourceBlob.Uri.AbsoluteUri + signature));
25 | }
26 |
27 | static public CloudBlobContainer GetCloudBlobContainer(string storageAccountName, string storageAccountKey, string containerName)
28 | {
29 |
30 | CloudStorageAccount sourceStorageAccount = new CloudStorageAccount(new StorageCredentials(storageAccountName, storageAccountKey), true);
31 |
32 | CloudBlobClient sourceCloudBlobClient = sourceStorageAccount.CreateCloudBlobClient();
33 |
34 | return sourceCloudBlobClient.GetContainerReference(containerName);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net5.0
4 | v3
5 |
6 |
7 |
8 |
9 |
10 |
11 | PreserveNewest
12 | Never
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | PreserveNewest
26 |
27 |
28 | PreserveNewest
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/LiveFunctions/delete-streaming-locator.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // delete-streaming-locator - This function delete a a streaming locator (to unpublish)
5 | //
6 | /*
7 | ```c#
8 | Input :
9 | {
10 | "streamingLocatorName": "locator-c03de9fe-dd04",
11 | "azureRegion": "euwe" or "we" or "euno" or "no" or "euwe,euno" or "we,no"
12 | // optional. If this value is set, then the AMS account name and resource group are appended with this value.
13 | // Resource name is not changed if "ResourceGroupFinalName" in app settings is to a value non empty.
14 | // This feature is useful if you want to manage several AMS account in different regions.
15 | // if two regions are sepecified using a comma as a separator, then the function will operate in the two regions at the same time
16 | // Note: the service principal must work with all this accounts
17 | }
18 |
19 | Output:
20 | {
21 | "success": true,
22 | "errorMessage" : "",
23 | "operationsVersion": "1.0.0.5"
24 | }
25 |
26 |
27 | ```
28 | */
29 |
30 | using LiveDrmOperationsV3.Helpers;
31 | using Microsoft.AspNetCore.Http;
32 | using Microsoft.AspNetCore.Mvc;
33 | using Microsoft.Azure.Management.Media;
34 | using Microsoft.Azure.WebJobs;
35 | using Microsoft.Azure.WebJobs.Extensions.Http;
36 | using Microsoft.Extensions.Configuration;
37 | using Microsoft.Extensions.Logging;
38 | using Newtonsoft.Json;
39 | using Newtonsoft.Json.Linq;
40 | using System;
41 | using System.Collections.Generic;
42 | using System.IO;
43 | using System.Linq;
44 | using System.Reflection;
45 | using System.Threading.Tasks;
46 |
47 | namespace LiveDrmOperationsV3
48 | {
49 | public static class DeleteStreamingLocator
50 | {
51 | [FunctionName("delete-streaming-locator")]
52 | public static async Task Run(
53 | [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
54 | HttpRequest req, ILogger log)
55 | {
56 | MediaServicesHelpers.LogInformation(log, "C# HTTP trigger function processed a request.");
57 |
58 | dynamic data;
59 | try
60 | {
61 | data = JsonConvert.DeserializeObject(new StreamReader(req.Body).ReadToEnd());
62 | }
63 | catch (Exception ex)
64 | {
65 | return IrdetoHelpers.ReturnErrorException(log, ex);
66 | }
67 |
68 | var streamingLocatorName = (string)data.streamingLocatorName;
69 | if (streamingLocatorName == null)
70 | return IrdetoHelpers.ReturnErrorException(log, "Error - please pass streamingLocatorName in the JSON");
71 |
72 |
73 | // Azure region management
74 | var azureRegions = new List();
75 | if ((string)data.azureRegion != null)
76 | {
77 | azureRegions = ((string)data.azureRegion).Split(',').ToList();
78 | }
79 | else
80 | {
81 | azureRegions.Add((string)null);
82 | }
83 |
84 | foreach (var region in azureRegions)
85 | {
86 | ConfigWrapper config = null;
87 |
88 | try
89 | {
90 | config = new ConfigWrapper(new ConfigurationBuilder()
91 | .SetBasePath(Directory.GetCurrentDirectory())
92 | .AddEnvironmentVariables()
93 | .Build(),
94 | region
95 | );
96 | }
97 | catch (Exception ex)
98 | {
99 | return IrdetoHelpers.ReturnErrorException(log, ex);
100 | }
101 |
102 | MediaServicesHelpers.LogInformation(log, "config loaded.", region);
103 | MediaServicesHelpers.LogInformation(log, "connecting to AMS account : " + config.AccountName, region);
104 |
105 | var client = await MediaServicesHelpers.CreateMediaServicesClientAsync(config);
106 | // Set the polling interval for long running operations to 2 seconds.
107 | // The default value is 30 seconds for the .NET client SDK
108 | client.LongRunningOperationRetryTimeout = 2;
109 |
110 | try
111 | {
112 | client.StreamingLocators.Delete(config.ResourceGroup, config.AccountName, streamingLocatorName);
113 |
114 | }
115 | catch (Exception ex)
116 | {
117 | return IrdetoHelpers.ReturnErrorException(log, ex);
118 | }
119 |
120 | }
121 |
122 | var response = new JObject
123 | {
124 | {"streamingLocatorName", streamingLocatorName},
125 | {"success", true},
126 | {
127 | "operationsVersion",
128 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString()
129 | }
130 | };
131 |
132 | return new OkObjectResult(
133 | response.ToString()
134 | );
135 |
136 | }
137 | }
138 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/LiveFunctions/ping.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // Ping - This function returns 200 (used by trafic manager)
5 | //
6 |
7 |
8 | using Microsoft.Azure.WebJobs;
9 | using Microsoft.Azure.WebJobs.Extensions.Http;
10 | using Microsoft.Extensions.Logging;
11 | using System.Net;
12 | using System.Net.Http;
13 | using System.Threading.Tasks;
14 |
15 | namespace LiveDrmOperationsV3
16 | {
17 | public static class Ping
18 | {
19 | [FunctionName("ping")]
20 | public static async Task Run(
21 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
22 | HttpRequestMessage req, ILogger log)
23 | {
24 | return req.CreateResponse(HttpStatusCode.OK);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/LiveFunctions/update-settings.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // update-settings - This function creates a document in Cosmos to store the settings for a live event (optional)
5 | //
6 | /*
7 | ```c#
8 | Input :
9 | {
10 | "liveEventName": "TEST",
11 | "urn": "urn:customer:video:e8927fcf-e1a0-0001-7edd-1eaaaaaa",
12 | "vendor": "Customer",
13 | "baseStorageName": "storagename",
14 | "archiveWindowLength": 10,
15 | "useStaticHostname": true,
16 | "lowLatency": false,
17 | "liveEventInputACL": [
18 | "192.168.0.0/24",
19 | "86.246.149.14"
20 | ],
21 | "liveEventPreviewACL": [
22 | "192.168.0.0/24",
23 | "86.246.149.14"
24 | ],
25 | "playerJSONData": null
26 | }
27 |
28 | Output:
29 | {
30 | "success": true,
31 | "errorMessage" : "",
32 | "operationsVersion": "1.0.0.5"
33 | }
34 |
35 |
36 | ```
37 | */
38 |
39 | using LiveDrmOperationsV3.Helpers;
40 | using LiveDrmOperationsV3.Models;
41 | using Microsoft.AspNetCore.Http;
42 | using Microsoft.AspNetCore.Mvc;
43 | using Microsoft.Azure.WebJobs;
44 | using Microsoft.Azure.WebJobs.Extensions.Http;
45 | using Microsoft.Extensions.Configuration;
46 | using Microsoft.Extensions.Logging;
47 | using Newtonsoft.Json;
48 | using Newtonsoft.Json.Linq;
49 | using System;
50 | using System.IO;
51 | using System.Reflection;
52 | using System.Threading.Tasks;
53 |
54 | namespace LiveDrmOperationsV3
55 | {
56 | public static class UpdateSettings
57 | {
58 | // This version registers keys in irdeto backend. For FairPlay and rpv3
59 |
60 | [FunctionName("update-settings")]
61 | public static async Task Run(
62 | [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
63 | HttpRequest req, ILogger log)
64 | {
65 | log.LogInformation("C# HTTP trigger function processed a request.");
66 |
67 | bool success = true;
68 |
69 | var requestBody = new StreamReader(req.Body).ReadToEnd();
70 |
71 | LiveEventSettingsInfo settings = null;
72 | try
73 | {
74 | settings = (LiveEventSettingsInfo)JsonConvert.DeserializeObject(requestBody,
75 | typeof(LiveEventSettingsInfo));
76 | }
77 | catch (Exception ex)
78 | {
79 | return IrdetoHelpers.ReturnErrorException(log, ex);
80 | }
81 |
82 |
83 | ConfigWrapper config = null;
84 | try
85 | {
86 | config = new ConfigWrapper(
87 | new ConfigurationBuilder()
88 | .SetBasePath(Directory.GetCurrentDirectory())
89 | .AddEnvironmentVariables()
90 | .Build()
91 | );
92 | }
93 | catch (Exception ex)
94 | {
95 | return IrdetoHelpers.ReturnErrorException(log, ex);
96 | }
97 |
98 | log.LogInformation("config loaded.");
99 |
100 | try
101 | {
102 | if (!await CosmosHelpers.CreateOrUpdateSettingsDocument(settings))
103 | {
104 | log.LogWarning("Cosmos access not configured or error.");
105 | success = false;
106 | }
107 | }
108 | catch (Exception ex)
109 | {
110 | return IrdetoHelpers.ReturnErrorException(log, ex);
111 | }
112 |
113 | var response = new JObject
114 | {
115 | {"Success", success},
116 | {
117 | "OperationsVersion",
118 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString()
119 | }
120 | };
121 |
122 | return new OkObjectResult(
123 | response.ToString()
124 | );
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/ManifestTemplate/manifest.ism:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Models/BaseModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace LiveDRMOperationsV3.Models
4 | {
5 | // Base model for other models.
6 | // It implements a partitionKey property always set to the same value - used for Cosmos
7 | public class BaseModel
8 | {
9 | public static string DefaultPartitionValue = "live";
10 |
11 | [JsonProperty(PropertyName = "partitionKey", NullValueHandling = NullValueHandling.Ignore)]
12 | public virtual string PartitionKey => DefaultPartitionValue;
13 | }
14 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Models/GeneralOutputInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Reflection;
3 | using LiveDrmOperationsV3.Helpers;
4 | using LiveDRMOperationsV3.Models;
5 | using Microsoft.Azure.Management.Media.Models;
6 | using Newtonsoft.Json;
7 |
8 | namespace LiveDrmOperationsV3.Models
9 | {
10 |
11 | public class Drm
12 | {
13 | [JsonProperty("type")] public string Type { get; set; }
14 |
15 | [JsonProperty("licenseUrl")] public string LicenseUrl { get; set; }
16 |
17 | [JsonProperty("certificateUrl", NullValueHandling = NullValueHandling.Ignore)] public string CertificateUrl { get; set; }
18 |
19 | [JsonProperty("protocols")] public List Protocols { get; set; }
20 | }
21 |
22 | public class UrlEntry
23 | {
24 | [JsonProperty("protocol")] public string Protocol { get; set; }
25 |
26 | [JsonProperty("url")] public string Url { get; set; }
27 | }
28 |
29 | public class StreamingLocatorEntry
30 | {
31 | [JsonProperty("streamingLocatorName")] public string StreamingLocatorName { get; set; }
32 |
33 | [JsonProperty("streamingPolicyName")] public string StreamingPolicyName { get; set; }
34 |
35 | [JsonProperty("cencKeyId")] public string CencKeyId { get; set; }
36 |
37 | [JsonProperty("cbcsKeyId")] public string CbcsKeyId { get; set; }
38 |
39 | [JsonProperty("drm")] public List Drm { get; set; }
40 |
41 | [JsonProperty("urls")] public List Urls { get; set; }
42 | }
43 |
44 | public class LiveOutputEntry
45 | {
46 | [JsonProperty("liveOutputName")] public string LiveOutputName { get; set; }
47 |
48 | [JsonProperty("archiveWindowLength")] public int ArchiveWindowLength { get; set; }
49 |
50 | [JsonProperty("assetName")] public string AssetName { get; set; }
51 |
52 | [JsonProperty("assetStorageAccountName")] public string AssetStorageAccountName { get; set; }
53 |
54 | [JsonProperty("resourceState")] public LiveOutputResourceState? ResourceState { get; set; }
55 |
56 | [JsonProperty("streamingLocators")] public List StreamingLocators { get; set; }
57 | }
58 |
59 | public class LiveEventEntry : BaseModel
60 | {
61 | [JsonProperty("liveEventName")] public string LiveEventName { get; set; }
62 |
63 | [JsonProperty("resourceState")] public string ResourceState { get; set; }
64 |
65 | [JsonProperty("useStaticHostname")] public bool? UseStaticHostname { get; set; }
66 |
67 | [JsonProperty("amsAccountName")] public string AMSAccountName { get; set; }
68 |
69 | [JsonProperty("region")] public string Region { get; set; }
70 |
71 | [JsonProperty("resourceGroup")] public string ResourceGroup { get; set; }
72 |
73 | [JsonProperty(PropertyName = "lowLatency")] public bool? LowLatency { get; set; }
74 |
75 | [JsonProperty(PropertyName = "id")] public string Id => (AMSAccountName + ":" + LiveEventName).ToLower();
76 |
77 | [JsonProperty("input")] public List Input { get; set; }
78 |
79 | [JsonProperty("inputACL")] public List InputACL { get; set; }
80 |
81 | [JsonProperty("preview")] public List Preview { get; set; }
82 |
83 | [JsonProperty("previewACL")] public List PreviewACL { get; set; }
84 |
85 | [JsonProperty("liveOutputs")] public List LiveOutputs { get; set; }
86 | }
87 |
88 | public class GeneralOutputInfo
89 | {
90 | [JsonProperty("success")] public bool Success { get; set; }
91 |
92 | [JsonProperty("operationsVersion")]
93 | public string OperationsCodeVersion =>
94 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString();
95 |
96 | [JsonProperty("liveEvents")] public List LiveEvents { get; set; }
97 | }
98 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Models/LiveEventSettingsInfo.cs:
--------------------------------------------------------------------------------
1 | using LiveDRMOperationsV3.Models;
2 | using Microsoft.Azure.Management.Media.Models;
3 | using Newtonsoft.Json;
4 | using System.Collections.Generic;
5 |
6 | namespace LiveDrmOperationsV3.Models
7 | {
8 | public class RedirectorStreamingEndpointData
9 | {
10 | [JsonProperty("streamingEndpointName")] public string StreamingEndpointName { get; set; }
11 |
12 | [JsonProperty("percentage")] public int Percentage { get; set; }
13 | }
14 |
15 | public class Dvr
16 | {
17 | [JsonProperty("enableByDefault")] public bool EnableByDefault { get; set; }
18 |
19 | [JsonProperty("allowed")] public bool Allowed { get; set; }
20 | }
21 |
22 | public class ResourceListOrder
23 | {
24 | [JsonProperty("dvr")] public Dvr Dvr { get; set; }
25 |
26 | [JsonProperty("encryptionSorted")] public bool EncryptionSorted { get; set; }
27 |
28 | [JsonProperty("defaultAzureRegion")] public string DefaultAzureRegion { get; set; }
29 | }
30 |
31 | public class PlayerJSONData
32 | {
33 | [JsonProperty("quality")] public string Quality { get; set; }
34 |
35 | [JsonProperty("encoding")] public string Encoding { get; set; }
36 |
37 | [JsonProperty("presentation")] public string Presentation { get; set; }
38 |
39 | [JsonProperty("live")] public bool Live { get; set; }
40 |
41 | [JsonProperty("mediaContainer")] public string MediaContainer { get; set; }
42 |
43 | [JsonProperty("audioCodec")] public string AudioCodec { get; set; }
44 |
45 | [JsonProperty("videoCodec")] public string VideoCodec { get; set; }
46 |
47 | [JsonProperty("resourceListOrder")] public ResourceListOrder ResourceListOrder { get; set; }
48 | }
49 |
50 | public class LiveEventSettingsInfo : BaseModel
51 | {
52 | public LiveEventSettingsInfo()
53 | {
54 | ArchiveWindowLength = 10;
55 | UseStaticHostname = false;
56 | InputProtocol = LiveEventInputProtocol.FragmentedMP4;
57 | AutoStart = true;
58 | LowLatency = false;
59 | }
60 |
61 | [JsonProperty("liveEventName")] public string LiveEventName { get; set; }
62 |
63 | [JsonProperty("urn")] public string Urn { get; set; }
64 |
65 | [JsonProperty("vendor")] public string Vendor { get; set; }
66 |
67 | [JsonProperty("akamaiHostname")] public string AkamaiHostname { get; set; }
68 |
69 | [JsonProperty("baseStorageName")] public string BaseStorageName { get; set; }
70 |
71 | [JsonIgnore] public string StorageName { get; set; }
72 |
73 | [JsonProperty("archiveWindowLength")] public int ArchiveWindowLength { get; set; }
74 |
75 | [JsonProperty("useStaticHostname")] public bool UseStaticHostname { get; set; }
76 |
77 | [JsonProperty("lowLatency")] public bool LowLatency { get; set; }
78 |
79 | [JsonIgnore] public LiveEventInputProtocol InputProtocol { get; set; }
80 |
81 | [JsonIgnore] public bool AutoStart { get; set; }
82 |
83 | [JsonProperty("liveEventInputACL")] public IList LiveEventInputACL { get; set; }
84 |
85 | [JsonProperty("liveEventPreviewACL")] public IList LiveEventPreviewACL { get; set; }
86 |
87 | [JsonProperty("playerJSONData")] public PlayerJSONData PlayerJSONData { get; set; }
88 |
89 | [JsonProperty("redirectorStreamingEndpointData")] public List RedirectorStreamingEndpointData { get; set; }
90 |
91 | [JsonProperty(PropertyName = "id")] public string Id => LiveEventName.ToLower();
92 | }
93 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Models/StreamingPolicy.cs:
--------------------------------------------------------------------------------
1 | using LiveDRMOperationsV3.Models;
2 | using Newtonsoft.Json;
3 |
4 | namespace LiveDrmOperationsV3.Models
5 | {
6 | public class StreamingPolicyInfo : BaseModel
7 | {
8 | [JsonProperty("streamingPolicyName")] public string StreamingPolicyName { get; set; }
9 |
10 | [JsonProperty("amsAccountName")] public string AMSAccountName { get; set; }
11 |
12 | [JsonProperty(PropertyName = "id")] public string Id => (AMSAccountName + ":" + Partition).ToLower();
13 |
14 | [JsonProperty(PropertyName = "partitionKey", NullValueHandling = NullValueHandling.Ignore)]
15 | public override string PartitionKey => Partition;
16 |
17 | public StreamingPolicyInfo(bool isVod)
18 | {
19 | Partition = isVod ? AssetEntry.DefaultPartitionValue : BaseModel.DefaultPartitionValue;
20 | }
21 |
22 | [JsonIgnore] private string Partition { get; set; }
23 | }
24 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Models/VodAssetInfo.cs:
--------------------------------------------------------------------------------
1 | using LiveDRMOperationsV3.Models;
2 | using Newtonsoft.Json;
3 | using System.Collections.Generic;
4 | using System.Reflection;
5 |
6 | namespace LiveDrmOperationsV3.Models
7 | {
8 |
9 | public partial class AssetEntry : BaseModel
10 | {
11 | public static readonly string DateFormat = "yyyyMMddTHH:mm:ssZ";
12 |
13 | public new static string DefaultPartitionValue = "vod";
14 |
15 | [JsonProperty("assetName")]
16 | public string AssetName { get; set; }
17 |
18 | [JsonProperty("assetStorageAccountName", NullValueHandling = NullValueHandling.Ignore)]
19 | public string AssetStorageAccountName { get; set; }
20 |
21 | [JsonProperty("streamingLocators", NullValueHandling = NullValueHandling.Ignore)]
22 | public List StreamingLocators { get; set; }
23 |
24 | [JsonProperty("amsAccountName", NullValueHandling = NullValueHandling.Ignore)]
25 | public string AMSAccountName { get; set; }
26 |
27 | [JsonProperty("region", NullValueHandling = NullValueHandling.Ignore)]
28 | public string Region { get; set; }
29 |
30 | [JsonProperty("resourceGroup", NullValueHandling = NullValueHandling.Ignore)]
31 | public string ResourceGroup { get; set; }
32 |
33 | [JsonProperty("urn", NullValueHandling = NullValueHandling.Ignore)]
34 | public string Urn { get; set; }
35 |
36 | [JsonProperty("createdTime", NullValueHandling = NullValueHandling.Ignore)]
37 | public string CreatedTime { get; set; }
38 |
39 | [JsonProperty("semaphore", NullValueHandling = NullValueHandling.Ignore)]
40 | public VodSemaphore Semaphore { get; set; }
41 |
42 | [JsonIgnore] public string ContentId { get; set; }
43 |
44 | [JsonProperty(PropertyName = "id", NullValueHandling = NullValueHandling.Ignore)]
45 | public string Id => (AMSAccountName + ":" + AssetName).ToLower();
46 |
47 | [JsonProperty(PropertyName = "partitionKey", NullValueHandling = NullValueHandling.Ignore)]
48 | public override string PartitionKey => (ContentId ?? "UND").ToLower();
49 | }
50 |
51 |
52 | public partial class AssetEntry
53 | {
54 | public static AssetEntry FromJson(string json) => JsonConvert.DeserializeObject(json, Converter.Settings);
55 | }
56 |
57 |
58 | public class VodAssetInfo
59 | {
60 | [JsonProperty("success")] public bool Success { get; set; }
61 |
62 | [JsonProperty("operationsVersion")]
63 | public string OperationsCodeVersion =>
64 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString();
65 |
66 | [JsonProperty("assets")] public List Assets { get; set; }
67 | }
68 |
69 | public class VodAssetInfoSimple
70 | {
71 | [JsonProperty("success")] public bool Success { get; set; }
72 |
73 | [JsonProperty("operationsVersion")]
74 | public string OperationsCodeVersion =>
75 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString();
76 |
77 | [JsonProperty("createdLocatorName")] public string CreatedLocatorName { get; set; }
78 |
79 | [JsonProperty("createdLocatorPath")] public string CreatedLocatorPath { get; set; }
80 |
81 | [JsonProperty("asset")] public AssetEntry Asset { get; set; }
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/Models/VodResource.cs:
--------------------------------------------------------------------------------
1 | using LiveDRMOperationsV3.Models;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace LiveDrmOperationsV3.Models
7 | {
8 |
9 | public partial class DrmList
10 | {
11 |
12 | [JsonProperty("type")]
13 | public string Type { get; set; }
14 |
15 | [JsonProperty("licenseUrl")]
16 | public string LicenseUrl { get; set; }
17 |
18 | [JsonProperty("certificateUrl")]
19 | public string CertificateUrl { get; set; }
20 | }
21 |
22 | public partial class Subtitles
23 | {
24 | [JsonProperty("url")]
25 | public string Url { get; set; }
26 |
27 | [JsonProperty("textLanguage")]
28 | public string TextLanguage { get; set; }
29 |
30 | [JsonProperty("textTitle")]
31 | public string TextTitle { get; set; }
32 | }
33 |
34 | public partial class ResourceList
35 | {
36 |
37 | [JsonProperty("url")]
38 | public string Url { get; set; }
39 |
40 | [JsonProperty("drmList")]
41 | public IList DrmList { get; set; }
42 |
43 | [JsonProperty("quality")]
44 | public string Quality { get; set; }
45 |
46 | [JsonProperty("protocol")]
47 | public string Protocol { get; set; }
48 |
49 | [JsonProperty("mimeType")]
50 | public string MimeType { get; set; }
51 |
52 | [JsonProperty("videoCodec")]
53 | public string VideoCodec { get; set; }
54 |
55 | [JsonProperty("audioCodec")]
56 | public string AudioCodec { get; set; }
57 |
58 | [JsonProperty("mediaContainer")]
59 | public string MediaContainer { get; set; }
60 |
61 | [JsonProperty("live")]
62 | public bool Live { get; set; }
63 |
64 | [JsonProperty("subTitles")]
65 | public IList SubTitles { get; set; }
66 | }
67 |
68 | public partial class VodResource : BaseModel
69 | {
70 |
71 | [JsonProperty("urn")]
72 | public string Urn { get; set; }
73 |
74 | [JsonProperty("resourceList")]
75 | public IList ResourceList { get; set; }
76 |
77 | [JsonIgnore] public AssetEntry MainAsset { get; set; }
78 |
79 | [JsonProperty(PropertyName = "id", NullValueHandling = NullValueHandling.Ignore)]
80 | public string Id => ((new Uri(ResourceList[0]?.Url)).Host + "-" + (new Uri(ResourceList[0]?.Url)).Segments[1].Replace("/", string.Empty)).ToLower();
81 |
82 | [JsonProperty(PropertyName = "partitionKey", NullValueHandling = NullValueHandling.Ignore)]
83 | public override string PartitionKey => (MainAsset.Semaphore.DrmContentId ?? DefaultPartitionValue).ToLower();
84 |
85 | public new static string DefaultPartitionValue = "vod";
86 | }
87 |
88 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/VodFunctions/generate-resource.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // generate-resource - This function generate a json structure to be used by the customer in their backend
5 | //
6 | /*
7 | ```c#
8 | Input :
9 | {
10 | "assetMain": ,
11 | "assetSub": ,
12 | "cdnHostName": "customertest-euwe.akamaized.net"
13 | }
14 |
15 |
16 | Output:
17 |
18 | ```
19 | */
20 |
21 | using LiveDrmOperationsV3.Helpers;
22 | using LiveDrmOperationsV3.Models;
23 | using Microsoft.AspNetCore.Http;
24 | using Microsoft.AspNetCore.Mvc;
25 | using Microsoft.Azure.WebJobs;
26 | using Microsoft.Azure.WebJobs.Extensions.Http;
27 | using Microsoft.Extensions.Logging;
28 | using Newtonsoft.Json;
29 | using Newtonsoft.Json.Linq;
30 | using System;
31 | using System.Collections.Generic;
32 | using System.IO;
33 | using System.Linq;
34 | using System.Threading.Tasks;
35 |
36 | namespace LiveDrmOperationsV3
37 | {
38 | public static class generateresource
39 | {
40 | [FunctionName("generate-resource")]
41 | public static async Task Run(
42 | [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
43 | HttpRequest req, ILogger log)
44 | {
45 | log.LogInformation("C# HTTP trigger function processed a request.");
46 |
47 | dynamic data;
48 | try
49 | {
50 | data = JsonConvert.DeserializeObject(new StreamReader(req.Body).ReadToEnd());
51 | }
52 | catch (Exception ex)
53 | {
54 | return IrdetoHelpers.ReturnErrorException(log, ex);
55 | }
56 |
57 | AssetEntry assetEntry1 = null;
58 |
59 | if (data.assetMain != null)
60 | {
61 | assetEntry1 = ((JObject)data?.assetMain).ToObject();
62 | }
63 |
64 | AssetEntry assetEntry2 = null;
65 | if (data.assetSub != null)
66 | {
67 | assetEntry2 = ((JObject)data?.assetSub).ToObject();
68 | }
69 |
70 | string newHostName = (string)data.cdnHostName;
71 | if (string.IsNullOrWhiteSpace(newHostName)) newHostName = null;
72 |
73 | VodResource vodResource = new VodResource()
74 | {
75 | Urn = assetEntry1.Urn,
76 | ResourceList = new List(),
77 | MainAsset = assetEntry1
78 | };
79 |
80 |
81 | var subtitlesList = new List();
82 | if (assetEntry2 != null)
83 | {
84 | var locator2 = assetEntry2.StreamingLocators.FirstOrDefault();
85 | var subtitlesUrl = locator2?.Urls.Where(p => p.Protocol == "Download");
86 | var subtitlesSema = assetEntry2?.Semaphore.Files.Where(f => f.CopyToSubAsset);
87 |
88 | var query = from subInfo in subtitlesSema
89 | join sub in subtitlesUrl on subInfo.FileName equals (new Uri(sub.Url)).Segments[(new Uri(sub.Url)).Segments.Length - 1]
90 | select new Subtitles { Url = MediaServicesHelpers.UpdateHostNameIfNeeded(newHostName, sub.Url), TextLanguage = subInfo.TextLanguage, TextTitle = subInfo.TextTitle };
91 | subtitlesList = query.ToList();
92 | }
93 |
94 | var locator1 = assetEntry1.StreamingLocators.FirstOrDefault();
95 |
96 | var resDashCsf = new ResourceList()
97 | {
98 | Url = MediaServicesHelpers.UpdateHostNameIfNeeded(newHostName, locator1?.Urls.Where(u => u.Protocol == "DashCsf").FirstOrDefault()?.Url),
99 | Protocol = "DASH",
100 | MimeType = "application/dash+xml",
101 | VideoCodec = "H264",
102 | AudioCodec = "AAC",
103 | MediaContainer = "MP4",
104 | Quality = "SD",
105 | Live = false,
106 | DrmList = new List() {
107 | new DrmList(){ Type = "PlayReady", LicenseUrl =locator1?.Drm?.Where(d=> d.Type=="PlayReady").FirstOrDefault()?.LicenseUrl },
108 | new DrmList(){ Type = "Widevine", LicenseUrl =locator1?.Drm?.Where(d=> d.Type=="Widevine").FirstOrDefault()?.LicenseUrl }
109 | },
110 | SubTitles = subtitlesList
111 | };
112 |
113 | vodResource.ResourceList.Add(resDashCsf);
114 |
115 | var resHlsTs = new ResourceList()
116 | {
117 | Url = MediaServicesHelpers.UpdateHostNameIfNeeded(newHostName, locator1?.Urls.Where(u => u.Protocol == "HlsTs").FirstOrDefault()?.Url),
118 | Protocol = "HLS",
119 | MimeType = "application/x-mpegURL",
120 | VideoCodec = "H264",
121 | AudioCodec = "AAC",
122 | MediaContainer = "MP4",
123 | Quality = "SD",
124 | Live = false,
125 | DrmList = new List() {
126 | new DrmList(){
127 | Type = "FairPlay",
128 | LicenseUrl =locator1.Drm.Where(d=> d.Type=="FairPlay").FirstOrDefault().LicenseUrl,
129 | CertificateUrl = locator1.Drm.Where(d=> d.Type=="FairPlay").FirstOrDefault().CertificateUrl
130 | },
131 | },
132 | SubTitles = subtitlesList
133 | };
134 | vodResource.ResourceList.Add(resHlsTs);
135 |
136 |
137 | // let's write it to Cosmos
138 | if (!await CosmosHelpers.CreateOrUpdateVODResourceDocument(vodResource))
139 | log.LogWarning("Cosmos access not configured.");
140 |
141 |
142 | return new OkObjectResult(
143 | JsonConvert.SerializeObject(vodResource, Formatting.Indented)
144 | );
145 | }
146 | }
147 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/VodFunctions/list-assets-startwith.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // list-assets-startwith
5 | /*
6 | This function creates an empty asset.
7 |
8 |
9 | ```c#
10 | Input:
11 | {
12 | "assetNameStartsWith" : "movie-", //
13 | "azureRegion": "euwe" or "we" or "euno" or "no" or "euwe,euno" or "we,no"
14 | // optional. If this value is set, then the AMS account name and resource group are appended with this value.
15 | // Resource name is not changed if "ResourceGroupFinalName" in app settings is to a value non empty.
16 | // This feature is useful if you want to manage several AMS account in different regions.
17 | // if two regions are sepecified using a comma as a separator, then the function will operate in the two regions at the same time. With this function, the live event will be deleted from the two regions.
18 | // Note: the service principal must work with all this accounts
19 | }
20 |
21 |
22 | Output:
23 | {
24 | "success": true,
25 | "assetNames": [
26 | "92ccbf1edb-input-59894",
27 | "92ccbf1edb-input-59894-ContentAwareEncode-output-59894"
28 | ],
29 | "operationsVersion": "1.0.1.0"
30 | }
31 |
32 | ```
33 | */
34 |
35 | using LiveDrmOperationsV3.Helpers;
36 | using Microsoft.AspNetCore.Http;
37 | using Microsoft.AspNetCore.Mvc;
38 | using Microsoft.Azure.Management.Media;
39 | using Microsoft.Azure.Management.Media.Models;
40 | using Microsoft.Azure.WebJobs;
41 | using Microsoft.Azure.WebJobs.Extensions.Http;
42 | using Microsoft.Extensions.Configuration;
43 | using Microsoft.Extensions.Logging;
44 | using Microsoft.Rest.Azure.OData;
45 | using Newtonsoft.Json;
46 | using Newtonsoft.Json.Linq;
47 | using System;
48 | using System.Collections.Generic;
49 | using System.IO;
50 | using System.Linq;
51 | using System.Reflection;
52 | using System.Threading.Tasks;
53 |
54 |
55 | namespace LiveDrmOperationsV3
56 | {
57 | public static class ListAssetsStartwith
58 | {
59 | [FunctionName("list-assets-startwith")]
60 | public static async Task Run(
61 | [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
62 | HttpRequest req, ILogger log, Microsoft.Azure.WebJobs.ExecutionContext execContext)
63 | {
64 | MediaServicesHelpers.LogInformation(log, "C# HTTP trigger function processed a request.");
65 |
66 | dynamic data;
67 | try
68 | {
69 | data = JsonConvert.DeserializeObject(new StreamReader(req.Body).ReadToEnd());
70 | }
71 | catch (Exception ex)
72 | {
73 | return IrdetoHelpers.ReturnErrorException(log, ex);
74 | }
75 |
76 | var assetNameStartsWith = (string)data.assetNameStartsWith;
77 | if (assetNameStartsWith == null)
78 | return IrdetoHelpers.ReturnErrorException(log, "Error - please pass assetNameStartsWith in the JSON");
79 |
80 | List assets = new List();
81 |
82 | // Azure region management
83 | var azureRegions = new List();
84 | if ((string)data.azureRegion != null)
85 | {
86 | azureRegions = ((string)data.azureRegion).Split(',').ToList();
87 | }
88 | else
89 | {
90 | azureRegions.Add((string)null);
91 | }
92 |
93 |
94 | foreach (var region in azureRegions)
95 | {
96 | ConfigWrapper config = new ConfigWrapper(new ConfigurationBuilder()
97 | .SetBasePath(Directory.GetCurrentDirectory())
98 | .AddEnvironmentVariables()
99 | .Build(),
100 | region
101 | );
102 |
103 | MediaServicesHelpers.LogInformation(log, "config loaded.", region);
104 | MediaServicesHelpers.LogInformation(log, "connecting to AMS account : " + config.AccountName, region);
105 |
106 | var client = await MediaServicesHelpers.CreateMediaServicesClientAsync(config);
107 | // Set the polling interval for long running operations to 2 seconds.
108 | // The default value is 30 seconds for the .NET client SDK
109 | client.LongRunningOperationRetryTimeout = 2;
110 |
111 | MediaServicesHelpers.LogInformation(log, "asset name starts : " + assetNameStartsWith, region);
112 |
113 | try
114 | {
115 | ODataQuery query = new ODataQuery();
116 | string search = "'" + assetNameStartsWith + "'";
117 | query.Filter = "name gt " + search.Substring(0, search.Length - 2) + char.ConvertFromUtf32(char.ConvertToUtf32(search, search.Length - 2) - 1) + new string('z', 262 - search.Length) + "'" + " and name lt " + search.Substring(0, search.Length - 1) + new string('z', 262 - search.Length) + "'";
118 | query.OrderBy = "Properties/Created";
119 | var assetsResult = client.Assets.List(config.ResourceGroup, config.AccountName, query);
120 |
121 | assets = assetsResult.Select(a => a.Name).ToList();
122 | }
123 | catch (Exception ex)
124 | {
125 | return IrdetoHelpers.ReturnErrorException(log, ex);
126 | }
127 | }
128 |
129 | var response = new JObject
130 | {
131 | {"success", true},
132 | {"assetNames", new JArray(assets)},
133 | {
134 | "operationsVersion",
135 | AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Version.ToString()
136 | }
137 | };
138 |
139 | return new OkObjectResult(
140 | response
141 | );
142 | }
143 | }
144 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingExcludedTypes": "Request",
6 | "samplingSettings": {
7 | "isEnabled": true
8 | }
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LiveAndVodDRMOperationsV3/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true",
5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet",
6 | "AzureWebJobsDashboard": "UseDevelopmentStorage=true",
7 | "AadClientId": "value",
8 | "AadEndpoint": "https://login.microsoftonline.com",
9 | "AadSecret": "value",
10 | "AadTenantId": "value",
11 | "AccountName": "value",
12 | "ArmAadAudience": "https://management.core.windows.net/",
13 | "ArmEndpoint": "https://management.azure.com/",
14 | "Region": "value",
15 | "AzureRegion": "euwe",
16 | "ResourceGroup": "value",
17 | "ResourceGroupFinalName": "true",
18 | "SubscriptionId": "value",
19 | "IrdetoUserName": "value",
20 | "IrdetoPassword": "value",
21 | "IrdetoAccountId": "value",
22 | "IrdetoSoapService": "https://test.ott.irdeto.com/LiveDRMService/livedrmservice.asmx",
23 | "IrdetoPlayReadyLAURL": "https://test.ott.irdeto.com/licenseServer/playready/v1/customer/license?contentId={AlternativeMediaId}",
24 | "IrdetoWidevineLAURL": "https://test.ott.irdeto.com/licenseServer/widevine/v1/customer/license?contentId={AlternativeMediaId}",
25 | "IrdetoFairPlayLAURL": "skd://test.ott.irdeto.com/licenseServer/streaming/v1/customer/getckc?contentId={AlternativeMediaId}&keyId={ContentKeyId}",
26 | "IrdetoFairPlayCertificateUrl": "https://test.ott.irdeto.com/licenseServer/streaming/v1/customer/getcertificate?applicationId=stage",
27 | "LiveIngestAccessToken": "value",
28 | "CosmosDBAccountEndpoint": "value",
29 | "CosmosDBAccountKey": "value",
30 | "CosmosDB": "liveDRMStreaming",
31 | "CosmosCollectionSettings": "liveEventSettings",
32 | "CosmosCollectionOutputs": "liveEventOutputInfo",
33 | "CosmosCollectionVODAssets": "vodAssets",
34 | "CosmosCollectionStreamingPolicies": "streamingPolicies",
35 | "CosmosCollectionVODResources": "vodResources",
36 | "AllowClearStream": "true"
37 | }
38 | }
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LogicApps/preencodedasset-workflow-deploy.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/4f0d6a3e0de03777d8ce49b4a7721cc0b6255ccc/LiveAndVodDRMOperationsV3/LogicApps/preencodedasset-workflow-deploy.json
--------------------------------------------------------------------------------
/LiveAndVodDRMOperationsV3/LogicApps/semaphore-sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "encodedAsset": true,
3 | "transformName": "myTransform",
4 | "startTime": "20180214T13:00:00Z",
5 | "endTime": "20290214T13:00:00Z",
6 | "urn": "asset URN",
7 | "drmContentId": "vodMajor1",
8 | "clearStream": false,
9 | "files": [
10 | {
11 | "fileName": "video-400.mp4",
12 | "containsVideo": true,
13 | "containsAudio": true,
14 | "videoCodec":"H264",
15 | "audioCodec":"AAC",
16 | "mediaContainer": "MP4",
17 | "videoQuality": "SD"
18 | },
19 | {
20 | "fileName": "video-700.mp4",
21 | "containsVideo": true,
22 | "containsAudio": true,
23 | "audioLanguage": "deu",
24 | "audioTitle ": "German audio"
25 | },
26 | {
27 | "fileName": "video-1200.mp4",
28 | "containsVideo": true,
29 | "containsAudio": true,
30 | "audioLanguage": "eng"
31 | },
32 | {
33 | "fileName": "subtitle-de.vtt",
34 | "containsText": true,
35 | "language": "deu",
36 | "copyToSubAsset" : true
37 | },
38 | {
39 | "fileName": "subtitle-en.vtt",
40 | "containsText": true,
41 | "textLanguage": "eng",
42 | "textTitle": "English subtitles",
43 | "copyToSubAsset" : true
44 | },
45 | {
46 | "fileName": "audio-en.mp4",
47 | "containsAudio": true,
48 | "audioLanguage ": "eng"
49 | }
50 | ]
51 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - csharp
5 | products:
6 | - azure
7 | - azure-functions
8 | - azure-media-services
9 | name: "Azure Media Services v3 - Serverless Workflows with Azure Functions and Logic Apps"
10 | description: "Projects that show how to integrate Azure Media Services with Azure Functions and Azure Logic Apps."
11 | azureDeploy: https://raw.githubusercontent.com/Azure-Samples/media-services-v3-dotnet-core-functions-integration/master/azuredeploy.json
12 | ---
13 |
14 | # Azure Media Services v3 - Serverless Workflows with Azure Functions & Logic Apps
15 |
16 | **IMPORTANT NOTE : Azure Media Services have been retired on June 30, 2024. Please see the [retirement guide](https://learn.microsoft.com/azure/media-services/latest/azure-media-services-retirement).**
17 |
18 | This repository contains projects that show how to integrate Azure Media Services with Azure Functions & Azure Logic Apps.
19 | These Media Services Functions examples are based on AMS REST API v3 on Azure Functions v3. Most of the functions can also be used from Logic Apps.
20 |
21 | This repository can be accessed directly using .
22 |
23 | ## Contents
24 |
25 | | Folder | Description |
26 | |-------------|-------------|
27 | | [Functions](/Functions)|**Updated March 2023** This sample exposes Azure Functions based on .NET 7.0 using the latest Media Services, Azure Functions and Identity SDKs. Deployment is done with an ARM template and GitHub Actions.|
28 | | [Encoding](/Encoding)|The sample exposes an Azure Function that encodes an Azure Storage blob with ffmpeg. Azure Functions Premium plan is recommended.|
29 | | [LiveAndVodDRMOperationsV3](/LiveAndVodDRMOperationsV3)|The sample exposes several Azure functions that can be used to manage live streaming and VOD with DRM with Azure Media Services v3, using Irdeto back-end to deliver the licenses.|
30 | | [advanced-vod-workflow](/advanced-vod-workflow)|This project contains advanced VOD media workflow examples of using Azure Functions with Azure Media Services v3. The project includes several folders of sample Azure Functions for use with Azure Media Services that show workflows related to ingesting content directly from blob storage, encoding, and writing content back to blob storage.|
31 | | [logic-app-using-workflow-functions](/logic-app-using-workflow-functions)|This project contains Logic Apps that converts-to-media-asset, encodes and publishes media files that you upload in an Azure Storage. It relies on Azure Functions and Azure Media Services.|
32 |
33 | ## Prerequisites for a sample Logic Apps deployments
34 |
35 | ### 1. Create an Azure Media Services account
36 |
37 | Create a Media Services account in your subscription if don't have it already ([follow this article](https://docs.microsoft.com/en-us/azure/media-services/latest/create-account-howto?tabs=portal)).
38 |
39 | ### 2. Create a Service Principal
40 |
41 | Create a Service Principal and save the password. It will be needed in step #4. To do so, go to the API tab in the account ([follow this article](https://docs.microsoft.com/en-us/azure/media-services/latest/access-api-howto?tabs=portal)).
42 |
43 | ### 3. Make sure the AMS streaming endpoint is started
44 |
45 | To enable streaming, go to the Azure portal, select the Azure Media Services account which has been created, and start the default streaming endpoint.
46 |
47 | ### 4. Deploy the Azure functions
48 |
49 | For the 'Functions" project, do not use the link below. Please see the dedicated [Readme](/Functions/README.md).
50 |
51 | If not already done : fork the repo, deploy Azure Functions and select the right project (IMPORTANT!).
52 |
53 | Note : if you never provided your GitHub account in the Azure portal before, the continuous integration probably will probably fail and you won't see the functions. In that case, you need to setup it manually. Go to your Azure Function App / Deployment / Deployment Center. Select GitHub as a source and configure it to use your fork.
54 |
55 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fmedia-services-v3-dotnet-core-functions-integration%2Fmaster%2Fazuredeploy.json)
56 |
--------------------------------------------------------------------------------
/Tutorial/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.Hosting;
4 | using Microsoft.Azure.Functions.Worker.Configuration;
5 |
6 | namespace TestFuncVS
7 | {
8 | public class Program
9 | {
10 | public static void Main()
11 | {
12 | var host = new HostBuilder()
13 | .ConfigureFunctionsWorkerDefaults()
14 | .Build();
15 |
16 | host.Run();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Tutorial/README.md:
--------------------------------------------------------------------------------
1 | This project is used by the article
2 | https://docs.microsoft.com/en-us/azure/media-services/latest/integrate-azure-functions-dotnet-how-to
3 |
--------------------------------------------------------------------------------
/Tutorial/TestFuncVS.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net5.0
4 | v3
5 | Exe
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | PreserveNewest
18 |
19 |
20 | PreserveNewest
21 | Never
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Tutorial/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingSettings": {
6 | "isEnabled": true,
7 | "excludedTypes": "Request"
8 | }
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/advanced-vod-workflow/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-dotnettools.csharp"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Attach to .NET Functions",
6 | "type": "coreclr",
7 | "request": "attach",
8 | "processId": "${command:azureFunctions.pickProcess}"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp3.1/publish",
3 | "azureFunctions.projectLanguage": "C#",
4 | "azureFunctions.projectRuntime": "~3",
5 | "debug.internalConsoleOptions": "neverOpen",
6 | "azureFunctions.preDeployTask": "publish (functions)"
7 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "clean (functions)",
6 | "command": "dotnet",
7 | "args": [
8 | "clean",
9 | "/property:GenerateFullPaths=true",
10 | "/consoleloggerparameters:NoSummary"
11 | ],
12 | "type": "process",
13 | "problemMatcher": "$msCompile"
14 | },
15 | {
16 | "label": "build (functions)",
17 | "command": "dotnet",
18 | "args": [
19 | "build",
20 | "/property:GenerateFullPaths=true",
21 | "/consoleloggerparameters:NoSummary"
22 | ],
23 | "type": "process",
24 | "dependsOn": "clean (functions)",
25 | "group": {
26 | "kind": "build",
27 | "isDefault": true
28 | },
29 | "problemMatcher": "$msCompile"
30 | },
31 | {
32 | "label": "clean release (functions)",
33 | "command": "dotnet",
34 | "args": [
35 | "clean",
36 | "--configuration",
37 | "Release",
38 | "/property:GenerateFullPaths=true",
39 | "/consoleloggerparameters:NoSummary"
40 | ],
41 | "type": "process",
42 | "problemMatcher": "$msCompile"
43 | },
44 | {
45 | "label": "publish (functions)",
46 | "command": "dotnet",
47 | "args": [
48 | "publish",
49 | "--configuration",
50 | "Release",
51 | "/property:GenerateFullPaths=true",
52 | "/consoleloggerparameters:NoSummary"
53 | ],
54 | "type": "process",
55 | "dependsOn": "clean release (functions)",
56 | "problemMatcher": "$msCompile"
57 | },
58 | {
59 | "type": "func",
60 | "dependsOn": "build (functions)",
61 | "options": {
62 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp3.1"
63 | },
64 | "command": "host start",
65 | "isBackground": true,
66 | "problemMatcher": "$func-dotnet-watch"
67 | }
68 | ]
69 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/DemoScript.md:
--------------------------------------------------------------------------------
1 | # Publish Asset with AES Open Restriction
2 |
3 | ## Script
4 | ### 1. POST CreateContentKeyPolicy
5 | {
6 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKeyOpenRestriction",
7 | "mode": "simple",
8 | "description": "Shared token restricted policy for Clear Key content key policy",
9 | "policyOptionName": "PolicyWithClearKeyOpenRestrictionOption",
10 | "openRestriction": true,
11 | "configurationType": "ClearKey"
12 | }
13 |
14 | ### 2. POST PublishAsset
15 | {
16 | "assetName": "RollsRoyceIoT-048cf514-6337-430a-b538-94b1727dbc91",
17 | "streamingPolicyName": "Predefined_ClearKey",
18 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKeyOpenRestriction",
19 | "contentKeys": [
20 | {
21 | "id": "271b37ed-6098-4a16-8e16-c3beb79c6199",
22 | "type": "EnvelopeEncryption",
23 | "labelReferenceInStreamingPolicy": "clearKeyDefault",
24 | "value": "on1W311b4SiZ9c2KCDIy8w==",
25 | "policyName": null,
26 | "tracks": []
27 | }
28 | ],
29 | "startDateTime": "2020-04-20T00:00Z",
30 | "endDateTime": "2025-12-31T23:59Z"
31 | }
32 |
33 | ## Clean Up
34 | ### 1. POST UnpublishAsset
35 | {
36 | "streamingLocatorName": "streaminglocator-6bcfd46d-ee30-4c4f-bd0a-9852a00a0452"
37 | }
38 |
39 | ### 2. POST DeleteContentKeyPolicy
40 | {
41 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKeyOpenRestriction",
42 | }
43 |
44 | # Publish Asset with AES Jwt Token Restriction
45 |
46 | ## Script
47 | ### 1. POST CreateContentKeyPolicy
48 | {
49 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKey",
50 | "mode": "advanced",
51 | "description": "Shared token restricted policy for Clear Key content key policy",
52 | "contentKeyPolicyOptions": [
53 | {
54 | "name": "PolicyWithClearKeyOption",
55 | "configuration": {
56 | "@odata.type": "#Microsoft.Media.ContentKeyPolicyClearKeyConfiguration"
57 | },
58 | "restriction": {
59 | "@odata.type": "#Microsoft.Media.ContentKeyPolicyTokenRestriction",
60 | "issuer": "myIssuer",
61 | "audience": "myAudience",
62 | "primaryVerificationKey": {
63 | "@odata.type": "#Microsoft.Media.ContentKeyPolicySymmetricTokenKey",
64 | "keyValue": "on1W311b4SiZ9c2KCDIy8w=="
65 | },
66 | "alternateVerificationKeys": [],
67 | "requiredClaims": [
68 | {
69 | "claimType": "urn:microsoft:azure:mediaservices:contentkeyidentifier",
70 | "claimValue": null
71 | }
72 | ],
73 | "restrictionTokenType": "Jwt",
74 | "openIdConnectDiscoveryDocument": null
75 | }
76 | }
77 | ]
78 | }
79 |
80 | ### 2. POST PublishAsset
81 | {
82 | "assetName": "AzureMediaServices-ba6aad15-0417-44d7-b778-159b12adb990",
83 | "streamingPolicyName": "Predefined_ClearKey",
84 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKey",
85 | "contentKeys": [
86 | {
87 | "id": "1d5f3e32-7314-46ac-a713-3e066d289ed7",
88 | "type": "EnvelopeEncryption",
89 | "labelReferenceInStreamingPolicy": "clearKeyDefault",
90 | "value": "njjOFXLDn3RLfkKTdnrwZQ==",
91 | "policyName": null,
92 | "tracks": []
93 | }
94 | ],
95 | "startDateTime": "2020-04-20T00:00Z",
96 | "endDateTime": "2025-12-31T23:59Z"
97 | }
98 |
99 | ## Clean Up
100 | ### 1. POST UnpublishAsset
101 | {
102 | "streamingLocatorName": "streaminglocator-0705f511-879a-4258-9ce2-ca0e13c31995"
103 | }
104 |
105 | ### 2. POST DeleteContentKeyPolicy
106 | {
107 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKey"
108 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/CreateEmptyAsset.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // CreateEmptyAsset - This function creates an empty asset.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the asset
11 | "assetNamePrefix": "TestAssetName",
12 |
13 | // The description of the asset,
14 | "assetDescription": "Filename",
15 |
16 | // The name of attached storage account where to create the asset
17 | "assetStorageAccount": "storage01"
18 | }
19 | Output:
20 | {
21 | // The name of the asset created
22 | "assetName": "TestAssetName-180c777b-cd3c-4e02-b362-39b8d94d7a85",
23 |
24 | // The identifier of the asset created
25 | "assetId": "nb:cid:UUID:68adb036-43b7-45e6-81bd-8cf32013c810",
26 |
27 | // The name of the destination container name for the asset created
28 | "destinationContainer": "asset-4a5f429c-686c-4f6f-ae86-4078a4e6139e"
29 | }
30 |
31 | ```
32 | */
33 | //
34 | //
35 |
36 | using advanced_vod_functions_v3.SharedLibs;
37 | using Microsoft.AspNetCore.Http;
38 | using Microsoft.AspNetCore.Mvc;
39 | using Microsoft.Azure.Management.Media;
40 | using Microsoft.Azure.Management.Media.Models;
41 | using Microsoft.Azure.WebJobs;
42 | using Microsoft.Azure.WebJobs.Extensions.Http;
43 | using Microsoft.Extensions.Logging;
44 | using Newtonsoft.Json;
45 | using System;
46 | using System.IO;
47 | using System.Threading.Tasks;
48 |
49 |
50 | namespace advanced_vod_functions_v3
51 | {
52 | public static class CreateEmptyAsset
53 | {
54 | [FunctionName("CreateEmptyAsset")]
55 | public static async Task Run(
56 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
57 | ILogger log)
58 | {
59 | log.LogInformation($"AMS v3 Function - CreateEmptyAsset was triggered!");
60 |
61 | string requestBody = new StreamReader(req.Body).ReadToEnd();
62 | dynamic data = JsonConvert.DeserializeObject(requestBody);
63 |
64 | if (data.assetNamePrefix == null)
65 | return new BadRequestObjectResult("Please pass assetNamePrefix in the input object");
66 | string assetStorageAccount = null;
67 | if (data.assetStorageAccount != null)
68 | assetStorageAccount = data.assetStorageAccount;
69 |
70 | Guid assetGuid = Guid.NewGuid();
71 | string assetName = data.assetNamePrefix + "-" + assetGuid.ToString();
72 |
73 | string assetDescription = assetName;
74 | if (data.assetDescription != null)
75 | assetDescription = data.assetDescription;
76 |
77 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
78 | Asset asset = null;
79 |
80 | try
81 | {
82 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
83 |
84 | Asset assetParams = new Asset(null, assetName, null, assetGuid, DateTime.Now, DateTime.Now, null, assetDescription, null, assetStorageAccount, AssetStorageEncryptionFormat.None);
85 | asset = client.Assets.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, assetName, assetParams);
86 | //asset = client.Assets.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, assetName, new Asset());
87 | }
88 | catch (ApiErrorException e)
89 | {
90 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
91 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
92 | }
93 | catch (Exception e)
94 | {
95 | log.LogError($"ERROR: Exception with message: {e.Message}");
96 | return new BadRequestObjectResult("Error: " + e.Message);
97 | }
98 |
99 | // compatible with AMS V2 API
100 | string assetId = "nb:cid:UUID:" + asset.AssetId;
101 | string destinationContainer = "asset-" + asset.AssetId;
102 |
103 | return (ActionResult)new OkObjectResult(new
104 | {
105 | assetName = assetName,
106 | assetId = assetId,
107 | destinationContainer = destinationContainer
108 | });
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/CreateJwtToken.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // CreateJwtToken - Create a Jwt Token
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the streaming locator
11 | "streamingLocatorName": "locator-12345",
12 |
13 | // [Required] The name of the content key policy
14 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKey",
15 |
16 | // [Required] The name of the Azure Media Service account
17 | "accountName": "amsaccount",
18 |
19 | // [Required] The resource group of the Azure Media Service account
20 | "resourceGroup": "mediaservices-rg"
21 | }
22 | Output:
23 | {
24 | // The created token
25 | "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cm46bWljcm9zb2Z0OmF6dXJlOm1lZGlhc2VydmljZXM6Y29udGVudGtleWlkZW50aWZpZXIiOiJmZWQ1ZWE5Ni0wMjRhLTQ1YmMtYmE5My02MDFlZWU4MjcxNTgiLCJuYmYiOjE1ODc3MDUxOTgsImV4cCI6MTU4NzcwNTc5OCwiaXNzIjoibXlJc3N1ZXIiLCJhdWQiOiJteUF1ZGllbmNlIn0.UOLeEdiMfTKdIcr3SA-tO0nbD5AAedTKBAf815quNmI",
26 | }
27 |
28 | ```
29 | */
30 | //
31 | //
32 |
33 | using advanced_vod_functions_v3.SharedLibs;
34 | using Microsoft.AspNetCore.Http;
35 | using Microsoft.AspNetCore.Mvc;
36 | using Microsoft.Azure.Management.Media;
37 | using Microsoft.Azure.Management.Media.Models;
38 | using Microsoft.Azure.WebJobs;
39 | using Microsoft.Azure.WebJobs.Extensions.Http;
40 | using Microsoft.Extensions.Logging;
41 | using Microsoft.IdentityModel.Tokens;
42 | using Newtonsoft.Json;
43 | using System;
44 | using System.IdentityModel.Tokens.Jwt;
45 | using System.IO;
46 | using System.Linq;
47 | using System.Security.Claims;
48 | using System.Threading.Tasks;
49 |
50 | namespace advanced_vod_functions_v3
51 | {
52 | public static class CreateJwtToken
53 | {
54 | [FunctionName("CreateJwtToken")]
55 | public static async Task Run(
56 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
57 | ILogger log)
58 | {
59 | log.LogInformation($"AMS v3 Function - CreateJwtToken was triggered!");
60 |
61 | string requestBody = new StreamReader(req.Body).ReadToEnd();
62 | dynamic data = JsonConvert.DeserializeObject(requestBody);
63 |
64 | string streaminglocatorName = data.streamingLocatorName;
65 | string contentKeyPolicyName = data.contentKeyPolicyName;
66 | string accountName = data.accountName;
67 | string resourceGroup = data.resourceGroup;
68 |
69 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
70 | string token = null;
71 |
72 | try
73 | {
74 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
75 |
76 | var response = client.StreamingLocators.ListContentKeys(resourceGroup, accountName, streaminglocatorName);
77 | var contentKeyId = response.ContentKeys.First().Id.ToString();
78 | var policyProperties = client.ContentKeyPolicies.GetPolicyPropertiesWithSecrets(resourceGroup, accountName, contentKeyPolicyName);
79 |
80 | var ckrestriction = (ContentKeyPolicyTokenRestriction)policyProperties.Options.FirstOrDefault()?.Restriction;
81 | var symKey = (ContentKeyPolicySymmetricTokenKey)ckrestriction.PrimaryVerificationKey;
82 | var tokenSigningKey = new SymmetricSecurityKey(symKey.KeyValue);
83 |
84 | SigningCredentials cred = new SigningCredentials(
85 | tokenSigningKey,
86 | // Use the HmacSha256 and not the HmacSha256Signature option, or the token will not work!
87 | SecurityAlgorithms.HmacSha256,
88 | SecurityAlgorithms.Sha256Digest);
89 |
90 | Claim[] claims = new Claim[] {
91 | new Claim(ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim.ClaimType, contentKeyId)
92 | };
93 |
94 | JwtSecurityToken jwtToken = new JwtSecurityToken(
95 | issuer: ckrestriction.Issuer,
96 | audience: ckrestriction.Audience,
97 | claims: claims,
98 | notBefore: DateTime.Now.AddMinutes(-5),
99 | expires: DateTime.Now.AddMinutes(60),
100 | signingCredentials: cred);
101 |
102 | JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
103 | token = $"Bearer {handler.WriteToken(jwtToken)}";
104 | }
105 | catch (ApiErrorException e)
106 | {
107 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
108 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
109 | }
110 | catch (Exception e)
111 | {
112 | log.LogError($"ERROR: Exception with message: {e.Message}");
113 | return new BadRequestObjectResult("Error: " + e.Message);
114 | }
115 |
116 | return (ActionResult)new OkObjectResult(new
117 | {
118 | token = token
119 | });
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/DeleteAsset.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // DeleteAsset - This function deletes an existing asset.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the asset
11 | "assetName": "TestAssetName-180c777b-cd3c-4e02-b362-39b8d94d7a85",
12 |
13 | // [Required] The name of the Azure Media Service account
14 | "accountName": "amsaccount",
15 |
16 | // [Required] The resource group of the Azure Media Service account
17 | "resourceGroup": "mediaservices-rg"
18 | }
19 | Output:
20 | {
21 | // The name of the deleted asset
22 | "assetName": "TestAssetName-180c777b-cd3c-4e02-b362-39b8d94d7a85"
23 | }
24 |
25 | ```
26 | */
27 | //
28 | //
29 |
30 | using advanced_vod_functions_v3.SharedLibs;
31 | using Microsoft.AspNetCore.Http;
32 | using Microsoft.AspNetCore.Mvc;
33 | using Microsoft.Azure.Management.Media;
34 | using Microsoft.Azure.Management.Media.Models;
35 | using Microsoft.Azure.WebJobs;
36 | using Microsoft.Azure.WebJobs.Extensions.Http;
37 | using Microsoft.Extensions.Logging;
38 | using Newtonsoft.Json;
39 | using System;
40 | using System.IO;
41 | using System.Threading.Tasks;
42 |
43 |
44 | namespace advanced_vod_functions_v3
45 | {
46 | public static class DeleteAsset
47 | {
48 | [FunctionName("DeleteAsset")]
49 | public static async Task Run(
50 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
51 | ILogger log)
52 | {
53 | log.LogInformation($"AMS v3 Function - DeleteAsset was triggered!");
54 |
55 | string requestBody = new StreamReader(req.Body).ReadToEnd();
56 | dynamic data = JsonConvert.DeserializeObject(requestBody);
57 |
58 | string assetName = data.assetName;
59 | string accountName = data.accountName;
60 | string resourceGroup = data.resourceGroup;
61 |
62 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
63 |
64 | try
65 | {
66 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
67 |
68 | client.Assets.Delete(resourceGroup, accountName, assetName);
69 | }
70 | catch (ApiErrorException e)
71 | {
72 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
73 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
74 | }
75 | catch (Exception e)
76 | {
77 | log.LogError($"ERROR: Exception with message: {e.Message}");
78 | return new BadRequestObjectResult("Error: " + e.Message);
79 | }
80 |
81 | // compatible with AMS V2 API
82 | return (ActionResult)new OkObjectResult(new
83 | {
84 | assetName = assetName
85 | });
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/DeleteContentKeyPolicy.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // DeleteContentKeyPolicy - This function deletes an ContentKeyPolicy object.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The content key policy name.
11 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKey",
12 | }
13 | Output:
14 | {
15 | // The name of the deleted content key policy.
16 | "contentKeyPolicyName": "SharedContentKeyPolicyForClearKey",
17 | }
18 |
19 | ```
20 | */
21 | //
22 | //
23 |
24 | using advanced_vod_functions_v3.SharedLibs;
25 | using Microsoft.AspNetCore.Http;
26 | using Microsoft.AspNetCore.Mvc;
27 | using Microsoft.Azure.Management.Media;
28 | using Microsoft.Azure.Management.Media.Models;
29 | using Microsoft.Azure.WebJobs;
30 | using Microsoft.Azure.WebJobs.Extensions.Http;
31 | using Microsoft.Extensions.Logging;
32 | using Newtonsoft.Json;
33 | using System;
34 | using System.IO;
35 | using System.Threading.Tasks;
36 |
37 |
38 | namespace advanced_vod_functions_v3
39 | {
40 | public static class DeleteContentKeyPolicy
41 | {
42 | [FunctionName("DeleteContentKeyPolicy")]
43 | public static async Task Run(
44 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
45 | ILogger log)
46 | {
47 | log.LogInformation($"AMS v3 Function - CreateContentKeyPolicy was triggered!");
48 |
49 | string requestBody = new StreamReader(req.Body).ReadToEnd();
50 | dynamic data = JsonConvert.DeserializeObject(requestBody);
51 |
52 | if (data.contentKeyPolicyName == null)
53 | return new BadRequestObjectResult("Please pass contentKeyPolicyName in the input object");
54 | string contentKeyPolicyName = data.contentKeyPolicyName;
55 |
56 | try
57 | {
58 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
59 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
60 |
61 | client.ContentKeyPolicies.Delete(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName);
62 | }
63 | catch (ApiErrorException e)
64 | {
65 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
66 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
67 | }
68 | catch (Exception e)
69 | {
70 | log.LogError($"ERROR: Exception with message: {e.Message}");
71 | return new BadRequestObjectResult("Error: " + e.Message);
72 | }
73 |
74 | return (ActionResult)new OkObjectResult(new
75 | {
76 | contentKeyPolicyName = contentKeyPolicyName
77 | });
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/DeleteStreamingPolicy.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // DeleteStreamingPolicy - This function deletes an StreamingPolicy object.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the streaming policy.
11 | "streamingPolicyName": "SharedStreamingForClearKey",
12 | }
13 | Output:
14 | {
15 | // The name of the streaming policy.
16 | "streamingPolicyName": "SharedStreamingForClearKey",
17 | }
18 |
19 | ```
20 | */
21 | //
22 | //
23 |
24 | using advanced_vod_functions_v3.SharedLibs;
25 | using Microsoft.AspNetCore.Http;
26 | using Microsoft.AspNetCore.Mvc;
27 | using Microsoft.Azure.Management.Media;
28 | using Microsoft.Azure.Management.Media.Models;
29 | using Microsoft.Azure.WebJobs;
30 | using Microsoft.Azure.WebJobs.Extensions.Http;
31 | using Microsoft.Extensions.Logging;
32 | using Newtonsoft.Json;
33 | using System;
34 | using System.IO;
35 | using System.Threading.Tasks;
36 |
37 |
38 | namespace advanced_vod_functions_v3
39 | {
40 | public static class DeleteStreamingPolicy
41 | {
42 | [FunctionName("DeleteStreamingPolicy")]
43 | public static async Task Run(
44 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
45 | ILogger log)
46 | {
47 | log.LogInformation($"AMS v3 Function - CreateStreamingPolicy was triggered!");
48 |
49 | string requestBody = new StreamReader(req.Body).ReadToEnd();
50 | dynamic data = JsonConvert.DeserializeObject(requestBody);
51 |
52 | if (data.streamingPolicyName == null)
53 | return new BadRequestObjectResult("Please pass streamingPolicyName in the input object");
54 | string streamingPolicyName = data.streamingPolicyName;
55 |
56 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
57 |
58 | try
59 | {
60 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
61 |
62 | client.StreamingPolicies.Delete(amsconfig.ResourceGroup, amsconfig.AccountName, streamingPolicyName);
63 | }
64 | catch (ApiErrorException e)
65 | {
66 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
67 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
68 | }
69 | catch (Exception e)
70 | {
71 | log.LogError($"ERROR: Exception with message: {e.Message}");
72 | return new BadRequestObjectResult("Error: " + e.Message);
73 | }
74 |
75 | return (ActionResult)new OkObjectResult(new
76 | {
77 | streamingPolicyName = streamingPolicyName
78 | });
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/GetTransform.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // CreateTransform - This function creates a new transform.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the transform.
11 | "transformName": "TestTransform"
12 | }
13 | Output:
14 | {
15 | // The name of the created TransformName
16 | "transformName": "TestTransform",
17 |
18 | // The resource identifier of the created Transform
19 | "transformId": "/subscriptions/694d5930-8ee4-4e50-917b-9dcfeceb6179/resourceGroups/AMSdemo/providers/Microsoft.Media/mediaservices/amsdemojapaneast/transforms/TestTransform"
20 | }
21 |
22 | ```
23 | */
24 | //
25 | //
26 |
27 | using advanced_vod_functions_v3.SharedLibs;
28 | using Microsoft.AspNetCore.Http;
29 | using Microsoft.AspNetCore.Mvc;
30 | using Microsoft.Azure.Management.Media;
31 | using Microsoft.Azure.Management.Media.Models;
32 | using Microsoft.Azure.WebJobs;
33 | using Microsoft.Azure.WebJobs.Extensions.Http;
34 | using Microsoft.Extensions.Logging;
35 | using Newtonsoft.Json;
36 | using System;
37 | using System.IO;
38 | using System.Threading.Tasks;
39 |
40 |
41 | namespace advanced_vod_functions_v3
42 | {
43 | public static class GetTransform
44 | {
45 | [FunctionName("GetTransform")]
46 | public static async Task Run(
47 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
48 | ILogger log)
49 | {
50 | log.LogInformation($"AMS v3 Function - GetTransform was triggered!");
51 |
52 | string requestBody = new StreamReader(req.Body).ReadToEnd();
53 | dynamic data = JsonConvert.DeserializeObject(requestBody);
54 |
55 | if (data.transformName == null)
56 | return new BadRequestObjectResult("Please pass transformName in the input object");
57 | string transformName = data.transformName;
58 |
59 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
60 | string transformId = null;
61 |
62 | try
63 | {
64 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
65 |
66 | Transform transform = client.Transforms.Get(amsconfig.ResourceGroup, amsconfig.AccountName, transformName);
67 | if (transform == null)
68 | transformName = null;
69 | else
70 | transformId = transform.Id;
71 | }
72 | catch (ApiErrorException e)
73 | {
74 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
75 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
76 | }
77 | catch (Exception e)
78 | {
79 | log.LogError($"ERROR: Exception with message: {e.Message}");
80 | return new BadRequestObjectResult("Error: " + e.Message);
81 | }
82 |
83 | return (ActionResult)new OkObjectResult(new
84 | {
85 | transformName = transformName,
86 | transformId = transformId
87 | });
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/MonitorMediaJob.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // MonitorMediaJob - This function monitors media job.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the media job
11 | "jobName": "amsv3function-job-24369d2e-7415-4ff5-ba12-b8a879a15401",
12 |
13 | // [Required] The name of the Transform for the media job
14 | "transformName": "TestTransform"
15 | }
16 | Output:
17 | {
18 | // The status name of the media job
19 | "jobStatus": "Finished",
20 |
21 | // The status of each task/output asset in the media job
22 | "jobOutputStateList": [
23 | {
24 | // Name of the Output Asset
25 | "AssetName": "out-testasset-efbf71e8-3f80-480d-9b92-f02bef6ad4d2",
26 | // Status of the media task for the Output Asset
27 | "State": "Finished",
28 | // Progress of the media task for the Output Asset
29 | "Progress": 100
30 | },
31 | ...
32 | ]
33 | }
34 |
35 | ```
36 | */
37 | // // https://docs.microsoft.com/en-us/dotnet/api/microsoft.windowsazure.mediaservices.client.jobstate?view=azure-dotnet
38 | // // Queued 0
39 | // // Scheduled 1
40 | // // Processing 2
41 | // // Finished 3
42 | // // Error 4
43 | // // Canceled 5
44 | // // Canceling 6
45 | //
46 | //
47 |
48 | using advanced_vod_functions_v3.SharedLibs;
49 | using Microsoft.AspNetCore.Http;
50 | using Microsoft.AspNetCore.Mvc;
51 | using Microsoft.Azure.Management.Media;
52 | using Microsoft.Azure.Management.Media.Models;
53 | using Microsoft.Azure.WebJobs;
54 | using Microsoft.Azure.WebJobs.Extensions.Http;
55 | using Microsoft.Extensions.Logging;
56 | using Newtonsoft.Json;
57 | using Newtonsoft.Json.Linq;
58 | using System;
59 | using System.IO;
60 | using System.Threading.Tasks;
61 |
62 |
63 | namespace advanced_vod_functions_v3
64 | {
65 | public static class MonitorMediaJob
66 | {
67 | [FunctionName("MonitorMediaJob")]
68 | public static async Task Run(
69 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
70 | ILogger log)
71 | {
72 | log.LogInformation($"AMS v3 Function - MonitorMediaJob was triggered!");
73 |
74 | string requestBody = new StreamReader(req.Body).ReadToEnd();
75 | dynamic data = JsonConvert.DeserializeObject(requestBody);
76 |
77 | // Validate input objects
78 | if (data.jobName == null)
79 | return new BadRequestObjectResult("Please pass jobName in the input object");
80 | if (data.transformName == null)
81 | return new BadRequestObjectResult("Please pass transformName in the input object");
82 | string jobName = data.jobName;
83 | string transformName = data.transformName;
84 |
85 |
86 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
87 | Job job = null;
88 |
89 | try
90 | {
91 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
92 | job = client.Jobs.Get(amsconfig.ResourceGroup, amsconfig.AccountName, transformName, jobName);
93 |
94 | }
95 | catch (ApiErrorException e)
96 | {
97 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
98 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
99 | }
100 | catch (Exception e)
101 | {
102 | log.LogError($"ERROR: Exception with message: {e.Message}");
103 | return new BadRequestObjectResult("Error: " + e.Message);
104 | }
105 |
106 | JObject result = new JObject();
107 | result["jobStatus"] = job.State.ToString();
108 | JArray jobOutputStateList = new JArray();
109 | foreach (JobOutputAsset o in job.Outputs)
110 | {
111 | JObject jobOutputState = new JObject();
112 | jobOutputState["AssetName"] = o.AssetName;
113 | jobOutputState["State"] = o.State.ToString();
114 | jobOutputState["Progress"] = o.Progress;
115 | if (o.Error != null)
116 | {
117 | jobOutputState["ErrorCode"] = o.Error.Code.ToString();
118 | jobOutputState["ErrorMessage"] = o.Error.Message.ToString();
119 | }
120 | jobOutputStateList.Add(jobOutputState);
121 | }
122 | result["jobOutputStateList"] = jobOutputStateList;
123 |
124 | return (ActionResult)new OkObjectResult(result);
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/Functions/UnpublishAsset.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 Functions
3 | //
4 | // UnpublishAsset - This function unpublishes an asset by deleting its streaming locator and policy.
5 | //
6 | /*
7 | ```c#
8 | Input:
9 | {
10 | // [Required] The name of the streaming locator
11 | "streamingLocatorName": "streaminglocator-911b65de-ac92-4391-9aab-80021126d403"
12 | }
13 | Output:
14 | {
15 | // The name of the deleted StreamingLocatorName
16 | "streamingLocatorName": "streaminglocator-911b65de-ac92-4391-9aab-80021126d403"
17 |
18 | // The name of the deleted streamingPolicyName
19 | "streamingPolicyName": "SharedStreamingForClearKey"
20 | }
21 |
22 | ```
23 | */
24 | //
25 | //
26 |
27 | using advanced_vod_functions_v3.SharedLibs;
28 | using Microsoft.AspNetCore.Http;
29 | using Microsoft.AspNetCore.Mvc;
30 | using Microsoft.Azure.Management.Media;
31 | using Microsoft.Azure.Management.Media.Models;
32 | using Microsoft.Azure.WebJobs;
33 | using Microsoft.Azure.WebJobs.Extensions.Http;
34 | using Microsoft.Extensions.Logging;
35 | using Newtonsoft.Json;
36 | using System;
37 | using System.IO;
38 | using System.Threading.Tasks;
39 |
40 |
41 | namespace advanced_vod_functions_v3
42 | {
43 | public static class UnpublishAsset
44 | {
45 | [FunctionName("UnpublishAsset")]
46 | public static async Task Run(
47 | [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
48 | ILogger log)
49 | {
50 | log.LogInformation($"AMS v3 Function - PublishAsset was triggered!");
51 |
52 | string requestBody = new StreamReader(req.Body).ReadToEnd();
53 | dynamic data = JsonConvert.DeserializeObject(requestBody);
54 |
55 | // Validate input objects
56 | if (data.streamingLocatorName == null)
57 | return new BadRequestObjectResult("Please pass streamingLocatorName in the input object");
58 | string streamingLocatorName = data.streamingLocatorName;
59 | string streamingPolicyName = null;
60 |
61 | MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper();
62 | string contentKeysJson = string.Empty;
63 | try
64 | {
65 | IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig);
66 |
67 | var streamingLocator = client.StreamingLocators.Get(amsconfig.ResourceGroup, amsconfig.AccountName, streamingLocatorName);
68 | streamingPolicyName = streamingLocator.StreamingPolicyName;
69 |
70 | client.StreamingLocators.Delete(amsconfig.ResourceGroup, amsconfig.AccountName, streamingLocatorName);
71 | if (!streamingPolicyName.StartsWith("Predefined_"))
72 | client.StreamingPolicies.Delete(amsconfig.ResourceGroup, amsconfig.AccountName, streamingPolicyName);
73 | }
74 | catch (ApiErrorException e)
75 | {
76 | log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}");
77 | return new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message);
78 | }
79 | catch (Exception e)
80 | {
81 | log.LogError($"ERROR: Exception with message: {e.Message}");
82 | return new BadRequestObjectResult("Error: " + e.Message);
83 | }
84 |
85 | return (ActionResult)new OkObjectResult(new
86 | {
87 | streamingLocatorName = streamingLocatorName,
88 | streamingPolicyName = streamingPolicyName == null || streamingPolicyName.StartsWith("Predefined_") ? "None" : streamingPolicyName,
89 | contentKeys = contentKeysJson
90 | });
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | services: media-services,functions,logic-app
3 | platforms: dotnetcore
4 | author: shigeyf
5 | ---
6 |
7 | # Media Services: Integrating Azure Media Services with Azure Functions & Azure Logic Apps
8 |
9 | This project contains advanced VOD media workflow examples of using Azure Functions with Azure Media Services.
10 | The project includes several folders of sample Azure Functions for use with Azure Media Services that show workflows related to ingesting content directly from blob storage, encoding, and writing content back to blob storage.
11 |
12 | This Media Services Functions example is based on AMS REST API v3 on Azure Functions v3.
13 |
14 | ## Prerequisites for a sample Logic Apps deployments
15 |
16 | ### 1. Create an Azure Media Services account
17 |
18 | Create a Media Services account in your subscription if don't have it already ([follow this article](https://docs.microsoft.com/en-us/azure/media-services/latest/create-account-howto?tabs=portal)).
19 |
20 | ### 2. Create a Service Principal
21 |
22 | Create a Service Principal and save the password. It will be needed in step #4. To do so, go to the API tab in the account ([follow this article](https://docs.microsoft.com/en-us/azure/media-services/latest/access-api-howto?tabs=portal)).
23 |
24 | ### 3. Make sure the AMS streaming endpoint is started
25 |
26 | To enable streaming, go to the Azure portal, select the Azure Media Services account which has been created, and start the default streaming endpoint.
27 |
28 | ### 4. Deploy the Azure functions
29 |
30 | If not already done : fork the repo, deploy Azure Functions and select the **"advanced-vod-workflow-functions"** Project (IMPORTANT!)
31 |
32 | Follow the guidelines in the [git tutorial](1-CONTRIBUTION-GUIDE/git-tutorial.md) for details on how to fork the project and use Git properly with this project.
33 |
34 | Note : if you never provided your GitHub account in the Azure portal before, the continous integration probably will probably fail and you won't see the functions. In that case, you need to setup it manually. Go to your azure functions deployment / Functions app settings / Configure continous integration. Select GitHub as a source and configure it to use your fork.
35 |
36 |
37 |
38 | Alternatively, deploy the [Azure Functions using Visual Studio](https://docs.microsoft.com/en-us/azure/azure-functions/functions-develop-vs#publish-to-azure).
39 |
40 | ## Functions documentation
41 |
42 | This [page](Functions-documentation.md) lists the functions available and describes the input and output parameters.
43 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/SharedLibs/BlobStorageHelper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using Microsoft.WindowsAzure.Storage;
8 | using Microsoft.WindowsAzure.Storage.Auth;
9 | using Microsoft.WindowsAzure.Storage.Blob;
10 | using System;
11 | using System.Collections.Generic;
12 |
13 |
14 | namespace advanced_vod_functions_v3.SharedLibs
15 | {
16 | public class BlobStorageHelper
17 | {
18 | static public CloudBlobContainer GetCloudBlobContainer(string storageAccountName, string storageAccountKey, string containerName)
19 | {
20 | CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(storageAccountName, storageAccountKey), true);
21 | CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
22 | return cloudBlobClient.GetContainerReference(containerName);
23 | }
24 |
25 | static public List ListBlobs(CloudBlobContainer blobContainer)
26 | {
27 | List blobList = new List();
28 | string blobPrefix = null;
29 | bool useFlatBlobListing = true;
30 | BlobContinuationToken blobContinuationToken = null;
31 |
32 | do
33 | {
34 | var results = blobContainer.ListBlobsSegmentedAsync(blobPrefix, useFlatBlobListing, BlobListingDetails.Copy, null, blobContinuationToken, null, null).Result;
35 |
36 | // Get the value of the continuation token returned by the listing call.
37 | blobContinuationToken = results.ContinuationToken;
38 |
39 | foreach (IListBlobItem item in results.Results)
40 | {
41 | if (item.GetType() == typeof(CloudBlockBlob))
42 | {
43 | CloudBlockBlob blob = (CloudBlockBlob)item;
44 | blobList.Add(blob);
45 | }
46 | }
47 | } while (blobContinuationToken != null); // Loop while the continuation token is not null.
48 |
49 | return blobList;
50 | }
51 |
52 | static public async void CopyBlobsAsync(CloudBlobContainer sourceBlobContainer, CloudBlobContainer destinationBlobContainer, List fileNames)
53 | {
54 | if (fileNames != null)
55 | {
56 | foreach (var fileName in fileNames)
57 | {
58 | CloudBlob sourceBlob = sourceBlobContainer.GetBlockBlobReference(fileName);
59 | CloudBlob destinationBlob = destinationBlobContainer.GetBlockBlobReference(fileName);
60 | CopyBlobAsync(sourceBlob as CloudBlob, destinationBlob);
61 | }
62 | }
63 | else
64 | {
65 | string blobPrefix = null;
66 | BlobContinuationToken blobContinuationToken = null;
67 | do
68 | {
69 | var results = await sourceBlobContainer.ListBlobsSegmentedAsync(blobPrefix, blobContinuationToken);
70 | // Get the value of the continuation token returned by the listing call.
71 | blobContinuationToken = results.ContinuationToken;
72 | foreach (IListBlobItem item in results.Results)
73 | {
74 | if (item.GetType() == typeof(CloudBlockBlob))
75 | {
76 | CloudBlockBlob sourceBlob = (CloudBlockBlob)item;
77 | CloudBlob destinationBlob = destinationBlobContainer.GetBlockBlobReference(sourceBlob.Name);
78 | CopyBlobAsync(sourceBlob as CloudBlob, destinationBlob);
79 | }
80 | }
81 | } while (blobContinuationToken != null); // Loop while the continuation token is not null.
82 | }
83 | }
84 |
85 | static public async void CopyBlobAsync(CloudBlob sourceBlob, CloudBlob destinationBlob)
86 | {
87 | var signature = sourceBlob.GetSharedAccessSignature(new SharedAccessBlobPolicy
88 | {
89 | Permissions = SharedAccessBlobPermissions.Read,
90 | SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24)
91 | });
92 | await destinationBlob.StartCopyAsync(new Uri(sourceBlob.Uri.AbsoluteUri + signature));
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/SharedLibs/GenericHelper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using System;
8 | using System.Collections.Generic;
9 |
10 |
11 | namespace advanced_vod_functions_v3.SharedLibs
12 | {
13 | class GenericHelper
14 | {
15 | public static byte[] GetRandomBuffer(int length)
16 | {
17 | var returnValue = new byte[length];
18 |
19 | using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())
20 | {
21 | rng.GetBytes(returnValue);
22 | }
23 |
24 | return returnValue;
25 | }
26 | }
27 | public class JsonObjectConversionRule
28 | {
29 | public Type t;
30 | public Dictionary rules;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/SharedLibs/MediaServiceClientCredentials.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using System;
8 |
9 | namespace advanced_vod_functions_v3.SharedLibs
10 | {
11 | public class MediaServiceClientCredentials
12 | {
13 | public Uri AadEndpoint
14 | {
15 | get { return new Uri(Environment.GetEnvironmentVariable("AadEndpoint")); }
16 | }
17 |
18 | public string AadTenantId
19 | {
20 | get { return Environment.GetEnvironmentVariable("AadTenantId"); }
21 | }
22 |
23 | public string AadClientId
24 | {
25 | get { return Environment.GetEnvironmentVariable("AadClientId"); }
26 | }
27 |
28 | public string AadClientSecret
29 | {
30 | get { return Environment.GetEnvironmentVariable("AadClientSecret"); }
31 | }
32 |
33 | public Uri ArmEndpoint
34 | {
35 | get { return new Uri(Environment.GetEnvironmentVariable("ArmEndpoint")); }
36 | }
37 |
38 | public Uri ArmAadAudience
39 | {
40 | get { return new Uri(Environment.GetEnvironmentVariable("ArmAadAudience")); }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/SharedLibs/MediaServicesConfigWrapper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using System;
8 |
9 | namespace advanced_vod_functions_v3.SharedLibs
10 | {
11 | public class MediaServicesConfigWrapper
12 | {
13 | public MediaServiceClientCredentials mediaServiceClientCredentials = new MediaServiceClientCredentials();
14 |
15 | public string SubscriptionId
16 | {
17 | get { return Environment.GetEnvironmentVariable("SubscriptionId"); }
18 | }
19 |
20 | public string ResourceGroup
21 | {
22 | get { return Environment.GetEnvironmentVariable("ResourceGroup"); }
23 | }
24 |
25 | public string AccountName
26 | {
27 | get { return Environment.GetEnvironmentVariable("AccountName"); }
28 | }
29 |
30 | public string Region
31 | {
32 | get { return Environment.GetEnvironmentVariable("Region"); }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/SharedLibs/MediaServicesHelper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Azure Media Services REST API v3 - Functions
3 | //
4 | // Shared Library
5 | //
6 |
7 | using Microsoft.Azure.Management.Media;
8 | using Microsoft.Azure.Management.Media.Models;
9 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
10 | using Microsoft.Rest;
11 | using Microsoft.Rest.Azure.Authentication;
12 | using Newtonsoft.Json.Linq;
13 | using System.Collections.Generic;
14 | using System.Threading.Tasks;
15 |
16 |
17 | namespace advanced_vod_functions_v3.SharedLibs
18 | {
19 | public class MediaServicesHelper
20 | {
21 | public static IAzureMediaServicesClient CreateMediaServicesClientAsync(MediaServicesConfigWrapper config)
22 | {
23 | var credentials = GetCredentialsAsync(config).Result;
24 |
25 | return new AzureMediaServicesClient(config.mediaServiceClientCredentials.ArmEndpoint, credentials)
26 | {
27 | SubscriptionId = config.SubscriptionId,
28 | };
29 | }
30 |
31 | private static async Task GetCredentialsAsync(MediaServicesConfigWrapper config)
32 | {
33 | // Use ApplicationTokenProvider.LoginSilentAsync to get a token using a service principal with symetric key
34 | ClientCredential clientCredential = new ClientCredential(config.mediaServiceClientCredentials.AadClientId, config.mediaServiceClientCredentials.AadClientSecret);
35 | return await ApplicationTokenProvider.LoginSilentAsync(config.mediaServiceClientCredentials.AadTenantId, clientCredential, ActiveDirectoryServiceSettings.Azure);
36 | }
37 |
38 | static public PublishAssetOutput ConvertToPublishAssetOutput(string locatorName, string streamingUrlPrefx, ListPathsResponse paths)
39 | {
40 | PublishAssetOutput output = new PublishAssetOutput();
41 |
42 | output.locatorName = locatorName;
43 | output.streamingUrl = "";
44 | output.captionVttUrl = "";
45 | output.annotationsJsonUrl = "";
46 | output.contentModerationJsonUrl = "";
47 | output.facesJsonUrl = "";
48 | output.insightsJsonUrl = "";
49 | output.ocrJsonUrl = "";
50 |
51 | List psUrls = new List();
52 | foreach (var path in paths.StreamingPaths)
53 | {
54 | PublishStreamingUrls s = new PublishStreamingUrls();
55 | s.streamingProtocol = path.StreamingProtocol.ToString();
56 | s.encryptionScheme = path.EncryptionScheme.ToString();
57 | s.urls = new string[path.Paths.Count];
58 | for (int i = 0; i < path.Paths.Count; i++) s.urls[i] = "https://" + streamingUrlPrefx + path.Paths[i];
59 | if (path.StreamingProtocol.ToString() == "SmoothStreaming")
60 | output.streamingUrl = "https://" + streamingUrlPrefx + path.Paths[0];
61 | psUrls.Add(s);
62 | }
63 | output.streamingUrls = psUrls.ToArray();
64 |
65 | List dUrls = new List();
66 | foreach (var path in paths.DownloadPaths)
67 | {
68 | dUrls.Add("https://" + streamingUrlPrefx + path);
69 | if (path.EndsWith("annotations.json")) output.annotationsJsonUrl = "https://" + streamingUrlPrefx + path;
70 | if (path.EndsWith("contentmoderation.json")) output.contentModerationJsonUrl = "https://" + streamingUrlPrefx + path;
71 | if (path.EndsWith("faces.json")) output.facesJsonUrl = "https://" + streamingUrlPrefx + path;
72 | if (path.EndsWith("insights.json")) output.insightsJsonUrl = "https://" + streamingUrlPrefx + path;
73 | if (path.EndsWith("transcript.vtt")) output.captionVttUrl = "https://" + streamingUrlPrefx + path;
74 | }
75 | output.downloadUrls = dUrls.ToArray();
76 |
77 | return output;
78 | }
79 | }
80 |
81 | public class PublishStreamingUrls
82 | {
83 | public string streamingProtocol;
84 | public string encryptionScheme;
85 | public string[] urls;
86 | }
87 |
88 | public class PublishAssetOutput
89 | {
90 | public string locatorName;
91 | public string streamingUrl;
92 | // Audio Analyzer - VTT (speech-to-text)
93 | public string captionVttUrl;
94 | // Video Analyzer JSON
95 | public string annotationsJsonUrl;
96 | public string contentModerationJsonUrl;
97 | public string facesJsonUrl;
98 | public string insightsJsonUrl;
99 | public string ocrJsonUrl;
100 | // URLs
101 | public PublishStreamingUrls[] streamingUrls;
102 | public string[] downloadUrls;
103 | }
104 |
105 | public static class JsonExtensions
106 | {
107 | public static List FindTokens(this JToken containerToken, string name)
108 | {
109 | List matches = new List();
110 | FindTokens(containerToken, name, matches);
111 | return matches;
112 | }
113 |
114 | private static void FindTokens(JToken containerToken, string name, List matches)
115 | {
116 | if (containerToken.Type == JTokenType.Object)
117 | {
118 | foreach (JProperty child in containerToken.Children())
119 | {
120 | if (child.Name == name)
121 | {
122 | matches.Add(child.Value);
123 | }
124 | FindTokens(child.Value, name, matches);
125 | }
126 | }
127 | else if (containerToken.Type == JTokenType.Array)
128 | {
129 | foreach (JToken child in containerToken.Children())
130 | {
131 | FindTokens(child, name, matches);
132 | }
133 | }
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/advanced_vod_functions_v3.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp3.1
4 | v3
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | PreserveNewest
24 |
25 |
26 | PreserveNewest
27 | Never
28 |
29 |
30 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/advanced_vod_functions_v3.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30011.22
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "advanced_vod_functions_v3", "advanced_vod_functions_v3.csproj", "{EF247D55-CF5C-4A45-A13B-CF3BEE2B46FF}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {EF247D55-CF5C-4A45-A13B-CF3BEE2B46FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {EF247D55-CF5C-4A45-A13B-CF3BEE2B46FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {EF247D55-CF5C-4A45-A13B-CF3BEE2B46FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {EF247D55-CF5C-4A45-A13B-CF3BEE2B46FF}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {4A3D7932-8484-4DA4-B7C1-A5B69714768F}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/advanced-vod-workflow/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingExcludedTypes": "Request",
6 | "samplingSettings": {
7 | "isEnabled": true
8 | }
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/advanced-vod-workflow/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true",
5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet"
6 | }
7 | }
--------------------------------------------------------------------------------
/azuredeploy.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "appName": {
6 | "value": "GEN-UNIQUE"
7 | },
8 | "functionKey": {
9 | "value" : "GEN-UNIQUE"
10 | },
11 | "sourceCodeRepositoryURL": {
12 | "value": "ENTER PATH TO YOUR FORK OF - https://github.com/Azure-Samples/media-services-dotnet-functions-integration"
13 | },
14 | "sourceCodeBranch": {
15 | "value": "main"
16 | },
17 | "sourceCodeManualIntegration": {
18 | "value": true
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/.gitignore:
--------------------------------------------------------------------------------
1 | *.local.json
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | services: media-services,logic-app
3 | platforms: dotnetcore
4 | author: raffertyuy
5 | ---
6 |
7 | # Media Services: Integrating Azure Media Services with Azure Functions & Azure Logic Apps
8 |
9 | This project contains Logic Apps that converts-to-media-asset, encodes and publishes media files that you upload in an Azure Storage.
10 |
11 | The project includes Logic Apps ARM templates that is dependent on the [advanced-vod-workflow](../advanced-vod-workflow) functions. There are 2 projects, one for uploading and encoding and another for publishing.
12 |
13 | This Media Services Functions example is based on AMS REST API v3 on Azure Functions v3.
14 |
15 | See [here](https://raffertyuy.com/raztype/creating-an-azure-media-services-upload-workflow-using-azure-storage-and-logic-apps) to read more about how this logic app is implemented.
16 |
17 | ## Prerequisites for a sample Logic Apps deployments
18 |
19 | ### 1. Deploy the Advanced VOD Workflow Azure Functions
20 |
21 | Follow the instructions and deploy the azure functions found in [advanced-vod-workflow](../advanced-vod-workflow).
22 |
23 | ### 2. Edit the ARM Template Parameters
24 |
25 | Update the parameters found in the LogicApp.json of both projects
26 |
27 | ### 3. Deploy the 2 Logic App Projects
28 |
29 | See [here](https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-azure-resource-manager-templates-overview) for instructions.
30 |
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/publish-logicapp/Deployment.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | bin\$(Configuration)\
7 | false
8 | true
9 | false
10 | None
11 | obj\
12 | $(BaseIntermediateOutputPath)\
13 | $(BaseIntermediateOutputPath)$(Configuration)\
14 | $(IntermediateOutputPath)ProjectReferences
15 | $(ProjectReferencesOutputPath)\
16 | true
17 |
18 |
19 |
20 | false
21 | false
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Always
33 |
34 |
35 | Never
36 |
37 |
38 | false
39 | Build
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | _GetDeploymentProjectContent;
48 | _CalculateContentOutputRelativePaths;
49 | _GetReferencedProjectsOutput;
50 | _CalculateArtifactStagingDirectory;
51 | _CopyOutputToArtifactStagingDirectory;
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Configuration=$(Configuration);Platform=$(Platform)
69 |
70 |
71 |
75 |
76 |
77 |
78 | $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)'))
79 |
80 |
81 |
82 |
83 |
84 |
85 | $(OutDir)
86 | $(OutputPath)
87 | $(ArtifactStagingDirectory)\
88 | $(ArtifactStagingDirectory)staging\
89 | $(Build_StagingDirectory)
90 |
91 |
92 |
93 |
94 |
96 |
97 | <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity)
98 | <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', ''))
99 |
100 |
101 |
102 |
103 | $(_RelativePath)
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | PrepareForRun
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/publish-logicapp/LogicApp.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "LogicAppName": {
6 | "value": "raz-mediaservices-publishworkflow-logic"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/publish-logicapp/publish-logicapp.deployproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 |
8 |
9 | Release
10 | AnyCPU
11 |
12 |
13 |
14 | 1d3b4467-6b5a-49e9-a1de-4fbe59b2184b
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | False
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/publish-streaming.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "publish-logicapp", "publish-logicapp\publish-logicapp.deployproj", "{1D3B4467-6B5A-49E9-A1DE-4FBE59B2184B}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {1D3B4467-6B5A-49E9-A1DE-4FBE59B2184B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {1D3B4467-6B5A-49E9-A1DE-4FBE59B2184B}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {1D3B4467-6B5A-49E9-A1DE-4FBE59B2184B}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {1D3B4467-6B5A-49E9-A1DE-4FBE59B2184B}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {D3EBB541-0775-4B6E-A972-498EDA852FD3}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/upload-and-encode-logicapp/Deployment.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | bin\$(Configuration)\
7 | false
8 | true
9 | false
10 | None
11 | obj\
12 | $(BaseIntermediateOutputPath)\
13 | $(BaseIntermediateOutputPath)$(Configuration)\
14 | $(IntermediateOutputPath)ProjectReferences
15 | $(ProjectReferencesOutputPath)\
16 | true
17 |
18 |
19 |
20 | false
21 | false
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Always
33 |
34 |
35 | Never
36 |
37 |
38 | false
39 | Build
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | _GetDeploymentProjectContent;
48 | _CalculateContentOutputRelativePaths;
49 | _GetReferencedProjectsOutput;
50 | _CalculateArtifactStagingDirectory;
51 | _CopyOutputToArtifactStagingDirectory;
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Configuration=$(Configuration);Platform=$(Platform)
69 |
70 |
71 |
75 |
76 |
77 |
78 | $([System.IO.Path]::GetFileNameWithoutExtension('%(ProjectReference.Identity)'))
79 |
80 |
81 |
82 |
83 |
84 |
85 | $(OutDir)
86 | $(OutputPath)
87 | $(ArtifactStagingDirectory)\
88 | $(ArtifactStagingDirectory)staging\
89 | $(Build_StagingDirectory)
90 |
91 |
92 |
93 |
94 |
96 |
97 | <_OriginalIdentity>%(DeploymentProjectContentOutput.Identity)
98 | <_RelativePath>$(_OriginalIdentity.Replace('$(MSBuildProjectDirectory)', ''))
99 |
100 |
101 |
102 |
103 | $(_RelativePath)
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | PrepareForRun
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/upload-and-encode-logicapp/LogicApp.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "videoindexer-v2_1_Connection_Name": {
6 | "value": "videoindexer-v2"
7 | },
8 | "azureblob_1_accessKey": {
9 | "value": ""
10 | },
11 | "videoindexer-v2_1_api_key": {
12 | "value": ""
13 | },
14 | "keyvault_1_token:clientId": {
15 | "value": ""
16 | },
17 | "keyvault_1_token:clientSecret": {
18 | "value": ""
19 | },
20 | "keyvault_1_token:TenantId": {
21 | "value": ""
22 | },
23 | "keyvault_1_token:resourceUri": {
24 | "value": ""
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/upload-and-encode-logicapp/upload-and-encode-logicapp.deployproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 |
8 |
9 | Release
10 | AnyCPU
11 |
12 |
13 |
14 | fe66cf17-0477-415a-8014-dc18097f41ff
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | False
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/logic-app-using-workflow-functions/upload-and-encode.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{151D2E53-A2C4-4D7D-83FE-D05416EBD58E}") = "upload-and-encode-logicapp", "upload-and-encode-logicapp\upload-and-encode-logicapp.deployproj", "{FE66CF17-0477-415A-8014-DC18097F41FF}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {FE66CF17-0477-415A-8014-DC18097F41FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {FE66CF17-0477-415A-8014-DC18097F41FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {FE66CF17-0477-415A-8014-DC18097F41FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {FE66CF17-0477-415A-8014-DC18097F41FF}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {D3EBB541-0775-4B6E-A972-498EDA852FD3}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/sample.env:
--------------------------------------------------------------------------------
1 | # Copy the content of this file to a file named ".env". It should be stored at the root of the repo.
2 | # Make sure to exclude this file from GitHub checkins using a .gitignore file
3 |
4 | # The values can be obtained from the API Access page for your Media Services account in the portal.
5 | AZURE_TENANT_DOMAIN="microsoft.onmicrosoft.com"
6 | AZURE_TENANT_ID="00000000-0000-0000-0000-000000000000"
7 | AZURE_MEDIA_SERVICES_ACCOUNT_NAME="amsaccount"
8 | AZURE_RESOURCE_GROUP="amsResourceGroup"
9 | AZURE_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
10 | AZURE_ARM_TOKEN_AUDIENCE="https://management.core.windows.net/"
11 | AZURE_ARM_ENDPOINT="https://management.azure.com/"
12 |
13 | # You must change this if you are using Gov Cloud, China, or other non standard cloud regions
14 | AZURE_AAD_ENDPOINT="https://login.microsoftonline.com"
--------------------------------------------------------------------------------