2024年安卓最新Android使用FFmpeg播放音频_qt 安卓ffmpeg avcodec模块不能识别,android打包流程面试

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

    musicPlayer.stopAudio()
}

/\*\*

* 这是初始化AudioTrack的方法,也是在C中调用的
*/
fun createTrack(sampleRateInHn:Int,nbChannel:Int){
val channelConfig =when (nbChannel) {
1 -> AudioFormat.CHANNEL_OUT_MONO
2 -> AudioFormat.CHANNEL_OUT_STEREO
else -> AudioFormat.CHANNEL_OUT_MONO
}
val bufferSize = AudioTrack.getMinBufferSize(sampleRateInHn,channelConfig,AudioFormat.ENCODING_PCM_16BIT)
audioTrack = AudioTrack(AudioManager.STREAM_MUSIC,sampleRateInHn,channelConfig,AudioFormat.ENCODING_PCM_16BIT,bufferSize,AudioTrack.MODE_STREAM)
audioTrack?.play()
}

/\*\*

* 这是在C代码中调用的,就是在解码出PCM就会调用这个方法,让AudioTrack进行播放
*/
fun playTrack(buffer:ByteArray,length:Int){
if(audioTrack != null && audioTrack?.playState == AudioTrack.PLAYSTATE_PLAYING){
audioTrack?.write(buffer,0,length)
}
}

private external fun playAudio(path:String)

companion object {
    init {
        System.loadLibrary("native-lib")
    }
}

}


使用OpenSL EL进行音频播放的代码:  
 JNI代码



SLObjectItf engineObject=NULL;//用SLObjectItf声明引擎接口对象
SLEngineItf engineEngine = NULL;//声明具体的引擎对象

SLObjectItf outputMixObject = NULL;//用SLObjectItf创建混音器接口对象
SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;具体的混音器对象实例
SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_DEFAULT;//默认情况

SLObjectItf audioplayer=NULL;//用SLObjectItf声明播放器接口对象
SLPlayItf slPlayItf=NULL;//播放器接口
SLAndroidSimpleBufferQueueItf slBufferQueueItf=NULL;//缓冲区队列接口

size_t buffersize =0;
void *buffer;
//将pcm数据添加到缓冲区中
void getQueueCallBack(SLAndroidSimpleBufferQueueItf slBufferQueueItf, void* context){

buffersize=0;

getPcm(&buffer,&buffersize);
if(buffer!=NULL&&buffersize!=0){
    //将得到的数据加入到队列中
    (\*slBufferQueueItf)->Enqueue(slBufferQueueItf,buffer,buffersize);
}

}

//创建引擎
void createEngine(){
slCreateEngine(&engineObject,0,NULL,0,NULL,NULL);//创建引擎
(*engineObject)->Realize(engineObject,SL_BOOLEAN_FALSE);//实现engineObject接口对象
(*engineObject)->GetInterface(engineObject,SL_IID_ENGINE,&engineEngine);//通过引擎调用接口初始化SLEngineItf
}

//创建混音器
void createMixVolume(){
(*engineEngine)->CreateOutputMix(engineEngine,&outputMixObject,0,0,0);//用引擎对象创建混音器接口对象
(*outputMixObject)->Realize(outputMixObject,SL_BOOLEAN_FALSE);//实现混音器接口对象
SLresult sLresult = (*outputMixObject)->GetInterface(outputMixObject,SL_IID_ENVIRONMENTALREVERB,&outputMixEnvironmentalReverb);//利用混音器实例对象接口初始化具体的混音器对象
//设置
if (SL_RESULT_SUCCESS == sLresult) {
(*outputMixEnvironmentalReverb)->
SetEnvironmentalReverbProperties(outputMixEnvironmentalReverb, &settings);
}
}

//创建播放器
void createPlayer(const char* path){
//初始化ffmpeg
int rate;
int channels;
createFFmpeg(&rate,&channels,path);
LOGE(“RATE %d”,rate);
LOGE(“channels %d”,channels);
/*
* typedef struct SLDataLocator_AndroidBufferQueue_ {
SLuint32 locatorType;//缓冲区队列类型
SLuint32 numBuffers;//buffer位数
} */

SLDataLocator_AndroidBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
/\*\*

typedef struct SLDataFormat_PCM_ {
SLuint32 formatType; pcm
SLuint32 numChannels; 通道数
SLuint32 samplesPerSec; 采样率
SLuint32 bitsPerSample; 采样位数
SLuint32 containerSize; 包含位数
SLuint32 channelMask; 立体声
SLuint32 endianness; end标志位
} SLDataFormat_PCM;
*/
SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM,(SLuint32)channels,(SLuint32)rate*1000
,SL_PCMSAMPLEFORMAT_FIXED_16
,SL_PCMSAMPLEFORMAT_FIXED_16
,SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,SL_BYTEORDER_LITTLEENDIAN};

