在 C 中分析影片內容是否有令人反感的內容#

本文提供資訊和程式碼範例,協助您開始使用 Content Moderator SDK for .NET 掃描成人或猥褻內容的視訊內容。

如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶

必要條件

  • Visual Studio 2015 或 2017 的任何版本

設定 Azure 資源

Content Moderator 的視訊仲裁功能可在 Azure 媒體服務 (AMS) 中作為免費的公開預覽 媒體處理器 使用。 Azure 媒體服務是專門用來儲存和串流視訊內容的 Azure 服務。

建立Azure 媒體服務帳戶

請遵循建立Azure 媒體服務帳戶 中的 指示來訂閱 AMS 並建立相關聯的 Azure 儲存體帳戶。 在該儲存體帳戶中,建立新的 Blob 儲存體容器。

建立 Microsoft Entra 應用程式

在Azure 入口網站中流覽至新的 AMS 訂用帳戶,然後從側邊功能表中選取 [API 存取 ]。 選取 [連線] 以使用服務主體 Azure 媒體服務。 請注意 REST API 端點 欄位中的值 ;您稍後將需要此值。

在 [ Microsoft Entra 應用程式 ] 區段中,選取 [ 新建 ] 並將新的 Microsoft Entra 應用程式註冊命名(例如,「VideoModADApp」 )。 選取 [儲存],在設定應用程式的同時,請稍候幾分鐘。 然後,您應該會在頁面的 [Microsoft Entra 應用程式] 區段下看到新的應用程式 註冊。

選取您的應用程式註冊,然後按一下其下方的 [ 管理應用程式 ] 按鈕。 請注意 [應用程式識別碼 ] 欄位中的值 ;您稍後將需要此值。 選取 [設定 > Keys ],然後輸入新金鑰的描述(例如 「VideoModKey」 )。 選取 [儲存],然後留意到新的金鑰值。 複製此字串,並將它儲存在安全的地方。

如需上述程式更徹底的逐步解說,請參閱 開始使用 Microsoft Entra 驗證

完成此動作之後,您可以使用兩種不同的方式使用影片仲裁媒體處理器。

使用Azure 媒體服務總管

Azure 媒體服務總管是 AMS 的使用者易記前端。 使用它來流覽 AMS 帳戶、上傳影片,以及使用 Content Moderator 媒體處理器掃描內容。 從 GitHub 下載並安裝它,或參閱 Azure 媒體服務 Explorer 部落格文章 以取得詳細資訊。

Azure Media Services explorer with Content Moderator

建立 Visual Studio 專案

  1. 在 Visual Studio 中,建立新的 主控台應用程式 (.NET Framework) 專案,並將其命名為 VideoModeration
  2. 如果您的方案中有其他專案,請選取此專案作為單一啟動專案。
  3. 取得必要的 NuGet 套件。 以滑鼠右鍵按一下方案總管中的專案,然後選取 [管理 NuGet 套件 ],然後尋找並安裝下列套件:
    • windowsazure.mediaservices
    • windowsazure.mediaservices.extensions

新增影片仲裁程式碼

接下來,您會將本指南中的程式碼複製並貼到專案中,以實作基本 con帳篷模式ration 案例。

更新程式的 using 語句

將下列 using 語句新增至 Program.cs 檔案頂 端。

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MediaServices.Client;
using System.IO;
using System.Threading;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using System.Collections.Generic;

設定資源參考

將下列靜態欄位新增至 Program.cs 中的 Program 類別。 這些欄位會保存連線到 AMS 訂用帳戶所需的資訊。 請填入您在上述步驟中取得的值。 請注意, CLIENT_ID Microsoft Entra 應用程式的應用程式識別碼 值,而 CLIENT_SECRET 是您為該應用程式建立的 「VideoModKey」 值。

// declare constants and globals
private static CloudMediaContext _context = null;
private static CloudStorageAccount _StorageAccount = null;

