×
Namespaces

Variants
Actions

Qt与Symbian C++混合编程——视频录制/播放范例

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

代码示例
文章
Cxt_programmer 在 10 Dec 2010 创建
最后由 hamishwillee 在 30 May 2013 编辑

Contents

概述

强大的Qt Framework支持各种形式的混合编程,在Symbian上做开发会经常遇到Qt与Native Symbian C++混编的情况,本文将为大家介绍Qt与Symbian C++混编实现录制、播放视频的功能。

主要文件

本例中,将取景器、视频播放、录制均封装为一个单独的widget,供外部调用,显示,其中xqviewfinderwidget.h/xqviewfinderwidget.cpp提供对外的接口,真正的功能代码在xqviewfinderwidgetimpl.cpp中实现,代码如下:

xqviewfinderwidgetimpl.h:

#ifndef __X_QVIEW_FINDER_WIDGETIMPL_H__
#define __X_QVIEW_FINDER_WIDGETIMPL_H__
 
#include <e32base.h>
#include <ecam.h>
 
#include <QSize>
#include <QPixmap>
#include <QImage>
 
class XQViewFinderWidget;
 
#ifdef Q_OS_SYMBIAN
class XQViewFinderWidgetImpl : public CBase, public MCameraObserver
#else
class XQViewFinderWidgetImpl
#endif
{
public:
XQViewFinderWidgetImpl( XQViewFinderWidget* vfWidget );
~XQViewFinderWidgetImpl();
 
public: // New functions
enum TFinderState
{
EFinderInactive = 0,
EFinderInitializing,
EFinderImageReady,
EFinderFailed,
EFinderActive
};
 
void ConstructL(TInt aCamera);
void setViewFinderSize( QSize& size );
 
/**
* This method starts video view finder.
* @return void
*/

void StartL();
 
/**
* This method stops video view finder.
* @return void
*/

void Stop();
 
/**
* This method gets the state of video view finder.
* @return finder state
*/

TFinderState State() const;
 
/**
* This method returns camera handle.
* @return camera handle
*/

void CameraHandle();
 
public:
void Draw();
void Release();
 
private: // Data
TPoint iFinderPosition;
TFinderState iState;
TSize iViewFinderSize;
QPixmap iPixMap;
QImage iImage;
 
CCamera* iCamera; // owned
CFbsBitmap* iBitmap; // owned
 
XQViewFinderWidget* iVFWidget; // not owned
 
public: // Functions from MCameraObserver
void ReserveComplete(TInt aError);
void PowerOnComplete(TInt aError);
void ViewFinderFrameReady(CFbsBitmap& aFrame);
void ImageReady(CFbsBitmap* aBitmap, HBufC8* aData, TInt aError);
void FrameBufferReady(MFrameBuffer* aFrameBuffer, TInt aError);
};
 
#endif // end of __X_QVIEW_FINDER_WIDGETIMPL_H__

xqviewfinderwidgetimpl.cpp:

#include "xqviewfinderwidgetimpl.h"
#include "xqviewfinderwidget.h"
 
#include <QPainter>
#include <QPoint>
#include <QDebug>
#include <FBS.H>
 
XQViewFinderWidgetImpl::XQViewFinderWidgetImpl( XQViewFinderWidget* vfWidget ) : iVFWidget(vfWidget)
{
iState = EFinderInactive;
}
 
XQViewFinderWidgetImpl::~XQViewFinderWidgetImpl()
{
Release();
 
// delete iBitmap;
}
 
void XQViewFinderWidgetImpl::ConstructL( TInt aCamera )
{
if ( !CCamera::CamerasAvailable() )
{
//Handle KErrHardwareNotAvailable error here
return;
}
 
Release();
 
TRAPD( errCode, iCamera = CCamera::NewL( *this, aCamera ) );
 
if ( errCode != KErrNone )
{
iCamera = CCamera::NewL( *this, aCamera );
}
 
qDebug() << "VFImpl::ConstructL";
}
 
void XQViewFinderWidgetImpl::setViewFinderSize( QSize& size )
{
iViewFinderSize.iWidth = size.width();
iViewFinderSize.iHeight = size.height();
}
 
void XQViewFinderWidgetImpl::Draw()
{
// QPainter painter( iVFWidget );
// QPoint point(50, 50 );//( iVFWidget->pos() );
 
// painter.drawPixmap( point, iPixMap );
 
if ( iState == EFinderImageReady )
{
QPainter painter( iVFWidget );
QPoint point( iVFWidget->pos() );
QSize vfSize = iVFWidget->size();
 
QPixmap tempPixmap = QPixmap::fromImage( iImage.scaled( vfSize, Qt::KeepAspectRatio) );
 
painter.drawPixmap(point, tempPixmap);
}
}
 
void XQViewFinderWidgetImpl::StartL()
{
if ( !iCamera )
{
User::Leave( KErrNotReady );
}
 
iState = EFinderInitializing;
qDebug() << "before reserve";
iCamera->Reserve();
qDebug() << "end Camera StartL";
}
 
void XQViewFinderWidgetImpl::Stop()
{
if ( iState == EFinderActive )
{
iCamera->PowerOff();
iCamera->Release();
}
iState = EFinderInactive;
}
 
/*
-----------------------------------------------------------------------------
Description: This method informs that camera reservation is complete.
Comments  : Called asynchronously when CCamera::Reserve() completes.
 
Return values: N/A
-----------------------------------------------------------------------------
*/

