网上有很多关于pos机免费办理音频,FFmpeg 4.0.2 + SDL2 播放音频「资料源码分享」的知识,也有很多人为大家解答关于pos机免费办理音频的问题,今天pos机之家(www.poszjia.com)为大家整理了关于这方面的知识,让我们一起来看下吧!
本文目录一览:
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机免费办理音频的知识,希望能够帮助到大家!