// Azure Media Services (AMS) associated Storage Account, Key, and the Container that has
// a list of Blobs to be processed.
static string STORAGE_NAME = "YOUR AMS ASSOCIATED BLOB STORAGE NAME";
static string STORAGE_KEY = "YOUR AMS ASSOCIATED BLOB STORAGE KEY";
static string STORAGE_CONTAINER_NAME = "YOUR BLOB CONTAINER FOR VIDEO FILES";

private static StorageCredentials _StorageCredentials = null;

// Azure Media Services authentication.
private const string AZURE_AD_TENANT_NAME = "microsoft.onmicrosoft.com";
private const string CLIENT_ID = "YOUR CLIENT ID";
private const string CLIENT_SECRET = "YOUR CLIENT SECRET";

// REST API endpoint, for example "https://accountname.restv2.westcentralus.media.azure.net/API".
private const string REST_API_ENDPOINT = "YOUR API ENDPOINT";

// Content Moderator Media Processor Nam
private const string MEDIA_PROCESSOR = "Azure Media Content Moderator";

// Input and Output files in the current directory of the executable
private const string INPUT_FILE = "VIDEO FILE NAME";
private const string OUTPUT_FOLDER = "";

// JSON settings file
private static readonly string CONTENT_MODERATOR_PRESET_FILE = "preset.json";

重要

當您完成時,請記得從程式碼中移除金鑰,且絕不會公開發布金鑰。 針對生產環境,請使用安全的方式來儲存和存取您的認證,例如 Azure 金鑰保存庫 。 如需詳細資訊,請參閱 Azure AI 服務安全性一文。

如果您想要使用本機視訊檔案(最簡單的案例),請將它新增至專案,並輸入其路徑作為 INPUT_FILE 值(相對路徑相對於執行目錄)。

您也必須在目前目錄中建立 preset.json 檔案,並使用它來指定版本號碼。 例如:

{
    "version": "2.0"
}

載入輸入視訊(s)

Program 類別的 Main 方法會建立 Azure 媒體內容,然後建立Azure 儲存體內容(如果您的影片位於 Blob 儲存體中)。 其餘程式碼會從 Azure 儲存體容器內的本機資料夾、Blob 或多個 Blob 掃描影片。 您可以藉由批註化其他幾行程式碼來嘗試所有選項。

// Create Azure Media Context
CreateMediaContext();

// Create Storage Context
CreateStorageContext();

// Use a file as the input.
IAsset asset = CreateAssetfromFile();

// -- OR ---

// Or a blob as the input
// IAsset asset = CreateAssetfromBlob((CloudBlockBlob)GetBlobsList().First());

// Then submit the asset to Content Moderator
RunContentModeratorJob(asset);

//-- OR ----

// Just run the content moderator on all blobs in a list (from a Blob Container)
// RunContentModeratorJobOnBlobs();

建立 Azure 媒體內容

將下列方法新增至 Program 類別。 這會使用 AMS 認證來允許與 AMS 通訊。

// Creates a media context from azure credentials
static void CreateMediaContext()
{
    // Get Azure AD credentials
    var tokenCredentials = new AzureAdTokenCredentials(AZURE_AD_TENANT_NAME,
        new AzureAdClientSymmetricKey(CLIENT_ID, CLIENT_SECRET),
        AzureEnvironments.AzureCloudEnvironment);

    // Initialize an Azure AD token
    var tokenProvider = new AzureAdTokenProvider(tokenCredentials);

    // Create a media context
    _context = new CloudMediaContext(new Uri(REST_API_ENDPOINT), tokenProvider);
}

新增程式碼以建立Azure 儲存體內容

將下列方法新增至 Program 類別。 您可以使用從儲存體認證建立儲存體內容來存取 Blob 儲存體。

