개요: 포렌식 워터마킹

이 주제에서는 Brightcove의 Forensic Watermarking 기능에 대한 높은 수준의 개요를 얻을 수 있습니다.

서문

Brightcove는 NAGRA 와 협력하여 비디오 클라우드 플랫폼의 기능으로 포렌식 워터마킹을 제공합니다. 이렇게 하면 불법 복제 및 무단 콘텐츠 공유로부터 프리미엄 콘텐츠를 보호하는 데 도움이 됩니다. 이 기능은 콘텐츠 유출의 원인을 신속하게 파악하여 조치를 취하는 데도 도움이 됩니다.

다음 다이어그램은 개요를 보여줍니다.

  • 콘텐츠 준비
    • Forensic Watermark는 Nagra의 SDK를 사용하여 트랜스코딩하는 동안 비디오에 포함된 보이지 않는 워터마크입니다.
    • Ingestion은 2개의 VOD 변환을 생성합니다. 하나는 워터마크 A이고 다른 하나는 워터마크 B입니다. 두 변환 모두 Video Cloud에서 동일한 타이틀의 일부입니다.
  • 배달
    • 콘텐츠 재생 시 Forensic Watermark 토큰을 플레이어에게 제공한 후 CDN에서 콘텐츠를 요청하는 URL에 포함
    • CDN은 토큰을 해석하고 A/B 세그먼트의 올바른 순서로 비디오를 시청자에게 전달합니다.
개요 다이어그램
포렌식 워터마킹 개요

설정

Brightcove의 Forensic Watermarking 솔루션을 지원하려면 다음 설정이 필요합니다.

  1. 고객 성공 관리자에게 문의하십시오.
    1. 귀하의 계정이 Dynamic Delivery에 대해 활성화되어 있는지 확인하십시오.
    2. Forensic Watermarking을 위해 귀하의 계정을 활성화하십시오. Video Cloud의 유료 애드온입니다.
  2. NAGRA 에서 라이센스 키를 받으십시오.
  3. Forensic Watermarking JWT에서 사용하고 CDN에서 해독할 퍼블릭-프라이빗 키 쌍을 생성합니다. (아래 참조)
  4. NAGRA에서 제공하는 스크립트를 사용하여 포렌식 워터마킹을 위한 JSON 웹 토큰(JWT)을 생성합니다. 포렌식 워터마크 토큰과 각 뷰어가 어떻게 연결되어 있는지 관리해야 합니다. 플레이어를 구성할 때와 감지 서비스를 수행하는 경우 어떤 시청자가 콘텐츠를 불법적으로 유출했는지 알기 위해 필요합니다.

공개-개인 키 쌍을 생성하는 방법에는 여러 가지가 있습니다. 다음은 몇 가지 예입니다.

배쉬 스크립트 예제:

키 쌍을 생성하는 예제 스크립트:

#!/bin/bash
set -euo pipefail

NAME=${1:-}
test -z "${NAME:-}" && NAME="brightcove-forensic-watermarking-key-$(date +%s)"
mkdir "$NAME"

PRIVATE_PEM="./$NAME/private.pem"
PUBLIC_PEM="./$NAME/public.pem"
PUBLIC_TXT="./$NAME/public_key.txt"

ssh-keygen -t rsa -b 2048 -m PEM -f "$PRIVATE_PEM" -q -N ""
openssl rsa -in "$PRIVATE_PEM" -pubout -outform PEM -out "$PUBLIC_PEM" 2>/dev/null
openssl rsa -in "$PRIVATE_PEM" -pubout -outform DER | base64 > "$PUBLIC_TXT"

rm "$PRIVATE_PEM".pub

echo "Public key to saved in $PUBLIC_TXT"

스크립트를 실행합니다.

$ bash keygen.sh
사용 예제Go

Go프로그래밍 언어를 사용하여 키 쌍을 생성하는 예:

