示例#1
0
        public virtual long GetLength(EncoderItem encoderItem, IBassStream stream)
        {
            var source      = default(int);
            var channelInfo = default(ChannelInfo);
            var inputLength = stream.Length;

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            if (channelInfo.Flags.HasFlag(BassFlags.Float))
            {
                source = DEPTH_32;
            }
            else
            {
                source = DEPTH_16;
            }
            var outputLength = (long)(inputLength / (source / (float)this.GetDepth(encoderItem, stream)));

            if (inputLength != outputLength)
            {
                Logger.Write(this, LogLevel.Debug, "Conversion requires change of data length: {0} bytes => {1} bytes.", inputLength, outputLength);
            }
            return(outputLength);
        }
示例#2
0
        public override string GetArguments(EncoderItem encoderItem, IBassStream stream)
        {
            var channelInfo = default(ChannelInfo);

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            var depth = this.Settings.GetDepth(encoderItem, stream);

            if (channelInfo.Flags.HasFlag(BassFlags.Float))
            {
                Logger.Write(this.GetType(), LogLevel.Debug, "Resampling file \"{0}\" from 32 bit float to {1} bit integer.", encoderItem.InputFileName, depth);
                return(string.Format(
                           "-t raw -e floating-point --bits 32 -r {0} -c {1} - -t raw -e signed-integer --bits {2} -r {0} -c {1} -",
                           channelInfo.Frequency,
                           channelInfo.Channels,
                           depth
                           ));
            }
            else
            {
                Logger.Write(this.GetType(), LogLevel.Debug, "Resampling file \"{0}\" from 16 bit integer to {1} bit integer.", encoderItem.InputFileName, depth);
                return(string.Format(
                           "-t raw -e signed-integer --bits 16 -r {0} -c {1} - -t raw -e signed-integer --bits {2} -r {0} -c {1} -",
                           channelInfo.Frequency,
                           channelInfo.Channels,
                           depth
                           ));
            }
        }
示例#3
0
        public static EncoderItem Create(string inputFileName, string outputFileName, IList <MetaDataItem> metaDatas, string profile)
        {
            var encoderItem = new EncoderItem()
            {
                InputFileName  = inputFileName,
                OutputFileName = outputFileName,
                Profile        = profile
            };

            if (metaDatas != null)
            {
                var metaData = default(IDictionary <string, string>);
                lock (metaDatas)
                {
                    metaData = metaDatas.ToDictionary(
                        metaDataItem => metaDataItem.Name,
                        metaDataItem => metaDataItem.Value,
                        StringComparer.OrdinalIgnoreCase
                        );
                }
                encoderItem.Bitrate       = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioBitrate));
                encoderItem.Channels      = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioChannels));
                encoderItem.SampleRate    = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioSampleRate));
                encoderItem.BitsPerSample = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.BitsPerSample));
            }
            return(encoderItem);
        }
示例#4
0
 protected virtual void EncodeWithResampler(EncoderItem encoderItem, IBassStream stream, IBassEncoderSettings settings)
 {
     using (var resamplerProcess = this.CreateResamplerProcess(encoderItem, stream, new SoxEncoderSettings(settings)))
     {
         using (var encoderProcess = this.CreateEncoderProcess(encoderItem, stream, settings))
         {
             var success = true;
             this.EncodeWithResampler(encoderItem, stream, resamplerProcess, encoderProcess);
             if (this.WaitForExit(resamplerProcess))
             {
                 if (resamplerProcess.ExitCode != 0)
                 {
                     success = false;
                 }
             }
             if (this.WaitForExit(encoderProcess))
             {
                 if (encoderProcess.ExitCode != 0)
                 {
                     success = false;
                 }
             }
             if (!success)
             {
                 throw new InvalidOperationException("Process does not indicate success.");
             }
         }
     }
 }