/\*

* typedef struct SLDataSource_ {
void *pLocator;//缓冲区队列
void *pFormat;//数据样式,配置信息
} SLDataSource;
* */
SLDataSource dataSource = {&android_queue,&pcm};

SLDataLocator_OutputMix slDataLocator_outputMix={SL_DATALOCATOR_OUTPUTMIX,outputMixObject};


SLDataSink slDataSink = {&slDataLocator_outputMix,NULL};


const SLInterfaceID ids[3]={SL_IID_BUFFERQUEUE,SL_IID_EFFECTSEND,SL_IID_VOLUME};
const SLboolean req[3]={SL_BOOLEAN_FALSE,SL_BOOLEAN_FALSE,SL_BOOLEAN_FALSE};

/\*

* SLresult (*CreateAudioPlayer) (
SLEngineItf self,
SLObjectItf * pPlayer,
SLDataSource *pAudioSrc,//数据设置
SLDataSink *pAudioSnk,//关联混音器
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
* */
LOGE(“执行到此处”)
(*engineEngine)->CreateAudioPlayer(engineEngine,&audioplayer,&dataSource,&slDataSink,3,ids,req);
(*audioplayer)->Realize(audioplayer,SL_BOOLEAN_FALSE);
LOGE(“执行到此处2”)
(*audioplayer)->GetInterface(audioplayer,SL_IID_PLAY,&slPlayItf);//初始化播放器
//注册缓冲区,通过缓冲区里面 的数据进行播放
(*audioplayer)->GetInterface(audioplayer,SL_IID_BUFFERQUEUE,&slBufferQueueItf);
//设置回调接口
(*slBufferQueueItf)->RegisterCallback(slBufferQueueItf,getQueueCallBack,NULL);
//播放
(*slPlayItf)->SetPlayState(slPlayItf,SL_PLAYSTATE_PLAYING);

//开始播放
getQueueCallBack(slBufferQueueItf,NULL);

}
//释放资源
void releaseResource(){
if(audioplayer!=NULL){
(*audioplayer)->Destroy(audioplayer);
audioplayer=NULL;
slBufferQueueItf=NULL;
slPlayItf=NULL;
}
if(outputMixObject!=NULL){
(*outputMixObject)->Destroy(outputMixObject);
outputMixObject=NULL;
outputMixEnvironmentalReverb=NULL;
}
if(engineObject!=NULL){
(*engineObject)->Destroy(engineObject);
engineObject=NULL;
engineEngine=NULL;
}
releaseFFmpeg();
}

AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodex;
AVPacket *packet;
AVFrame *frame;
SwrContext *swrContext;
uint8_t *out_buffer;
int out_channer_nb;
int audio_stream_idx=-1;
//opensl es调用 int * rate,int *channel
int createFFmpeg(int *rate,int *channel,const char* path){
av_register_all();
const char *input = path;
pFormatCtx = avformat_alloc_context();
LOGE(“Lujng %s”,input);
LOGE(“xxx %p”,pFormatCtx);
int error;
char buf[] = “”;
//打开视频地址并获取里面的内容(解封装)
if (error = avformat_open_input(&pFormatCtx, input, NULL, NULL) < 0) {
av_strerror(error, buf, 1024);
// LOGE(“%s” ,inputPath)
LOGE(“Couldn’t open file %s: %d(%s)”, input, error, buf);
// LOGE(“%d”,error)
LOGE(“打开视频失败”);
}
//3.获取视频信息
if(avformat_find_stream_info(pFormatCtx,NULL) < 0){
LOGE(“%s”,“获取视频信息失败”);
return -1;
}

int i=0;
for (int i = 0; i < pFormatCtx->nb_streams; ++i) {
    if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
        LOGE(" 找到音频id %d", pFormatCtx->streams[i]->codec->codec_type);
        audio_stream_idx=i;
        break;
    }
}

// mp3的解码器

// 获取音频编解码器
pCodecCtx=pFormatCtx->streams[audio_stream_idx]->codec;
LOGE("获取视频编码器上下文 %p ",pCodecCtx);

pCodex = avcodec\_find\_decoder(pCodecCtx->codec_id);
LOGE("获取视频编码 %p",pCodex);

if (avcodec\_open2(pCodecCtx, pCodex, NULL)<0) {
}
packet = (AVPacket \*)av\_malloc(sizeof(AVPacket));

// av_init_packet(packet);
// 音频数据

frame = av\_frame\_alloc();

