Cloudflare Streamで動画のクリッピングをしてみた

Cloudflare Streamで動画のクリッピングをサポートしました。アップロード済みのVOD動画に対して、In/Out点を指定することで新たな動画コンテンツが生成されます。現時点ではAPIのみのサポートである点などに注意しましょう。
2022.08.31

はじめに

清水です。Cloudflareの動画配信プラットフォームのサービスCloudflare StreamでAPIを使って動画のクリッピングが行えるアップデートがありました。ドキュメントのChangelogによると2022/08/02にアップデートされていたようです。

本エントリではこのAPIによる動画のクリッピング機能について、実際に動作を確認してみたのでまとめてみます。

Stream APIで動画のクリッピングをしてみた

それでは実際にドキュメント(Clip videos · Cloudflare Stream docs)を参照しながら、動画のクリッピングをやってみたいと思います。なおここで言うクリッピングは、動画の尺(時間軸)に対して開始(In点)、終了(Out点)を指定して新たな動画コンテンツとして切り出す、という操作を示しています。トリミングなどとも呼ばれますね。紛らわしい言葉としてクロッピング(Cropping)と呼ばれる、動画の縦・横から指定の幅・高さを切り出す操作がありますが、今回扱うのはクリッピング(Clipping)のほうとなります。

動画のクリッピングは現在のところStreamダッシュボードからの操作はサポートされておらず、API経由での操作が必要な点に注意しましょう。以下エントリなどを参考に、APIトークンを準備しておきます。

まずはクリッピング対象となる動画コンテンツを確認しておきます。なおライブストリーミングを録画した動画コンテンツはクリッピングサポート外とのことです。VODコンテンツとしてアップロードしたものがクリッピング対象となるわけですね。今回は以下のコンテンツを対象としました。動画の尺は53秒のものです。

API経由で動画コンテンツの情報も確認しておきましょう。以下のようにシェルの変数でTOKENACCOUNTそしてVIDEOIDをあらかじめ指定しておきます。

% TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
% ACCOUNT=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
% VIDEOID=bbd3XXXXXXXXXXXXXXXXXXXXXXXXXXXX
% curl -X GET \
     -H "Authorization: Bearer ${TOKEN}" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/${VIDEOID}"
{
  "result": {
    "uid": "bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "creator": "user-musashino",
    "thumbnail": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/thumbnails/thumbnail.jpg",
    "thumbnailTimestampPct": 0,
    "readyToStream": true,
    "status": {
      "state": "ready",
      "pctComplete": "100.000000",
      "errorReasonCode": "",
      "errorReasonText": ""
    },
    "meta": {
      "downloaded-from": "https://my-s3-bucket.s3.ap-northeast-1.amazonaws.com/IMG_3435.MOV",
      "name": "吉祥寺の駅"
    },
    "created": "2022-04-30T10:53:00.119086Z",
    "modified": "2022-08-30T14:35:50.367746Z",
    "size": 336065892,
    "preview": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/watch",
    "allowedOrigins": [],
    "requireSignedURLs": false,
    "uploaded": "2022-04-30T10:53:00.119078Z",
    "uploadExpiry": null,
    "maxSizeBytes": null,
    "maxDurationSeconds": null,
    "duration": 53.8,
    "input": {
      "width": 3840,
      "height": 2160
    },
    "playback": {
      "hls": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest/video.m3u8",
      "dash": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest/video.mpd"
    },
    "watermark": null,
    "clippedFrom": null,
    "publicDetails": {
      "title": "",
      "share_link": "",
      "channel_link": "",
      "logo": ""
    }
  },
  "success": true,
  "errors": [],
  "messages": []
}

クリッピングの実行には/clipエンドポイントに、必要なデータをJSONでまとめてPOSTします。JSONデータは以下のように指定を行います。

{
    "clippedFromVideoUID": "クリップするもとの動画コンテンツのビデオID",
    "startTimeSeconds": クリッピングの開始時間(IN点、秒),
    "endTimeSeconds": クリッピングの終了時間(OUT点、秒),
    "meta": {
      "name": "クリッピング後の動画コンテンツ名称"
    }
}

動画コンテンツ名称はオプションで必須ではありません。そのほかWatermarkの指定や署名付きURL設定、サムネイル画像の指定なども行うことができます。詳細はドキュメントを参照ください。

以下がAPI実行のcurlコマンドになります。

curl -L -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     -H "Content-Type: application/json" \
     -d "{
             \"clippedFromVideoUID\": \"${VIDEOID}\",
             \"startTimeSeconds\": 20,
             \"endTimeSeconds\": 35,
             \"meta\": {
                 \"name\": \"吉祥寺の駅(15秒Ver)\"
             }
         }" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/clip"

