Showing video with Qt toolbox and ffmpeg libraries
更新时间:2023-11-04 01:28:01 阅读量: 综合文库 文档下载
- showing推荐度:
- 相关推荐
Showing video with Qt toolbox and ffmpeg libraries
I recently had to build a demo client that shows short video messages for Ubuntu environment.
After checking out GTK+ I decided to go with the more natively OOP Qt toolbox (GTKmm didn't look right to me), and I think i made the right choice.
So anyway, I have my video files encoded in some unknown format and I need my program to show them in a some widget. I went around looking for an exiting example, but i couldn't find anything concrete, except for a good tip here that led me here for an example of using ffmpeg's libavformat and libavcodec, but no end-to-end example including the Qt code.
The ffmpeg example was simple enough to just copy-paste into my project, but the whole painting over the widget's canvas was not covered. Turns out painting video is not as simple as overriding paintEvent()...
Firstly, you need a separate thread for grabbing frames from the video file, because you won't let the GUI event thread do that.
That makes sense, but when the frame-grabbing thread (I called VideoThread) actually grabbed a frame and inserted it somewhere in the memory, I needed to tell the GUI thread to take that buffered pixels and paint them over the widget's canvas.
This is the moment where I praise Qt's excellent Signals/Slots mechanism. So I'll have my VideoThread emit a signal notifying some external entity that a new frame is in the buffer. Here's a little code:
void VideoThread::run() { /*
... Initialize libavformat & libavcodec data structures. You can see it in the example i referred to before */
// Open video file
if(av_open_input_file(&pFormatCtx, \
NULL, 0, NULL)!=0)
return -1; // Couldn't open file
// Retrieve stream information
if(av_find_stream_info(pFormatCtx)<0)
return -1; // Couldn't find stream information
// Find the first video stream ...
// Get a pointer to the codec context for the video // stream...
// Find the decoder for the video stream...
// Open codec...
// Allocate video frame
pFrame=avcodec_alloc_frame();
// Allocate an AVFrame structure pFrameRGB=avcodec_alloc_frame(); if(pFrameRGB==NULL) return -1;
int dst_fmt = PIX_FMT_RGB24; int dst_w = 160; int dst_h = 120;
// Determine required buffer size and allocate buffer numBytes = avpicture_get_size(dst_fmt, dst_w, dst_h); buffer = new uint8_t[numBytes + 64];
//put a PPM header on the buffer
int headerlen = sprintf((char *) buffer, \dst_w, dst_h);
_v->buf = (uchar*)buffer;
_v->len = avpicture_get_size(dst_fmt,dst_w,dst_h) + headerlen;
// Assign appropriate parts of buffer to image planes // in pFrameRGB...
// I use libswscale to scale the frames to the required // size.
// Setup the scaling context: SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(
pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, dst_w, dst_h, dst_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
// Read frames and notify i=0;
while(av_read_frame(pFormatCtx, &packet)>=0) {
// Is this a packet from the video stream? if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, packet.data, packet.size);
// Did we get a video frame? if(frameFinished) {
// Convert the image to RGB sws_scale(img_convert_ctx, pFrame->data,
pFrame->linesize, 0,
pCodecCtx->height, pFrameRGB->data,
pFrameRGB->linesize);
emit frameReady();
//My video is 5FPS so sleep for 200ms. this->msleep(200); } }
// Free the packet that was allocated by // av_read_frame
av_free_packet(&packet); }
// Free the RGB image
delete [] buffer; av_free(pFrameRGB);
// Free the YUV frame av_free(pFrame);
// Close the codec...
// Close the video file... } //end VideoThread::run
Ok so I have a frame-grabber that emits a frameReady signal everytime the buffer is full and ready for painting.
A couple of things to notice:
? I convert the image format to PIX_FMT_RGB24 (avcodec.h), which is required by Qt's QImage::fromData() method.
? I scale the image using ffmpeg's libswscale. All conversion/scaling methods inside libavcodev are deprecated now.
But it's fairly simple, here's a good example. Just remember you need a sws_getContext and then sws_scale.
? I totally disregard actual frame rate here, I just sleep for 200ms because i know my file is 5FPS. For a (far-) more sophisticated way to get the FPS, very important if this is not a constant frame-rate video, you can find here.
? I don't cover audio in this example, although the mechanism to extract it from the file exists... you just need to grabe the audio stream's frame. For playing audio you also need some Qt-external library. In a different project I used SDL very easily, here's an example online. Now, for painting over the widget. This is fairly easy:
void VideoWidget::paintEvent(QPaintEvent * e) { QPainter painter(this);
if(buf) {
QImage i = QImage::fromData(buf,len,\painter.drawImage(QPoint(0,0),i); } }
Two things to note:
? The widget needs to be given the pointer to the video frame buffer (buf).
? The frame buffer needs to be in a PPM format. That means it needs to get a PPM header, which looks something like this: \in 3-byte per-pixel format (RGB24). You can see that i take care of that in the previous code block.
Finally we need to orchestrate this whole mess. So in my GUI-screen class I do:
....
vt = new VideoThread();
connect(vt,SIGNAL(frameReady()),this,SLOT(updateVideoWidget()));
vt->start(); .... And:
void playMessage::updateVideoWidget() { videoWidget->repaint(); //or update(). }
This will make the widget repaint on each frame ready. Note:
? In this example I don't take care of multi-threading issues. Since the GUI and the ffmpeg decoder threads share a memory buffer, I should probably have a mutex to protect it. It's a classic producer-consumer problem.
? Performance wise, Qt's paint mechanism is by far the worst way to go when displaying video... but it's great for a quick-and-dirty solution (I only needed 5fps). A more performance favorable solution will probably be using an overlay block and frame-serving with SDL. Enjoy! Roy.
正在阅读:
Showing video with Qt toolbox and ffmpeg libraries11-04
谈对中学生进行道德教育06-22
管理人员测评题06-18
宝丰能源公司公司简介及2012校园招聘简章2011091512-13
烹饪原料知识 畜禽类03-28
MARC 出错调解11-02
2016-2017最新苏教版小学二年级上册数学期末试题305-13
项目成本管理之项目管理挣值分析BCWP09-09
关于祝福端午快乐的句子_端午节祝福语07-31
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- libraries
- Showing
- toolbox
- ffmpeg
- video
- with
- Qt
- 四川省宜宾市高三上学期半期测试理综生物试题
- 微观经济学选择题
- 在现代服务业项目推进大会上的讲话
- 常州市征地房屋拆迁安置及地上附着物补偿管理办法
- 潮汕民俗文化体验节项目可行性报告
- 新教材西师版四年级下册数学单元测试题(全套) - 图文
- 让文言文教学充满趣味
- 5、定向钻施工组织设计投标用
- 论会计职业道德与内部控制
- 第二章 细胞的基本功能 第二节 细胞膜的跨膜信号转导
- 民俗文化旅游资源开发初探论文(洮州民俗博物馆)
- 山东省潍坊市2019届高考考前模拟理综试题 Word版含答案 - 图文
- DES加密解密算法
- 2012全国两会网民最关注的五个热点话题
- 北师大版三年级数学下册《第一单元测试卷》(附答案)
- 政府会计准则复习题WORD版
- 2012年江苏省高考数学一轮训练试题考点6:解析几何
- 在全县招商引资工作会议上的表态发言材料
- 浙江教师资格普通话指导:普通话语音系统小常识
- 西方音乐史(课本顺序)