AI時代的網站與手機App建置與開發Part33 - 使用Azure Video Indexer探索影片內容
l 摘要
Microsoft Azure雲端提供了眾多的AI服務, 涵蓋了視覺辨識, 語言分析, 語音辨識與合成, 決策與內容安全, 以及支援生成式AI服務的Azure OpenAI服務.
應用程式能夠使用Azure提供的AI服務進行語音辨識, 辨識說話者, 執行語音轉文字和文字轉語音, 分析文本, 擷取文字關鍵字與關鍵詞, , 使用內容安全功能審查文字, 圖片, 甚至影片的內容是否有暴力, 色情, 自殘, 與仇恨相關的內容, 並加以屏蔽或修訂. 除此之外, 也可以利用Azure OpenAI服務實作聯天生成, 圖片生成, 影片生成, 語音生成, 以及AI代理功能, 為企業的資訊系統植入現代化的AI功能.
在這篇文章中, 我將要為大家介紹如何使用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) |
是 |
l 認識Azure Video Indexer Developer Portal:
Azure Video
Indexer目前有提供每月2400分鐘的免費試用帳號, 您可以登入Azure Video Indexer開發者網站(網址https://www.videoindexer.ai/),
螢幕上就會出現如圖1的畫面:
![]() |
您可以點選圖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所示:
做好之後請點選上傳至[儲存體帳戶]服務容器中的影片, 點選[產生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的畫面:
請點選網頁中的[Upload & Index Video]鍵將指定的影片上傳至Azure Video Indexer進行分析. 等待一段時間後再按點選網頁中的[Check Video Status]鍵, 檢查上傳至Azure Video Indexer的影片是否己經分析完成, 並顯示己分析完成的影片的分析結果, 如圖5所示:
圖5: 顯示己分析完成的影片的分析結果的畫面






留言
張貼留言