您的位置:首页 > 编程语言 > Qt开发

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

2017-07-03 23:47 585 查看
海康的格式比较特殊,几乎是私有的,解码的话要使用海康的库才行。

先要下载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 <QDebug>
#include <QMetaObject>
#include <QPixmap>
#include <QImage>
#include <QFileDialog>
#include <QStandardPaths>
#include <QThread>

// 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用户唤出文件选择框。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: