Tutorial: Cargar, codificar y hacer streaming de vídeos con Media Services v3
¿Busca la documentación de Media Services, versión 2?
Nota
Aunque en este tutorial se usan los ejemplos del SDK de .NET, los pasos generales son los mismos para la API REST, la CLI u otros SDK admitidos.
Azure Media Services le permite codificar los archivos multimedia en formatos que se pueden reproducir en una gran variedad de exploradores y dispositivos. Por ejemplo, puede que quiera transmitir su contenido en los formatos HLS o MPEG DASH de Apple. Antes de la transmisión, primero debe codificar su archivo de medios digitales de alta calidad. Para obtener ayuda con la codificación, consulte el concepto de codificación. Este tutorial carga un archivo de vídeo local y codifica el archivo cargado. También puede codificar contenido accesible a través de una dirección URL HTTPS. Para más información, consulte Creación de una entrada de un trabajo desde una dirección URL HTTP(s).

En este tutorial se muestra cómo realizar las siguientes acciones:
- Descargue la aplicación de ejemplo que se describe en el tema
- Examine el código que se carga, codifica y transmite en streaming.
- Ejecute la aplicación.
- Pruebe la URL de streaming.
- Limpieza de recursos.
Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.
Requisitos previos
- Instale Visual Studio Code para Windows, macOS o Linux o Visual Studio 2019 para Windows o Mac.
- Instale el SDK para .NET 5.0.
- Cree una cuenta de Media Services. Asegúrese de copiar los detalles de acceso a la API en formato JSON o de almacenar los valores necesarios para conectarse a la cuenta de Media Services en el formato de archivo .env que se usa en este ejemplo.
- Siga los pasos que se indican en Acceso a la API de Azure Media Services con la CLI de Azure y guarde las credenciales. Las necesitará para acceder a la API de este ejemplo, o bien deberá especificarlas en el formato de archivo .env.
Descarga y configuración del ejemplo
Clone un repositorio GitHub que contenga el ejemplo de .NET de streaming en la máquina con el siguiente comando:
git clone https://github.com/Azure-Samples/media-services-v3-dotnet-tutorials.git
El ejemplo se encuentra en la carpeta UploadEncodeAndStreamFiles.
Abra appsettings.json en el proyecto que ha descargado. Sustituya los valores por las credenciales que obtuvo de acceder a las API.
Nota
También puede usar el formato de archivo .env en la raíz del proyecto para establecer las variables de entorno solo una vez para todos los proyectos del repositorio de ejemplos de .NET. Solo tiene que copiar el archivo sample.env y rellenar la información que obtuvo de la página Acceso de API de Media Services en Azure Portal o la CLI de Azure. Cambie el nombre del archivo sample.env a solo .env para usarlo en todos los proyectos.
El archivo .gitignore ya está configurado para evitar su publicación en el repositorio bifurcado.
Examen del código que carga, codifica y transmite en secuencias
En esta sección se examinan las funciones definidas en el archivo Program.cs del proyecto UploadEncodeAndStreamFiles.
Este ejemplo realiza las acciones siguientes:
- Crea una nueva transformación (antes comprueba si existe la transformación especificada).
- Crea un recurso de salida que se usa como salida del trabajo de codificación.
- Crea un recurso de entrada y carga en él el archivo de vídeo local especificado. El recurso se usa como entrada del trabajo.
- Envía al trabajo de codificación con la entrada y salida que se han creado.
- Comprueba el estado del trabajo.
- Crea un objeto StreamingLocator.
- Crea direcciones URL de streaming.
Empiece a usar las API de Media Services con el SDK de .NET.
Para empezar a usar las API de Media Services con. NET, debe crear un objeto AzureMediaServicesClient. Para crear el objeto, debe proporcionar las credenciales para que el cliente se conecte a Azure mediante Azure Active Directory. Otra opción es usar la autenticación interactiva, que se implementa en GetCredentialsInteractiveAuthAsync.
public static async Task<IAzureMediaServicesClient> CreateMediaServicesClientAsync(ConfigWrapper config, bool interactive = false)
{
ServiceClientCredentials credentials;
if (interactive)
credentials = await GetCredentialsInteractiveAuthAsync(config);
else
credentials = await GetCredentialsAsync(config);
return new AzureMediaServicesClient(config.ArmEndpoint, credentials)
{
SubscriptionId = config.SubscriptionId,
};
}
En el código que ha clonado al principio del artículo, la función GetCredentialsAsync crea el objeto ServiceClientCredentials en función de las credenciales proporcionadas en el archivo de configuración local (appsettings.json) o por medio del archivo de variables de entorno .env situado en la raíz del repositorio.
private static async Task<ServiceClientCredentials> GetCredentialsAsync(ConfigWrapper config)
{
// Use ConfidentialClientApplicationBuilder.AcquireTokenForClient to get a token using a service principal with symmetric key
var scopes = new[] { config.ArmAadAudience + "/.default" };
var app = ConfidentialClientApplicationBuilder.Create(config.AadClientId)
.WithClientSecret(config.AadSecret)
.WithAuthority(AzureCloudInstance.AzurePublic, config.AadTenantId)
.Build();
var authResult = await app.AcquireTokenForClient(scopes)
.ExecuteAsync()
.ConfigureAwait(false);
return new TokenCredentials(authResult.AccessToken, TokenType);
}
En el caso de la autenticación interactiva, la función GetCredentialsInteractiveAuthAsync crea el objeto ServiceClientCredentials en función de una autenticación interactiva y los parámetros de conexión proporcionados en el archivo de configuración local (appsettings.json) o a través del archivo de variables de entorno .env en la raíz del repositorio. En ese caso, AADCLIENTID y AADSECRET no son necesarios en el archivo de variables de entorno o de configuración.
private static async Task<ServiceClientCredentials> GetCredentialsInteractiveAuthAsync(ConfigWrapper config)
{
var scopes = new[] { config.ArmAadAudience + "/user_impersonation" };
// client application of Az Cli
string ClientApplicationId = "04b07795-8ddb-461a-bbee-02f9e1bf7b46";
AuthenticationResult result = null;
IPublicClientApplication app = PublicClientApplicationBuilder.Create(ClientApplicationId)
.WithAuthority(AzureCloudInstance.AzurePublic, config.AadTenantId)
.WithRedirectUri("http://localhost")
.Build();
var accounts = await app.GetAccountsAsync();
try
{
result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
try
{
result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
}
catch (MsalException maslException)
{
Console.Error.WriteLine($"ERROR: MSAL interactive authentication exception with code '{maslException.ErrorCode}' and message '{maslException.Message}'.");
}
}
catch (MsalException maslException)
{
Console.Error.WriteLine($"ERROR: MSAL silent authentication exception with code '{maslException.ErrorCode}' and message '{maslException.Message}'.");
}
return new TokenCredentials(result.AccessToken, TokenType);
}
Creación de un recurso de entrada y carga de un archivo local en él
La función CreateInputAsset crea un nuevo recurso de entrada y carga en él el archivo de vídeo local especificado. Este Recurso se utiliza como entrada para el trabajo de codificación. En Media Services v3, la entrada a un trabajo puede ser tanto un recurso como contenido que se pone a disposición de la cuenta de Media Services a través de direcciones URL HTTPS. Para más información sobre cómo codificar desde una dirección URL HTTPS, consulte este artículo.
En Media Services v3, se utilizan las API de Azure Storage para cargar archivos. En el siguiente fragmento de código de .NET se muestra cómo hacerlo.
La función siguiente realiza estas acciones:
Crea un recurso.
Obtiene una dirección URL de SAS que se puede escribir para el contenedor de almacenamiento del recurso.
Si usa la función ListContainerSas de un recurso para obtener direcciones URL SAS, tenga en cuenta que la función devuelve varias URL de SAS, ya que hay dos claves para cada cuenta de almacenamiento. Las cuentas de almacenamiento tienen dos claves, ya que eso permite una rotación perfecta de las claves de cuenta de almacenamiento (por ejemplo, cambiar una mientras se usa la otra y, luego, empezar a usar la clave nueva y rotar la otra). La primera dirección URL de SAS representa clave de almacenamiento 1, mientras que la segunda representa clave de almacenamiento 2.
Carga el archivo en el contenedor de almacenamiento mediante la dirección URL de SAS.
private static async Task<Asset> CreateInputAssetAsync(
IAzureMediaServicesClient client,
string resourceGroupName,
string accountName,
string assetName,
string fileToUpload)
{
// In this example, we are assuming that the asset name is unique.
//
// If you already have an asset with the desired name, use the Assets.Get method
// to get the existing asset. In Media Services v3, the Get method on entities returns null
// if the entity doesn't exist (a case-insensitive check on the name).
// Call Media Services API to create an Asset.
// This method creates a container in storage for the Asset.
// The files (blobs) associated with the asset will be stored in this container.
Asset asset = await client.Assets.CreateOrUpdateAsync(resourceGroupName, accountName, assetName, new Asset());
// Use Media Services API to get back a response that contains
// SAS URL for the Asset container into which to upload blobs.
// That is where you would specify read-write permissions
// and the exparation time for the SAS URL.
var response = await client.Assets.ListContainerSasAsync(
resourceGroupName,
accountName,
assetName,
permissions: AssetContainerPermission.ReadWrite,
expiryTime: DateTime.UtcNow.AddHours(4).ToUniversalTime());
var sasUri = new Uri(response.AssetContainerSasUrls.First());
// Use Storage API to get a reference to the Asset container
// that was created by calling Asset's CreateOrUpdate method.
BlobContainerClient container = new BlobContainerClient(sasUri);
BlobClient blob = container.GetBlobClient(Path.GetFileName(fileToUpload));
// Use Strorage API to upload the file into the container in storage.
await blob.UploadAsync(fileToUpload);
return asset;
}
Creación de un recurso de salida para almacenar el resultado de un trabajo
El recurso de salida almacena el resultado del trabajo de codificación. El proyecto define la función DownloadResults que descarga los resultados de este recurso de salida en la carpeta "output", para que se pueda ver lo que tiene.
private static async Task<Asset> CreateOutputAssetAsync(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string assetName)
{
bool existingAsset = true;
Asset outputAsset;
try
{
// Check if an Asset already exists
outputAsset = await client.Assets.GetAsync(resourceGroupName, accountName, assetName);
}
catch (ErrorResponseException ex) when (ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
existingAsset = false;
}
Asset asset = new Asset();
string outputAssetName = assetName;
if (existingAsset)
{
// Name collision! In order to get the sample to work, let's just go ahead and create a unique asset name
// Note that the returned Asset can have a different name than the one specified as an input parameter.
// You may want to update this part to throw an Exception instead, and handle name collisions differently.
string uniqueness = $"-{Guid.NewGuid():N}";
outputAssetName += uniqueness;
Console.WriteLine("Warning – found an existing Asset with name = " + assetName);
Console.WriteLine("Creating an Asset with this name instead: " + outputAssetName);
}
return await client.Assets.CreateOrUpdateAsync(resourceGroupName, accountName, outputAssetName, asset);
}
Creación de una transformación y de un trabajo que codifica el archivo cargado
Cuando se codifica o procesa contenido en Media Services, es un patrón común configurar los ajustes de codificación como una receta. Después, podría enviar un trabajo para aplicar esa receta a un vídeo. Al enviar nuevos trabajos en cada nuevo vídeo, está aplicando dicha receta a todos los vídeos de la biblioteca. Una receta en Media Services se llama transformación. Para obtener más información, consulte Transformaciones y trabajos. El ejemplo descrito en este tutorial define una receta que codifica el vídeo para transmitirlo a varios dispositivos iOS y Android.
Transformación
Al crear una nueva instancia de la transformación, debe especificar qué desea originar como salida. El parámetro requerido es un objeto TransformOutput, como se muestra en el código siguiente. Cada objeto TransformOutput contiene un valor preestablecido. El valor preestablecido describe las instrucciones paso a paso de las operaciones de procesamiento de vídeo o audio que se utilizarán para generar el objeto TransformOutput deseado. El ejemplo descrito en este artículo utiliza un valor preestablecido integrado denominado AdaptiveStreaming. El valor preestablecido codifica el vídeo de entrada en una escala de velocidad de bits generada automáticamente (pares resolución-velocidad de bits) basada en la resolución y la velocidad de bits, y produce archivos ISO MP4 con vídeo H.264 y audio AAC correspondiente a cada par resolución-velocidad de bits. Para más información sobre este valor preestablecido, consulte el artículo sobre la generación automática de la escala de velocidad de bits.
Puede usar un valor de EncoderNamedPreset integrado o valores preestablecidos personalizados. Para más información, consulte Personalización de los valores predefinidos del codificador.
Al crear una transformación, debe comprobar primero si ya existe una con el método Get, tal como se muestra en el código siguiente. En Media Services v3, los métodos Get en las entidades devuelven null si la entidad no existe (una comprobación sin distinción entre mayúsculas y minúsculas en el nombre).
private static async Task<Transform> GetOrCreateTransformAsync(
IAzureMediaServicesClient client,
string resourceGroupName,
string accountName,
string transformName)
{
bool createTransform = false;
Transform transform = null;
try
{
// Does a transform already exist with the desired name? Assume that an existing Transform with the desired name
// also uses the same recipe or Preset for processing content.
transform = client.Transforms.Get(resourceGroupName, accountName, transformName);
}
catch (ErrorResponseException ex) when (ex.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
createTransform = true;
}
if (createTransform)
{
// You need to specify what you want it to produce as an output
TransformOutput[] output = new TransformOutput[]
{
new TransformOutput
{
// The preset for the Transform is set to one of Media Services built-in sample presets.
// You can customize the encoding settings by changing this to use "StandardEncoderPreset" class.
Preset = new BuiltInStandardEncoderPreset()
{
// This sample uses the built-in encoding preset for Adaptive Bitrate Streaming.
PresetName = EncoderNamedPreset.AdaptiveStreaming
}
}
};
// Create the Transform with the output defined above
transform = await client.Transforms.CreateOrUpdateAsync(resourceGroupName, accountName, transformName, output);
}
return transform;
}
Trabajo
Como se mencionó anteriormente, el objeto Transform es la receta y un trabajo es la solicitud real a Media Services para aplicar que dicho objeto Transform a un determinado contenido de audio o vídeo de entrada. El trabajo especifica información como la ubicación del vídeo de entrada y la ubicación de la salida.
En este ejemplo, el vídeo de entrada se ha cargado desde la máquina local. Para más información sobre cómo codificar desde una dirección URL HTTPS, consulte este artículo.
private static async Task<Job> SubmitJobAsync(IAzureMediaServicesClient client,
string resourceGroupName,
string accountName,
string transformName,
string jobName,
string inputAssetName,
string outputAssetName)
{
// Use the name of the created input asset to create the job input.
JobInput jobInput = new JobInputAsset(assetName: inputAssetName);
JobOutput[] jobOutputs =
{
new JobOutputAsset(outputAssetName),
};
// In this example, we are assuming that the job name is unique.
//
// If you already have a job with the desired name, use the Jobs.Get method
// to get the existing job. In Media Services v3, the Get method on entities returns null
// if the entity doesn't exist (a case-insensitive check on the name).
Job job = await client.Jobs.CreateAsync(
resourceGroupName,
accountName,
transformName,
jobName,
new Job
{
Input = jobInput,
Outputs = jobOutputs,
});
return job;
}
Espere a que el trabajo se complete.
El trabajo tarda algún tiempo en completarse y cuando lo hace querrá recibir una notificación. En el ejemplo de código siguiente se muestra cómo sondear el servicio para conocer el estado del trabajo. El sondeo no es un procedimiento recomendado para aplicaciones de producción debido a la posible latencia. El sondeo se puede limitar si se sobreutiliza en una cuenta. Los desarrolladores deben utilizar en su lugar Event Grid.
Event Grid está diseñado para una alta disponibilidad, un rendimiento consistente y una escala dinámica. Con Event Grid, sus aplicaciones pueden escuchar y reaccionar a eventos de casi todos los servicios de Azure y de orígenes personalizados. El control de eventos sencillo y reactivo basado en HTTP le ayuda a crear soluciones eficaces con filtrado y enrutamiento de eventos inteligente. Consulte Enrutamiento de eventos a un punto de conexión web personalizado.
El trabajo pasa normalmente por los siguientes estados: Programado, En cola, Procesando, Finalizado (el estado final). Si el trabajo ha encontrado un error, obtendrá el estado Error. Si el trabajo está en proceso de cancelación, obtendrá los mensajes Cancelando y Cancelado cuando haya terminado.
private static async Task<Job> WaitForJobToFinishAsync(IAzureMediaServicesClient client,
string resourceGroupName,
string accountName,
string transformName,
string jobName)
{
const int SleepIntervalMs = 20 * 1000;
Job job;
do
{
job = await client.Jobs.GetAsync(resourceGroupName, accountName, transformName, jobName);
Console.WriteLine($"Job is '{job.State}'.");
for (int i = 0; i < job.Outputs.Count; i++)
{
JobOutput output = job.Outputs[i];
Console.Write($"\tJobOutput[{i}] is '{output.State}'.");
if (output.State == JobState.Processing)
{
Console.Write($" Progress (%): '{output.Progress}'.");
}
Console.WriteLine();
}
if (job.State != JobState.Finished && job.State != JobState.Error && job.State != JobState.Canceled)
{
await Task.Delay(SleepIntervalMs);
}
}
while (job.State != JobState.Finished && job.State != JobState.Error && job.State != JobState.Canceled);
return job;
}
Códigos de error de trabajo
Consulte Códigos de error.
Obtención de un objeto StreamingLocator
Una vez finalizada la codificación, el siguiente paso es poner el vídeo del recurso de salida a disposición de los clientes para su reproducción. Puede hacerlo disponible en dos pasos: en primer lugar, cree un objeto localizador de streaming y, después, cree las direcciones URL de streaming que pueden usar los clientes.
El proceso de creación de un objeto StreamingLocator se denomina publicación. De forma predeterminada, el objeto StreamingLocator es válido inmediatamente después de realizar las llamadas a la API y dura hasta que se elimina, salvo que configure las horas de inicio y de finalización opcionales.
Al crear un objeto StreamingLocator, deberá especificar el objeto StreamingPolicyName deseado. En este ejemplo, transmitirá contenido no cifrado, de modo que se puede usar la directiva de streaming sin cifrar predefinida, PredefinedStreamingPolicy.ClearStreamingOnly.
Importante
Al utilizar un objeto StreamingPolicy personalizado, debe diseñar un conjunto limitado de dichas directivas para su cuenta de Media Service y reutilizarlas para sus localizadores de streaming siempre que se necesiten las mismas opciones y protocolos de cifrado. La cuenta de Media Service tiene una cuota para el número de entradas de Streaming Policy. No debe crear un una nueva directiva de streaming para cada localizador de streaming.
En el código siguiente se da por supuesto que está llamando a la función con un único objeto locatorName.
private static async Task<StreamingLocator> CreateStreamingLocatorAsync(
IAzureMediaServicesClient client,
string resourceGroup,
string accountName,
string assetName,
string locatorName)
{
StreamingLocator locator = await client.StreamingLocators.CreateAsync(
resourceGroup,
accountName,
locatorName,
new StreamingLocator
{
AssetName = assetName,
StreamingPolicyName = PredefinedStreamingPolicy.ClearStreamingOnly
});
return locator;
}
Aunque el ejemplo de este tema trata del streaming, puede utilizar la misma llamada para crear un objeto StreamingLocator para la entrega de vídeo mediante descarga progresiva.
Obtención de direcciones URL de streaming
Ahora que se ha creado el objeto StreamingLocator, puede obtener las direcciones URL de streaming, como se muestra en GetStreamingURLs. Para crear una dirección URL, debe concatenar el nombre de host del punto de conexión de streaming y la ruta de acceso del objeto StreamingLocator. En este ejemplo, se usa el punto de conexión de streaming predeterminado. Cuando cree su primera cuenta de Media Services, este punto de conexión de streaming predeterminado estará en un estado detenido, por lo que deberá llamar a Iniciar.
Nota
En este método, se necesita el objeto locatorName que se utilizó al crear el objeto StreamingLocator del recurso de salida.
private static async Task<IList<string>> GetStreamingUrlsAsync(
IAzureMediaServicesClient client,
string resourceGroupName,
string accountName,
String locatorName)
{
const string DefaultStreamingEndpointName = "default";
IList<string> streamingUrls = new List<string>();
StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(resourceGroupName, accountName, DefaultStreamingEndpointName);
if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running)
{
await client.StreamingEndpoints.StartAsync(resourceGroupName, accountName, DefaultStreamingEndpointName);
}
ListPathsResponse paths = await client.StreamingLocators.ListPathsAsync(resourceGroupName, accountName, locatorName);
foreach (StreamingPath path in paths.StreamingPaths)
{
UriBuilder uriBuilder = new UriBuilder
{
Scheme = "https",
Host = streamingEndpoint.HostName,
Path = path.Paths[0]
};
streamingUrls.Add(uriBuilder.ToString());
}
return streamingUrls;
}
Limpieza de los recursos en su cuenta de Media Services
Por lo general, debe limpiar todo, excepto los objetos que piensa reutilizar (normalmente, reutilizará transformaciones y conservará objetos StreamingLocators, etc.). Si quiere que la cuenta esté limpia después de la experimentación, elimine los recursos que no tiene previsto volver a usar. Por ejemplo, el siguiente código elimina el trabajo, los recursos creados y la directiva de clave de contenido:
private static async Task CleanUpAsync(
IAzureMediaServicesClient client,
string resourceGroupName,
string accountName,
string transformName,
string jobName,
List<string> assetNames,
string contentKeyPolicyName = null
)
{
await client.Jobs.DeleteAsync(resourceGroupName, accountName, transformName, jobName);
foreach (var assetName in assetNames)
{
await client.Assets.DeleteAsync(resourceGroupName, accountName, assetName);
}
if (contentKeyPolicyName != null)
{
client.ContentKeyPolicies.Delete(resourceGroupName, accountName, contentKeyPolicyName);
}
}
Ejecutar la aplicación de ejemplo
- Presione Control + F5 para ejecutar la aplicación EncodeAndStreamFiles.
- Copie una de las direcciones URL de streaming desde la consola.
En este ejemplo se muestran las direcciones URL que pueden usarse para reproducir el vídeo con diferentes protocolos:

