既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
super.onActivityResult(requestCode, resultCode, data);
}
### 2、录音
相关技术就是:MediaCodec硬编码和MediaMuxer生成mp3文件
package com.example.myapplication;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.MediaRecorder;
import android.os.Build;
import android.util.Log;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class AudioEncoder implements Runnable {
private String mime = "audio/mp4a-latm";
private AudioRecord mRecorder;
private MediaCodec mEnc;
private int rate=256000;
//录音设置
private int sampleRate=44100; //采样率,默认44.1k
private int channelCount=2; //音频采样通道,默认2通道
private int channelConfig= AudioFormat.CHANNEL_IN_STEREO; //通道设置,默认立体声
private int audioFormat=AudioFormat.ENCODING_PCM_16BIT; //设置采样数据格式,默认16比特PCM
private FileOutputStream fos;
private byte[] buffer;
private boolean isRecording;
private Thread mThread;
private int bufferSize;
private String mSavePath;
private MediaMuxer mMuxer; //多路复用器,用于音视频混合
private int mAudioTrack=-1;
public AudioEncoder(){
}
public void setMuxer(MediaMuxer mMuxer){this.mMuxer=mMuxer;}
public void setMime(String mime){
this.mime=mime;
}
public void setRate(int rate){
this.rate=rate;
}
public void setSampleRate(int sampleRate){
this.sampleRate=sampleRate;
}
public void setSavePath(String path){
this.mSavePath=path;
}
public boolean prepare() throws IOException {
//fos=new FileOutputStream(mSavePath);
//音频编码相关
MediaFormat format= MediaFormat.createAudioFormat(mime,sampleRate,channelCount);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
// format.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_MONO);
format.setInteger(MediaFormat.KEY_BIT_RATE, rate);
mEnc=MediaCodec.createEncoderByType(mime);
mEnc.configure(format,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
//音频录制相关`
bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat)*2;
buffer=new byte[bufferSize];
mRecorder=new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,bufferSize);
if (mRecorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
return false;
}
mMuxer=new MediaMuxer(mSavePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
return true;
}
public void start() throws InterruptedException {
mEnc.start();
//开始录制音频
try{
// 防止某些手机崩溃,例如联想
mRecorder.startRecording();
}catch (IllegalStateException e){
e.printStackTrace();
}
if(mThread!=null&&mThread.isAlive()){
isRecording=false;
mThread.join();
}
isRecording=true;
mThread=new Thread(this);
mThread.start();
}
private ByteBuffer getInputBuffer(int index){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return mEnc.getInputBuffer(index);
}else{
return mEnc.getInputBuffers()[index];
}
}
private ByteBuffer getOutputBuffer(int index){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return mEnc.getOutputBuffer(index);
}else{
return mEnc.getOutputBuffers()[index];
}
}
//TODO Add End Flag
private void readOutputData() throws IOException{
int index=mEnc.dequeueInputBuffer(-1);
if(index>=0){
final ByteBuffer buffer=getInputBuffer(index);
buffer.clear();
int length=mRecorder.read(buffer,bufferSize);
if(length>0){
mEnc.queueInputBuffer(index,0,length,System.nanoTime()/1000,0);
}else{
Log.e("wuwang","length-->"+length);
}
}
MediaCodec.BufferInfo mInfo=new MediaCodec.BufferInfo();
int outIndex;
do{
outIndex=mEnc.dequeueOutputBuffer(mInfo,0);
Log.e("wuwang","audio flag---->"+mInfo.flags+"/"+outIndex);
if(outIndex>=0){
ByteBuffer buffer=getOutputBuffer(outIndex);
buffer.position(mInfo.offset);
// byte[] temp=new byte[mInfo.size+7];
// buffer.get(temp,7,mInfo.size);
// addADTStoPacket(temp,temp.length);
if(mAudioTrack>=0&&mInfo.size>0&&mInfo.presentationTimeUs>0){
try {
mMuxer.writeSampleData(mAudioTrack,buffer,mInfo);
}catch (Exception e){
//Log.e(TAG,“audio error:size=”+mInfo.size+“/offset=”
// +mInfo.offset+“/timeUs=”+mInfo.presentationTimeUs);
e.printStackTrace();
}
}
mEnc.releaseOutputBuffer(outIndex,false);
if((mInfo.flags&MediaCodec.BUFFER_FLAG_END_OF_STREAM)!=0){
//Log.e(TAG,“audio end”);
return ;
}
}else if(outIndex ==MediaCodec.INFO_TRY_AGAIN_LATER){
}else if(outIndex==MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){
mAudioTrack=mMuxer.addTrack(mEnc.getOutputFormat());
//Log.e(TAG,"add audio track-->"+mAudioTrack);
if(mAudioTrack>=0){
mMuxer.start();
}
}
}while (outIndex>=0);
}
/**
* 给编码出的aac裸流添加adts头字段
* @param packet 要空出前7个字节,否则会搞乱数据
* @param packetLen
*/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; //AAC LC
int freqIdx = 4; //44.1KHz
int chanCfg = 2; //CPE
packet[0] = (byte)0xFF;
packet[1] = (byte)0xF9;
packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
packet[4] = (byte)((packetLen&0x7FF) >> 3);
packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
packet[6] = (byte)0xFC;
}
/**
* 停止录制
*/
public void stop(){
try {
isRecording=false;
mThread.join();
mRecorder.stop();
mEnc.stop();
mEnc.release();
// fos.flush();
// fos.close();
mAudioTrack=-1;
mMuxer.stop();
mMuxer.release();
} catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
while (isRecording){
try {
readOutputData();
// fos.write(buffer,0,length);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
### 3、录像
涉及技术点:Camera摄像机类、MediaCodec硬编码,需要注意的是一些格式的转换,最好是使用C++jni调用,单纯用java有点花屏
注意:需要surfaceView控件,如果不需要显示则可以设置为单位1
![在这里插入图片描述](https://img-blog.csdnimg.cn/88f3f99a6eef49e092084511938d45fc.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAencxOTk2,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
![img](https://img-blog.csdnimg.cn/img_convert/cec3160a186efd0eb22c40feff16e4a4.png)
![img](https://img-blog.csdnimg.cn/img_convert/174e62535fa98f75392f7786bc28fcc5.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**
)]
[外链图片转存中...(img-pPzRS92g-1715538863296)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**