package main
  
  import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/base64"
    "encoding/pem"
    "flag"
    "fmt"
    "io/ioutil"
    "os"
    "path"
    "strconv"
    "time"
  )
  
  func main() {
    var out string
  
    flag.StringVar(&out, "output-dir", "", "Output directory to write files into")
    flag.Parse()
  
    if out == "" {
      out = "rsa-key_" + strconv.FormatInt(time.Now().Unix(), 10)
    }
  
    if err := os.MkdirAll(out, os.ModePerm); err != nil {
      panic(err.Error())
    }
  
    priv, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
      panic(err.Error())
    }
  
    privBytes := x509.MarshalPKCS1PrivateKey(priv)
  
    pubBytes, err := x509.MarshalPKIXPublicKey(priv.Public())
    if err != nil {
      panic(err.Error())
    }
  
    privOut, err := os.OpenFile(path.Join(out, "private.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
    if err != nil {
      panic(err.Error())
    }
  
    if err := pem.Encode(privOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}); err != nil {
      panic(err.Error())
    }
  
    pubOut, err := os.OpenFile(path.Join(out, "public.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
    if err != nil {
      panic(err.Error())
    }
  
    if err := pem.Encode(pubOut, &pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}); err != nil {
      panic(err.Error())
    }
  
    var pubEnc = base64.StdEncoding.EncodeToString(pubBytes)
  
    var pubEncOut = path.Join(out, "public_key.txt")
    if err := ioutil.WriteFile(pubEncOut, []byte(pubEnc+"\n"), 0600); err != nil {
      panic(err.Error())
    }
  
    fmt.Println("Public key saved in " + pubEncOut)
  }
  

node.js 사용 예제

node.js 를 사용하여 키 페어를 생성하는 예:

var crypto = require("crypto");
  var fs = require("fs");
  
  var now = Math.floor(new Date() / 1000);
  var dir = "rsa-key_" + now;
  fs.mkdirSync(dir);
  
  crypto.generateKeyPair(
    "rsa",
    {modulusLength: 2048},
    (err, publicKey, privateKey) => {
      fs.writeFile(
        dir + "/public.pem",
        publicKey.export({ type: "spki", format: "pem" }),
        err => {}
      );
      fs.writeFile(
        dir + "/public_key.txt",
        publicKey.export({ type: "spki", format: "der" }).toString("base64") +
          "\n",
        err => {}
      );
      fs.writeFile(
        dir + "/private.pem",
        privateKey.export({ type: "pkcs1", format: "pem" }),
        err => {}
      );
    }
  );
  
  console.log("Public key saved in " + dir + "/public_key.txt");

구현

Video Cloud Studio를 사용하여 Forensic Watermarking을 구현하거나 Brightcove API를 사용하여 수동으로 구현할 수 있습니다. 방법은 다음 섹션에 자세히 설명되어 있습니다.

비디오 클라우드 스튜디오

Video Cloud Studio에서 Forensic Watermarking을 사용하려면 다음 단계를 따르십시오.

  1. Forensic Watermarking은 특정 수집 프로필에 연결되어 있지 않습니다. Dynamic Delivery 또는 컨텍스트 인식 인코딩 프로필을 사용할 수 있습니다.

    1. NAGRA 라이선스 키를 Brightcove에 제공합니다. 이 라이센스 키는 트랜스코딩 중에 워터마크를 생성하는 데 사용됩니다.
    2. 업로드 모듈에서 인제스트 프로필을 선택합니다.
    3. 포렌식 워터마크 활성화 옵션을 선택합니다.

      워터마킹 옵션 활성화
      워터마킹 옵션 활성화
    4. watermarked비디오에 태그를 추가하면 포렌식 워터마킹이 적용된 비디오를 훨씬 쉽게 식별하고 이에 대한 분석 보고서를생성할 수 있습니다 .
      태그 추가
      태그 추가
    5. 처리를 시작하려면 동영상을 드래그하거나 찾아보세요.

  2. 플레이어를 구성합니다.

    여기에서 NAGRA 워터마크 토큰과 뷰어 ID를 플레이어에게 전달합니다. Brightcove 웹 플레이어 또는 Native SDK 플레이어를 사용할 수 있습니다.

  3. 포렌식 워터마킹을 위해 수집된 콘텐츠를 재생합니다.

분석 보고서

포렌식 워터마크 비디오에 대한 뷰어에 대한 Analytics 보고서는 Analytics API 를 통해서만 사용할 수 있습니다. 보고서는 JSON, CSV 또는 XLXS 형식으로 반환될 수 있습니다.

애널리틱스 데이터에서:

1 Transaction = 1 unique Viewer per video in 24 hours

예 1: 날짜별 동영상 시청자

이 예시에서는video , viewerdate측정기준을 쿼리하고 보고서를 CSV 형식으로 다시 가져와보겠습니다.

샘플 요청

https://analytics.api.brightcove.com/v1/data?accounts=4800266849001&from=2021-06-23&to=2021-06-25&dimensions=date,viewer&limit=10&where=video==70702952720202&fields=video,viewer,video_view&format=csv

대응

"date","video","viewer","video_view"
"2021-06-25","70702952720202","3f46037f932b0c5a","1"
"2021-06-24","70702952720202","3f46037f932b0c5a","2"

viewer는 Brightcove 플레이어에서 생성되며 사용자 에이전트 및 IP를 기반으로 고유한 문자열로 설정된다는 점에 유의하십시오. 이상적으로는 로그인 ID를 기반으로 뷰어 식별자를 직접 설정해야 합니다. 이를 수행하는 방법에 대한 정보는 이 항목을 참조하십시오. 귀하의 식별자는 JavaScript를 통해 검색할 수 있는 정보를 기반으로 합니다.

예 2: 시청자 수

이 예시에서는 포렌식 워터마킹이 적용된 모든 동영상에 태그가 있다고 가정해 보겠습니다watermarked . 다시video , viewerdate차원을 쿼리하고 하나의 항목만 반환하겠습니다. 이는 우리가 관심을 갖고 있는 요약이므로 다음과 같습니다.

샘플 요청

https://analytics.api.brightcove.com/v1/data?accounts=4800266849001&from=2021-06-23&to=2021-06-25&dimensions=date,viewer&limit=1&where=video.q==tags:watermarked

대응

{
  "item_count": 7,
  "items": [
    {
      "date": "2021-06-25",
      "viewer": "07B1489C-5786-400E-945B-ABB3559B3897",
      "video_view": 1
    }
  ],
  "summary": {
    "video_view": 25
  }
}

API

포렌식 워터마킹과 관련된 API 및 필드는 다음과 같습니다.

동적 인제스트 API

계정에 포렌식 워터마킹이 활성화되면 인제스트 요청에forensic_watermarking필드를 추가하고 로 설정하여 비디오에 포렌식 워터마킹을 추가할 수true있습니다. 이 작업은 비디오의 원본 수집, 교체 또는 재변환에 대해 수행할 수 있습니다.

샘플 요청 본문

{
  "master": {
          "url": "https://solutions.brightcove.com/video/Walking_Dead_609.mp4",
          "audio_tracks": [
              {
                  "language": "en",
                  "variant": "main"
              }
          ]
      },
    "profile": "multi-platform-standard-static-with-mp4",
    "forensic_watermarking": true,
    "capture-images": true
}

또 한있다forensic_watermarking_stub_mode플래그로 설정하면true눈에 보이는 포렌식 워터마크 생성:

가시적 포렌식 워터마크
가시적 포렌식 워터마크

forensic_watermarking또한 보이는 워터마크를true활성화하려면 로 설정해야 합니다.

동영상에 보이는 워터마크를 사용하여 통합을 테스트합니다(최소 10분 길이의 동영상으로 테스트해야 함). 포렌식 워터마크가 있는 것을 확인한 후에는 포렌식 워터마크가 보이지 않도록 제거해야 합니다. 이렇게 하려면 동영상을 다시 트랜스코딩하기 위한 또 다른 Dynamic Ingest 요청을 제출해야 합니다. 이번에는forensic_watermarking_stub_mode로 설정해야false합니다.

가시적인 포렌식 워터마크에 대한 샘플 요청 본문

{
  "master": {
          "url": "https://solutions.brightcove.com/video/Walking_Dead_609.mp4",
          "audio_tracks": [
              {
                  "language": "en",
                  "variant": "main"
              }
          ]
      },
    "profile": "multi-platform-standard-static-with-mp4",
    "forensic_watermarking": true,
    "forensic_watermarking_stub_mode": true,
    "capture-images": true
}

보이는 포렌식 워터마크를 제거하기 위한 샘플 요청 본문

{
    "profile": "multi-platform-standard-static-with-mp4",
    "forensic_watermarking": true,
    "forensic_watermarking_stub_mode": false,
    "capture-images": true
}

CMS API

기본적으로 수집 중에 포렌식 워터마크가 요청된 경우 포렌식 워터마크가 있는 변환이 전달됩니다. 포렌식 워터마크가 있는지 여부는 읽기 전용 필드로 표시됩니다forensic_watermarking . 필드의ACTIVE값이 이면 포렌식 워터마크가 VOD에 추가된 것입니다. 필드의 값이UNAVAILABLE또는null인 경우 VOD에는 포렌식 워터마크가 없습니다.

젠코더

Zencoder에서 포렌식 워터마킹을 사용하여 출력을 생성하려면 비디오당 2개의 출력을 지정해야 합니다. 하나는 포함된"forensic_watermark": "A"출력이고 다른 하나는 포함입니다"forensic_watermark": "B" ( forensic_watermark필드에서 가질 수 있는 유일한 두 개의 값임).

샘플 요청(출력만 해당)

{
  "outputs": [
      {
          "base_url": "s3://urlTest",
          "filename": "contextAwareEncoding1_A.m4f",
          "public": false,
          "format": "m4f",
          "label": "m4f-contextAwareEncoding1-A-b30e1",
          "generate_mp4_atom_map": true,
          "Mp4_atom_map_filename": "contextAwareEncod-A-atom_map.json",
          "skip_audio": true,
          "forensic_watermark": "A",
          "dynamic_profile_rendition": 1,
          "skip": {
              "require_video": true
          },
          "fragment_duration": 2000,
          "segment_seconds": 2,
          "headers": {
              "x-amz-server-side-encryption": "AES256"
          }
      },
      {         
          "base_url": "s3://urlTest",
          "filename": "contextAwareEncoding1_B.m4f",
          "public": false,
          "format": "m4f",
          "label": "m4f-contextAwareEncoding1-B-e348",
          "generate_mp4_atom_map": true,
          "mp4_atom_map_filename": "contextAwareEncod-B-atom_map.json",
          "skip_audio": true,
          "forensic_watermark": "B",
          "dynamic_profile_rendition": 1,
          "skip": {
              "require_video": true
          },
          "fragment_duration": 2000,
          "segment_seconds": 2,
          "headers": {
              "x-amz-server-side-encryption": "AES256"
          }
      }
  ]
}

테스트를 위한 보이는 워터마크

테스트 목적으로 포렌식 워터마킹이 있는지 확인하려면 아래 샘플에 표시된 대로 출력에 포렌식 워터마킹을 추가하여 가시적인 포렌식 워터마킹을"forensic_watermark_stub_mode":true강제할 수 있습니다.

{
  "outputs": [
      {
          "base_url": "s3://urlTest",
          "filename": "contextAwareEncoding1_A.m4f",
          "public": false,
          "format": "m4f",
          "label": "m4f-contextAwareEncoding1-A-b30e1",
          "generate_mp4_atom_map": true,
          "Mp4_atom_map_filename": "contextAwareEncod-A-atom_map.json",
          "skip_audio": true,
          "forensic_watermark": "A",
          "forensic_watermark_stub_mode":true,
          "dynamic_profile_rendition": 1,
          "skip": {
              "require_video": true
          },
          "fragment_duration": 2000,
          "segment_seconds": 2,
          "headers": {
              "x-amz-server-side-encryption": "AES256"
          }
      },
      {         
          "base_url": "s3://urlTest",
          "filename": "contextAwareEncoding1_B.m4f",
          "public": false,
          "format": "m4f",
          "label": "m4f-contextAwareEncoding1-B-e348",
          "generate_mp4_atom_map": true,
          "mp4_atom_map_filename": "contextAwareEncod-B-atom_map.json",
          "skip_audio": true,
          "forensic_watermark": "B",
          "forensic_watermark_stub_mode":true,
          "dynamic_profile_rendition": 1,
          "skip": {
              "require_video": true
          },
          "fragment_duration": 2000,
          "segment_seconds": 2,
          "headers": {
              "x-amz-server-side-encryption": "AES256"
          }
      }
  ]
}

지원되는 기능

  • HEVC
  • 혼합 코덱 변환 래더
  • 5.1 오디오
  • DRM
  • 재생 제한
  • 재트랜스코딩
  • 소스 파일 교체
  • 케이
  • 오프라인 다운로드
  • 크롬캐스트
  • 에어플레이

제한 사항

  • 현재 VOD만 지원됩니다. 라이브 스트림에 대한 포렌식 워터마킹은 지원되지 않습니다.
  • 포렌식 워터마킹을 적용하려면 동영상 길이가 5분 이상이어야 합니다.
  • 암호화된 HLS 비디오(HLSe)는 현재 지원되지 않습니다.
  • SSAI는 Forensic Watermarking에서 지원되지 않습니다. Forensic Watermarking이 있는 자산에 SSAI가 사용되는 경우 Forensic Watermarking이 제공되지 않습니다.
  • 이 기능에는 NAGRA 라이선스 키가 필요합니다.
  • 플레이어는 NAGRA에서 제공하는 스크립트를 사용하여 생성할 포렌식 워터마크 JWT가 필요합니다.
  • 전달 규칙은 포렌식 워터마킹이 포함된 비디오를 전달하는 데 사용되는 플레이어와 함께 사용할 수 없습니다.
  • Brightcove의 CDN을 사용해야 합니다. BYO CDN은 지원되지 않습니다.
  • Brightcove는 탐지 분석을 처리하지 않습니다. 이에 대해서는 NAGRA에 문의하십시오.
  • Forensic Watermarking은 License Keys Protection 에서 지원되지 않습니다.