11.QT-ffmpeg+QAudioOutput实现音频播放器
- 2.AVFormatContext和AVInputFormat
- 3.AVPacket使用
- 4.FFMPEG-AVFrame
- 5.AVStream和AVCodecParameters
- 6.AVCodecContext和AVCodec
- 7.SwrContext音频重采样使用
- 8.ffmpeg-基础常用知识
- 9.下载ffmpeg、使QT支持同时编译32位和64位
- 10.QT-QAudioOutput类使用



#include "playthread.h" playthread::playthread()
{
audio=NULL;
type = control_none;
} bool playthread::initAudio(int SampleRate)
{
QAudioFormat format; if(audio!=NULL)
return true; format.setSampleRate(SampleRate); //设置采样率
format.setChannelCount(); //设置通道数
format.setSampleSize(); //样本数据16位
format.setCodec("audio/pcm"); //播出格式为pcm格式
format.setByteOrder(QAudioFormat::LittleEndian); //默认小端模式
format.setSampleType(QAudioFormat::UnSignedInt); //无符号整形数 QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); //选择默认输出设备 // foreach(int count,info.supportedChannelCounts())
// {
// qDebug()<<"输出设备支持的通道数:"<<count;
// } // foreach(int count,info.supportedSampleRates())
// {
// qDebug()<<"输出设备支持的采样率:"<<count;
// } // foreach(int count,info.supportedSampleSizes())
// {
// qDebug()<<"输出设备支持的样本数据位数:"<<count;
// } if (!info.isFormatSupported(format))
{
qDebug()<<"输出设备不支持该格式,不能播放音频";
return false;
} audio = new QAudioOutput(format, this); audio->setBufferSize(); return true;
} void playthread::play(QString filePath)
{
this->filePath = filePath;
type = control_play; if(!this->isRunning())
{
this->start();
}
} void playthread::stop()
{ if(this->isRunning())
{
type = control_stop;
} }
void playthread::pause()
{ if(this->isRunning())
{
type = control_pause;
} } void playthread::resume()
{
if(this->isRunning())
{
type = control_resume;
}
} void playthread::seek(int value)
{ if(this->isRunning())
{
seekMs = value;
type = control_seek;
}
} void playthread::debugErr(QString prefix, int err) //根据错误编号获取错误信息并打印
{
char errbuf[]={}; av_strerror(err,errbuf,sizeof(errbuf)); qDebug()<<prefix<<":"<<errbuf; emit ERROR(prefix+":"+errbuf);
} bool playthread::runIsBreak() //处理控制,判断是否需要停止
{ bool ret = false;
//处理播放暂停
if(type == control_pause)
{
while(type == control_pause)
{
audio->suspend();
msleep();
} if(type == control_resume)
{
audio->resume();
}
} if(type == control_play) //重新播放
{
ret = true;
if(audio->state()== QAudio::ActiveState)
audio->stop();
} if(type == control_stop) //停止
{
ret = true;
if(audio->state()== QAudio::ActiveState)
audio->stop();
}
return ret;
} void playthread::runPlay()
{
int ret; int destMs,currentMs; if(audio==NULL)
{
emit ERROR("输出设备不支持该格式,不能播放音频");
return ;
}
//初始化网络库 (可以打开rtsp rtmp http 协议的流媒体视频)
avformat_network_init();
AVFormatContext *pFmtCtx=NULL;
ret = avformat_open_input(&pFmtCtx, this->filePath.toLocal8Bit().data(),NULL, NULL) ; //打开音视频文件并创建AVFormatContext结构体以及初始化.
if (ret!= )
{
debugErr("avformat_open_input",ret);
return ;
}
ret = avformat_find_stream_info(pFmtCtx, NULL); //初始化流信息
if (ret!= )
{
debugErr("avformat_find_stream_info",ret);
return ;
} int audioindex=-; audioindex = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -, -, NULL, ); qDebug()<<"audioindex:"<<audioindex; AVCodec *acodec = avcodec_find_decoder(pFmtCtx->streams[audioindex]->codecpar->codec_id);//获取codec AVCodecContext *acodecCtx = avcodec_alloc_context3(acodec); //构造AVCodecContext ,并将vcodec填入AVCodecContext中
avcodec_parameters_to_context(acodecCtx, pFmtCtx->streams[audioindex]->codecpar); //初始化AVCodecContext ret = avcodec_open2(acodecCtx, NULL,NULL); //打开解码器,由于之前调用avcodec_alloc_context3(vcodec)初始化了vc,那么codec(第2个参数)可以填NULL
if (ret!= )
{
debugErr("avcodec_open2",ret);
return ;
}
SwrContext *swrctx =NULL;
swrctx=swr_alloc_set_opts(swrctx, av_get_default_channel_layout(),AV_SAMPLE_FMT_S16,,
acodecCtx->channel_layout, acodecCtx->sample_fmt,acodecCtx->sample_rate, NULL,NULL);
swr_init(swrctx); destMs = av_q2d(pFmtCtx->streams[audioindex]->time_base)**pFmtCtx->streams[audioindex]->duration;
qDebug()<<"码率:"<<acodecCtx->bit_rate;
qDebug()<<"格式:"<<acodecCtx->sample_fmt;
qDebug()<<"通道:"<<acodecCtx->channels;
qDebug()<<"采样率:"<<acodecCtx->sample_rate;
qDebug()<<"时长:"<<destMs;
qDebug()<<"解码器:"<<acodec->name; AVPacket * packet =av_packet_alloc();
AVFrame *frame =av_frame_alloc(); audio->stop();
QIODevice*io = audio->start(); while()
{ if(runIsBreak())
break; if(type == control_seek)
{
av_seek_frame(pFmtCtx, audioindex, seekMs/(double)/av_q2d(pFmtCtx->streams[audioindex]->time_base),AVSEEK_FLAG_BACKWARD);
type = control_none;
emit seekOk();
} ret = av_read_frame(pFmtCtx, packet);
if (ret!= )
{
debugErr("av_read_frame",ret);
emit duration(destMs,destMs);
break ;
} //解码一帧数据
ret = avcodec_send_packet(acodecCtx, packet);
av_packet_unref(packet); if (ret != )
{
debugErr("avcodec_send_packet",ret);
continue ;
} if(packet->stream_index==audioindex)
{
while( avcodec_receive_frame(acodecCtx, frame) == )
{ if(runIsBreak())
break;
uint8_t *data[] = { };
int byteCnt=frame->nb_samples * * ; unsigned char *pcm = new uint8_t[byteCnt]; //frame->nb_samples*2*2表示分配样本数据量*两通道*每通道2字节大小 data[] = pcm; //输出格式为AV_SAMPLE_FMT_S16(packet类型),所以转换后的LR两通道都存在data[0]中 ret = swr_convert(swrctx,
data, frame->nb_samples, //输出
(const uint8_t**)frame->data,frame->nb_samples ); //输入 //将重采样后的data数据发送到输出设备,进行播放
while (audio->bytesFree() < byteCnt)
{
if(runIsBreak())
break;
msleep();
} if(!runIsBreak())
io->write((const char *)pcm,byteCnt); currentMs = av_q2d(pFmtCtx->streams[audioindex]->time_base)**frame->pts;
//qDebug()<<"时长:"<<destMs<<currentMs;
emit duration(currentMs,destMs); delete[] pcm;
}
} } //释放内存
av_frame_free(&frame);
av_packet_free(&packet);
swr_free(&swrctx);
avcodec_free_context(&acodecCtx);
avformat_close_input(&pFmtCtx); } void playthread::run()
{ if(!initAudio())
{
emit ERROR("输出设备不支持该格式,不能播放音频");
} while()
{ switch(type)
{
case control_none: msleep(); break;
case control_play : type=control_none;runPlay(); break; //播放
default: type=control_none; break;
}
} }
4.2 widget界面类
而在界面中要处理的就很简单,widget.cpp如下所示:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug> Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this); this->setAcceptDrops(true); thread = new playthread(); connect(thread,SIGNAL(duration(int,int)),this,SLOT(onDuration(int,int))); connect(thread,SIGNAL(seekOk()),this,SLOT(onSeekOk())); void duration(long currentMs,long destMs); //播放时长 thread->start(); sliderSeeking =false;
} Widget::~Widget()
{
delete ui; thread->stop();
} void Widget::onSeekOk()
{
sliderSeeking=false;
} void Widget::onDuration(int currentMs,int destMs) //时长
{
static int currentMs1=-,destMs1=-; if(currentMs1==currentMs&&destMs1==destMs)
{
return;
} currentMs1 = currentMs;
destMs1 = destMs; qDebug()<<"onDuration:"<<currentMs<<destMs<<sliderSeeking; QString currentTime = QString("%1:%2:%3").arg(currentMs1/%,,,QChar('')).arg(currentMs1/%,,,QChar('')).arg(currentMs1/%,,,QChar('')); QString destTime = QString("%1:%2:%3").arg(destMs1/%,,,QChar('')).arg(destMs1/%,,,QChar('')).arg(destMs1/%,,,QChar('')); ui->label_duration->setText(currentTime+"/"+destTime); if(!sliderSeeking) //未滑动
{
ui->slider->setMaximum(destMs);
ui->slider->setValue(currentMs);
} } void Widget::dragEnterEvent(QDragEnterEvent *event)
{
if(event->mimeData()->hasUrls()) //判断拖的类型
{
event->acceptProposedAction();
}
else
{
event->ignore();
}
} void Widget::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls()) //判断放的类型
{ QList<QUrl> List = event->mimeData()->urls(); if(List.length()!=)
{
ui->line_audioPath->setText(List[].toLocalFile());
} }
else
{
event->ignore();
}
} void Widget::on_btn_start_clicked()
{ sliderSeeking=false; thread->play(ui->line_audioPath->text()); } void Widget::on_btn_stop_clicked()
{
thread->stop();
} void Widget::on_btn_pause_clicked()
{
thread->pause();
} void Widget::on_btn_resume_clicked()
{
thread->resume();
} void Widget::on_slider_sliderPressed()
{
sliderSeeking=true;
} void Widget::on_slider_sliderReleased()
{ thread->seek(ui->slider->value()); }
11.QT-ffmpeg+QAudioOutput实现音频播放器的更多相关文章
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- ffmpeg+SDL2实现的音频播放器V2.0(无杂音)
1. 前言 目前为止,学习了并记录了ffmpeg+SDL2显示视频以及事件(event)的内容. 这篇中记录ffmpeg+SDL2播放音频,没加入事件处理. 接下来加入事件处理并继续学习音视频同步,再 ...
- IOS开发之简单音频播放器
今天第一次接触IOS开发的UI部分,之前学OC的时候一直在模拟的使用Target-Action回调模式,今天算是真正的用了一次.为了熟悉一下基本控件的使用方法,和UI部分的回调,下面开发了一个特别简易 ...
- 与众不同 windows phone (14) - Media(媒体)之音频播放器, 视频播放器, 与 Windows Phone 的音乐和视频中心集成
原文:与众不同 windows phone (14) - Media(媒体)之音频播放器, 视频播放器, 与 Windows Phone 的音乐和视频中心集成 [索引页][源码下载] 与众不同 win ...
- Unity3D音频播放器 动态装载组件
大多数在线Unity有关如何只教程Unity在播放音乐.之后如何通过拖动它们无法继续添加音频文件 但有时在游戏中的对象要玩几个声音.这时候我们就需要使用代码控制,拖动推教程AudioClip颂值的方法 ...
- H.264:FFMpeg 实现简单的播放器
H.264:FFMpeg 实现简单的播放器 FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手.我刚接触FFMPEG的时候也感觉不知从何学起. 因此我 ...
- 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 ...
随机推荐
- scanf函数与getchar函数
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h&g ...
- md文件批量转化为html
任务描述 博客的源文件一般以md文件保存 读取md源文件解析为html代码,然后嵌入到body中去 公式部分,需要使用第三方js库加载 实现办法 基于Django实现,进入webpage页面,然后通过 ...
- angular中阿里矢量图标使用
<!DOCTYPE html> <html lang="en" ng-app="app"> <head> <meta ...
- HTML基础-04
定位 定位:通过定位可以将元素摆放在页面中任意位置 语法:position属性设置元素的定位 可选值:static:默认值,开启定位 relative开启相对定位 absolute开启绝对定位 fix ...
- Maven项目在进行单元测试报错:ClassNoFoundExceptipon
解决方法: 只要把Java--------compiler-------building-------Buil path problems ------- incomplete build path ...
- 微服务技术栈:API网关中心,落地实现方案
本文源码:GitHub·点这里 || GitEE·点这里 一.服务网关简介 1.外观模式 客户端与各个业务子系统的通信必须通过一个统一的外观对象进行,外观模式提供一个高层次的接口,使得子系统更易于使用 ...
- PC,移动端H5实现实现小球加入购物车效果
HTML部分: <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" ...
- Jmeter 常用函数(6)- 详解 __P
如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.html 作用 和 __property 作用一样,不 ...
- go 多线程并发 queue demo
原文链接:Writing worker queues, in Go 1.work.go [root@wangjq queue]# cat work.go package main import &qu ...
- ThinkCMF&Thinkphp 首页静态化处理
基于TP5的页面静态化教程 1.首页在控制器添加以下代码生成静态页面文件 $info = $this->buildHtml("/staticIndex", 'static', ...