共用方式為


快速入門:使用「播放至」功能串流投影片放映 (HTML)

[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]

您可以使用「播放至」功能,讓使用者在自己的家用網路上輕易地將音訊、視訊或影像從電腦串流至裝置。這個主題會教您如何在 Windows 市集應用程式中使用「播放至」功能,讓使用者將影像以投影片放映串流處理至目標裝置。

目標: 使用「播放至」將影像以投影片放映串流處理至目標裝置。

先決條件

Microsoft Visual Studio

指示

1. 建立新專案並啟用對 [圖片] 的存取

  1. 開啟 Visual Studio,然後選取 [檔案] 功能表的 [新增專案]。在 [Javascript] 區段中,選取 [空白的應用程式]。將應用程式命名為 PlayToSlideShow,然後按一下 [確定]。
  2. 開啟 Package.appxmanifest 檔案,然後選取 [功能]**** 索引標籤。選取 [圖片庫] 功能,讓應用程式可以存取電腦的 [圖片] 資料夾。關閉並儲存資訊清單檔案。

2. 新增 HTML UI

開啟 Default.html 檔案,然後將下列的 HTML 新增到 <body> 區段。UI 包含一個用來顯示影像的 <div>,以及另一個用來顯示狀態訊息的 <div>。UI 還包含一個告知使用者如何使用「播放至」開始串流處理的 <div>,以及一個可讓使用者在串流處理時中斷連線的按鈕。要隱藏或顯示這兩個元素,取決於是否正在串流處理投影片放映。

<div id="slideshowDiv" style="height:600px;display:table-cell;vertical-align:bottom;"></div>
<div id="messageDiv">Slideshow disconnected</div>
<button id="disconnectButton" style="width:600px;height:60px;display: none">
    Connected to <img id="iconImage" style="width: 30px;" /> <span id="deviceSpan" />
</button>
<div id="instructionsDiv">Swipe from the right edge of the screen, select "Devices", and select a device to stream the slide show to.</div>

3. 新增初始化程式碼

這個步驟中的程式碼會開始投影片放映,並針對中斷連線按鈕按一下事件建立處理常式。程式碼也包含捷徑函式 id,以方便存取 getElementById 函式。

開啟 js 資料夾。開啟 Default.js 檔案,然後將下列程式碼新增至預設的 onactivated 函式。

app.onactivated = function (args) {
    if (args.detail.kind === activation.ActivationKind.launch) {

        startSlideShow();

        args.setPromise(WinJS.UI.processAll());
    }
};

// Disconnect button event handler.
function disconnectButtonClick() {
    Windows.Media.PlayTo.PlayToManager.showPlayToUI();
}

// Shortcut function.
function id(tagName) {
    return document.getElementById(tagName);
}

4. 新增程式碼以取得影像並以投影片放映的方式顯示

這個範例會使用 [圖片] 的根資料夾中的影像,將影像顯示成投影片放映。首先從 [圖片] 取得影像清單,然後建立 <image> 物件循環播放清單,就可以完成這項工作。

使用「播放至」串流處理影像時,這個投影片放映應用程式的程式碼會利用功能,使用「播放至」緩衝下一個媒體項目。這是選用的方式,不過當我們需要額外時間才能串流下一個媒體項目的時候,卻很實用。透過媒體緩衝的方式,當目前的媒體項目完成後,可以立即串流處理,避免媒體項目之間的延遲。

如果要緩衝下一個媒體項目,我們會將下一個項目的「播放至」來源設定為目前項目的 next 屬性。當目前的項目完成時,我們呼叫目前項目的 playNext 方法,將下一個媒體來源串流處理至目標裝置。

