網上有很多關于pos機免費辦理音頻,FFmpeg 4.0.2 + SDL2 播放音頻「資料源碼分享」的知識,也有很多人為大家解答關于pos機免費辦理音頻的問題,今天pos機之家(www.shbwcl.net)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
pos機免費辦理音頻
本章開始之前希望大家有基本的音頻的一些基礎知識,包括且不限于
音頻采樣采樣率采樣格式(位寬/位數)聲道數聲道布局 (單聲道,雙聲道,5.1 7.1)FFmpeg+SDL播放器開發與實現+源碼分享點擊查看 「鏈接」
SDL2 音頻播放流程簡介SDL2 音頻播放比視頻播放要復雜一點,我盡量通俗點解釋流程
首先初始化一個結構體SDL_AudioSpec,這個結構體放著你想要播放的音頻的格式聲明一個函數void fill_audio(void * codecContext, Uint8 stream, int len),這個函數指針被SDL_AudioSpec.callback引用,第一個void的參數為SDL_AudioSpec.userdata,這個是用戶自己設置的一個數據的指針,第二個就是當前音頻設備需要喂入的數據指針,第三個是需要的喂入的音頻采樣長度,這個方法會在設備需要播放音頻的時候被動調用去獲取需要播放的音頻采樣調用SDL_OpenAudio(desired,obtained)打開音頻,這個方法比較奇怪,desired 傳進去之后,打開設備,如果obtained不為null,則硬件的實際參數將賦值到obtained,如果它為NULL,則傳遞出去的音頻數據將自動轉為硬件的音頻格式,如果返回-1,則說明打開設備或者設置音頻線程失敗在FFmpeg解碼返回一幀PCM數據后,需要把這個數據播完才能繼續播下一幀數據大概就是這么個流程,我們上代碼對應代碼看的話就比較清晰點了 FFmpeg 解析音頻 + SDL2 播放 這邊為了大家整塊的看的清楚 我直接貼上來所有的代碼,里面有詳細的注釋
//// Created by MirsFang on 2019-03-20.//namespace sdl_audio {#include <iostream>extern "C" {#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>#include <libswresample/swresample.h>#include <SDL2/SDL.h>}using namespace std;/** * 準備 ffmpeg * @param url 視頻路徑 */void preparFFmpeg(const char *url);/** * 釋放內存 */void free();#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio 48000 * (32/8)//一幀PCM的數據長度unsigned int audioLen = 0;unsigned char *audioChunk = nullptr;//當前讀取的位置unsigned char *audioPos = nullptr;/** 被SDL2調用的回調函數 當需要獲取數據喂入硬件播放的時候調用 **/void fill_audio(void *codecContext, Uint8 *stream, int len) { //SDL2中必須首先使用SDL_memset()將stream中的數據設置為0 SDL_memset(stream, 0, len); if (audioLen == 0) return; len = (len > audioLen ? audioLen : len); //將數據合并到 stream 里 SDL_MixAudio(stream, audioPos, len, SDL_MIX_MAXVOLUME); //一幀的數據控制 audioPos += len; audioLen -= len;}/** ########### SDL初始化 ############## **//** 自己想要的輸出的音頻格式 **/SDL_AudioSpec wantSpec;/** 重采樣上下文 **/SwrContext *auConvertContext;/** ########### FFmpeg 相關 ############# **/AVFormatContext *formatContext;AVCodecContext *codecContext;AVCodec *codec;AVPacket *packet;AVFrame *frame;int audioIndex = -1;uint64_t out_chn_layout = AV_CH_LAYOUT_STEREO; //輸出的通道布局 雙聲道enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; //輸出的聲音格式int out_sample_rate = 44100; //輸出的采樣率int out_nb_samples = -1; //輸出的音頻采樣int out_channels = -1; //輸出的通道數int out_buffer_size = -1; //輸出buff大小unsigned char *outBuff = NULL;//輸出的Buffer數據uint64_t in_chn_layout = -1; //輸入的通道布局/** 外部調用方法 **/void playAudio(const char *url) { /** ########### 初始化FFmpeg ############# **/ preparFFmpeg(url); /** ########## 獲取實際音頻的參數 ##########**/ //單個通道中的采樣數 out_nb_samples = codecContext->frame_size; //輸出的聲道數 out_channels = av_get_channel_layout_nb_channels(out_chn_layout); //輸出音頻的布局 in_chn_layout = av_get_default_channel_layout(codecContext->channels); /** 計算重采樣后的實際數據大小,并分配空間 **/ //計算輸出的buffer的大小 out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1); //分配輸出buffer的空間 outBuff = (unsigned char *) av_malloc(MAX_AUDIO_frame_SIZE * 2); //雙聲道 //初始化SDL中自己想設置的參數 wantSpec.freq = out_sample_rate; wantSpec.format = AUDIO_S16SYS; wantSpec.channels = out_channels; wantSpec.silence = 0; wantSpec.samples = out_nb_samples; wantSpec.callback = fill_audio; wantSpec.userdata = codecContext; //打開音頻之后wantSpec的值可能會有改動,返回實際設備的參數值 if (SDL_OpenAudio(&wantSpec, NULL) < 0) { cout << "[error] open audio error" << endl; return; } //初始化重采樣器 auConvertContext = swr_alloc_set_opts(NULL, out_chn_layout, out_sample_fmt, out_sample_rate, in_chn_layout, codecContext->sample_fmt, codecContext->sample_rate, 0, NULL); //初始化SwResample的Context swr_init(auConvertContext); //開始播放 調用這個方法硬件才會開始播放 SDL_PauseAudio(0); //循環讀取packet并且解碼 int sendcode = 0; while (av_read_frame(formatContext, packet) >= 0) { if (packet->stream_index != audioIndex)continue; //接受解碼后的音頻數據 while (avcodec_receive_frame(codecContext, frame) == 0) { swr_convert(auConvertContext, &outBuff, MAX_AUDIO_FRAME_SIZE, (const uint8_t **) frame->data, frame->nb_samples); //如果沒有播放完就等待1ms while (audioLen > 0) SDL_Delay(1); //同步數據 audioChunk = (unsigned char *) outBuff; audioPos = audioChunk; audioLen = out_buffer_size; } //發送解碼前的包數據 sendcode = avcodec_send_packet(codecContext, packet); //根據發送的返回值判斷狀態 if (sendcode == 0) { cout << "[debug] " << "SUCCESS" << endl; } else if (sendcode == AVERROR_EOF) { cout << "[debug] " << "EOF" << endl; } else if (sendcode == AVERROR(EAGAIN)) { cout << "[debug] " << "EAGAIN" << endl; } else { cout << "[debug] " << av_err2str(AVERROR(sendcode)) << endl; } av_packet_unref(packet); }}/** 準備FFmpeg **/void preparFFmpeg(const char *url) { int retcode; //初始化FormatContext formatContext = avformat_alloc_context(); if (!formatContext) { cout << "[error] alloc format context error!" << endl; return; } //打開輸入流 retcode = avformat_open_input(&formatContext, url, nullptr, nullptr); if (retcode != 0) { cout << "[error] open input error!" << endl; return; } //讀取媒體文件信息 retcode = avformat_find_stream_info(formatContext, NULL); if (retcode != 0) { cout << "[error] find stream error!" << endl; return; } //分配codecContext codecContext = avcodec_alloc_context3(NULL); if (!codecContext) { cout << "[error] alloc codec context error!" << endl; return; } //尋找到音頻流的下標 audioIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); //將視頻流的的編解碼信息拷貝到codecContext中 retcode = avcodec_parameters_to_context(codecContext, formatContext->streams[audioIndex]->codecpar); if (retcode != 0) { cout << "[error] parameters to context error!" << endl; return; } //查找解碼器 codec = avcodec_find_decoder(codecContext->codec_id); if (codec == nullptr) { cout << "[error] find decoder error!" << endl; return; } //打開解碼器 retcode = avcodec_open2(codecContext, codec, nullptr); if (retcode != 0) { cout << "[error] open decodec error!" << endl; return; } //初始化一個packet packet = av_packet_alloc(); //初始化一個Frame frame = av_frame_alloc();}void free(){ if (formatContext != nullptr) avformat_close_input(&formatContext); if (codecContext != nullptr) avcodec_free_context(&codecContext); if (packet != nullptr) av_packet_free(&packet); if (frame != nullptr) av_frame_free(&frame); if (auConvertContext != nullptr) swr_free(&auConvertContext); SDL_CloseAudio(); SDL_Quit();}}
我們在main方法中
sdl_audio::playAudio(url);
我們就能聽到聲音了
作者:Mirs 鏈接:https://juejin.cn/post/6844903815930609677
以上就是關于pos機免費辦理音頻,FFmpeg 4.0.2 + SDL2 播放音頻「資料源碼分享」的知識,后面我們會繼續為大家整理關于pos機免費辦理音頻的知識,希望能夠幫助到大家!
