Ejemplo n.º 1
0
        public static ConversionQuality ConvertToFormat(AudioContent content, ConversionFormat formatType, ConversionQuality quality, string saveToFile)
        {
            var temporaryOutput = Path.GetTempFileName();

            try
            {
                string ffmpegCodecName, ffmpegMuxerName;
                //int format;
                switch (formatType)
                {
                case ConversionFormat.Adpcm:
                    // ADPCM Microsoft
                    ffmpegCodecName = "adpcm_ms";
                    ffmpegMuxerName = "wav";
                    //format = 0x0002; /* WAVE_FORMAT_ADPCM */
                    break;

                case ConversionFormat.Pcm:
                    // XNA seems to preserve the bit size of the input
                    // format when converting to PCM.
                    if (content.Format.BitsPerSample == 8)
                    {
                        ffmpegCodecName = "pcm_u8";
                    }
                    else if (content.Format.BitsPerSample == 32 && content.Format.Format == 3)
                    {
                        ffmpegCodecName = "pcm_f32le";
                    }
                    else
                    {
                        ffmpegCodecName = "pcm_s16le";
                    }
                    ffmpegMuxerName = "wav";
                    //format = 0x0001; /* WAVE_FORMAT_PCM */
                    break;

                case ConversionFormat.WindowsMedia:
                    // Windows Media Audio 2
                    ffmpegCodecName = "wmav2";
                    ffmpegMuxerName = "asf";
                    //format = 0x0161; /* WAVE_FORMAT_WMAUDIO2 */
                    break;

                case ConversionFormat.Xma:
                    throw new NotSupportedException(
                              "XMA is not a supported encoding format. It is specific to the Xbox 360.");

                case ConversionFormat.ImaAdpcm:
                    // ADPCM IMA WAV
                    ffmpegCodecName = "adpcm_ima_wav";
                    ffmpegMuxerName = "wav";
                    //format = 0x0011; /* WAVE_FORMAT_IMA_ADPCM */
                    break;

                case ConversionFormat.Aac:
                    // AAC (Advanced Audio Coding)
                    // Requires -strict experimental
                    ffmpegCodecName = "aac";
                    ffmpegMuxerName = "ipod";
                    //format = 0x0000; /* WAVE_FORMAT_UNKNOWN */
                    break;

                case ConversionFormat.Vorbis:
                    // Vorbis
                    ffmpegCodecName = "libvorbis";
                    ffmpegMuxerName = "ogg";
                    //format = 0x0000; /* WAVE_FORMAT_UNKNOWN */
                    break;

                default:
                    // Unknown format
                    throw new NotSupportedException();
                }

                string ffmpegStdout, ffmpegStderr;
                int    ffmpegExitCode;
                do
                {
                    ffmpegExitCode = ExternalTool.Run(
                        "ffmpeg",
                        string.Format(
                            "-y -i \"{0}\" -vn -c:a {1} -b:a {2} -ar {3} -f:a {4} -strict experimental \"{5}\"",
                            content.FileName,
                            ffmpegCodecName,
                            QualityToBitRate(quality),
                            QualityToSampleRate(quality, content.Format.SampleRate),
                            ffmpegMuxerName,
                            temporaryOutput),
                        out ffmpegStdout,
                        out ffmpegStderr);
                    if (ffmpegExitCode != 0)
                    {
                        quality--;
                    }
                } while (quality >= 0 && ffmpegExitCode != 0);

                if (ffmpegExitCode != 0)
                {
                    throw new InvalidOperationException("ffmpeg exited with non-zero exit code: \n" + ffmpegStdout + "\n" + ffmpegStderr);
                }

                byte[] rawData;
                using (var fs = new FileStream(temporaryOutput, FileMode.Open, FileAccess.Read))
                {
                    rawData = new byte[fs.Length];
                    fs.Read(rawData, 0, rawData.Length);
                }

                if (saveToFile != null)
                {
                    using (var fs = new FileStream(saveToFile, FileMode.Create, FileAccess.Write))
                        fs.Write(rawData, 0, rawData.Length);
                }

                // Use probe to get the final format and information on the converted file.
                AudioFileType audioFileType;
                AudioFormat   audioFormat;
                TimeSpan      duration;
                int           loopStart, loopLength;
                ProbeFormat(temporaryOutput, out audioFileType, out audioFormat, out duration, out loopStart, out loopLength);

                AudioFormat riffAudioFormat;
                byte[]      data = StripRiffWaveHeader(rawData, out riffAudioFormat);

                // deal with adpcm
                if (audioFormat.Format == 2 || audioFormat.Format == 17)
                {
                    // riff contains correct blockAlign
                    audioFormat = riffAudioFormat;

                    // fix loopLength -> has to be multiple of sample per block
                    // see https://msdn.microsoft.com/de-de/library/windows/desktop/ee415711(v=vs.85).aspx
                    int samplesPerBlock = SampleAlignment(audioFormat);
                    loopLength = (int)(audioFormat.SampleRate * duration.TotalSeconds);
                    int remainder = loopLength % samplesPerBlock;
                    loopLength += samplesPerBlock - remainder;
                }

                content.SetData(data, audioFormat, duration, loopStart, loopLength);
            }
            finally
            {
                ExternalTool.DeleteFile(temporaryOutput);
            }

            return(quality);
        }