上篇文章,介绍了如何将猫眼例程移植到鸿蒙IPC开发板,并实现了在VLC播放器中通过网络实时显示rtsp的视频流。
在实际的猫眼应用中,摄像头还应该单独拥有一个屏幕放在家中,便于查看门外情况。
本篇,就使用Qt设计一款rtsp显示客户端,并运行在我的一块Linux板子上,作为鸿蒙IPC开发板的显示客户端。
本篇实现rtsp视频流的播放,需要用到FFmpeg库,这里先简单介绍了FFmpeg。
FFmpeg是一套可以用来****记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。
FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括Windows、Mac OS X等。项目的名称来自MPEG视频编码标准,前面的"FF"代表"Fast Forward"。 FFmpeg编码库可以使用GPU加速。
ffmpeg有7个library,分别是:
RTSP视频流解码与播放主要代码
voidVideoPlayer::run() { AVFormatContext *pFormatCtx;//音视频封装格式上下文结构体AVCodecContext *pCodecCtx;//音视频编码器上下文结构体AVCodec *pCodec;//音视频编码器结构体AVFrame *pFrame;//存储一帧解码后像素数据AVFrame *pFrameRGB; AVPacket *pPacket;//存储一帧压缩编码数据uint8_t *pOutBuffer;staticstruct SwsContext *pImgConvertCtx; avformat_network_init();//初始化FFmpeg网络模块av_register_all();//初始化FFMPEG 调用了这个才能正常适用编码器和解码器//Allocate an AVFormatContext.pFormatCtx = avformat_alloc_context();//AVDictionaryAVDictionary *avdic=nullptr; char option_key[]="rtsp_transport"; char option_value[]="udp"; av_dict_set(&avdic,option_key,option_value,0); char option_key2[]="max_delay"; char option_value2[]="100"; av_dict_set(&avdic,option_key2,option_value2,0);if(avformat_open_input(&pFormatCtx, m_strFileName.toLocal8Bit().data(), nullptr, &avdic) !=0) { printf("can't open the file. \n");return; }if(avformat_find_stream_info(pFormatCtx, nullptr) <0) { printf("Could't find stream infomation.\n");return; }//查找视频中包含的流信息,音频流先不处理intvideoStreamIdx = -1;for(inti =0; i < pFormatCtx->nb_streams; i++) {if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStreamIdx = i;//视频流} }//查找解码器qDebug("avcodec_find_decoder..."); pCodecCtx = pFormatCtx->streams[videoStreamIdx]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec == nullptr) { printf("Codec not found.\n");return; } pCodecCtx->bit_rate =0;//初始化为0pCodecCtx->time_base.num=1;//下面两行:一秒钟25帧pCodecCtx->time_base.den=10; pCodecCtx->frame_number=1;//每包一个视频帧//打开解码器if(avcodec_open2(pCodecCtx, pCodec, nullptr) <0) { printf("Could not open codec.\n");return; }//将解码后的YUV数据转换成RGB32pImgConvertCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, nullptr, nullptr, nullptr);intnumBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height); pFrame = av_frame_alloc(); pFrameRGB = av_frame_alloc(); pOutBuffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); avpicture_fill((AVPicture *) pFrameRGB, pOutBuffer, AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height); pPacket = (AVPacket *) malloc(sizeof(AVPacket));//分配一个packetinty_size = pCodecCtx->width * pCodecCtx->height; av_new_packet(pPacket, y_size);//分配packet的数据while(1) {if(av_read_frame(pFormatCtx, pPacket) <0) {break;//这里认为视频读取完了}if(pPacket->stream_index == videoStreamIdx) {intgot_picture;intret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,pPacket);if(ret <0) { printf("decode error.\n");return; }if(got_picture) { sws_scale(pImgConvertCtx, (uint8_tconst*const*) pFrame->data, pFrame->linesize,0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);//把这个RGB数据 用QImage加载QImage tmpImg((uchar *)pOutBuffer, pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB32); QImage image = tmpImg.copy();//把图像复制一份 传递给界面显示emit sig_GetOneFrame(image);//发送信号} } av_free_packet(pPacket); } av_free(pOutBuffer); av_free(pFrameRGB); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); }
解码完一帧图像后,发送信号,让显示线程来显示画面:
voidMainWindow::slotGetOneFrame(QImage img) { m_Image = img; update();//调用update将执行paintEvent函数}voidMainWindow::paintEvent(QPaintEvent *event) { QPainter painter(this);intshowWidth = this->width() -100;intshowHeight = this->height() -50; painter.setBrush(Qt::white); painter.drawRect(0,0, this->width(), this->height());//先画成白色//将图像按比例缩放QImage img = m_Image.scaled(QSize(showWidth, showHeight),Qt::KeepAspectRatio); img = img.mirrored(m_bHFlip, m_bVFlip);intx = this->width() - img.width();inty = this->height() - img.height(); x /=2; y /=2; painter.drawImage(QPoint(x-40,y+20),img);//画出图像}
Qt程序是使用Qt Creator在Windows平台开发的,先在Windows平台运行看下实际效果。
在Windows中运行,rtsp视频流播放的比较流畅。
由于猫眼例程输出的视频流默认是上下倒置的,这里在QT客户端中增加了图像翻转功能,可实现画面的上下或左右翻转显示。
将源码拷贝到Ubuntu中进行交叉编译,再将编译的程序拷贝到Linux板子中进行运行(需要先在Linux板子上搭建Qt运行环境与FFmpeg运行环境)。
在嵌入式Linux板子中运行,rtsp视频流播放的比较卡,需要再对程序进行优化。
视频发布于硬声,还在审核中...
本篇介绍了使用Qt设计一款rtsp显示客户端,并运行在我的一块Linux板子上,作为鸿蒙IPC开发板的显示客户端,从而实现一个较为完整的猫眼功能。