stream-to-youtube-english
授權方式(Auhorization): CC-BY 4.0
Pre
You need have a google api-key from google developer console
- create project: fill project name and id
- API auth: find youtube data api and set status to ON
- Credentials: create Client ID for web application get your Client ID and Client Secret !! Attention: youtube live streaming api do not support service account flow, because it needs to access user account.
APIs Explorer
it's the google api playground!
https://developers.google.com/apis-explorer/
- youtube Data API: find youtube.liveBroadcasts.insert
- set OAuth request to ON
- part: snippet,status
- request body: add property -> status,snippet
All required above , NOTE: time format is ISO-8601: YYYY-MM-DDThh:mm:ss.sZrequest body { "snippet": { "scheduledEndTime": "2014-04-16T20:00:00.0+08", "scheduledStartTime": "2014-04-16T18:00:00.0+08", "title": "hero g0v" }, "status": { "privacyStatus": "private" } }
Nodejs
its official api client
source code
if you are familiar with nodejs, you can directly use npm install googleapis
Workflow
- Get authorization code by Oauth2
- Get access-token by authorization code
- Access youtube by access-token
- Open a youtube live broadcast by 5 steps below
- Set up your broadcast
- create broadcast
- create stream
- bind broadcast and stream
- Claim your content # You need to get Youtube Content API
- Test (Preview)
- liveStreams.list use stream id from step 1.3 when stream status is 'active'
- livebroadcasts.transition to 'testing'
- Broadcast
- livebroadcasts.transition tto 'live' when broadcast status is 'testStarting'
- Conclude your broadcast done! get your youtube stream url by broadcast id from step 1.1
- Set up your broadcast
Other Details here Life of a broadcast
Create Broadcast
require parameters
part: 'snippet, status'
snippet: { title, scheduledStartTime, scheduledEndTime }
status: { privacyStatus }
request exmaple
{
"part": "snippet,status",
"snippet": {
"title": "Example Broadcast",
"scheduledStartTime": "2014-04-18T05:00:00.00s+08:00",
"scheduledEndTime": "2014-04-18T15:00:00.00s+08:00"
},
"status": {
"privacyStatus": "private"
}
}
code exmaple
err, broadcast <- client.youtube.live-broadcasts.insert part: 'snippet,status', req-broadcast
.with-auth-client auth
.execute
return console.log err if err
console.log broadcast
response example
{ kind: 'youtube#liveBroadcast',
etag: '"X98aQHqGvPBJLZLOiSGUHCM9jnE/2kEP-c4VUkPHY301QBKEBcJJRMA"',
id: 'v-MKk0Z3HB4',
snippet:
{ publishedAt: '2014-04-16T05:23:58.000Z',
channelId: 'UCWDNcRqKYS8PjGn2Z7RUocg',
title: 'test',
description: '',
thumbnails: { default: [Object], medium: [Object], high: [Object] },
scheduledStartTime: '2014-05-16T21:00:00.000Z',
scheduledEndTime: '2014-05-17T00:00:00.000Z' },
status:
{ lifeCycleStatus: 'created',
privacyStatus: 'private',
recordingStatus: 'notRecording' } }
You can see a new evenet here youtube live event
Create Stream
required parameters
part: 'snippet, cdn'
snippet: { title}
cdn: {format, ingestionType}
request example
{
"part": "snippet,cdn",
"snippet": {
"title": "Example Stream"
},
"cdn": {
"format: "240p",
"ingestionType": "rtmp"
}
}
code example
err, stream <- client.youtube.live-streams.insert part: 'snippet,cdn', req-stream
.with-auth-client auth
.execute
return console.log err if err
console.log stream
response example
{
"kind": "youtube#liveStream",
"etag": "\"X98aQHqGvPBJLZLOiSGUHCM9jnE/F8dDAvNbcjro8PFQe4H82hilSmQ\"",
"id": "WDNcRqKYS8PjGn2Z7RUocg1397629864085436",
"snippet": {
"publishedAt": "2014-04-16T06:31:04.000Z",
"channelId": "UCWDNcRqKYS8PjGn2Z7RUocg",
"title": "test g0v",
"description": ""
},
"cdn": {
"format": "720p",
"ingestionType": "rtmp",
"ingestionInfo": {
"streamName": "ly.forever.rkx0-bwp3-7fy0-9ykd",
"ingestionAddress": "rtmp://a.rtmp.youtube.com/live2",
"backupIngestionAddress": "rtmp://b.rtmp.youtube.com/live2?backup=1"
}
}
}
Bind stream
required parameters
part: 'id,contentDetails'
id: { broadcast-id }
streamId: { stream-id }
request example
{
"part": "id,contentDetails",
"id": "v-MKk0Z3HB4",
"streamId": "WDNcRqKYS8PjGn2Z7RUocg1397629864085436"
}
code example
err, bind <- client.youtube.live-broadcasts.bind part: 'id,contentDetails', id: video-id, stream-id: stream-id
.with-auth-client auth
.execute
console.log bind
response example
{
"kind": "youtube#liveBroadcast",
"etag": "\"X98aQHqGvPBJLZLOiSGUHCM9jnE/B5DR-1fKyXag5mlIwZ6Tqc9-ysk\"",
"id": "v-MKk0Z3HB4"
}
Use ffmpeg stream to youtube rtmp
we can get a streaming settings from step 1.2, you will get streamName and ingestionAddress,
combine them to be a STREAM-URL.
so from example we can use this cmd to stream video from sky news to youtube.
$ ffmpeg -i rtmp://cp49989.live.edgefcs.net:1935/live/streamRM1@2564 -vcodec libx264 -maxrate 700k -r 30 -s 426x240 -g 0 -acodec libvo_aacenc -ab 128k -ac 1 -ar 44100 -f flv rtmp://SREAM-URL
that we have a elegant api in nodejs is fluent-ffmpeg
code example
new fluent-ffmpeg source: 'rtmp://cp49989.live.edgefcs.net:1935/live/streamRM1@2564'
.with-video-codec 'libx264'
.with-audio-codec 'libfaac'
.with-audio-bitrate '128k'
.with-audio-channels 1
.with-audio-frequency 44100
.with-size '426x240'
.with-fps 30
.to-format 'flv'
.add-options ['-g 1', '-force_key_frames 2']
.on 'start' -> console.log 'FFmpeg start with ' + it
.on 'progress' ->
err, streams <- client.youtube.live-streams.list part: 'id,status', id: stream-id
.with-auth-client auth
.execute
err, test <- transit-it auth, client, 'testing'
err, live <- transit-it auth, client, 'live'
console.log live.status if live
.on 'end' -> console.log 'FFmpeg end.'
.write-to-stream stream-url
Test
err, it <- client.youtube.live-broadcasts.transition broadcast-status: 'testing', id: video-id, part: 'id,status,contentDetails'
.with-auth-client auth
.execute
consoel.log it
Broadcast
err, it <- client.youtube.live-broadcasts.transition broadcast-status: 'live', id: video-id, part: 'id,status,contentDetails'
.with-auth-client auth
.execute
consoel.log it
Conclusion
- google document is useful but still easy get lost in lots of pages.
- nodejs sample code is on github googleapis example
- through this, I get a tip to retrieve needed info from google api document!