AI時代的網站與手機App建置與開發Part33 - 使用Azure Video Indexer探索影片內容

 l  摘要

Microsoft Azure雲端提供了眾多的AI服務, 涵蓋了視覺辨識, 語言分析, 語音辨識與合成,  決策與內容安全, 以及支援生成式AI服務的Azure OpenAI服務.

應用程式能夠使用Azure提供的AI服務進行語音辨識, 辨識說話者, 執行語音轉文字和文字轉語音, 分析文本, 擷取文字關鍵字與關鍵詞, , 使用內容安全功能審查文字, 圖片, 甚至影片的內容是否有暴力, 色情, 自殘, 與仇恨相關的內容, 並加以屏蔽或修訂. 除此之外, 也可以利用Azure OpenAI服務實作聯天生成, 圖片生成, 影片生成, 語音生成, 以及AI代理功能, 為企業的資訊系統植入現代化的AI功能.

在這篇文章中, 我將要為大家介紹如何使用Azure Video Indexer服務分析影片的內容.

: 支援分析影片內容的Azure Video Indexer服務

l  認識Azure Video Indexer服務

Azure AI Video Indexer屬於Azure AI服務的一部分, Azure AI服務(例如臉部、翻譯工具、電腦視覺和語音)為基礎建構. 支援利用Azure AI Video Indexer擷取影片的內容與見解, 包括影片中人物的情緒, 人臉, 文字的關鍵字, 地點, 知名人物, 以及標籤(內含標籤出現的起始時間和結束時間)等等.

企業可以將Azure AI Video Indexer應用在以下的場合:

1.       搜尋影片的內容

2.       建立影片摘要內容: 例如建立預告片, 精華片段

3.       自動翻譯影片文字與建立字幕

4.       依據影片內容投放廣告, 創造營收

5.       審查影片內容

6.       分析影片內容, 分類影片, 實踐影片推薦

7.       數位資產分類與管理

l  Azure Video Indexer支援的影片格式

欲使用Azure Video Indexer分析影片內容, 首先要了解Azure Video Indexer支援的影片格式. 1即為Azure Video Indexer支援的影片格式列表:

影片格式(副檔名)

支援狀態

FLV (with H.264 and AAC codecs) (.flv)

MXF (.mxf)

GXF (.gxf)

MPEG2-PS, MPEG2-TS, 3GP (.ts, .ps, .3gp, .3gpp, .mpg)

Windows Media Video (WMV)/ASF (.wmv, .asf)

AVI (Uncompressed 8bit/10bit) (.avi)

MP4 (.mp4, .m4a, .m4v)/ISMV (.isma, .ismv)

Microsoft Digital Video Recording(DVR-MS) (.dvr-ms)

Matroska/WebM (.mkv)

WAVE/WAV (.wav)

QuickTime (.mov)

 1: Azure Video Indexer支援的影片格式列表

l  認識Azure Video Indexer Developer Portal:

