Implement IAudioSource.Duration property and IAudioDecoderSettings.Open extension method.

This commit is contained in:
Grigory Chudov
2018-04-07 23:02:01 -04:00
parent be881945ac
commit deb3448a55
27 changed files with 817 additions and 75 deletions

View File

@@ -165,7 +165,9 @@ namespace CUETools.Codecs.ALAC
_IO.Close();
}
public long Length
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get
{

View File

@@ -127,7 +127,9 @@ namespace CUETools.Codecs.Flake
_IO.Close();
}
public long Length
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get
{

View File

@@ -12,13 +12,9 @@ namespace CUETools.Codecs.LossyWAV
public IAudioDecoderSettings Settings => null;
public long Length
{
get
{
return _audioSource.Length;
}
}
public TimeSpan Duration => _audioSource.Duration;
public long Length => _audioSource.Length;
public long Position
{
@@ -33,29 +29,11 @@ namespace CUETools.Codecs.LossyWAV
}
}
public long Remaining
{
get
{
return _audioSource.Remaining;
}
}
public long Remaining => _audioSource.Remaining;
public AudioPCMConfig PCM
{
get
{
return _audioSource.PCM;
}
}
public AudioPCMConfig PCM => _audioSource.PCM;
public string Path
{
get
{
return _audioSource.Path;
}
}
public string Path => _audioSource.Path;
public LossyWAVReader(IAudioSource audioSource, IAudioSource lwcdfSource)
{

View File

@@ -74,6 +74,8 @@ namespace CUETools.Codecs.MACLib
public string Path => _path;
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length => _sampleCount;
internal long SamplesInBuffer => _bufferLength - _bufferOffset;

View File

@@ -0,0 +1,657 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
namespace CUETools.Codecs.MPEG.ATSI
{
public class AudioDecoder : IAudioSource
{
public unsafe AudioDecoder(DecoderSettings settings, string path, Stream IO)
{
m_settings = settings;
_path = path;
_IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000);
int length = (int)_IO.Length;
contents = new byte[length];
if (_IO.Read(contents, 0, length) != length) throw new Exception("");
fixed (byte* ptr = &contents[0])
{
var fr = new FrameReader(ptr, length);
hdr_m = parseHeader(fr);
fr = new FrameReader(ptr + hdr_m.list_pos, length - hdr_m.list_pos);
parsePlaylist(fr);
fr = new FrameReader(ptr + hdr_m.mark_pos, length - hdr_m.mark_pos);
parsePlaylistMarks(fr);
}
}
void openEntries()
{
readers = new List<IAudioSource>();
var pids = new List<int>();
foreach (var item in hdr_m.play_item)
foreach (var audio in item.audio)
{
if (audio.coding_type != 0x80 /* LPCM */) continue;
pids.Add(audio.pid);
}
int chosenPid;
if (m_settings.StreamId.HasValue)
{
if (!pids.Contains(m_settings.StreamId.Value))
throw new Exception("StreamId can be " +
string.Join(", ", pids.ConvertAll(pid => pid.ToString()).ToArray()));
chosenPid = m_settings.StreamId.Value;
}
else if (m_settings.Stream.HasValue)
{
if (m_settings.Stream.Value < 0 || m_settings.Stream.Value >= pids.Count)
throw new Exception("Stream can be 0.." + (pids.Count - 1).ToString());
chosenPid = pids[m_settings.Stream.Value];
}
else throw new Exception("multiple streams present, please specify StreamId or Stream");
foreach (var item in hdr_m.play_item)
foreach (var audio in item.audio)
{
if (audio.coding_type != 0x80 /* LPCM */) continue;
if (m_settings.IgnoreShortItems && item.out_time - item.in_time < shortItemDuration) continue;
if (audio.pid == chosenPid)
{
var parent = Directory.GetParent(System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(_path)));
var m2ts = System.IO.Path.Combine(
System.IO.Path.Combine(parent.FullName, "STREAM"),
item.clip_id + ".m2ts");
var settings = new BDLPCM.DecoderSettings() { StreamId = chosenPid };
var entry = settings.Open(m2ts);
readers.Add(entry);
break;
}
}
currentReader = readers[0];
pcm = currentReader.PCM;
}
MPLSHeader parseHeader(FrameReader fr)
{
var hdr = new MPLSHeader();
hdr.play_item = new List<MPLSPlaylistItem>();
hdr.play_mark = new List<MPLSPlaylistMark>();
long length = fr.Length;
hdr.type_indicator = fr.read_uint();
hdr.type_indicator2 = fr.read_uint();
hdr.list_pos = fr.read_uint();
hdr.mark_pos = fr.read_uint();
hdr.ext_pos = fr.read_uint();
if (hdr.type_indicator != 0x4d504c53 /*MPLS*/) throw new NotSupportedException();
if (hdr.type_indicator2 != 0x30313030 && hdr.type_indicator2 != 0x30323030) throw new NotSupportedException();
if (hdr.list_pos > length || hdr.mark_pos > length || hdr.ext_pos > length) throw new NotSupportedException();
return hdr;
}
void parsePlaylist(FrameReader parentFr)
{
uint len = parentFr.read_uint();
var fr = new FrameReader(parentFr, len);
parentFr.skip(len);
ushort reserved = fr.read_ushort();
hdr_m.list_count = fr.read_ushort();
hdr_m.sub_count = fr.read_ushort();
for (int i = 0; i < hdr_m.list_count; i++)
hdr_m.play_item.Add(parsePlaylistItem(fr));
}
void parsePlaylistMarks(FrameReader parentFr)
{
uint len = parentFr.read_uint();
var fr = new FrameReader(parentFr, len);
parentFr.skip(len);
hdr_m.mark_count = fr.read_ushort();
for (int ii = 0; ii < hdr_m.mark_count; ii++)
hdr_m.play_mark.Add(parsePlaylistMark(fr));
}
MPLSPlaylistItem parsePlaylistItem(FrameReader parentFr)
{
var item = new MPLSPlaylistItem();
item.video = new List<MPLSStream>();
item.audio = new List<MPLSStream>();
item.pg = new List<MPLSStream>();
// PlayItem Length
ushort len = parentFr.read_ushort();
var fr = new FrameReader(parentFr, len);
parentFr.skip(len);
// Primary Clip identifer
item.clip_id = fr.read_string(5);
// skip the redundant "M2TS" CodecIdentifier
uint codecId = fr.read_uint();
if (codecId != 0x4D325453) throw new NotSupportedException("Incorrect CodecIdentifier");
ushort flags = fr.read_ushort();
bool is_multi_angle = ((flags >> 4) & 1) != 0;
item.connection_condition = (byte)(flags & 15);
if (item.connection_condition != 0x01 &&
item.connection_condition != 0x05 &&
item.connection_condition != 0x06)
throw new NotSupportedException("Unexpected connection condition");
item.stc_id = fr.read_byte();
item.in_time = fr.read_uint();
item.out_time = fr.read_uint();
// Skip UO_mask_table, random_access_flag, reserved, still_mode
// and still_time
fr.skip(12);
if (is_multi_angle)
{
byte num_angles = fr.read_byte();
// skip reserved, is_different_audio, is_seamless_angle_change
fr.skip(1);
for (int ii = 1; ii < num_angles; ii++)
{
// Drop clip_id, clip_codec_id, stc_id
fr.skip(10);
}
}
// Skip STN len
fr.skip(2);
// Skip 2 reserved bytes
fr.skip(2);
item.num_video = fr.read_byte();
item.num_audio = fr.read_byte();
item.num_pg = fr.read_byte();
item.num_ig = fr.read_byte();
item.num_secondary_audio = fr.read_byte();
item.num_secondary_video = fr.read_byte();
item.num_pip_pg = fr.read_byte();
// 5 reserve bytes
fr.skip(5);
for (int ii = 0; ii < item.num_video; ii++)
item.video.Add(parseStream(fr));
for (int ii = 0; ii < item.num_audio; ii++)
item.audio.Add(parseStream(fr));
for ( int ii = 0; ii < item.num_pg; ii++)
item.pg.Add(parseStream(fr));
return item;
}
MPLSStream parseStream(FrameReader parentFr)
{
MPLSStream s = new MPLSStream();
byte len = parentFr.read_byte();
var fr = new FrameReader(parentFr, len);
parentFr.skip(len);
s.stream_type = fr.read_byte();
switch (s.stream_type)
{
case 1:
s.pid = fr.read_ushort();
break;
case 2:
case 4:
s.subpath_id = fr.read_byte();
s.subclip_id = fr.read_byte();
s.pid = fr.read_ushort();
break;
case 3:
s.subpath_id = fr.read_byte();
s.pid = fr.read_ushort();
break;
default:
throw new Exception("unrecognized stream type");
};
len = parentFr.read_byte();
fr = new FrameReader(parentFr, len);
parentFr.skip(len);
s.coding_type = fr.read_byte();
if (s.coding_type == 0x01
|| s.coding_type == 0x02
|| s.coding_type == 0xea
|| s.coding_type == 0x1b)
{
// Video
byte fmt = fr.read_byte();
s.format = (byte)(fmt >> 4);
s.rate = (byte)(fmt & 15);
}
else if (s.coding_type == 0x03
|| s.coding_type == 0x04
|| s.coding_type == 0x80
|| s.coding_type == 0x81
|| s.coding_type == 0x82
|| s.coding_type == 0x83
|| s.coding_type == 0x84
|| s.coding_type == 0x85
|| s.coding_type == 0x86)
{
// Audio
byte fmt = fr.read_byte();
s.format = (byte)(fmt >> 4);
s.rate = (byte)(fmt & 15);
s.lang = fr.read_string(3);
}
else if (s.coding_type == 0x90
|| s.coding_type == 0x91)
{
s.lang = fr.read_string(3);
}
else if (s.coding_type == 0x92)
{
s.char_code = fr.read_byte();
s.lang = fr.read_string(3);
}
else throw new Exception("unrecognized stream type");
return s;
}
MPLSPlaylistMark parsePlaylistMark(FrameReader fr)
{
var mark = new MPLSPlaylistMark();
mark.mark_id = fr.read_byte();
mark.mark_type = fr.read_byte();
mark.play_item_ref = fr.read_ushort();
mark.time = fr.read_uint();
mark.entry_es_pid = fr.read_ushort();
mark.duration = fr.read_uint();
return mark;
}
public IAudioDecoderSettings Settings => m_settings;
public void Close()
{
if (readers != null)
foreach (var rdr in readers)
{
rdr.Close();
}
readers = null;
currentReader = null;
_IO = null;
}
public long Length
{
get
{
return -1;
}
}
public TimeSpan Duration
{
get
{
uint totalLength = 0;
foreach (var item in hdr_m.play_item)
{
if (item.num_audio == 0) continue;
uint item_duration = item.out_time - item.in_time;
if (m_settings.IgnoreShortItems && item_duration < shortItemDuration) continue;
totalLength += item_duration;
}
return TimeSpan.FromSeconds(totalLength / 45000.0);
}
}
public long Remaining
{
get
{
return -1;
}
}
public long Position
{
get
{
long res = 0;
foreach (var rdr in readers)
{
res += rdr.Position;
if (rdr == currentReader) break;
}
return res;
}
set
{
throw new NotSupportedException();
}
}
public unsafe AudioPCMConfig PCM
{
get {
if (readers == null) openEntries();
return pcm;
}
}
public string Path { get { return _path; } }
public unsafe int Read(AudioBuffer buff, int maxLength)
{
if (readers == null) openEntries();
int res = currentReader.Read(buff, maxLength);
if (res == 0)
{
bool nextOne = false;
foreach (var rdr in readers)
{
if (nextOne)
{
currentReader = rdr;
return currentReader.Read(buff, maxLength);
}
nextOne = (rdr == currentReader);
}
currentReader = null;
}
return res;
}
public string FileName
{
get
{
return System.IO.Path.GetFileName(_path);
}
}
public MPLSHeader MPLSHeader
{
get
{
return hdr_m;
}
}
public List<uint> Chapters
{
get
{
//settings.IgnoreShortItems
var res = new List<uint>();
if (hdr_m.play_mark.Count < 1) return res;
if (hdr_m.play_item.Count < 1) return res;
res.Add(0);
for (int i = 0; i < hdr_m.mark_count; i++)
{
ushort mark_item = hdr_m.play_mark[i].play_item_ref;
uint item_in_time = hdr_m.play_item[mark_item].in_time;
uint item_out_time = hdr_m.play_item[mark_item].out_time;
if (m_settings.IgnoreShortItems && item_out_time - item_in_time < shortItemDuration) continue;
uint item_offset = 0;
for (int j = 0; j < mark_item; j++)
{
if (hdr_m.play_item[j].num_audio == 0) continue;
uint item_duration = hdr_m.play_item[j].out_time - hdr_m.play_item[j].in_time;
if (m_settings.IgnoreShortItems && item_duration < shortItemDuration) continue;
item_offset += item_duration;
}
res.Add(hdr_m.play_mark[i].time - item_in_time + item_offset);
}
uint end_offset = 0;
for (int j = 0; j < hdr_m.play_item.Count; j++)
{
if (hdr_m.play_item[j].num_audio == 0) continue;
uint item_duration = hdr_m.play_item[j].out_time - hdr_m.play_item[j].in_time;
if (m_settings.IgnoreShortItems && item_duration < shortItemDuration) continue;
end_offset += hdr_m.play_item[j].out_time - hdr_m.play_item[j].in_time;
}
res.Add(end_offset);
while (res.Count > 1 && res[1] - res[0] < 45000) res.RemoveAt(1);
while (res.Count > 1 && res[res.Count - 1] - res[res.Count - 2] < 45000) res.RemoveAt(res.Count - 2);
return res;
}
}
readonly static int shortItemDuration = 45000 * 30;
string _path;
Stream _IO;
byte[] contents;
AudioPCMConfig pcm;
List<IAudioSource> readers;
IAudioSource currentReader;
MPLSHeader hdr_m;
DecoderSettings m_settings;
}
public struct MPLSPlaylistMark
{
public byte mark_id;
public byte mark_type;
public ushort play_item_ref;
public uint time;
public ushort entry_es_pid;
public uint duration;
}
public struct MPLSStream
{
public byte stream_type;
public byte coding_type;
public ushort pid;
public byte subpath_id;
public byte subclip_id;
public byte format;
public byte rate;
public byte char_code;
public string lang;
public string FormatString
{
get
{
if (coding_type == 0x01
|| coding_type == 0x02
|| coding_type == 0xea
|| coding_type == 0x1b)
switch (format)
{
case 0: return "reserved0";
case 1: return "480i";
case 2: return "576i";
case 3: return "480p";
case 4: return "1080i";
case 5: return "720p";
case 6: return "1080p";
case 7: return "576p";
default: return format.ToString();
}
switch (format)
{
case 0: return "reserved0";
case 1: return "mono";
case 2: return "reserved2";
case 3: return "stereo";
case 4: return "reserved4";
case 5: return "reserved5";
case 6: return "multi-channel";
case 12: return "combo";
default: return format.ToString();
}
}
}
public int FrameRate
{
get
{
switch (rate)
{
case 1: return 24;
case 2: return 24;
case 3: return 25;
case 4: return 30;
case 6: return 50;
case 7: return 60;
default: throw new NotSupportedException();
}
}
}
public bool Interlaced
{
get
{
return format == 1 || format == 2 || format == 4;
}
}
public string RateString
{
get
{
if (coding_type == 0x01
|| coding_type == 0x02
|| coding_type == 0xea
|| coding_type == 0x1b)
switch (rate)
{
case 0: return "reserved0";
case 1: return "23.976";
case 2: return "24";
case 3: return "25";
case 4: return "29.97";
case 5: return "reserved5";
case 6: return "50";
case 7: return "59.94";
default: return rate.ToString();
}
switch (rate)
{
case 0: return "reserved0";
case 1: return "48KHz";
case 2: return "reserved2";
case 3: return "reserved3";
case 4: return "96KHz";
case 5: return "192KHz";
//case 12: return "48/192KHz"; (core/hd)
case 12: return "192KHz";
//case 14: return "48/96KHz"; (core/hd)
case 14: return "96KHz";
default: return rate.ToString();
}
}
}
public string CodecString
{
get
{
switch (coding_type)
{
case 0x01: return "MPEG-1 Video";
case 0x02: return "MPEG-2 Video";
case 0x03: return "MPEG-1 Audio";
case 0x04: return "MPEG-2 Audio";
//case 0x80: return "LPCM";
case 0x80: return "RAW/PCM";
case 0x81: return "AC-3";
case 0x82: return "DTS";
case 0x83: return "TrueHD";
case 0x84: return "AC-3 Plus";
case 0x85: return "DTS-HD";
//case 0x86: return "DTS-HD Master";
case 0x86: return "DTS Master Audio";
case 0xea: return "VC-1";
case 0x1b: return "h264/AVC";
case 0x90: return "Presentation Graphics";
case 0x91: return "Interactive Graphics";
case 0x92: return "Text Subtitle";
default: return coding_type.ToString();
}
}
}
public byte CodingType
{
get
{
return coding_type;
}
}
public byte FormatType
{
get
{
return format;
}
}
public string LanguageString
{
get
{
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (var culture in cultures)
{
// Exclude custom cultures.
if ((culture.CultureTypes & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
continue;
if (culture.ThreeLetterISOLanguageName == lang)
return culture.EnglishName;
}
return lang;
}
}
}
public struct MPLSPlaylistItem
{
public string clip_id;
public byte connection_condition;
public byte stc_id;
public uint in_time;
public uint out_time;
public byte num_video;
public byte num_audio;
public byte num_pg;
public byte num_ig;
public byte num_secondary_audio;
public byte num_secondary_video;
public byte num_pip_pg;
public List<MPLSStream> video;
public List<MPLSStream> audio;
public List<MPLSStream> pg;
}
public struct MPLSHeader
{
public uint type_indicator;
public uint type_indicator2;
public uint list_pos;
public uint mark_pos;
public uint ext_pos;
public ushort list_count;
public ushort sub_count;
public ushort mark_count;
public List<MPLSPlaylistItem> play_item;
public List<MPLSPlaylistMark> play_mark;
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using Newtonsoft.Json;
namespace CUETools.Codecs.MPEG.ATSI
{
[JsonObject(MemberSerialization.OptIn)]
public class DecoderSettings : IAudioDecoderSettings
{
#region IAudioDecoderSettings implementation
[Browsable(false)]
public string Extension => "ifo";
[Browsable(false)]
public string Name => "cuetools";
[Browsable(false)]
public Type DecoderType => typeof(AudioDecoder);
[Browsable(false)]
public int Priority => 2;
public IAudioDecoderSettings Clone()
{
return MemberwiseClone() as IAudioDecoderSettings;
}
#endregion
public DecoderSettings()
{
this.Init();
}
[DefaultValue(true)]
public bool IgnoreShortItems { get; set; }
[Browsable(false)]
public int? Stream { get; set; }
[Browsable(false)]
public int? StreamId { get; set; }
}
}

View File

@@ -8,11 +8,6 @@ namespace CUETools.Codecs.MPEG.BDLPCM
{
public class AudioDecoder : IAudioSource
{
public unsafe AudioDecoder(string path, Stream IO, int pid)
: this(new DecoderSettings() { StreamId = pid }, path, IO)
{
}
public unsafe AudioDecoder(DecoderSettings settings, string path, Stream IO)
{
_path = path;
@@ -38,6 +33,8 @@ namespace CUETools.Codecs.MPEG.BDLPCM
_IO = null;
}
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get

View File

@@ -7,11 +7,6 @@ namespace CUETools.Codecs.MPEG.MPLS
{
public class AudioDecoder : IAudioSource
{
public unsafe AudioDecoder(string path, Stream IO, ushort pid)
: this(new DecoderSettings() { StreamId = pid }, path, IO)
{
}
public unsafe AudioDecoder(DecoderSettings settings, string path, Stream IO)
{
m_settings = settings;
@@ -33,7 +28,7 @@ namespace CUETools.Codecs.MPEG.MPLS
void openEntries()
{
readers = new List<BDLPCM.AudioDecoder>();
readers = new List<IAudioSource>();
var pids = new List<int>();
foreach (var item in hdr_m.play_item)
foreach (var audio in item.audio)
@@ -67,7 +62,8 @@ namespace CUETools.Codecs.MPEG.MPLS
var m2ts = System.IO.Path.Combine(
System.IO.Path.Combine(parent.FullName, "STREAM"),
item.clip_id + ".m2ts");
var entry = new BDLPCM.AudioDecoder(m2ts, null, chosenPid);
var settings = new BDLPCM.DecoderSettings() { StreamId = chosenPid };
var entry = settings.Open(m2ts);
readers.Add(entry);
break;
}
@@ -434,8 +430,8 @@ namespace CUETools.Codecs.MPEG.MPLS
byte[] contents;
AudioPCMConfig pcm;
List<BDLPCM.AudioDecoder> readers;
BDLPCM.AudioDecoder currentReader;
List<IAudioSource> readers;
IAudioSource currentReader;
MPLSHeader hdr_m;
DecoderSettings m_settings;
}

View File

@@ -127,6 +127,11 @@ namespace TTA {
}
}
virtual property TimeSpan Duration {
TimeSpan get() {
return Length < 0 ? TimeSpan::Zero : TimeSpan::FromSeconds((double)Length / PCM->SampleRate);
}
}
virtual property Int64 Length {
Int64 get() {
return _sampleCount;

View File

@@ -252,6 +252,8 @@ namespace CUETools.Codecs.WMA
m_syncReader = null;
}
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get

View File

@@ -191,7 +191,7 @@ namespace CUETools.Codecs.ffmpegdll
//if (stream->duration > 0)
// _sampleCount = stream->duration;
//else
_sampleCount = -1;
_sampleCount = -1;
int bps = stream->codecpar->bits_per_raw_sample != 0 ?
stream->codecpar->bits_per_raw_sample :
@@ -279,6 +279,21 @@ namespace CUETools.Codecs.ffmpegdll
public string Path => _path;
public TimeSpan Duration
{
get
{
// Sadly, duration is unreliable for most codecs.
if (stream->codecpar->codec_id == AVCodecID.AV_CODEC_ID_MLP)
return TimeSpan.Zero;
if (stream->duration > 0)
return TimeSpan.FromSeconds((double)stream->duration / stream->codecpar->sample_rate);
if (fmt_ctx->duration > 0)
return TimeSpan.FromSeconds((double)fmt_ctx->duration / ffmpeg.AV_TIME_BASE);
return TimeSpan.Zero;
}
}
public long Length => _sampleCount;
public long Position

View File

@@ -20,7 +20,7 @@ namespace CUETools.Codecs.libFLAC
public string Name => "libFLAC";
[Browsable(false)]
public Type DecoderType => typeof(Reader);
public Type DecoderType => typeof(AudioDecoder);
[Browsable(false)]
public int Priority => 1;
@@ -37,9 +37,9 @@ namespace CUETools.Codecs.libFLAC
}
}
public unsafe class Reader : IAudioSource
public unsafe class AudioDecoder : IAudioSource
{
public Reader(DecoderSettings settings, string path, Stream IO)
public AudioDecoder(DecoderSettings settings, string path, Stream IO)
{
m_settings = settings;
@@ -306,6 +306,8 @@ namespace CUETools.Codecs.libFLAC
public string Path => m_path;
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length => m_sampleCount;
private int SamplesInBuffer => m_bufferLength - m_bufferOffset;

View File

@@ -99,6 +99,8 @@ namespace CUETools.Codecs.libwavpack
public string Path => _path;
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length => _sampleCount;
public long Position

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;
using Newtonsoft.Json;
using System.IO;
namespace CUETools.Codecs
{
@@ -44,5 +45,10 @@ namespace CUETools.Codecs
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(settings))
property.ResetValue(settings);
}
public static IAudioSource Open(this IAudioDecoderSettings settings, string path, Stream IO = null)
{
return Activator.CreateInstance(settings.DecoderType, settings, path, IO) as IAudioSource;
}
}
}

View File

@@ -54,6 +54,8 @@ namespace CUETools.Codecs
}
}
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get

View File

@@ -27,6 +27,15 @@ namespace CUETools.Codecs.CommandLine
}
}
public TimeSpan Duration
{
get
{
Initialize();
return rdr.Duration;
}
}
public long Length
{
get

View File

@@ -1,4 +1,6 @@
namespace CUETools.Codecs
using System;
namespace CUETools.Codecs
{
public interface IAudioSource
{
@@ -7,7 +9,8 @@
AudioPCMConfig PCM { get; }
string Path { get; }
long Length { get; }
TimeSpan Duration { get; }
long Length { get; }
long Position { get; set; }
long Remaining { get; }

View File

@@ -1,4 +1,6 @@
namespace CUETools.Codecs.NULL
using System;
namespace CUETools.Codecs.NULL
{
public class AudioDecoder : IAudioSource
{
@@ -8,6 +10,8 @@
public IAudioDecoderSettings Settings => null;
public TimeSpan Duration => TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get { return _sampleCount; }

View File

@@ -55,6 +55,8 @@ namespace CUETools.Codecs.WAV
}
}
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get

View File

@@ -162,7 +162,7 @@ namespace CUETools.Converter
AudioBuffer buff = new AudioBuffer(audioSource, 0x10000);
Console.Error.WriteLine("Filename : {0}", sourceFile);
Console.Error.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample, TimeSpan.FromSeconds(audioSource.Length * 1.0 / audioSource.PCM.SampleRate));
Console.Error.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample, audioSource.Duration);
CUEToolsFormat fmt;
if (encoderFormat == null)
@@ -226,15 +226,16 @@ namespace CUETools.Converter
TimeSpan elapsed = DateTime.Now - start;
if ((elapsed - lastPrint).TotalMilliseconds > 60)
{
long length = audioSource.Length;
if (length < 0 && sourceInfo != null) length = (long)(sourceInfo.Properties.Duration.TotalMilliseconds * audioSource.PCM.SampleRate / 1000);
if (length < audioSource.Position) length = audioSource.Position;
if (length < 1) length = 1;
var duration = audioSource.Duration;
var position = TimeSpan.FromSeconds((double)audioSource.Position / audioSource.PCM.SampleRate);
if (duration == TimeSpan.Zero && sourceInfo != null) duration = sourceInfo.Properties.Duration;
if (duration < position) duration = position;
if (duration < TimeSpan.FromSeconds(1)) duration = TimeSpan.FromSeconds(1);
Console.Error.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}",
100.0 * audioSource.Position / length,
audioSource.Position / elapsed.TotalSeconds / audioSource.PCM.SampleRate,
100.0 * position.TotalSeconds / duration.TotalSeconds,
position.TotalSeconds / elapsed.TotalSeconds,
elapsed,
TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * length)
TimeSpan.FromSeconds(elapsed.TotalSeconds / position.TotalSeconds * duration.TotalSeconds)
);
lastPrint = elapsed;
}

