【问题标题】:Monodroid(Xamarin) how to play multiple mp3 in syncMonodroid(Xamarin)如何同步播放多个mp3
【发布时间】:2015-02-26 21:36:47
【问题描述】:

我的项目需要一个 mp3 播放器,多个 mp3 文件可以完全同步播放。 我已经尝试过 MediaPlayer,但问题是当我在循环中启动两个 mp3 文件时,它们稍微不同步。当然,它们是在调用 Play() 之前创建和准备好的。 这些不仅仅是声音,还有 3-4 分钟的音乐文件,也需要无缝循环播放。

目前我正在努力使用 AudioTrack,因为这些文件是 AndroidAssets,当我从中创建流时,ByteReader 会出现内存不足错误...

那么有没有更好的方法来进行这种 mp3 音乐同步播放?

谢谢 格雷格

【问题讨论】:

    标签: android xamarin xamarin.android android-mediaplayer audiotrack


    【解决方案1】:

    这几天我一直在为同样的问题苦苦挣扎。我的方法是让多个线程使用 MediaExtractor/MediaCodec/AudioTrack 流式传输/解码/播放 mp3 文件。我让它在 C# 中工作,但在播放期间观察到很多 GC 活动。您可以在下面找到我的单轨代码。你可以在这里阅读更多关于我遇到的问题以及我将如何解决它:How to stream data from MediaCodec to AudioTrack with Xamarin for Android

    我还发现,在低端设备上,曲目不会同步播放(延迟 10 秒到 100 秒毫秒)。我认为问题在于,当我执行 audioTrack.Play() 时,AudioTrack 的缓冲区中没有足够的数据来立即开始播放,并且根据输入文件格式,它需要不同数量的 mp3 帧来填充它,因此曲目以不同的延迟开始。我正在尝试的解决方案是推迟audioTrack.Play(),直到我知道缓冲区有足够的字节(AudioTrack.GetMinBufferSize(...)) 才能立即开始播放,并且只调用audioTrack.Play()。

    var fd = this.Resources.OpenRawResourceFd(Resource.Raw.PianoInsideMics);
    
    var extractor = new MediaExtractor();
    extractor.SetDataSource(fd.FileDescriptor, fd.StartOffset, fd.Length);
    extractor.SelectTrack(0);
    
    var trackFormat = extractor.GetTrackFormat(0);
    
    var decoder = MediaCodec.CreateDecoderByType(trackFormat.GetString(MediaFormat.KeyMime));
    decoder.Configure(trackFormat, null, null, MediaCodecConfigFlags.None);
    
    var thread = new Thread(() =>
    {
        decoder.Start();
        var decoderInputBuffers = decoder.GetInputBuffers();
        var decoderOutputBuffers = decoder.GetOutputBuffers();
    
        var inputIndex = decoder.DequeueInputBuffer(-1);
        var inputBuffer = decoderInputBuffers[inputIndex];
        var bufferInfo = new MediaCodec.BufferInfo();
        byte[] audioBuffer = null;
        AudioTrack audioTrack = null;
    
        var read = extractor.ReadSampleData(inputBuffer, 0);
        while (read > 0)
        {
            decoder.QueueInputBuffer(inputIndex, 0, read, extractor.SampleTime,
                extractor.SampleFlags == MediaExtractorSampleFlags.Sync ? MediaCodecBufferFlags.SyncFrame : MediaCodecBufferFlags.None);
    
            extractor.Advance();
    
            var outputIndex = decoder.DequeueOutputBuffer(bufferInfo, -1);
            if (outputIndex == (int) MediaCodecInfoState.OutputFormatChanged)
            {
                trackFormat = decoder.OutputFormat;
            }
            else if (outputIndex >= 0)
            {
                if (bufferInfo.Size > 0)
                {
                    var outputBuffer = decoderOutputBuffers[outputIndex];
                    if (audioBuffer == null || audioBuffer.Length < bufferInfo.Size)
                    {
                        audioBuffer = new byte[bufferInfo.Size];
                        Debug.WriteLine("Allocated new audiobuffer: {0}", audioBuffer.Length);
                    }
    
                    outputBuffer.Rewind();
                    outputBuffer.Get(audioBuffer, 0, bufferInfo.Size);
                    decoder.ReleaseOutputBuffer(outputIndex, false);
    
                    if (audioTrack == null)
                    {
                        var sampleRateInHz = trackFormat.GetInteger(MediaFormat.KeySampleRate);
                        var channelCount = trackFormat.GetInteger(MediaFormat.KeyChannelCount);
                        var channelConfig = channelCount == 1 ? ChannelOut.Mono : ChannelOut.Stereo;
    
                        audioTrack = new AudioTrack(
                            Stream.Music,
                            sampleRateInHz,
                            channelConfig,
                            Encoding.Pcm16bit,
                            AudioTrack.GetMinBufferSize(sampleRateInHz, channelConfig, Encoding.Pcm16bit)*2,
                            AudioTrackMode.Stream);
    
                        audioTrack.Play();
                    }
    
                    audioTrack.Write(audioBuffer, 0, bufferInfo.Size);
                }
            }
    
            inputIndex = decoder.DequeueInputBuffer(-1);
            inputBuffer = decoderInputBuffers[inputIndex];
    
            read = extractor.ReadSampleData(inputBuffer, 0);
        }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多