24_提供 JavaScript 对象表示法 (JSON) 章节

为 HTTP 实时流式处理准备 JSON 章节。

概述

内容提供商使用 HTTP 实时流 (HLS) 多变量播放列表中的 EXT-X-SESSION-DATA 标记提供章节标记和其他每章元数据。Apple 的 iOS、tvOS 和 macOS 平台以 JSON 形式接收此元数据,这是一种使用人类可读文本来定义 RFC 7159 中描述的数据对象的格式。

注意

本文仅供参考。Apple 可能拥有涵盖本文档中主题的专利、专利申请、商标、版权或其他知识产权。本文的提供并不授予我们任何专利、商标、版权或其他知识产权的许可。

组织章节元数据

章节数据是使用四种不同类型描述章节的信息:计时、标题、图像和常规元数据。设计章节数据时,请记住以下几点:

章节元数据显示为章节数组。数组中的每个元素都包含有关该章节的信息。第一个数组元素描述第一章,第二个元素描述第二章,依此类推。

章节数组中的每个元素都是一个称为章节条目的 JSON 对象。章节条目必须包含开始时间。章节条目应包含标题、图像和可能的元数据。

章节条目可能包含名为 Chapter 的项目,以提高 JSON 的人类可读性。它还可能包含名为持续时间的项目。除非指定持续时间,否则假定章节条目具有从开始时间到下一章条目的开始时间的持续时间。章节计时可以重叠和嵌套,在这种情况下,必须同时存在开始时间和持续时间。

下面是格式化为 JSON 的章节数据的简单三章示例。仅显示章节标题和开始时间。每个章节标题都有两种不同的语言:英语和西班牙语。

[
    {
        "chapter": 1,
        "start-time": 0,
        "titles": [
            {
                "language": "en",
                "title": "birth"
            },
            {
                "language": "es",
                "title": "nacimiento"
            }
        ]
    },
    {
        "chapter": 2,
        "start-time": 500.1,
        "titles": [
            {
                "language": "en",
                "title": "life"
            },
            {
                "language": "es",
                "title": "vida"
            }
        ]
    },
    {
        "chapter": 3,
        "start-time": 1200.2,
        "titles": [
            {
                "language": "en",
                "title": "death"
            },
            {
                "language": "es",
                "title": "muerte"
            }
        ]
    }
]

下面是 JSON 章节数据格式的一般布局。JavaScript 注释不是合法的 JSON,仅用于说明目的。

[
    {
        "chapter": number,
        "start-time": number,
        "duration": number,
        "titles": [
            {
                "language": string,
                "title": string
            },
            // … (for each language for this chapter)
        ],
        "images": [
            {
                "image-category": string,
                "pixel-width": number,
                "pixel-height": number,
                "url": string
            },
            // … (for each image type for this chapter)
        ],
        "metadata": [
            {
                "key": string,
                "value": object | number | string | array,
                "language": string,
            },
            // … for each metadata value for this chapter
        ],
    },
    // … for each chapter
]

添加标题

章节条目可能包含标题 JSON 数组。标题数组的每个元素都是一个 JSON 对象,该对象必须同时包含语言 BCP 47 字符串和标题字符串,其中包含该章的标题,以语言字符串指定的语言编写。所有字符串都必须使用 UTF-8 进行编码。如果标题字符串(如数字字符串)与语言无关,请将语言设置为“und”。

添加图像

章节条目可能包含图像 JSON 数组。图像数组的每个元素都是一个 JSON 对象,其中包含有关每章图像的信息。例如,图像数组可能包含缩略图图像的元素和高清图像的元素。

图像数组中的每个元素都必须包含一个图像类别字符串、一个像素宽度数字、一个像素高度数字和一个 url 字符串。

对于相似的图像,图像类别字符串在章节中应相同。在上面提到的三章案例中,我们将对缩略图(缩略图)使用一个字符串,对高清图像 (hd) 使用另一个字符串。

url 字符串必须是与章节关联的图像数据的绝对或相对 URL。相对 URL 相对于包含 JSON 章节文档的路径。

图像文件本身可能采用多种图像格式。例如,JPEG、PNG 和 TIFF 都受支持。

添加元数据

章节条目还可能包含元数据 JSON 数组。元数据数组的每个元素都是一个 JSON 对象,其中包含该章的元数据。每个元数据数组元素都包含一个必需的键和值,以及一个可选语言 BCP-47 字符串。键元素必须是字符串。value 元素可以是字符串、数字、数组或对象。如果任何值是 URI,则按原样传递。系统无法在该上下文中解释相对 URI。

