예제 #1
0
        /// <summary>
        /// Returns a suitable audio resample context according to sample format, number of channels, and sample rate.
        /// The context returned will be cached until this function is called again with different arguments.
        /// </summary>
        /// <param name="sampleFormat">Sample format of the output.</param>
        /// <param name="channels">Number of channels of the output.</param>
        /// <param name="sampleRate">Sample rate of the output (Hz).</param>
        /// <returns>Cached or created resample context.</returns>
        internal SwrContext *GetSuitableResampleContext(AVSampleFormat sampleFormat, int channels, int sampleRate)
        {
            EnsureNotDisposed();

            Trace.Assert(channels > 0 && sampleRate > 0);
            Trace.Assert(channels == FFmpegHelper.RequiredChannels);

            var resampleContext = _resampleContext;

            if (resampleContext == null || sampleFormat != _lastSampleFormat || channels != _lastChannels || sampleRate != _lastSampleRate)
            {
                if (resampleContext != null)
                {
                    ffmpeg.swr_close(resampleContext);
                    ffmpeg.swr_free(&resampleContext);
                    _resampleContext = null;
                }

                var codecContext = CodecContext;

                var srcChannelLayout = codecContext->channels == ffmpeg.av_get_channel_layout_nb_channels(codecContext->channel_layout) ? codecContext->channel_layout : (ulong)ffmpeg.av_get_default_channel_layout(codecContext->channels);

                int dstChannelLayout;

                if (channels == 1)
                {
                    dstChannelLayout = ffmpeg.AV_CH_LAYOUT_MONO;
                }
                else if (channels == 2)
                {
                    dstChannelLayout = ffmpeg.AV_CH_LAYOUT_STEREO;
                }
                else
                {
                    // There are more kinds of layouts; but we don't actually need them.
                    dstChannelLayout = ffmpeg.AV_CH_LAYOUT_SURROUND;
                }

                // There is another function swr_alloc_setopts(), but re-creating doesn't matter,
                // since changing parameters is not frequent.
                resampleContext = ffmpeg.swr_alloc();

                if (resampleContext == null)
                {
                    Dispose();

                    throw new FFmpegException("Failed to init audio resample context.");
                }

                // Set options.
                FFmpegHelper.Verify(ffmpeg.av_opt_set_int(resampleContext, "in_channel_layout", (int)srcChannelLayout, 0), Dispose);
                FFmpegHelper.Verify(ffmpeg.av_opt_set_int(resampleContext, "in_sample_rate", codecContext->sample_rate, 0), Dispose);
                FFmpegHelper.Verify(ffmpeg.av_opt_set_sample_fmt(resampleContext, "in_sample_fmt", codecContext->sample_fmt, 0), Dispose);
                FFmpegHelper.Verify(ffmpeg.av_opt_set_int(resampleContext, "out_channel_layout", dstChannelLayout, 0), Dispose);
                FFmpegHelper.Verify(ffmpeg.av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0), Dispose);
                FFmpegHelper.Verify(ffmpeg.av_opt_set_sample_fmt(resampleContext, "out_sample_fmt", sampleFormat, 0), Dispose);

                // Don't forget to initialize the context. This is the difference between SWR and SWS (sws_getContext).
                FFmpegHelper.Verify(ffmpeg.swr_init(resampleContext));

                _resampleContext = resampleContext;

                _lastSampleFormat = sampleFormat;
                _lastChannels     = channels;
                _lastSampleRate   = sampleRate;
            }

            return(_resampleContext);
        }