我正在一个项目中,我正在使用AudioRecord
类记录音频,并使用MediaMuxer
将编码后的数据写入输出文件。一旦开始记录,一切似乎都正常,但是在对下面的writeRecordingAudioFileSampleData
方法进行了几次调用之后,dequeueInputBuffer
方法不断返回INFO_TRY_AGAIN_LATER (-1)
。
每次调用该方法时,我都尝试刷新编码器,并且不再发生此问题。但是,当我在媒体混合器上调用stop方法时,应用程序崩溃了(它说“无法停止混合器”)。我不必调用flush MediaCodec,但没有它,我会不断得到INFO_TRY_AGAIN_LATER
。
这是开始记录过程的方法。为简便起见,我没有包括获取演示时间的方法或初始化AudioRecord实例,MediaMuxer
和MediaCodec
编码器的方法。我认为问题与他们无关,但是如果他们可能有帮助,请告诉我,我将其发布。
public ActionResponse startRecording()
{
ActionResponse response = new ActionResponse();
try
{
File recordDir = new File(RECORD_TEMP_DIR);
if(!recordDir.exists())
{
if(!recordDir.mkdirs())
throw new IOException("Could not create file");
}
String fileName = generateRecordingName();
String path = RECORD_TEMP_DIR + "/" + fileName + "." + recordingOutputOptions.recordAudioFormat.name;
currentTrack = new AudioFile();
currentTrack.setName(fileName);
currentTrack.setPath(path);
currentTrack.setFormat(recordingOutputOptions.recordAudioFormat);
this.initializeAudioRecord();
if(audioRecord.getState() != AudioRecord.STATE_INITIALIZED)
throw new IOException("Could not initialize audio record instance");
this.initializeRecordingAudioEncoder();
this.initializeRecordingMediaMuxer();
encoder.start();
audioRecord.startRecording();
recordReadThread = new Thread(readAudioRecordRunnable);
recordReadThread.start();
recorderState = MEDIA_RECORDER_STATE.RECORDING;
response.setStatus(ActionResponse.ResponseStatus.SUCCESS);
}
catch (IOException e)
{
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setError(e);
}
return response;
}
这是我正在从AudioRecord实例读取数据的地方:
private Runnable readAudioRecordRunnable = new Runnable()
{
@Override
public void run()
{
ActionResponse response = new ActionResponse(ActionResponse.ResponseStatus.SUCCESS);
File outFile = new File(currentTrack.path);
try
{
if(outFile.exists())
outFile.delete();
// Parent directory should have already been created before we started recording
if(!outFile.createNewFile())
{
response.setStatusMessage("Could not create file");
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
}
else
{
ByteBuffer buffer = ByteBuffer.allocateDirect(recordingOutputOptions.bufferSize);
int numReads = 0;
while (recorderState == MEDIA_RECORDER_STATE.RECORDING)
{
int result = audioRecord.read(buffer, recordingOutputOptions.bufferSize);
if (result >= 0)
{
audioAbsolutePtsUs = (System.nanoTime()) / 1000L;
int samplesPerBuffer = recordingOutputOptions.bufferSize / recordingOutputOptions.bytesPerSample;
long presentationTime = getPresentationTimeUs(audioAbsolutePtsUs,samplesPerBuffer);
Log.e("TAG","Writing " + result + " bytes of recorded data with presentation time: " + String.valueOf(presentationTime));
ActionResponse encodeResponse = writeRecordingAudioFileSampleData(buffer,false,presentationTime);
if(!encodeResponse.isSuccess())
{
response = encodeResponse;
break;
}
buffer.clear();
numReads++;
//encoder.flush();
}
else
{
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage("Audio record return result: " + result);
break;
}
}
}
if(response.isSuccess())
writeRecordingAudioFileSampleData(null,true,0);
}
catch (Exception e)
{
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage("Error occurred while recording");
response.setError(e);
}
finally
{
try
{
encoder.stop();
encoder.release();
encoder = null;
muxer.stop();
muxer.release();
muxer = null;
isMuxerStarted = false;
}
catch (Exception ex)
{
Log.e("Recording Error","Error stopping and cleaning up encoder and muxer",ex);
}
}
if(!response.isSuccess())
{
stopRecording();
outFile.delete();
Log.e("Recording Error",response.statusMessage,response.error);
if(recordEventHandler!=null)
recordEventHandler.onRecordError(response);
}
}
};
这是writeRecordingAudioFileSampleData方法:
public ActionResponse writeRecordingAudioFileSampleData(final ByteBuffer data,boolean isEndOfStream, long presentationTime)
{
ActionResponse response = new ActionResponse(ActionResponse.ResponseStatus.SUCCESS);
try
{
boolean doneSubmittingInput = false;
int index;
int numBytesSubmitted = 0;
int numBytesEncoded = 0;
int numRetriesDequeueOutputBuffer = 0;
ByteBuffer[] inputBuffers = encoder.getInputBuffers();
ByteBuffer[] outputBuffers = encoder.getOutputBuffers();
while (true)
{
if (!doneSubmittingInput)
{
index = encoder.dequeueInputBuffer(ENCODER_BUFFER_TIMEOUT_US);
if (index != MediaCodec.INFO_TRY_AGAIN_LATER)
{
Log.e("TAG","Dequeued input buffer: " + index);
if(isEndOfStream)
{
doneSubmittingInput = true;
encoder.queueInputBuffer(index, 0, 0, 0, BUFFER_FLAG_END_OF_STREAM);
}
else
{
int dataSize = data.capacity();
if (numBytesSubmitted >= dataSize)
{
doneSubmittingInput = true;
}
else
{
ByteBuffer buffer = inputBuffers[index];
buffer.clear();
buffer.put(data);
encoder.queueInputBuffer(index, 0, buffer.remaining(), presentationTime, 0);
Log.e("TAG","Queued input buffer: " + index);
numBytesSubmitted += buffer.remaining();
}
}
}
else
{ response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage("Dequeue input buffer returned: " + index);
break;
}
}
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
index = encoder.dequeueOutputBuffer(info, ENCODER_BUFFER_TIMEOUT_US);
if (index == MediaCodec.INFO_TRY_AGAIN_LATER)
{
Log.e("TAG","No output buffer available");
if (++numRetriesDequeueOutputBuffer > MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER)
{
if(!isEndOfStream)
{
// All data encoded
Log.e("TAG","Max Retries Exceeded. All data has been encoded.");
break;
}
else
{
Log.e("TAG","Max Retries Exceeded. End of stream input has been queued.");
// EOS Input Queued, Continue Loop to Receive output
}
}
}
else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
// should only happen once before receiving buffers
if (isMuxerStarted)
{
// should not occur
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage("Output format changed after muxer started");
break;
}
MediaFormat newFormat = encoder.getOutputFormat();
muxerTrackIndex = muxer.addTrack(newFormat);
muxer.start();
isMuxerStarted = true;
Log.e("TAG","Started Muxer");
}
else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
// should not occur
Log.e("TAG","Output buffers changed");
outputBuffers = encoder.getOutputBuffers();
}
else if (index < 0)
{
Log.e("TAG","Unexpected index " + index + " received from dequeueOutputBuffer");
// Unexpected result - should not occur. Ignore it
}
else
{
Log.e("TAG","Dequeued output buffer: " + index);
ByteBuffer encodedData = outputBuffers[index];
if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0)
{
// The codec config data was pulled out and fed to the muxer when we got
// the INFO_OUTPUT_FORMAT_CHANGED status. Ignore it.
Log.e("TAG","Ignoring codec config data");
info.size = 0;
}
if (info.size != 0)
{
if (!isMuxerStarted)
{
// should not occur
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage("Attempting to write data but muxer was not started");
break;
}
info.presentationTimeUs = presentationTime;
muxer.writeSampleData(muxerTrackIndex,encodedData,info);
Log.e("TAG","Wrote " + info.size + " bytes to muxer");
numBytesEncoded += info.size;
}
encoder.releaseOutputBuffer(index, false);
Log.e("TAG","Releasing output buffer: " + index);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
{
// EOS Submitted
if(!isEndOfStream)
{
// Unexpected EOS
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage("Unexpected buffer end of stream flag");
}
else
Log.e("TAG","Dequeued end of stream reached. All data has been encoded.");
break;
}
}
}
}
catch (Exception exc)
{
response.setStatus(ActionResponse.ResponseStatus.FAILURE);
response.setStatusMessage(exc.getMessage());
response.setError(exc);
}
finally
{
}
return response;
}
最后,这是运行该应用程序时获得的输出示例,其中显示了记录的停止位置:
W/ExtendedACodec: Failed to get extension for extradata parameter
E/TAG: Writing 28288 bytes of recorded data with presentation time: 41035517230
E/TAG: Dequeued input buffer: 0
E/TAG: Queued input buffer: 0
I/MPEG4Writer: limits: 4294967295/0 bytes/us, bit rate: -1 bps and the estimated moov size 3195 bytes
D/MPEG4Writer: Audio track starting
E/TAG: Started Muxer
E/TAG: Dequeued input buffer: 1
E/TAG: Dequeued output buffer: 0
Ignoring codec config data
E/TAG: Releasing output buffer: 0
E/TAG: Dequeued output buffer: 1
I/MPEG4Writer: setStartTimestampUs: 41035517230
Earliest track starting time: 41035517230
E/TAG: Wrote 371 bytes to muxer
Releasing output buffer: 1
E/TAG: Dequeued output buffer: 2
E/TAG: Wrote 372 bytes to muxer
E/TAG: Releasing output buffer: 2
E/TAG: Dequeued output buffer: 3
W/MPEG4Writer: 0-duration samples found: 1
E/TAG: Wrote 520 bytes to muxer
Releasing output buffer: 3
E/TAG: No output buffer available
E/TAG: No output buffer available
I/chatty: uid=10286(com.bandindustries.musicjournal) Thread-4 identical 3 lines
E/TAG: No output buffer available
E/TAG: Max Retries Exceeded. All data has been encoded.
Writing 28288 bytes of recorded data with presentation time: 41035677592
Dequeued input buffer: 2
E/TAG: Queued input buffer: 2
E/TAG: Dequeued output buffer: 0
W/MPEG4Writer: 0-duration samples found: 1
E/TAG: Wrote 513 bytes to muxer
E/TAG: Releasing output buffer: 0
E/TAG: Dequeued input buffer: 3
E/TAG: Dequeued output buffer: 1
Wrote 462 bytes to muxer
E/TAG: Releasing output buffer: 1
E/TAG: Dequeued output buffer: 2
Wrote 433 bytes to muxer
E/TAG: Releasing output buffer: 2
E/TAG: No output buffer available
I/chatty: uid=10286(com.bandindustries.musicjournal) Thread-4 identical 4 lines
E/TAG: No output buffer available
Max Retries Exceeded. All data has been encoded.
E/TAG: Writing 28288 bytes of recorded data with presentation time: 41035837955
E/TAG: Dequeued input buffer: 0
E/TAG: Queued input buffer: 0
E/TAG: Dequeued output buffer: 3
W/MPEG4Writer: 0-duration samples found: 2
E/TAG: Wrote 407 bytes to muxer
E/TAG: Releasing output buffer: 3
E/TAG: Dequeued input buffer: 2
E/TAG: Dequeued output buffer: 0
Wrote 408 bytes to muxer
E/TAG: Releasing output buffer: 0
E/TAG: Dequeued output buffer: 1
E/TAG: Wrote 392 bytes to muxer
E/TAG: Releasing output buffer: 1
E/TAG: Dequeued output buffer: 2
E/TAG: Wrote 390 bytes to muxer
E/TAG: Releasing output buffer: 2
E/TAG: No output buffer available
I/chatty: uid=10286(com.bandindustries.musicjournal) Thread-4 identical 4 lines
E/TAG: No output buffer available
E/TAG: Max Retries Exceeded. All data has been encoded.
E/TAG: Writing 28288 bytes of recorded data with presentation time: 41035998318
E/TAG: Dequeued input buffer: 0
E/TAG: Queued input buffer: 0
E/TAG: Dequeued output buffer: 3
W/MPEG4Writer: 0-duration samples found: 3
E/TAG: Wrote 356 bytes to muxer
E/TAG: Releasing output buffer: 3
I/zygote64: Do partial code cache collection, code=27KB, data=29KB
After code cache collection, code=27KB, data=29KB
Increasing code cache capacity to 128KB
D/MPEG4Writer: Audio track stopping. Stop source
Audio track source stopping
Audio track source stopped
I/MPEG4Writer: Received total/0-length (11/0) buffers and encoded 11 frames. - Audio
Audio track drift time: 0 us
D/MPEG4Writer: Audio track stopped. Stop source
Audio track stopped. Stop source
Stopping writer thread
D/MPEG4Writer: 0 chunks are written in the last batch
D/MPEG4Writer: Writer thread stopped
I/MPEG4Writer: Ajust the moov start time from 41035517230 us -> 41035517230 us
D/MPEG4Writer: Audio track stopping. Stop source
E/Recording Error: Dequeue input buffer returned: -1
有人曾经经历过吗?这是我第一次使用Android中的低级媒体类,并且在网上或文档中找不到很多好的示例。感谢您的帮助。谢谢。
更新:停止媒体多路复用器时应用程序崩溃的问题是由于发送0作为最后一次呼叫的演示时间戳,即流的结尾。但是由于某种原因,我得到了一个空文件作为输出。