示例#5
0
 public virtual int GetDepth(EncoderItem encoderItem, IBassStream stream)
 {
     if (this.Format.AutoDepth)
     {
         switch (encoderItem.BitsPerSample)
         {
         case DEPTH_16:
         case DEPTH_24:
         case DEPTH_32:
             Logger.Write(this, LogLevel.Debug, "Using meta data suggested bit depth for file \"{0}\": {1} bit", encoderItem.InputFileName, encoderItem.BitsPerSample);
             return(encoderItem.BitsPerSample);
         }
         var channelInfo = default(ChannelInfo);
         if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
         {
             throw new NotImplementedException();
         }
         if (channelInfo.Flags.HasFlag(BassFlags.Float))
         {
             Logger.Write(this, LogLevel.Debug, "Using decoder bit depth for file \"{0}\": 32 bit", encoderItem.InputFileName);
             return(DEPTH_32);
         }
         else
         {
             Logger.Write(this, LogLevel.Debug, "Using decoder bit depth for file \"{0}\": 16 bit", encoderItem.InputFileName);
             return(DEPTH_16);
         }
     }
     Logger.Write(this, LogLevel.Debug, "Using user defined bit depth for file \"{0}\": {1} bit", encoderItem.InputFileName, this.Format.Depth);
     return(this.Format.Depth);
 }
示例#6
0
        public override string GetArguments(EncoderItem encoderItem, IBassStream stream)
        {
            var channelInfo = default(ChannelInfo);

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            var length    = this.GetLength(encoderItem, stream);
            var arguments = string.Format(
                "--no-seektable --force-raw-format --endian=little --sign=signed --sample-rate={0} --channels={1} --bps={2} - --compression-level-{3} -o \"{4}\"",
                channelInfo.Frequency,
                channelInfo.Channels,
                this.GetDepth(encoderItem, stream),
                this.Compression,
                encoderItem.OutputFileName
                );

            if (this.IgnoreErrors)
            {
                arguments += " --decode-through-errors";
            }
            else
            {
                arguments += string.Format(
                    "--input-size={0}",
                    length
                    );
            }
            return(arguments);
        }
示例#7
0
 protected virtual Action <Exception> GetErrorHandler(EncoderItem encoderItem)
 {
     return(e =>
     {
         Logger.Write(this, LogLevel.Warn, "Encoder background thread for file \"{0}\" error: {1}", encoderItem.InputFileName, e.Message);
         encoderItem.AddError(e.Message);
     });
 }
示例#8
0
 protected virtual void OnStatusChanged(EncoderItem encoderItem)
 {
     if (this.StatusChanged == null)
     {
         return;
     }
     this.StatusChanged(this, new BassEncoderMonitorEventArgs(encoderItem));
 }
示例#9
0
 public EncodePlaylistItemsTask(BassEncoderBehaviour behaviour, PlaylistItem[] playlistItems) : this()
 {
     this.Behaviour     = behaviour;
     this.PlaylistItems = playlistItems;
     this.EncoderItems  = playlistItems
                          .OrderBy(playlistItem => playlistItem.FileName)
                          .Select(playlistItem => EncoderItem.FromPlaylistItem(playlistItem))
                          .ToArray();
 }
示例#10
0
        protected virtual void UpdateStatus(EncoderItem encoderItem)
        {
            var currentEncoderItem = default(EncoderItem);

                                             if (this.EncoderItems.TryGetValue(encoderItem.Id, out currentEncoderItem) && currentEncoderItem.Status != encoderItem.Status)
            {
                Logger.Write(this, LogLevel.Debug, "Encoder status changed for file \"{0}\": {1}", encoderItem.InputFileName, Enum.GetName(typeof(EncoderItemStatus), encoderItem.Status));
                this.OnStatusChanged(encoderItem);
            }
                                             this.EncoderItems[encoderItem.Id] = encoderItem;
        }
示例#11
0
 public override string GetArguments(EncoderItem encoderItem, IBassStream stream)
 {
     return(string.Format(
                "-i -q -y --raw-pcm={0} {1} -x{2} {3} - \"{4}\"",
                this.GetFormat(encoderItem, stream),
                this.GetCompression(),
                this.Processing,
                this.GetHybrid(),
                encoderItem.OutputFileName
                ));
 }
