Передача видео в YouTube Streaming API V3 с Unity - PullRequest
0 голосов
/ 29 января 2020

Я пытаюсь развить функциональность живого потока в пределах единства, в настоящее время я использую RTMP как способ передачи видео на YouTube, также я использовал кодер FFmpeg для кодирования и отправки видео MP4 на сервер RTMP. Я сталкиваюсь с двумя проблемами

1 - видео показывается в потоке после отправки его на сервер RTMP несколько раз, это может занять 10 минут. в то время как поток имеет отличное соединение для передачи данных.

2- Я был в состоянии непрерывно отправлять видео * stati c MP4. Как я могу кодировать и отправлять данные в режиме реального времени?

3-I Я ищу лучший кодер, который может отправлять на сервер RTMP и будет работать с Android / P C

. Любые советы, которые могут помочь в разработке, приветствуются.

{
    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);
    }
}
...