# Netflix licensedManifest API — Android ストリーミングプロファイル・画質指定 Netflix Android アプリが動画再生に必要なストリーム情報と DRM ライセンスを一括取得する `/licensedManifest` API の仕様。Frida フック (L3 強制環境) で取得した平文リクエストに基づく。 > **iOS との違い**: iOS 版では `/manifest` (マニフェスト) と `/license` (DRM ライセンス) が別リクエストだが、Android 版では `/licensedManifest` として**統合**されている。 --- ## 1. 概要 `/licensedManifest` は MSL (Message Security Layer) で暗号化された API エンドポイント。マニフェスト取得と Widevine ライセンス取得を 1 リクエストで行う。バッチリクエストにより複数の `viewableId` を同時に指定可能。 --- ## 2. 通信フロー ```mermaid %%{init: {'theme': 'dark'}}%% sequenceDiagram participant UI as Netflix UI participant Player as Samurai Player participant MSL as MSL Layer participant Crypto as WidevineCryptoContext participant DRM as MediaDrm (Widevine) participant Server as android14.prod.ftl.netflix.com Note over UI: ユーザーがコンテンツを選択 rect rgba(180, 130, 50, 0.2) Note over Player,DRM: DRM チャレンジ生成 Player->>DRM: openSession() DRM->>Player: sessionId Player->>DRM: getKeyRequest(sessionId, initData, STREAMING) DRM->>Player: challengeBase64 (Widevine protobuf) end rect rgba(50, 160, 80, 0.2) Note over Player,Server: licensedManifest (PRE_FETCH) Player->>MSL: apiRequest("/licensedManifest", params) Note over MSL: viewableId × N + challengeBase64 MSL->>Crypto: encrypt(payload) MSL->>Crypto: sign(message) MSL->>Server: POST /nq/androidui/samurai/~9.0.0/api Server->>MSL: MSL 暗号化レスポンス MSL->>Crypto: decrypt(payload) MSL->>Player: manifest JSON + Widevine ライセンス end rect rgba(60, 100, 180, 0.2) Note over Player,DRM: コンテンツ鍵インストール Player->>DRM: provideKeyResponse(sessionId, license) DRM->>Player: コンテンツ鍵有効化 end rect rgba(130, 60, 160, 0.2) Note over Player,Server: /license (standard, 再生開始時) Player->>MSL: apiRequest("/license", params) Note over MSL: licenseType=standard + challengeBase64 MSL->>Server: POST (with playbackContextId, esn) Server->>MSL: Widevine ライセンスレスポンス end Note over Player: 再生開始 (CDN URL + コンテンツ鍵) ``` ### 全体の流れ ```mermaid %%{init: {'theme': 'dark'}}%% flowchart LR subgraph "1. マニフェスト + ライセンス" A["/licensedManifest
PRE_FETCH
(バッチ: N viewableIds)"] end subgraph "2. 再生時ライセンス" B["/license
standard
(challengeBase64)"] end subgraph "3. ストリーム再生" C["CDN からセグメント取得
(DASH + Widevine CENC)"] end A --> B B --> C style A fill:#6b4c1e,stroke:#c8943e,color:#f0d8a8 style B fill:#1e3a6b,stroke:#3e78c8,color:#a8c8f0 style C fill:#4a1e6b,stroke:#8e3ec8,color:#d0a8f0 ``` --- ## 3. 暗号化 `/licensedManifest` のリクエスト・レスポンスは **MSL プロトコル (Widevine CryptoContext)** で暗号化されている。 ```mermaid %%{init: {'theme': 'dark'}}%% flowchart TD subgraph "リクエスト (クライアント → サーバー)" R1["平文 JSON
(viewableId, profiles, challenge, ...)"] R2["MSL PayloadChunk
WidevineCryptoContext.encrypt"] R3["MSL MessageHeader
encrypt + sign"] R4["HTTP POST Body
(CBOR 暗号化済み)"] R1 -->|"encrypt()"| R2 R1 -->|"sign()"| R3 R2 --> R4 R3 --> R4 end subgraph "レスポンス (サーバー → クライアント)" S1["HTTP Response Body
(CBOR 暗号化済み)"] S2["CBOR dict
key 62 = GZIP データ"] S3["平文 JSON
(CDN URL, ストリーム一覧, ライセンス)"] S1 -->|"WidevineCryptoContext.decrypt()"| S2 S2 -->|"gzip.decompress()"| S3 end ``` | 項目 | 暗号化 | 状態 | |---|---|---| | リクエスト (profiles, viewableId, challenge 等) | MSL (Widevine CryptoContext) | **平文取得済み** — `apiRequest` フックで暗号化前に捕捉 | | レスポンス (CDN URL, ストリーム一覧) | MSL + GZIP 圧縮 | **L3: 復元可能** — decrypt 平文 → CBOR → GZIP で復元 / L1: 未取得 | | HTTP トランスポート | TLS 1.2/1.3 | TLS 上に MSL が重ねられている (二重暗号化) | | 動画セグメント本体 | Widevine CENC (Common Encryption) | コンテンツ鍵は `/license` レスポンスから取得 | --- ## 4. リクエストパラメータ `ApiHandlerImpl.apiRequest("/licensedManifest", params)` で送信される JSON。 ### 4.1 全パラメータ一覧 ```json { "version": 2, "url": "/licensedManifest", "languages": ["en-JP"], "common": { "challenge": "" }, "params": [ { "viewableId": "81756595", "profiles": [ ... ], "profileGroups": [ ... ], "challenges": { "primary": [{ "challengeBase64": "", "drmSessionId": 1, "clientTime": 1773373148 }] }, "method": "licensedManifest", "flavor": "PRE_FETCH", "drmType": "widevine", "manifestVersion": "v2", "licenseType": "limited", "cellularCap": "auto", "netType": "wifi", "useHttpsStreams": true, "useBetterTextUrls": true, "supportsWatermark": true, "supportsPreReleasePin": true, "requestEligibleABTests": true, "supportsUnequalizedDownloadables": true, "supportsAdBreakHydration": true, "supportsPartialHydration": true, "supportsAuxiliaryManifestDeduplication": true, "supportsNetflixMediaEvents": true, "supportsVideoTrackSwitching": false, "prefersVerticalVideo": false, "liveAdsCapability": "dynamic", "liveMetadataFormat": "INDEXED_SEGMENT_TEMPLATE", "maxSupportedLanguages": -1, "contentPlaygraph": ["v2"], "osName": "android", "osVersion": "34", "application": "samurai", "clientVersion": "9.57.0", "uiVersion": "9.57.0", "uiPlatform": "android", "player": "streaming", "hardware": "lito", "uiContext": { "uiFlavor": "android", "clientAppVersion": "9.57.0", "deviceTier": "AndroidDeviceTier", "adCanvasUICapabilities": ["SlotBasedUI"] } } ] } ``` ### 4.2 主要パラメータの意味 | パラメータ | 型 | 説明 | |---|---|---| | `version` | number | API バージョン。`2` | | `url` | string | MSL 内部パス。`"/licensedManifest"` | | `languages` | string[] | 優先言語。`["en-JP"]` | | `common.challenge` | string | **共通 Widevine チャレンジ** — 全 viewableId で共有される CDM protobuf | | `params` | array | **バッチリクエスト** — 複数の viewableId を同時に指定可能 | | `viewableId` | string | コンテンツ ID。Netflix の各作品/エピソードに割り当てられた一意の番号 | | `profiles` | string[] | クライアントが対応するコーデック・画質プロファイルの一覧 | | `profileGroups` | object[] | profiles をグループ分けした構造 | | `challenges.primary` | array | **個別 Widevine チャレンジ** — viewableId ごとの CDM protobuf + `drmSessionId` | | `method` | string | `"licensedManifest"` | | `flavor` | string | `"PRE_FETCH"` = 先読み | | `drmType` | string | `"widevine"` (iOS では `"fairplay"`) | | `manifestVersion` | string | `"v2"` | | `licenseType` | string | `"limited"` (PRE_FETCH) / `"standard"` (再生時) | | `cellularCap` | string | セルラー回線時の帯域制限。`"auto"` | | `netType` | string | 接続種別。`"wifi"` / `"cellular"` | | `liveAdsCapability` | string | ライブ広告対応。`"dynamic"` | | `liveMetadataFormat` | string | ライブメタデータ形式。`"INDEXED_SEGMENT_TEMPLATE"` (iOS: `"HLS"`) | | `contentPlaygraph` | string[] | 再生グラフバージョン。`["v2"]` (iOS: `["start"]`) | | `hardware` | string | SoC 名。`"lito"` (Qualcomm Snapdragon 765G) | | `uiContext.deviceTier` | string | `"AndroidDeviceTier"` | | `uiContext.adCanvasUICapabilities` | string[] | 広告 UI 対応。`["SlotBasedUI"]` | | `maxSupportedLanguages` | number | `-1` = 無制限 | ### 4.3 iOS 版にないパラメータ | パラメータ | 説明 | |---|---| | `common.challenge` | 共通チャレンジ (iOS では各リクエストに個別の SPC) | | `challenges.primary[].drmSessionId` | Widevine DRM セッション ID | | `challenges.primary[].clientTime` | クライアントタイムスタンプ | | `method` | MSL 内部メソッド名 | | `useBetterTextUrls` | 字幕 URL の改善版使用 | | `requestEligibleABTests` | A/B テスト適格性リクエスト | | `liveAdsCapability` | ライブ広告対応レベル | | `supportsAuxiliaryManifestDeduplication` | 補助マニフェスト重複排除 | | `supportsNetflixMediaEvents` | Netflix メディアイベント対応 | | `supportsVideoTrackSwitching` | ビデオトラック切替対応 | --- ## 5. プロファイル (profiles) — L3 環境 L3 (ソフトウェア) 強制環境で送信されるプロファイル一覧。L1 (TEE) 環境ではより多くの高解像度プロファイルが含まれる。 ### 5.1 映像プロファイル #### H.264 (AVC) | プロファイル名 | コーデック | Level | 最大解像度目安 | 備考 | |---|---|---|---|---| | `none-h264mpl30-dash` | H.264 Main Profile | 3.0 | SD (~720x480) | DRM なし | | `playready-h264mpl30-dash` | H.264 Main Profile | 3.0 | SD | PlayReady | | `playready-h264hpl22-dash` | H.264 High Profile | 2.2 | ~352x288 | PlayReady | | `playready-h264hpl30-dash` | H.264 High Profile | 3.0 | SD | PlayReady | | `h264hpl22-dash-playready-live` | H.264 High Profile | 2.2 | 低解像度 | PlayReady (live) | | `h264hpl30-dash-playready-live` | H.264 High Profile | 3.0 | SD | PlayReady (live) | > **L1 環境で追加されるプロファイル** (推定): `playready-h264mpl31-dash`, `playready-h264mpl40-dash`, `playready-h264hpl31-dash`, `playready-h264hpl40-dash`, `h264hpl31-dash-playready-live`, `h264hpl40-dash-playready-live` #### VP9 | プロファイル名 | コーデック | Level | 最大解像度目安 | |---|---|---|---| | `vp9-profile0-L21-dash-cenc` | VP9 Profile 0 | 2.1 | ~480x360 | | `vp9-profile0-L30-dash-cenc` | VP9 Profile 0 | 3.0 | ~720x480 (SD) | > **L1 環境で追加されるプロファイル** (推定): `vp9-profile0-L31-dash-cenc`, `vp9-profile0-L40-dash-cenc` #### HEVC (H.265) — L1 環境のみ (推定) L3 環境ではキャプチャされていないが、L1 環境では以下が追加される: | プロファイル名 | コーデック | Level | 備考 | |---|---|---|---| | `hevc-hdr-main10-L30-dash-cenc` | HEVC HDR10 Main 10 | 3.0 | HDR | | `hevc-hdr-main10-L31-dash-cenc` | HEVC HDR10 Main 10 | 3.1 | HDR | | `hevc-hdr-main10-L40-dash-cenc` | HEVC HDR10 Main 10 | 4.0 | HDR | | `hevc-hdr-main10-L41-dash-cenc` | HEVC HDR10 Main 10 | 4.1 | HDR | #### その他 | プロファイル名 | 用途 | |---|---| | `iso_23001_18-dash-live` | ISO 23001-18 ライブストリーミング | ### 5.2 音声プロファイル | プロファイル名 | コーデック | チャンネル | 備考 | |---|---|---|---| | `heaac-2-dash` | HE-AAC v1 | 2ch (ステレオ) | 標準音声 | | `xheaac-dash` | xHE-AAC | 2ch | 低ビットレート対応 | > **iOS との違い**: iOS では `heaac-2hq-dash` (HQ), `dd-5.1-dash` (Dolby Digital 5.1), `ddplus-5.1-dash` / `ddplus-5.1hq-dash` (Dolby Digital Plus), `ddplus-atmos-dash` (Dolby Atmos) も含まれる。Android L3 では Dolby 系プロファイルが含まれていない。 ### 5.3 字幕・その他 | プロファイル名 | 種別 | 説明 | |---|---|---| | `imsc1.1` | 字幕 | IMSC 1.1 (Timed Text) | | `nflx-cmisc` | メタデータ | Netflix 制御メタデータ (チャプター、スキップ情報等) | | `BIF320` | サムネイル | BIF (Base Index Frames) 320px — シークバーのプレビュー | > **iOS との違い**: iOS では `webvtt-lssdh-ios13` / `webvtt-lssdh-ios8` (WebVTT), `BIF240` も含まれる。 ### 5.4 プロファイルグループ (profileGroups) L3 環境では全プロファイルが単一の `primary` グループに属する: | グループ名 | 対象プロファイル | |---|---| | `primary` | 全プロファイル (映像 + 音声 + 字幕 + その他) | > **iOS との違い**: iOS では `live` (ライブ用), `ce3` (H.264 PlayReady), `ce4` (HEVC PRK) の 3 グループに分かれる。 --- ## 6. バッチリクエスト iOS 版と異なり、Android 版では **複数の viewableId を 1 リクエストで同時に送信** できる。 キャプチャでは 3 つの viewableId が同時にリクエストされた: | viewableId | 用途 | |---|---| | `81756595` | コンテンツ 1 | | `80243261` | コンテンツ 2 | | `81774276` | コンテンツ 3 | 各エントリは同一の `profiles`, `profileGroups`, `challenges` を含むが、`viewableId` のみ異なる。`common.challenge` で共通のチャレンジを 1 つ指定し、`params[].challenges.primary` で viewableId ごとの個別チャレンジも指定する構造。 --- ## 7. 画質制御パラメータ | パラメータ | 値 | 画質への影響 | |---|---|---| | `profiles` | (上記一覧) | **対応コーデック/画質の上限**。サーバーはこの一覧に基づいてストリームを返す | | `cellularCap` | `"auto"` | セルラー回線時の帯域上限。`auto` = アダプティブ | | `netType` | `"wifi"` / `"cellular"` | ネットワーク種別。wifi 時は帯域制限が緩和される | | `hardware` | `"lito"` | SoC 名。サーバー側でハードウェアデコード能力を判定 | | `prefersVerticalVideo` | `false` | 縦動画優先 | | `licenseType` | `"limited"` / `"standard"` | `limited` = プリフェッチ (制限付き), `standard` = 本再生 | ### L1 vs L3 の画質差 | 項目 | L1 (TEE) | L3 (ソフトウェア) | |---|---|---| | 最大解像度 | FHD (1920x1080) 以上 | SD (~720x480) | | HEVC HDR10 | 利用可能 | 利用不可 | | VP9 最大 Level | L40 | L30 | | H.264 最大 Level | HPL40 (FHD) | HPL30 (SD) | | Dolby Audio | 利用可能 (推定) | 利用不可 | --- ## 8. レスポンス ### 8.1 取得状況 | 方法 | 状態 | |---|---| | `BaseHandler.processRequest` (直接取得) | **失敗** — `response: null` (ProGuard フィールド名不一致) | | `WidevineCryptoContext.decrypt` (L3) | **復元済み** — CBOR (key 62) → GZIP → JSON で完全復元 | | `WidevineCryptoContext.decrypt` (L1) | **不可** — TEE 内で処理されるため | ### 8.2 レスポンス構造 (実データ) L3 Widevine decrypt → CBOR → GZIP 展開で復元。8 チャンク、合計 456KB。 ```json { "id": 1, "version": 2, "serverTime": 1773373149628, "result": [ { "movieId": "81756595", "packageId": "2596051", "duration": 8523000, "drmContextId": "2596051", "playbackContextId": "E3-Bgj5tevc...", "video_tracks": [{ "..." }], "audio_tracks": [{ "..." }], "timedtexttracks": [{ "..." }], "servers": [{ "..." }], "links": { "events": {}, "ldl": {}, "license": {} } } ] } ``` > **バッチ**: `result` は配列。リクエストの `params` に含まれる viewableId ごとに 1 エントリ。キャプチャでは 3 件。 ### 8.3 result エントリ詳細 | フィールド | 型 | 値 (例) | 説明 | |---|---|---|---| | `movieId` | string | `"81756595"` | コンテンツ ID | | `packageId` | string | `"2596051"` | DRM パッケージ ID (`drmContextId` と対応) | | `duration` | number | `8523000` | 再生時間 (ms)。8523 秒 = 2h22m3s | | `drmContextId` | string | `"2596051"` | DRM コンテキスト ID | | `playbackContextId` | string | `"E3-Bgj5tevc..."` | 再生セッション ID (後続 API URL に埋め込み) | ### 8.4 video_tracks ```json { "trackType": "PRIMARY", "new_track_id": "V:2:1;2;;primary;-1;none;-1;", "dimensionsLabel": "2D", "streams": [ { "content_profile": "playready-h264hpl30-dash", "bitrate": 1050, "peakBitrate": 2250, "res_w": 960, "res_h": 540, "framerate_value": 24000, "framerate_scale": 1001, "size": 1181780966, "downloadable_id": "1496730611", "vmaf": 87, "isDrm": true, "urls": [ {"cdn_id": 140368, "url": "https://ipv4-c062-osa001-ix.1.oca.nflxvideo.net/?o=1&v=23&e=..."}, {"cdn_id": 140566, "url": "https://ipv4-c010-osa003-ix.1.oca.nflxvideo.net/?o=1&v=18&e=..."} ], "moov": {"offset": 108, "size": 1048}, "sidx": {"offset": 1156, "size": 37036} } ] } ``` L3 環境での映像ストリーム一覧: | content_profile | bitrate (kbps) | 解像度 | vmaf | isDrm | |---|---|---|---|---| | `playready-h264hpl22-dash` | 80 | 480x270 | 32 | true | | `playready-h264hpl22-dash` | 100 | 480x270 | 39 | true | | `playready-h264hpl30-dash` | 200 | 608x342 | 52 | true | | `playready-h264hpl30-dash` | 350 | 608x342 | 64 | true | | `playready-h264hpl30-dash` | 560 | 768x432 | 74 | true | | `playready-h264hpl30-dash` | 750 | 768x432 | 79 | true | | `playready-h264hpl30-dash` | 1050 | 960x540 | 87 | true | > **L3 制限**: 最大解像度 960x540 (SD)。L1 環境では 1920x1080 以上、HEVC HDR10 プロファイルも含まれる。 ### 8.5 audio_tracks ```json { "trackType": "PRIMARY", "channels": "2.0", "language": "ja", "languageDescription": "Japanese [Original]", "profile": "xheaac-dash", "bitrates": [32, 64, 96, 192], "streams": [ { "content_profile": "xheaac-dash", "bitrate": 192, "size": 216960714, "downloadable_id": "1758195596", "channels": "2.0", "isDrm": false, "tags": ["SpeakerSpatialAudio"] } ] } ``` | 言語 | プロファイル | ビットレート (kbps) | チャンネル | |---|---|---|---| | ja (Original) | xheaac-dash, heaac-2-dash | 32, 64, 96, 192 | 2.0 | | en | xheaac-dash, heaac-2-dash | 32, 64, 96, 192 | 2.0 | | pt-BR, es, es-ES, fr, de, it, pl, fil, hu | 同上 | 同上 | 2.0 | 合計 19 トラック (11 言語 × xheaac-dash / heaac-2-dash、一部言語は片方のみ)。 ### 8.6 timedtexttracks (字幕) ```json { "trackType": "PRIMARY", "rawTrackType": "subtitles", "language": "en", "languageDescription": "Off", "downloadableIds": {"imsc1.1": "945969240"}, "ttDownloadables": { "imsc1.1": { "size": 16270, "hashValue": "6uq3FARi9emju1mN/qygW1nd/fg=", "hashAlgo": "sha1", "urls": [ {"cdn_id": 140368, "url": "https://ipv4-c062-osa001-ix.1.oca.nflxvideo.net/?o=1&v=23&e=..."} ], "isImage": false } }, "isForcedNarrative": true } ``` 合計 57 トラック。フォーマットは全て `imsc1.1`。言語: en, ja, de, es, es-ES, fr, fil, hu, it, pl, pt-BR。 種別: subtitles, closedcaptions。 ### 8.7 servers (CDN) ```json { "id": 140368, "key": "1-17676-high", "name": "c062.osa001.ix.nflxvideo.net", "rank": 1, "type": "OPEN_CONNECT_APPLIANCE", "lowgrade": false, "dns": { "host": "ipv4-c062-osa001-ix.1.oca.nflxvideo.net", "ipv4": "45.57.82.139", "ipv6": null, "forceLookup": false } } ``` | rank | サーバー名 | IPv4 | ロケーション | |---|---|---|---| | 1 | c062.osa001.ix.nflxvideo.net | 45.57.82.139 | 大阪 (osa001) | | 2 | c010.osa003.ix.nflxvideo.net | 23.246.52.11 | 大阪 (osa003) | | 3 | c106.osa001.ix.nflxvideo.net | 45.57.84.3 | 大阪 (osa001) | 全て `OPEN_CONNECT_APPLIANCE` タイプ。`rank` でフェイルオーバー優先度を指定。 ### 8.8 links ```json { "events": { "href": "/events?playbackContextId=E3-Bgj5tevc...&esn=NFANDROID1-PRV-P-L3-GOOGLPIXEL%3D4A%3D%3D5G%3D-22594-...", "rel": "events" }, "ldl": { "href": "/license?licenseType=limited&playbackContextId=...&esn=...&drmContextId=2596051", "rel": "license" }, "license": { "href": "/license?licenseType=standard&playbackContextId=...&esn=...&drmContextId=2596051", "rel": "license" } } ``` | リンク | 用途 | 説明 | |---|---|---| | `events` | 再生イベント報告 | `playbackContextId` + `esn` を含む。keepAlive 等 | | `ldl` | Limited Duration License | ビットレート変更時等の追加ライセンス取得 | | `license` | Standard License | 再生開始時の本ライセンス取得 | > **ESN に L3 マーカー**: `esn` パラメータに `L3` が含まれる (`NFANDROID1-PRV-P-L3-...`)。L1 環境では `L1` になる。 --- ## 9. /license リクエスト (再生開始時) PRE_FETCH 後、実際の再生開始時に `standard` ライセンスを個別に取得する。 ### リクエスト URL ``` https://android14.prod.ftl.netflix.com/nq/androidui/samurai/~9.0.0/api ?licenseType=standard &playbackContextId= &esn=NFANDROID1-PRV-P-GOOGLPIXEL%3D4A%3D%3D5G%3D-{userId}-{fingerprint} &drmContextId=2596051 ``` ### パラメータ | パラメータ | 値 | 説明 | |---|---|---| | `licenseType` | `"standard"` | 本再生用ライセンス | | `playbackContextId` | JWT-like トークン | PRE_FETCH で取得した再生コンテキスト | | `esn` | `NFANDROID1-PRV-P-...` | デバイス ESN | | `drmContextId` | `2596051` | DRM コンテキスト ID | | `challengeBase64` | Widevine CDM protobuf (~4KB) | ライセンスチャレンジ | | `xid` | `"7616568730841682443"` | リクエストトレーシング ID | --- ## 10. プロファイル名の命名規則 ``` {drm}-{codec}{profile}{level}-{container}[-{encryption}][-{variant}] ``` ```mermaid %%{init: {'theme': 'dark'}}%% flowchart LR subgraph "プロファイル名の構造" A["playready"] --- B["h264"] --- C["hpl30"] --- D["dash"] end A2["DRM
playready / none"] -.-> A B2["コーデック
h264 / hevc / vp9"] -.-> B C2["プロファイル+レベル
mpl (Main) / hpl (High)
profile0 (VP9)"] -.-> C D2["コンテナ
dash (MPEG-DASH)"] -.-> D ``` | 略称 | 意味 | |---|---| | `hpl` | High Profile Level (H.264) | | `mpl` | Main Profile Level (H.264) | | `profile0` | Profile 0 (VP9, 8bit) | | `hdr-main10` | Main 10 Profile (HEVC, 10bit HDR) | | `L21`〜`L41` | コーデックレベル (解像度・ビットレート上限) | | `dash` | MPEG-DASH コンテナ | | `cenc` | Common Encryption (ISO 23001-7) | | `playready` | Microsoft PlayReady DRM | | `none` | DRM なし | | `live` | ライブストリーミング | --- ## 11. 画質を変更するには profiles 配列の内容を変更することで、サーバーから返されるストリームの種類が変わる。 | やりたいこと | profiles の変更 | |---|---| | H.264 のみにする | `vp9-*`, `hevc-*` プロファイルを全て削除 | | VP9 のみにする | `*h264*`, `hevc-*` プロファイルを全て削除 | | 最低画質に制限 | `none-h264mpl30-dash` + `heaac-2-dash` のみ残す | | xHE-AAC を無効化 | `xheaac-dash` を削除 | | 字幕を除外 | `imsc1.1` を削除 | | サムネイルを除外 | `BIF320` を削除 | > **注意**: profiles を書き換えるには `apiRequest` フック内で `params` オブジェクトの profiles 配列を操作する必要がある。MSL 暗号化前のアプリ層で介入する。 --- ## 12. iOS 版との比較 | 項目 | iOS (`/manifest`) | Android (`/licensedManifest`) | |---|---|---| | **API パス** | `/manifest` + `/license` (分離) | `/licensedManifest` (統合) | | **バッチ** | 1 viewableId/リクエスト | 複数 viewableId/リクエスト | | **DRM** | `fairplay` (SPC/CKC) | `widevine` (CDM protobuf) | | **チャレンジ** | 個別の `challengeBase64` | `common.challenge` + 個別 `challenges.primary` | | **映像コーデック** | H.264, HEVC Main 10 | H.264, VP9, HEVC HDR10 (L1 のみ) | | **音声コーデック** | HE-AAC, DD 5.1, DD+ 5.1, Atmos | HE-AAC, xHE-AAC | | **字幕** | WebVTT (LSSDH) | IMSC 1.1 | | **サムネイル** | BIF240, BIF320 | BIF320 | | **プロファイルグループ** | `live`, `ce3`, `ce4` (3グループ) | `primary` (単一グループ) | | **画質ターゲット** | `desiredVmaf: "phone_plus_lts"` | なし (profiles のみ) | | **ライブメタデータ** | `"HLS"` | `"INDEXED_SEGMENT_TEMPLATE"` | | **再生グラフ** | `["start"]` | `["v2"]` | | **広告対応** | `supportsAdBreakHydration` | `liveAdsCapability: "dynamic"` + `adCanvasUICapabilities` | | **レスポンス** | 未取得 | L3: decrypt 経由で **復元済み** (456KB) |