// Creates a storage context from the AMS associated storage name and key
static void CreateStorageContext()
{
    // Get a reference to the storage account associated with a Media Services account.
    if (_StorageCredentials == null)
    {
        _StorageCredentials = new StorageCredentials(STORAGE_NAME, STORAGE_KEY);
    }
    _StorageAccount = new CloudStorageAccount(_StorageCredentials, false);
}

新增程式碼以從本機檔案和 Blob 建立 Azure 媒體資產

Content Moderator 媒體處理器會在 Azure 媒體服務 平臺內的 Assets 執行作業。 這些方法會從本機檔案或相關聯的 Blob 建立 Assets。

// Creates an Azure Media Services Asset from the video file
static IAsset CreateAssetfromFile()
{
    return _context.Assets.CreateFromFile(INPUT_FILE, AssetCreationOptions.None); ;
}

// Creates an Azure Media Services asset from your blog storage
static IAsset CreateAssetfromBlob(CloudBlockBlob Blob)
{
    // Create asset from the FIRST blob in the list and return it
    return _context.Assets.CreateFromBlob(Blob, _StorageCredentials, AssetCreationOptions.None);
}

新增程式碼以掃描容器內的影片集合(以 Blob 的形式)

// Runs the Content Moderator Job on all Blobs in a given container name
static void RunContentModeratorJobOnBlobs()
{
    // Get the reference to the list of Blobs. See the following method.
    var blobList = GetBlobsList();

    // Iterate over the Blob list items or work on specific ones as needed
    foreach (var sourceBlob in blobList)
    {
        // Create an Asset
        IAsset asset = _context.Assets.CreateFromBlob((CloudBlockBlob)sourceBlob,
                            _StorageCredentials, AssetCreationOptions.None);
        asset.Update();

        // Submit to Content Moderator
        RunContentModeratorJob(asset);
    }
}

// Get all blobs in your container
static IEnumerable<IListBlobItem> GetBlobsList()
{
    // Get a reference to the Container within the Storage Account
    // that has the files (blobs) for moderation
    CloudBlobClient CloudBlobClient = _StorageAccount.CreateCloudBlobClient();
    CloudBlobContainer MediaBlobContainer = CloudBlobClient.GetContainerReference(STORAGE_CONTAINER_NAME);

    // Get the reference to the list of Blobs
    var blobList = MediaBlobContainer.ListBlobs();
    return blobList;
}

新增 方法以執行 Content Moderator 作業

// Run the Content Moderator job on the designated Asset from local file or blob storage
static void RunContentModeratorJob(IAsset asset)
{
    // Grab the presets
    string configuration = File.ReadAllText(CONTENT_MODERATOR_PRESET_FILE);

    // grab instance of Azure Media Content Moderator MP
    IMediaProcessor mp = _context.MediaProcessors.GetLatestMediaProcessorByName(MEDIA_PROCESSOR);

    // create Job with Content Moderator task
    IJob job = _context.Jobs.Create(String.Format("Content Moderator {0}",
            asset.AssetFiles.First() + "_" + Guid.NewGuid()));

    ITask contentModeratorTask = job.Tasks.AddNew("Adult and racy classifier task",
            mp, configuration,
            TaskOptions.None);
    contentModeratorTask.InputAssets.Add(asset);
    contentModeratorTask.OutputAssets.AddNew("Adult and racy classifier output",
        AssetCreationOptions.None);

    job.Submit();


    // Create progress printing and querying tasks
    Task progressPrintTask = new Task(() =>
    {
        IJob jobQuery = null;
        do
        {
            var progressContext = _context;
            jobQuery = progressContext.Jobs
            .Where(j => j.Id == job.Id)
                .First();
                Console.WriteLine(string.Format("{0}\t{1}",
                DateTime.Now,
                jobQuery.State));
                Thread.Sleep(10000);
            }
            while (jobQuery.State != JobState.Finished &&
            jobQuery.State != JobState.Error &&
            jobQuery.State != JobState.Canceled);
    });
    progressPrintTask.Start();

    Task progressJobTask = job.GetExecutionProgressTask(
    CancellationToken.None);
    progressJobTask.Wait();

    // If job state is Error, the event handling
    // method for job progress should log errors.  Here we check
    // for error state and exit if needed.
    if (job.State == JobState.Error)
    {
        ErrorDetail error = job.Tasks.First().ErrorDetails.First();
        Console.WriteLine(string.Format("Error: {0}. {1}",
        error.Code,
        error.Message));
    }

    DownloadAsset(job.OutputMediaAssets.First(), OUTPUT_FOLDER);
}