示例#12
0
        protected virtual void Encode(EncoderItem encoderItem, IBassEncoderSettings settings)
        {
            var flags = BassFlags.Decode;

            if (this.ShouldDecodeFloat(encoderItem, settings))
            {
                Logger.Write(this, LogLevel.Debug, "Decoding file \"{0}\" in high quality mode (32 bit floating point).", encoderItem.InputFileName);
                flags |= BassFlags.Float;
            }
            else
            {
                Logger.Write(this, LogLevel.Debug, "Decoding file \"{0}\" in standaed quality mode (16 bit integer).", encoderItem.InputFileName);
            }
            var stream = this.CreateStream(encoderItem.InputFileName, flags);

            if (stream.IsEmpty)
            {
                Logger.Write(this, LogLevel.Debug, "Failed to create stream for file \"{0}\": Unknown error.", encoderItem.InputFileName);
                return;
            }
            Logger.Write(this, LogLevel.Debug, "Created stream for file \"{0}\": {1}", encoderItem.InputFileName, stream.ChannelHandle);
            try
            {
                if (flags.HasFlag(BassFlags.Float))
                {
                    this.EncodeWithResampler(encoderItem, stream, settings);
                }
                else
                {
                    this.Encode(encoderItem, stream, settings);
                }
            }
            finally
            {
                Logger.Write(this, LogLevel.Debug, "Releasing stream for file \"{0}\": {1}", encoderItem.InputFileName, stream.ChannelHandle);
                Bass.StreamFree(stream.ChannelHandle); //Not checking result code as it contains an error if the application is shutting down.
            }
            if (this.CancellationToken.IsCancellationRequested)
            {
                encoderItem.Status = EncoderItemStatus.Cancelled;
                if (File.Exists(encoderItem.OutputFileName))
                {
                    Logger.Write(this, LogLevel.Debug, "Deleting incomplete output \"{0}\": Cancelled.", encoderItem.OutputFileName);
                    File.Delete(encoderItem.OutputFileName);
                }
            }
            else
            {
                encoderItem.Status = EncoderItemStatus.Complete;
            }
        }
示例#13
0
 protected virtual void Encode(EncoderItem encoderItem, IBassStream stream, IBassEncoderSettings settings)
 {
     using (var encoderProcess = this.CreateEncoderProcess(encoderItem, stream, settings))
     {
         this.Encode(encoderItem, stream, encoderProcess);
         if (this.WaitForExit(encoderProcess))
         {
             if (encoderProcess.ExitCode != 0)
             {
                 throw new InvalidOperationException("Process does not indicate success.");
             }
         }
     }
 }
示例#14
0
        protected virtual string GetFormat(EncoderItem encoderItem, IBassStream stream)
        {
            var channelInfo = default(ChannelInfo);

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            return(string.Format(
                       "{0},{1}s,{2},le",
                       channelInfo.Frequency,
                       this.GetDepth(encoderItem, stream),
                       channelInfo.Channels
                       ));
        }
示例#15
0
 protected virtual bool ShouldDecodeFloat(EncoderItem encoderItem, IBassEncoderSettings settings)
 {
     if (encoderItem.BitsPerSample == 1)
     {
         Logger.Write(this, LogLevel.Debug, "Suggesting high quality mode for file \"{0}\": dsd.", encoderItem.InputFileName);
         return(true);
     }
     if (encoderItem.BitsPerSample > 16 || settings.Format.Depth > 16)
     {
         Logger.Write(this, LogLevel.Debug, "Suggesting high quality mode for file \"{0}\": >16 bit.", encoderItem.InputFileName);
         return(true);
     }
     Logger.Write(this, LogLevel.Debug, "Suggesting standard quality mode for file \"{0}\": <=16 bit.", encoderItem.InputFileName);
     return(false);
 }
示例#16
0
        protected virtual string GetDescription(EncoderItem encoderItem)
        {
            var builder = new StringBuilder();

            builder.AppendFormat("{0} -> {1}", encoderItem.InputFileName, encoderItem.OutputFileName);
            if (encoderItem.Status != EncoderItemStatus.Complete && encoderItem.Errors.Any())
            {
                builder.Append(Environment.NewLine);
                foreach (var error in encoderItem.Errors)
                {
                    builder.Append("\t");
                    builder.Append(error);
                }
            }
            return(builder.ToString());
        }
