지금 며칠 동안 같은 문제로 strugling되었다. 내 aproach 스트림/디코딩/MediaExtractor/MediaCodec/AudioTrack를 사용하여 MP3 파일을 재생 mutiple 스레드를했다. 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);
}
});