×
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 05:15.
236 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.

×