diff --git a/CUETools.Codecs.MPEG/ATSI/AudioDecoder.cs b/CUETools.Codecs.MPEG/ATSI/AudioDecoder.cs index c6adee5..f559aa3 100644 --- a/CUETools.Codecs.MPEG/ATSI/AudioDecoder.cs +++ b/CUETools.Codecs.MPEG/ATSI/AudioDecoder.cs @@ -6,7 +6,7 @@ using static CUETools.Codecs.AudioPCMConfig; namespace CUETools.Codecs.MPEG.ATSI { - public class AudioDecoder : IAudioSource, IAudioContainer + public class AudioDecoder : IAudioSource, IAudioTitleSet { public unsafe AudioDecoder(DecoderSettings settings, string path, Stream IO) { @@ -331,7 +331,7 @@ namespace CUETools.Codecs.MPEG.ATSI public ushort codec; public uint format; - public byte StreamId + public int StreamId { get { @@ -342,64 +342,6 @@ namespace CUETools.Codecs.MPEG.ATSI } } - public string CodecString - { - get - { - switch (StreamId) - { - case DVDA.PCM_STREAM_ID: return "RAW/PCM"; - case DVDA.MLP_STREAM_ID: return "MLP"; - default: return StreamId.ToString(); - } - //switch (codec) - //{ - // case 0x000: return "RAW/PCM"; - // case 0x100: return "MLP"; - // default: return codec.ToString(); - //} - } - } - - public AudioPCMConfig PCM - { - get - { - if (track_sector.Count < 1) return null; - if (track_sector[0].dvdaBlock == null) return null; - return new AudioPCMConfig( - track_sector[0].dvdaBlock.gr1_bits, - track_sector[0].dvdaBlock.channels, - track_sector[0].dvdaBlock.gr1_frequency); - } - } - - public string RateString - { - get - { - var sr = PCM.SampleRate; - if (sr % 1000 == 0) return $"{sr / 1000}KHz"; - if (sr % 100 == 0) return $"{sr / 100}.{(sr / 100) % 10}KHz"; - return $"{sr}Hz"; - } - } - - public string FormatString - { - get - { - if (track_sector.Count < 1) return "?"; - if (track_sector[0].dvdaBlock == null) return "?"; - switch (track_sector[0].dvdaBlock.ch_assignment) - { - case 0: return "mono"; - case 1: return "stereo"; - default: return "multi-channel"; - } - } - } - public List Chapters { get @@ -436,6 +378,40 @@ namespace CUETools.Codecs.MPEG.ATSI } } + public AudioPCMConfig PCM + { + get + { + if (track_sector.Count < 1) return null; + if (track_sector[0].dvdaBlock == null) return null; + return new AudioPCMConfig( + track_sector[0].dvdaBlock.gr1_bits, + track_sector[0].dvdaBlock.channels, + track_sector[0].dvdaBlock.gr1_frequency); + } + } + + public string Codec + { + get + { + switch (StreamId) + { + case DVDA.PCM_STREAM_ID: return "RAW/PCM"; + case DVDA.MLP_STREAM_ID: return "MLP"; + default: return StreamId.ToString(); + } + //switch (codec) + //{ + // case 0x000: return "RAW/PCM"; + // case 0x100: return "MLP"; + // default: return codec.ToString(); + //} + } + } + + public string Language => ""; + public List track_timestamp; public List track_sector; } diff --git a/CUETools.Codecs.MPEG/MPLS/AudioDecoder.cs b/CUETools.Codecs.MPEG/MPLS/AudioDecoder.cs index 07aec49..61798ab 100644 --- a/CUETools.Codecs.MPEG/MPLS/AudioDecoder.cs +++ b/CUETools.Codecs.MPEG/MPLS/AudioDecoder.cs @@ -5,7 +5,7 @@ using System.IO; namespace CUETools.Codecs.MPEG.MPLS { - public class AudioDecoder : IAudioSource, IAudioContainer + public class AudioDecoder : IAudioSource, IAudioTitleSet { public unsafe AudioDecoder(DecoderSettings settings, string path, Stream IO) { @@ -392,7 +392,7 @@ namespace CUETools.Codecs.MPEG.MPLS foreach (var item in hdr_m.play_item) foreach (var audio in item.audio) { - if (audio.coding_type != 0x80 /* LPCM */) continue; + //if (audio.coding_type != 0x80 /* LPCM */) continue; titles.Add(new AudioTitle(this, audio.pid)); } return titles; @@ -461,6 +461,44 @@ namespace CUETools.Codecs.MPEG.MPLS } public List Chapters => source.Chapters; + public AudioPCMConfig PCM + { + get + { + var s = FirstStream; + int channelCount = s.format == 1 ? 1 : s.format == 3 ? 2 : s.format == 6 ? 5 : 0; + int sampleRate = s.rate == 1 ? 48000 : s.rate == 4 ? 96000 : s.rate == 5 ? 192000 : s.rate == 12 ? 192000 : s.rate == 14 ? 96000 : 0; + int bitsPerSample = 0; + return new AudioPCMConfig(bitsPerSample, channelCount, sampleRate); + } + } + public string Codec + { + get + { + var s = FirstStream; + return s != null ? s.CodecString : "?"; + } + } + public string Language + { + get + { + var s = FirstStream; + return s != null ? s.LanguageString : "?"; + } + } + public int StreamId => pid; + + MPLSStream FirstStream + { + get + { + MPLSStream result = null; + source.MPLSHeader.play_item.ForEach(i => i.audio.FindAll(a => a.pid == pid).ForEach(x => result = x)); + return result; + } + } AudioDecoder source; int pid; @@ -476,7 +514,7 @@ namespace CUETools.Codecs.MPEG.MPLS public uint duration; } - public struct MPLSStream + public class MPLSStream { public byte stream_type; public byte coding_type; diff --git a/CUETools.Codecs.MPEG/TsStream.cs b/CUETools.Codecs.MPEG/TsStream.cs index 040f62b..7c95f50 100644 --- a/CUETools.Codecs.MPEG/TsStream.cs +++ b/CUETools.Codecs.MPEG/TsStream.cs @@ -56,13 +56,4 @@ namespace CUETools.Codecs.MPEG savedBufferSize = 0; } }; - - public class AudioDescription - { - public int StreamId; - public string CodecString; - public string LanguageString; - public string FormatString; - public string RateString; - }; } diff --git a/CUETools.Codecs/IAudioSource.cs b/CUETools.Codecs/IAudioSource.cs index 472e8f1..50ecd40 100644 --- a/CUETools.Codecs/IAudioSource.cs +++ b/CUETools.Codecs/IAudioSource.cs @@ -22,25 +22,61 @@ namespace CUETools.Codecs public interface IAudioTitle { List Chapters { get; } + AudioPCMConfig PCM { get; } + string Codec { get; } + string Language { get; } + int StreamId { get; } //IAudioSource Open { get; } } - public interface IAudioContainer + public interface IAudioTitleSet { List AudioTitles { get; } } - public class NoContainerAudioTitle : IAudioTitle + public static class IAudioTitleExtensions { - public NoContainerAudioTitle(IAudioSource source) { this.source = source; } + public static TimeSpan GetDuration(this IAudioTitle title) + { + var chapters = title.Chapters; + return chapters[chapters.Count - 1]; + } + + + public static string GetRateString(this IAudioTitle title) + { + var sr = title.PCM.SampleRate; + if (sr % 1000 == 0) return $"{sr / 1000}KHz"; + if (sr % 100 == 0) return $"{sr / 100}.{(sr / 100) % 10}KHz"; + return $"{sr}Hz"; + } + + public static string GetFormatString(this IAudioTitle title) + { + switch (title.PCM.ChannelCount) + { + case 1: return "mono"; + case 2: return "stereo"; + default: return "multi-channel"; + } + } + } + + public class SingleAudioTitle : IAudioTitle + { + public SingleAudioTitle(IAudioSource source) { this.source = source; } public List Chapters => new List { TimeSpan.Zero, source.Duration }; + public AudioPCMConfig PCM => source.PCM; + public string Codec => source.Settings.Extension; + public string Language => ""; + public int StreamId => 0; IAudioSource source; } - public class NoContainer : IAudioContainer + public class SingleAudioTitleSet : IAudioTitleSet { - public NoContainer(IAudioSource source) { this.source = source; } - public List AudioTitles => new List { new NoContainerAudioTitle(source) }; + public SingleAudioTitleSet(IAudioSource source) { this.source = source; } + public List AudioTitles => new List { new SingleAudioTitle(source) }; IAudioSource source; } } diff --git a/CUETools.eac3to/Program.cs b/CUETools.eac3to/Program.cs index e2478d9..7d7f76b 100644 --- a/CUETools.eac3to/Program.cs +++ b/CUETools.eac3to/Program.cs @@ -130,10 +130,10 @@ namespace CUETools.eac3to #endif { IAudioSource audioSource = null; - IAudioContainer audioContainer = null; + IAudioTitleSet audioContainer = null; IAudioDest audioDest = null; var videos = new List(); - var audios = new List(); + List audios = null; List chapters = null; TagLib.UserDefined.AdditionalFileTypes.Config = config; @@ -160,29 +160,23 @@ namespace CUETools.eac3to TypeDescriptor.GetConverter(property.PropertyType).ConvertFromString(decOpt.Value)); } audioSource = decoderSettings.Open(sourceFile); - audioContainer = audioSource as IAudioContainer; - if (audioContainer == null) audioContainer = new NoContainer(audioSource); + audioContainer = audioSource as IAudioTitleSet; + if (audioContainer == null) audioContainer = new SingleAudioTitleSet(audioSource); Console.ForegroundColor = ConsoleColor.White; int frameRate = 0; bool interlaced = false; - audioContainer.AudioTitles.ForEach(t => chapters = t.Chapters); + audios = audioContainer.AudioTitles; + audios.ForEach(t => chapters = t.Chapters); if (audioSource is Codecs.MPEG.MPLS.AudioDecoder) { var mpls = audioSource as Codecs.MPEG.MPLS.AudioDecoder; mpls.MPLSHeader.play_item.ForEach(i => i.video.ForEach(v => { if (!videos.Exists(v1 => v1.pid == v.pid)) videos.Add(v); })); - mpls.MPLSHeader.play_item.ForEach(i => i.audio.ForEach(v => { if (!audios.Exists(v1 => v1.StreamId == v.pid)) audios.Add(new Codecs.MPEG.AudioDescription() { StreamId = v.pid, CodecString = v.CodecString, LanguageString = v.LanguageString, FormatString = v.FormatString, RateString = v.RateString }); })); - } - else - if (audioSource is Codecs.MPEG.ATSI.AudioDecoder) - { - var atsi = audioSource as Codecs.MPEG.ATSI.AudioDecoder; - atsi.ATSIHeader.titles.ForEach(t => audios.Add(new Codecs.MPEG.AudioDescription() { StreamId = 0/*!*/, CodecString = t.CodecString, FormatString = t.FormatString, RateString = t.RateString })); } videos.ForEach(v => { frameRate = v.FrameRate; interlaced = v.Interlaced; }); Console.Error.Write($@"M2TS, { videos.Count} video track{(videos.Count != 1 ? "s" : "")}, { audios.Count} audio track{(audios.Count != 1 ? "s" : "")}, { - CDImageLayout.TimeToString(audioSource.Duration, "{0:0}:{1:00}:{2:00}")}, { + CDImageLayout.TimeToString(audios[0].GetDuration(), "{0:0}:{1:00}:{2:00}")}, { (frameRate * (interlaced ? 2 : 1))}{ (interlaced ? "i" : "p")}"); Console.Error.WriteLine(); @@ -213,7 +207,7 @@ namespace CUETools.eac3to Console.Error.Write(id++); Console.Error.Write(": "); Console.ForegroundColor = ConsoleColor.Gray; - Console.Error.WriteLine("{0}, {1}, {2}, {3}", audio.CodecString, audio.LanguageString, audio.FormatString, audio.RateString); + Console.Error.WriteLine("{0}, {1}, {2}, {3}", audio.Codec, audio.Language, audio.GetFormatString(), audio.GetRateString()); } } }