diff --git a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs index 91d4e4e1..553631f4 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs @@ -58,7 +58,22 @@ namespace Vocaluxe.Lib.Video.Acinerella [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct SACFileInfo { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string title; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string author; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string copyright; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string comment; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string album; + public readonly int year; + public readonly int track; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public readonly string genre; public readonly Int64 Duration; + public readonly int Bitrate; } // TAc_instance represents an Acinerella instance. Each instance can open and @@ -105,14 +120,17 @@ namespace Vocaluxe.Lib.Video.Acinerella } // Contains information about an Acinerella stream. - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Explicit)] public struct SACStreamInfo { //Contains the type of the stream. + [FieldOffset(0)] public readonly EACStreamType StreamType; //Additional info about the stream + [FieldOffset(8)] public SACAudioStreamInfo AudioInfo; + [FieldOffset(8)] public SACVideoStreamInfo VideoInfo; } @@ -128,7 +146,7 @@ namespace Vocaluxe.Lib.Video.Acinerella //The timecode of the currently decoded picture in seconds. public readonly double Timecode; - public readonly double VideoClock; + //public readonly double VideoClock; //Contains information about the stream the decoder is attached to. public SACStreamInfo StreamInfo; @@ -219,14 +237,14 @@ namespace Vocaluxe.Lib.Video.Acinerella // Initializes an Acinerella instance. //function ac_init(): PAc_instance; cdecl; external ac_dll; - [DllImport(_AcDll, EntryPoint = "ac_init", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_init(); + [DllImport(_AcDll, EntryPoint = "ac_init_of", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] + private static extern IntPtr _ac_init(EACOutputFormat outputFormat); public static IntPtr AcInit() { lock (_Lock) { - return _ac_init(); + return _ac_init(EACOutputFormat.ACOutputRGBA32); } } @@ -243,52 +261,7 @@ namespace Vocaluxe.Lib.Video.Acinerella } } - // Opens a media file. - // @param(inst specifies the Acinerella Instance the stream should be opened for) - // @param(sender specifies a pointer that is sent to all callback functions to - // allow you to do object orientated programming. May be NULL.) - // @param(open_proc specifies the callback function that is called, when the - // media file is opened. May be NULL.) - // @param(close_proc specifies the callback function that is called when the media - // file is closed. May be NULL.) - /*function ac_open( - inst: PAc_instance; - sender: Pointer; - open_proc: TAc_openclose_callback; - read_proc: TAc_read_callback; - seek_proc: TAc_seek_callback; - close_proc: TAc_openclose_callback; - proberesult: PAc_proberesult): integer; cdecl; external ac_dll; - */ - /* - [DllImport(AcDll, EntryPoint = "ac_open", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern Int32 _ac_open( - IntPtr PAc_instance, - IntPtr sender, - TAc_openclose_callback open_proc, - TAc_read_callback read_proc, - TAc_seek_callback seek_proc, - TAc_openclose_callback close_proc, - IntPtr proberesult - ); - - public static Int32 ac_open( - IntPtr PAc_instance, - IntPtr sender, - TAc_openclose_callback open_proc, - TAc_read_callback read_proc, - TAc_seek_callback seek_proc, - TAc_openclose_callback close_proc, - IntPtr proberesult - ) - { - lock (_GetLockToken(pAcDecoder)) - { - return _ac_open(PAc_instance, sender, open_proc, read_proc, seek_proc, close_proc, proberesult); - } - }*/ - - [DllImport(_AcDll, EntryPoint = "ac_open", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + [DllImport(_AcDll, EntryPoint = "ac_open_file", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern Int32 _ac_open2(IntPtr pAcInstance, string filename); // ReSharper disable UnusedMethodReturnValue.Global @@ -337,28 +310,55 @@ namespace Vocaluxe.Lib.Video.Acinerella [DllImport(_AcDll, EntryPoint = "ac_free_package", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] public static extern void ac_free_package(IntPtr pAcPackage); - [DllImport(_AcDll, EntryPoint = "ac_create_video_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_create_video_decoder(IntPtr pAcInstance); + [DllImport(_AcDll, EntryPoint = "ac_create_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] + private static extern IntPtr _ac_create_decoder(IntPtr pAcInstance, int i); public static IntPtr AcCreateVideoDecoder(IntPtr pAcInstance) { lock (_GetLockToken(pAcInstance)) { - return _ac_create_video_decoder(pAcInstance); + var firstVideoStreamId = _GetFirstStreamByType(pAcInstance, EACStreamType.ACStreamTypeVideo); + + if (firstVideoStreamId < 0) + { + throw new ArgumentException("The instace does not contain a video stream."); + } + + return _ac_create_decoder(pAcInstance, firstVideoStreamId); } } - - [DllImport(_AcDll, EntryPoint = "ac_create_audio_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_create_audio_decoder(IntPtr pAcInstance); - + public static IntPtr AcCreateAudioDecoder(IntPtr pAcInstance) { lock (_GetLockToken(pAcInstance)) { - return _ac_create_audio_decoder(pAcInstance); + var firstAudioStreamId = _GetFirstStreamByType(pAcInstance, EACStreamType.ACStreamTypeAudio); + + if (firstAudioStreamId < 0) + { + throw new ArgumentException("The instace does not contain a audio stream."); + } + return _ac_create_decoder(pAcInstance, firstAudioStreamId); } } + private static int _GetFirstStreamByType(IntPtr pAcInstance, EACStreamType type) + { + var instance = (SACInstance)Marshal.PtrToStructure(pAcInstance, typeof(SACInstance)); + + int currentStream = 0; + SACStreamInfo currentStreamInfo; + + while (currentStream < instance.StreamCount) + { + AcGetStreamInfo(pAcInstance, currentStream, out currentStreamInfo); + if (currentStreamInfo.StreamType == type) + return currentStream; + currentStream++; + } + return -1; + } + // Frees an created decoder. //procedure ac_free_decoder(pDecoder: PAc_decoder); cdecl; external ac_dll; [DllImport(_AcDll, EntryPoint = "ac_free_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] @@ -401,26 +401,61 @@ namespace Vocaluxe.Lib.Video.Acinerella } } - [DllImport(_AcDll, EntryPoint = "ac_get_frame", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern Int32 _ac_get_frame(IntPtr pAcInstance, IntPtr pAcDecoder); + [DllImport(_AcDll, EntryPoint = "ac_read_package", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] + private static extern IntPtr _ac_read_package(IntPtr pAcInstance); public static bool AcGetFrame(IntPtr pAcInstance, IntPtr pAcDecoder) { lock (_GetLockToken(pAcDecoder)) { - return _ac_get_frame(pAcInstance, pAcDecoder) != 0; + var pckt = _ac_read_package(pAcInstance); + if (pckt != IntPtr.Zero) + { + if (pAcDecoder != IntPtr.Zero) + { + // The packet is for the video stream, try to decode it + if (_ac_decode_package(pckt, pAcDecoder) != 0) + { + ac_free_package(pckt); + return true; + } + } + ac_free_package(pckt); + } + return false; } } - [DllImport(_AcDll, EntryPoint = "ac_skip_frames", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern Int32 _ac_skip_frames(IntPtr pAcInstance, IntPtr pAcDecoder, Int32 num); + [DllImport(_AcDll, EntryPoint = "ac_skip_package", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] + private static extern Int32 _ac_skip_package(IntPtr pAcInstance, IntPtr pAcDecoder); public static bool AcSkipFrames(IntPtr pAcInstance, IntPtr pAcDecoder, Int32 num) { - lock (_GetLockToken(pAcDecoder)) + int skipedFrames = 0; + while (skipedFrames < num) { - return _ac_skip_frames(pAcInstance, pAcDecoder, num) != 0; + lock (_GetLockToken(pAcDecoder)) + { + var pckt = _ac_read_package(pAcInstance); + if (pckt != IntPtr.Zero) + { + if (pAcDecoder != IntPtr.Zero) + { + // Decode the package to figure out if its completing a frame + if (_ac_skip_package(pckt, pAcDecoder) != 0) + { + skipedFrames++; + } + } + ac_free_package(pckt); + } + else + { + return false; + } + } } + return true; } // Seeks to the given target position in the file. The seek funtion is not able to seek a single audio/video stream diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs index 78707644..eb913429 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -406,6 +406,7 @@ namespace Vocaluxe.Lib.Video.Acinerella { _Free(); Stop(); + return; } while (!_Terminated)