API を使用して、ビデオオンデマンド (VOD) ファイルから 24 時間 365 日のライブストリームを作成します。複数の VOD ファイルを 1 つの連続したライブストリームに結合し、配信をスケジュールし、広告をリアルタイムまたはスケジュールされた間隔で挿入して収益を得ることができます。
仕組み
VOD-to-live ストリームを作成するには、プレイリストモードのプロダクションスタジオ用の API を呼び出します。処理は 4 つの手順で構成されます。
-
VOD システムバケットの有効化:ApsaraVideo VOD を有効化すると、システムは各サービスリージョンに独立した VOD システムバケットを割り当てます。このバケットを有効化して、メディアアセットをアップロードおよび管理します。
-
音声ファイルと動画ファイルのアップロード:ストリーミングする動画ファイルを ApsaraVideo VOD ストレージにアップロードします。例えば、再生順に従って動画 A、B、C をアップロードします。
-
ストリーミングドメインの追加:このドメインは、視聴者向けの再生 URL を提供します。
-
API を使用したプロダクションスタジオの設定:API を呼び出して、各動画の再生回数、およびエピソードリスト全体のループ回数を指定します。例えば、動画 A を 1 回、動画 B を 2 回、動画 C を 3 回再生するように設定します。その後、エピソードリストを取得し、ストリームを開始します。
前提条件
-
Alibaba Cloud アカウントを作成し、実名認証を完了していること。
-
ApsaraVideo VOD、ApsaraVideo Live、および Cloud Production Studio サービスが有効化されていること。詳細については、「Activate ApsaraVideo VOD」、「Activate and purchase ApsaraVideo Live」、「Activate the Cloud Production Studio service」をご参照ください。
説明プロダクションスタジオ機能は現在、中国 (上海)、中国 (北京)、アジアパシフィック SE 1 (シンガポール)、アジアパシフィック SE 3 (ジャカルタ) リージョンで利用できます。今後、さらに多くのリージョンに対応予定です。
-
ストリーミングドメインを保有していること。すぐに開始するには、中国本土外のライブセンターを選択し、アクセラレーションリージョンを 中国本土以外 に設定することを推奨します。これにより、ドメインが ICP 申請要件の対象外になります。
-
AliyunFCFullAccess、AliyunLiveFullAccess、AliyunVODFullAccess のシステムポリシーが RAM ユーザーにアタッチされていること。詳細については、「Create a RAM user and grant permissions」をご参照ください。
ステップ1. VOD システムバケットの有効化
ApsaraVideo VOD console で、[Configuration Management] > メディアアセット管理の設定 > ストレージ を選択します。VOD システムバケットで 有効化 をクリックします。
ストレージアドレスが有効になるまで待ちます。システムに「[ストレージアドレスが有効です]」というメッセージが表示され、ストレージアドレスのステータスが 正常 になった後でのみ、ストレージアドレスを使用できます。
ステップ2. 音声ファイルと動画ファイルのアップロード
-
ApsaraVideo VOD console で、 ページに移動し、オーディオ / ビデオのアップロード をクリックします。
-
オーディオ / ビデオのアップロード ページで、メディアの追加 をクリックします。
-
メディアの追加 ダイアログボックスで ローカルアップロード を選択し、準備した 3 つの動画ファイルを順番に選択してから、アップロード をクリックします。
-
アップロードが完了したら、[Audio/Video] ページに戻り、各ファイルのリソース ID を確認して記録します。各動画の [操作] 列で、詳細 > クラウドスタジオで使用可能にする をクリックします。これにより、コンテンツを ApsaraVideo Live のプロダクションスタジオで使用できるようになります。プロダクションスタジオの機能については、「Feature overview」をご参照ください。
ステップ3. ストリーミングドメインの追加
-
ApsaraVideo Live console で、アップストリームミングまたはストリーミングのドメイン名管理 ページに移動し、ドメインの追加 をクリックします。
-
ドメインの詳細を設定し、次へ をクリックします。パラメータの詳細については、「Add an accelerated domain name」をご参照ください。
このチュートリアルでは、[Business Type] を [ストリーミングドメイン]、[Acceleration Region] を [Outside Chinese Mainland] に設定し、[Accelerated Domain Name] を入力して、[Live Center] を [China (Shanghai)] に設定します。
-
次のステップのために、生成された CNAME 値を記録します。
また、DNS プロバイダーで CNAME レコードを追加し、[Host] が CNAME 値を参照するように設定する必要があります。これにより、CDN アクセラレーションが有効になります。
-
Alibaba Cloud DNS ページで、設定するドメインを見つけ、Actions 列の 解決設定 をクリックします。
-
Add Record をクリックし、CNAME 設定を完了してから、[Confirm] をクリックします。詳細については、「Configure a CNAME record for a domain name」をご参照ください。
[Record Type] を [CNAME]、[Host] を [@]、[Resolution Line] を [Default] に設定します。[Record Value] フィールドに CNAME ターゲットアドレスを入力します。[TTL] を [10 Minutes] に設定します。
ステップ4. API を使用したプロダクションスタジオの設定
-
IntelliJ IDEA を開き、Maven プロジェクトを作成します。pom.xml ファイルで <dependencies></dependencies> タグを作成し、次の依存関係を追加します。
<dependency> <groupId>com.aliyun</groupId> <artifactId>live20161101</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> -
プロジェクトの
src/main/javaディレクトリで、javaフォルダーを右クリックし、新しい Java クラスを作成します。この例では、Bodanという名前にします。 -
次のサンプルコードでパラメータを設定し、実行します。
package com.alibaba.aliyundebug.common; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.aliyun.live20161101.Client; import com.aliyun.live20161101.models.*; import com.aliyun.teaopenapi.models.Config; import org.apache.commons.codec.digest.DigestUtils; import java.util.List; import java.util.Random; import java.util.UUID; public class Bodan { private final static String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); private final static String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"); private static class LiveClient { private static volatile Client instance; private LiveClient() { } public static Client getInstance(String endpoint, String accessKeyId, String accessKeySecret) { if (instance == null) { synchronized (LiveClient.class) { if (instance == null) { try { Config config = new Config(); config.setEndpoint(endpoint); config.setAccessKeyId(accessKeyId); config.setAccessKeySecret(accessKeySecret); instance = new Client(config); } catch (Exception e) { throw new RuntimeException("Live client initialization failed: " + e.getMessage(), e); } } } } return instance; } } private static CreateCasterResponse createCaster(Client client) throws Exception { CreateCasterRequest request = new CreateCasterRequest(); Random random = new Random(); int i = random.nextInt(100000); request.setCasterName("casterName" + i); UUID uuid = UUID.randomUUID(); String token = "thisIsaToken"; String clientToken = DigestUtils.sha256Hex(token + uuid); request.setClientToken(clientToken); // エピソードリストを使用するには、プロダクションスタジオをプレイリストモードに設定する必要があります。 request.setNormType(6); request.setChargeType("PostPaid"); CreateCasterResponse response = client.createCaster(request); System.out.println("The production studio is created. Response: " + JSON.toJSONString(response)); return response; } private static void setCasterConfig(Client client, String casterId,String domainName) throws Exception { SetCasterConfigRequest request = new SetCasterConfigRequest(); request.setCasterId(casterId); // ドメイン名を設定します。 request.setDomainName(domainName); JSONObject transcodeConfig = new JSONObject(); JSONArray liveTemplate = new JSONArray(); // プロダクションスタジオのテンプレートを設定します。 liveTemplate.add("lld"); transcodeConfig.put("LiveTemplate", liveTemplate); // トランスコーディングテンプレートを設定します。 transcodeConfig.put("CasterTemplate", "lp_sd"); request.setTranscodeConfig(transcodeConfig.toJSONString()); SetCasterConfigResponse response = client.setCasterConfig(request); System.out.println("The production studio is configured. Response: " + JSON.toJSONString(response)); } private static StartCasterResponse startCaster(Client client, String casterId) throws Exception { StartCasterRequest startCasterRequest = new StartCasterRequest(); startCasterRequest.setCasterId(casterId); StartCasterResponse acsResponse = client.startCaster(startCasterRequest); System.out.println("The production studio is started."); return acsResponse; } private static StopCasterResponse stopCaster(Client client, String casterId) throws Exception { StopCasterRequest stopCasterRequest = new StopCasterRequest(); stopCasterRequest.setCasterId(casterId); StopCasterResponse acsResponse = client.stopCaster(stopCasterRequest); System.out.println("The production studio is stopped."); return acsResponse; } private static AddShowIntoShowListResponse addShowIntoShowList(Client client, String showName, String resourceId, String resourceUrl, String resourceType, Integer spot, Integer repeatTimes, String casterId, Long duration) throws Exception { AddShowIntoShowListRequest addShowIntoShowListRequest = new AddShowIntoShowListRequest(); if (casterId == null || resourceType == null) { return null; } if (resourceId == null && resourceUrl == null) { return null; } addShowIntoShowListRequest.setCasterId(casterId); addShowIntoShowListRequest.setResourceType(resourceType); if (showName != null) { addShowIntoShowListRequest.setShowName(showName); } if (resourceUrl != null) { addShowIntoShowListRequest.setResourceUrl(resourceUrl); } if (resourceId != null) { addShowIntoShowListRequest.setResourceId(resourceId); } if (spot != null) { addShowIntoShowListRequest.setSpot(spot); } if (repeatTimes != null) { addShowIntoShowListRequest.setRepeatTimes(repeatTimes); } if (duration != null) { addShowIntoShowListRequest.setDuration(duration); } return client.addShowIntoShowList(addShowIntoShowListRequest); } private static void removeShowFromShowList(Client client, String casterId, String showId) throws Exception { RemoveShowFromShowListRequest removeShowFromShowList = new RemoveShowFromShowListRequest(); removeShowFromShowList.setShowId(showId); removeShowFromShowList.setCasterId(casterId); RemoveShowFromShowListResponse removeShowFromShowListFromShowListResponse = client.removeShowFromShowList(removeShowFromShowList); System.out.println("The show is removed from the production studio. Response: " + JSON.toJSONString(removeShowFromShowListFromShowListResponse)); } private static void modifyShowList(Client client, String casterId, String showId, Integer repeatTimes, Integer spot, String highPriorityShowId, String highPriorityShowStartTime) throws Exception { ModifyShowListRequest modifyShowListRequest = new ModifyShowListRequest(); if (casterId != null) { modifyShowListRequest.setCasterId(casterId); } if (showId != null) { modifyShowListRequest.setShowId(showId); } if (repeatTimes != null) { modifyShowListRequest.setRepeatTimes(repeatTimes); } if (spot != null) { modifyShowListRequest.setSpot(spot); } if (highPriorityShowId != null) { modifyShowListRequest.setHighPriorityShowId(highPriorityShowId); } if (highPriorityShowStartTime != null) { modifyShowListRequest.setHighPriorityShowStartTime(highPriorityShowStartTime); } ModifyShowListResponse modifyShowListResponse = client.modifyShowList(modifyShowListRequest); System.out.println("The episode list is modified. Response: " + JSON.toJSONString(modifyShowListResponse)); } private static void describeShowList(Client client, String casterId) throws Exception { DescribeShowListRequest describeShowListRequest = new DescribeShowListRequest(); if (casterId != null) { describeShowListRequest.setCasterId(casterId); } DescribeShowListResponse describeShowListRequestResponse = client.describeShowList(describeShowListRequest); System.out.println("The query for the episode list is successful. Response: " + JSON.toJSONString(describeShowListRequestResponse)); DescribeShowListResponseBody showListBody = describeShowListRequestResponse.getBody(); JSONObject showList = JSON.parseObject(showListBody.getShowList()); JSONArray shows = showList.getJSONArray("Shows"); // エピソードリストを出力します。 for (int i = 0; i < shows.size(); i++) { JSONObject show = (JSONObject) shows.get(i); String showId = show.getString("ShowId"); String resourceType = show.getString("ResourceType"); String resourceInfo = show.getString("ResourceInfo"); Integer repeatTimes = show.getInteger("RepeatTimes"); Long duration = show.getLong("Duration"); String showInfo = String.format("show%d: showId: %s \n resourceType: %s \n resourceInfo: %s \n RepeatTimes: %d \n Duration: %d", i + 1, showId, resourceType, resourceInfo, repeatTimes, duration); System.out.println(showInfo); } } private static void playChoosenShow(Client client, String casterId, String showId) throws Exception { PlayChoosenShowRequest playChoosenShow = new PlayChoosenShowRequest(); playChoosenShow.setCasterId(casterId); playChoosenShow.setShowId(showId); PlayChoosenShowResponse playChoosenShowResponse = client.playChoosenShow(playChoosenShow); System.out.println("Successfully switched to showId: " + showId); } private static List<DescribeCasterStreamUrlResponseBody.DescribeCasterStreamUrlResponseBodyCasterStreamsCasterStream> describeCasterStreamUrl(Client client, String casterId) throws Exception { DescribeCasterStreamUrlRequest describeCasterStreamUrlRequest = new DescribeCasterStreamUrlRequest(); describeCasterStreamUrlRequest.setCasterId(casterId); DescribeCasterStreamUrlResponse response = client.describeCasterStreamUrl(describeCasterStreamUrlRequest); return response.getBody().getCasterStreams().getCasterStream(); } public static void main(String[] args) throws Exception { Client client = LiveClient.getInstance("live.aliyuncs.com", ACCESS_KEY_ID, ACCESS_KEY_SECRET); // プロダクションスタジオを作成します。 CreateCasterResponse caster = createCaster(client); String casterId = caster.getBody().getCasterId(); // プロダクションスタジオを設定します。 String domainName = "example.aliyundoc.com"; // ドメイン名を設定します。 setCasterConfig(client, casterId,domainName); // 3 つの VOD ファイルを追加します。1 つ目のファイルは 1 回、2 つ目は 2 回、3 つ目は 3 回再生されます。 String[] resourceIds = new String[]{"698d2b23581f476ea71107703e64****", "9c97e83e211a435b9f797e4e20ee****", "76c6addaa41c438985666a8a964f****"}; for (int i = 0; i < resourceIds.length; i++) { String showName = "ShowName#" + i; Integer repeatTimes = i; addShowIntoShowList(client, showName, resourceIds[i], null, "vod", null, repeatTimes, casterId, null); } modifyShowList(client, casterId, null, 10, null, null, null); describeShowList(client, casterId); startCaster(client, casterId); Thread.sleep(500000); stopCaster(client, casterId); } }パラメータの説明:
パラメータ
説明
private final static String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); private final static String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");AccessKey ペアは、本人確認に使用します。コードのセキュリティを確保するため、環境変数として AccessKey ペアを設定することを推奨します。AccessKey ペアは AccessKey ID と AccessKey secret で構成されます。
-
AccessKey ID:ユーザーを識別します。
-
AccessKey secret:ユーザーを認証します。AccessKey secret は厳重に管理してください。
詳細については、「Create an AccessKey pair」をご参照ください。
String domainName = "example.aliyundoc.com";ストリーミングドメイン。
String[] resourceIds = new String[]{"698d2b23581f476ea71107703e64****", "9c97e83e211a435b9f797e4e20ee****", "76c6addaa41c438985666a8a964f****"};リソース ID。取得方法については、「ステップ2. 音声ファイルと動画ファイルのアップロード」をご参照ください。
-
-
実行結果を確認します。
出力例:
"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" ... The production studio is created. Response: {"casterId":"87564f62-8c51-4xxx","requestId":"853D754D-440A-5743-xxx"} The production studio is configured. Response:{"casterId":"87564f62-8c3xxx","requestId":"4727BCE9-2058-5xxx"} The episode list is modified. Response: {"data":"{\"RequestId\":\"1B2E6CCF-7726-5xxx\",xxx}","httpResponse":{"encoding":"UTF-8","headers":{"Keep-Alive":"timeout=25","Access-Control-xxx"}}} The query for the episode list is successful. Response: {"data":"{\"RequestId\":\"CCE3BF90-E6A5-xxx\",\"ShowListInfo\":{\"TotalShowListRepeatTimes\":10,\"ShowListRepeatTimes\":10,\"ShowList\":xxx}}"} show1: showId: 69548057-i7z xxx resourceType: "vod" resourceInfo: {"resourceId":"908xxx","resourceUrl":"https://outin-f7/07xxx-xxx-22ef7"} RepeatTimes: 0 -
プロダクションスタジオ管理 ページで、作成した制作スタジオを見つけ、アクション 列の 開く をクリックします。エピソードリストに追加された 3 つの VOD ファイルが、設定どおりに順次再生されるのを確認できます。
次のステップ
ストリームを再生するには、プロダクションスタジオで ストリーミング URL をクリックして URL をコピーします。VLC などのメディアプレーヤー、ライブストリーミングデモ、またはプレーヤー SDK を使用して再生します。詳細については、「Live stream playback」をご参照ください。
[Streaming URL] ダイアログボックスには、[Original] や [lld] など、解像度ごとにグループ化された URL が表示されます。各グループには、FLV、RTMP、M3U8、RTS プロトコルの再生 URL が含まれます。使用するプロトコルの URL をコピーします。