我想做一个可以观看当前Twitch.tv直播流的Unity3D应用程序。
我不确定这是否可能,例如,使用twitch api (https://github.com/justintv/twitch-api)
我知道Unity3D中的视频纹理,也知道如何使用默认的twitch api基础知识,但我不知道如何将正在运行的twitch流集成到我的应用程序中。
如果可能的话,有人能给我一个提示吗?
非常感谢,并向我致以最良好的问候
发布于 2017-10-28 01:13:19
最终来自twitch的流是MPEG-4 (H264/M3U)。因此,如果你可以在Unity中渲染它,那么你就可以渲染twitch streams。
从twitch获取请求的正确URL需要几个步骤,而这些步骤可能会随着时间的推移而改变。您必须在播放流的同时检查当前的twitch页面,以查看javascript如何构建请求(url和头)。
最后,javascript将构建一个访问令牌,然后使用它从twitch边缘服务器之一请求一个名为index-live.m3u8的文件。该文件包含实况流最后几秒钟的文件名列表(以及其他一些元数据)。它看起来像这样
https://video-edge-c61b44.lax01.hls.ttvnw.net/v0/[some-long-access-token]/index-live.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#ID3-EQUIV-TDTG:2017-10-27T16:53:27
#EXT-X-MEDIA-SEQUENCE:8788
#EXT-X-TWITCH-ELAPSED-SECS:17576.000
#EXT-X-TWITCH-TOTAL-SECS:17589.870
#EXTINF:2.000,
index-0000008788-Y6OH.ts
#EXTINF:2.000,
index-0000008789-l0QY.ts
#EXTINF:2.000,
index-0000008790-gCUV.ts
#EXTINF:2.000,
index-0000008791-1ngg.ts
#EXTINF:2.000,
index-0000008792-wpQL.ts
#EXTINF:2.000,
index-0000008793-koO4.ts然后将index-live.m3u8替换为列表中某个文件的名称,并请求它获取该剪辑。类似于:
它将是一个大约1秒长的MPEG-4流。这个列表大约有6个文件长,所以如果你全部请求它们,你可以得到大约6秒的缓冲区。
每隔一到两秒钟,index-live.m3u8就会更新一次,旧文件会随着新文件添加到底部而滚出。当缓冲区耗尽时,您需要每隔几秒钟重新请求此文件,并请求其中的新剪辑以继续播放。
发布于 2018-03-22 16:47:50
使用Ted Bigham的answer,您可以获得视频的m3u8流。然后,您可以将此流传输到像AVPro video from Renderheads这样的插件中,通过各种自定义和设置,直接在任何形状或模型上统一播放。
然而,这不是一个免费的插件,可能还有其他的选择。我与他们没有任何关系,但在过去使用过这个插件,效果很好。
附言:我最初只是想把这篇文章作为评论,我相信Ted Bigham已经回答了你的问题。但由于声誉的原因,我不被允许。
发布于 2020-04-07 06:01:09
@Ted Bigham有没有使用默认的unity视频播放器就能做到这一点?
到目前为止,你所说的一切都很有效!只需使用chrome,我就可以打开.m3u8并下载每1秒的.ts文件。使用任何视频播放器,我都可以很好地查看每个视频文件。
当我尝试通过视频播放器传递url时,它显示“无法读取文件”。我甚至尝试过用.mp4替换.ts,因为它是一种受支持的格式。当我在Unity外部测试它时,这是有效的,但给我同样的错误。
这是我的代码。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Video;
public class TwitchStreamer : MonoBehaviour
{
public string m3u8 = "https://video-weaver.atl01.hls.ttvnw.net/v1/playlist/Cq4EuEYkh5IqurC4gy3nHqGhPVtUwH_" +
"5QcQbCatC5Fhit9qbivMQ2rdh2MS_m_2OuLd3VS2mF0eTrCKrz8YTuDO19mcbIBMJL3BUMz4jnNuU_t-e53V51TOtaN3vcCk9n3Qr" +
"dP0WyLREnVR0n_30d4PlUjjW4_si5Wr2XuePQ0dPtxP6jnsenKnX56YTLohtCN2-FdfSvHQMdfd0aw68FA4h9wawHoIM9-U6YRmPa" +
"fDsfdCiZr_iToSR6lZi81VoYPVjt7Ygf7xKwhjlNwrvA5SnsAnWQGIOVt4UjDkNLw-hmNMAr7RT0iiDghKXZY1VI6Tuc-umB1VXYE" +
"7BH5hHbDfHgB3_IYNb0fjoudtSuaZxISyWoazPrw3AibEO7k1-quhdcjarBTGpIi_dlPEp-yZlQOy98_OZY_tqjk8ZWTBIaAAYEG_" +
"miwqsgH4d6eIfkh3ehyMvPQH1C5dVG9tQcSWPUYU6D6hWhxvJhEr-UC0_BYWIVzX7z_Uf74FJGIEqSQc0d6igiowdMM_lyD8ZV9BE" +
"7wqQs3RegMPqux-AOfF-_Q7Ki2MBv9u7D9ZRXMH_cm20bTx5-ShEDRnWMApSfXK-9bAGNXUcw8YlBbHYeSN5VxEZMC2oGjcivBsGs" +
"RPMTQ_yNBSM1S6GxFRIR4nqA-mbdXg3rXMW3V6MNybBb1lrrQeEqF1tdYE0rfxe3Ki5WWkxeKmSjMGbMl1tHCwMaReTYkQnX5Qhjl" +
"HXXtKLtEIEEhB3cXW3oF05-E_q87s68JQIGgyIEKPiQlTsANR9zRc.m3u8";
public float updateClip = 1f, updateFile = 6f;
public VideoPlayer vp;
Queue<string> urls;
void OnEnable()
{
StartCoroutine(UpdateFile());
//InvokeRepeating("UpdateFile", 0f, updateFile);
InvokeRepeating("UpdateClip", updateClip, updateClip);
urls = new Queue<string>();
vp.prepareCompleted += Vp_prepareCompleted;
vp.errorReceived += Vp_errorReceived;
}
private void Vp_errorReceived(VideoPlayer source, string message)
{
Debug.Log("4567: Playback preparation failed. " + message, source);
}
private void Vp_prepareCompleted(VideoPlayer source)
{
Debug.Log("4567: Playback preparation complete.");
source.Play();
}
void OnDisable()
{
CancelInvoke();
StopAllCoroutines();
vp.prepareCompleted -= Vp_prepareCompleted;
vp.errorReceived -= Vp_errorReceived;
}
void UpdateClip()
{
//vp.Stop();
if (urls.Count > 0)
{
vp.url = urls.Dequeue();
vp.Prepare();
Debug.Log("4567: Prepare playback for " + vp.url);
}
}
IEnumerator UpdateFile()
{
UnityWebRequest www = UnityWebRequest.Get(m3u8);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
// Show results as text
//Debug.Log(www.downloadHandler.text);
string[] raw = www.downloadHandler.text.Split('\n');
foreach (string line in raw)
{
if (line.Contains("http"))
{
string cnvrt = line.Replace(".ts", ".mp4");
urls.Enqueue(cnvrt);
Debug.Log(line + " has been added to stream queue.");
}
}
// Or retrieve results as binary data
//byte[] results = www.downloadHandler.data;
}
yield return new WaitForSeconds(updateFile);
}
}https://stackoverflow.com/questions/34857327
复制相似问题