Qt:解码海康视频格式并显示在QLabel上

海康的格式比较特殊,几乎是私有的,解码的话要使用海康的库才行。

先要下载SDK,地址如下:
http://www1.hikvision.com/cn/download_more_406.html

我这里下载的是64位的,我本地的环境是Win10 64位, Qt是5.9.0 64bit,编译器使用VS2013

使用的话,还是挺方便的

pro中导入海康的库:

LIBS += -L$$PWD/hik -lPlayCtrl

代码中的使用:

#include "mainwindow.h"

// Qt lib import
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// UI import
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui_(new Ui::MainWindow)
{
    ui_->setupUi(this);

    qRegisterMetaType< QPixmap >( "QPixmap" );

    connect( ui_->pushButton, &QPushButton::clicked, this, &MainWindow::play );
}

MainWindow::~MainWindow()
{
    delete ui_;
}

bool MainWindow::yv12ToRGB888(const unsigned char *yv12, unsigned char *rgb888, int width, int height)
{
    if ( ( width < 1 ) || ( height < 1 ) || ( yv12 == nullptr ) || ( rgb888 == nullptr ) ) { return false; }

    const auto &&len = width * height;
    unsigned char const *yData = yv12;
    unsigned char const *vData = &yData[ len ];
    unsigned char const *uData = &vData[ len >> 2 ];

    int rgb[ 3 ];
    int yIdx, uIdx, vIdx, idx;

    for ( auto i = 0; i < height; ++i )
    {
        for ( auto j = 0; j < width; ++j )
        {
            yIdx = i * width + j;
            vIdx = ( i / 2 ) * ( width / 2 ) + ( j / 2 );
            uIdx = vIdx;

            rgb[ 0 ] = static_cast< int >( yData[ yIdx ] + 1.370705 * ( vData[ uIdx ] - 128 ) );
            rgb[ 1 ] = static_cast< int >( yData[ yIdx ] - 0.698001 * ( uData[ uIdx ] - 128 ) - 0.703125 * ( vData[ vIdx ] - 128 ) );
            rgb[ 2 ] = static_cast< int >( yData[ yIdx ] + 1.732446 * ( uData[ vIdx ] - 128 ) );

            for ( auto k = 0; k < 3; ++k )
            {
                idx = ( i * width + j ) * 3 + k;

                if( ( rgb[ k ] >= 0 ) && ( rgb[ k ] <= 255 ) )
                {
                    rgb888[ idx ] = static_cast< unsigned char >( rgb[ k ] );
                }
                else
                {
                    rgb888[ idx ] = ( rgb[ k ] < 0 )? ( 0 ) : ( 255 );
                }
            }
        }
    }
    return true;
}

void MainWindow::decCallback(long /*nPort*/, char *pBuf, long /*nSize*/, FRAME_INFO *pFrameInfo, void *nUser, void * /*nReserved2*/)
{
    auto this_ = reinterpret_cast< MainWindow * >( nUser );

    if ( ( pFrameInfo->nWidth < 1 ) || ( pFrameInfo->nHeight < 1 ) )
    {
        qDebug() << "decCallback: width or height error";
        return;
    }

//    qDebug() << pFrameInfo->nWidth;
//    qDebug() << pFrameInfo->nHeight;

    switch ( pFrameInfo->nType )
    {
        case T_RGB32: { break; }
        case T_UYVY: { break; }
        case T_YV12:
        {
            QImage image( pFrameInfo->nWidth, pFrameInfo->nHeight, QImage::Format_RGB888 );

            if ( !yv12ToRGB888( reinterpret_cast< unsigned char * >( pBuf ), image.bits(), pFrameInfo->nWidth, pFrameInfo->nHeight ) )
            {
                qDebug() << "decCallback: yv12ToRGB888 error";
                break;
            }

            QMetaObject::invokeMethod( this_->ui_->label, "setPixmap", Qt::QueuedConnection, Q_ARG( QPixmap, QPixmap::fromImage( image ) ) );

            break;
        }
    }

    return;
}

void MainWindow::endCallback(long nPort, void *pUser)
{
    auto this_ = reinterpret_cast< MainWindow * >( pUser );

    qDebug() << "endCallback:" << nPort << this_;
}

void MainWindow::play()
{
    const auto &&filePath = QFileDialog::getOpenFileName(
                this,
                "Choose mp4 file",
                QStandardPaths::writableLocation( QStandardPaths::DesktopLocation ),
                "mp4 (*.mp4)"
            );
    if ( filePath.isEmpty() ) { return; }

    ui_->pushButton->hide();

    const auto &&local8Bit = filePath.toLocal8Bit();

    auto buf = new char[ static_cast< size_t >( local8Bit.size() ) + 1 ];
    memcpy( buf, local8Bit.data(), static_cast< size_t >( local8Bit.size() ) );

    qDebug() << "PlayM4_OpenFile: return:" << PlayM4_OpenFile( port_, buf );

    PlayM4_SetDecCallBackExMend( port_, decCallback, nullptr, 0, reinterpret_cast< void * >( this ) );
    PlayM4_SetFileEndCallback( port_, endCallback, reinterpret_cast< void * >( this ) );
    PlayM4_Play( port_, nullptr );

    // QThread::sleep( 1 );

    // PlayM4_Fast( port_ );
    // PlayM4_Fast( port_ );
}

这里只列了mainwindow.cpp中的源码,核心的都在这里了。UI上只有一个label用于显示QPixmap还有一个button用户唤出文件选择框。

你可能感兴趣的:(Qt)