如果投影片放映只在本機播放,程式碼會使用逾時移到清單中的下一個影像。如果投影片放映是串流處理到「播放至」接收器,程式碼還是會使用逾時移到下一個影像,但也會在「播放至」接收器暫停投影片放映時、在逾時到期之前移到下一個影像時或中斷連線時做出回應。使用影像物件的 msPlayToSource 屬性參照之「播放至」來源的 statechanged 事件,就可以完成這項工作。在 statechanged 事件中,程式碼會檢查已傳遞到事件之引數的 currentStatepreviousState 屬性。不同的狀態以及識別引發 statechanged 事件的影像索引編號,都會告訴我們如何回應,如下表所示。

currentState 要採取的行動
disconnected

如果引發事件的影像索引與目前顯示的影像索引相同,「播放至」來源就會在影像顯示時中斷連線。這表示「播放至」接收器不再處於連線狀態,而我們會使用最新的影像索引在本機開始投影片放映。否則,disconnected 的狀態只會指出投影片放映已完成顯示引發事件的影像,而我們可以清除不再需要的影像物件。

connected

如果先前的狀態是 disconnected, 則表示引發事件的影像剛剛才連接到「播放至」接收器。此時我們取得下一個影像,會在顯示目前影像時載入。

如果先前的狀態是 rendering,則表示使用者已暫停「播放至」接收器上的投影片放映,而我們可以清除目前的逾時,直到使用者重新開始放映 為止。

rendering 如果先前的狀態是 connected,則表示「播放至」接收器已經取消暫停投影片放映,而我們可以再次開始放映。

 

在 Default.js 檔案中,將下列程式碼新增到上一個步驟的程式碼後面。

var states = Windows.Media.PlayTo.PlayToConnectionState, // alias for PlayToConnectionState
    imageList,               // contains the list of images to show
    streaming = false,       // true when streaming using Play To; otherwise false
    cancel = 0,              // used to cancel a timeout
    timeLapse = 5,           // time between images (5 seconds)
    imageSize = "600px",     // size of current displayed image
    thumbnailSize = "200px", // size of "thumbnail" of next image
    currentImage = 0;        // index of the current image from imageList

// Get the list of images from the Pictures folder and start the slide show.

function startSlideShow() {
    Windows.Storage.KnownFolders.picturesLibrary.getFilesAsync().then(
        function (resultsLibrary) {
            imageList = resultsLibrary;
            if (imageList.length > 0) {
                var image = queueImage(0, true);
            } else {
                id("messageDiv").innerHTML = "There are no images in the Pictures library.";
            }
        });
}


// playNextImage
// Called when a new image is displayed due to a timeout.
// Removes the current image object and queues a new next image.
// Sets the next image index as the new current image, and increases the size 
// of the new current image. Then sets the timeout to display the next image.

function playNextImage(num) {
    id("slideshowDiv").removeChild(id("image" + num));
    queueImage(num + 2, false);

    currentImage = num + 1;
    id("image" + currentImage).style.width = imageSize;

    cancel = setTimeout(function () {
        playNextImage(num + 1);
    }, timeLapse * 1000);
}


// queueImage
// Called to create an image object for the displayed images.

