Media Streams

Oracle Cloud Infrastructure(OCI) Media Streams은 개발자가 비디오 콘텐츠를 패키지화하여 OCI 또는 콘텐츠 전송 네트워크(CDN)를 통해 스트리밍할 수 있도록 지원하는 서비스입니다. 미디어 콘텐츠를 암호화하여 스마트 TV, 모바일 장치, 컴퓨터, 게임 콘솔 등의 다양한 디바이스까지 안전하게 전송합니다. 개발자는 이제 미디어 인프라를 직접 관리할 필요 없이, OCI의 확장성을 활용하여 완벽한 비디오 경험을 제공할 수 있게 되었습니다.

Oracle Cloud Infrastructure(OCI) Media Streams: 개요(1:31)

OCI Media Streams의 작동 방식

OCI Media Streams의 작동 방식 다이어그램
비디오 파일이 생성되어 Oracle Cloud Infrastructure(OCI) Object Storage에 업로드됩니다. Oracle Cloud Infrastructure(OCI) Media Flow를 통해 비디오 파일로부터 썸네일이 사용자가 설정한 시간 간격으로 생성되고, 생성된 썸네일 또한 OCI Object Storage에 저장할 수 있습니다. 또한 OCI Media Flow는 스트리밍을 위해 단일 비디오 파일의 다양한 변형을 생성하고, HLS 스트리밍을 위한 비디오 매니페스트 파일이 고객의 파일 저장소에 추가됩니다. OCI Media Flow는 검색 가능한 콘텐츠 인덱스가 포함된 AI 메타데이터가 담긴 JSON 파일을 생성합니다. OCI Media Flow는 스트리밍의 전제 조건인 여러 개의 파편화된 MP4 파일들 및 마스터 재생 목록을 생성합니다. OCI Media Streams은 유효한 HLS 마스터 재생 목록을 수집하고 비디오 스트리밍용 비디오 패키지를 생성합니다.

개발자가 비디오 파일을 준비 및 트랜스코딩하는 방법

미디어를 스트리밍하고 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 사용 사례

비디오 콘텐츠 액세스 및 패키지화

OCI Media Streams을 사용하면 애셋 ID를 통해 저장된 비디오에 간단히 액세스할 수 있습니다. OCI Media Streams은 콘텐츠를 패키지화하고 한 번만 트랜스코딩하면 다양한 디바이스에 다양한 포맷으로 스트리밍할 수 있게 자동으로 변환해 줍니다. 콘텐츠 암호화 및 스트리밍 형식이 동적으로 적용되어 개발자의 시간과 노력을 크게 절약해 줍니다.

비디오 클리핑

OCI Media Flow가 인기 소셜 미디어 사이트에 적합한 비디오 포맷을 제공하면, OCI Media Streams이 비디오 콘텐츠를 패키징하고 암호화하여 휴대폰, 게임 콘솔 등 다양한 디바이스에서 스트리밍할 수 있도록 지원합니다.

학습 플랫폼 생성

OCI Media Flow로 학습 플랫폼 경험을 위한 비디오를 제작, 처리, 저장합니다. 이후 안전한 전달 및 스트리밍을 위해 OCI Media Streams를 사용하여 저장된 콘텐츠를 패키지화하고 암호화합니다. 강력한 콘텐츠 암호화를 통해 사용자가 지정한 곳에서만 동영상을 스트리밍할 수 있습니다.

2022년 7월 20일

Oracle, OCI 상에서의 비디오 운영을 가속화하는 OCI Digital Media Services 출시

Oracle, Principal Product Manager, Remi Fourreau

기쁜 마음으로 Oracle Cloud Infrastructure(OCI)용 Digital Media Services(DMS)의 정식 출시를 발표합니다. 비디오 콘텐츠를 보유한 OCI 고객은 DMS Media Flow의 저렴한 미디어 프로세싱 기능을 활용하고, DMS Media Streams 서비스를 통해 비디오를 전송할 수 있습니다. 해당 서비스들이 제공하는, 보다 나은 고객 경험을 창출하고 비즈니스 운영을 개선하기 위한 신규 미디어 기능들을 통해 애플리케이션 및 비즈니스 프로세스를 더욱 강화할 수 있습니다.

게시글 전문 읽어보기

추천 블로그

모두 보기

OCI Media Streams 시작하기

상시 무료 클라우드 서비스를 사용해보고 30일 평가판을 받으세요

Oracle은 Media Streams, Media Flow, AI Services 등의 엄선된 서비스를 시간 제한 없이 무료로 이용할 수 있는 Free Tier와 함께 추가 클라우드 서비스 체험을 지원하기 위한 미화 300 달러 상당의 무료 크레디트를 제공합니다. 자세한 내용을 확인하고 지금 바로 무료 계정에 가입해보세요.

  • Oracle Cloud 무료 체험에는 무엇이 포함되어 있나요?

    • 상시 무료
    • Autonomous Database 2개(각 20GB)
    • 컴퓨팅 VM
    • 100GB 블록 볼륨
    • 10GB의 객체 스토리지

영업 팀에 문의하기

Media Streams에 대한 추가 정보가 필요하신가요? Oracle의 전문가가 도와 드리겠습니다.

  • 다음과 같은 질문에 답해드릴 수 있습니다.

    • OCI Media Streams과 원활히 통합 가능한 서비스로는 어떤 것들이 있나요?
    • 우리 회사의 도입 비용은 어느 정도일까요?
    • 비디오 콘텐츠 전송을 보호하기 위한 방법은 무엇인가요?