送信データのJSONを整形すると以下となります。クリッピングの開始点(in点)がもとの動画コンテンツの先頭から20秒の時点、終了(Out点)がもとの動画コンテンツの先頭から35秒の時点、合計15秒のクリップを作成する、というように指定してみました。

{
    "clippedFromVideoUID": "${VIDEOID}"
    "startTimeSeconds": 20,
    "endTimeSeconds": 35,
    "meta": {
      "name": "吉祥寺の駅(15秒Ver)"
    }
}

以下が実行結果です。

% curl -L -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     -H "Content-Type: application/json" \
     -d "{
             \"clippedFromVideoUID\": \"${VIDEOID}\",
             \"startTimeSeconds\": 20,
             \"endTimeSeconds\": 35,
             \"meta\": {
                 \"name\": \"吉祥寺の駅(15秒Ver)\"
             }
         }" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/clip"

{
  "result": {
    "uid": "3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "creator": null,
    "thumbnail": "https://cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/thumbnails/thumbnail.jpg",
    "thumbnailTimestampPct": 0,
    "readyToStream": false,
    "status": {
      "state": "queued",
      "errorReasonCode": "",
      "errorReasonText": ""
    },
    "meta": {
      "name": "吉祥寺の駅(15秒Ver)"
    },
    "created": "2022-08-30T15:18:57.275817Z",
    "modified": "2022-08-30T15:18:57.275817Z",
    "size": 0,
    "preview": "https://cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/watch",
    "allowedOrigins": [],
    "requireSignedURLs": false,
    "uploaded": null,
    "uploadExpiry": null,
    "maxSizeBytes": null,
    "maxDurationSeconds": null,
    "duration": -1,
    "input": {
      "width": -1,
      "height": -1
    },
    "playback": {
      "hls": "https://cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest/video.m3u8",
      "dash": "https://cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest/video.mpd"
    },
    "watermark": null,
    "clippedFrom": "bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "publicDetails": null
  },
  "success": true,
  "errors": [],
  "messages": []
}

クリッピングAPI実行後、Streamダッシュボードのほうで動画コンテンツを確認してみましょう。API実行直後は以下のように「待ち状態」と表示されています。動画コンテンツアップロードなどの場合と同様、変換に少し時間がかかります。「準備ができました」の表示なればコンテンツの視聴が可能です。

ビデオIDが新しく振られています。もとの(クリッピング前の)動画コンテンツと別の動画コンテンツとして扱われるぐあいですね。

API経由で動画コンテンツの情報についても確認しておきましょう。クリッピングAPI実行直後は"duration"などの値が設定されていませんでしたが、以下ではきちんと値が設定されていますね。

% CLIPPEDVIDEOID="3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
% curl -X GET \
     -H "Authorization: Bearer ${TOKEN}" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/${CLIPPEDVIDEOID}"
{
  "result": {
    "uid": "3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "creator": null,
    "thumbnail": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/thumbnails/thumbnail.jpg",
    "thumbnailTimestampPct": 0,
    "readyToStream": true,
    "status": {
      "state": "ready",
      "pctComplete": "100.000000",
      "errorReasonCode": "",
      "errorReasonText": ""
    },
    "meta": {
      "name": "吉祥寺の駅(15秒Ver)"
    },
    "created": "2022-08-30T15:18:57.275817Z",
    "modified": "2022-08-30T15:20:55.047092Z",
    "size": 0,
    "preview": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/watch",
    "allowedOrigins": [],
    "requireSignedURLs": false,
    "uploaded": null,
    "uploadExpiry": null,
    "maxSizeBytes": null,
    "maxDurationSeconds": null,
    "duration": 15,
    "input": {
      "width": 3840,
      "height": 2160
    },
    "playback": {
      "hls": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest/video.m3u8",
      "dash": "https://customer-0jyoxxxxxxxxflpw.cloudflarestream.com/3ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest/video.mpd"
    },
    "watermark": null,
    "clippedFrom": "bbd3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "publicDetails": {
      "title": "",
      "share_link": "",
      "channel_link": "",
      "logo": ""
    }
  },
  "success": true,
  "errors": [],
  "messages": []
}

まとめ

Cloudflare Streamの動画クリッピングについて確認してみました。すでにCloudfare Streamにアップロードしている動画コンテンツであれば、クリッピングした動画を再度アップロードするのではなく、In/Out点を指定したクリッピングAPIを実行することでCloudflare Stream側でクリッピング動画が作成可能です。非常に便利で、強力な機能だと思います。現状ではStreamダッシュボードでは非対応でありAPIから実行する必要がある点、またライブストリーミングを録画した動画コンテンツはサポート対象外である点に注意しましょう。個人的には後者のライブストリーミングの録画コンテンツに対するクリッピングのサポートが待ち遠しいです!