如何将live stream发布到Youtube

来源:互联网 发布:老王python视频教程 编辑:程序博客网 时间:2024/04/30 13:07

1.搭建开发环境

  1. 申请Google账号
  2. 登录Google账号,进入创作者工作室。进入直播栏目,打开个人账户直播功能
  3. 进入google develop console 
    1. a. 创建新项目 
      b. 启用YouTube Data API v3 
      c. 创建凭据,Oauth 客户端 ID,选择网页客户端。输入名称,重定向URL,点击创建。完成以后就可以获取一个json文件。里面就有需要的secrete_id。保存该json文件,会放入Android 工程中。 
      d.如果完全没有使用过Youtube API可以下载youtube-api-samples。或者观看教学影片:YouTube Developers Live: Setting up your Java IDE for Google API samples

    2.获取用户授权

    (Java code,更加详细的授权,会在另一篇文章中呈现)

    a.需要导入准备工作中下载的client_secrets.json文件。里面有client_id和client_secret。调用GoobleOAuth.login函数即可获得OAuth2AccessToken;

    GoogleOAuth.login(VrSpherePreviewActivity.this).setClientId(clientSecrets.getDetails().getClientId()).setClientSecret(clientSecrets.getDetails().getClientSecret()).setAdditionalScopes("https://www.googleapis.com/auth/youtube").setRedirectUri("http://localhost:8080").setCallback(new OnLoginCallback()).init();

    获取token成功之后,我们就可以在OnLoginCallback()中得到OAuth2AccessToken token,其中包含token 和 fresh_token;

    b.调用 Auth.authorize(clientSecrets, token);来获取Credential相关数据。 
    c.最后,调用下面的程序就可以通过credential数据来授权youtube账户下的Channel和live相关的操作;

    youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential)        .setApplicationName("youtube-cmdline-createbroadcast-sample").build();

    3.建立LiveBroadCast频道

    它的作用是在直播活动中建立一个频道。有频道的名称、开始和结束时间、频道的状态等信息。频道建立好以后,可以通过YouTube.LiveBroadcasts.Insert插入频道的一些属性。比如我们代码中就插入了snippet,status,contentDetails三种属性:

    PropertyIntroductionsnippetThe snippet object contains basic details about the event, including its title, description, start time, and end time.statusThe status object contains information about the event’s status.contentDetailsThe contentDetails object contains information about the event’s video content, such as whether the content can be shown in an embedded video player or if it will be archived and therefore available for viewing after the event has concluded.

    具体的属性信息可以参考Youtube的官方文档,有详细的介绍:https://developers.google.com/youtube/v3/live/docs/liveBroadcasts。

    我们需要设定的一些属性:

    • snippet.title
    • snippet.actualStartTime
    • snippet.scheduledStartTime
    • snippet.scheduledEndTime
    • status.privacyStatus
    • contentDetails.projection

    设置完成之后,通过HTTP POST将请求发送给服务器。

    POST https://www.googleapis.com/youtube/v3/liveBroadcasts
    • 1

    HTTP:

    POST /youtube/v3/liveBroadcasts?part=id,snippet,status,contentDetails HTTP/1.1        Host: www.googleapis.com        Content-Type: application/json        Authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudddfJTg        Cache-Control: no-cache        Postman-Token: 29293451-38a3-306b-35ef-c652b4c1d3e7        {          "snippet": {            "title": "TestLiveCode",            "actualStartTime": "2017-01-19T06:14:40.000Z",            "scheduledStartTime": "2017-01-19T06:14:40.000Z",            "scheduledEndTime": "2017-01-19T20:14:40.000Z"          },          "status": {            "privacyStatus": "public"          },          "contentDetails": {            "projection": "360"          }      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    获得Response,得到LiveBroadCasts信息:

    {    "kind": "youtube#liveBroadcast",    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/RS5N6l3SydSyJtxvNL0Y1C1OYs4\"",    "id": "TgaR-sHrnjM",    "snippet": { "publishedAt": "2017-01-19T07:30:15.000Z", "channelId": "UCl75gUJzbdbrzNDWlu4nYkA", "title": "TestLiveCode", "description": "", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/TgaR-sHrnjM/default_live.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/TgaR-sHrnjM/mqdefault_live.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/TgaR-sHrnjM/hqdefault_live.jpg", "width": 480, "height": 360 } }, "scheduledStartTime": "2017-01-19T07:14:30.000Z", "scheduledEndTime": "2017-01-19T20:14:40.000Z", "isDefaultBroadcast": false, "liveChatId": "Cg0KC1RnYVItc0hybmpN" },    "status": { "lifeCycleStatus": "created", "privacyStatus": "public", "recordingStatus": "notRecording" },    "contentDetails": { "monitorStream": { "enableMonitorStream": true, "broadcastStreamDelayMs": 0, "embedHtml": "<iframe width=\"425\" height=\"344\" src=\"https://www.youtube.com/embed/TgaR-sHrnjM?autoplay=1&livemonitor=1\" frameborder=\"0\" allowfullscreen></iframe>" }, "enableEmbed": true, "enableDvr": true, "enableContentEncryption": false, "startWithSlate": false, "recordFromStart": true, "enableClosedCaptions": false, "closedCaptionsType": "closedCaptionsDisabled", "enableLowLatency": false, "projection": "360" } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Java

        // Create a snippet with the title and scheduled start and end    // times for the broadcast. Currently, those times are hard-coded.    LiveBroadcastSnippet broadcastSnippet = new LiveBroadcastSnippet();    broadcastSnippet.setTitle(title);    long time = System.currentTimeMillis();    broadcastSnippet.setPublishedAt(new DateTime(time));    broadcastSnippet.setScheduledStartTime(new DateTime(time));    broadcastSnippet.setScheduledEndTime(new DateTime(time+60*60*1000));    // Set the broadcast's privacy status to "private". See:    // https://developers.google.com/youtube/v3/live/docs/liveBroadcasts#status.privacyStatus    LiveBroadcastStatus status = new LiveBroadcastStatus();    status.setPrivacyStatus("public");    LiveBroadcast broadcast = new LiveBroadcast();    broadcast.setKind("youtube#liveBroadcast");    broadcast.setSnippet(broadcastSnippet);    broadcast.setStatus(status);    LiveBroadcastContentDetails contentDetails = new LiveBroadcastContentDetails();    contentDetails.setProjection("360");     broadcast.setContentDetails(contentDetails);    // Construct and execute the API request to insert the broadcast.    YouTube.LiveBroadcasts.Insert liveBroadcastInsert =            youtube.liveBroadcasts().insert("snippet,status,contentDetails", broadcast);    liveBroadcast = liveBroadcastInsert.execute();

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet%2Cstatus");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: 97d63c4d-8e5d-7c09-9de8-66b7db42c23b");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudnKfJTg");headers = curl_slist_append(headers, "content-type: application/json");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\n  \"snippet\": {\n    \"title\": \"TestLiveCode\",\n    \"actualStartTime\": \"2017-01-19T06:14:40.000Z\",\n    \"scheduledStartTime\": \"2017-01-19T06:14:40.000Z\",\n    \"scheduledEndTime\": \"2017-01-19T20:14:40.000Z\"\n  },\n  \"status\": {\n    \"privacyStatus\": \"public\"\n  },\n  \"contentDetails\": {\n    \"projection\": \"360\"\n  }\n}");CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.建立streaming通道

    建立频道的streaming通道。有了这个streaming通道,我们就可以通过该通道向频道发送直播视频。 
    需要设置一些streaming的属性:snippet,cdn ,status

    PropertyIntroductionsnippetThe snippet object contains basic details about the stream, including its channel, title, and descriptioncdnThe cdn object defines the live stream’s content delivery network (CDN) settings. These settings provide details about the manner in which you stream your content to YouTube.statusThe status object contains information about live stream’s status.

    具体的属性信息可以参考Youtube的官方文档,有详细的介绍:https://developers.google.com/youtube/v3/live/docs/liveStreams。

    我们需要设定的一些属性:

    • snippet.title
    • cdn.ingestionInfo.streamName
    • cdn.ingestionInfo.ingestionAddress
    • cdn.resolution
    • cdn.ingestionType
    • cdn.frameRate

    设置完成之后,通过HTTP POST将请求发送给服务器。

    POST https://www.googleapis.com/youtube/v3/liveStreams
    • 1

    HTTP

    POST //www.googleapis.com/youtube/v3/liveStreams?part=snippet,cdn HTTP/1.1Host: POST https:Content-Type: application/jsonAuthorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudnKfJTgCache-Control: no-cachePostman-Token: b3d3157d-9915-c084-2d43-85d9bdd74a88{ "snippet": { "title": "TestStream" }, "cdn": { "ingestionInfo": { "streamName": "MyTestStream", "ingestionAddress": "rtmp://a.rtmp.youtube.com/live2" }, "resolution": "720p", "ingestionType": "rtmp" "frameRate": "30fps" } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    获得Response,得到LiveStreams的信息

    {    "kind": "youtube#liveStream",    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/OsA5SrDlgCAfnSbwtDkNYyeBko0\"",    "id": "l75gUJzbdbrzNDWlu4nYkA1484811227264011",    "snippet": { "publishedAt": "2017-01-19T07:33:47.000Z", "channelId": "UCl75gUJzbdbrzNDWlu4nYkA", "title": "TestStream", "description": "", "isDefaultStream": false },    "cdn": { "format": "720p", "ingestionType": "rtmp", "ingestionInfo": { "streamName": "qhvu-315p-y3wr-5uf7", "ingestionAddress": "rtmp://a.rtmp.youtube.com/live2", "backupIngestionAddress": "rtmp://b.rtmp.youtube.com/live2?backup=1" }, "resolution": "720p", "frameRate": "30fps" } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    streamName + ingestionAddress 则是我们的推送地址:rtmp://a.rtmp.youtube.com/live2/qhvu-315p-y3wr-5uf7

    Java

    // Create a snippet with the video stream's title.LiveStreamSnippet streamSnippet = new LiveStreamSnippet();streamSnippet.setTitle(title);IngestionInfo ingestionInfo = new IngestionInfo();ingestionInfo.setStreamName("Education");//此Rtmp位址為固定,不需改變//Youtube提供給我們打入Stream訊號的Rtmp ServeringestionInfo.setIngestionAddress("rtmp://a.rtmp.youtube.com/live2");// Define the content distribution network settings for the// video stream. The settings specify the stream's format and// ingestion type. See:// https://developers.google.com/youtube/v3/live/docs/liveStreams#cdnCdnSettings cdnSettings = new CdnSettings();cdnSettings.setIngestionInfo(ingestionInfo);cdnSettings.setFormat("720p");cdnSettings.setIngestionType("rtmp");LiveStream stream = new LiveStream();stream.setKind("youtube#liveStream");stream.setSnippet(streamSnippet);stream.setCdn(cdnSettings);// Construct and execute the API request to insert the stream.YouTube.LiveStreams.Insert liveStreamInsert =        youtube.liveStreams().insert("snippet,cdn", stream);liveStream = liveStreamInsert.execute();push_addr = liveStream.getCdn().getIngestionInfo().getIngestionAddress() + "/" + liveStream.getCdn()        .getIngestionInfo().getStreamName(); ==>此处就是我们获取的stream的推送地址
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "http://post/%20https://www.googleapis.com/youtube/v3/liveStreams?part=snippet%2Ccdn");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: d3a48a2e-8d19-3c22-932d-9c615a2ffafa");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudnKfJTg");headers = curl_slist_append(headers, "content-type: application/json");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\n  \"snippet\": {\n    \"title\": \"TestStream\"\n  },\n  \"cdn\": {\n    \"ingestionInfo\": {\n      \"streamName\": \"MyTestStream\",\n      \"ingestionAddress\": \"rtmp://a.rtmp.youtube.com/live2\"\n    },\n    \"resolution\": \"720p\",\n    \"ingestionType\": \"rtmp\"\n  }\n}");CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5.绑定LiveBroadcast和LiveStreams

    将前面所建立的broadcast对象和stream对象进行绑定。一个broadcast只能有一个stream来源,但是一个stream来源可以同时绑定多个broadcast频道。

    需要的设置的属性:

    • Id:LiveBroadCast的ID
    • streamId:LiveStreams的ID 
      设置完成之后,通过HTTP POST将请求发送给服务器。
    POST https://www.googleapis.com/youtube/v3/liveBroadcasts/bind
    • 1

    HTTP

    POST /youtube/v3/liveBroadcasts/bind?part=id,contentDetails&amp;id=TgaR-sHrnjM&amp;streamId=l75gUJzbdbrzNDWlu4nYkA1484811227264011 HTTP/1.1Host: www.googleapis.comContent-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gWAuthorization: Bearer ya29.GlvYAxeqIoZCYHcg34TYX_cdtlFxk_9FVmw-Xlbf9uZhk_Jf5VeQ2RBPjDD-wcjxvLLvk4iG6ZZiFrySHzwHxsuasDPagrJVeVoQwYhods-vzXNM1wiZ67-ofWSNCache-Control: no-cachePostman-Token: d936a1fc-ca1c-8cf8-7950-837fcd297928
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    获得Response,得到Bind的信息

    {    "kind": "youtube#liveBroadcast",    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/1B1cxYwwGl93plqlVa67-0ilytE\"",    "id": "TgaR-sHrnjM",    "contentDetails": { "boundStreamId": "l75gUJzbdbrzNDWlu4nYkA1484811227264011", "boundStreamLastUpdateTimeMs": "2017-01-19T07:33:47.306Z", "monitorStream": { "enableMonitorStream": true, "broadcastStreamDelayMs": 0, "embedHtml": "<iframe width=\"425\" height=\"344\" src=\"https://www.youtube.com/embed/TgaR-sHrnjM?autoplay=1&livemonitor=1\" frameborder=\"0\" allowfullscreen></iframe>" }, "enableEmbed": true, "enableDvr": true, "enableContentEncryption": false, "startWithSlate": false, "recordFromStart": true, "enableClosedCaptions": false, "closedCaptionsType": "closedCaptionsDisabled", "enableLowLatency": false, "projection": "360" } }
    • 1
    • 2
    • 3
    • 4
    • 5

    分享给用户观看的地址则是:”https://www.youtube.com/watch?v= + id

    Java

    // Construct and execute a request to bind the new broadcast and stream.YouTube.LiveBroadcasts.Bind liveBroadcastBind =        youtube.liveBroadcasts().bind(liveBroadcast.getId(), "id,contentDetails");liveBroadcastBind.setStreamId(liveStream.getId());liveBroadcast = liveBroadcastBind.execute();String share_addr = "https://www.youtube.com/watch?v=" + liveBroadcast.getId(); ==>此处即是我们分享给观众的观看地址。
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts/bind?part=id%2CcontentDetails&id=TgaR-sHrnjM&streamId=l75gUJzbdbrzNDWlu4nYkA1484811227264011");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: 2008a012-a4e6-991e-e977-a9c7095b0b89");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxeqIoZCYHcg34TYX_cdtlFxk_9FVmw-Xlbf9uZhk_Jf5VeQ2RBPjDD-wcjxvLLvk4iG6ZZiFrySHzwHxsuasDPagrJVeVoQwYhods-vzXNM1wiZ67-ofWSN");headers = curl_slist_append(headers, "content-type: application/json");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    到这里,创建频道,获取视频流推送地址,以及用户观看地址都已经准备好了。此时我们就可以通过推流工具,或者自己的推流方法来完成向直播频道推流。在Youtube 直播栏目下面,进入直播活动,我们就可以看到已经创建的频道。点击进去以后,可以看到当前的频道是否有接收到码流。如果现实正常,则表示我们整个直播的频道和视频流都已经建立成功。只需要再下一步将我们的视频流播放给观众就可以了。

    6.切换liveBroadcast状态

    当我们建立好频道并且频道已经能够成功接收到稳定的码流数据之后。我们就可以通过获取stream的状态来获取码流是否正常。如下代码就是检测当前频道是否有稳定的码流上传:

    使用HTTP GET来获取liveBroadcast状态

    GET https://www.googleapis.com/youtube/v3/liveBroadcasts
    • 1

    HTTP

    GET /youtube/v3/liveStreams?part=id,status&id=l75gUJzbdbrzNDWlu4nYkA1484811227264011 HTTP/1.1Host: www.googleapis.comAuthorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckFCache-Control: no-cachePostman-Token: 53301af4-fada-9f59-1568-be32d824aecc
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Response

    {    "kind": "youtube#liveStreamListResponse",    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/t4CVyYZj7CiWAqXNBYsuscwbjZk\"",    "pageInfo": { "totalResults": 0, "resultsPerPage": 5 },    "items": [ { "kind": "youtube#liveStream", "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/oTGzu9UF_NhJNIkjGpqqg_rpX-I\"", "id": "l75gUJzbdbrzNDWlu4nYkA1484811227264011", "status": { "streamStatus": "active", "healthStatus": { "status": "bad", "configurationIssues": [ { "type": "videoResolutionUnsupported", "severity": "error", "reason": "Unsupported resolution", "description": "You need to change the video resolution. The current resolution is (320x240), which is not supported for this configuration. The expected video resolution is (1280x720)." }, { "type": "bitrateLow", "severity": "warning", "reason": "Video output low", "description": "The stream's current bitrate (592.00 Kbps) is lower than the recommended bitrate. We recommend that you use a stream bitrate of 2500 Kbps." }, { "type": "audioBitrateLow", "severity": "info", "reason": "Check audio settings", "description": "The audio stream's current bitrate (96.00 Kbps) is lower than the recommended bitrate. We recommend that you use an audio stream bitrate of 128 Kbps." }, { "type": "gopSizeOver", "severity": "info", "reason": "Check video settings", "description": "Please use a keyframe frequency of four seconds or less. Currently, keyframes are not being sent often enough, which can cause buffering. The current keyframe frequency is 5.0 seconds. Note that ingestion errors can cause incorrect GOP (group of pictures) sizes." } ] } } } ] }
    • 1
    • 2
    • 3
    • 4
    • 5

    从Response里面的 “streamStatus”字段可以看出目前stream已经是处于”active”状态,表示目前我们LiveStreams已经可以收到稳定的视频流了。

    Java

    liveStreamRequest = youtube.liveStreams()        .list("id,status")        .setId(liveBroadcast.getContentDetails()                .getBoundStreamId());LiveStreamListResponse returnedList = liveStreamRequest.execute();List<LiveStream> liveStreams = returnedList.getItems();if (liveStreams != null && liveStreams.size() > 0) {    LiveStream liveStream = liveStreams.get(0);    if (liveStream != null)        while (!liveStream.getStatus().getStreamStatus()                .equals("active")) {            Thread.sleep(1000);            returnedList = liveStreamRequest.execute();            liveStreams = returnedList.getItems();            liveStream = liveStreams.get(0);        }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveStreams?part=id%2Cstatus&id=l75gUJzbdbrzNDWlu4nYkA1484811227264011");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: a6337852-8b07-703f-df71-e4c8a0e36060");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    当我们等到stream的状态为“Active”的时候。则表示码流正常。此时离用户能够看到直播的视频还差两步: 
    a.转换频道的状态为testing,此时我们可以让频道进入测试状态。用于直播发布者预览和检测直播视频。注意此时用户是没有办法看到直播画面的。

    使用HTTP POST来切换liveBroadcast状态:

    POST https://www.googleapis.com/youtube/v3/liveBroadcasts/transition
    • 1

    HTTP

    POST /youtube/v3/liveBroadcasts/transition?broadcastStatus=testing&amp;id=TgaR-sHrnjM&amp;part=id,snippet,contentDetails,status HTTP/1.1Host: www.googleapis.comAuthorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckFCache-Control: no-cachePostman-Token: db9e406a-876e-9cc6-21e9-9713f7e5828eContent-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Response

    {    "kind": "youtube#liveBroadcast",    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/nNn7HZoSfMyCoMfqBvaAw1FEgdA\"",    "id": "8jD-N6GIlkA",    "snippet": { "publishedAt": "2017-01-19T09:02:42.000Z", "channelId": "UCl75gUJzbdbrzNDWlu4nYkA", "title": "TestLiveCode", "description": "", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/8jD-N6GIlkA/default_live.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/8jD-N6GIlkA/mqdefault_live.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/8jD-N6GIlkA/hqdefault_live.jpg", "width": 480, "height": 360 } }, "scheduledStartTime": "2017-01-19T08:14:30.000Z", "scheduledEndTime": "2017-01-19T20:14:40.000Z", "isDefaultBroadcast": false, "liveChatId": "Cg0KCzhqRC1ONkdJbGtB" },    "status": { "lifeCycleStatus": "testStarting", "privacyStatus": "public", "recordingStatus": "notRecording" },    "contentDetails": { "boundStreamId": "l75gUJzbdbrzNDWlu4nYkA1484816504294010", "boundStreamLastUpdateTimeMs": "2017-01-19T09:01:44.342Z", "monitorStream": { "enableMonitorStream": true, "broadcastStreamDelayMs": 0, "embedHtml": "<iframe width=\"425\" height=\"344\" src=\"https://www.youtube.com/embed/8jD-N6GIlkA?autoplay=1&livemonitor=1\" frameborder=\"0\" allowfullscreen></iframe>" }, "enableEmbed": true, "enableDvr": true, "enableContentEncryption": false, "startWithSlate": false, "recordFromStart": true, "enableClosedCaptions": false, "closedCaptionsType": "closedCaptionsDisabled", "enableLowLatency": false, "projection": "360" } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Java

    //the broadcast cann't transition the status from ready to live directly,//it must change to testing first and then live.YouTube.LiveBroadcasts.Transition broadCastTestingRequest = youtube        .liveBroadcasts().transition("testing",                liveBroadcast.getId(), "id,snippet,contentDetails,status");liveBroadcast = broadCastTestingRequest.execute();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts/transition?broadcastStatus=testing&id=TgaR-sHrnjM&part=id%2Csnippet%2CcontentDetails%2Cstatus");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: 96da5833-3923-2bbe-e453-1c29efcf8973");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    b.当broadcast的状态变成testing之后。我们需要将状态切换成为“live”,此时用户就可以看到直播画面。

    使用HTTP POST切换liveBroadCast状态从testing到live

    POST https://www.googleapis.com/youtube/v3/liveBroadcasts/transition
    • 1

    HTTP

    POST /youtube/v3/liveBroadcasts/transition?broadcastStatus=live&amp;id=TgaR-sHrnjM&amp;part=id,snippet,contentDetails,status HTTP/1.1Host: www.googleapis.comAuthorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckFCache-Control: no-cachePostman-Token: 65b123be-7641-8561-56fa-11f3c1f53193Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Java

    YouTube.LiveBroadcasts.Transition transitionRequest = youtube.liveBroadcasts().transition("live", liveBroadcast.getId(), "status");liveBroadcast = transitionRequest.execute();
    • 1
    • 2

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts/transition?broadcastStatus=live&id=TgaR-sHrnjM&part=id%2Csnippet%2CcontentDetails%2Cstatus");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: cb2eb41c-803e-e1ec-d0f9-419772850ff5");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    需要注意的有两个地方:1.频道的状态转换必须是active->testing->live。不能直接从active转为live。2.必须要等待broadcast的状态变成testing之后,才能进行testing->live的转换。所以必须进行一个testing状态转换完成的一个确认,如下代码即可:

    使用HTTP GET来获取liveBroadcast状态:

    GET https://www.googleapis.com/youtube/v3/liveBroadcasts
    • 1

    HTTP

    GET /youtube/v3/liveBroadcasts?part=id,status&amp;id=TgaR-sHrnjM HTTP/1.1Host: www.googleapis.comAuthorization: Bearer ya29.GlvYA7oXl3IVdI4Bok9jyXC4eXhOzm98oja33jCdrRClc49ie7lOm8inRprZ9qAYyEf7OpsekQUTOarlip-DvY1gewZQGKeW1G1jTWR6djxxpTi4hGmQzSzEOadJCache-Control: no-cachePostman-Token: cd8dada9-5a1b-bab2-611a-c515bbc9c6d7
    • 1
    • 2
    • 3
    • 4
    • 5

    Response

    {    "kind": "youtube#liveBroadcastListResponse",    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/absIVeqkZihPc-0pJMCYTpR5yjU\"",    "pageInfo": { "totalResults": 0, "resultsPerPage": 5 },    "items": [ { "kind": "youtube#liveBroadcast", "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/xrp9a15kZwGJVPtt4AT1OHJjXPw\"", "id": "TgaR-sHrnjM", "status": { "lifeCycleStatus": "testStarting", "privacyStatus": "public", "recordingStatus": "notRecording" } } ] }
    • 1
    • 2
    • 3
    • 4
    • 5

    从Response得到的”lifeCycleStatus”字段可以看到目前的状态为”testStarting”,表示正在切换testing状态中。需要等到”lifeCycleStatus”: “testing”,则表示状态已经切换完成,可以继续从testing 向 live状态切换。

    Java

    liveBroadRequest = youtube.liveBroadcasts().list("id,status");liveBroadRequest.setBroadcastStatus("all");LiveBroadcastListResponse liveBroadcastResponse = liveBroadRequest.execute();List<LiveBroadcast> returnedList = liveBroadcastResponse.getItems();if (returnedList != null && returnedList.size() > 0) {    liveBroadcastReq = returnedList.get(0);    if (liveBroadcastReq != null)        while (!liveBroadcastReq.getStatus().getLifeCycleStatus().equals("testing")) {            Thread.sleep(1000);            AppLog.d("Error","publish broadcast - getLifeCycleStatus: " + liveBroadcastReq.getStatus().getLifeCycleStatus());            liveBroadcastResponse = liveBroadRequest.execute();            returnedList = liveBroadcastResponse.getItems();            liveBroadcastReq = returnedList.get(0);        }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    C

    CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Cstatus&id=TgaR-sHrnjM");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "postman-token: bf3a9e6f-52ae-e159-a2ad-cc81c979c68e");headers = curl_slist_append(headers, "cache-control: no-cache");headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYA7oXl3IVdI4Bok9jyXC4eXhOzm98oja33jCdrRClc49ie7lOm8inRprZ9qAYyEf7OpsekQUTOarlip-DvY1gewZQGKeW1G1jTWR6djxxpTi4hGmQzSzEOadJ");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "code=4%2FYxFunij3D3aBdBolu0wDJvM1heM17gfg5e-gYjby2cU&client_id=982555336638-e1e18fh47oo0dceecq9v1pejm4p7ske8.apps.googleusercontent.com&client_secret=2RpCEltwtZvkUS4MsX6rzwmG&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code");CURLcode ret = curl_easy_perform(hnd);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    至此,我们就可以在分享给用户的地址中观看到直播视频了。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 ai保存时未响应怎么办 ai还没保存卡了怎么办 ai卡住了没保存怎么办 屁股沟有硬块红肿怎么办 卧室床选太大了怎么办 画板的笔尖掉了怎么办 宜家水壶盖子有水怎么办 背滤鱼缸除油膜怎么办 书多了没地方放怎么办 学生在教室内丢手机怎么办 新车尾箱坏了怎么办 放书的箱子烂了怎么办 车钥匙锁后备箱里怎么办 布的收纳箱有味怎么办 车漆清漆层掉了怎么办 副驾驶储物箱卡子断了怎么办 玛莎拉蒂车门打不开怎么办 新买的水杯漏水怎么办 泰迪小狗掉毛怎么办 手机jlc调用接口状态异常怎么办 进门和厕所对着怎么办 p过的照片有竖条怎么办 当照片p出竖条纹怎么办 月子里落下脚心怕风怕凉怎么办 鞋胶把手粘住了怎么办 凉鞋魔术贴长了怎么办 新买的狗一直叫怎么办 刚买的幼犬老叫怎么办 狗狗什么都不吃怎么办 新买的吊扇风小怎么办 夜市卖果汁没电怎么办 榻榻米太长2米45怎么办 木质桌子黏黏的怎么办 白色塑料桌子染色了怎么办 3dmax模型变透明了怎么办 刚养的兔子不吃怎么办 熊猫兔不吃下喝怎么办 熊猫兔感冒了一直打喷嚏怎么办 兔子后腿骨断了怎么办 兔子的腿肿了怎么办 仓鼠喝了牛奶该怎么办