// mp3 里面所包含的编码格式 转换成 pcm SwcContext
swrContext = swr_alloc();

int length=0;
int got_frame;

// 44100*2
out_buffer = (uint8_t *) av_malloc(44100 * 2);
uint64_t out_ch_layout=AV_CH_LAYOUT_STEREO;
// 输出采样位数 16位
enum AVSampleFormat out_formart=AV_SAMPLE_FMT_S16;
//输出的采样率必须与输入相同
int out_sample_rate = pCodecCtx->sample_rate;

swr\_alloc\_set\_opts(swrContext, out_ch_layout, out_formart, out_sample_rate,
                   pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0,
                   NULL);

swr\_init(swrContext);

// 获取通道数 2
out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
*rate = pCodecCtx->sample_rate;
*channel = pCodecCtx->channels;
return 0;
}
//
int getPcm(void **pcm,size_t *pcm_size){
int frameCount=0;
int got_frame;
while (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet->stream_index == audio_stream_idx) {
// 解码 mp3 编码格式frame----pcm frame
avcodec_decode_audio4(pCodecCtx, frame, &got_frame, packet);
if (got_frame) {
LOGE(“解码”);
/**
* int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
const uint8_t **in , int in_count);
*/
swr_convert(swrContext, &out_buffer, 44100 * 2, (const uint8_t **) frame->data, frame->nb_samples);
// 缓冲区的大小
int size = av_samples_get_buffer_size(NULL, out_channer_nb, frame->nb_samples,
AV_SAMPLE_FMT_S16, 1);
*pcm = out_buffer;
*pcm_size = size;
break;
}
}
}
return 0;
}

void releaseFFmpeg(){
av_free_packet(packet);
av_free(out_buffer);
av_frame_free(&frame);
swr_free(&swrContext);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);

题外话

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-WwsrDcZk-1715806332006)]

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!要在Qt编程中解码H.264音频,可以使用FFmpeg库。以下是一个简单的示例代码,展示如何使用FFmpeg解码H.264音频文件。 首先,确保您已经在Qt项目中添加了FFmpeg库,并设置了正确的链接器选项。 ```cpp extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> } int main(int argc, char *argv[]) { av_register_all(); // 打开输入文件 AVFormatContext *formatContext = nullptr; if (avformat_open_input(&formatContext, "input.mp4", nullptr, nullptr) != 0) { qDebug() << "无法打开输入文件"; return -1; } // 获取音频流信息 if (avformat_find_stream_info(formatContext, nullptr) < 0) { qDebug() << "无法获取流信息"; return -1; } // 寻找音频流索引 int audioStreamIndex = -1; for (unsigned int i = 0; i < formatContext->nb_streams; i++) { if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { audioStreamIndex = i; break; } } // 检查是否找到音频流 if (audioStreamIndex == -1) { qDebug() << "未找到音频流"; return -1; } // 获取音频解码器 AVCodecParameters *audioCodecParameters = formatContext->streams[audioStreamIndex]->codecpar; AVCodec *audioCodec = avcodec_find_decoder(audioCodecParameters->codec_id); if (audioCodec == nullptr) { qDebug() << "找不到音频解码器"; return -1; } // 创建音频解码器上下文 AVCodecContext *audioCodecContext = avcodec_alloc_context3(audioCodec); if (avcodec_parameters_to_context(audioCodecContext, audioCodecParameters) < 0) { qDebug() << "无法创建音频解码器上下文"; return -1; } // 打开音频解码器 if (avcodec_open2(audioCodecContext, audioCodec, nullptr) < 0) { qDebug() << "无法打开音频解码器"; return -1; } // 循环读取音频帧 AVPacket packet; while (av_read_frame(formatContext, &packet) >= 0) { if (packet.stream_index == audioStreamIndex) { AVFrame *frame = av_frame_alloc(); int ret = avcodec_send_packet(audioCodecContext, &packet); if (ret < 0) { qDebug() << "发送音频数据包失败"; return -1; } while (ret >= 0) { ret = avcodec_receive_frame(audioCodecContext, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; else if (ret < 0) { qDebug() << "接收音频帧失败"; return -1; } // 在这里进行音频帧的处理 } av_frame_free(&frame); } av_packet_unref(&packet); } // 清理资源 avcodec_free_context(&audioCodecContext); avformat_close_input(&formatContext); avformat_free_context(formatContext); return 0; } ``` 请注意,上述代码仅展示了如何使用FFmpeg解码H.264音频文件,并没有包括附加的音频处理逻辑。你可以在注释中的"在这里进行音频帧的处理"部分添加你自己的处理逻辑。 希望这可以帮助到您!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值