Просмотр исходного кода

V1.2.0

1.使用FFMPEG解码视频,并使用QPaint绘制到QWidget上
叶海辉 6 лет назад
Родитель
Сommit
8352591c16
8 измененных файлов с 238 добавлено и 49 удалено
  1. 9 4
      VideoPlayer.pro
  2. 28 0
      src/main.cpp
  3. 57 0
      src/mainwindow.cpp
  4. 43 0
      src/mainwindow.h
  5. 33 0
      src/mainwindow.ui
  6. 30 43
      src/videoplayer/videoplayer.cpp
  7. 35 0
      src/videoplayer/videoplayer.h
  8. 3 2
      说明.txt

+ 9 - 4
VideoPlayer_1.pro → VideoPlayer.pro

@@ -8,15 +8,20 @@ QT       += core gui
 
 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 
-TARGET = VideoPlayer_1
+TARGET = VideoPlayer
 TEMPLATE = app
 
 
-SOURCES += main.cpp
+SOURCES += src/main.cpp \
+    src/videoplayer/videoplayer.cpp \
+    src/mainwindow.cpp
 
-HEADERS  +=
+HEADERS  += \
+    src/videoplayer/videoplayer.h \
+    src/mainwindow.h
 
-FORMS    +=
+FORMS    += \
+    src/mainwindow.ui
 
 INCLUDEPATH += $$PWD/ffmpeg/include \
                 $$PWD/src

+ 28 - 0
src/main.cpp

@@ -0,0 +1,28 @@
+
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include <QApplication>
+#include <QTextCodec>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+
+    QTextCodec *codec = QTextCodec::codecForName("UTF-8"); //设置编码格式为UTF-8
+    QTextCodec::setCodecForLocale(codec);
+    QTextCodec::setCodecForCStrings(codec);
+    QTextCodec::setCodecForTr(codec);
+
+
+    MainWindow w;
+    w.show();
+
+    return a.exec();
+}
+

+ 57 - 0
src/mainwindow.cpp

@@ -0,0 +1,57 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include <QPainter>
+
+MainWindow::MainWindow(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::MainWindow)
+{
+    ui->setupUi(this);
+
+    mPlayer = new VideoPlayer;
+    connect(mPlayer,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(slotGetOneFrame(QImage)));
+
+    mPlayer->setFileName("E:\\in.mp4");
+    mPlayer->startPlay();
+
+}
+
+MainWindow::~MainWindow()
+{
+    delete ui;
+}
+
+void MainWindow::paintEvent(QPaintEvent *event)
+{
+    QPainter painter(this);
+    painter.setBrush(Qt::black);
+    painter.drawRect(0, 0, this->width(), this->height()); //先画成黑色
+
+    if (mImage.size().width() <= 0) return;
+
+    ///将图像按比例缩放成和窗口一样大小
+    QImage img = mImage.scaled(this->size(),Qt::KeepAspectRatio);
+
+    int x = this->width() - img.width();
+    int y = this->height() - img.height();
+
+    x /= 2;
+    y /= 2;
+
+    painter.drawImage(QPoint(x,y),img); //画出图像
+
+}
+
+void MainWindow::slotGetOneFrame(QImage img)
+{
+    mImage = img;
+    update(); //调用update将执行 paintEvent函数
+}

+ 43 - 0
src/mainwindow.h

@@ -0,0 +1,43 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QImage>
+#include <QPaintEvent>
+
+#include "videoplayer/videoplayer.h"
+
+namespace Ui {
+class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    explicit MainWindow(QWidget *parent = 0);
+    ~MainWindow();
+
+protected:
+    void paintEvent(QPaintEvent *event);
+
+private:
+    Ui::MainWindow *ui;
+
+    VideoPlayer *mPlayer; //播放线程
+
+    QImage mImage; //记录当前的图像
+
+private slots:
+    void slotGetOneFrame(QImage img);
+
+};
+
+#endif // MAINWINDOW_H

+ 33 - 0
src/mainwindow.ui

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>800</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QVBoxLayout" name="verticalLayout"/>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>800</width>
+     <height>23</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 30 - 43
main.cpp → src/videoplayer/videoplayer.cpp

@@ -1,10 +1,11 @@
-
-/**
+/**
  * 叶海辉
  * QQ群121376426
  * http://blog.yundiantech.com/
  */
 
+#include "videoplayer.h"
+
 extern "C"
 {
     #include "libavcodec/avcodec.h"
@@ -15,40 +16,26 @@ extern "C"
 
 #include <stdio.h>
 
-///现在我们需要做的是让SaveFrame函数能把RGB信息定稿到一个PPM格式的文件中。
-///我们将生成一个简单的PPM格式文件,请相信,它是可以工作的。
-void SaveFrame(AVFrame *pFrame, int width, int height,int index)
+VideoPlayer::VideoPlayer()
 {
 
-  FILE *pFile;
-  char szFilename[32];
-  int  y;
-
-  // Open file
-  sprintf(szFilename, "frame%d.ppm", index);
-  pFile=fopen(szFilename, "wb");
-
-  if(pFile==NULL)
-    return;
+}
 
-  // Write header
-  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
+VideoPlayer::~VideoPlayer()
+{
 
-  // Write pixel data
-  for(y=0; y<height; y++)
-  {
-    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
-  }
+}
 
-  // Close file
-  fclose(pFile);
+void VideoPlayer::startPlay()
+{
+    ///调用 QThread 的start函数 将会自动执行下面的run函数 run函数是一个新的线程
+    this->start();
 
 }
 
-
-int main(int argc, char *argv[])
+void VideoPlayer::run()
 {
-    char *file_path = "E:\\in.mp4";
+    char *file_path = mFileName.toUtf8().data();
 
     AVFormatContext *pFormatCtx;
     AVCodecContext *pCodecCtx;
@@ -69,12 +56,12 @@ int main(int argc, char *argv[])
 
     if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
         printf("can't open the file. \n");
-        return -1;
+        return;
     }
 
     if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
         printf("Could't find stream infomation.\n");
-        return -1;
+        return;
     }
 
     videoStream = -1;
@@ -91,7 +78,7 @@ int main(int argc, char *argv[])
     ///如果videoStream为-1 说明没有找到视频流
     if (videoStream == -1) {
         printf("Didn't find a video stream.\n");
-        return -1;
+        return;
     }
 
     ///查找解码器
@@ -100,26 +87,27 @@ int main(int argc, char *argv[])
 
     if (pCodec == NULL) {
         printf("Codec not found.\n");
-        return -1;
+        return;
     }
 
     ///打开解码器
     if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
         printf("Could not open codec.\n");
-        return -1;
+        return;
     }
 
     pFrame = av_frame_alloc();
     pFrameRGB = av_frame_alloc();
 
+    ///这里我们改成了 将解码后的YUV数据转换成RGB32
     img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
             pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
-            PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
+            PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
 
-    numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);
+    numBytes = avpicture_get_size(PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
 
     out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
-    avpicture_fill((AVPicture *) pFrameRGB, out_buffer, PIX_FMT_RGB24,
+    avpicture_fill((AVPicture *) pFrameRGB, out_buffer, PIX_FMT_RGB32,
             pCodecCtx->width, pCodecCtx->height);
 
     int y_size = pCodecCtx->width * pCodecCtx->height;
@@ -129,8 +117,6 @@ int main(int argc, char *argv[])
 
     av_dump_format(pFormatCtx, 0, file_path, 0); //输出视频信息
 
-    int index = 0;
-
     while (1)
     {
         if (av_read_frame(pFormatCtx, packet) < 0)
@@ -143,7 +129,7 @@ int main(int argc, char *argv[])
 
             if (ret < 0) {
                 printf("decode error.\n");
-                return -1;
+                return;
             }
 
             if (got_picture) {
@@ -152,17 +138,18 @@ int main(int argc, char *argv[])
                         pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
                         pFrameRGB->linesize);
 
-                SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height,index++); //保存图片
-                if (index > 50) return 0; //这里我们就保存50张图片
+                //把这个RGB数据 用QImage加载
+                QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
+                QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
+                emit sig_GetOneFrame(image);  //发送信号
             }
         }
         av_free_packet(packet);
+
+        msleep(5); //停一停  不然放的太快了
     }
     av_free(out_buffer);
     av_free(pFrameRGB);
     avcodec_close(pCodecCtx);
     avformat_close_input(&pFormatCtx);
-
-    return 0;
 }
-

+ 35 - 0
src/videoplayer/videoplayer.h

@@ -0,0 +1,35 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef VIDEOPLAYER_H
+#define VIDEOPLAYER_H
+
+#include <QThread>
+#include <QImage>
+
+class VideoPlayer : public QThread
+{
+    Q_OBJECT
+
+public:
+    explicit VideoPlayer();
+    ~VideoPlayer();
+
+    void setFileName(QString path){mFileName = path;}
+
+    void startPlay();
+
+signals:
+    void sig_GetOneFrame(QImage); //没获取到一帧图像 就发送此信号
+
+protected:
+    void run();
+
+private:
+    QString mFileName;
+};
+
+#endif // VIDEOPLAYER_H

+ 3 - 2
说明.txt

@@ -1,7 +1,8 @@
 这是Qt的工程,建议使用Qt Creator 打开
 
 
-是一个Windows下使用FFMPEG解码视频并保存成图片文件的简单的例子
+是一个Windows下使用FFMPEG解码视频
+并使用QPaint绘制到QWidget上
 FFMPEG的版本是2.5.2
 
 
@@ -9,7 +10,7 @@ FFMPEG
 
 
 关于代码的解释 请参考:
-http://blog.yundiantech.com/?log=blog&id=8
+http://blog.yundiantech.com/?log=blog&id=9
 
 
 Qt开发环境的搭建 请参考: