一个类一个类介绍
1 BugCallJava
//
// Created by Administrator on 2020/9/10.
//
#ifndef MYCPP_BUGCALLJAVA_H
#define MYCPP_BUGCALLJAVA_H
#define MAIN_THILD 0
#define CHILD_THILD 1
extern "C" {
#include "jni.h"
};
class BugCallJava {
public:
JavaVM *jvm;
JNIEnv *jenv;
jobject jobj;
jclass jclz;
jmethodID jmid;
public:
BugCallJava(JavaVM *vm, JNIEnv *env, jobject obj);
~BugCallJava();
public:
void callJava(int type);
};
#endif //MYCPP_BUGCALLJAVA_H
//
// Created by Administrator on 2020/9/10.
//
#include "BugCallJava.h"
BugCallJava::~BugCallJava() {
}
BugCallJava::BugCallJava(JavaVM *vm, JNIEnv *env, jobject obj) {
jvm = vm;
jenv = env;
jobj = env->NewGlobalRef(obj);
jclz = env->GetObjectClass(jobj);
jmid = env->GetMethodID(jclz, "callBack", "()V");
}
void BugCallJava::callJava(int type) {
if (type == MAIN_THILD) {
jenv->CallVoidMethod(jobj, jmid);
} else if (type == CHILD_THILD) {
jvm->AttachCurrentThread(&jenv, NULL);
jenv->CallVoidMethod(jobj, jmid);
jvm->DetachCurrentThread();
}
}
2 BugFfmpeg
//
// Created by Administrator on 2020/9/10.
//
#ifndef MYCPP_BUGFFMPEG_H
#define MYCPP_BUGFFMPEG_H
#include "BugPlayer.h"
#include "BugCallJava.h"
#include "BugQueue.h"
class BugFfmpeg {
public:
BugPlayer *pPlayer;
BugCallJava *mCallJava;
BugQueue *mQueue;
pthread_t load_thread;
const char *url;
public:
BugFfmpeg(BugPlayer *player, BugCallJava *callJava, BugQueue *pQueue, const char *url);
~BugFfmpeg();
public:
void load();
void toLoad();
void start();
};
#endif //MYCPP_BUGFFMPEG_H
//
// Created by Administrator on 2020/9/10.
//
#include "BugFfmpeg.h"
BugFfmpeg::~BugFfmpeg() {
}
BugFfmpeg::BugFfmpeg(BugPlayer *player, BugCallJava *callJava, BugQueue *pQueue, const char *url) {
this->pPlayer = player;
this->mCallJava = callJava;
this->mQueue = pQueue;
this->url = url;
}
void *load_function(void *data) {
BugFfmpeg *ffmpeg = static_cast<BugFfmpeg *>(data);
ffmpeg->toLoad();
pthread_exit(&ffmpeg->load_thread);
}
void BugFfmpeg::load() {
pthread_create(&this->load_thread, NULL, load_function, this);
}
void BugFfmpeg::toLoad() {
avcodec_register_all();
avformat_network_init();
pPlayer->pFormatContext = avformat_alloc_context();
int openInput = avformat_open_input(&pPlayer->pFormatContext, url, NULL, NULL);
if (openInput != 0) {
LOGE("打开失败 %s", url);
return;
}
int streamInfo = avformat_find_stream_info(pPlayer->pFormatContext, NULL);
if (streamInfo < 0) {
LOGE("寻找流失败 %s", url);
return;
}
for (int i = 0; i < pPlayer->pFormatContext->nb_streams; ++i) {
if (pPlayer->pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
pPlayer->stream_index = i;
pPlayer->setSampleRate(pPlayer->pFormatContext->streams[i]->codecpar->sample_rate);
pPlayer->codecpar = pPlayer->pFormatContext->streams[i]->codecpar;
break;
}
}
if (pPlayer->stream_index == -1) {
LOGE("寻找流失败 %s", url);
return;
}
AVCodec *pCodec = avcodec_find_decoder(pPlayer->codecpar->codec_id);
if (!pCodec) {
LOGE("寻找解码器失败 ");
return;
}
pPlayer->pCodeContext = avcodec_alloc_context3(pCodec);
if (!pPlayer->pCodeContext) {
LOGE("请求空间失败 ");
return;
}
int ret = avcodec_parameters_to_context(pPlayer->pCodeContext, pPlayer->codecpar);
if (ret < 0) {
LOGE("复制失败 ");
return;
}
int open2 = avcodec_open2(pPlayer->pCodeContext, pCodec, NULL);
if (open2 != 0) {
return;
}
mCallJava->callJava(CHILD_THILD);
}
void BugFfmpeg::start() {
pPlayer->play();
while (pPlayer->pQueue->mStatue != NULL && !pPlayer->pQueue->mStatue->exit) {
AVPacket *pPacket = av_packet_alloc();
if (av_read_frame(pPlayer->pFormatContext, pPacket) == 0) {
if (pPacket->stream_index == pPlayer->stream_index) {
pPlayer->pQueue->putPacket(pPacket);
} else {
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
}
} else {
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
while (pPlayer->pQueue->mStatue != NULL && !pPlayer->pQueue->mStatue->exit) {
if (pPlayer->pQueue->getQueueSize() > 0) {
continue;
} else {
pPlayer->pQueue->mStatue->exit = true;
}
}
}
}
}
3 BugPlayer
//
// Created by Administrator on 2020/9/10.
//
#ifndef MYCPP_BUGPLAYER_H
#define MYCPP_BUGPLAYER_H
#include "BugQueue.h"
extern "C"{
#include "SLES/OpenSLES.h"
#include "SLES/OpenSLES_Android.h"
};
class BugPlayer {
public:
AVFormatContext *pFormatContext;
int stream_index;
int sampleRate;
AVCodecParameters *codecpar;
BugQueue *pQueue;
pthread_t play_t;
void setSampleRate(int i);
AVCodecContext *pCodeContext;
SLObjectItf enginObj;
SLEngineItf enginEngin;
SLObjectItf outObj;
SLEnvironmentalReverbItf outItf;
SLEnvironmentalReverbSettings outSetting;
SLObjectItf pcmObj;
SLPlayItf pcmPlay;
SLVolumeItf pcmVol;
SLAndroidSimpleBufferQueueItf slDataLocatorAndroidSimpleBufferQueue;
public:
BugPlayer(BugQueue *bugQueue);
int run();
void init();
void play();
uint8_t *buffer;
int getCurrentSampleRateForOpensles();
};
#endif //MYCPP_BUGPLAYER_H
//
// Created by Administrator on 2020/9/10.
//
#include "BugPlayer.h"
void BugPlayer::setSampleRate(int i) {
this->sampleRate = i;
buffer = static_cast<uint8_t *>(malloc(i * 2 * 2));
}
void pcmBufferCallback(SLAndroidSimpleBufferQueueItf buff, void *context) {
BugPlayer *bugPlayer = static_cast<BugPlayer *>(context);
int size = bugPlayer->run();
LOGE("pcmBufferCallback %d", size)
if (size > 0) {
(*bugPlayer->slDataLocatorAndroidSimpleBufferQueue)->Enqueue(
bugPlayer->slDataLocatorAndroidSimpleBufferQueue, (char *) bugPlayer->buffer, size);
}
}
int BugPlayer::run() {
int dataSize;
while (pQueue->mStatue != NULL && !pQueue->mStatue->exit) {
LOGE("1123132")
AVPacket *pPacket = av_packet_alloc();
if (pQueue->getPacket(pPacket) != 0) {
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
continue;
}
int ret;
ret = avcodec_send_packet(pCodeContext, pPacket);
LOGE(" cccc %d", ret)
if (ret != 0) {
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
continue;
}
AVFrame *pFrame = av_frame_alloc();
ret = avcodec_receive_frame(pCodeContext, pFrame);
if (ret != 0) {
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
av_frame_free(&pFrame);
av_free(pFrame);
pFrame = NULL;
continue;
}
if (pFrame->channel_layout == 0 && pFrame->channels > 0) {
pFrame->channel_layout = av_get_default_channel_layout(pFrame->channels);
} else if (pFrame->channels == 0 && pFrame->channel_layout > 0) {
pFrame->channels = av_get_channel_layout_nb_channels(pFrame->channel_layout);
}
SwrContext *sclz;
sclz = swr_alloc_set_opts(
NULL,
AV_CH_LAYOUT_STEREO,
AV_SAMPLE_FMT_S16,
pFrame->sample_rate,
pFrame->channel_layout,
static_cast<AVSampleFormat>(pFrame->format),
pFrame->sample_rate,
NULL, NULL
);
if (!sclz || swr_init(sclz) < 0) {
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
av_frame_free(&pFrame);
av_free(pFrame);
pFrame = NULL;
swr_free(&sclz);
continue;
}
int nb = swr_convert(sclz, &buffer, pFrame->nb_samples,
(const uint8_t **) (pFrame->data), pFrame->nb_samples);
int outchannels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
dataSize = nb * outchannels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
av_frame_free(&pFrame);
av_free(pFrame);
pFrame = NULL;
swr_free(&sclz);
break;
}
return dataSize;
}
BugPlayer::BugPlayer(BugQueue *bugQueue) {
this->pQueue = bugQueue;
}
int BugPlayer::getCurrentSampleRateForOpensles() {
int rate = 0;
switch (sampleRate) {
case 8000:
rate = SL_SAMPLINGRATE_8;
break;
case 11025:
rate = SL_SAMPLINGRATE_11_025;
break;
case 12000:
rate = SL_SAMPLINGRATE_12;
break;
case 16000:
rate = SL_SAMPLINGRATE_16;
break;
case 22050:
rate = SL_SAMPLINGRATE_22_05;
break;
case 24000:
rate = SL_SAMPLINGRATE_24;
break;
case 32000:
rate = SL_SAMPLINGRATE_32;
break;
case 44100:
rate = SL_SAMPLINGRATE_44_1;
break;
case 48000:
rate = SL_SAMPLINGRATE_48;
break;
case 64000:
rate = SL_SAMPLINGRATE_64;
break;
case 88200:
rate = SL_SAMPLINGRATE_88_2;
break;
case 96000:
rate = SL_SAMPLINGRATE_96;
break;
case 192000:
rate = SL_SAMPLINGRATE_192;
break;
default:
rate = SL_SAMPLINGRATE_44_1;
}
return rate;
}
void BugPlayer::init() {
SLresult result;
slCreateEngine(&enginObj, 0, 0, 0, 0, 0);
(*enginObj)->Realize(enginObj, SL_BOOLEAN_FALSE);
(*enginObj)->GetInterface(enginObj, SL_IID_ENGINE, &enginEngin);
const SLInterfaceID mid[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean req[1] = {SL_BOOLEAN_FALSE};
result = (*enginEngin)->CreateOutputMix(enginEngin, &outObj, 1, mid, req);
result = (*outObj)->Realize(outObj, SL_BOOLEAN_FALSE);
result = (*outObj)->GetInterface(outObj, SL_IID_ENVIRONMENTALREVERB, &outItf);
if (SL_RESULT_SUCCESS == result) {
result = (*outItf)->SetEnvironmentalReverbProperties(outItf, &outSetting);
}
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outObj};
SLDataLocator_AndroidSimpleBufferQueue androidSimpleBufferQueue = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM pcm = {
SL_DATAFORMAT_PCM,
2,
(SLuint32) getCurrentSampleRateForOpensles(),
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN
};
SLDataSource slDataSource = {&androidSimpleBufferQueue, &pcm};
SLDataSink sink = {&outputMix, NULL};
SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*enginEngin)->CreateAudioPlayer(enginEngin, &pcmObj, &slDataSource, &sink, 3, ids,
req2);
(*pcmObj)->Realize(pcmObj, SL_BOOLEAN_FALSE);
(*pcmObj)->GetInterface(pcmObj, SL_IID_PLAY, &pcmPlay);
(*pcmObj)->GetInterface(pcmObj, SL_IID_BUFFERQUEUE, &slDataLocatorAndroidSimpleBufferQueue);
(*slDataLocatorAndroidSimpleBufferQueue)->RegisterCallback(
slDataLocatorAndroidSimpleBufferQueue, pcmBufferCallback, this);
(*pcmObj)->GetInterface(pcmObj, SL_IID_VOLUME, &pcmVol);
(*pcmPlay)->SetPlayState(pcmPlay, SL_PLAYSTATE_PLAYING);
pcmBufferCallback(slDataLocatorAndroidSimpleBufferQueue, this);
}
void *play_function(void *data) {
BugPlayer *player = static_cast<BugPlayer *>(data);
player->init();
pthread_exit(&player->play_t);
}
void BugPlayer::play() {
pthread_create(&play_t, NULL, play_function, this);
}
4 BugQueue
//
// Created by Administrator on 2020/9/10.
//
#ifndef MYCPP_BUGQUEUE_H
#define MYCPP_BUGQUEUE_H
#include "pthread.h"
#include "queue"
#include "BugStatue.h"
#include "AndroidLog.h"
#include "string.h"
#include "jni.h"
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavfilter/avfilter.h"
#include "libswresample/swresample.h"
#include "libswscale/swscale.h"
};
class BugQueue {
public:
pthread_mutex_t mutex;
pthread_cond_t cond;
std::queue<AVPacket *> mQueue;
BugStatue *mStatue;
public:
BugQueue(BugStatue *statue);
~BugQueue();
public:
int getQueueSize();
int putPacket(AVPacket *packet);
int getPacket(AVPacket *packet);
};
#endif //MYCPP_BUGQUEUE_H
//
// Created by Administrator on 2020/9/10.
//
#include "BugQueue.h"
BugQueue::~BugQueue() {
}
BugQueue::BugQueue(BugStatue *statue) {
mStatue = statue;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
}
int BugQueue::getQueueSize() {
int size = 0;
pthread_mutex_lock(&mutex);
size = mQueue.size();
pthread_mutex_unlock(&mutex);
return size;
}
int BugQueue::putPacket(AVPacket *packet) {
pthread_mutex_lock(&mutex);
mQueue.push(packet);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return 0;
}
int BugQueue::getPacket(AVPacket *packet) {
pthread_mutex_lock(&mutex);
while (mStatue != NULL && !mStatue->exit) {
if (mQueue.size() > 0) {
AVPacket *pPacket = mQueue.front();
if (av_packet_ref(packet, pPacket) == 0) {
mQueue.pop();
}
av_packet_free(&pPacket);
av_free(pPacket);
pPacket = NULL;
break;
} else {
pthread_cond_wait(&cond, &mutex);
}
}
pthread_mutex_unlock(&mutex);
return 0;
}
5 BugStatue
//
// Created by Administrator on 2020/9/10.
//
#ifndef MYCPP_BUGSTATUE_H
#define MYCPP_BUGSTATUE_H
class BugStatue {
public:
bool exit;
public:
BugStatue();
~BugStatue();
};
#endif //MYCPP_BUGSTATUE_H
//
// Created by Administrator on 2020/9/10.
//
#include "BugStatue.h"
BugStatue::~BugStatue() {
}
BugStatue::BugStatue() {
exit = false;
}
6 主类
#include <jni.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include "BugFfmpeg.h"
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
}
JavaVM *javaVm;
BugFfmpeg *pFfmpeg;
extern "C"
JNIEXPORT void JNICALL
Java_com_rulerbug_myldemo_Demo_play(JNIEnv *env, jobject instance, jstring path) {
BugCallJava *pJava = new BugCallJava(javaVm, env, instance);
BugStatue *pStatue = new BugStatue();
BugQueue *pQueue = new BugQueue(pStatue);
BugPlayer *pPlayer = new BugPlayer(pQueue);
pFfmpeg = new BugFfmpeg(pPlayer, pJava, pQueue, env->GetStringUTFChars(path, 0));
pFfmpeg->load();
}
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
jint result = -1;
javaVm = vm;
JNIEnv *env;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return result;
}
return JNI_VERSION_1_4;
}extern "C"
JNIEXPORT void JNICALL
Java_com_rulerbug_myldemo_Demo_start(JNIEnv *env, jobject thiz) {
if (pFfmpeg == NULL) {
return;
}
pFfmpeg->start();
}
kotlin类
class Demo {
external fun play(s: String)
external fun start()
fun callBack() {
start()
}
companion object {
init {
System.loadLibrary("native-lib");
System.loadLibrary("avcodec");
System.loadLibrary("avdevice");
System.loadLibrary("avfilter");
System.loadLibrary("avformat");
System.loadLibrary("avutil");
System.loadLibrary("postproc");
System.loadLibrary("swresample");
System.loadLibrary("swscale");
}
}
}