Android下的PVPlayer的实现(4)

最后才是do_nothing,把同步做的事情分成几步来做了。

剩下的基本都是很简单的,就是发送一条又一条的命令即可,其实主要的操作,都在PlayerDriver中。

下面我们来简单的看看这个PlayerDriver,这个事实现播放的主要成员,首先他是一个管理器,他管理者OpenCore的整个框架,最后的输出的 MIO,其次,他是一个异步的东东,存在着一个命令的队列。这个里面虽然代码很多,但是思路很清晰,我们就不一一的列出来,这个里面主要的播放功能被封装到一个叫PVPlayerInterface的接口中了。

这里我们首先分析它的视频显示,在接收到设置显示面的时候,有这样的一个处理:

// if no device-specific MIO was created, use the generic one
if (mio == NULL) {
LOGW("Using generic video MIO");
mio = new AndroidSurfaceOutput();
}

// initialize the MIO parameters
status_t ret = mio->set(mPvPlayer, command->surface(), mEmulation);
if (ret != NO_ERROR) {
LOGE("Video MIO set failed");
commandFailed(command);
delete mio;
return;
}
mVideoOutputMIO = mio;

mVideoNode = PVMediaOutputNodeFactory::CreateMediaOutputNode(mVideoOutputMIO);
mVideoSink = new PVPlayerDataSinkPVMFNode;

((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkNode(mVideoNode);
((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkFormatType(PVMF_YUV420);

OSCL_TRY(error, mPlayer->AddDataSink(*mVideoSink, command));

这个mPlayer就是一个PVPlayerInterface的成员。在opencore中我们的最终都是要封装成NODE的,MIO可以属于 NODE,MIO主要负责和硬件打交道的一部分,这几行代码首先创建一个AndroidSurfaceOutput的MIO,创建了之后设置一些基本的属性set函数,然后,由MIO创建OutPutNode,这就是一个NOde了,这个东东创建了之后,就要把这个Node添加到整个数据链路中,并且设置一下基本的属性。这样我们的输出Node就添加到了数据链路中了,那么我们的MIO是如何工作的呢?

创建MIO之后有这样的一个函数

status_t AndroidSurfaceOutput::set(PVPlayer* pvPlayer, const sp<ISurface>& surface, bool emulation)
{
mPvPlayer = pvPlayer;
mSurface = surface;
mEmulation = emulation;
return NO_ERROR;
}

这个函数就设置了我们Vedio out MIO最主要的几个属性,一个是pvPlayer,一个是surface,最后的一个参数应该是表明是不是模拟器。

我们来看看这个MIO。关于MIO前面我们基本已经讲过,可能没有放在blog上。一般由这几个接口派生:

public OsclTimerObject, public PvmiMIOControl,
public PvmiMediaTransfer, public PvmiCapabilityAndConfig

但是作为一个视频输出的MIO,这里有几个自己特色的函数:

// For frame buffer
virtual bool initCheck();
virtual PVMFStatus writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info);
virtual void postLastFrame();
virtual void closeFrameBuf();

bool GetVideoSize(int *w, int *h);

我们一跳一条的分析:

首先是initCheck,这个函数什么时候开始调用?

// create a frame buffer for software codecs
OSCL_EXPORT_REF bool AndroidSurfaceOutput::initCheck()
{

// initialize only when we have all the required parameters

//首先看看是不是视频相关的属性发生改变了,如果不是视频就不用管他,直接返回
if (!checkVideoParameterFlags())
return mInitialized;

// release resources if previously initialized 删除以前分配的缓存
closeFrameBuf();

// reset flags in case display format changes in the middle of a stream
resetVideoParameterFlags(); //视频改变的标志位还原

// copy parameters in case we need to adjust them

//得到新的宽和高,(包括视频和显示器,我们在横屏的时候就可以这样搞)
int displayWidth = iVideoDisplayWidth;
int displayHeight = iVideoDisplayHeight;
int frameWidth = iVideoWidth;
int frameHeight = iVideoHeight;
int frameSize;

// RGB-565 frames are 2 bytes/pixel //因为我们的数据都是565的16位的像素点

//&-2 表明取偶数
displayWidth = (displayWidth + 1) & -2;
displayHeight = (displayHeight + 1) & -2;
frameWidth = (frameWidth + 1) & -2;
frameHeight = (frameHeight + 1) & -2;


frameSize = frameWidth * frameHeight * 2;

// create frame buffer heap and register with surfaceflinger //然后分配两帧的数据
mFrameHeap = new MemoryHeapBase(frameSize * kBufferCount);
if (mFrameHeap->heapID() < 0) {
LOGE("Error creating frame buffer heap");
return false;
}
//分配之后把数据指明给buffer,这样我们的buffer是到是一个什么样的格式,长和宽分别是多少
ISurface::BufferHeap buffers(displayWidth, displayHeight,
frameWidth, frameHeight, PIXEL_FORMAT_RGB_565, mFrameHeap);

//然后注册这个buffer
mSurface->registerBuffers(buffers);

// create frame buffers

//mFrameBuffers[i]保存的是第I帧的起始位置
for (int i = 0; i < kBufferCount; i++) {
mFrameBuffers[i] = i * frameSize;
}

//然后初始化视频数据转换器

// initialize software color converter
iColorConverter = ColorConvert16::NewL();
iColorConverter->Init(displayWidth, displayHeight, frameWidth, displayWidth, displayHeight, displayWidth, CCROTATE_NONE);
iColorConverter->SetMemHeight(frameHeight);
iColorConverter->SetMode(1);

LOGV("video = %d x %d", displayWidth, displayHeight);
LOGV("frame = %d x %d", frameWidth, frameHeight);
LOGV("frame #bytes = %d", frameSize);

// register frame buffers with SurfaceFlinger
mFrameBufferIndex = 0;
mInitialized = true;
mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, iVideoDisplayWidth, iVideoDisplayHeight);
return mInitialized;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwspdx.html