Azure Video Indexer目前有提供每月2400分鐘的免費試用帳號, 您可以登入Azure Video Indexer開發者網站(網址https://www.videoindexer.ai/), 螢幕上就會出現如圖1的畫面:

1: Azure Video Indexer Developer Portal網站畫面

您可以點選圖1右上角的[Upload]鍵手動上傳欲分析的影片到Azure Video Indexer Developer Portal進行分析, 也可以寫程式執行上傳影片的工作, 並讀取分析的結果.

l  使用Azure Video Indexer實作影片分析

接下來我們就要實作使用Azure Video Indexer服務將欲分析的影片上傳並進行分析.

欲使用程式上傳影片至Azure Video Indexer服務, 首先您可以於Microsoft Azure建立[儲存體帳戶]服務, [儲存體帳戶]服務建立存放影片檔案的容器, 再使用[儲存體帳戶]服務提供的上傳功能將影片預先上傳至[儲存體帳戶]服務.

上傳妥欲分析的影片之後, 必須設定[儲存體帳戶]服務的CORS資源共用設定, 允許Azure Video Indexer服務讀取準備在[儲存體帳戶]服務的影片檔案, 請點選[設定 | 資源共用(CORS)]功能, [允許的來源]欄位填入:*, [允許的標頭]欄位填入:*, [公開的標頭]欄位填入:*, [存留期上限]填入: 3600, 如圖2所示:

2: 設定[儲存體帳戶]服務的CORS資源共用設定的畫面

做好之後請點選上傳至[儲存體帳戶]服務容器中的影片, 點選[產生SAS]頁籤, 填入允許存取的到期日, 點選[產生SAS權杖與URL], 再複製[Blob SAS URL]供程式使用, 如圖3所示:

3: 建立欲分析的影片的Blob SAS URL的畫面

l  上傳影片與分析影片範例

設定妥[儲存體帳戶]CORS資源共用設定, 並取得欲分析的影片的SAS URL之後, 我們就可以利用以下的網頁上傳欲分析的影片至Azure Video Indexer, 等分析完成, 再讀取影片分析的結果:

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-

scale=1.0">

    <title>Document</title>

</head>

<body>

    <h1>Azure Video Indexer Example</h1>

    <table>

        <tr>

            <td><button id="go">Upload & Index Video</button></td>

            <td><button id="check">Check Video Status</button></td>

        </tr>

    </table>

    <div id="output"></div>

    <script>

        // Configuration

        const API_URL = 'https://api.videoindexer.ai';

        const ACCOUNT_ID = '您的ACCOUNT_ID';  

        const LOCATION = 'trial';              // 試用版地區

        const API_KEY = '您的金鑰';                

        //處理go按鍵的Click事件

        document.getElementById("go").addEventListener(

"click", async ()=>{

            await uploadAndIndexVideo();

        });

        //處理check按鍵的Click事件

        document.getElementById("check").addEventListener(

"click", async ()=>{

            const accessToken=await getAccessToken();

            await debugVideoStatus(accessToken);

        });

        //取得存取權杖

        async function getAccessToken(allowEdit = true) {

            const params = new URLSearchParams({        //準備參數

                allowEdit: allowEdit ? 'true' : 'false'

            });

            const response = await fetch(                // 求取權杖

                `${API_URL}/auth/${LOCATION}/Accounts/${ACCOUNT_ID}/

AccessToken?${params}`, {

                    method: 'GET',

                    headers: {

                        'Ocp-Apim-Subscription-Key': API_KEY

                    }

                }

            );

            if (!response.ok) {                   // 求取權杖失敗

                throw new Error(

                `Failed to get access token: ${response.statusText}`);

            }

            const data = await response.json();   // 取得權杖

            return data;                          // 傳回權杖

        }

        // 測試欲分析的影片是否能夠正常讀取

        async function testBlobUrl(fullBlobUrl) {

            try {

// 測試影片是否能夠正常讀取但不下載

const testResponse = await fetch(fullBlobUrl,

{ method: 'HEAD' });  

                console.log('Blob Status:', testResponse.status);

                console.log('Content-Type:',

testResponse.headers.get('content-type'));

                if (testResponse.ok) {    // 影片能夠正常讀取

                    console.log('Blob reachable! Size:',

testResponse.headers.get('content-length'));

                    return true;

                } else {                   // 影片無法正常讀取

                    const errorText = await testResponse.text();

                    console.error('Blob unreachable:',

testResponse.status, errorText);

                    return false;

                }

            } catch (err) {

                console.error('Fetch error (network/firewall?):',

err.message);

                return false;

            }

        }

        //上傳影片至Azure Video Indexer, 並分析影片內容

        async function uploadToVideoIndexer(

videoUrl, videoName, accessToken) {

          if (!(await testBlobUrl(videoUrl))) { //檢驗影片是否能夠被讀取

                console.error('Blob not ready—fix first');

                return;

            }

            const encoded=encodeURIComponent(videoUrl); //編碼影片的網址

            const videoIndexerUrl = `https://api.videoindexer.ai/

trial/Accounts/${ACCOUNT_ID}/Videos` +

`?accessToken=${accessToken}&name=${videoName}&

 privacy=Private&videoUrl=${encoded}`;

            try {

                const response = await fetch(videoIndexerUrl,{

method: 'POST', mode: 'cors' }); //執行上傳與分析

                if (!response.ok) {

                    const errorData = await response.json().catch(()

=> response.text());

console.error('Upload Error:', response.status,

errorData);

                    if (errorData.includes('URL_UNREACHABLE')) {

                        console.log('Double-check SAS expiry.');

                    }

                    return;

                }

                const result = await response.json(); // 取得上傳結果  

                console.log('Upload Success! Video Details:', result);

                console.log('Video ID for status polling:',result.id);

                return result.id;                  // 取得影片id

            } catch (err) {

                console.error('Network/Fetch Error:', err);

            }

        }

        // 準備欲分析的影片, 並叫用uploadToVideoIndexer上傳影片至Azure

// Video Indexer進行分析

        async function uploadAndIndexVideo() {

            const output = document.getElementById('output');

            output.innerHTML = '<p>Starting process...</p>';

            try {

                // Step 1: 取得存取權杖

                const accessToken = await getAccessToken(true);  

                console.log('Access Token:', accessToken);

                output.innerHTML += '<p>Access token obtained.</p>';

                 // Step 2: 上傳影片至Azure Video Indexer

                const videoUrl="儲放於Azure儲存體帳戶的影片SAS URL";  

                videoId=await uploadToVideoIndexer(videoUrl,

"Bird", accessToken);

                output.innerHTML += `<p>Video uploaded. ID:

${videoId}. Indexing started (may take minutes).</p>`;

            } catch (error) {

                console.error('Error:', error);

                output.innerHTML += `<p>Error: ${error.message}</p>`;

            }

        }

        // 查詢所有上傳至Azure Video Indexer的影片

        async function listVideos(accessToken) {

            const listUrl = `https://api.videoindexer.ai/trial/

Accounts/${ACCOUNT_ID}/Videos?accessToken=${accessToken}`;

            const response = await fetch(listUrl, {

method: 'GET', mode: 'cors' });

            if (!response.ok) {      // 如果查詢發生錯誤

                const errorText = await response.text();

                console.error('List error:',response.status, errorText);

                return [];

            }    

            const data = await response.json();         // 取得查詢結果

            const videos=data["results"];    // 讀取results屬性的內容值

            console.log('Your videos:');

            videos.forEach(v => { // 列示影片的編號,名稱,狀態,和影片長度

                console.log(`- ID: ${v.id}, Name: "${v.name}", State:

${v.state}, Duration: ${v.durationInSeconds}s`);

            });

            return videos;               // 傳回所有的影片資料

        }

        // 判斷影片是否分析完成, 並顯示分析完成的影片的分析結果(見解)

        async function debugVideoStatus(accessToken) {

            try {

           // 取得己上傳至Azure Video Indexer的所有影片

                const videos = await listVideos(accessToken);      

                if (videos.length === 0) {       // 如果查無影片

                    console.log('No videos found');

                    return;

                }

                else {  // 查詢影片的編號與狀態

                    videos.forEach(async (video, index)=>{          

                        console.log(`Found video: ID "${video.id}",

State: ${video.state}`);

                        //如果狀態為Processed(己分析完成),則顯示分析結果

                        if (video.state=="Processed") {            

                            const insightsUrl = `${API_URL}/

${LOCATION}/Accounts/${ACCOUNT_ID}/

Videos/${video.id}/Index?accessToken=${accessToken}`;

                            const insightsRes = await fetch(

insightsUrl, { method: 'GET' });

                            const insights = await insightsRes.json();

                            var labels=insights[

'summarizedInsights']['labels'];

                            labels.forEach((value, index)=>{

                                console.log(value.name);

                            });

                        }

                    });

                }

            } catch (err) {

                console.error('error:', err.message);

            }

        }

    </script>

</body>

</html>

執行上述的程式您將會看到如圖4的畫面:

4: 使用Azure Video Indexer分析影片內容的網頁執行的情形

請點選網頁中的[Upload & Index Video]鍵將指定的影片上傳至Azure Video Indexer進行分析. 等待一段時間後再按點選網頁中的[Check Video Status], 檢查上傳至Azure Video Indexer的影片是否己經分析完成, 並顯示己分析完成的影片的分析結果, 如圖5所示:

5: 顯示己分析完成的影片的分析結果的畫面

程式碼範例下載網址: https://github.com/CraigIII/UseAzureVideoIndexer.git

留言

這個網誌中的熱門文章

AI時代的網站與手機App建置與開發Part27 - ML.NET與物件偵測

AI時代的網站與手機App建置與開發Part28 - 使用YOLO模型進行物件偵測

AI時代的網站與手機App建置與開發Part24 - ML.NET與圖片異常偵測