Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/Source/Media/Video.cs
Joonas Rikkonen 044fd3344b 2f107db...5202af9
2019-03-18 21:42:26 +02:00

299 lines
11 KiB
C#

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Sounds;
namespace Barotrauma.Media
{
public class Video : IDisposable
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr LibVLCVideoLockCb(IntPtr opaque, IntPtr planes);
private static LibVLCVideoLockCb VideoLockDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCVideoUnlockCb(IntPtr opaque, IntPtr picture, IntPtr planes);
private static LibVLCVideoUnlockCb VideoUnlockDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCVideoDisplayCb(IntPtr opaque, IntPtr picture);
private static LibVLCVideoDisplayCb VideoDisplayDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCAudioPlayCb(IntPtr data, IntPtr samples, uint count, long pts);
private static LibVLCAudioPlayCb AudioPlayDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCAudioPauseCb(IntPtr data, long pts);
private static LibVLCAudioPauseCb AudioPauseDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCAudioResumeCb(IntPtr data, long pts);
private static LibVLCAudioResumeCb AudioResumeDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCAudioFlushCb(IntPtr data, long pts);
private static LibVLCAudioFlushCb AudioFlushDelegate;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LibVLCAudioDrainCb(IntPtr data);
private static LibVLCAudioDrainCb AudioDrainDelegate;
private static IntPtr lib = IntPtr.Zero;
private static Dictionary<int, Video> videos;
private static int latestVideoId;
public static void Init()
{
if (lib == IntPtr.Zero)
{
string[] parameters = {
//"--no-xlib"
};
lib = LibVlcWrapper.LibVlcMethods.libvlc_new(parameters.Length, parameters);
videos = new Dictionary<int, Video>();
latestVideoId = 0;
VideoLockDelegate = VideoLockCallback;
VideoUnlockDelegate = VideoUnlockCallback;
VideoDisplayDelegate = VideoDisplayCallback;
AudioPlayDelegate = AudioPlayCallback;
AudioPauseDelegate = AudioPauseCallback;
AudioResumeDelegate = AudioResumeCallback;
AudioFlushDelegate = AudioFlushCallback;
AudioDrainDelegate = AudioDrainCallback;
}
}
public static void Close()
{
if (lib != IntPtr.Zero)
{
List<int> keys = videos.Keys.ToList();
foreach (int key in keys)
{
videos[key].Dispose();
}
LibVlcWrapper.LibVlcMethods.libvlc_free(lib);
lib = IntPtr.Zero;
}
}
private int videoId;
private IntPtr unmanagedData;
private IntPtr media;
private IntPtr mediaPlayer;
private Texture2D texture;
private byte[] textureData;
private object mutex;
private VideoSound sound;
/*private IntPtr videoLockDelegate;
private IntPtr videoUnlockDelegate;
private IntPtr videoDisplayDelegate;*/
public uint Width { get; private set; }
public uint Height { get; private set; }
public Video(GraphicsDevice graphicsDevice,SoundManager soundManager,string filename,uint width,uint height)
{
Init();
mutex = new object();
sound = new VideoSound(soundManager, filename, 44100, this);
videos.Add(latestVideoId, this);
videoId = latestVideoId; latestVideoId++;
/*using (var stream = File.OpenRead(filename))
{*/
byte[] filenameBytes = Encoding.UTF8.GetBytes(filename);
byte[] filenameBytesNullTerminated = new byte[filenameBytes.Length + 1];
filenameBytesNullTerminated[filenameBytes.Length] = 0;
Array.Copy(filenameBytes, filenameBytesNullTerminated, filenameBytes.Length);
media = LibVlcWrapper.LibVlcMethods.libvlc_media_new_path(lib, filenameBytesNullTerminated);
LibVlcWrapper.LibVlcMethods.libvlc_media_parse(media);
mediaPlayer = LibVlcWrapper.LibVlcMethods.libvlc_media_player_new(lib);
LibVlcWrapper.LibVlcMethods.libvlc_media_player_set_media(mediaPlayer, media);
//LibVlcWrapper.LibVlcMethods.libvlc_media_release(media);
//LibVlcWrapper.LibVlcMethods.libvlc_video_get_size(mediaPlayer, 0, out width, out height);
texture = new Texture2D(graphicsDevice, (int)width, (int)height);
Width = width; Height = height;
unmanagedData = Marshal.AllocHGlobal(sizeof(int)*2+(int)(width*height*3));
int[] arr = { videoId, 1 };
Marshal.Copy(arr, 0, unmanagedData, 2);
textureData = new byte[width * height * 3];
for (int i = 0; i < width*height*3; i++)
{
textureData[i] = 0;
}
IntPtr videoLockDelegatePtr = Marshal.GetFunctionPointerForDelegate(VideoLockDelegate);
IntPtr videoUnlockDelegatePtr = Marshal.GetFunctionPointerForDelegate(VideoUnlockDelegate);
IntPtr videoDisplayDelegatePtr = Marshal.GetFunctionPointerForDelegate(VideoDisplayDelegate);
LibVlcWrapper.LibVlcMethods.libvlc_video_set_callbacks(mediaPlayer, videoLockDelegatePtr, videoUnlockDelegatePtr, videoDisplayDelegatePtr, unmanagedData);
LibVlcWrapper.LibVlcMethods.libvlc_video_set_format(mediaPlayer, Encoding.UTF8.GetBytes("RV24"), (int)width, (int)height, (int)width * 3);
IntPtr audioPlayDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioPlayDelegate);
IntPtr audioPauseDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioPauseDelegate);
IntPtr audioResumeDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioResumeDelegate);
IntPtr audioFlushDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioFlushDelegate);
IntPtr audioDrainDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioDrainDelegate);
LibVlcWrapper.LibVlcMethods.libvlc_audio_set_callbacks(mediaPlayer, audioPlayDelegatePtr, audioPauseDelegatePtr, audioResumeDelegatePtr, audioFlushDelegatePtr, audioDrainDelegatePtr, unmanagedData);
LibVlcWrapper.LibVlcMethods.libvlc_audio_set_format(mediaPlayer, Encoding.UTF8.GetBytes("S16N"), 44100, 2);
LibVlcWrapper.LibVlcMethods.libvlc_audio_set_delay(mediaPlayer, 0);
LibVlcWrapper.LibVlcMethods.libvlc_media_player_play(mediaPlayer);
//}
}
public void Dispose()
{
LibVlcWrapper.LibVlcMethods.libvlc_media_player_stop(mediaPlayer);
Monitor.Enter(mutex);
//just waiting for callbacks to be done
Monitor.Exit(mutex);
Marshal.FreeHGlobal(unmanagedData);
sound.Dispose();
LibVlcWrapper.LibVlcMethods.libvlc_media_release(media);
LibVlcWrapper.LibVlcMethods.libvlc_media_player_release(mediaPlayer);
texture.Dispose();
videos.Remove(videoId);
}
public bool IsPlaying
{
get
{
return LibVlcWrapper.LibVlcMethods.libvlc_media_player_is_playing(mediaPlayer)!=0;
}
}
public Texture2D GetTexture()
{
Monitor.Enter(mutex);
int[] arr = { -1 };
IntPtr changedPtr = (IntPtr)(unmanagedData.ToInt64() + sizeof(int));
Marshal.Copy(changedPtr, arr, 0, 1);
if (arr[0]!=0)
{
IntPtr colorLocation = (IntPtr)(unmanagedData.ToInt64() + sizeof(int) * 2);
Marshal.Copy(colorLocation, textureData, 0, (int)(Width * Height * 3));
Color[] colors = new Color[Width * Height];
for (int y = 0; y < Height;y++)
{
for (int x = 0; x < Width;x++)
{
colors[x + y * Width] = new Color(textureData[3 * (x + y * Width) + 0],
textureData[3 * (x + y * Width) + 1],
textureData[3 * (x + y * Width) + 2],
(byte)255);
}
}
texture.SetData(colors);
arr[0] = 0;
Marshal.Copy(arr, 0, changedPtr, 1);
}
if (!sound.IsPlaying()) videos[videoId].sound.Play();
Monitor.Exit(mutex);
return texture;
}
static IntPtr VideoLockCallback(IntPtr opaque, IntPtr planes)
{
int[] arr = { -1 };
Marshal.Copy(opaque, arr, 0, 1);
int mutexIndex = arr[0];
Monitor.Enter(videos[mutexIndex].mutex);
IntPtr unmanagedData = (IntPtr)(opaque.ToInt64() + sizeof(int) * 2);
IntPtr[] ptrPtr = { unmanagedData };
Marshal.Copy(ptrPtr, 0, planes, 1);
return IntPtr.Zero;
}
static void VideoUnlockCallback(IntPtr opaque, IntPtr picture, IntPtr planes)
{
int[] arr = { -1 };
Marshal.Copy(opaque, arr, 0, 1);
int mutexIndex = arr[0];
arr[0] = 1;
IntPtr changedPtr = (IntPtr)(opaque.ToInt64() + sizeof(int));
Marshal.Copy(arr, 0, changedPtr, 1);
Monitor.Exit(videos[mutexIndex].mutex);
}
static void VideoDisplayCallback(IntPtr opaque,IntPtr picture)
{
//Assert(picture == IntPtr.Zero);
}
static void AudioPlayCallback(IntPtr data, IntPtr samples, uint count, long pts)
{
short[] buf = new short[count*2];
Marshal.Copy(samples, buf, 0, (int)count*2);
int[] arr = { -1 };
Marshal.Copy(data, arr, 0, 1);
int mutexIndex = arr[0];
Monitor.Enter(videos[mutexIndex].mutex);
videos[mutexIndex].sound.Enqueue(buf);
Monitor.Exit(videos[mutexIndex].mutex);
}
static void AudioPauseCallback(IntPtr data, long pts)
{
}
static void AudioResumeCallback(IntPtr data, long pts)
{
}
static void AudioFlushCallback(IntPtr data, long pts)
{
}
static void AudioDrainCallback(IntPtr data)
{
}
}
}