示例#17
0
        public override int GetDepth(EncoderItem encoderItem, IBassStream stream)
        {
            var depth = base.GetDepth(encoderItem, stream);

            if (depth < DEPTH_16)
            {
                Logger.Write(this.GetType(), LogLevel.Warn, "Requsted bit depth {0} is invalid, using minimum: 16 bit", depth);
                return(DEPTH_16);
            }
            if (depth > DEPTH_32)
            {
                Logger.Write(this.GetType(), LogLevel.Warn, "Requsted bit depth {0} is invalid, using maximum: 32 bit", depth);
                return(DEPTH_32);
            }
            return(depth);
        }
示例#18
0
        public static EncoderItem FromPlaylistItem(PlaylistItem playlistItem)
        {
            var encoderItem = new EncoderItem()
            {
                InputFileName = playlistItem.FileName
            };

            if (playlistItem.MetaDatas != null)
            {
                var metaData = playlistItem.MetaDatas.ToDictionary(metaDataItem => metaDataItem.Name, metaDataItem => metaDataItem.Value, StringComparer.OrdinalIgnoreCase);
                encoderItem.Bitrate       = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioBitrate));
                encoderItem.Channels      = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioChannels));
                encoderItem.SampleRate    = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.AudioSampleRate));
                encoderItem.BitsPerSample = Convert.ToInt32(metaData.GetValueOrDefault(CommonProperties.BitsPerSample));
            }
            return(encoderItem);
        }
        public override string GetArguments(EncoderItem encoderItem, IBassStream stream)
        {
            var channelInfo = default(ChannelInfo);

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            return(string.Format(
                       "--alac --raw --raw-rate {0} --raw-channels {1} --raw-format {2} - --bits-per-sample {3} -o \"{4}\"",
                       channelInfo.Frequency,
                       channelInfo.Channels,
                       this.GetFormat(encoderItem, stream),
                       this.GetDepth(encoderItem, stream),
                       encoderItem.OutputFileName
                       ));
        }
示例#20
0
        public override string GetArguments(EncoderItem encoderItem, IBassStream stream)
        {
            var channelInfo = default(ChannelInfo);

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            return(string.Format(
                       "--quiet --raw --raw-rate={0} --raw-chan={1} --raw-bits={2} --raw-endianness=0 - --quality={3} -o \"{4}\"",
                       channelInfo.Frequency,
                       channelInfo.Channels,
                       this.GetDepth(encoderItem, stream),
                       this.Quality,
                       encoderItem.OutputFileName
                       ));
        }
示例#21
0
        public override string GetArguments(EncoderItem encoderItem, IBassStream stream)
        {
            var channelInfo = default(ChannelInfo);

            if (!Bass.ChannelGetInfo(stream.ChannelHandle, out channelInfo))
            {
                throw new NotImplementedException();
            }
            return(string.Format(
                       "--silent -r --little-endian --signed -s {0} -m {1} --bitwidth {2} - --cbr -b {3} \"{4}\"",
                       channelInfo.Frequency,
                       this.GetStereoMode(channelInfo.Channels),
                       this.GetDepth(encoderItem, stream),
                       this.Bitrate,
                       encoderItem.OutputFileName
                       ));
        }
示例#22
0
        protected virtual Process CreateEncoderProcess(EncoderItem encoderItem, IBassStream stream, IBassEncoderSettings settings)
        {
            Logger.Write(this, LogLevel.Debug, "Creating encoder process for file \"{0}\".", encoderItem.InputFileName);
            var arguments = settings.GetArguments(encoderItem, stream);
            var process   = this.CreateProcess(
                encoderItem,
                stream,
                settings.Executable,
                settings.Directory,
                arguments,
                true,
                false,
                true
                );

            Logger.Write(this, LogLevel.Debug, "Created encoder process for file \"{0}\": \"{1}\" {2}", encoderItem.InputFileName, settings.Executable, arguments);
            return(process);
        }