View File

@@ -29,6 +29,11 @@ namespace CUETools.DSP.Mixer
set { throw new NotSupportedException(); }
}
public TimeSpan Duration
{
get { throw new NotSupportedException(); }
}
public long Length
{
get { throw new NotSupportedException(); }

View File

@@ -13,6 +13,8 @@ namespace CUETools.Processor
public IAudioDecoderSettings Settings => null;
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get { return _sampleLen; }

View File

@@ -1149,7 +1149,9 @@ namespace CUETools.Ripper.SCSI
return buff.Length;
}
public long Length
public TimeSpan Duration => TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get
{

View File

@@ -56,7 +56,9 @@ namespace CUETools.TestHelpers
{
}
public long Length
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
public long Length
{
get
{

View File

@@ -126,7 +126,6 @@ namespace CUETools.eac3to
var videos = new List<Codecs.MPEG.MPLS.MPLSStream>();
var audios = new List<Codecs.MPEG.MPLS.MPLSStream>();
List<uint> chapters;
TimeSpan duration;
TagLib.UserDefined.AdditionalFileTypes.Config = config;
#if !DEBUG
@@ -147,7 +146,7 @@ namespace CUETools.eac3to
Console.Error.WriteLine("M2TS, {0} video track{1}, {2} audio track{3}, {4}, {5}{6}",
videos.Count, videos.Count > 1 ? "s" : "",
audios.Count, audios.Count > 1 ? "s" : "",
CDImageLayout.TimeToString(mpls.Duration, "{0:0}:{1:00}:{2:00}"), frameRate * (interlaced ? 2 : 1), interlaced ? "i" : "p");
CDImageLayout.TimeToString(audioSource.Duration, "{0:0}:{1:00}:{2:00}"), frameRate * (interlaced ? 2 : 1), interlaced ? "i" : "p");
//foreach (var item in mpls.MPLSHeader.play_item)
//Console.Error.WriteLine("{0}.m2ts", item.clip_id);
{
@@ -178,8 +177,6 @@ namespace CUETools.eac3to
Console.Error.WriteLine("{0}, {1}, {2}, {3}", audio.CodecString, audio.LanguageString, audio.FormatString, audio.RateString);
}
}
duration = mpls.Duration;
}
if (destFile == null)
@@ -323,7 +320,7 @@ namespace CUETools.eac3to
AudioBuffer buff = new AudioBuffer(audioSource, 0x10000);
Console.Error.WriteLine("Filename : {0}", sourceFile);
Console.Error.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample,
duration);
audioSource.Duration);
CUEToolsFormat fmt;
if (encoderFormat == null)
@@ -397,14 +394,15 @@ namespace CUETools.eac3to
TimeSpan elapsed = DateTime.Now - start;
if ((elapsed - lastPrint).TotalMilliseconds > 60)
{
long length = (long)(duration.TotalSeconds * audioSource.PCM.SampleRate);
if (length < audioSource.Position) length = audioSource.Position;
if (length < 1) length = 1;
var duration = audioSource.Duration;
var position = TimeSpan.FromSeconds((double)audioSource.Position / audioSource.PCM.SampleRate);
if (duration < position) duration = position;
if (duration < TimeSpan.FromSeconds(1)) duration = TimeSpan.FromSeconds(1);
Console.Error.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}",
100.0 * audioSource.Position / length,
audioSource.Position / elapsed.TotalSeconds / audioSource.PCM.SampleRate,
100.0 * position.TotalSeconds / duration.TotalSeconds,
position.TotalSeconds / elapsed.TotalSeconds,
elapsed,
TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * length)
TimeSpan.FromSeconds(elapsed.TotalSeconds / position.TotalSeconds * duration.TotalSeconds)
);
lastPrint = elapsed;
}

