Video Creative Ingest API

影片廣告素材匯入 API 可讓第三方廣告系統主動將廣告素材匯入 YouTube 和 DAI 產品。這個程序可確保在從非 Google 廣告伺服器決定廣告時,傳回的廣告素材已準備就緒,可放送至 YouTube 或 DAI 影片串流。

主動從第三方廣告系統擷取廣告素材的程序包含兩個主要部分。第一部分可讓第三方廣告系統向 Google 提供廣告素材,並監控廣告素材在擷取至 Google 影片基礎架構時的進度。廣告素材成功攝入後,系統會將 ID 傳回廣告系統。

第二個步驟是廣告系統使用通用廣告 ID (VAST 4.0 以上版本) 或「UniversalAdId」類型的廣告素材擴充功能,取得這些 ID,並將其納入參照提交廣告素材的 VAST 文件中。當 DAI 或 YouTube 在決策時刻遇到廣告系統的 VAST 文件時,廣告素材系統會從 VAST 中擷取這些 ID,並從 Google 影片基礎架構中擷取適當的廣告素材,以便插入播放。

媒體相關規定

提交至 API 的廣告素材應符合下列條件,確保系統能順利處理。

媒體類型

Google 接受下列媒體類型。任何其他媒體類型都可能在提交時遭到拒絕。

  • video/mp4
  • video/webm
  • video/quicktime
  • video/avi
  • video/mpeg
  • video/x-flv
  • flv-application/octet-stream
  • application/octet-stream
  • video/3gpp
  • video/ogg
  • audio/mp4
  • audio/mpeg

媒體資源

提交的媒體必須符合下列條件:

  • 媒體必須至少包含一個音訊或影片音軌。
  • 媒體內容的長度必須合理。影片長度不得超過數分鐘。
  • 媒體必須包含長度超過 1 秒的音訊或影片。
  • 如果媒體含有音訊,則必須具備標準音訊聲道設定,例如單聲道、立體聲或環場音效。

提交廣告素材供攝入

攝入程序的流程圖

  1. 第三方廣告系統會將 HTTP 要求傳送至 Video Creative Ingest API,並附上與廣告素材相關聯的媒體檔案清單。
  2. 影片廣告素材攝入 API 會從提供的清單中選取品質最高的廣告素材,並從 CDN 下載。
  3. 影片廣告素材攝入 API 會將下載的廣告素材攝入 Google 影片基礎架構,讓 YouTube 和 DAI 產品都能使用。
  4. 系統會將 Pub/Sub 通知傳回至第三方廣告系統,並附上廣告素材的狀態。通知會指出廣告是否已成功載入至 YouTube 和 DAI。如果載入廣告素材失敗,通知會指出失敗原因。

提交廣告素材時,請遵循下列指南。

驗證

您必須使用 Google Cloud 服務帳戶存取 API。在整合時,您必須提供帳戶資訊給 Google,才能取得適當的授權。

透過 creativeingestion@google.com 向 Google 提供帳戶資訊後,系統就會授予 API 端點和用於發布通知的 Cloud Pub/Sub 主題的存取權。

如要啟動驗證程序,請按照下列步驟操作:

  1. 建立 Google Cloud 帳戶。
  2. 使用帳戶設定專案,以便向 DAI API 傳送要求。
  3. 在專案中,前往左側的「IAM 與管理」分頁,然後建立新的服務帳戶;系統會使用服務帳戶傳送要求。
  4. 啟用 Pub/Sub API,並建立單一專屬的合作夥伴通知主題,讓 API 發布所有擷取成功和失敗通知。

    如果您已建立網域限制機構政策,請將 Google 客戶 ID 新增至許可客戶清單。請與 creativeingestion@google.com 聯絡,取得 ID。完成後,您就可以將主體 (我們的機器人帳戶) 從獲准客戶名單 (API 的客戶 ID) 新增至 IAM 政策 (PubSub 發布者)。

    video-creative-library-discovery@system.gserviceaccount.com 新增為主題的 Pub/Sub 發布者。

  5. 請提供服務帳戶電子郵件地址和 Pub/Sub 主題,讓 creativeingestion@google.com 將這些資訊註冊到 API。

  6. 將帳戶新增為服務消費者後,請啟用 DAI API

  7. 如要設定存取 API 的憑證,請按照下列步驟操作:

    • 從服務帳戶下載憑證:按一下「IAM 與管理」分頁的「服務帳戶」部分中的服務帳戶,然後按一下「建立金鑰」,並儲存憑證。

    • 驗證 API 呼叫端。將 GOOGLE_APPLICATION_CREDENTIALS 設為 JSON 檔案的路徑。請參閱程式碼範例,瞭解如何使用常見語言驗證 gRPC 用戶端。

廣告素材攝入

每當合作夥伴的廣告系統提供新廣告素材時,合作夥伴的系統應將廣告素材提交至 Creative Ingest API。

將新廣告素材提交給 Google 以載入至影片基礎架構時,請提供廣告系統產生的 VAST 文件中所包含的廣告素材資料。這可確保主動將廣告素材取入 Google 的行為,與首次在廣告回應中載入廣告素材的行為相同。

每個提交的廣告素材都會在伺服器上建立長時間執行的攝入作業,且可查詢其狀態。作業成功完成後,系統會產生廣告素材資源。提交廣告素材的回應中會包含要求所產生的作業 ID。系統會在作業完成時傳送 Cloud Pub/Sub 通知,其中包含產生的作業 ID,以便將作業對應回提交的原始廣告素材。您也可以隨時使用作業 ID 檢查作業進度。

廣告素材要求

資料會以 Protocol Buffers 或 JSON 物件的形式傳送至 API。建議使用 gRPC 傳送通訊協定緩衝區,因為這類緩衝區是使用 PubSub 通知的必要條件,而且由於回應中含有 google.protobuf.Any 欄位,因此解析 JSON 會變得更加複雜。

創意回覆

成功後,伺服器會傳回 Protocol Buffer 回應或 JSON 回應,具體取決於要求類型。回應會包含新建的攝入作業名稱和作業詳細資料。

在初次提交時,與作業相關聯的部分中繼資料可能會為空白,且結果可能不會顯示。作業完成後,結果會填入廣告素材資源 (或錯誤),中繼資料則包含擷取狀態的相關資訊。

請注意,中繼資料必須從 Any 前置詞 unmarshal 至 CreateCreativeOperationMetadata 前置詞,且回應 (如有) 必須 unmarshal 至 Creative 前置詞。

用於存取 API 的用戶端程式庫

如要整合 API,請按照下列步驟操作:

  1. 請下載通訊協定緩衝區依附元件,然後將整個 google 資料夾移至 src 目錄。如果使用 Google Cloud App Engine,可以略過這個步驟。
  2. 使用 protoc 外掛程式從 proto 檔案產生 gRPC 程式碼,並將產生的程式碼放入相關目錄。
  3. 針對 Pub/Sub 通知中傳回的 proto 建立新的 proto 檔案;重複執行上一個步驟,從 proto 產生程式碼。
  4. 使用 gRPC 向 API 提出要求:

    1. 取得具有下列範圍的預設憑證:

    https://www.googleapis.com/auth/video-ads

    https://www.googleapis.com/auth/pubsub

    1. 將要求傳送至 Creative Ingest。
    • 使用預設憑證連線至 dai.googleapis.com:443
    • 使用 gRPC proto 產生的程式碼,為廣告素材攝入服務建立用戶端 Stub。
    • 使用用戶端存根呼叫 CreateCreative

    您可以選擇使用長時間執行作業的 gRPC 程式碼 (在步驟 2 下載的 googleapis 目錄中提供),為 Operations 服務建立 Stub,用於取得特定作業 (GetOperation) 的狀態。

  5. 查看 Pub/Sub 通知:

    1. 使用 PubSub 用戶端程式庫或 gRPC 連線至 PubSub 服務,並輪詢發布至指定主題的 PubSub 通知。

    2. 將 PubSub 訊息解除封送至步驟 4 中的 protobuf。

    3. 每當長時間執行的作業從對 CreateCreativeGetOperation 的呼叫,或在 Pub/Sub 通知中傳回時,請從 google.protobuf.Any 原型中 unmarshal 中繼資料至 discovery.proto 中的 CreateCreativeOperationMetadata,並將任何回應 unmarshal 至 discovery.proto 中的 Creative

Go 用戶端程式碼範例

// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
  dai "google.golang.org/genproto/googleapis/ads/dai/v1"
  psnotif "protos/dai"
  "google.golang.org/genproto/googleapis/longrunning"
  "cloud.google.com/go/pubsub"
  "golang.org/x/net/context"
  "google.golang.org/grpc"
  "google.golang.org/grpc/credentials"
  "google.golang.org/grpc/credentials/oauth"
  "github.com/golang/protobuf/proto"
  anypb "github.com/golang/protobuf/ptypes/any"
)

var scopes = []string{"https://www.googleapis.com/auth/video-ads", "https://www.googleapis.com/auth/pubsub"}

const (
  subID = "sub-id" // The ID for the subscription to the topic you provided us (projects/<project ID>/subscriptions/<subscription ID>)
  project = "your-project-id" // Your Google Cloud Project ID
)

func main() {
  ctx := context.Background()
  crpc, err := oauth.NewApplicationDefault(ctx, scopes...)
  if err != nil {
    // TODO: Handle error
  }

  conn, err := grpc.Dial("dai.googleapis.com:443",
    grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")),
    grpc.WithPerRPCCredentials(crpc))
  if err != nil {
    // TODO: Handle error 
  }

  apiclient := dai.NewPartnerDiscoveryServiceClient(conn)
  opclient := longrunning.NewOperationsClient(conn)

  op, err := apiclient.CreateCreative(ctx, &dai.CreateCreativeRequest{
    // TODO: Add Creative with metadata and media files.
  })
  if err != nil {
    // TODO: Handle error
  }

  pubsubClient, err := pubsub.NewClient(ctx, project)
  if err != nil {
    // TODO: Handle error
  }
  sub := pubsubClient.Subscription(subID)

  // TODO: Pull from Pub/Sub subscription to receive messages, and acknowledge them
  var msg *pubsub.Message // Assume msg = a received Pub/Sub message

  // Unmarshal the Pub/Sub message into the proto created in step 9a of guide
  var n psnotif.CreateCreativeStatus
  if err := proto.Unmarshal(msg.Data, &n); err != nil {
    // TODO: Handle error
  }
  op = n.GetDetails()
  md, err = anyToMetadata(op.GetMetadata())
  if err != nil {
    // TODO: Handle error
  }
  // TODO: Check if ingest was successful and get Google Video ID from md.GetGvRegistryId()
  // TODO: Enable serving of creative using Google Video ID in VAST document

  // Optionally check the status of an ingest request using the status endpoint
  op, err = opclient.GetOperation(ctx, &longrunning.GetOperationRequest{Name:   op.Name})
  if err != nil {
    // TODO: Handle error
  }
}

// anyToMetadata converts the metadata Any field in an Operation message to
// CreateCreativeOperationMetadata.
func anyToMetadata(msg *anypb.Any) (*dai.CreateCreativeOperationMetadata, error) {
  var md dai.CreateCreativeOperationMetadata
  return &md, proto.Unmarshal(msg.Value, &md)
}

// anyToCreative converts the response Any field in an Operation message to
// Creative.
func anyToCreative(msg *anypb.Any) (*dai.Creative, error) {
  var cr dai.Creative
  return &cr, proto.Unmarshal(msg.Value, &cr)
}

播放期間的廣告素材查詢

廣告素材查詢程序的流程圖

  1. 使用者要求觀看 YouTube 或 DAI 中的內容。
  2. YouTube / DAI 會從第三方廣告系統取得 VAST 回應,以便將廣告插入內容中。
  3. 系統會將傳回的廣告對應至先前擷取的廣告素材。這些廣告素材已準備好播放,會從 Google 影片基礎架構擷取,並為使用者播放。

合作夥伴修改的 VAST 文件

廣告素材成功載入 Google 影片基礎架構後,廣告系統會傳回 VAST 回應,而該文件應包含已處理廣告素材的參照。VAST 文件應繼續納入特定廣告素材的媒體檔案,但無法保證系統會使用這些媒體檔案。

在 VAST 文件中參照已處理的廣告素材有兩種方式:在 VAST 4+ 文件中新增 UniversalAdId 元素,或新增自訂擴充功能。

通用廣告 ID

由 Video Creative Ingest API 傳回的 gvRegistryID 是通用的公開 ID,用於在多個廣告系統中唯一識別影片廣告素材。這個 ID 應加入廣告系統的 VAST 4+ 文件,這樣當 YouTube 或 DAI 收到 VAST 文件時,系統就能使用這個 ID 將其對應至原先提交的廣告素材。

廣告系統應在「Creative」節點下,將新的「UniversalAdId」元素新增至 VAST 4+ 文件。idRegistry 屬性應設為「googlevideo」,且值應為已成功處理廣告素材通知的狀態中提供的值。

以下是已新增通用廣告 ID 的 VAST 4 範例文件:

<VAST xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vast.xsd" version="4.0">
  <Ad id="318230556">
    <InLine>
      <AdSystem>DCM</AdSystem>
      <AdTitle>In-Stream Video</AdTitle>
      <Creatives>
        <Creative id="79534759" AdID="" sequence="1">
          <UniversalAdId idRegistry="googlevideo">dQw4w9WgXcQ</UniversalAdId>
          <Linear>
            <Duration>00:00:15</Duration>
            <MediaFiles>
              <Mezzanine>
                <![CDATA[https://cdn.com/media.mp4]]>
              </Mezzanine>
              <MediaFile delivery="progressive" width="640" height="360" type="video/mp4" bitrate="313">
                <![CDATA[https://cdn.com/low-res-media.mp4]]>
              </MediaFile>
            </MediaFiles>
          </Linear>
        </Creative>
      </Creatives>
    </InLine>
  </Ad>
</VAST>

CreativeExtension

由於通用廣告 ID 元素僅在 VAST 4.0 中推出,因此相同的資料需要自訂擴充功能,才能在 VAST 4.0 以下版本的文件中顯示。方法是在 VAST 規格的 Creative 元素下方使用 CreativeExtension 元素。

這項新推出的額外資訊是通用額外資訊,可用於填入任何通用廣告 ID 值。在這種特殊情況下,通用廣告 ID 會屬於 Google 影片註冊表,而 ID 則會是 Google 影片 ID。

<VAST version="3.0">
  <Ad id="318230556">
    <InLine>
      <AdSystem>My Ad Server</AdSystem>
      <AdTitle>Car Company</AdTitle>
      <Creatives>
        <Creative id="79534759" AdID="" sequence="1">
          <Linear>...</Linear>
          <CreativeExtensions>
            <CreativeExtension type="UniversalAdId">
              <UniversalAdId idRegistry="googlevideo">dQw4w9WgXcQ</UniversalAdId>
            </CreativeExtension>
          </CreativeExtensions>
        </Creative>
      </Creative>
    </InLine>
  </Ad>
</VAST>

如果 UniversalAdId 已填入其他 UniversalAdId 註冊表的 ID,CreativeExtension 方法也可以用於 VAST 4+:

<VAST xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vast.xsd" version="4.0">
  <Ad id="318230556">
    <InLine>
      <AdSystem>DCM</AdSystem>
      <AdTitle>In-Stream Video</AdTitle>
      <Creatives>
        <Creative id="79534759" AdID="" sequence="1">
          <UniversalAdId idRegistry="other-registry">other-id</UniversalAdId>
          <Linear>
            <Duration>00:00:15</Duration>
            <MediaFiles>
              <Mezzanine>
                <![CDATA[https://cdn.com/media.mp4]]>
              </Mezzanine>
              <MediaFile delivery="progressive" width="640" height="360" type="video/mp4" bitrate="313">
                <![CDATA[https://cdn.com/low-res-media.mp4]]>
              </MediaFile>
            </MediaFiles>
          </Linear>
          <CreativeExtensions>
            <CreativeExtension type="UniversalAdId">
              <UniversalAdId idRegistry="googlevideo">dQw4w9WgXcQ</UniversalAdId>
            </CreativeExtension>
          </CreativeExtensions>
        </Creative>
      </Creatives>
    </InLine>
  </Ad>
</VAST>