指定主播放列表

JSON 格式的章节数据必须在主播放列表中使用 EXT-X-SESSION-DATA 标记指定,才能在 HTTP 实时流式传输中使用。

EXT-X-SESSION-DATA 的 DATA-ID 属性必须是 com.apple.hls.chapters。URI 属性必须指向 JSON 格式的章节数据。URI 可以是绝对的,也可以是相对于包含主播放列表的路径的,如下所示:

#EXT-X-SESSION-DATA:DATA-ID=“com.apple.hls.chapters”,URI=“http://meta.example.com/movie403/chapters.json”

执行验证

使用以下 JSON 架构来验证章节数据。

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "HLS Chapter Data",
    "description": "HLS chapter data format",
    "type": "array",
    "items": {
        "description": "chapter entry",
        "type": "object",
        "properties": {
            "chapter": {
                "description": "Chapter number (optional)",
                "type": "number",
                "minimum": 1
            },
            "start-time": {
                "description": "Chapter start time",
                "type": "number",
                "minimum": 0
            },
            "duration": {
                "description": "Chapter duration (optional)",
                "type": "number",
                "minimum": 0,
                "exclusiveMinimum": true
            },
            "titles": {
                "description": "List of titles by language for chapter (optional)",
                "type": "array",
                "items": {
                    "description": "Title object",
                    "type": "object",
                    "properties": {
                        "language": {
                            "description": "BCP 47 language code; und for undefined",
                            "type": "string"
                        },
                        "title": {
                            "description": "Chapter title string",
                            "type": "string"
                        }
                    },
                    "required": ["language", "title"]
                }
            },
            "images": {
                "description": "List of images for chapter (optional)",
                "type": "array",
                "items": {
                    "description": "Image object",
                    "type": "object",
                    "properties": {
                        "image-category": {
                            "description": "Image category",
                            "type": "string"
                        },
                        "pixel-width": {
                            "description": "Pixel width",
                            "type": "integer",
                            "minimum": 0,
                            "exclusiveMinimum": true
                        },
                        "pixel-height": {
                            "description": "Pixel height",
                            "type": "integer",
                            "minimum": 0,
                            "exclusiveMinimum": true
                        },
                        "url": {
                            "description": "URL to image (relative or absolute)",
                            "type": "string"
                        }
                    },
                    "required": ["image-category", "pixel-width", "pixel-height", "url"]
                }
            },
            "metadata": {
                "description": "List of metadata entries for chapter (optional)",
                "type": "array",
                "items": {
                    "description": "Metadata object",
                    "type": "object",
                    "properties": {
                        "key": {
                            "description": "Key value name",
                            "type": "string"
                        },
                        "value": {
                            "description": "Metadata value",
                            "type": ["string", "number", "boolean", "array", "object"]
                        },
                        "language": {
                            "description": "BCP 47 language code (optional)",
                            "type": "string"
                        }
                    },
                    "required": ["key", "value"]
                }
            }
        },
        "required": ["start-time"]
    }
}

测试和访问章节数据

使用 QuickTime Player 使用章节数据快速测试 HLS 流。QuickTime Player 将显示章节弹出控件(带有图像,如果有的话)。在 QuickTime 播放器中,使用“文件>打开位置”或“⌘L ”打开 URL。QuickTime Player 按章节在 JSON 文件中出现的顺序显示章节,而不对章节进行排序或重新排列。

AVAsset 包含有关如何访问章节数据的详细信息。所描述的方法返回一个 AVTimedMetadataGroup 对象的数组,每章一个对象。组的顺序与 JSON 文件的顺序匹配。

每个 AVTimedMetadataGroup 对象都有一个开始时间、结束时间和一个 AVMetadataItem 列表。JSON 中的标题、图像和元数据数组中的每个项都位于元数据项列表中。

图像有一个额外的属性字典。此字典包含一个键“iTunesImageResolution”,其值是一个字典,其中包含 JSON 条目中的像素宽度、像素高度和图像类别。

元数据项键放置在密钥空间 AVMetadataKeySpaceQuickTimeMetadata。此密钥空间定义其要表示为反向 DNS 字符串的密钥值。这允许我们以既定的方式定义自己的密钥,以避免冲突。