201 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C#
		
	
	
	
| #if !UNITY_WEBPLAYER
 | |
| #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_EDITOR
 | |
| 	#define AVPRO_FILESYSTEM_SUPPORT
 | |
| #endif
 | |
| #endif
 | |
| using UnityEngine;
 | |
| using System.Collections;
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // Copyright 2015-2018 RenderHeads Ltd.  All rights reserverd.
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| namespace RenderHeads.Media.AVProVideo.Demos
 | |
| {
 | |
| 	/// <summary>
 | |
| 	/// A demo that shows how to extract a series of frames from the video,
 | |
| 	/// copy them into textures, and then save them to disk as images
 | |
| 	/// </summary>
 | |
| 	public class FrameExtract : MonoBehaviour
 | |
| 	{
 | |
| 		private const int NumFrames = 8;
 | |
| 		public MediaPlayer _mediaPlayer;
 | |
| 		public bool _accurateSeek = false;
 | |
| 		public int _timeoutMs = 250;
 | |
| 		public GUISkin _skin;
 | |
| 		public bool _asyncExtract = false;
 | |
| 
 | |
| #if AVPRO_FILESYSTEM_SUPPORT
 | |
| 		public bool _saveToJPG = false;
 | |
| 		private string _filenamePrefix;
 | |
| #endif
 | |
| 		private float _timeStepSeconds;
 | |
| 		private int _frameIndex = -1;
 | |
| 		private Texture2D _texture;
 | |
| 		private RenderTexture _displaySheet;
 | |
| 
 | |
| 		void Start()
 | |
| 		{
 | |
| 			_mediaPlayer.Events.AddListener(OnMediaPlayerEvent);
 | |
| 
 | |
| 			// Create a texture to draw the thumbnails on
 | |
| 			_displaySheet = RenderTexture.GetTemporary(Screen.width, Screen.height, 0);
 | |
| 			_displaySheet.useMipMap = false;
 | |
| 			#if UNITY_5_5_OR_NEWER
 | |
| 			_displaySheet.autoGenerateMips = false;
 | |
| 			#else
 | |
| 			_displaySheet.generateMips = false;
 | |
| 			#endif
 | |
| 			_displaySheet.antiAliasing = 1;
 | |
| 			_displaySheet.Create();
 | |
| 
 | |
| 			// Clear the texture
 | |
| 			RenderTexture.active = _displaySheet;
 | |
| 			GL.Clear(false, true, Color.black, 0f);
 | |
| 			RenderTexture.active = null;
 | |
| 		}
 | |
| 
 | |
| 		public void OnMediaPlayerEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode)
 | |
| 		{
 | |
| 			switch (et)
 | |
| 			{
 | |
| 				case MediaPlayerEvent.EventType.MetaDataReady:
 | |
| 					// Android platform doesn't display its first frame until poked
 | |
| 					mp.Play();
 | |
| 					mp.Pause();
 | |
| 					break;
 | |
| 				case MediaPlayerEvent.EventType.FirstFrameReady:
 | |
| 					OnNewMediaReady();
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private void OnNewMediaReady()
 | |
| 		{
 | |
| 			IMediaInfo info = _mediaPlayer.Info;
 | |
| 
 | |
| 			// Create a texture the same resolution as our video
 | |
| 			if (_texture != null)
 | |
| 			{
 | |
| 				Texture2D.Destroy(_texture);
 | |
| 				_texture = null;
 | |
| 			}
 | |
| 
 | |
| 			int textureWidth = info.GetVideoWidth();
 | |
| 			int textureHeight = info.GetVideoHeight();
 | |
| #if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IPHONE || UNITY_IOS || UNITY_TVOS
 | |
| 			Orientation ori = Helper.GetOrientation(_mediaPlayer.Info.GetTextureTransform());
 | |
| 			if (ori == Orientation.Portrait || ori == Orientation.PortraitFlipped)
 | |
| 			{
 | |
| 				textureWidth = info.GetVideoHeight();
 | |
| 				textureHeight = info.GetVideoWidth();
 | |
| 			}
 | |
| #endif
 | |
| 
 | |
| 			_texture = new Texture2D(textureWidth, textureHeight, TextureFormat.ARGB32, false);
 | |
| 
 | |
| 			_timeStepSeconds = (_mediaPlayer.Info.GetDurationMs() / 1000f) / (float)NumFrames;
 | |
| 
 | |
| #if AVPRO_FILESYSTEM_SUPPORT
 | |
| 			_filenamePrefix = System.IO.Path.GetFileName(_mediaPlayer.m_VideoPath);
 | |
| #endif
 | |
| 		}
 | |
| 
 | |
| 		void OnDestroy()
 | |
| 		{
 | |
| 			if (_texture != null)
 | |
| 			{
 | |
| 				Texture2D.Destroy(_texture);
 | |
| 				_texture = null;
 | |
| 			}
 | |
| 
 | |
| 			if (_displaySheet != null)
 | |
| 			{
 | |
| 				RenderTexture.ReleaseTemporary(_displaySheet);
 | |
| 				_displaySheet = null;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void Update()
 | |
| 		{
 | |
| 			if (_texture != null && _frameIndex >=0 && _frameIndex < NumFrames)
 | |
| 			{
 | |
| 				ExtractNextFrame();
 | |
| 				_frameIndex++;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private void ProcessExtractedFrame(Texture2D texture)
 | |
| 		{
 | |
| #if AVPRO_FILESYSTEM_SUPPORT
 | |
| 			// Save frame to JPG
 | |
| 			if (_saveToJPG)
 | |
| 			{
 | |
| 				string filePath = _filenamePrefix + "-" + _frameIndex + ".jpg";
 | |
| 				Debug.Log("Writing frame to file: " + filePath);
 | |
| 				System.IO.File.WriteAllBytes(filePath, texture.EncodeToJPG());
 | |
| 			}
 | |
| #endif
 | |
| 
 | |
| 			// Draw frame to the thumbnail sheet texture
 | |
| 			GL.PushMatrix();
 | |
| 			RenderTexture.active = _displaySheet;
 | |
| 			GL.LoadPixelMatrix(0f, _displaySheet.width, _displaySheet.height, 0f);
 | |
| 			Rect sourceRect = new Rect(0f, 0f, 1f, 1f);
 | |
| 
 | |
| 			float thumbSpace = 8f;
 | |
| 			float thumbWidth = ((float)_displaySheet.width / (float)NumFrames) - thumbSpace;
 | |
| 			float thumbHeight = thumbWidth / ((float)texture.width / (float)texture.height);
 | |
| 			float thumbPos = ((thumbWidth + thumbSpace) * (float)_frameIndex);
 | |
| 
 | |
| 			Rect destRect = new Rect(thumbPos, (_displaySheet.height / 2f) - (thumbHeight / 2f), thumbWidth, thumbHeight);
 | |
| 
 | |
| 			Graphics.DrawTexture(destRect, texture, sourceRect, 0, 0, 0, 0);
 | |
| 			RenderTexture.active = null;
 | |
| 			GL.PopMatrix();
 | |
| 			GL.InvalidateState();
 | |
| 		}
 | |
| 
 | |
| 		private void ExtractNextFrame()
 | |
| 		{
 | |
| 			// Extract the frame to Texture2D
 | |
| 			float timeSeconds = _frameIndex * _timeStepSeconds;
 | |
| 
 | |
| 			if (!_asyncExtract)
 | |
| 			{
 | |
| 				_texture = _mediaPlayer.ExtractFrame(_texture, timeSeconds, _accurateSeek, _timeoutMs);
 | |
| 				ProcessExtractedFrame(_texture);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				_mediaPlayer.ExtractFrameAsync(_texture, ProcessExtractedFrame, timeSeconds, _accurateSeek, _timeoutMs);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void OnGUI()
 | |
| 		{
 | |
| 			GUI.skin = _skin;
 | |
| 
 | |
| 			if (_displaySheet != null)
 | |
| 			{
 | |
| 				GUI.DrawTexture(new Rect(0f, 0f, Screen.width, Screen.height), _displaySheet, ScaleMode.ScaleToFit, false);
 | |
| 			}
 | |
| 
 | |
| 			float debugGuiScale = 4f * (Screen.height / 1080f);
 | |
| 			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(debugGuiScale, debugGuiScale, 1.0f));
 | |
| 
 | |
| 			GUILayout.Space(16f);
 | |
| 			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true), GUILayout.Width(Screen.width / debugGuiScale));
 | |
| 			GUILayout.FlexibleSpace();
 | |
| 			if (GUILayout.Button("Start Extracting Frames"))
 | |
| 			{
 | |
| 				_frameIndex = 0;
 | |
| 				RenderTexture.active = _displaySheet;
 | |
| 				GL.Clear(false, true, Color.black, 0f);
 | |
| 				RenderTexture.active = null;
 | |
| 			}
 | |
| 			GUILayout.FlexibleSpace();
 | |
| 			GUILayout.EndHorizontal();
 | |
| 		}
 | |
| 	}
 | |
| } |