Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

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

From 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 06:34.
305 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×