基于Node.js使用Azure Media Services转码生成HLS流的技术咨询
从AWS Elastic Transcoder迁移到Azure Media Services的方案
背景
原AWS架构通过Lambda触发Elastic Transcoder,将S3上传的视频转码为多画质HLS流。现已将S3替换为Azure Blob Storage,需基于Azure Media Services实现相同转码逻辑。
1. Node.js中使用Azure Media Services转码为HLS的示例
以下示例基于Azure Media Services v3 SDK(@azure/arm-mediaservices)实现,对应原AWS Lambda的转码逻辑:
前置准备
- 安装依赖:
npm install @azure/arm-mediaservices @azure/identity @azure/storage-blob dotenv - 配置环境变量:Azure订阅ID、资源组名、Media Services账户名、Blob存储连接字符串、存储账户名
代码示例
const { DefaultAzureCredential } = require("@azure/identity"); const { AzureMediaServices } = require("@azure/arm-mediaservices"); const { BlobServiceClient } = require("@azure/storage-blob"); const dotenv = require("dotenv"); dotenv.config(); // 初始化客户端 const credential = new DefaultAzureCredential(); const mediaServicesClient = new AzureMediaServices( credential, process.env.AZURE_SUBSCRIPTION_ID ); const blobServiceClient = BlobServiceClient.fromConnectionString( process.env.AZURE_STORAGE_CONNECTION_STRING ); // 核心转码函数 async function transcodeVideoToHLS(blobName, containerName) { const accountName = process.env.AZURE_MEDIA_SERVICES_ACCOUNT_NAME; const resourceGroupName = process.env.AZURE_RESOURCE_GROUP_NAME; // 1. 创建Media Services Asset(关联Blob存储中的源视频) const assetName = `input-asset-${Date.now()}`; const asset = await mediaServicesClient.assets.createOrUpdate( resourceGroupName, accountName, assetName, { description: "Input asset for video transcoding", storageAccountName: process.env.AZURE_STORAGE_ACCOUNT_NAME } ); // 2. 将Blob中的视频复制到Asset对应的存储容器 const sourceContainerClient = blobServiceClient.getContainerClient(containerName); const sourceBlobClient = sourceContainerClient.getBlobClient(blobName); const assetContainerClient = blobServiceClient.getContainerClient(asset.container); const destinationBlobClient = assetContainerClient.getBlobClient(blobName); await destinationBlobClient.syncCopyFromURL(sourceBlobClient.url); // 3. 创建或复用Transform(对应AWS Preset,定义转码规则) const transformName = "MultiBitrateHLS"; try { await mediaServicesClient.transforms.get(resourceGroupName, accountName, transformName); } catch (err) { // 创建包含多画质HLS和MP4输出的Transform await mediaServicesClient.transforms.createOrUpdate( resourceGroupName, accountName, transformName, { description: "Multi-bitrate HLS + MP4 transcoding preset", outputs: [ // HLS多码率自适应流(360p/480p/720p/1080p+64k音频) { preset: { "@odata.type": "#Microsoft.Media.StandardEncoderPreset", codecs: [ { "@odata.type": "#Microsoft.Media.H264Video", keyFrameInterval: "PT2S", complexity: "Balanced", layers: [ { bitrate: 600000, width: "640", height: "360", label: "360p" }, { bitrate: 1500000, width: "854", height: "480", label: "480p" }, { bitrate: 3000000, width: "1280", height: "720", label: "720p" }, { bitrate: 6000000, width: "1920", height: "1080", label: "1080p" } ] }, { "@odata.type": "#Microsoft.Media.AacAudio", bitrate: 64000, channels: 2 } ], formats: [ { "@odata.type": "#Microsoft.Media.HlsFormat", filenamePattern: "{Basename}_{Label}_{Bitrate}", segmentsPerTsFile: 10 // 对应原SegmentDuration=10 } ] } }, // 额外MP4输出(对应原AWS的MP4 Preset) { preset: { "@odata.type": "#Microsoft.Media.StandardEncoderPreset", codecs: [ { "@odata.type": "#Microsoft.Media.H264Video", keyFrameInterval: "PT2S", complexity: "Balanced", layers: [{ bitrate: 5000000, width: "1920", height: "1080" }] }, { "@odata.type": "#Microsoft.Media.AacAudio", bitrate: 128000, channels: 2 } ], formats: [ { "@odata.type": "#Microsoft.Media.Mp4Format", filenamePattern: "{Basename}_1080p.mp4" } ] } } ] } ); } // 4. 创建转码Job const jobName = `transcode-job-${Date.now()}`; const outputAssetName = `output-asset-${Date.now()}`; await mediaServicesClient.jobs.create( resourceGroupName, accountName, transformName, jobName, { input: { "@odata.type": "#Microsoft.Media.JobInputAsset", assetName: assetName }, outputs: [ { "@odata.type": "#Microsoft.Media.JobOutputAsset", assetName: outputAssetName } ] } ); console.log(`转码任务已启动:${jobName}`); console.log(`输出文件将存储在Asset:${outputAssetName}`); } // Azure Function触发器入口(监听Blob上传事件) module.exports = async function (context, myBlob) { const blobName = context.bindingData.name; const containerName = context.bindingData.containerName; try { await transcodeVideoToHLS(blobName, containerName); context.done(null, "转码任务初始化成功"); } catch (err) { context.log.error(err); context.done(err); } };
2. 视频存储:Blob Storage还是Media Services Assets?
- 核心结论:转码操作必须基于Media Services Assets,但源视频可先存储在Blob Storage,再关联到Assets;转码后的输出默认存储在Assets对应的Blob容器中,也可复制到其他Blob容器用于分发。
- 详细说明:
- Assets是Media Services的核心载体:Media Services的转码、流式处理等功能仅支持Assets作为输入输出,Assets本质是Blob Storage容器的逻辑封装,由Media Services管理权限和生命周期。
- Blob Storage可作为源存储:用户上传的视频可直接存在Blob Storage中,无需迁移,只需将文件复制或关联到Media Services Asset即可触发转码。
- 输出文件的处理:转码后的HLS流和MP4文件会自动保存到Output Asset对应的Blob容器,可直接通过Media Services流式终结点分发,也可复制到公共Blob容器配合CDN加速分发。
内容的提问来源于stack exchange,提问作者Ammar Abdul Aziz
相关产品推荐
相关产品推荐