View File

@@ -228,10 +228,11 @@ namespace BluTools
void workerExtract_DoWork(object sender, DoWorkEventArgs e)
{
CUETools.Codecs.MPEG.MPLS.AudioDecoder reader = null;
IAudioSource reader = null;
try
{
reader = new CUETools.Codecs.MPEG.MPLS.AudioDecoder(chosenReader.Path, null, pid);
var decoderSettings = new CUETools.Codecs.MPEG.MPLS.DecoderSettings() { StreamId = pid };
reader = decoderSettings.Open(chosenReader.Path);
Directory.CreateDirectory(outputFolderPath);
if (File.Exists(outputCuePath)) throw new Exception(string.Format("File \"{0}\" already exists", outputCuePath));
if (File.Exists(outputAudioPath)) throw new Exception(string.Format("File \"{0}\" already exists", outputAudioPath));

View File

@@ -49,7 +49,7 @@ namespace CUETools.TestCodecs
[TestMethod()]
public void SeekTest()
{
var r = new CUETools.Codecs.libFLAC.Reader(new Codecs.libFLAC.DecoderSettings(), "test.flac", null);
var r = new Codecs.libFLAC.DecoderSettings().Open("test.flac", null);
var buff1 = new AudioBuffer(r, 16536);
var buff2 = new AudioBuffer(r, 16536);
Assert.AreEqual(0, r.Position);