Exemple #1
0
        static void UpdateMetadata(NativeMetadataIterator iterator, NativeVorbisCommentBlock newComments, NativePictureBlock newPicture)
        {
            Contract.Requires(iterator != null);
            Contract.Requires(newComments != null);

            var metadataInserted = false;
            var pictureInserted  = false;

            do
            {
                switch ((MetadataType)Marshal.ReadInt32(iterator.GetBlock()))
                {
                // Replace the existing Vorbis comment:
                case MetadataType.VorbisComment:
                    if (!iterator.DeleteBlock(false))
                    {
                        throw new IOException(Resources.MetadataEncoderDeleteError);
                    }
                    if (!iterator.InsertBlockAfter(newComments.Handle))
                    {
                        throw new IOException(Resources.MetadataEncoderInsertBlockError);
                    }
                    metadataInserted = true;
                    break;

                // Replace the existing Picture block:
                case MetadataType.Picture:
                    if (!iterator.DeleteBlock(false))
                    {
                        throw new IOException(Resources.MetadataEncoderDeleteError);
                    }
                    if (newPicture != null && !iterator.InsertBlockAfter(newPicture.Handle))
                    {
                        throw new IOException(Resources.MetadataEncoderInsertBlockError);
                    }
                    pictureInserted = true;
                    break;

                // Delete any padding:
                case MetadataType.Padding:
                    if (!iterator.DeleteBlock(false))
                    {
                        throw new IOException(Resources.MetadataEncoderDeleteError);
                    }
                    break;
                }
            } while (iterator.Next());

            // If there was no existing metadata block to replace, insert it now:
            if (!metadataInserted && !iterator.InsertBlockAfter(newComments.Handle))
            {
                throw new IOException(Resources.MetadataEncoderInsertBlockError);
            }

            // If there was no existing picture block to replace, and a new one is available, insert it now:
            if (newPicture != null && !pictureInserted && !iterator.InsertBlockAfter(newPicture.Handle))
            {
                throw new IOException(Resources.MetadataEncoderInsertBlockError);
            }

            newComments.ReleaseHandleOwnership();
            newPicture?.ReleaseHandleOwnership();
        }
Exemple #2
0
        public void WriteMetadata(Stream stream, MetadataDictionary metadata, SettingsDictionary settings)
        {
            bool usePadding;

            if (string.IsNullOrEmpty(settings["UsePadding"]))
            {
                usePadding = false;
            }
            else if (!bool.TryParse(settings["UsePadding"], out usePadding))
            {
                throw new InvalidSettingException(string.Format(CultureInfo.CurrentCulture,
                                                                Resources.MetadataEncoderBadUsePadding, settings["UsePadding"]));
            }

            NativeVorbisCommentBlock vorbisCommentBlock = null;
            NativePictureBlock       pictureBlock       = null;

            try
            {
                using (var chain = new NativeMetadataChain(stream))
                {
                    if (!chain.Read())
                    {
                        MetadataChainStatus chainStatus = chain.GetStatus();
                        if (chainStatus == MetadataChainStatus.NotAFlacFile)
                        {
                            throw new UnsupportedAudioException(Resources.MetadataEncoderNotFlacError);
                        }
                        else
                        {
                            throw new IOException(string.Format(CultureInfo.CurrentCulture,
                                                                Resources.MetadataEncoderReadError, chainStatus));
                        }
                    }

                    // Create a Vorbis Comment block, even if empty:
                    vorbisCommentBlock = new NativeVorbisCommentBlock();
                    foreach (var item in new MetadataToVorbisCommentAdapter(metadata))
                    {
                        vorbisCommentBlock.Append(item.Key, item.Value);
                    }

                    // Create a Picture block if cover art is available:
                    if (metadata.CoverArt != null)
                    {
                        pictureBlock = new CoverArtToPictureBlockAdapter(metadata.CoverArt);
                    }

                    // Iterate over the existing blocks, replacing and deleting as needed:
                    using (var iterator = new NativeMetadataIterator(chain.Handle))
                        UpdateMetadata(iterator, vorbisCommentBlock, pictureBlock);

                    if (chain.CheckIfTempFileNeeded(usePadding))
                    {
                        // If FLAC requests a temporary file, use a MemoryStream instead. Then overwrite the original:
                        using (var tempStream = new MemoryStream())
                        {
                            if (!chain.WriteWithTempFile(usePadding, tempStream))
                            {
                                throw new IOException(string.Format(CultureInfo.CurrentCulture,
                                                                    Resources.MetadataEncoderTempFileError, chain.GetStatus()));
                            }

                            // Clear the original stream, and copy the temporary one over it:
                            stream.SetLength(tempStream.Length);
                            stream.Position = 0;
                            tempStream.WriteTo(stream);
                        }
                    }
                    else if (!chain.Write(usePadding))
                    {
                        throw new IOException(string.Format(CultureInfo.CurrentCulture,
                                                            Resources.MetadataEncoderWriteError, chain.GetStatus()));
                    }
                }
            }
            finally
            {
                vorbisCommentBlock?.Dispose();
                pictureBlock?.Dispose();
            }
        }