示例#23
0
 protected virtual async Task CopyTags(EncoderItem encoderItem)
 {
     try
     {
         Logger.Write(this, LogLevel.Debug, "Copying tags from \"{0}\" to \"{1}\".", encoderItem.InputFileName, encoderItem.OutputFileName);
         var fileData = this.GetFileData(encoderItem);
         using (var task = new WriteFileMetaDataTask(encoderItem.OutputFileName, fileData.MetaDatas))
         {
             task.InitializeComponent(this.Core);
             await task.Run().ConfigureAwait(false);
         }
     }
     catch (Exception e)
     {
         Logger.Write(this, LogLevel.Warn, "Failed to copy tags from \"{0}\" to \"{1}\": {2}", encoderItem.InputFileName, encoderItem.OutputFileName, e.Message);
         await this.OnError(e).ConfigureAwait(false);
     }
 }
示例#24
0
        protected virtual void Encode(EncoderItem encoderItem, IBassStream stream, Process encoderProcess)
        {
            var channelReader = new ChannelReader(encoderItem, stream);
            var encoderWriter = new ProcessWriter(encoderProcess);
            var thread        = new Thread(() =>
            {
                this.Try(() => channelReader.CopyTo(encoderWriter, this.CancellationToken), this.GetErrorHandler(encoderItem));
            })
            {
                Name         = string.Format("ChannelReader(\"{0}\", {1})", encoderItem.InputFileName, stream.ChannelHandle),
                IsBackground = true
            };

            Logger.Write(this, LogLevel.Debug, "Starting background thread for file \"{0}\".", encoderItem.InputFileName);
            thread.Start();
            Logger.Write(this, LogLevel.Debug, "Completing background thread for file \"{0}\".", encoderItem.InputFileName);
            this.Join(thread);
            encoderWriter.Close();
        }
示例#25
0
        protected virtual Process CreateProcess(EncoderItem encoderItem, IBassStream stream, string executable, string directory, string arguments, bool redirectStandardInput, bool redirectStandardOutput, bool redirectStandardError)
        {
            if (!File.Exists(executable))
            {
                throw new InvalidOperationException(string.Format("A required utility was not found: {0}", executable));
            }
            var processStartInfo = new ProcessStartInfo()
            {
                FileName               = executable,
                WorkingDirectory       = directory,
                Arguments              = arguments,
                RedirectStandardInput  = redirectStandardInput,
                RedirectStandardOutput = redirectStandardOutput,
                RedirectStandardError  = redirectStandardError,
                UseShellExecute        = false,
                CreateNoWindow         = true
            };
            var process = Process.Start(processStartInfo);

            try
            {
                process.PriorityClass = ProcessPriorityClass.BelowNormal;
            }
            catch
            {
                //Nothing can be done, probably access denied.
            }
            process.ErrorDataReceived += (sender, e) =>
            {
                if (string.IsNullOrEmpty(e.Data))
                {
                    return;
                }
                Logger.Write(this, LogLevel.Trace, "{0}: {1}", executable, e.Data);
                encoderItem.AddError(e.Data);
            };
            process.BeginErrorReadLine();
            return(process);
        }
示例#26
0
 public BassEncoderMonitorEventArgs(EncoderItem encoderItem)
 {
     this.EncoderItem = encoderItem;
 }
示例#27
0
 public override int GetDepth(EncoderItem encoderItem, IBassStream stream)
 {
     return(DEPTH_16);
 }
示例#28
0
 protected virtual IFileData GetFileData(EncoderItem encoderItem)
 {
     return(this.FileDatas.FirstOrDefault(fileData => string.Equals(fileData.FileName, encoderItem.InputFileName, StringComparison.OrdinalIgnoreCase)));
 }
示例#29
0
        public EncoderItem Create(IFileData[] fileDatas, IFileData fileData, string profile)
        {
            var outputFileName = this.GetOutputFileName(fileDatas, fileData, profile);

            return(EncoderItem.Create(fileData.FileName, outputFileName, fileData.MetaDatas, profile));
        }
示例#30
0
 public ReportRow(Guid id, EncoderItem encoderItem)
 {
     this.Id          = id;
     this.EncoderItem = encoderItem;
 }