FFMPEG学习----使用SDL构建音频播放器
ffmpeg版本:ffmpeg-20160413-git-0efafc5
#include <stdio.h>
#include <stdlib.h>
#include <string.h> extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "SDL.h"
}; #define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio Uint32 audio_len;//音频数据大小
Uint8 *audio_pos;//指向音频数据的指针 //回调函数
void fill_audio(void *userdata, Uint8 *stream, int len)
{
//SDL 2.0
SDL_memset(stream, 0, len);
if (audio_len == 0)
{
return;
} len = (len > audio_len ? audio_len : len); SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
audio_pos += len;
audio_len -= len;
} int main(int argc, char* argv[])
{
//FFmpeg
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVPacket packet;
AVFrame *pFrame;
struct SwrContext *au_convert_ctx;
int got_picture;
int audioIndex; //SDL
uint8_t *out_buffer;
SDL_AudioSpec wanted_spec;
int index = 0; char filepath[1024] = "";
printf("Usage: player.exe *.mp3\n");
if (argc == 2)
{
strcpy(filepath, argv[1]);
}
else
{
printf("Could not find a audio file\n");
return -1;
} av_register_all(); pFormatCtx = avformat_alloc_context(); if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)
{
printf("Couldn't open input stream.\n");
return -1;
} if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
printf("Couldn't find stream information.\n");
return -1;
} av_dump_format(pFormatCtx, -1, filepath, 0); audioIndex = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
{
//AVStream->codec不推荐使用
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioIndex = i;
break;
}
}
if (audioIndex == -1)
{
printf("Didn't find a audio stream.\n");
return -1;
} //------------------------------------------------
//新版本:分配、填充AVCodecContext
pCodecCtx = avcodec_alloc_context3(NULL);
if (pCodecCtx == NULL)
{
printf("Could not allocate AVCodecContext\n");
return -1;
} if (avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[audioIndex]->codecpar) < 0)
{
printf("Could not initialize AVCodecContext\n");
return -1;
}
//------------------------------------------------ pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL)
{
printf("Codec not found.\n");
return -1;
} if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)
{
printf("Could not open codec.\n");
return -1;
} //Out Audio Param
uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
//nb_samples: AAC-1024 MP3-1152
int out_nb_samples = pCodecCtx->frame_size;
AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
int out_sample_rate = 44100;
int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
//Out Buffer Size
int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1); out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
pFrame = av_frame_alloc(); //Init
if (SDL_Init(SDL_INIT_AUDIO))
{
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
//SDL_AudioSpec
wanted_spec.freq = out_sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = out_channels;
wanted_spec.silence = 0;
wanted_spec.samples = out_nb_samples;
wanted_spec.callback = fill_audio;
wanted_spec.userdata = pCodecCtx; if (SDL_OpenAudio(&wanted_spec, NULL) < 0)
{
printf("can't open audio.\n");
return -1;
} au_convert_ctx = swr_alloc();
au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,
pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);
swr_init(au_convert_ctx); //Play
SDL_PauseAudio(0); while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == audioIndex)
{
if (avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, &packet) < 0)
{
printf("Error in decoding audio frame.\n");
return -1;
}
if (got_picture)
{
swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame->data, pFrame->nb_samples);
printf("index:%5d\t pts:%lld\t packet size:%d\n", index, packet.pts, packet.size);
index++;
} while (audio_len > 0)//Wait until finish
{
SDL_Delay(1);
} //Audio buffer length
audio_len = out_buffer_size;
audio_pos = (Uint8 *)out_buffer; }
av_packet_unref(&packet);
} swr_free(&au_convert_ctx);
SDL_CloseAudio();//Close SDL
SDL_Quit();
av_free(out_buffer);
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
FFMPEG学习----使用SDL构建音频播放器的更多相关文章
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- FFMPEG学习----使用SDL构建视频播放器
#include <stdio.h> #include <string.h> extern "C" { #include "libavcodec/ ...
- ffmpeg+SDL2实现的音频播放器V2.0(无杂音)
1. 前言 目前为止,学习了并记录了ffmpeg+SDL2显示视频以及事件(event)的内容. 这篇中记录ffmpeg+SDL2播放音频,没加入事件处理. 接下来加入事件处理并继续学习音视频同步,再 ...
- 11.QT-ffmpeg+QAudioOutput实现音频播放器
1.前言 由于QAudioOutput支持的输入数据必须是原始数据,所以播放mp3,WAV,AAC等格式文件,需要解封装后才能支持播放. 而在QT中,提供了QMediaPlayer ...
- IOS开发之简单音频播放器
今天第一次接触IOS开发的UI部分,之前学OC的时候一直在模拟的使用Target-Action回调模式,今天算是真正的用了一次.为了熟悉一下基本控件的使用方法,和UI部分的回调,下面开发了一个特别简易 ...
- 基于c开发的全命令行音频播放器
cmus是一个内置了音频播放器的强大的音乐文件管理器.用它的基于ncurses的命令行界面,你可以浏览你的音乐库,并从播放列表或队列中播放音乐,这一切都是在命令行下. Linux上安装cmus 首先, ...
- HTML5 音频播放器-Javascript代码(短小精悍)
直接上干货咯! //HTML5 音频播放器 lzpong 2015/01/19 var wavPlayer = function () { if(window.parent.wavPlayer) re ...
- 【jquery】一款不错的音频播放器——Amazing Audio Player
前段时间分享了一款视频播放器,点击这里.今天介绍一款不错的音频播放器——Amazing Audio Player. 介绍: Amazing Audio Player 是一个使用很方便的 Windows ...
随机推荐
- JVM探秘:垃圾收集器
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 垃圾收集器 垃圾收集算法是是内存回收的方法论,垃圾收集器是内存回收的具体实现.不同的虚 ...
- spinor/spinand flash之高频通信延迟采样
SPI协议 对于spinor和spinand flash,其通信总线为SPI总线. SPI有四种工作模式,对应不同的极性和相位组合 极性,一般表示为CPOL(Clock POLarity),即SPI空 ...
- Python+appium+unittest UI自动化测试
什么是UI自动化 自动化分层 单元自动化测试,指对软件中最小可测试单元进行检查和验证,一般需要借助单元测试框架,如java的JUnit,python的unittest等 接口自动化测试,主要检查验证模 ...
- 使用sqlmap中的tamper脚本绕过waf
使用sqlmap中tamper脚本绕过waf 脚本名:0x2char.py 作用:用UTF-8全角对应字符替换撇号字符 作用:用等价的CONCAT(CHAR(),...)对应替换每个(MySQL)0x ...
- 02_jQuery 验证密码是6位或者8位纯数字
var reg = new RegExp(/^\d{8}$/); //工作密码必须是8位数字 if(!reg.test("12544444").val())) { alert(&q ...
- ElementUi 表格取消全选框,用文字表示
Echarts ElementUi 表格取消全选框,用文字表示 1.先看看实现的图 一. 添加添加复选框列 <el-table v-loading="zongShipLoading&q ...
- CSS的核心属性和浮动
1.CSS属性组成和作用 属性:属性值 1)每个css样式都必须由两部分组成:选择符(Selector)和声明(Decleration) 注:声明又包括属性(Properyt)和属性值(Value ...
- Quartz 和 springboot schedule中的cron表达式关于星期(周几)的不同表示
一.Quartz中cron 表达式分析: quartz 官方源码(org.quartz.CronExpression)解释: Cron expressions are comprised of 6 r ...
- 微信小程序之双重循环(包含左滑删除,以及数据各项处理)
<view wx:for="{{hommer}}" wx:for-item="item" wx:for-index="index" w ...
- Win10系统下MySQL压缩版安装配置教程
MySQL分为安装版和压缩.为了以后MySQL出问题想重装时的各种不必要的麻烦,我个人推荐压缩版MySQL.下面进入教程: 进入官网下载MySQL压缩包,并解压如下 配置环境变量---将bin文件的目 ...