function queueImage(num, isFirstImage) {

    // Create the image element for the specified image index and add to the
    // slide show div.

    var image = document.createElement("img");
    image.style.width = (isFirstImage ? imageSize : thumbnailSize);
    image.id = "image" + num;
    image.src = URL.createObjectURL(imageList[num % imageList.length], { oneTimeOnly: true });
    id("slideshowDiv").appendChild(image);

    // If this is the first image of the slide show, queue the next image. Do
    // not queue if streaming as images are already queued before
    // streaming using Play To.

    if (isFirstImage && !streaming) {

        queueImage(num + 1, false);

        cancel = setTimeout(function () {
            playNextImage(num);
        }, timeLapse * 1000);            
    }

    // Use the transferred event of the Play To connection for the current image object
    // to "move" to the next image in the slide show. The transferred event occurs
    // when the PlayToSource.playNext() method is called, or when the Play To
    // Receiver selects the next image.

    image.msPlayToSource.connection.addEventListener("transferred", function () {

        currentImage = num + 1;
        id("image" + currentImage).style.width = imageSize;

    }, false);


    // Use the statechanged event to determine which action to take or to respond
    // if the Play To Receiver is disconnected.
    image.msPlayToSource.connection.addEventListener("statechanged", function (e) {

        switch (e.currentState) {
            case states.disconnected:

                // If the state is disconnected and the current image index equals the 
                // num value passed to queueImage, then the image element is not connected 
                // to the Play To Receiver any more. Restart the slide show.
                // Otherwise, the current image has been discarded and the slide show
                // has moved to the next image. Clear the current image object and
                // remove it from the slide show div.

                if (currentImage == num) {
                    id("messageDiv").innerHTML = "Slideshow disconnected";

                    // Cancel any existing timeout
                    if (cancel) {
                        clearTimeout(cancel);
                    }

                    // Clear all image objects from the slide show div
                    while (id("slideshowDiv").firstChild) {
                        id("slideshowDiv").removeChild(id("slideshowDiv").firstChild);
                    }

                    // Reset the slide show objects and values to their beginning state
                    streaming = false;
                    id("disconnectButton").style.display = "none";
                    id("instructionsDiv").style.display = "block";
                    disconnectButton.removeEventListener("click", disconnectButtonClick, false);

                    // Restart the slide show from the current image index
                    queueImage(currentImage, true);
                } else {
                    image.msPlayToSource.next = null;
                    image.removeAttribute("src");

                    if (streaming) {
                        id("slideshowDiv").removeChild(image);
                    }
                }

                break;
                
            case states.connected:

                // If the state is connected and the previous state is disconnected, 
                // then the image element is newly connected. Queue up the next image so 
                // that it is loaded while the current image is being displayed.
                // If the previous state is rendering, then the user has paused the slideshow 
                // on the Play To Receiver. Clear the current timeout until the user restarts
                // the slide show.

                if (e.previousState === states.disconnected) {
                    var imageNext = queueImage(num + 1, false);
                    image.msPlayToSource.next = imageNext.msPlayToSource;
                } else if (e.previousState === states.rendering) {
                    if (cancel) {
                        clearTimeout(cancel);
                        cancel = 0;
                    }
                }

                if (currentImage == num) {
                    id("messageDiv").innerHTML = "Slideshow connected";
                }

                break;

            case states.rendering:

                // If the state is rendering and the previous state is
                // connected, then the Play To Receiver has restarted
                // the slide show.

                if (e.previousState === states.connected) {

                    // Clear any existing timeout.
                    if (cancel) {
                        clearTimeout(cancel);
                    }

                    // Restart the slide show.
                    cancel = setTimeout(function () {
                        image.msPlayToSource.playNext();
                    }, timeLapse * 1000);
                }

                if (currentImage == num) {
                    id("messageDiv").innerHTML = "Slideshow rendering";
                }

                break;
        }

    }, false);

    return image;
}

5. 新增「播放至」程式碼

這個步驟中的程式碼會實作播放至協定。它會為目前應用程式取得 PlayToManager 的參考,然後和 sourcerequestedsourceselected 事件的事件處理常式建立關聯。

因為影像物件是針對投影片放映中的每個影像所建立和摧毀,所以我們在 sourcerequested 事件中使用永遠不會摧毀的暫時影像物件。這是因為我們不知道逾時是否會在使用者選取「播放至」接收器之前到期。如果發生這種情況,會摧毀目前的影像,並將 Null 參照傳送到「播放至」。所以,我們會將永遠不會摧毀的影像物件參照傳送到「播放至」,並在使用者選取「播放至」接收器時,將影像來源更新為目前顯示的影像。當影像狀態變更為 connected,我們就知道發生了這個狀況。

在 Default.js 檔案中,將下列程式碼新增到上一個步驟的程式碼後面。

// Set up the Play To contract.

// Used to pass an image to Play To that will not be removed/destroyed
// by the slide show logic. For example, if the user opens the Devices
// charm and the sourcerequested event fires, but the image display timeout
// completes before the user selects a target device, then the image that
// was being displayed is removed and destroyed. intialImage is never 
// destroyed so Play To will always have a valid source to stream.
var initialImage = null;

var ptm = Windows.Media.PlayTo.PlayToManager.getForCurrentView();

ptm.addEventListener("sourcerequested", function (e) {
    initialImage = document.createElement("img");

    // Use the statechanged event of the image passed to Play To to determine when
    // the image is finally connected to the Play To Receiver.
    initialImage.msPlayToSource.connection.addEventListener("statechanged", function (e) {

        if (e.currentState === states.connected) {

            // Clear any existing timeout.
            if (cancel) {
                clearTimeout(cancel);
                cancel = 0;
            }

            // Clear the slide show div.
            while (id("slideshowDiv").firstChild) {
                id("slideshowDiv").removeChild(id("slideshowDiv").firstChild);
            }

            // Set the slide show objects and values to show that we are streaming.
            streaming = true;
            id("disconnectButton").style.display = "block";
            id("instructionsDiv").style.display = "none";

            // Queue and display the next image.
            var image = queueImage(currentImage, true);
            initialImage.msPlayToSource.next = image.msPlayToSource;
            initialImage.msPlayToSource.playNext();
        }
    }, false);

    // Provide Play To with the first image to stream.
    e.sourceRequest.setSource(initialImage.msPlayToSource);

}, false);

// Update the once the user has selected a device to stream to.
ptm.addEventListener("sourceselected", function (e) {
    disconnectButton.addEventListener("click", disconnectButtonClick, false);
    id("messageDiv").innerHTML = "Streaming to " + e.friendlyName + "...";
    id("deviceSpan").innerHTML = e.friendlyName + ".<br/>Click here to disconnect.";
    id("iconImage").src = URL.createObjectURL(e.icon, { oneTimeOnly: true });
}, false);

6. 建立「播放至」目標 (選用)

如果要執行應用程式,您需要一個目標裝置,讓「播放至」可以串流媒體。如果您沒有已認證的「播放至」接收器,可以使用 Windows Media Player 做為目標裝置。為了使用 Windows Media Player 當作目標裝置,您的電腦必須連線至私人網路。執行 Windows Media Player 的電腦不能是「播放至」來源應用程式所在的電腦。

  1. 啟動 Windows Media Player。
  2. 展開 [串流] 功能表,然後啟用 [允許遠端控制我的播放程式...]**** 選項。讓 Windows Media Player 保持開啟;它必須為執行中,才能當作「播放至」目標。
  3. 開啟 [裝置和印表機] 控制台。按一下 [新增裝置和印表機]。在 [新增裝置和印表機] 精靈中的 [選擇要新增至此電腦的裝置或印表機] 視窗中,找到電腦的 [數位媒體轉譯器]。這是您電腦的 Windows Media Player。選取它,然後按 [下一步]****。精靈完成之後,您會在 [多媒體裝置] 的清單中看到 Windows Media Player 的執行個體。

7. 執行應用程式

  • 在 Visual Studio 中,按 F5 (偵錯) 以執行應用程式。您可以選取任何媒體按鈕,即可播放或查看不同媒體櫃中的第一個媒體項目。播放媒體的時候,開啟裝置常用鍵並選取「播放至」目標,即可將媒體串流至目標裝置。

摘要

在這個快速入門中,您已將「播放至」功能新增到應用程式,該應用程式會將影像當作投影片放映在目標裝置上顯示。「播放至」功能可以讓使用者將來自應用程式的內容串流到網路上已認證的「播放至」接收器。

相關主題

使用「播放至」將媒體串流至裝置

範例

播放至範例

PlayToReceiver 範例

媒體伺服器範例