Exemple #3
0
        public void Initialize(Stream stream, AudioInfo audioInfo, MetadataDictionary metadata, SettingsDictionary settings)
        {
            Contract.Ensures(_encoder != null);
            Contract.Ensures(_encoder.GetState() == EncoderState.Ok);
            Contract.Ensures(_multiplier > 0);

            _encoder        = InitializeEncoder(audioInfo, stream);
            _metadataBlocks = new List <NativeMetadataBlock>(3); // Assumes one metadata block, one picture and one seek table
            _multiplier     = (float)Math.Pow(2, audioInfo.BitsPerSample - 1);

            uint compressionLevel;

            if (string.IsNullOrEmpty(settings["CompressionLevel"]))
            {
                compressionLevel = 5;
            }
            else if (!uint.TryParse(settings["CompressionLevel"], out compressionLevel) || compressionLevel > 8)
            {
                throw new InvalidSettingException(string.Format(CultureInfo.CurrentCulture,
                                                                Resources.SampleEncoderBadCompressionLevel, settings["CompressionLevel"]));
            }
            _encoder.SetCompressionLevel(compressionLevel);

            var vorbisCommentBlock = new NativeVorbisCommentBlock();

            foreach (var field in new MetadataToVorbisCommentAdapter(metadata))
            {
                vorbisCommentBlock.Append(field.Key, field.Value);
            }
            _metadataBlocks.Add(vorbisCommentBlock);

            // Add a seek table, unless SeekPointInterval = 0:
            uint seekPointInterval;

            if (string.IsNullOrEmpty(settings["SeekPointInterval"]))
            {
                seekPointInterval = 10;
            }
            else if (!uint.TryParse(settings["SeekPointInterval"], out seekPointInterval))
            {
                throw new InvalidSettingException(string.Format(CultureInfo.CurrentCulture,
                                                                Resources.SampleEncoderBadSeekPointInterval, settings["SeekPointInterval"]));
            }
            if (seekPointInterval > 0)
            {
                _metadataBlocks.Add(new NativeSeekTableBlock(
                                        (int)Math.Ceiling(audioInfo.SampleCount / (double)audioInfo.SampleRate / seekPointInterval),
                                        audioInfo.SampleCount));
            }

            // Add a picture block, if cover art is available:
            if (metadata.CoverArt != null)
            {
                _metadataBlocks.Add(new CoverArtToPictureBlockAdapter(metadata.CoverArt));
            }

            _encoder.SetMetadata(_metadataBlocks);

            EncoderInitStatus initStatus = _encoder.Initialize();

            if (initStatus != EncoderInitStatus.Ok)
            {
                throw new IOException(string.Format(CultureInfo.CurrentCulture,
                                                    Resources.SampleEncoderInitializationError, initStatus));
            }
        }