Slide 1

Slide 1 text

Leveraging Open Source to Create Virtual Live Channels from On-Demand Video July, 2020

Slide 2

Slide 2 text

@flavioribeiro /in/flavioribeiro /flavioribeiro Flavio Ribeiro Director of Engineering, Video Technology Group ViacomCBS Digital

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

AGENDA ● Why? ● How?

Slide 8

Slide 8 text

WHY? ● recycle on-demand catalog ● possible new revenue streams ● pop-up channels ● personalized channels ● cheap "rundown/playout" alternative ● cheap (no encoding) streaming alternative

Slide 9

Slide 9 text

ON THE FLY PACKAGING from https://open.nytimes.com/improving-our-video-experience-part-one-our-on-demand-video-platform-cf818e03353d

Slide 10

Slide 10 text

OUR DEPLOYMENT

Slide 11

Slide 11 text

OUR DEPLOYMENT

Slide 12

Slide 12 text

Goofy is a R&D Project For Virtual 24/7 Linear Channels from VoD Assets

Slide 13

Slide 13 text

Architecture AWS S3 Scheduler Playout MP4 MP4 MP4 Google Cloud Storage MP4 MP4 MP4 File Streamer https://github.com/nytimes/gcs-helper https://github.com/crunchyroll/evs-s3helper

Slide 14

Slide 14 text

SCHEDULER ● REST API ● Mediainfo ○ calculate asset duration ● detect overlap/content collision

Slide 15

Slide 15 text

SCHEDULER $ http POST http://scheduler <<< ' { "title": "STAR TREK SEASON 01 EP 01", "airing_time_start": "2020-07-01T18:14:52Z", "renditions": [ { "label": "720p", "url": "http://gcs-helper:2000/proxy/STARTREK_S01E01_720p.mp4" }, { "label": "540p", "url": "http://gcs-helper:2000/proxy/STARTREK_S01E01_540p.mp4" }, { "label": "360p", "url": "http://gcs-helper:2000/proxy/STARTREK_S01E01_360p.mp4" }, ]

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

PLAYOUT ● fetch & display "rolling window" of scheduled content ● format JSON payload expected by the NGINX VOD Module

Slide 18

Slide 18 text

PLAYOUT $ http GET http://playout { "clipSegments": [305, 305], "durations": [3045000, 3049000], "clipTimes": [ 1593174206000, 1593618600000, ], "currentTime": 1593618583000, "discontinuity": true, "initialClipIndex": 890, "initialSegmentIndex": 84913, "playlistType": "live", "sequences": [ { "clips": [ {"path": "/proxy/STARTREK_S01E01_720p.mp4", "type": "source"}, {"path": "/proxy/STARTREK_S01E02_720p.mp4", "type": "source"} ], "language": "eng" }, { "clips": [ {"path": "/proxy/STARTREK_S01E01_640p.mp4", "type": "source"}, {"path": "/proxy/STARTREK_S01E02_640p.mp4", "type": "source"} ], "language": "eng" } ] }

Slide 19

Slide 19 text

PLAYOUT $ http GET http://playout { "clipSegments": [305, 305], "durations": [3045000, 3049000], "clipTimes": [ 1593174206000, 1593618600000, ], "currentTime": 1593618583000, "discontinuity": true, "initialClipIndex": 890, "initialSegmentIndex": 84913, "playlistType": "live", "sequences": [ { "clips": [ {"path": "/proxy/STARTREK_S01E01_720p.mp4", "type": "source"}, {"path": "/proxy/STARTREK_S01E02_720p.mp4", "type": "source"} ], "language": "eng" }, { "clips": [ {"path": "/proxy/STARTREK_S01E01_640p.mp4", "type": "source"}, {"path": "/proxy/STARTREK_S01E02_640p.mp4", "type": "source"} ], "language": "eng" } ] } from scheduler airing time since epoch # of clips in the past (+1) # of segments in the past sum(clip durations) / segment length

Slide 20

Slide 20 text

NGINX http { vod_mode mapped; vod_upstream_location /goofy-playout-map; vod_hls_segment_file_name_prefix "segment"; vod_segment_duration 10000; vod_align_segments_to_key_frames on; vod_live_window_duration 60000; upstream goofy-playout { server playout:2828; } server { listen 80; server_name localhost; location /goofy-playout-map { rewrite ^/goofy-playout-map/h/(.*)$ /$2 break; proxy_pass http://goofy-playout; proxy_http_version 1.1; proxy_set_header Connection ""; } location /h { vod hls; add_header Access-Control-Allow-Headers '*'; add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS'; add_header Access-Control-Allow-Origin '*'; } }

Slide 21

Slide 21 text

NGINX http { vod_mode mapped; vod_upstream_location /goofy-playout-map; vod_hls_segment_file_name_prefix "segment"; vod_segment_duration 10000; vod_align_segments_to_key_frames on; vod_live_window_duration 60000; upstream goofy-playout { server playout:2828; } server { listen 80; server_name localhost; location /goofy-playout-map { rewrite ^/goofy-playout-map/h/(.*)$ /$2 break; proxy_pass http://goofy-playout; proxy_http_version 1.1; proxy_set_header Connection ""; } location /h { vod hls; add_header Access-Control-Allow-Headers '*'; add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS'; add_header Access-Control-Allow-Origin '*'; } } point vod module to the playout service Initiate vod module in mapped mode create a location for the hls delivery

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

FUTURE ● UI/CMS for linear "programming"

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

FUTURE ● UI/CMS for linear "programming" ● ads support (via scte-35 manifest decoration)

Slide 26

Slide 26 text

FUTURE ● UI/CMS for linear "programming" ● ads support (via scte-35 manifest decoration) ● support for mixed "real" live and virtual live

Slide 27

Slide 27 text

FUTURE ● UI/CMS for linear "programming" ● ads support (via scte-35 manifest decoration) ● support for mixed "real" live and virtual live ● support for personalized slots on the linear feed ● DASH (variant bitrates on the VOD library)

Slide 28

Slide 28 text

Thanks!