×
Namespaces

Variants
Actions

Symbian^3录制/播放视频范例

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

代码示例
兼容于
平台: Symbian^3 and later

文章
Cxt_programmer 在 09 Dec 2010 创建
最后由 hamishwillee 在 15 Dec 2011 编辑

Contents

背景

S60 Platform: Video Example v2.0,是Forum Nokia早期提供的一个录制、播放视频的例子,此例子适用于S60 2nd、3rd、5th平台。

由于Symbian^3在图形图像架构进行了很大的修改,Symbian^3采用了全新的NGA架构(New Graphics Architecture,此架构对DSA绘制方法带来了一些直接的影响,请参考SDK文档“DSA Migration Guide”)。

在Symbian^3设备上调试Video例子会发现两个问题,一个是取景器viewfinder中无法看到摄像头传来的图像二是在播放视频的时候,看不到视频内容,只能听到视频的声音,而使用系统自带播放器打开录制的视频文件是可以正常显示的。

问题分析

前面已经提到,Symbian^3在图形图像架构上做了很大修改,而此例子中的视频播放API又使用到了CWsScreenDevice,所以首先怀疑是架构调整带来的“不兼容”问题,凭经验,此类问题大多可以通过调整API的使用/调用来解决。

解决问题

我们知道,取景器是以“帧”的形式把摄像头传来的图片显示给用户的,查看VRexViewFinder.cpp代码,加断电并联机调试,发现打开摄像头、ViewFinderFrameReady(CFbsBitmap& aFrame)等各种回调函数均被正常调用到,而且aFrame参数是有图像内容的,查阅ViewFinderFrameReady函数代码:

void CVideoViewFinder::ViewFinderFrameReady(CFbsBitmap& aFrame)
{
// Keep backlight on while finder is active
User::ResetInactivityTime();
 
// Get graphics context
CWindowGc &gc = SystemGc();
 
// Graphics context must be activated, because we are not in Draw()
gc.Activate(Window());
 
// Draw finder frame to screen; BitBlt is much faster than DrawBitmap
gc.BitBlt(iFinderPosition, &aFrame);
 
// Deactivate graphics context
gc.Deactivate();
}

熟悉Symbian的朋友都清楚,这是Symbian中在CCoeControl::Draw函数外绘制内容的标准做法,先Activate(Window()),然后绘制,绘制完成后Deactivate(),才能把绘制内容显示在屏幕,并未看出有什么错误。但调试时候看到参数aFrame是有内容的,并且录制出的视频系统可以播放,所以我就打算改变一下绘制方式看看,于是ViewFinderFrameReady被我改造成了下面的样子:

void CVideoViewFinder::ViewFinderFrameReady(CFbsBitmap& aFrame)
{
if ( iBitmap != NULL )
{
delete iBitmap;
iBitmap = NULL;
}
 
TSize size = aFrame.SizeInPixels();
iBitmap = new(ELeave) CFbsBitmap;
User::LeaveIfError( iBitmap->Create( aFrame.SizeInPixels(), iEikonEnv->ScreenDevice()->DisplayMode() ) );
 
RDesWriteStream writeStream;
RDesReadStream readStream;
 
HBufC8* imgBuffer = HBufC8::NewLC( aFrame.Header().iBitmapSize );
TPtr8 ptr = imgBuffer->Des();
 
writeStream.Open( ptr );
writeStream.PushL();
 
aFrame.ExternalizeL( writeStream );
writeStream.CommitL();
writeStream.Pop();
writeStream.Release();
 
readStream.Open(imgBuffer->Des());
readStream.PushL();
iBitmap->InternalizeL(readStream);
readStream.Pop();
readStream.Release();
CleanupStack::PopAndDestroy(imgBuffer);
 
writeStream.Close();
readStream.Close();
 
DrawNow();
}

思路就是将参数传来的帧图像复制到成员变量iBitmap中,然后在Draw函数中绘制:

void CVideoViewFinder::Draw(const TRect& aRect) const
{
// Draw the background of finder
CWindowGc &gc = SystemGc();
 
// gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
// gc.SetBrushColor(KRgbWhite);
//
// gc.DrawRect(aRect);
 
if ( State() != EFinderInactive && iBitmap != NULL )
{
gc.BitBlt( iFinderPosition, iBitmap );
}
}

Bingo!成功将取景器中的图像内容显示在程序中!

PS:这里我并未深究为什么Activate(Window())的绘制方式在Symbian^3中无效,感兴趣的朋友可以就此问题深入研究一下,欢迎继续编辑此篇文章。

第二个问题就是程序中播放录制的视频时,只能听到视频的声音但看不到视频图像,而用系统播放器播放视频文件是正常的,从而确定录制的视频文件没有问题,从解决上一个问题的经验来分析,可能也是绘制上出了问题。

查看CVideoPlayerAdapter代码发现,程序中使用CVideoPlayerUtility API播放视频文件,此API在构造时传入WsSession,WsScreenDevice以及某个CCoeControl的Window等参数,便可在CCoeControl的窗口中播放视频,API使用均未发现问题。在程序中增加断点调试,发现构造CVideoPlayerUtility时传入的是CVRexVideoContainer的Window,进而在CVRexVideoContainer中增加断点调试,发现CVRexVideoContainer::Draw方法播放视频时也会不断被调用,而Draw方法的代码中,有填充控件窗口矩形的操作,当时怀疑视频播放的图像被这些操作给“清空”了!Draw函数修改如下:

void CVRexVideoContainer::Draw(const TRect& aRect) const
{
CWindowGc& gc = SystemGc();
// gc.SetPenStyle( CGraphicsContext::ENullPen );
// gc.SetBrushColor( KRgbGray );
// gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
// gc.DrawRect( aRect );
}

问题解决!

工程下载

VRex for Symbian^3下载:File:VRex For Symbian3.zip

注意事项

Symbian^3 SDK中未包含mmferrors.h头文件,可从之前版本SDK中拷贝。附带例子中的mmferrors.h在inc目录中。

待改进功能

程序中“Embedded Player”功能还无法正常使用,欢迎大家随时修改,更新此文章和例子。

相关链接

This page was last modified on 15 December 2011, at 08:15.
125 page views in the last 30 days.