邊轉邊播是面向視頻在線播放需求的實時轉碼功能。通過閱讀本文,您可以了解邊轉邊播功能的優勢以及如何使用邊轉邊播。
功能簡介
不同于媒體轉碼需要在視頻上傳完成后等待整個視頻轉碼完成才能播放,邊轉邊播作為實時轉碼功能,可以實現原視頻文件上傳完成后立即開始播放,并在播放時僅對需要播放的視頻片段進行轉碼。邊轉邊播主要能為您帶來:
邊播放邊轉碼,播放無需等待。
轉碼優化,秒級開播跳播,接近本地的播放體驗。
不播放不轉碼,即使轉碼文件刪除了也能重新轉,顯著節省轉碼和存儲成本。
支持幾十種轉碼參數,轉碼參數可高度自定義。
兼容性高,支持300+種音視頻格式。
邊轉邊播不支持匿名播放。
使用流程
將視頻文件上傳到對象存儲OSS。
通過GenerateVideoPlaylist接口快速生成媒體播放列表文件,并使用OSS的簽名功能對播放列表進行簽名,最終獲取簽名后的播放列表。
播放器獲取播放列表進行播放,播放過程中自動觸發邊轉邊播功能。
使用場景
網盤:用戶上傳視頻到網盤,各種網盤客戶端立即能根據網絡情況選擇不同的分辨率進行播放。既保證了播放的實時性,又能確保視頻在不同設備上的兼容性。且網盤中大部分視頻都是冷視頻,使用邊轉邊播功能,沒有被用戶播放的視頻內容不會觸發轉碼,極大節省了轉碼和存儲成本。
聊天軟件視頻預覽:在即時通訊或社交媒體平臺中,發送方把視頻發送完畢(服務端接收完成),接收方立刻可以開始播放視頻,提高交流的實時性。歷史聊天記錄中長期不被觀看的視頻,轉碼生成的視頻文件可以定期清理以降低存儲成本,再次播放時亦可立刻播放。
網絡論壇與博客交流:使用邊轉邊播功能,用戶在要分享的原視頻上傳完成后,其他用戶可以立即播放轉碼后的視頻,同時保證視頻播放的流暢性、清晰度和兼容性。
功能特性
邊轉邊播的更多功能特性如下表所示。
特性 | 說明 |
標準化 |
|
低成本 |
|
高效率 |
|
支持音視頻格式列表
邊轉邊播支持的音視頻格式有300多種,幾乎包含了所有常見的音視頻格式。下面是邊轉邊播支持的部分常見音視頻格式。
輸入視頻格式 | avi、mov、flv、mkv、webm、mpeg、wmv、rm、vob、ts等 |
輸入音頻格式 | mp3、wav、aac、flac、wma等 |
輸出容器格式 | ts |
前提條件
已創建并獲取AccessKey。具體操作,請參見創建AccessKey。
已開通OSS服務、創建存儲空間并上傳文件到存儲空間。具體操作,請參見控制臺上傳文件。
您也可以調用API接口創建項目。具體操作,請參見CreateProject - 創建項目。
您可以調用ListProjects - 列出所有項目信息的列表接口列出指定地域下已創建的所有項目信息。
使用邊轉邊播功能時,您需要為RAM用戶授予IMM處理所需的相關權限。具體操作,請參見權限。
邊轉邊播需要使用到OSS的媒體處理能力(x-oss-process處理方式)。請在OSS配額中心申請“開啟新版本IMM數據處理能力”。
使用邊轉邊播前,需要先綁定IMM Project。關于控制臺和API如何綁定,請參見快速入門和AttachOSSBucket。
如您對源視頻或輸出目標視頻所在Bucket啟用了防盜鏈,請確保您設置“允許空Referer”的防盜鏈策略。防盜鏈參見Referer防盜鏈。
如您的播放器需跨域訪問OSS,請務必為目標視頻所在的Bucket啟用OSS跨域訪問。,請參見:跨域設置。
使用方法
使用Media Playlist示例
轉碼信息
源視頻信息
視頻格式:AVI
視頻源地址:oss://your-oss-bucket-name/test.avi
目標視頻信息
轉碼分片大小:10秒
預轉視頻長度:36秒
視頻流格式:H.264
視頻分辨率:1280x720
視頻幀率:25 fps
視頻碼率:2 Mbps
音頻流格式:AAC
音頻碼率:128 Kbps
目標文件存儲路徑前綴:oss://your-oss-bucket-name/output/media
步驟一:生成播放列表
請求示例
{ "ProjectName": "test-project", "SourceURI": "oss://your-oss-bucket-name/test.avi", "Targets": [ { "Audio": { "TranscodeAudio": { "Codec": "aac", "Bitrate": 128000, "SampleRate": 44100 } }, "Duration": 10, "InitialSegments": [ 2, 2, 2 ], "InitialTranscode": 36, "URI": "oss://your-oss-bucket-name/output/media", "Video": { "TranscodeVideo": { "Codec": "h264", "Bitrate": 2400000, "FrameRate": 25, "Resolution": "1280x", "ScaleType": "fit" } } } ] }
返回示例
{ "RequestId": "********-3ADC-576A-BD1E-************", "VideoPlaylist": [ { "FrameRate": "25", "Resolution": "1280x720", "Token": "3d8ca7d6b3**********4b3cb69fe3bf", "URI": "oss://your-oss-bucket-name/output/media.m3u8" } ] }
示例代碼
# -*- coding: utf-8 -*- import json from alibabacloud_imm20200930 import models as imm_20200930_models from alibabacloud_imm20200930.client import Client as imm20200930Client from alibabacloud_tea_openapi import models as open_api_models class Sample: def __init__(self): pass @staticmethod def create_client( access_key_id: str, access_key_secret: str, ) -> imm20200930Client: """ 使用AccessKey ID和AccessKey Secret初始化賬號Client。 @param access_key_id: @param access_key_secret: @return: Client @throws Exception """ config = open_api_models.Config( # 填寫您的AccessKey ID。 access_key_id=access_key_id, # 填寫您的AccessKey Secret。 access_key_secret=access_key_secret ) # 填寫訪問的IMM域名。 config.endpoint = f'imm.cn-hangzhou.aliyuncs.com' return imm20200930Client(config) @staticmethod def main() -> None: # 填寫IMM的AccessKey ID、AccessKey Secret,建議從配置中讀取。 imm_access_key_id = "yourAccessKeyId" imm_access_key_secret = "yourAccessKeySecret" # 填寫項目名稱。 project_name = "test-project" # 填寫源視頻的OSS URI。 source_uri = "oss://your-oss-bucket-name/test.avi" # 目標URI。 target_uri = "oss://your-oss-bucket-name/output/media" # 初始化客戶端。 client = Sample.create_client(imm_access_key_id, imm_access_key_secret) # 創建Target。 target = imm_20200930_models.GenerateVideoPlaylistRequestTargets( audio=imm_20200930_models.TargetAudio( transcode_audio=imm_20200930_models.TargetAudioTranscodeAudio( codec="aac", bitrate=128000, sample_rate=44100, ) ), duration=10, initial_segments=[2, 2, 2], initial_transcode=36, uri=target_uri, video=imm_20200930_models.TargetVideo( transcode_video=imm_20200930_models.TargetVideoTranscodeVideo( codec="h264", bitrate=2400000, frame_rate=25, resolution="1280x", scale_type="fit", ) ), ) # 創建API請求。 req = imm_20200930_models.GenerateVideoPlaylistRequest( project_name=project_name, source_uri=source_uri, targets=[target] ) # 打印API的請求值。 print(json.dumps(req.to_map(), indent=4)) # 發起請求 response = client.generate_video_playlist(req) # 打印API的返回值。 print(json.dumps(response.body.to_map(), indent=4)) if __name__ == '__main__': Sample.main()
package main import ( "fmt" openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" imm "github.com/alibabacloud-go/imm-20200930/v2/client" "github.com/alibabacloud-go/tea/tea" ) func main() { // 初始化IMM客戶端。 immClient, err := imm.NewClient(&openapi.Config{ RegionId: tea.String("cn-hangzhou"), // 填寫項目所在地域ID。 AccessKeyId: tea.String("your_access_key_id"), // 填寫RAM用戶的AccessKey ID。 AccessKeySecret: tea.String("your_access_key_secret"), // 填寫RAM用戶的AccessKey Secret。 }) if err != nil { // 錯誤處理。 panic(err) } // 填寫項目名稱。 projectName := "test-project" // 填寫視頻的OSS URI。 sourceUri := "oss://your-oss-bucket-name/test.avi" // 目標URI。 targetUri := "oss://your-oss-bucket-name/output/media" target := &imm.GenerateVideoPlaylistRequestTargets{ Audio: &imm.TargetAudio{ TranscodeAudio: &imm.TargetAudioTranscodeAudio{ Bitrate: tea.Int32(98304), Codec: tea.String("aac"), SampleRate: tea.Int32(44100), }, }, Duration: tea.Float32(10), InitialSegments: []*float32{tea.Float32(2), tea.Float32(2), tea.Float32(2)}, InitialTranscode: tea.Float32(36), URI: tea.String(targetUri), Video: &imm.TargetVideo{ TranscodeVideo: &imm.TargetVideoTranscodeVideo{ Codec: tea.String("h264"), Bitrate: tea.Int32(2400000), FrameRate: tea.Float32(25), Resolution: tea.String("1280x"), ScaleType: tea.String("fit"), }, }, } // 創建API請求。 req := &imm.GenerateVideoPlaylistRequest{ ProjectName: tea.String(projectName), SourceURI: tea.String(sourceUri), Targets: []*imm.GenerateVideoPlaylistRequestTargets{target}, } // 發起請求 res, err := immClient.GenerateVideoPlaylist(req) if err != nil { panic(err) } // 打印API的返回值。 fmt.Println("Response:", *res.Body) }
// This file is auto-generated, don't edit it. Thanks. package com.aliyun.sample; import com.aliyun.tea.*; public class Sample { /** * <b>description</b> : * <p>使用AK&SK初始化賬號Client</p> * @return Client * * @throws Exception */ public static com.aliyun.teaopenapi.Client createClient() throws Exception { // 工程代碼泄露可能會導致 AccessKey 泄露,并威脅賬號下所有資源的安全性。以下代碼示例僅供參考。 // 建議使用更安全的 STS 方式,更多鑒權訪問方式請參見:http://bestwisewords.com/document_detail/378657.html。 com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() // 必填,請確保代碼運行環境設置了環境變量 ALIBABA_CLOUD_ACCESS_KEY_ID。 .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")) // 必填,請確保代碼運行環境設置了環境變量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。 .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); // Endpoint 請參考 https://api.aliyun.com/product/imm config.endpoint = "imm.cn-beijing.aliyuncs.com"; return new com.aliyun.teaopenapi.Client(config); } /** * <b>description</b> : * <p>API 相關</p> * * @param path string Path parameters * @return OpenApi.Params */ public static com.aliyun.teaopenapi.models.Params createApiInfo() throws Exception { com.aliyun.teaopenapi.models.Params params = new com.aliyun.teaopenapi.models.Params() // 接口名稱 .setAction("GenerateVideoPlaylist") // 接口版本 .setVersion("2020-09-30") // 接口協議 .setProtocol("HTTPS") // 接口 HTTP 方法 .setMethod("POST") .setAuthType("AK") .setStyle("RPC") // 接口 PATH .setPathname("/") // 接口請求體內容格式 .setReqBodyType("json") // 接口響應體內容格式 .setBodyType("json"); return params; } public static void main(String[] args_) throws Exception { java.util.List<String> args = java.util.Arrays.asList(args_); com.aliyun.teaopenapi.Client client = Sample.createClient(); com.aliyun.teaopenapi.models.Params params = Sample.createApiInfo(); // query params java.util.Map<String, Object> queries = new java.util.HashMap<>(); queries.put("ProjectName", "test-project"); queries.put("SourceURI", "oss://your-oss-bucket-name/test.avi"); queries.put("Targets", "[{\"Video\":{\"TranscodeVideo\":{\"Codec\":\"h264\",\"Bitrate\":128000,\"FrameRate\":25,\"Resolution\":\"1280x\"}},\"Audio\":{\"TranscodeAudio\":{\"SampleRate\":44100,\"Codec\":\"aac\",\"Bitrate\":2400000}},\"Duration\":10,\"InitialSegments\":[2,2,2],\"InitialTranscode\":36,\"URI\":\"oss://your-oss-bucket-name/output/media\"}]"); // runtime options com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); com.aliyun.teaopenapi.models.OpenApiRequest request = new com.aliyun.teaopenapi.models.OpenApiRequest() .setQuery(com.aliyun.openapiutil.Client.query(queries)); // 復制代碼運行請自行打印 API 的返回值 // 返回值實際為 Map 類型,可從 Map 中獲得三類數據:響應體 body、響應頭 headers、HTTP 返回的狀態碼 statusCode。 client.callApi(params, request, runtime); } }
步驟二:對播放列表簽名
# -*- coding: utf-8 -*-
import os
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 從環境變量中獲取訪問憑證。運行本代碼示例之前,請先配置環境變量。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# 填寫Bucket所在地域對應的Endpoint。請按實際情況填寫。
endpoint = 'yourEndpoint'
# 填寫Endpoint對應的Region信息,例如cn-hangzhou。
region = 'cn-hangzhou'
# 目標Bucket名稱。
bucket_name = 'your-oss-bucket-name'
# 填寫生成的播放列表名稱。
key = 'output/media.m3u8'
# 指定Bucket實例,所有文件相關的方法都需要通過Bucket實例來調用。
bucket = oss2.Bucket(auth, endpoint, bucket_name, region=region)
# x-oss-process的處理方式為hls/sign,live_1。
params = {}
params.update({oss2.Bucket.PROCESS: 'hls/sign,live_1'})
# 簽名URL。
url = bucket.sign_url('GET', key, 7200, params=params, slash_safe=True)
# 生成的URL可以直接在HLS播放器中播放。
print(url)
# 本例生成的URL: http://your-oss-bucket-name.yourendpoint/output/media.m3u8?x-oss-process=hls%2Fsign%2Clive_1&x-oss-signature-version=OSS2&x-oss-expires=1683619052&x-oss-access-key-id=yourAccessKeyId&x-oss-signature=4Lja6Sgb7zXWzY9R9QTRe4FxI240fApDavp%2BSMj3ufg%3D
package main
import (
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"net/http"
"net/url"
"os"
"strings"
)
func main() {
// 從環境變量中獲取訪問憑證。運行本代碼示例之前,請先配置環境變量。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 創建OSSClient實例。
// yourEndpoint填寫Bucket對應的Endpoint,以華東1(杭州)為例,填寫為https://oss-cn-hangzhou.aliyuncs.com。其它Region請按實際情況填寫。
// yourRegion填寫Endpoint對應的Region信息,例如cn-hangzhou。
client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider), oss.AuthVersion(oss.AuthV4), oss.Region("yourRegion"))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 填寫Bucket名稱,例如your-oss-bucket-name。
bucket, err := client.Bucket("your-oss-bucket-name")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 使用oss hls/sign簽名。"hls/sign,live_1" 是指使用邊轉邊播的能力,為固定的格式。
// 填寫m3u8的完整路徑,例如output/media.m3u8。
// 填寫簽名的有效時間,例如7200,兩個小時有效。
signedURL, err := bucket.SignURL("output/media.m3u8", http.MethodGet, 7200, oss.Process("hls/sign,live_1"))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 轉換為可供播放器使用的URL。
rawUrl, err := url.Parse(signedURL)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
rawUrl.RawPath = strings.Replace(rawUrl.RawPath, "%2F", "/", -1)
// 打印輸出簽名后的URL。
fmt.Println(rawUrl.String())
// 簽名輸出URL可以直接粘貼到HLS播放器中播放。
//http://your-oss-bucket-name.yourEndpoint/output/media.m3u8?x-oss-access-key-id=yourAccessKeyId&x-oss-expires=1683618084&x-oss-process=hls%2Fsign%2Clive_1&x-oss-signature=%2BqTZ0R04Ft065gdyoP6f9yJdd1UXi%2F8eoxd9c9Stl2g%3D&x-oss-signature-version=OSS2
}
package com.aliyun.sample;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.net.URL;
import java.util.Date;
public class demo {
public static void main(String[] args) throws Throwable {
// 以華東2(北京)的外網Endpoint為例,其它Region請按實際情況填寫。
String endpoint = "https://oss-cn-beijing.aliyuncs.com";
String region = "cn-beijing";
// 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,請確保代碼運行環境設置了環境變量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,請確保代碼運行環境設置了環境變量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填寫Bucket名稱,例如examplebucket。
String bucketName = "test-project";
// 填寫Object完整路徑,例如exampleobject.txt。Object完整路徑中不能包含Bucket名稱。
String objectKey = "output/media.m3u8";
// 創建OSSClient實例。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
// 設置URL過期時間
Date expiration = new Date(new Date().getTime() + 7200 * 1000); // 2小時
GeneratePresignedUrlRequest request=new GeneratePresignedUrlRequest(bucketName, objectKey, HttpMethod.GET);
request.setExpiration(expiration);
request.setProcess("hls/sign,live_1");
// 生成簽名URL
URL signedUrl = ossClient.generatePresignedUrl(request);
// 輸出簽名URL
System.out.println(signedUrl);
// 關閉OSS客戶端
// 關閉OSSClient。
ossClient.shutdown(); try {
// 設置簽名URL過期時間,單位為毫秒。本示例以設置過期時間為1小時為例。
URL url = ossClient.generatePresignedUrl(bucketName, objectKey, expiration);
System.out.println(url);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
步驟三:播放視頻
步驟二:對播放列表簽名中生成的簽名后的URL,可以直接粘貼到HLS播放器中播放,操作方法如下。
Mac使用Safari播放
Mac系統的Safari播放器支持HLS視頻播放,您可以直接粘貼URL到Safari地址欄播放。
使用Aliplayer播放
打開阿里云Aliplayer播放器,粘貼URL到地址欄后播放,如下圖所示。
說明您也可以集成阿里云播放器SDK到您的業務系統中,在您的業務系統中播放。具體操作,請參見Web播放器簡介。
使用HLS播放器播放
把簽名后的URL粘貼到HLS播放器中。
使用Master Playlist示例
轉碼信息
源視頻信息
視頻格式:AVI
視頻源地址:oss://your-oss-bucket-name/test.avi
Master playlist地址:oss://your-oss-bucket-name/output/master.m3u8
目標視頻信息1
轉碼分片大小:10秒
預轉視頻長度:36秒
視頻流格式:H.264
視頻分辨率:1920x1080
視頻幀率:25 fps
音頻流格式:AAC
音頻碼率:128 Kbps
目標文件存儲路徑前綴:oss://your-oss-bucket-name/output/1080p/1080p
目標視頻信息2
轉碼分片大小:10秒
預轉視頻長度:36秒
視頻流格式:H.264
視頻分辨率:1280x720
視頻幀率:25 fps
音頻流格式:AAC
音頻碼率:96 Kbps
目標文件存儲路徑前綴:oss://your-oss-bucket-name/output/720p/720p
目標視頻信息3
轉碼分片大小:10秒
預轉視頻長度:36秒
視頻流格式:H.264
視頻分辨率:720x540
視頻幀率:25 fps
音頻流格式:AAC
音頻碼率:64 Kbps
目標文件存儲路徑前綴:oss://your-oss-bucket-name/output/540p/540p
步驟一:生成播放列表
步驟二:對播放列表簽名
您需要對返回的master playlist進行OSS URL簽名。簽名方式請參見步驟二:對播放列表簽名。
步驟三:播放視頻
播放方式請參見步驟三:播放視頻。
常見問題
需要使用定制的播放器嗎?
不需要。邊轉邊播功能支持標準的HLS協議,您使用支持標準HLS協議的播放器(例如:阿里云Aliplayer播放器,Safari瀏覽器)即可使用邊轉邊播功能。
輸出文件包括有哪些?
我們會根據您指定的輸入路徑前綴生成m3u8文件和ts文件,m3u8文件立刻生成。
如果您指定了預轉時長,系統將異步生成與該預轉時長相對應的TS文件。未指定預轉的部分將在視頻播放時按需觸發異步轉碼。如果視頻從未播放,則不會為未指定預轉的部分生成TS文件。例如,如果視頻從15分鐘的位置開始播放,系統僅會從該位置開始進行轉碼。相應生成的文件目錄樹如下:
.
├── outobjprefix.m3u8
├── outobjprefix-c280f054328fcde47c1732a8f2915009-0.ts
├── outobjprefix-c280f054328fcde47c1732a8f2915009-1.ts
├── outobjprefix-c280f054328fcde47c1732a8f2915009-2.ts
├── outobjprefix-c280f054328fcde47c1732a8f2915009-3.ts
已經生成的ts文件手動刪除后能正常播放嗎?
可以。只要視頻源文件和m3u8播放列表未被刪除,手動刪除部分或全部ts文件后,視頻仍能正常播放。這是因為當m3u8播放列表再次被請求時,會觸發ts文件的重新生成。這種方法允許對之前已播放但長時間未被觀看的視頻的ts文件進行清理,從而減少存儲成本,而不影響視頻未來的重新播放。
能使用非邊轉邊播的m3u8文件做邊轉邊播嗎?
不允許使用非邊轉邊播生成的m3u8文件來實現邊轉邊播功能。
能使用CDN為邊轉邊播加速嗎?
可以。詳情參見使用CDN為邊轉邊播加速。