Oracle Cloud Infrastructure(OCI) Media Streams은 개발자가 비디오 콘텐츠를 패키지화하여 OCI 또는 콘텐츠 전송 네트워크(CDN)를 통해 스트리밍할 수 있도록 지원하는 서비스입니다. 미디어 콘텐츠를 암호화하여 스마트 TV, 모바일 장치, 컴퓨터, 게임 콘솔 등의 다양한 디바이스까지 안전하게 전송합니다. 개발자는 이제 미디어 인프라를 직접 관리할 필요 없이, OCI의 확장성을 활용하여 완벽한 비디오 경험을 제공할 수 있게 되었습니다.
OCI Media Streams과 같은 just-in-time(JIT) 비디오 패키징 서비스를 사용하면 동일한 콘텐츠를 여러 번 트랜스코딩할 필요가 없어집니다. OCI Media Streams 서비스는 단일 소스 파일을 사용자가 필요로 하는 형식으로 자동으로 변환합니다. 다양한 기기별 요청에 따라 콘텐츠 암호화 및 스트리밍 포맷이 동적으로 자동 적용되므로 그만큼 사용자의 시간과 노력을 절약할 수 있습니다.
비디오 애플리케이션 관련 데이터 수요의 변화폭은 매우 큽니다. OCI Media Streams를 활용하면 트래픽에 따라 인프라가 자동으로 확장 및 축소됩니다. OCI에서의 직접 스트리밍, CDN 또는 맞춤형 경험을 통한 스트리밍을 모두 지원합니다.
강력한 콘텐츠 암호화 방식으로 귀사의 콘텐츠 전송을 보호하고, 안전한 전송을 보장합니다. OCI Media Streams은 다른 모든 OCI 서비스와 같이 높은 수준의 보안 규정 및 암호화 표준이 자동으로 적용되므로 GDPR 표준을 간단히 준수할 수 있습니다.
미디어를 스트리밍하고 OCI Media Streams 작업을 실행하는 방법을 살펴보세요. OCI의 최신 Java SDK가 필요하며, 마스터 재생 목록 이름과 상주 버킷 이름을 반드시 입력해야 합니다. 하단의 예제는 데모 용도로만 사용해야 하고, 실제 운용에 사용해서는 안 됩니다.
/***********
This is a demo program to create media streams.
This requires the latest java SDK of OCI.
Takes input of the master playlist name and residing bucket name.
This is intended for a demonstration only and not for Production usage.
************/
/***********
1. Accept User Input of Object Storage Bucket name & HLS Master playlist (m3u8).
(Note: This takes only master.m3u8 and not sub-playlists as input)
2. Create Media Client.
3. Create Distribution Channel.
4. Configure CDN for Distribution Channel.
5. Create Stream Packaging Configuration.
6. Create Asset ID for the provided input master playlist.
7. Ingest the Asset ID into the Distribution Channel.
8. Create MediaStreams Client with distribution channel as endpoint.
9. After Ingest complete, generate Session Token.
10. Display's URL that is HLS streamable.
************/
import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider;
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import com.oracle.bmc.mediaservices.MediaServicesClient;
import com.oracle.bmc.mediaservices.*;
import com.oracle.bmc.mediaservices.requests.*;
import com.oracle.bmc.mediaservices.responses.*;
import com.oracle.bmc.mediaservices.model.*;
import com.oracle.bmc.mediaservices.requests.CreateStreamCdnConfigRequest;
import com.oracle.bmc.mediaservices.requests.CreateStreamDistributionChannelRequest;
import com.oracle.bmc.mediaservices.requests.CreateMediaAssetRequest;
import com.oracle.bmc.mediaservices.requests.CreateStreamPackagingConfigRequest;
import com.oracle.bmc.mediaservices.requests.IngestStreamDistributionChannelRequest;
import com.oracle.bmc.mediaservices.responses.CreateMediaAssetResponse;
import com.oracle.bmc.mediaservices.responses.CreateStreamCdnConfigResponse;
import com.oracle.bmc.mediaservices.responses.CreateStreamDistributionChannelResponse;
import com.oracle.bmc.mediaservices.responses.CreateStreamPackagingConfigResponse;
import com.oracle.bmc.mediaservices.responses.IngestStreamDistributionChannelResponse;
import com.oracle.bmc.mediaservices.model.IngestStreamDistributionChannelResult;
import com.oracle.bmc.mediaservices.model.MediaAsset;
import com.oracle.bmc.mediaservices.model.StreamCdnConfig;
import com.oracle.bmc.mediaservices.model.StreamDistributionChannel;
import com.oracle.bmc.mediaservices.model.StreamPackagingConfig;
import com.oracle.bmc.mediaservices.MediaStreamClient;
import com.oracle.bmc.mediaservices.model.CreateStreamDistributionChannelDetails;
import com.oracle.bmc.mediaservices.model.CreateStreamCdnConfigDetails;
import com.oracle.bmc.mediaservices.model.IngestStreamDistributionChannelDetails;
import com.oracle.bmc.mediaservices.requests.CreateStreamDistributionChannelRequest;
import com.oracle.bmc.mediaservices.model.EdgeStreamCdnConfig;
import com.oracle.bmc.mediaservices.model.StreamCdnConfigSection;
import com.oracle.bmc.mediaservices.model.CreateStreamPackagingConfigDetails.StreamPackagingFormat;
import com.oracle.bmc.mediaservices.model.StreamPackagingConfigEncryptionNone;
import com.oracle.bmc.mediaservices.model.AssetType;
import com.oracle.bmc.mediaservices.requests.GenerateSessionTokenRequest;
import com.oracle.bmc.mediaservices.model.GenerateSessionTokenDetails;
import com.oracle.bmc.mediaservices.requests.GetMediaWorkflowJobRequest;
import com.oracle.bmc.mediaservices.responses.GetMediaWorkflowJobResponse;
import com.oracle.bmc.mediaservices.model.MediaWorkflowJob.LifecycleState;
import org.json.simple.*;
import org.json.simple.parser.*;
import java.util.Collections;
import java.util.*;
import java.util.Scanner;
public class MediastreamsDemoApp {
// User Input
public static String[] getUserInput(){
String[] inputs = new String[2];
MediastreamsDemoApp.printString("\n", "Enter name of bucket where master playlist is located:");
Scanner input = new Scanner(System.in);
String inputBucketName = input.nextLine();
MediastreamsDemoApp.printString("\n","Enter name of master playlist to be ingested:");
String inputPlaylistName = input.nextLine();
input.close();
inputs[0] = inputBucketName;
inputs[1] = inputPlaylistName;
return inputs;
}
// Print Function
public static void printString(Object stringtoPrint , Object stringtoPrint2){
System.out.println(stringtoPrint);
System.out.println(stringtoPrint2);
}
// Media Client Creation by default with Instance Principal.
// Toggle the other java lines in this code for User Principal.
public static MediaServicesClient connectMediaService(){
InstancePrincipalsAuthenticationDetailsProvider provider = InstancePrincipalsAuthenticationDetailsProvider.builder().build();
MediaServicesClient mediaClient = new MediaServicesClient(provider);
// User Principal
// Read config from the profile DEFAULT in the file "~/.oci/config". You can switch to different profile.
// AuthenticationDetailsProvider authenticationDetailsProvider = new ConfigFileAuthenticationDetailsProvider(PROFILE_DEFAULT);
// MediaServicesClient mediaClient = MediaServicesClient.builder().build(authenticationDetailsProvider);
return mediaClient;
}
// Closing Media Client
public static void closeMediaService(MediaServicesClient mc,MediaStreamClient ms){
mc.close();
ms.close();
MediastreamsDemoApp.printString("\n", "Media Clients are Closed");
}
// Create Media Streams Client
// Default this program creates using Instance Principal
public static MediaStreamClient connectMediaStreams(StreamDistributionChannel dc){
String endpoint = dc.getDomainName();
InstancePrincipalsAuthenticationDetailsProvider provider = InstancePrincipalsAuthenticationDetailsProvider.builder().build();
MediaStreamClient mediaStreamsClient = new MediaStreamClient(provider);
// User Principal
// Read config from the profile DEFAULT in the file "~/.oci/config". You can switch to different profile.
// AuthenticationDetailsProvider authenticationDetailsProvider = new ConfigFileAuthenticationDetailsProvider(PROFILE_DEFAULT);
// MediaStreamClient mediaStreamsClient = MediaStreamClient.builder().build(authenticationDetailsProvider);
mediaStreamsClient.setEndpoint("https://"+endpoint);
MediastreamsDemoApp.printString("\n" ,"Media Streams Client Instatiated Successfully");
return mediaStreamsClient;
}
// Create Distribution Channel
public static StreamDistributionChannel createDistributionChannel(MediaServicesClient mc, String compartment_id){
CreateStreamDistributionChannelRequest request = CreateStreamDistributionChannelRequest.builder().createStreamDistributionChannelDetails(CreateStreamDistributionChannelDetails.builder().displayName("test-java-sdk").compartmentId(compartment_id).build()).build();
CreateStreamDistributionChannelResponse response = mc.createStreamDistributionChannel(request);
StreamDistributionChannel dc = response.getStreamDistributionChannel();
return dc;
}
//Create CDN - In this case, its OCI Edge.
public static void createCDN(MediaServicesClient mc, String compartment_id, StreamDistributionChannel dc){
String channelId = dc.getId();
CreateStreamCdnConfigRequest request = CreateStreamCdnConfigRequest.builder().createStreamCdnConfigDetails(
CreateStreamCdnConfigDetails.builder().displayName("test-java-sdk").isEnabled(true).distributionChannelId(channelId).config(EdgeStreamCdnConfig.builder().build()).build()).build();
CreateStreamCdnConfigResponse response = mc.createStreamCdnConfig(request);
StreamCdnConfig cdnConfig = response.getStreamCdnConfig();
}
// Create Streaming Package Configuration
// By default Unencrypted in this code.
public static StreamPackagingConfig createStreamPackage(MediaServicesClient mc, StreamDistributionChannel dc){
String channelId = dc.getId();
// Unencrypted Stream
CreateStreamPackagingConfigRequest request = CreateStreamPackagingConfigRequest.builder().createStreamPackagingConfigDetails(CreateStreamPackagingConfigDetails.builder().displayName("test-java-sdk").distributionChannelId(channelId).streamPackagingFormat(CreateStreamPackagingConfigDetails.StreamPackagingFormat.valueOf("Hls")).segmentTimeInSeconds(6).encryption(StreamPackagingConfigEncryptionNone.builder().build()).build()).build();
// AES 128 encrypted stream
//CreateStreamPackagingConfigRequest request = CreateStreamPackagingConfigRequest.builder().createStreamPackagingConfigDetails(CreateStreamPackagingConfigDetails.builder().displayName("test-java-sdk").distributionChannelId(channelId).streamPackagingFormat(CreateStreamPackagingConfigDetails.StreamPackagingFormat.valueOf("Hls")).segmentTimeInSeconds(6).encryption(StreamPackagingConfigEncryptionAes128.builder().build()).build()).build();
CreateStreamPackagingConfigResponse response = mc.createStreamPackagingConfig(request);
StreamPackagingConfig packageConfig = response.getStreamPackagingConfig();
return packageConfig;
}
// Create Media Asset ID for given master playlist
public static MediaAsset createAsset(MediaServicesClient mc, String inputBucket,String masterPlayList, String namespace, String compartmentId){
CreateMediaAssetRequest request = CreateMediaAssetRequest.builder().createMediaAssetDetails(CreateMediaAssetDetails.builder().bucketName(inputBucket).displayName("test-java-sdk").objectName(masterPlayList).namespaceName(namespace).type(AssetType.valueOf("Playlist")).compartmentId(compartmentId).build()).build();
CreateMediaAssetResponse response = mc.createMediaAsset(request);
MediaAsset mediaAsset = response.getMediaAsset();
return mediaAsset;
}
// Ingest the Master Playlist to Distribution Channel
public static IngestStreamDistributionChannelResult ingestAsset(MediaServicesClient mc, MediaAsset ma, StreamDistributionChannel dc, String compartmentId){
String assetId = ma.getId();
String channelId = dc.getId();
IngestStreamDistributionChannelRequest request = IngestStreamDistributionChannelRequest.builder().ingestStreamDistributionChannelDetails(AssetMetadataEntryDetails.builder().mediaAssetId(assetId).compartmentId(compartmentId).build()).streamDistributionChannelId(channelId).build();
IngestStreamDistributionChannelResponse response = mc.ingestStreamDistributionChannel(request);
IngestStreamDistributionChannelResult ingestResult = response.getIngestStreamDistributionChannelResult();
return ingestResult;
}
// Get the Media WorkflowJob ID for the Ingest Job
public static MediaWorkflowJob checkIngestJobStatus(MediaServicesClient mc, IngestStreamDistributionChannelResult ingestStatus) {
String mediaWorkflowId = ingestStatus.getMediaWorkflowJobId();
GetMediaWorkflowJobRequest request = GetMediaWorkflowJobRequest.builder().mediaWorkflowJobId(mediaWorkflowId).build();
GetMediaWorkflowJobResponse response = mc.getMediaWorkflowJob(request);
MediaWorkflowJob mediaWorkflowJob = response.getMediaWorkflowJob();
return mediaWorkflowJob;
}
// Check the status of the Ingest Job using above Media Workflow Job ID
public static String jobLifecycleState(MediaServicesClient mediaClient,IngestStreamDistributionChannelResult ingestStatus){
MediaWorkflowJob mediaWorkflowJob = MediastreamsDemoApp.checkIngestJobStatus(mediaClient,ingestStatus);
MediaWorkflowJob.LifecycleState lifestate = mediaWorkflowJob.getLifecycleState();
String ingestCurrentStatus = lifestate.getValue();
return ingestCurrentStatus;
}
// Create Session Token
// Defaults to 24 hour validity
public static SessionToken generateSessionToken(MediaStreamClient ms, StreamPackagingConfig sp, MediaAsset ma){
String streamPackagingId = sp.getId();
String mediaAssetId = ma.getId();
List<GenerateSessionTokenDetails.Scopes> scopes = new ArrayList<GenerateSessionTokenDetails.Scopes>();
scopes.add(GenerateSessionTokenDetails.Scopes.valueOf("Edge"));
scopes.add(GenerateSessionTokenDetails.Scopes.valueOf("Playlist"));
List<String> assetIds = new ArrayList<String>();
assetIds.add(mediaAssetId);
GenerateSessionTokenRequest request = GenerateSessionTokenRequest.builder().generateSessionTokenDetails(GenerateSessionTokenDetails.builder().packagingConfigId(streamPackagingId).scopes(scopes).assetIds(assetIds).build()).build();
GenerateSessionTokenResponse response = ms.generateSessionToken(request);
SessionToken sessionToken = response.getSessionToken();
return sessionToken;
}
public static void spinningWheel() throws InterruptedException{
String a = "|/-\\";
while (true) {
for (int i = 0; i < 4; i++) {
System.out.print("\033[0;0H"); // place cursor at top left corner
for (int j = 0; j < 80; j++) { // 80 character terminal width, say
System.out.print(a.charAt(i));
}
Thread.sleep(250);
}
}
}
public static void main(String[] args) throws InterruptedException{
// **Variable Declarations** //
String compartment_id = "ocid1.compartment.oc1..aaaaaaaabhuut4zoztxlfneotrwuauqt5wjhmj4kxaka6ajme4ipxqlcwv6a";
String namespace = "axjagzvlc4vi";
String [] inputs = MediastreamsDemoApp.getUserInput();
String inputBucket = inputs[0];
String masterPlayList = inputs[1];
// Connect to media services
MediaServicesClient mediaClient = MediastreamsDemoApp.connectMediaService();
MediastreamsDemoApp.printString("\n", "Media Client Instatiated Successfully");
// Create Distribution Channel
StreamDistributionChannel distributionChannel = MediastreamsDemoApp.createDistributionChannel(mediaClient, compartment_id);
MediastreamsDemoApp.printString("\n Distribution Channel Created Successfully",distributionChannel.getId());
// Configure CDN for the distribution channel
MediastreamsDemoApp.createCDN(mediaClient, compartment_id, distributionChannel);
// Create stream packaging Configuration
StreamPackagingConfig streamPackageConfig = MediastreamsDemoApp.createStreamPackage(mediaClient, distributionChannel);
MediastreamsDemoApp.printString("\n Streaming Packaging Configuration Created Successfully", streamPackageConfig.getId());
// Create Media Asset for provided master playlist
MediaAsset mediaAsset = MediastreamsDemoApp.createAsset(mediaClient, inputBucket, masterPlayList, namespace, compartment_id);
MediastreamsDemoApp.printString("\n Media Asset Registered Successfully" , mediaAsset.getId());
// Initiate Ingest of the master playlist into the Distribution channel
IngestStreamDistributionChannelResult ingestStatus = MediastreamsDemoApp.ingestAsset(mediaClient, mediaAsset, distributionChannel, compartment_id);
MediastreamsDemoApp.printString("\n Ingest of Asset Initiated with Job", ingestStatus.getMediaWorkflowJobId());
// Run Loop for ingest job to complete.
boolean status = false;
System.out.print("Ingesting");
while (!status){
String ingestValue = MediastreamsDemoApp.jobLifecycleState(mediaClient,ingestStatus);
System.out.print(".");
Thread.sleep(3000);
//System.out.println(ingestCurrentStatus);
if ((ingestValue == "SUCCEEDED") || (ingestValue == "FAILED")){
break;
}
}
String ingestOutcome = MediastreamsDemoApp.jobLifecycleState(mediaClient,ingestStatus);
MediastreamsDemoApp.printString("\nIngest Completed with status", ingestOutcome);
if (ingestOutcome == "SUCCEEDED") {
// Create media Streams Client with distribution cahnnel
MediaStreamClient mediaStreamsClient = MediastreamsDemoApp.connectMediaStreams(distributionChannel);
// Generate session token for the master playlist.
SessionToken sessionToken = MediastreamsDemoApp.generateSessionToken(mediaStreamsClient, streamPackageConfig, mediaAsset);
//MediastreamsDemoApp.printString(sessionToken.getToken());
MediastreamsDemoApp.printString("\n\nStream Media with your player:\n\n","https://"+distributionChannel.getDomainName()+"/20211101/actions/generatePlaylist?mediaAssetId="+mediaAsset.getId()+"&streamPackagingConfigId="+streamPackageConfig.getId()+"&token="+sessionToken.getToken());
// Close the Media Clients
MediastreamsDemoApp.closeMediaService(mediaClient,mediaStreamsClient);
}
else {
mediaClient.close();
}
}
}
OCI Media Streams을 사용하면 애셋 ID를 통해 저장된 비디오에 간단히 액세스할 수 있습니다. OCI Media Streams은 콘텐츠를 패키지화하고 한 번만 트랜스코딩하면 다양한 디바이스에 다양한 포맷으로 스트리밍할 수 있게 자동으로 변환해 줍니다. 콘텐츠 암호화 및 스트리밍 형식이 동적으로 적용되어 개발자의 시간과 노력을 크게 절약해 줍니다.
OCI Media Flow가 인기 소셜 미디어 사이트에 적합한 비디오 포맷을 제공하면, OCI Media Streams이 비디오 콘텐츠를 패키징하고 암호화하여 휴대폰, 게임 콘솔 등 다양한 디바이스에서 스트리밍할 수 있도록 지원합니다.
OCI Media Flow로 학습 플랫폼 경험을 위한 비디오를 제작, 처리, 저장합니다. 이후 안전한 전달 및 스트리밍을 위해 OCI Media Streams를 사용하여 저장된 콘텐츠를 패키지화하고 암호화합니다. 강력한 콘텐츠 암호화를 통해 사용자가 지정한 곳에서만 동영상을 스트리밍할 수 있습니다.
Oracle, Principal Product Manager, Remi Fourreau
기쁜 마음으로 Oracle Cloud Infrastructure(OCI)용 Digital Media Services(DMS)의 정식 출시를 발표합니다. 비디오 콘텐츠를 보유한 OCI 고객은 DMS Media Flow의 저렴한 미디어 프로세싱 기능을 활용하고, DMS Media Streams 서비스를 통해 비디오를 전송할 수 있습니다. 해당 서비스들이 제공하는, 보다 나은 고객 경험을 창출하고 비즈니스 운영을 개선하기 위한 신규 미디어 기능들을 통해 애플리케이션 및 비즈니스 프로세스를 더욱 강화할 수 있습니다.
게시글 전문 읽어보기Oracle은 Media Streams, Media Flow, AI Services 등의 엄선된 서비스를 시간 제한 없이 무료로 이용할 수 있는 Free Tier와 함께 추가 클라우드 서비스 체험을 지원하기 위한 미화 300 달러 상당의 무료 크레디트를 제공합니다. 자세한 내용을 확인하고 지금 바로 무료 계정에 가입해보세요.