关于音频播放器视频前两秒黑屏的解决,及QtAV和ffmpeg的环境搭建(软件包可以找李青璠提供,也可以自己下)
首先我们可以参考下面两个博客进行ffmpeg的搭建,第一个博客的问题可以在第二个博客里寻求方法解决。其中第一个博客ffmpeg的编译命令应该改成./configure --enable-shared --prefix=/usr/local/ffmpeg,如果需要安装yasm,那么编译语句
中的./configure可以改成./configure --prefix=/usr/local/yasm (--prefix的作用是指定路径,而--enable-shared是指定生成动态库)
(1条消息) Ubuntu安装ffmpeg_大笨钟47的博客-CSDN博客_ffmpeg ubuntu安装
(1条消息) linux上如何安装QtAV插件?(环境:ubuntu18.04,qt5.12.3,ffmpeg-4.1.3)_ResttaPersevere的博客-CSDN博客
这里我们安装好了ffmpeg.下面我们进行QtAV的编译安装,可以直接点击下面的网址,Build QtAV · wang-bin/QtAV Wiki · GitHub我按他的推荐选了一种方式,大家可以参考如下;
sudo apt-get install libopenal-dev libpulse-dev libva-dev libxv-dev libass-dev libegl1-mesa-dev
cp -r /usr/local/ffmpeg/include/* /home/liqingfan/Qt5.12.10/5.12.10/gcc_64/include/
cp -r /usr/local/ffmpeg/lib/* /home/liqingfan/Qt5.12.10/5.12.10/gcc_64/lib/
下面就可以使用QtCreator With MSVCQtCreator will detect VC compiler if it is installed. So it's easy to build in QtCreator这样这个环境就搭建完成了。用QtCreator选中QtAV.pro进行编译即可
下面描述一下问题的解决过程和结论,
首先
在编译后的文件目录下会找到:sdk_install.sh
赋予sdk_install.sh 执行权限,命令 chmod 777 sdk_install.sh
安装qtav,命令:./ sdk_install.sh
并且把/home/liqingfan/ffmpegAndQtav/build-QtAV-Desktop_Qt_5_12_10_GCC_64bit-Debug/lib_linux_x86_64/目录下的文件放到/home/liqingfan/ffmpegAndQtav/203ideoclient/libs/下就可以正常的编译这个视频项目啦
后面是关于卡顿问题的分析:
我们随意打开一个视频,可以看到日志有下面几句非常的可疑。
"AVClock started!!!!!!!!"
"no frame could be decompressed: Error number 1390 occurred 0/1390"
"invalid video frame from decoder. undecoded data size: 0"
"no frame could be decompressed: Error number 898 occurred 0/898"
"invalid video frame from decoder. undecoded data size: 0"
"no frame could be decompressed: Error number 490 occurred 0/490"
"invalid video frame from decoder. undecoded data size: 0"
"setInSize => calculating aspect ratio from converted input data(1.777778)"
QtAV::VideoFormat(pixelFormat: 15 "yuvj420p" alpha: false, channels: 3, planes: 3, bpc: 8, bpp: 12/12 -8-8-8)
"pixel format changed: => yuvj420p 15"
material changed: "gl material 16to8bit: 0, planar: 0, has alpha: 0, 2d texture: 0, 2nd plane rg: 0, xyz: 0" => "gl material 16to8bit: 0, planar: 1, has alpha: 0, 2d texture: 1,
可以看出前面几面的视频帧有问题,通过向上去找log,invalid video frame from decoder. undecoded data size: 0"证明了猜想
通过log定位在了解码器。bool VideoDecoderFFmpegBase::decode(const Packet &packet);
这是我们再分析视频合成的视频,这里分析工具用的是
我们把视频拖进去看一下,
明显第一帧和其他是不一项的。从此入手,我的解决方案就是跳过有问题的帧。于是对解码这块的源码做了如下改进。改进的函数是bool VideoDecoderFFmpegBase::decode(const Packet &packet);
bool VideoDecoderFFmpegBase::decode(const Packet &packet)
{
if (!isAvailable())
return false;
DPTR_D(VideoDecoderFFmpegBase);
// some decoders might need other fields like flags&AV_PKT_FLAG_KEY
// const AVPacket*: ffmpeg >= 1.0. no libav
int got_frame_ptr = 0;
int ret = 0;
if (packet.isEOF()) {
AVPacket eofpkt;
av_init_packet(&eofpkt);
eofpkt.data = NULL;
eofpkt.size = 0;
ret = avcodec_decode_video2(d.codec_ctx, d.frame, &got_frame_ptr, &eofpkt);
} else {
ret = avcodec_decode_video2(d.codec_ctx, d.frame, &got_frame_ptr, (AVPacket*)packet.asAVPacket());
}
//qDebug("pic_type=%c", av_get_picture_type_char(d.frame->pict_type));
d.undecoded_size = qMin(packet.data.size() - ret, packet.data.size());
if (ret < 0) {
//qWarning("[VideoDecoderFFmpegBase] %s", av_err2str(ret));
return false;
}
if (!got_frame_ptr) {
//liqingfan add for fix delay:begin
while(!got_frame_ptr){
if (packet.isEOF()) {
AVPacket eofpkt;
av_init_packet(&eofpkt);
eofpkt.data = NULL;
eofpkt.size = 0;
ret = avcodec_decode_video2(d.codec_ctx, d.frame, &got_frame_ptr, &eofpkt);
if (ret < 0) {
//qWarning("[VideoDecoderFFmpegBase] %s", av_err2str(ret));
return false;
}
if(!got_frame_ptr){
return !packet.isEOF();
}
} else {
ret = avcodec_decode_video2(d.codec_ctx, d.frame, &got_frame_ptr, (AVPacket*)packet.asAVPacket());
if (ret < 0) {
//qWarning("[VideoDecoderFFmpegBase] %s", av_err2str(ret));
return false;
}
}
}
//liqingfan add for fix delay:end
qWarning("no frame could be decompressed: %s %d/%d", av_err2str(ret), d.undecoded_size, packet.data.size());
return !packet.isEOF();
}
if (!d.codec_ctx->width || !d.codec_ctx->height)
return false;
//qDebug("codec %dx%d, frame %dx%d", d.codec_ctx->width, d.codec_ctx->height, d.frame->width, d.frame->height);
d.width = d.frame->width; // TODO: remove? used in hwdec
d.height = d.frame->height;
//avcodec_align_dimensions2(d.codec_ctx, &d.width_align, &d.height_align, aligns);
return true;
}