Files
Vocaluxe/Vocaluxe/Lib/Sound/Decoder/CAudioDecoderFFmpeg.cs
T

224 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Vocaluxe.Base;
using Vocaluxe.Lib.Video.Acinerella;
namespace Vocaluxe.Lib.Sound.Decoder
{
class CAudioDecoderFFmpeg: CAudioDecoder
{
private TAc_read_callback _rc;
private TAc_seek_callback _sc;
private FileStream _fs;
private IntPtr _instance = IntPtr.Zero;
private IntPtr _audiodecoder = IntPtr.Zero;
private TAc_instance _Instance;
private FormatInfo _FormatInfo;
private float _CurrentTime;
private string _FileName;
private bool _FileOpened = false;
public override void Init()
{
_rc = new TAc_read_callback(read_proc);
_sc = new TAc_seek_callback(seek_proc);
_FileOpened = false;
_Initialized = true;
}
public override void Open(string FileName, bool Loop)
{
if (!_Initialized)
return;
_FileName = FileName;
_fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read);
_instance = CAcinerella.ac_init();
CAcinerella.ac_open(_instance, IntPtr.Zero, null, _rc, _sc, null, IntPtr.Zero);
_Instance = (TAc_instance)Marshal.PtrToStructure(_instance, typeof(TAc_instance));
if (!_Instance.opened)
{
//Free();
return;
}
int AudioStreamIndex = -1;
TAc_stream_info Info = new TAc_stream_info();
for (int i = 0; i < _Instance.stream_count; i++)
{
CAcinerella.ac_get_stream_info(_instance, i, out Info);
if (Info.stream_type == TAc_stream_type.AC_STREAM_TYPE_AUDIO)
{
try
{
_audiodecoder = CAcinerella.ac_create_decoder(_instance, i);
}
catch (Exception)
{
return;
}
AudioStreamIndex = i;
break;
}
}
if (AudioStreamIndex < 0)
{
//Free();
return;
}
TAc_decoder Audiodecoder = (TAc_decoder)Marshal.PtrToStructure(_audiodecoder, typeof(TAc_decoder));
_FormatInfo = new FormatInfo();
_FormatInfo.SamplesPerSecond = Audiodecoder.stream_info.audio_info.samples_per_second;
_FormatInfo.BitDepth = Audiodecoder.stream_info.audio_info.bit_depth;
_FormatInfo.ChannelCount = Audiodecoder.stream_info.audio_info.channel_count;
_CurrentTime = 0f;
if (_FormatInfo.BitDepth != 16)
{
CLog.LogError("Unsupported BitDepth in file " + FileName);
return;
}
_FileOpened = true;
}
public override void Close()
{
if (!_Initialized)
return;
_Initialized = false;
if (!_FileOpened)
return;
if (_audiodecoder != IntPtr.Zero)
CAcinerella.ac_free_decoder(_audiodecoder);
if (_instance != IntPtr.Zero)
CAcinerella.ac_close(_instance);
if (_instance != IntPtr.Zero)
CAcinerella.ac_free(_instance);
_FileOpened = false;
}
public override FormatInfo GetFormatInfo()
{
if (!_Initialized && !_FileOpened)
return new FormatInfo();
return _FormatInfo;
}
public override float GetLength()
{
if (!_Initialized && !_FileOpened)
return 0f;
return (float)_Instance.info.duration / 1000f;
}
public override void SetPosition(float Time)
{
if (!_Initialized && !_FileOpened)
return;
try
{
CAcinerella.ac_seek(_audiodecoder, 0, (Int64)(Time * 1000f));
}
catch (Exception)
{
CLog.LogError("Error seeking in file: " + _FileName);
Close();
}
}
public override float GetPosition()
{
if (!_Initialized && !_FileOpened)
return 0f;
return _CurrentTime;
}
public override void Decode(out byte[] Buffer, out float TimeStamp)
{
if (!_Initialized && !_FileOpened)
{
Buffer = null;
TimeStamp = 0f;
return;
}
int FrameFinished = 0;
try
{
FrameFinished = CAcinerella.ac_get_audio_frame(_instance, _audiodecoder);
}
catch (Exception)
{
FrameFinished = 0;
}
if (FrameFinished == 1)
{
TAc_decoder Decoder = (TAc_decoder)Marshal.PtrToStructure(_audiodecoder, typeof(TAc_decoder));
TimeStamp = (float)Decoder.timecode;
_CurrentTime = TimeStamp;
//Console.WriteLine(_CurrentTime.ToString("#0.000") + " Buffer size: " + Decoder.buffer_size.ToString());
Buffer = new byte[Decoder.buffer_size];
if (Decoder.buffer_size > 0)
Marshal.Copy(Decoder.buffer, Buffer, 0, Buffer.Length);
return;
}
Buffer = null;
TimeStamp = 0f;
}
#region Callbacks
private Int32 read_proc(IntPtr sender, IntPtr buf, Int32 size)
{
Int32 r = 0;
byte[] bb = new byte[size];
r = _fs.Read(bb, 0, size);
Marshal.Copy(bb, 0, buf, size);
return r;
}
private Int64 seek_proc(IntPtr sender, Int64 pos, Int32 whence)
{
return (Int64)_fs.Seek((long)pos, (SeekOrigin)whence);
}
#endregion Callbacks
}
}