功能要求是這樣的,錄像錄音并且保存為mp4檔案。因為需要取兩個聲道輸入后的音個聲道聲音,所以必須配合AudioRecord來取音源。用camera2取視頻,聲音與視頻都是通過MediaCodec編碼。最后用MediaMuxer做信道合并成mp4。
開啟相機后才啟用MediaCodec進行編碼合成成功沒有問題。。。
但但但。。。。。。。。。。。。。。。。。。。。
因為視頻是分段錄的(根據K歌錄像,每首歌都要錄),就會產生如錄像一段5分鐘視頻,錄完后馬上關閉,馬上又要錄第二段視頻,所以camera2就不能關閉了(啟動時間比較長)。
所以我拆解了兩步,第一步是camera2通過MediaCodec(叫它 A)處理生成資料流,開啟攝像頭后就一直傳輸,不停止。
第二步要錄像時,新建一個MediaCodec(叫它 B),接收上A產生的流,把它處理出來再放入MediaMuxer與聲音合并成mp4。
問題在于B無法處理A出來的資料,要么卡死,要么退出出借。跪求大神幫忙,重酬!重酬!重酬!(重要事情說三次)
以下為code片段:
try {
/*創建編碼器*/
mMuxerMediaCodec = MediaCodec.createEncoderByType(codecType);
} catch (IOException e) {
Log.d(Tag, "getMuxerMediaCodec" + e.getMessage());
mMuxerMediaCodec = null;
}
if (mMuxerMediaCodec == null) return;
/*設定編碼引數*/
MediaFormat mediaFormatSave = MediaFormat.createVideoFormat(codecType, CanUseMinSize.getWidth(), CanUseMinSize.getHeight());
/*設定顏色格式*/
mediaFormatSave.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
/*設定位元率*/
mediaFormatSave.setInteger(MediaFormat.KEY_BIT_RATE, 1200000);
/*設定幀率*/
mediaFormatSave.setInteger(MediaFormat.KEY_FRAME_RATE, 24);
/*設定關鍵幀間隔時間(S)*/
mediaFormatSave.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
//設定h264中的pps及sps資料
byte[] header_sps = {0, 0, 0, 1, 103, 66, 0, 42, (byte) 149, (byte) 168, 30, 0, (byte) 137, (byte) 249, 102, (byte) 224, 32, 32, 32, 64};
byte[] header_pps = {0, 0, 0, 1, 104, (byte) 206, 60, (byte) 128, 0, 0, 0, 1, 6, (byte) 229, 1, (byte) 151, (byte) 128};
mediaFormatSave.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
mediaFormatSave.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));
// format 如果為解碼器,此處表示輸入資料的格式;如果為編碼器,此處表示輸出資料的格式。
//surface 指定一個surface,可用作decode的輸出渲染。
//crypto 如果需要給媒體資料加密,此處指定一個crypto類.
// flags 如果正在配置的物件是用作編碼器,此處加上CONFIGURE_FLAG_ENCODE 標簽。
mMuxerMediaCodec.configure(mediaFormatSave, mRSurfaceHolder.getSurface(), null, MediaCodec.CRYPTO_MODE_UNENCRYPTED);
//mMuxerMediaCodec.getOutputFormat();
mMuxerMediaCodec.start();
-----------------------------------------------------------資料寫入:
try {
inputBufferIndex = mMediaCodec.dequeueInputBuffer(10000);
} catch (IllegalStateException e) {
Log.w(Tag, FromType + " encode IllegalStateException:" + e.getMessage());
return;
}
Log.d(Tag, "encode mMediaCodec :" + FromType);
Log.d(Tag, FromType + "inputBufferIndex:" + String.valueOf(inputBufferIndex));
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = mMediaCodec.getInputBuffer(inputBufferIndex);
inputBuffer.clear();
if (buffer != null) {
inputBuffer.put(buffer);
}
// Log.v(Tag, "encode:queueInputBuffer");
if (buffer == null) {
Log.i(Tag, "send BUFFER_FLAG_END_OF_STREAM");
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
return;
}
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, inputBuffer.limit(), presentationTimeUs, 0);
} else if (inputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
}
---------------------------------------------------------------------------資料取出
try {
status = mMediaCodec.dequeueOutputBuffer(saveBufferInfo, 100000000);//等待時間不適合過短,過短會出問題
} catch (IllegalStateException e) {
Log.d(Tag, String.valueOf(fromType) + "MediaMuxerdrain:" + e.getMessage());
}
if (status == MediaCodec.INFO_TRY_AGAIN_LATER) {
// wait 5 counts(=TIMEOUT_USEC x 5 = 500msec) until data/EOS come
if (++count > 5)
break; // out of while
continue;
} else if (status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
Log.v(Tag, String.valueOf(fromType) + "INFO_OUTPUT_FORMAT_CHANGED");
if (mMuxerStarted) { // second time request is error
Log.d(Tag, String.valueOf(fromType) + "format changed twice");
break;
}
Log.d(Tag, String.valueOf(fromType) + "MediaMuxerWrapper:getStart");
// 如果未開始,先加入信道并且開始
if (!MediaMuxerWrapper.getInstance().getStart()) {
mTrackIndex = MediaMuxerWrapper.getInstance().addTrack(mMediaCodec.getOutputFormat());// API >= 16
mMuxerStarted = true;
}
continue;
} else if (status < 0) {
Log.w(Tag, String.valueOf(fromType) + "drain:unexpected result from encoder#dequeueOutputBuffer: " + status);
continue;
}
ByteBuffer encodedData = null;
try {
encodedData = mMediaCodec.getOutputBuffer(status);
} catch (IllegalStateException e) {
Log.d(Tag, String.valueOf(fromType) + "MediaMuxerdrain============getOutputBuffer=======" + String.valueOf(status) + "====>IllegalStateException:" + e.getMessage());
break;
}
if (encodedData == null) {
Log.d(Tag, String.valueOf(fromType) + "encoderOutputBuffer " + status + " was null");
break;
}
if ((saveBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
Log.d(Tag, String.valueOf(fromType) + "drain:BUFFER_FLAG_CODEC_CONFIG");
saveBufferInfo.size = 0;
}
if (saveBufferInfo.size != 0) {
// encoded data is ready, clear waiting counter
count = 0;
if (!mMuxerStarted) {
// muxer is not ready...this will prrograming failure.
Log.d(Tag, String.valueOf(fromType) + "drain:muxer hasn't started");
}
// write encoded data to muxer(need to adjust presentationTimeUs.
saveBufferInfo.presentationTimeUs = getPTSUs(prevOutputPTSUs);
//不暫停的情況下,向混合器提交資料寫入
if (!MuxerIsPause)
MediaMuxerWrapper.getInstance().writeSampleData(mTrackIndex, encodedData, saveBufferInfo);
prevOutputPTSUs = saveBufferInfo.presentationTimeUs;
}
mMediaCodec.releaseOutputBuffer(status, false);
if ((saveBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
// when EOS come.
break; // out of while
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/56208.html
標籤:Android
上一篇:微信引入mqtt.js庫一直提示VM42 WAService.js:1 Uncaught TypeError: s is not a constructor
