Overview
This is a memo on how to add a table of contents to videos using iiif-prezi3.
Segment Detection
We use Amazon Rekognition's video segment detection.
保存されたビデオ内のビデオセグメントの検出 - Amazon Rekognition
保存されたビデオでの Amazon Rekognition ビデオセグメント検出の概要。
Sample code is available at the following link.
例: 保存されたビデオ内のセグメントの検出 - Amazon Rekognition
以下の手順は、Amazon S3 バケットに保存されているビデオ内のテクニカルキューセグメントとショット検出セグメントを検出する方法を示しています。この手順では、Amazon Rekognition Video が持つ検出精度に対する信頼度に基づいて、検出されたセグメントをフィルタリングする方法も示します。
Data Used
We use "Prefectural News Volume 1" (Nagano Prefectural Library).
県政ニュース 第1巻
昭和30年に長野県が制作した記録映像。次の8タイトルを収録する。
「地方選挙終る」、「地方選挙後初の県議会開かる」、「三十年度を賄う県のお台所」、「すすむ土木建設」、「明るく正しく健やかに」、「幕をとじた善光寺の御開帳」、「勇ましい水防訓練」、「お国じまん民謡大会」
Reflecting in the Manifest File
We assume that a manifest file has already been created by referring to the following article.

Creating IIIF v3 Manifests for Video Using iiif-prezi3
Creating IIIF v3 Manifests for Video Using iiif-prezi3
The following script adds a VTT file to the manifest file.
from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config, HomepageItem, KeyValueString
#| export
class IiifClient:
def load_manifest(self, manifest_path):
with open(manifest_path, "r") as f:
manifest_json = json.load(f)
manifest = Manifest(**manifest_json)
return manifest
def add_segment(self, manifest_path):
manifest = self.load_manifest(manifest_path)
path = f"{self.input_dir}/output_segment.json"
with open(path, "r") as f:
data = json.load(f)
range_id = f"{self.prefix}/range"
range_toc = manifest.make_range(
id=f"{range_id}/r",
label="Table of Contents"
)
canvas_id = manifest.items[0].id
for s in data["Segments"]:
s_type = s["Type"]
if s_type != "SHOT":
continue
index = s["Shot Index"]
start = s["Start Timestamp (milliseconds)"] / 1000
end = s["End Timestamp (milliseconds)"] / 1000
range_seg = range_toc.make_range(
id=f"{range_id}/r{index}",
label=f"Segment {index}",
)
range_seg.items.append({
"id": f"{canvas_id}#t={start},{end}",
"type": "Canvas"
})
output_path = f"{self.input_dir}/manifest_segment.json"
with open(output_path, "w") as f:
f.write(manifest.json(indent=2))
return output_path
A manifest file like the following is created.
d1u7hq8ziluwl9.cloudfront.net
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/manifest.json",
"type": "Manifest",
"label": {
"ja": [
"県政ニュース 第1巻"
]
},
"requiredStatement": {
"label": {
"ja": [
"Attribution"
]
},
"value": {
"ja": [
"『県政ニュース 第1巻』(県立長野図書館)を改変"
]
}
},
"homepage": [
{
"id": "https://www.ro-da.jp/shinshu-dcommons/library/02FT0102974177",
"type": "Text",
"label": {
"ja": [
"信州デジタルコモンズ 県立長野図書館所蔵資料"
]
}
},
{
"id": "https://jpsearch.go.jp/item/sdcommons_npl-02FT0102974177",
"type": "Text",
"label": {
"ja": [
"ジャパンサーチ"
]
}
}
],
"items": [
...
],
"structures": [
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/range/r",
"type": "Range",
"label": {
"ja": [
"Table of Contents"
]
},
"items": [
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/range/r0",
"type": "Range",
"label": {
"ja": [
"Segment 0"
]
},
"items": [
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/canvas#t=0.0,5.338",
"type": "Canvas"
}
]
},
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/range/r1",
"type": "Range",
"label": {
"ja": [
"Segment 1"
]
},
"items": [
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/canvas#t=5.372,6.74",
"type": "Canvas"
}
]
},
...
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/range/r151",
"type": "Range",
"label": {
"ja": [
"Segment 151"
]
},
"items": [
{
"id": "https://d1u7hq8ziluwl9.cloudfront.net/sdcommons_npl-02FT0102974177/canvas#t=618.651,619.586",
"type": "Canvas"
}
]
}
]
}
]
}
Viewer Display Example
An example of the display in a viewer is shown below. Theseus Viewer is used.
Theseus Viewer

Summary
I hope this serves as a helpful reference for adding table of contents to video files using IIIF.



Comments
…