Android audio and video goes deep into 14 FFmpeg and OpenSL ES to play mp3 music, can pause (with source code download), ffmpegopensl
Project address
Https://github.com/979451341/FFmpegOpenslES
This time, FFmpeg is used to decode mp3, and the data is played to OpenSL ES and can be paused.
1. Create an engine
SlCreateEngine (& engineObject, 0, NULL, 0, NULL, NULL); // create an engine (* engineObject)-> Realize (engineObject, SL_BOOLEAN_FALSE ); // implement the engineObject interface object (* engineObject)-> GetInterface (engineObject, SL_IID_ENGINE, & engineEngine); // use the engine call interface to initialize SLEngineItf
2. Create a mixer
(* EngineEngine)-> CreateOutputMix (engineEngine, & outputMixObject, 0); // use an engine object to create a mixer interface object (* outputMixObject)-> Realize (outputMixObject, SL_BOOLEAN_FALSE ); // implement the SLresult sLresult = (* outputMixObject)-> GetInterface (outputMixObject, SL_IID_ENVIRONMENTALREVERB, & outputMixEnvironmentalReverb ); // use the interface of the mixer instance object to initialize a specific mixer object // set if (SL_RESULT_SUCCESS = sLresult) {(* response)-> SetEnvironmentalReverbProperties (outputMixEnvironmentalReverb, & settings );}
3. FFmpeg mp3 decoding preparation
Av_register_all (); char * input = "/storage/emulated/0/pauseRecordDemo/video/a.mp3"; pFormatCtx = avformat_alloc_context (); LOGE ("Lujng % s", input ); LOGE ("xxx % p", pFormatCtx); int error; char buf [] = ""; // open the video address and obtain the content (unencapsulate) 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 ("failed to open video")} // 3. get video information if (avformat_find_stream_info (pFormatCtx, NULL) <0) {LOGE ("% s", "failed to get video information"); 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 ("find audio id % d", pFormatCtx-> streams [I]-> codec-> codec_type); audio_stream_idx = I; break ;}} // mp3 decoder // obtain the audio codecs pCodecCtx = pFormatCtx-> streams [audio_stream_idx]-> codec; LOGE ("Get video encoder context % p", pCodecCtx ); pCodex = avcodec_find_decoder (pCodecCtx-> codec_id); LOGE ("Get video encoding % p", pCodex); if (avcodec_open2 (pCodecCtx, pCodex, NULL) <0) {} packet = (AVPacket *) av_malloc (sizeof (AVPacket); // av_init_packet (packet); // audio data frame = av_frame_alloc (); // convert the encoding format contained in mp3 to 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; // output 16-bit enum AVSampleFormat out_formart = AV_SAMPLE_FMT_S16; // The output sampling rate must be the same as the input int out_sample_rate = pCodecCtx-> sample_rate; percentile (swrContext, metrics, out_formart, metrics, pCodecCtx-> channel_layout, pCodecCtx-> sample_fmt, pCodecCtx-> sample_rate, 0, NULL); swr_init (swrContext); // get the number of channels 2 out_channer_nb = channels (AV_CH_LAYOUT_STEREO); * rate = pCodecCtx-> sample_rate; * channel = pCodecCtx-> channels;4. cache queue settings
Int rate; int channels; createFFmpeg (& rate, & channels); LOGE ("RATE % d", rate); LOGE ("channels % d", channels ); /** typedef struct evaluate _ {SLuint32 locatorType; // buffer Queue type SLuint32 numBuffers; // buffer bits} */SLDataLocator_AndroidBufferQueue android_queue = {queue, 2 }; /** typedef struct encode _ {SLuint32 formatType; pcm SLuint32 numChannels; number of channels SLuint32 samplesPerSec; sampling rate SLuint32 bitsPerSample; number of sampling bits SLuint32 containerSize; Number of BITs SLuint32 channelMask; end flag} SLDataFormat_PCM; */SLDataFormat_PCM = {SL_DATAFORMAT_PCM, channels, rate * 1000, weight, weight, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, weight }; /** typedef struct SLDataSource _ {void * pLocator; // Buffer Queue void * pFormat; // data style, configuration information} SLDataSource; **/SLDataSource dataSource = {& android_queue, & pcm}; Metrics metrics = {metrics, outputMixObject}; SLDataSink slDataSink = {& Metrics, NULL}; const SLInterfaceID ids [3] = {metrics, SL_IID_VOLUME tsend, SL_IID_VOLUME }; const SLboolean req [3] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE, listener};/** SLresult (* CreateAudioPlayer) (SLEngineItf self, SLObjectItf * pPlayer, SLDataSource * pAudioSrc, // set SLDataSink * pAudioSnk for data, // associate SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired); **/LOGE ("Run here ") (* engineEngine)-> CreateAudioPlayer (engineEngine, & audioplayer, & dataSource, & slDataSink, 3, ids, req); (* audioplayer)-> Realize (audioplayer, SL_BOOLEAN_FALSE ); LOGE ("Run here 2") (* audioplayer)-> GetInterface (audioplayer, SL_IID_PLAY, & slPlayItf); // initialize the player // register the buffer, play the data in the buffer (* audioplayer)-> GetInterface (audioplayer, callback, & slBufferQueueItf); // set the callback interface (* callback)-> RegisterCallback (slBufferQueueItf, getQueueCallBack, NULL );
Finally, we need to assign parameters to the cache callback function. This callback function is mainly responsible for providing the data decoded by FFmpeg.
// Start getQueueCallBack (slBufferQueueItf, NULL );
Let's take a look at what this function says. The Enqueue function puts the data into the queue, and the data is obtained from the getPcm function.
Void getQueueCallBack (SLAndroidSimpleBufferQueueItf slBufferQueueItf, void * context) {buffersize = 0; getPcm (& buffer, & buffersize); if (buffer! = NULL & buffersize! = 0) {// Add the obtained data to the queue (* slBufferQueueItf)-> Enqueue (slBufferQueueItf, buffer, buffersize );}}
This FFmpeg decodes mp3 to get Pcm data. This is mainly because every time a packet data is decoded, it jumps out of the loop and pushes the data to the upper-layer function into the queue. When the data in the queue is read, call the getQueueCallBack function to obtain the pcm Data decoded by FFmpeg.
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) {// decode the mp3 encoding format frame ---- pcm frame avcodec_decode_audio4 (pCodecCtx, frame, & got_frame, packet); if (got_frame) {LOGE ("decoding");/*** 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 ); // buffer size int size = bytes (NULL, out_channer_nb, frame-> nb_samples, AV_SAMPLE_FMT_S16, 1); * pcm = out_buffer; * pcm_size = size; break ;}}} return 0 ;}
5. Play Music
(*slPlayItf)->SetPlayState(slPlayItf,SL_PLAYSTATE_PLAYING);
6. Pause music
(*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PAUSED);
7. release resources
First release the entity about OpenSL ES
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; }
Then release the resources occupied by FFmpeg.
av_free_packet(packet); av_free(out_buffer); av_frame_free(&frame); swr_free(&swrContext); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx);