Ffmpeg + OpenSLES + Android 播放音频

一个类一个类介绍

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");

        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值