Unity3d 使用Unity将视频传输到YouTube流媒体API V3

Unity3d 使用Unity将视频传输到YouTube流媒体API V3,unity3d,youtube-api,video-streaming,streaming,youtube-data-api,Unity3d,Youtube Api,Video Streaming,Streaming,Youtube Data Api,我正在尝试开发unity内部的实时流功能,目前我使用RTMP将视频传输到YouTube,我还使用FFmpeg编码器对MP4视频进行编码,并将其发送到RTMP服务器。我面临两个问题 1-视频在多次发送到RTMP服务器后显示在流上,可能需要10分钟。而流具有良好的数据连接 2-我已经能够连续发送静态MP4视频了如何实时编码和发送数据 3-我正在寻找更好的编码器,可以发送到RTMP服务器,并将与android/PC工作 欢迎任何有助于发展的建议 { private Thread thread;

我正在尝试开发unity内部的实时流功能,目前我使用RTMP将视频传输到YouTube,我还使用FFmpeg编码器对MP4视频进行编码,并将其发送到RTMP服务器。我面临两个问题

1-视频在多次发送到RTMP服务器后显示在流上,可能需要10分钟。而流具有良好的数据连接

2-我已经能够连续发送静态MP4视频了如何实时编码和发送数据

3-我正在寻找更好的编码器,可以发送到RTMP服务器,并将与android/PC工作

欢迎任何有助于发展的建议

{
    private Thread thread;
    IEnumerator Start()
    {
        // GOOGLE API KEYS
        var clientId = "";
        var clientSecret = "";

        var code = ""; // LEAVE IT

        // Login and get the token
        LocalServer(c => code = c);

        var authUrl = "https://accounts.google.com/o/oauth2/v2/auth?response_type=code"
          + "&client_id=" + clientId
          + "&redirect_uri=" + "http://localhost:8080"
          + "&scope=" + "https://www.googleapis.com/auth/youtube.force-ssl"
          + "&access_type=" + "offline";
        Application.OpenURL(authUrl);
        yield return new WaitUntil(() => code != "");

        //  Debug.Log(code);

        var tokenUrl = "https://www.googleapis.com/oauth2/v4/token";
        var content = new Dictionary<string, string>() {
      { "code", code },
      { "client_id", clientId },
      { "client_secret", clientSecret },
      { "redirect_uri",  "http://localhost:8080" },
      { "grant_type", "authorization_code" },
      { "access_type", "offline" },
    };
        var request = UnityWebRequest.Post(tokenUrl, content);
        yield return request.SendWebRequest();

        var json = JSON.Parse(request.downloadHandler.text);
        var token = json["access_token"].RawString();

        // Insert the live broadcast
        var liveBroadCastURL = "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=snippet%2CcontentDetails%2Cstatus";

        // Create live broadcast json to send to the server
        LiveBroadcast.Snippet liveBroadcastSnip = new LiveBroadcast.Snippet();
        liveBroadcastSnip.title = "Sample broadcast";
        liveBroadcastSnip.scheduledStartTime = "2020-01-29T10:07:48+0000";
        liveBroadcastSnip.scheduledEndTime = "2020-01-29T10:07:48+0000";
        LiveBroadcast.Status liveBroadcastState = new LiveBroadcast.Status();
        liveBroadcastState.privacyStatus = "public";
        liveBroadcastState.selfDeclaredMadeForKids = true;
        LiveBroadcast.LiveBroadcastObject liveBroadcastData = new LiveBroadcast.LiveBroadcastObject();
        liveBroadcastData.snippet = liveBroadcastSnip;
        liveBroadcastData.status = liveBroadcastState;

        var liveBroadcastRequest = new UnityWebRequest(liveBroadCastURL, "POST");
        string broadcastData = JsonUtility.ToJson(liveBroadcastData);
        byte[] broadcastBody = Encoding.UTF8.GetBytes(broadcastData);
        liveBroadcastRequest.uploadHandler = new UploadHandlerRaw(broadcastBody);
        liveBroadcastRequest.downloadHandler = new DownloadHandlerBuffer();
        liveBroadcastRequest.SetRequestHeader("Authorization", "Bearer " + token);
        liveBroadcastRequest.SetRequestHeader("Content-Type", "application/json");
        yield return liveBroadcastRequest.SendWebRequest();

        // server response and save created broadcast id
        var broadcastJson = JSON.Parse(liveBroadcastRequest.downloadHandler.text);
        var broadcastID = broadcastJson["id"].RawString();

        UnityEngine.Debug.Log("Broadcast ID: " + broadcastID);

        // Create live stream 
        var LiveStreamURL = "https://www.googleapis.com/youtube/v3/liveStreams?part=snippet%2Ccdn%2CcontentDetails%2Cstatus";

        // Create live stream json to send to the server
        LiveStream.Snippet liveStreamSnip = new LiveStream.Snippet();
        liveStreamSnip.title = "Sample Test";
        liveStreamSnip.description = "Hello My Video";
        LiveStream.Cdn liveStreamCDN = new LiveStream.Cdn();
        liveStreamCDN.frameRate = "60fps";
        liveStreamCDN.ingestionType = "rtmp";
        liveStreamCDN.resolution = "720p";
        LiveStream.ContentDetails liveStreamDetails = new LiveStream.ContentDetails();
        liveStreamDetails.isReusable = false;
        LiveStream.LiveStreamObject liveStreamData = new LiveStream.LiveStreamObject();
        liveStreamData.snippet = liveStreamSnip;
        liveStreamData.cdn = liveStreamCDN;
        liveStreamData.contentDetails = liveStreamDetails;


        string streamData = JsonUtility.ToJson(liveStreamData);
        var liveStreamRequest = new UnityWebRequest(LiveStreamURL, "POST");
        byte[] streamBody = Encoding.UTF8.GetBytes(streamData);
        liveStreamRequest.uploadHandler = new UploadHandlerRaw(streamBody);
        liveStreamRequest.downloadHandler = new DownloadHandlerBuffer();
        liveStreamRequest.SetRequestHeader("Authorization", "Bearer " + token);
        liveStreamRequest.SetRequestHeader("Content-Type", "application/json");
        yield return liveStreamRequest.SendWebRequest();

        // server response and save created stream data
        var streamJson = JSON.Parse(liveStreamRequest.downloadHandler.text);
        var streamID = streamJson["id"].RawString();
        var streamName = streamJson["cdn"]["ingestionInfo"]["streamName"].RawString();
        var ingestionAddress = streamJson["cdn"]["ingestionInfo"]["ingestionAddress"].RawString();

        UnityEngine.Debug.Log("Stream ID: "+ streamID);
        UnityEngine.Debug.Log("Stream Name: " + streamName);
        UnityEngine.Debug.Log("Ingestion Address: " + ingestionAddress);

        // Bind the stream and broadcast
        var bindUrl = "https://www.googleapis.com/youtube/v3/liveBroadcasts/bind";
        var bindContent = new Dictionary<string, string>() {
      { "id", broadcastID },
      { "part", "snippet" },
      { "streamId", streamID },
    };
        var bindRequest = UnityWebRequest.Post(bindUrl, bindContent);
        bindRequest.SetRequestHeader("Authorization", "Bearer " + token);
        bindRequest.SetRequestHeader("Accept", "application/json");
        yield return bindRequest.SendWebRequest();

        var bindJson = JSON.Parse(bindRequest.downloadHandler.text);
        var bindID = bindJson["id"].RawString(); // not importand or used 
        UnityEngine.Debug.Log("Bind ID: " + bindID);

        Application.OpenURL("https://studio.youtube.com/channel/"+streamID+"/livestreaming/dashboard?v=" + broadcastID);

        // Start the encoder
        List<string> commands = new List<string>();
        commands.Add(@"cd " + Application.dataPath + "/Resources/FFmpeg");
        commands.Add("ffmpeg -re -i Sample.mp4 -c copy -f flv rtmp://a.rtmp.youtube.com/live2/" + streamName);
        thread = new Thread(() => RunCommands(commands));
        thread.Start();
    }

    void LocalServer(Action<string> onReceive)
    {
        ThreadStart start = () => {
            try
            {
                var listener = new HttpListener();
                listener.Prefixes.Add("http://*:8080/");
                listener.Start();

                var context = listener.GetContext();
                var req = context.Request;
                var res = context.Response;

                var re = new Regex(@"/\?code=(?<c>.*)");
                var code = re.Match(req.RawUrl).Groups["c"].ToString();
                onReceive(code);

                res.StatusCode = 200;
                res.Close();
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError(e);
            }
        };
        new Thread(start).Start();
    }

    public static void RunCommands(List<string> cmds, string workingDirectory = "")
    {
        var process = new Process();
        var psi = new ProcessStartInfo();
        psi.FileName = "cmd.exe";
        psi.RedirectStandardInput = true;
        psi.CreateNoWindow = true;
        psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardError = true;
        psi.UseShellExecute = false;
        psi.WorkingDirectory = workingDirectory;
        process.StartInfo = psi;
        process.Start();
        process.OutputDataReceived += (sender, e) => { UnityEngine.Debug.Log(e.Data); };
        process.ErrorDataReceived += (sender, e) => { UnityEngine.Debug.Log(e.Data); };
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();
        using (StreamWriter sw = process.StandardInput)
        {
            foreach (var cmd in cmds)
            {
                sw.WriteLine(cmd);
            }
        }
        process.WaitForExit();
        RunCommands(cmds);
    }

    private void OnApplicationQuit()
    {
        thread.Abort();
    }

}

public static class SimpleJsonUtility
{
    public static string RawString(this JSONNode node)
    {
        var len = node.ToString().Length - 2;
        return node.ToString().Substring(1, len);
    }
}
{
私有线程;
IEnumerator Start()
{
//谷歌API密钥
var clientId=“”;
var clientSecret=“”;
var code=”“;//离开它
//登录并获取令牌
LocalServer(c=>code=c);
var authUrl=”https://accounts.google.com/o/oauth2/v2/auth?response_type=code"
+“&client_id=“+clientId
+“&重定向_uri=“+”http://localhost:8080"
+“&scope=“+”https://www.googleapis.com/auth/youtube.force-ssl"
+“&access_type=“+”脱机”;
Application.OpenURL(authUrl);
返回新的等待时间(()=>代码!=“”);
//调试日志(代码);
var tokenUrl=”https://www.googleapis.com/oauth2/v4/token";
var content=newdictionary(){
{“代码”,代码},
{“client_id”,clientId},
{“客户机密”,clientSecret},
{“重定向uri”http://localhost:8080" },
{“授权类型”、“授权代码”},
{“访问类型”,“脱机”},
};
var request=UnityWebRequest.Post(令牌URL,内容);
生成返回请求。SendWebRequest();
var json=json.Parse(request.downloadHandler.text);
var token=json[“访问令牌”].RawString();
//插入直播
var liveBroadCastURL=”https://www.googleapis.com/youtube/v3/liveBroadcasts?part=snippet%2CcontentDetails%2Cstatus";
//创建要发送到服务器的直播json
LiveBroadcast.Snippet liveBroadcastSnip=new LiveBroadcast.Snippet();
liveBroadcastSnip.title=“示例广播”;
liveBroadcastSnip.scheduledStartTime=“2020-01-29T10:07:48+0000”;
liveBroadcastSnip.scheduledEndTime=“2020-01-29T10:07:48+0000”;
LiveBroadcast.Status liveBroadcastState=新的LiveBroadcast.Status();
liveBroadcastState.privacyStatus=“public”;
liveBroadcastState.selfDeclaredMadeForKids=true;
LiveBroadcast.LiveBroadcastObject liveBroadcastData=新的LiveBroadcast.LiveBroadcastObject();
liveBroadcastData.snippet=liveBroadcastSnip;
liveBroadcastData.status=liveBroadcastState;
var liveBroadcastRequest=newunityWebRequest(liveBroadCastURL,“POST”);
string broadcastData=JsonUtility.ToJson(liveBroadcastData);
byte[]broadcastBody=Encoding.UTF8.GetBytes(broadcastData);
liveBroadcastRequest.uploadHandler=新的UploadHandlerRaw(broadcastBody);
liveBroadcastRequest.downloadHandler=新的DownloadHandlerBuffer();
SetRequestHeader(“授权”、“承载者”+令牌);
SetRequestHeader(“内容类型”、“应用程序/json”);
返回liveBroadcastRequest.SendWebRequest();
//服务器响应并保存创建的广播id
var broadcastJson=JSON.Parse(liveBroadcastRequest.downloadHandler.text);
var broadcastID=broadcastJson[“id”].RawString();
UnityEngine.Debug.Log(“广播ID:+broadcastID”);
//创建实时流
var LiveStreamURL=”https://www.googleapis.com/youtube/v3/liveStreams?part=snippet%2Ccdn%2CcontentDetails%2Cstatus";
//创建要发送到服务器的实时流json
LiveStream.Snippet liveStreamSnip=新的LiveStream.Snippet();
liveStreamSnip.title=“样本测试”;
liveStreamSnip.description=“你好,我的视频”;
LiveStream.Cdn liveStreamCDN=新的LiveStream.Cdn();
liveStreamCDN.frameRate=“60fps”;
liveStreamCDN.ingestionType=“rtmp”;
liveStreamCDN.resolution=“720p”;
LiveStream.ContentDetails liveStreamDetails=新的LiveStream.ContentDetails();
liveStreamDetails.isReusable=false;
LiveStream.LiveStreamObject liveStreamData=新的LiveStream.LiveStreamObject();
liveStreamData.snippet=liveStreamSnip;
liveStreamData.cdn=liveStreamCDN;
liveStreamData.contentDetails=liveStreamDetails;
string streamData=JsonUtility.ToJson(liveStreamData);
var liveStreamRequest=newunitywebrequest(LiveStreamURL,“POST”);
byte[]streamBody=Encoding.UTF8.GetBytes(streamData);
liveStreamRequest.uploadHandler=新的UploadHandlerRaw(streamBody);
liveStreamRequest.downloadHandler=新的DownloadHandlerBuffer();
SetRequestHeader(“授权”、“承载者”+令牌);
SetRequestHeader(“内容类型”、“应用程序/json”);
返回liveStreamRequest.SendWebRequest();
//服务器响应并保存创建的流数据
var streamJson=JSON.Parse(liveStreamRequest.downloadHandler.text);
var streamID=streamJson[“id”].RawString();
var streamName=streamJson[“cdn”][“ingestionInfo”][“streamName”].RawString();
var-ingestionAddress=streamJson[“cdn”][“ingestionInfo”][“ingestionAddress”].RawString();
UnityEngine.Debug.Log(“流ID:+streamID”);
UnityEngine.Debug.Log(“流名称:”+streamName);
UnityEngine.Debug.Log(“摄取地址:+ingestionAddress”);
//绑定流并广播
var bindUrl=”https://www.googleapis.com/youtube/v3/liveBroadcasts/bind";
var bindConten