我正在开发AR游戏。在特定情况下,我想在一个场景的一部分(例如在平面上)播放一个用户从电话画廊中选择的视频。 我测试统一视频播放器,但是当视频大小超过100 MB甚至纹理没有显示时,这将会滞后很多,只是我能听到视频声音。
我现在该怎么办?我应该编写一个java原生插件,它在java中流式传输视频并将纹理设置为统一吗?
谢谢,抱歉英语不好。
videoPlayer.playOnAwake = false;
videoPlayer.source = VideoSource.Url;
videoPlayer.url = url;
videoPlayer.Prepare();
//Wait until video is prepared
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
//Assign the Texture from Video to RawImage to be displayed
image.texture = videoPlayer.texture;
//Play Video
videoPlayer.Play();
我还在编辑器中分配了AudioSource。 如果视频大小低于10 MB,一切正常。
答案 0 :(得分:3)
VideoPlayer
似乎在一些Android设备上落后。 Android设备上的一个可能的解决方案是以块的形式阅读视频,然后使用HttpListener
将其托管在Android设备上。
使用VideoPlayer
API连接到您在设备上创建的主机,并使用VideoSource.Url;
并将VideoPlayer.url
设置为本地设备上的主机网址,然后播放视频。
使用HttpListener
托管视频(必须更改filePath
以指向视频的实际路径:
//Server url
string url = "http://127.0.0.1:8080/";
//Types of media supported(Can be extended)
private static IDictionary<string, string> mimeDic =
new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{".asf", "video/x-ms-asf"},
{".asx", "video/x-ms-asf"},
{".avi", "video/x-msvideo"},
{".flv", "video/x-flv"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".mng", "video/x-mng"},
{".mov", "video/quicktime"},
{".mp3", "audio/mpeg"},
{".mpeg", "video/mpeg"},
{".mp4", "video/mp4" },
{".mpg", "video/mpeg"},
{".ra", "audio/x-realaudio"},
{".swf", "application/x-shockwave-flash"},
{".wbmp", "image/vnd.wap.wbmp"},
{".wmv", "video/x-ms-wmv"},
};
List<HttpListenerResponse> httpResponses = new List<HttpListenerResponse>();
Thread listeningThread;
void Awake()
{
Application.runInBackground = true;
//Your Video Path
string filePath = Path.Combine(Application.persistentDataPath, "Cater2U.mp4");
Debug.Log(filePath.Replace("/", "\\"));
//Create Server
StartHttpServer(filePath);
}
void StartHttpServer(string dataPath)
{
listeningThread = new Thread(new ParameterizedThreadStart(ListenToClient));
listeningThread.IsBackground = true;
listeningThread.Start(dataPath);
}
void StopHttpServer()
{
//Stop thread
if (listeningThread != null && listeningThread.IsAlive)
{
listeningThread.Abort();
Debug.LogWarning("Listening Thread Stopped!");
}
}
void DisconnectClients()
{
//Disconnect from each connected client
for (int i = 0; i < httpResponses.Count; i++)
{
if (httpResponses[i] != null)
{
httpResponses[i].StatusDescription = "Server done";
httpResponses[i].OutputStream.Close();
Debug.LogWarning("Disconnected Client!");
}
}
}
void ListenToClient(object path)
{
//Get the param
string dataPath = (string)path;
HttpListener listener = new HttpListener();
listener.Prefixes.Add(url);
listener.Start();
Debug.Log("Listening to Client");
while (true)
{
HttpListenerContext context = listener.GetContext();
Debug.LogWarning("New Client Connected: " + context.Request.RemoteEndPoint.ToString());
//Construct param that will be sent to the Thread
ServerParamData serverData = new ServerParamData(context, dataPath);
ThreadPool.QueueUserWorkItem(new WaitCallback(RunInNewThread), serverData);
}
}
private void RunInNewThread(object ctx)
{
//Get the param
ServerParamData serverData = (ServerParamData)ctx;
//Open the file and start sending it to the client
WriteFile(serverData.context, serverData.path);
}
void WriteFile(HttpListenerContext ctx, string path)
{
HttpListenerResponse response = ctx.Response;
httpResponses.Add(response);
using (FileStream fs = File.OpenRead(path))
{
string filename = Path.GetFileName(path);
string mime;
//Set the type of media to play
if (!mimeDic.TryGetValue(Path.GetExtension(filename), out mime))
mime = "application/octet-stream";
ctx.Response.ContentType = mime;
response.ContentLength64 = fs.Length;
//Stream the File
response.SendChunked = true;
//Enable Media Seek(Rewind/Fastforward)
response.StatusCode = 206;
response.AddHeader("Content-Range", "bytes 0-" + (fs.Length - 1) + "/" + fs.Length);
//According to Content Range
//https://greenbytes.de/tech/webdav/rfc7233.html#header.content-range
//Send data to the connected client
byte[] buffer = new byte[64 * 1024];
int read;
using (BinaryWriter bw = new BinaryWriter(response.OutputStream))
{
while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
{
bw.Write(buffer, 0, read);
bw.Flush(); //seems to have no effect
}
bw.Close();
}
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusDescription = "OK";
response.OutputStream.Close();
}
}
void OnDisable()
{
//Clean Up
StopHttpServer();
DisconnectClients();
}
//Holds multiple params sent to a function in another Thread
public class ServerParamData
{
public HttpListenerContext context;
public string path;
public ServerParamData(HttpListenerContext context, string path)
{
this.context = context;
this.path = path;
}
}
使用VideoPlayer
API播放托管视频(这是对this帖子中代码的一个小修改):
//Raw Image to Show Video Images [Assign from the Editor]
public RawImage image;
private VideoPlayer videoPlayer;
private VideoSource videoSource;
//Audio
private AudioSource audioSource;
//Server url
string url = "http://127.0.0.1:8080/";
// Use this for initialization
void Start()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
IEnumerator playVideo()
{
//Add VideoPlayer to the GameObject
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//Add AudioSource
audioSource = gameObject.AddComponent<AudioSource>();
//Disable Play on Awake for both Video and Audio
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
//We want to play from url
videoPlayer.source = VideoSource.Url;
videoPlayer.url = url;
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
//Prepare Audio to prevent Buffering
videoPlayer.Prepare();
//Wait until video is prepared
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
Debug.Log("Done Preparing Video");
//Assign the Texture from Video to RawImage to be displayed
image.texture = videoPlayer.texture;
//Play Video
videoPlayer.Play();
//Play Sound
audioSource.Play();
Debug.Log("Playing Video");
while (videoPlayer.isPlaying)
{
Debug.LogWarning("Video Time: " + Mathf.FloorToInt((float)videoPlayer.time));
yield return null;
}
Debug.Log("Done Playing Video");
}
这适用于我,但可能适用于您的设备。如果是这种情况,那么您现在必须放弃VideoPlayer
API并使用MediaPlayer
与OpenGL ES一起制作适用于Android的视频播放器。 This和this帖子可以帮助您开始使用该插件。