您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
16. 在835cpu的手机中测试并修正了音频播放Close的bug~1
发布时间:2021-06-14 11:10:45编辑:雪饮阅读()
要解決這個問題的核心在於重采樣的時候close方法,因爲一般不關閉頂多就是一直消耗著内存,最後被强行崩潰或者假死,而這種秒崩的情況肯定是close處理的不當。所以cpp/IPlayer.cpp
#include "IPlayer.h"
#include "IDemux.h"
#include "IDecode.h"
#include "IAudioPlay.h"
#include "IVideoView.h"
#include "IResample.h"
#include "XLog.h"
IPlayer *IPlayer::Get(unsigned char index)
{
static IPlayer p[256];
return &p[index];
}
void IPlayer::Main()
{
while (!isExit)
{
mux.lock();
if(!audioPlay|| !vdecode)
{
mux.unlock();
XSleep(2);
continue;
}
//同步
//获取音频的pts 告诉视频
int apts = audioPlay->pts;
//XLOGE("apts = %d",apts);
vdecode->synPts = apts;
mux.unlock();
XSleep(2);
}
}
void IPlayer::Close()
{
mux.lock();
//2 先关闭主体线程,再清理观察者
//同步线程
XThread::Stop();
//解封装
if(demux)
demux->Stop();
//解码
if(vdecode)
vdecode->Stop();
if(adecode)
adecode->Stop();
//2 清理缓冲队列
if(vdecode)
vdecode->Clear();
if(adecode)
adecode->Clear();
if(audioPlay)
audioPlay->Clear();
//3 清理资源
if(audioPlay)
audioPlay->Close();
if(videoView)
videoView->Close();
if(vdecode)
vdecode->Close();
if(adecode)
adecode->Close();
if(demux)
demux->Close();
mux.unlock();
}
bool IPlayer::Open(const char *path)
{
Close();
mux.lock();
//解封装
if(!demux || !demux->Open(path))
{
mux.unlock();
XLOGE("demux->Open %s failed!",path);
return false;
}
//解码 解码可能不需要,如果是解封之后就是原始数据
if(!vdecode || !vdecode->Open(demux->GetVPara(),isHardDecode))
{
XLOGE("vdecode->Open %s failed!",path);
//return false;
}
if(!adecode || !adecode->Open(demux->GetAPara()))
{
XLOGE("adecode->Open %s failed!",path);
//return false;
}
//重采样 有可能不需要,解码后或者解封后可能是直接能播放的数据
//if(outPara.sample_rate <= 0)
outPara = demux->GetAPara();
if(!resample || !resample->Open(demux->GetAPara(),outPara))
{
XLOGE("resample->Open %s failed!",path);
}
mux.unlock();
return true;
}
bool IPlayer::Start()
{
mux.lock();
if(vdecode)
vdecode->Start();
if(!demux || !demux->Start())
{
mux.unlock();
XLOGE("demux->Start failed!");
return false;
}
if(adecode)
adecode->Start();
if(audioPlay)
audioPlay->StartPlay(outPara);
XThread::Start();
mux.unlock();
return true;
}
void IPlayer::InitView(void *win)
{
if(videoView)
{
videoView->Close();
videoView->SetRender(win);
}
}
#include "IDemux.h"
#include "IDecode.h"
#include "IAudioPlay.h"
#include "IVideoView.h"
#include "IResample.h"
#include "XLog.h"
IPlayer *IPlayer::Get(unsigned char index)
{
static IPlayer p[256];
return &p[index];
}
void IPlayer::Main()
{
while (!isExit)
{
mux.lock();
if(!audioPlay|| !vdecode)
{
mux.unlock();
XSleep(2);
continue;
}
//同步
//获取音频的pts 告诉视频
int apts = audioPlay->pts;
//XLOGE("apts = %d",apts);
vdecode->synPts = apts;
mux.unlock();
XSleep(2);
}
}
void IPlayer::Close()
{
mux.lock();
//2 先关闭主体线程,再清理观察者
//同步线程
XThread::Stop();
//解封装
if(demux)
demux->Stop();
//解码
if(vdecode)
vdecode->Stop();
if(adecode)
adecode->Stop();
//2 清理缓冲队列
if(vdecode)
vdecode->Clear();
if(adecode)
adecode->Clear();
if(audioPlay)
audioPlay->Clear();
//3 清理资源
if(audioPlay)
audioPlay->Close();
if(videoView)
videoView->Close();
if(vdecode)
vdecode->Close();
if(adecode)
adecode->Close();
if(demux)
demux->Close();
mux.unlock();
}
bool IPlayer::Open(const char *path)
{
Close();
mux.lock();
//解封装
if(!demux || !demux->Open(path))
{
mux.unlock();
XLOGE("demux->Open %s failed!",path);
return false;
}
//解码 解码可能不需要,如果是解封之后就是原始数据
if(!vdecode || !vdecode->Open(demux->GetVPara(),isHardDecode))
{
XLOGE("vdecode->Open %s failed!",path);
//return false;
}
if(!adecode || !adecode->Open(demux->GetAPara()))
{
XLOGE("adecode->Open %s failed!",path);
//return false;
}
//重采样 有可能不需要,解码后或者解封后可能是直接能播放的数据
//if(outPara.sample_rate <= 0)
outPara = demux->GetAPara();
if(!resample || !resample->Open(demux->GetAPara(),outPara))
{
XLOGE("resample->Open %s failed!",path);
}
mux.unlock();
return true;
}
bool IPlayer::Start()
{
mux.lock();
if(vdecode)
vdecode->Start();
if(!demux || !demux->Start())
{
mux.unlock();
XLOGE("demux->Start failed!");
return false;
}
if(adecode)
adecode->Start();
if(audioPlay)
audioPlay->StartPlay(outPara);
XThread::Start();
mux.unlock();
return true;
}
void IPlayer::InitView(void *win)
{
if(videoView)
{
videoView->Close();
videoView->SetRender(win);
}
}
還有就是在c語言中一個變量清理后還要置於null,這個也很重要,所以cpp/SLAudioPlay.cpp:
#include "SLAudioPlay.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include "XLog.h"
static SLObjectItf engineSL = NULL;
static SLEngineItf eng = NULL;
static SLObjectItf mix = NULL;
static SLObjectItf player = NULL;
static SLPlayItf iplayer = NULL;
static SLAndroidSimpleBufferQueueItf pcmQue = NULL;
SLAudioPlay::SLAudioPlay()
{
buf = new unsigned char[1024*1024];
}
SLAudioPlay::~SLAudioPlay()
{
delete buf;
buf = 0;
}
static SLEngineItf CreateSL()
{
SLresult re;
SLEngineItf en;
re = slCreateEngine(&engineSL,0,0,0,0,0);
if(re != SL_RESULT_SUCCESS) return NULL;
re = (*engineSL)->Realize(engineSL,SL_BOOLEAN_FALSE);
if(re != SL_RESULT_SUCCESS) return NULL;
re = (*engineSL)->GetInterface(engineSL,SL_IID_ENGINE,&en);
if(re != SL_RESULT_SUCCESS) return NULL;
return en;
}
void SLAudioPlay::PlayCall(void *bufq)
{
if(!bufq)return;
SLAndroidSimpleBufferQueueItf bf = (SLAndroidSimpleBufferQueueItf)bufq;
//XLOGE("SLAudioPlay::PlayCall");
//阻塞
XData d = GetData();
if(d.size<=0)
{
XLOGE("GetData() size is 0");
return;
}
if(!buf)
return;
memcpy(buf,d.data,d.size);
mux.lock();
if(pcmQue && (*pcmQue))
(*pcmQue)->Enqueue(pcmQue,buf,d.size);
mux.unlock();
d.Drop();
}
static void PcmCall(SLAndroidSimpleBufferQueueItf bf,void *contex)
{
SLAudioPlay *ap = (SLAudioPlay *)contex;
if(!ap)
{
XLOGE("PcmCall failed contex is null!");
return;
}
ap->PlayCall((void *)bf);
}
void SLAudioPlay::Close()
{
IAudioPlay::Clear();
mux.lock();
//停止播放
if(iplayer && (*iplayer))
{
(*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_STOPPED);
}
//清理播放队列
if(pcmQue && (*pcmQue))
{
(*pcmQue)->Clear(pcmQue);
}
//销毁player对象
if(player && (*player))
{
(*player)->Destroy(player);
}
//销毁混音器
if(mix && (*mix))
{
(*mix)->Destroy(mix);
}
//销毁播放引擎
if(engineSL && (*engineSL))
{
(*engineSL)->Destroy(engineSL);
}
engineSL = NULL;
eng = NULL;
mix = NULL;
player = NULL;
iplayer = NULL;
pcmQue = NULL;
mux.unlock();
}
bool SLAudioPlay::StartPlay(XParameter out)
{
Close();
mux.lock();
//1 创建引擎
eng = CreateSL();
if(eng)
{
XLOGI("CreateSL success! ");
}
else
{
mux.unlock();
XLOGE("CreateSL failed! ");
return false;
}
//2 创建混音器
SLresult re = 0;
re = (*eng)->CreateOutputMix(eng,&mix,0,0,0);
if(re !=SL_RESULT_SUCCESS )
{
mux.unlock();
XLOGE("SL_RESULT_SUCCESS failed!");
return false;
}
re = (*mix)->Realize(mix,SL_BOOLEAN_FALSE);
if(re !=SL_RESULT_SUCCESS )
{
mux.unlock();
XLOGE("(*mix)->Realize failed!");
return false;
}
SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX,mix};
SLDataSink audioSink= {&outmix,0};
//3 配置音频信息
//缓冲队列
SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10};
//音频格式
SLDataFormat_PCM pcm = {
SL_DATAFORMAT_PCM,
(SLuint32) out.channels,// 声道数
(SLuint32) out.sample_rate*1000,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN //字节序,小端
};
SLDataSource ds = {&que,&pcm};
//4 创建播放器
const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE};
const SLboolean req[] = {SL_BOOLEAN_TRUE};
re = (*eng)->CreateAudioPlayer(eng,&player,&ds,&audioSink,sizeof(ids)/sizeof(SLInterfaceID),ids,req);
if(re !=SL_RESULT_SUCCESS )
{
mux.unlock();
XLOGE("CreateAudioPlayer failed!");
return false;
} else{
XLOGI("CreateAudioPlayer success!");
}
(*player)->Realize(player,SL_BOOLEAN_FALSE);
//获取player接口
re = (*player)->GetInterface(player,SL_IID_PLAY,&iplayer);
if(re !=SL_RESULT_SUCCESS )
{
mux.unlock();
XLOGE("GetInterface SL_IID_PLAY failed!");
return false;
}
re = (*player)->GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);
if(re !=SL_RESULT_SUCCESS )
{
mux.unlock();
XLOGE("GetInterface SL_IID_BUFFERQUEUE failed!");
return false;
}
//设置回调函数,播放队列空调用
(*pcmQue)->RegisterCallback(pcmQue,PcmCall,this);
//设置为播放状态
(*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING);
//启动队列回调
(*pcmQue)->Enqueue(pcmQue,"",1);
mux.unlock();
XLOGI("SLAudioPlay::StartPlay success!");
return true;
}
然後OpenUrl.java中要實現直播流的播放按鈕對應的響應事件:
package com.example.xplay;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
/**
* Created by Administrator on 2018-03-11.
*/
public class OpenUrl extends AppCompatActivity {
private Button btfile;
private Button btrtmp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.openurl );
btfile = findViewById( R.id.playvideo );
btfile.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText t = findViewById( R.id.fileurl );
//用户输入的URL,打开视频
Open(t.getText().toString());
//关闭当前窗口
finish();
}
}
);
btrtmp = findViewById( R.id.playrtmp );
btrtmp.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText t = findViewById( R.id.rtmpurl );
//用户输入的URL,打开视频
Open(t.getText().toString());
//关闭当前窗口
finish();
}
}
);
}
public native void Open(String url);
}
关键字词:835cpu
相关文章
-
无相关信息