Prueba de la URL de streaming
Para probar el streaming, este artículo usa Azure Media Player.
Nota
Si el reproductor está hospedado en un sitio https, asegúrese de actualizar la dirección URL a "https".
- Abra un explorador web y vaya a https://aka.ms/azuremediaplayer/.
- En el cuadro Dirección URL: , pegue uno de los valores de la dirección URL de streaming que obtuvo al ejecutar la aplicación.
- Seleccione Update Player (Actualizar reproductor).
Azure Media Player puede usarse para realizar pruebas, pero no debe usarse en un entorno de producción.
Limpieza de recursos
Si ya no necesita ninguno de los recursos del grupo de recursos, incluida las cuentas de almacenamiento y de Media Services que ha creado en este tutorial, elimine el grupo de recursos que ha creado antes.
Ejecute el siguiente comando de la CLI:
az group delete --name amsResourceGroup
Subprocesamiento múltiple
Los SDK de Azure Media Services v3 no son seguros para subprocesos. Al desarrollar una aplicación multiproceso, debe generar y utilizar un nuevo objeto AzureMediaServicesClient por subproceso.
Formule preguntas, realice comentarios y obtenga actualizaciones
Consulte el artículo Comunidad de Azure Media Services para ver diferentes formas de formular preguntas, enviar comentarios y obtener actualizaciones de Media Services.
Pasos siguientes
Ahora que sabe cómo cargar, codificar y transmitir el vídeo, consulte el siguiente artículo: