如何自主建设企业网站,手机seo关键词优化,永康网站建设的公司,网络推广免费平台一、使用场景 因为项目中需要加载MP4播放开机视频#xff0c;而我们的设备所使用的架构为arm架构#xff0c;其中缺乏一些多媒体库。安装这些插件库比较麻烦#xff0c;所以最终决定使用FFmpeg播放视频。
二、下载编译ffmpeg库
2.1 下载源码 源码下载路径#xff1a;http…一、使用场景 因为项目中需要加载MP4播放开机视频而我们的设备所使用的架构为arm架构其中缺乏一些多媒体库。安装这些插件库比较麻烦所以最终决定使用FFmpeg播放视频。
二、下载编译ffmpeg库
2.1 下载源码 源码下载路径https://www.ffmpeg.org/download.html#build-windows
2.2 编译源码 1) 解压将源码放到指定目录并运行tar -jxvf ffmpeg-snapshot.tar.bz2。若是xxx.tar.gz源文件则用tar -zxvf ffmpeg-xxx.tar.gz。 2) 创建构建目录cd ffmpeg, mkdir build; 3)编译 a) ubuntu编译 ./configure --enable-static --prefix./build b)arm交叉编译 ./configure --ccxxx/aarch64-linux-gnu-gcc(QT指定的gcc路径) --cxxxxx/aarch64-linux-gnu-g --enable-staticc(QT指定的g路径) --prefix./build --enable-cross-compile --archarm64 --target-oslinux。 4) make安装 make make install。 5) 运行若需要运行ffmpeg则需要增加--enable-shared参数并且添加环境变量export LD_LIBRARY_PATHxxx/build/lib/。 6)使用帮助 在xxx/build/bin路径下运行./ffmpeg --help。
2.3 常见报错 1) 交叉编译需要指定对应的gcc和g编译器和其它的如平台参数Linux的QTCreator可以通过如下选项查看对应的编译器路径工程-》管理构建-》编译器-》指南(Manual)-》双击gcc或g。注意在操作之前需要先选择工程当前的运行和构建平台为arrch64。 2) make install 报错:strip: Unable to recognise the format of the input file将config.mak中的Tripstrip改为Triparm -linux-strip。
三、使用源码 1.在工程中导入头文件和库注意库顺序。eg:
INCLUDEPATH xxx/build/include
LIBS -Lxxx/xxx -lavformat\-lavdevice \-lavcodec \-lswresample \-lavfilter \ -lavutil \-lswscale 2.头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include QMainWindow
#include QDebug
#include QTimer
#include QTime
#include QAudioOutput
extern C
{#include libavcodec/avcodec.h#include libavformat/avformat.h#include libswscale/swscale.h#include libavdevice/avdevice.h#include libavformat/version.h#include libavutil/time.h#include libavutil/mathematics.h#include libavfilter/buffersink.h#include libavfilter/buffersrc.h#include libavutil/avutil.h#include libavutil/imgutils.h#include libavutil/pixfmt.h#include libswresample/swresample.h
}#define MAX_AUDIO_FRAME_SIZE 192000namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent nullptr);~MainWindow();public slots:void timeCallback(void);void on_play_clicked();void resizeEvent(QResizeEvent* );private:Ui::MainWindow *ui;int playVedio(void);QTimer *timer; // 定时播放根据帧率来int vedioW,vedioH; // 图像宽高QListQPixmap vedioBuff; // 图像缓存区QString myUrl QString(E:/workspace/Qt_workspace/ffmpeg/三国之战神无双.mp4); // 视频地址AVFormatContext *pFormatCtx;AVCodecContext *pCodecCtx;AVCodec *pCodec;AVFrame *pFrame, *pFrameRGB;int ret, got_picture,got_audio; // 视频解码标志int videoindex; // 视频序号// 音频int audioindex; // 音频序号AVCodecParameters *aCodecParameters;AVCodec *aCodec;AVCodecContext *aCodecCtx;QByteArray byteBuf;//音频缓冲QAudioOutput *audioOutput;QIODevice *streamOut;
};#endif // MAINWINDOW_H 3.源文件
#include mainwindow.h
#include ui_mainwindow.hMainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui-setupUi(this);
// qDebug(avcodec_configuration());
// unsigned version avcodec_version();
// QString ch QString::number(version,10);
// qDebug()version:version;timer new QTimer(this);timer-setTimerType(Qt::PreciseTimer); // 精准定时设置connect(timer,SIGNAL(timeout()),this,SLOT(timeCallback()));
}void MainWindow::timeCallback(void)
{// 视频缓存播放if(!vedioBuff.isEmpty()){ui-label-setPixmap(vedioBuff.at(0));vedioBuff.removeAt(0);}else {timer-stop();}// 音频缓存播放if(audioOutput audioOutput-state() ! QAudio::StoppedState audioOutput-state() ! QAudio::SuspendedState){int writeBytes qMin(byteBuf.length(), audioOutput-bytesFree());streamOut-write(byteBuf.data(), writeBytes);byteBuf byteBuf.right(byteBuf.length() - writeBytes);}
}void Delay_MSec(unsigned int msec)
{QTime _Timer QTime::currentTime().addMSecs(msec);while( QTime::currentTime() _Timer )QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}int MainWindow::playVedio(void)
{QAudioFormat fmt;fmt.setSampleRate(44100);fmt.setSampleSize(16);fmt.setChannelCount(2);fmt.setCodec(audio/pcm);fmt.setByteOrder(QAudioFormat::LittleEndian);fmt.setSampleType(QAudioFormat::SignedInt);audioOutput new QAudioOutput(fmt);streamOut audioOutput-start();char *filepath myUrl.toUtf8().data();av_register_all();avformat_network_init();pFormatCtx avformat_alloc_context();// 打开视频文件初始化pFormatCtx结构if(avformat_open_input(pFormatCtx,filepath,NULL,NULL)!0){qDebug(视频文件打开失败.\n);return -1;}// 获取音视频流if(avformat_find_stream_info(pFormatCtx,NULL)0){qDebug(媒体流获取失败.\n);return -1;}videoindex -1;audioindex -1;//nb_streams视音频流的个数这里当查找到视频流时就中断了。for(int i0; ipFormatCtx-nb_streams; i)if(pFormatCtx-streams[i]-codec-codec_typeAVMEDIA_TYPE_VIDEO){videoindexi;break;}if(videoindex-1){qDebug(找不到视频流.\n);return -1;}//nb_streams视音频流的个数这里当查找到音频流时就中断了。for(int i0; ipFormatCtx-nb_streams; i)if(pFormatCtx-streams[i]-codecpar-codec_typeAVMEDIA_TYPE_AUDIO){audioindexi;break;}if(audioindex-1){qDebug(找不到音频流.\n);return -1;}//获取视频流编码结构pCodecCtxpFormatCtx-streams[videoindex]-codec;float frameNum pCodecCtx-framerate.num; // 每秒帧数if(frameNum100) frameNum frameNum/1001;int frameRate 1000/frameNum; //qDebug(帧/秒 %f 播放间隔是时间%d\n,frameNum,frameRate);//查找解码器pCodecavcodec_find_decoder(pCodecCtx-codec_id);if(pCodecNULL){qDebug(找不到解码器.\n);return -1;}//使用解码器读取pCodecCtx结构if(avcodec_open2(pCodecCtx, pCodec,NULL)0){qDebug(打开视频码流失败.\n);return -1;}//获取音频流编码结构-------------------------------------------------------------aCodecParameters pFormatCtx-streams[audioindex]-codecpar;aCodec avcodec_find_decoder(aCodecParameters-codec_id);if (aCodec 0) {qDebug(找不到解码器.\n);return -1;}aCodecCtx avcodec_alloc_context3(aCodec);avcodec_parameters_to_context(aCodecCtx, aCodecParameters);//使用解码器读取aCodecCtx结构if (avcodec_open2(aCodecCtx, aCodec, 0) 0) {qDebug(打开视频码流失败.\n);return 0;}// 清空缓存区byteBuf.clear();vedioBuff.clear();//创建帧结构此函数仅分配基本结构空间图像数据空间需通过av_malloc分配pFrame av_frame_alloc();pFrameRGB av_frame_alloc();// 获取音频参数uint64_t out_channel_layout aCodecCtx-channel_layout;AVSampleFormat out_sample_fmt AV_SAMPLE_FMT_S16;int out_sample_rate aCodecCtx-sample_rate;int out_channels av_get_channel_layout_nb_channels(out_channel_layout);uint8_t *audio_out_buffer (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2);SwrContext *swr_ctx swr_alloc_set_opts(NULL, out_channel_layout, out_sample_fmt,out_sample_rate, aCodecCtx-channel_layout, aCodecCtx-sample_fmt, aCodecCtx-sample_rate, 0, 0);swr_init(swr_ctx);//创建动态内存,创建存储图像数据的空间unsigned char *out_buffer (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, pCodecCtx-width, pCodecCtx-height, 1));av_image_fill_arrays(pFrameRGB-data, pFrameRGB-linesize, out_buffer, AV_PIX_FMT_RGB32, pCodecCtx-width, pCodecCtx-height, 1);AVPacket *packet (AVPacket *)av_malloc(sizeof(AVPacket));//初始化img_convert_ctx结构struct SwsContext *img_convert_ctx sws_getContext(pCodecCtx-width, pCodecCtx-height, pCodecCtx-pix_fmt, pCodecCtx-width, pCodecCtx-height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);timer-start(frameRate); //定时间隔播放while (av_read_frame(pFormatCtx, packet) 0){if (packet-stream_index audioindex){int ret avcodec_decode_audio4(aCodecCtx, pFrame, got_audio, packet);if ( ret 0){qDebug(解码失败.\n);return 0;}if (got_audio){int len swr_convert(swr_ctx, audio_out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame-data, pFrame-nb_samples);if (len 0){continue;}int dst_bufsize av_samples_get_buffer_size(0, out_channels, len, out_sample_fmt, 1);QByteArray atemp QByteArray((const char *)audio_out_buffer, dst_bufsize);byteBuf.append(atemp);}}//如果是视频数据else if (packet-stream_index videoindex){//解码一帧视频数据ret avcodec_decode_video2(pCodecCtx, pFrame, got_picture, packet);if (ret 0){qDebug(解码失败.\n);return 0;}if (got_picture){sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame-data, pFrame-linesize, 0, pCodecCtx-height,pFrameRGB-data, pFrameRGB-linesize);QImage img((uchar*)pFrameRGB-data[0],pCodecCtx-width,pCodecCtx-height,QImage::Format_RGB32);img img.scaled(vedioW, vedioH);QPixmap temp QPixmap::fromImage(img);vedioBuff.append(temp);Delay_MSec(frameRate-5); // 这里需要流出时间来显示如果不要这个延时界面回卡死到整个视频解码完成才能播放显示//ui-label-setPixmap(temp);}}av_free_packet(packet);}sws_freeContext(img_convert_ctx);av_frame_free(pFrameRGB);av_frame_free(pFrame);avcodec_close(pCodecCtx);avformat_close_input(pFormatCtx);
}void MainWindow::resizeEvent(QResizeEvent* )
{vedioW ui-label-width();vedioH ui-label-height();
}
MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_play_clicked()
{vedioW ui-label-width();vedioH ui-label-height();if(timer-isActive()) timer-stop();playVedio();
}