新增協助程式函式

這些方法會從Azure 媒體服務資產下載 Content Moderator 輸出檔案 (JSON),並協助追蹤仲裁作業的狀態,讓程式可以將執行狀態記錄到主控台。

static void DownloadAsset(IAsset asset, string outputDirectory)
{
    foreach (IAssetFile file in asset.AssetFiles)
    {
        file.Download(Path.Combine(outputDirectory, file.Name));
    }
}

// event handler for Job State
static void StateChanged(object sender, JobStateChangedEventArgs e)
{
    Console.WriteLine("Job state changed event:");
    Console.WriteLine("  Previous state: " + e.PreviousState);
    Console.WriteLine("  Current state: " + e.CurrentState);
    switch (e.CurrentState)
    {
        case JobState.Finished:
            Console.WriteLine();
            Console.WriteLine("Job finished.");
            break;
        case JobState.Canceling:
        case JobState.Queued:
        case JobState.Scheduled:
        case JobState.Processing:
            Console.WriteLine("Please wait...\n");
            break;
        case JobState.Canceled:
            Console.WriteLine("Job is canceled.\n");
            break;
        case JobState.Error:
            Console.WriteLine("Job failed.\n");
            break;
        default:
            break;
    }
}

執行程式並檢閱輸出

完成內容仲裁作業之後,請分析 JSON 回應。 它包含下列元素:

  • 影片資訊摘要
  • 拍攝為「 片段
  • 主要畫面格 為「 事件 」,並具有 reviewRecommended「 (= true 或 false)」 旗標,以成人 猥褻 分數為基礎
  • start duration totalDuration timestamp 是「刻度」。 除 以時幅 以秒為單位取得數位。

注意

  • adultScore 代表在某些情況下可能被視為性明確或成人內容的潛在存在和預測分數。
  • racyScore 代表在某些情況下可能被視為性暗示或成熟內容的潛在存在和預測分數。
  • adultScoreracyScore 介於 0 到 1 之間。 分數越高,模型預測類別可能適用愈高。 此預覽依賴統計模型,而不是手動編碼的結果。 建議您使用您自己的內容進行測試,以判斷每個類別如何符合您的需求。
  • reviewRecommended 根據內部分數閾值,為 true 或 false。 客戶應評估是否要使用此值,或根據其內容原則決定自訂閾值。
{
"version": 2,
"timescale": 90000,
"offset": 0,
"framerate": 50,
"width": 1280,
"height": 720,
"totalDuration": 18696321,
"fragments": [
{
    "start": 0,
    "duration": 18000
},
{
    "start": 18000,
    "duration": 3600,
    "interval": 3600,
    "events": [
    [
        {
        "reviewRecommended": false,
        "adultScore": 0.00001,
        "racyScore": 0.03077,
        "index": 5,
        "timestamp": 18000,
        "shotIndex": 0
        }
    ]
    ]
},
{
    "start": 18386372,
    "duration": 119149,
    "interval": 119149,
    "events": [
    [
        {
        "reviewRecommended": true,
        "adultScore": 0.00000,
        "racyScore": 0.91902,
        "index": 5085,
        "timestamp": 18386372,
        "shotIndex": 62
        }
    ]
    ]
}
]
}

下一步

下載適用于此和適用于 .NET 的其他 Content Moderator 快速入門的 Visual Studio 解決方案