void XQViewFinderWidgetImpl::ReserveComplete(TInt aError)
{
qDebug() << "ReserveComplete: errcode:" << aError;
// User::LeaveIfError( aError );
 
if(aError==KErrNone)
{
qDebug() << "Before PowerOn";
iCamera->PowerOn();
qDebug() << "end PowerOn";
}
else
{
iCamera->Reserve();
// iState = EFinderFailed;
}
}
 
/*
-----------------------------------------------------------------------------
Description: This method indicates camera power on is complete.
Comments  : Called on completion of CCamera:PowerOn().
 
Return values: N/A
-----------------------------------------------------------------------------
*/

void XQViewFinderWidgetImpl::PowerOnComplete(TInt aError)
{
if ( aError == KErrNone )
{
// TSize finderSize = Size();
// Start view finder. On return, finderSize contains the finder size
TRAPD( ignored, iCamera->StartViewFinderBitmapsL(iViewFinderSize) );
 
iState = EFinderActive;
 
CameraHandle();
}
else
{
iCamera->Release();
iState = EFinderFailed;
}
}
 
/*
-----------------------------------------------------------------------------
Description: This method tests whether transfer of view finder data has completed.
Comments  : Called periodically in response to the use of
CCamera::StartViewFinderBitmapsL().
 
Return values: N/A
-----------------------------------------------------------------------------
*/

void XQViewFinderWidgetImpl::ViewFinderFrameReady(CFbsBitmap& aFrame)
{
iState = EFinderImageReady;
 
int bytesPerLine = aFrame.ScanLineLength( iViewFinderSize.iWidth, aFrame.DisplayMode() );
QImage image( (uchar *)aFrame.DataAddress(), iViewFinderSize.iWidth, iViewFinderSize.iHeight, bytesPerLine, QImage::Format_RGB32 );
 
iImage = image;
 
iVFWidget->repaint();
}
 
/*
-----------------------------------------------------------------------------
Description: This method transfers the current image from the camera to the client.
Comments  : Called asynchronously when CCamera::CaptureImage() completes.
 
Return values: N/A
-----------------------------------------------------------------------------
*/

void XQViewFinderWidgetImpl::ImageReady(CFbsBitmap* /*aBitmap*/, HBufC8* /*aData*/, TInt /*aError*/)
{
}
 
/*
-----------------------------------------------------------------------------
Description: This method passes a filled frame buffer to the client.
Comments  : Called asynchronously, when a buffer has been filled with the
required number of video frames by CCamera::StartVideoCapture().
 
Return values: N/A
-----------------------------------------------------------------------------
*/

void XQViewFinderWidgetImpl::FrameBufferReady(MFrameBuffer* /*aFrameBuffer*/, TInt /*aError*/)
{
}
 
void XQViewFinderWidgetImpl::CameraHandle()
{
iVFWidget->emitCameraHandler( iCamera->Handle() );
}
 
void XQViewFinderWidgetImpl::Release()
{
if ( iCamera )
{
Stop();
delete iCamera;
iCamera = NULL;
}
}

这种封装方式最大的好处有两个,一是只对程序员暴漏公共接口,关键数据结构都封装在impl中,程序员无需知道接口具体实现方式;二是提供统一接口供外部调用,在移植到其他平台时,只需修改impl实现方式,接口不变,对使用该接口的程序员不产生任何影响。这种模式在跨平台应用、框架中使用的很多。

工程中录制视频的工具类xqvideorecordutil/xqvideorecordutilimpl以及播放视频的工具类xqvideoplayerwidget/xqvideoplayerwidgetimpl均使用这种模式开发,详细代码请参阅附件工程。

注意事项

在实现视频播放时,xqvideoplayerwidgetimpl中使用的是Symbian API CVideoPlayerUtility,在构造它的时候,会发现它需要一个RWindow对象做参数;在Symbian平台,每个控件都可以很容易获取自己的RWindow,而我们封装的Qt代码中,只有QWidget对象。这里有一个技巧,用于从QWidget获取Symbian的RWindow对象,可以解决遇到的问题,代码如下:

CCoeControl* pControl = static_cast<CCoeControl*>(iPlayerWidget->winId());
RWindow* pWindow = static_cast<RWindow*>(pControl->DrawableWindow());

详细代码在XQVideoPlayerWidgetImpl::InitControllerL函数中。

另外在Qt和Symbian C++混编时,需要注意在pro文件中添加Symbian API相关的lib文件,否则会出现链接错误,本例中我们主要使用了camera相关的lib,pro文件修改如下:

symbian {
TARGET.UID3 = 0xeb0bcf09
TARGET.CAPABILITY += UserEnvironment
TARGET.EPOCSTACKSIZE = 0x14000
TARGET.EPOCHEAPSIZE = 0x020000 0x800000
 
LIBS += -lecam \
-lfbscli \
-lmediaclientvideo \
-lmmfcontrollerframework \
-lPlatformEnv \
-lcone \
-lws32
debug{
MMP_RULES -= PAGED
MMP_RULES += UNPAGED
}

mainwindow.cpp中,创建了各个组件和菜单,并把相应的signal和slot连接起来。

工程下载

File:QtVideoRecordTest.zip

相关链接

This page was last modified on 30 May 2013, at 09:34.
163 page views in the last 30 days.