当前位置:  编程技术>移动开发
本页文章导读:
    ▪求大神解决,长按图片怎么拖动到指定位置        求大神解决,长按图片如何拖动到指定位置求大神     求大神解决,长按图片如何拖动到指定位置 qq1790542492 ......
    ▪ 跨平台的游戏客户端Socket打包        跨平台的游戏客户端Socket封装        依照惯例,先上代码: #pragma once #ifdef WIN32 #include <windows.h> #include <WinSock.h> #else #include <sys/socket.h> #include <fcntl.h> #include <errno.h> #i.........
    ▪ Andriod4.2 Camera 架构与兑现       Andriod4.2 Camera 架构与实现 1.Camera架构包括客户端和服务端,他们之间的通信采用Binder机制实现。 Camera的实现主要包括本地代码和Java代码两个层次: Camera本地框架: frameworks/native/include/ui .........

[1]求大神解决,长按图片怎么拖动到指定位置
    来源: 互联网  发布时间: 2014-02-18
求大神解决,长按图片如何拖动到指定位置

求大神     求大神解决,长按图片如何拖动到指定位置

qq1790542492


    
[2] 跨平台的游戏客户端Socket打包
    来源: 互联网  发布时间: 2014-02-18
跨平台的游戏客户端Socket封装

        依照惯例,先上代码:

#pragma once

#ifdef WIN32
#include <windows.h>
#include <WinSock.h>
#else
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SOCKET int
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1

#endif

#ifndef CHECKF
#define CHECKF(x) \
	do \
{ \
	if (!(x)) { \
	log_msg("CHECKF", #x, __FILE__, __LINE__); \
	return 0; \
	} \
} while (0)
#endif

#define _MAX_MSGSIZE 16 * 1024		// 暂定一个消息最大为16k
#define BLOCKSECONDS	30			// INIT函数阻塞时间
#define INBUFSIZE	(64*1024)		//?	具体尺寸根据剖面报告调整  接收数据的缓存
#define OUTBUFSIZE	(8*1024)		//? 具体尺寸根据剖面报告调整。 发送数据的缓存,当不超过8K时,FLUSH只需要SEND一次

class CGameSocket {
public:
	CGameSocket(void);
	bool	Create(const char* pszServerIP, int nServerPort, int nBlockSec = BLOCKSECONDS, bool bKeepAlive = false);
	bool	SendMsg(void* pBuf, int nSize);
	bool	ReceiveMsg(void* pBuf, int& nSize);
	bool	Flush(void);
	bool	Check(void);
	void	Destroy(void);
	SOCKET	GetSocket(void) const { return m_sockClient; }
private:
	bool	recvFromSock(void);		// 从网络中读取尽可能多的数据
	bool    hasError();			// 是否发生错误,注意,异步模式未完成非错误
	void    closeSocket();

	SOCKET	m_sockClient;

	// 发送数据缓冲
	char	m_bufOutput[OUTBUFSIZE];	//? 可优化为指针数组
	int		m_nOutbufLen;

	// 环形缓冲区
	char	m_bufInput[INBUFSIZE];
	int		m_nInbufLen;
	int		m_nInbufStart;				// INBUF使用循环式队列,该变量为队列起点,0 - (SIZE-1)
};

#include "stdafx.h"
#include "Socket.h"

CGameSocket::CGameSocket()
{ 
	// 初始化
	memset(m_bufOutput, 0, sizeof(m_bufOutput));
	memset(m_bufInput, 0, sizeof(m_bufInput));
}

void CGameSocket::closeSocket()
{
#ifdef WIN32
    closesocket(m_sockClient);
    WSACleanup();
#else
    close(m_sockClient);
#endif
}

bool CGameSocket::Create(const char* pszServerIP, int nServerPort, int nBlockSec, bool bKeepAlive /*= FALSE*/)
{
	// 检查参数
	if(pszServerIP == 0 || strlen(pszServerIP) > 15) {
		return false;
	}

#ifdef WIN32
	WSADATA wsaData;
	WORD version = MAKEWORD(2, 0);
	int ret = WSAStartup(version, &wsaData);//win sock start up
	if (ret != 0) {
		return false;
	}
#endif

	// 创建主套接字
	m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(m_sockClient == INVALID_SOCKET) {
        closeSocket();
		return false;
	}

	// 设置SOCKET为KEEPALIVE
	if(bKeepAlive)
	{
		int		optval=1;
		if(setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (char *) &optval, sizeof(optval)))
		{
            closeSocket();
			return false;
		}
	}

#ifdef WIN32
	DWORD nMode = 1;
	int nRes = ioctlsocket(m_sockClient, FIONBIO, &nMode);
	if (nRes == SOCKET_ERROR) {
		closeSocket();
		return false;
	}
#else
	// 设置为非阻塞方式
	fcntl(m_sockClient, F_SETFL, O_NONBLOCK);
#endif

	unsigned long serveraddr = inet_addr(pszServerIP);
	if(serveraddr == INADDR_NONE)	// 检查IP地址格式错误
	{
		closeSocket();
		return false;
	}

	sockaddr_in	addr_in;
	memset((void *)&addr_in, 0, sizeof(addr_in));
	addr_in.sin_family = AF_INET;
	addr_in.sin_port = htons(nServerPort);
	addr_in.sin_addr.s_addr = serveraddr;
	
	if(connect(m_sockClient, (sockaddr *)&addr_in, sizeof(addr_in)) == SOCKET_ERROR) {
		if (hasError()) {
			closeSocket();
			return false;
		}
		else	// WSAWOLDBLOCK
		{
			timeval timeout;
			timeout.tv_sec	= nBlockSec;
			timeout.tv_usec	= 0;
			fd_set writeset, exceptset;
			FD_ZERO(&writeset);
			FD_ZERO(&exceptset);
			FD_SET(m_sockClient, &writeset);
			FD_SET(m_sockClient, &exceptset);

			int ret = select(FD_SETSIZE, NULL, &writeset, &exceptset, &timeout);
			if (ret == 0 || ret < 0) {
				closeSocket();
				return false;
			} else	// ret > 0
			{
				ret = FD_ISSET(m_sockClient, &exceptset);
				if(ret)		// or (!FD_ISSET(m_sockClient, &writeset)
				{
					closeSocket();
					return false;
				}
			}
		}
	}

	m_nInbufLen		= 0;
	m_nInbufStart	= 0;
	m_nOutbufLen	= 0;

	struct linger so_linger;
	so_linger.l_onoff = 1;
	so_linger.l_linger = 500;
	setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger));

	return true;
}

bool CGameSocket::SendMsg(void* pBuf, int nSize)
{
	if(pBuf == 0 || nSize <= 0) {
		return false;
	}

	if (m_sockClient == INVALID_SOCKET) {
		return false;
	}

	// 检查通讯消息包长度
	int packsize = 0;
	packsize = nSize;

	// 检测BUF溢出
	if(m_nOutbufLen + nSize > OUTBUFSIZE) {
		// 立即发送OUTBUF中的数据,以清空OUTBUF。
		Flush();
		if(m_nOutbufLen + nSize > OUTBUFSIZE) {
			// 出错了
			Destroy();
			return false;
		}
	}
	// 数据添加到BUF尾
	memcpy(m_bufOutput + m_nOutbufLen, pBuf, nSize);
	m_nOutbufLen += nSize;
	return true;
}

bool CGameSocket::ReceiveMsg(void* pBuf, int& nSize)
{
	//检查参数
	if(pBuf == NULL || nSize <= 0) {
		return false;
	}
	
	if (m_sockClient == INVALID_SOCKET) {
		return false;
	}

	// 检查是否有一个消息(小于2则无法获取到消息长度)
	if(m_nInbufLen < 2) {
		//  如果没有请求成功  或者   如果没有数据则直接返回
		if(!recvFromSock() || m_nInbufLen < 2) {		// 这个m_nInbufLen更新了
			return false;
		}
	}

    // 计算要拷贝的消息的大小(一个消息,大小为整个消息的第一个16字节),因为环形缓冲区,所以要分开计算
	int packsize = (unsigned char)m_bufInput[m_nInbufStart] +
		(unsigned char)m_bufInput[(m_nInbufStart + 1) % INBUFSIZE] * 256; // 注意字节序,高位+低位

	// 检测消息包尺寸错误 暂定最大16k
	if (packsize <= 0 || packsize > _MAX_MSGSIZE) {
		m_nInbufLen = 0;		// 直接清空INBUF
		m_nInbufStart = 0;
		return false;
	}

	// 检查消息是否完整(如果将要拷贝的消息大于此时缓冲区数据长度,需要再次请求接收剩余数据)
	if (packsize > m_nInbufLen) {
		// 如果没有请求成功   或者    依然无法获取到完整的数据包  则返回,直到取得完整包
		if (!recvFromSock() || packsize > m_nInbufLen) {	// 这个m_nInbufLen已更新
			return false;
		}
	}

	// 复制出一个消息
	if(m_nInbufStart + packsize > INBUFSIZE) {
		// 如果一个消息有回卷(被拆成两份在环形缓冲区的头尾)
		// 先拷贝环形缓冲区末尾的数据
		int copylen = INBUFSIZE - m_nInbufStart;
		memcpy(pBuf, m_bufInput + m_nInbufStart, copylen);

		// 再拷贝环形缓冲区头部的剩余部分
		memcpy((unsigned char *)pBuf + copylen, m_bufInput, packsize - copylen);
		nSize = packsize;
	} else {
		// 消息没有回卷,可以一次拷贝出去
		memcpy(pBuf, m_bufInput + m_nInbufStart, packsize);
		nSize = packsize;
	}

	// 重新计算环形缓冲区头部位置
	m_nInbufStart = (m_nInbufStart + packsize) % INBUFSIZE;
	m_nInbufLen -= packsize;
	return	true;
}

bool CGameSocket::hasError()
{
#ifdef WIN32
	int err = WSAGetLastError();
	if(err != WSAEWOULDBLOCK) {
#else
	int err = errno;
	if(err != EINPROGRESS && err != EAGAIN) {
#endif
		return true;
	}

	return false;
}

// 从网络中读取尽可能多的数据,实际向服务器请求数据的地方
bool CGameSocket::recvFromSock(void)
{
	if (m_nInbufLen >= INBUFSIZE || m_sockClient == INVALID_SOCKET) {
		return false;
	}

	// 接收第一段数据
	int	savelen, savepos;			// 数据要保存的长度和位置
	if(m_nInbufStart + m_nInbufLen < INBUFSIZE)	{	// INBUF中的剩余空间有回绕
		savelen = INBUFSIZE - (m_nInbufStart + m_nInbufLen);		// 后部空间长度,最大接收数据的长度
	} else {
		savelen = INBUFSIZE - m_nInbufLen;
	}

	// 缓冲区数据的末尾
	savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE;
	CHECKF(savepos + savelen <= INBUFSIZE);
	int inlen = recv(m_sockClient, m_bufInput + savepos, savelen, 0);
	if(inlen > 0) {
		// 有接收到数据
		m_nInbufLen += inlen;
		
		if (m_nInbufLen > INBUFSIZE) {
			return false;
		}

		// 接收第二段数据(一次接收没有完成,接收第二段数据)
		if(inlen == savelen && m_nInbufLen < INBUFSIZE) {
			int savelen = INBUFSIZE - m_nInbufLen;
			int savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE;
			CHECKF(savepos + savelen <= INBUFSIZE);
			inlen = recv(m_sockClient, m_bufInput + savepos, savelen, 0);
			if(inlen > 0) {
				m_nInbufLen += inlen;
				if (m_nInbufLen > INBUFSIZE) {
					return false;
				}	
			} else if(inlen == 0) {
				Destroy();
				return false;
			} else {
				// 连接已断开或者错误(包括阻塞)
				if (hasError()) {
					Destroy();
					return false;
				}
			}
		}
	} else if(inlen == 0) {
		Destroy();
		return false;
	} else {
		// 连接已断开或者错误(包括阻塞)
		if (hasError()) {
			Destroy();
			return false;
		}
	}

	return true;
}

bool CGameSocket::Flush(void)		//? 如果 OUTBUF > SENDBUF 则需要多次SEND()
{
	if (m_sockClient == INVALID_SOCKET) {
		return false;
	}

	if(m_nOutbufLen <= 0) {
		return true;
	}
	
	// 发送一段数据
	int	outsize;
	outsize = send(m_sockClient, m_bufOutput, m_nOutbufLen, 0);
	if(outsize > 0) {
		// 删除已发送的部分
		if(m_nOutbufLen - outsize > 0) {
			memcpy(m_bufOutput, m_bufOutput + outsize, m_nOutbufLen - outsize);
		}

		m_nOutbufLen -= outsize;

		if (m_nOutbufLen < 0) {
			return false;
		}
	} else {
		if (hasError()) {
			Destroy();
			return false;
		}
	}

	return true;
}

bool CGameSocket::Check(void)
{
	// 检查状态
	if (m_sockClient == INVALID_SOCKET) {
		return false;
	}

	char buf[1];
	int	ret = recv(m_sockClient, buf, 1, MSG_PEEK);
	if(ret == 0) {
		Destroy();
		return false;
	} else if(ret < 0) {
		if (hasError()) {
			Destroy();
			return false;
		} else {	// 阻塞
			return true;
		}
	} else {	// 有数据
		return true;
	}
	
	return true;
}

void CGameSocket::Destroy(void)
{
	// 关闭
	struct linger so_linger;
	so_linger.l_onoff = 1;
	so_linger.l_linger = 500;
	int ret = setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger));

    closeSocket();

	m_sockClient = INVALID_SOCKET;
	m_nInbufLen = 0;
	m_nInbufStart = 0;
	m_nOutbufLen = 0;

	memset(m_bufOutput, 0, sizeof(m_bufOutput));
	memset(m_bufInput, 0, sizeof(m_bufInput));
}

// 发送消息
bSucSend = m_pSocket->SendMsg(buf, nLen);

// 接收消息处理(放到游戏主循环中,每帧处理)
if (!m_pSocket) {
		return;
	}

	if (!m_pSocket->Check()) {
		m_pSocket = NULL;
		// 掉线了
		onConnectionAbort();
		return;
	}

	// 发送数据(向服务器发送消息)
	m_pSocket->Flush();

	// 接收数据(取得缓冲区中的所有消息,直到缓冲区为空)
	while (true)
	{
		char buffer[_MAX_MSGSIZE] = { 0 };
		int nSize = sizeof(buffer);
		char* pbufMsg = buffer;
		if(m_pSocket == NULL)
		{
			break;
		}
		if (!m_pSocket->ReceiveMsg(pbufMsg, nSize)) {
			break;
		}
		
		while (true)
		{
			MsgHead* pReceiveMsg = (MsgHead*)(pbufMsg);
			uint16	dwCurMsgSize = pReceiveMsg->usSize;
//			CCLOG("msgsize: %d", dwCurMsgSize);

			if((int)dwCurMsgSize > nSize || dwCurMsgSize <= 0) {	// broken msg
				break;
			}

			CMessageSubject::instance().OnMessage((const char*)pReceiveMsg, pReceiveMsg->usSize);

			pbufMsg	+= dwCurMsgSize;
			nSize	-= dwCurMsgSize;
			if(nSize <= 0) {
				break;
			}
		}
	}

        这样的一个Socket封装,适用于windows mac ios android等平台, Socket处理是异步非阻塞的,所以可以放心的放到主线程处理消息, 最大支持64k的接收消息缓冲(一般一个消息不可能大于3k)。

        这里展示这个,目的并不是说这个封装有多么优异,多么高科技,多么牛x。  恰恰是想表达它的简单。  这个简单的封装完全可以胜任一个mmo客户端的消息底层(注意是客户端,服务器对消息底层的性能要求要远远大于客户端),甚至是魔兽世界这类的大型mmo都可以用这么一个小的封装来做消息底层。

       对于游戏客户端消息底层的要求非常简单,根本不需要boost::asio什么的开源库。

       1、非阻塞模型,这样我才放心把消息处理放到主线程,多线程处理消息其实很浪费。不知道得多大型的mmo才会用到。

       2、消息接收缓存处理,避免大消息被截掉。

       3、没了,剩下的一些特殊处理应该是上层逻辑来考虑的。比如掉线重连等。


    
[3] Andriod4.2 Camera 架构与兑现
    来源: 互联网  发布时间: 2014-02-18
Andriod4.2 Camera 架构与实现

1.Camera架构包括客户端和服务端,他们之间的通信采用Binder机制实现。

Camera的实现主要包括本地代码和Java代码两个层次:

Camera本地框架:

frameworks/native/include/ui

frameworks/native/libs/ui

frameworks/av/camera/

Camera的本地实现包含在上述目录中,这部分内容被编译生成库libui.so和libcamera_client.so。

Camera服务部分:

frameworks/av/services/camera/libcameraservice

这部分编译生成libcameraservice.so。

Camera HAL:

frameworks/av/camera

frameworks/av/services/camera/libcameraservice/CameraHardwareInterface.h

CameraHardwareInterface.h是HAL接口的定义,需要各个系统根据自己的情况实现。

2.AndroidCamera采用C/S架构,client与server两个独立的线程之间使用Binder通信。这里将介绍Camera从设备开机,到进入相机应用是如何完成初始化工作的。

首先既然Camera是利用binder通信,它肯定要将它的service注册到ServiceManager里面,以备后续Client引用,那么这一步是在哪里进行的呢?在frameworks/av/media/mediaserver/main_mediaserver.cpp下有个main函数,可以用来注册媒体服务。在这里,CameraService完成了服务的注册。

intmain(int argc, char** argv)

{

sp<ProcessState>proc(ProcessState::self());

sp<IServiceManager> sm= defaultServiceManager();

ALOGI("ServiceManager:%p", sm.get());

AudioFlinger::instantiate();

MediaPlayerService::instantiate();

CameraService::instantiate();

AudioPolicyService::instantiate();

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}

可是我们到CameraService文件里面却找不到instantiate()这个函数,它在哪?继续追到它的一个父类BinderService

template<typenameSERVICE>

classBinderService

{

public:

static status_t publish(bool allowIsolated =false) {

sp<IServiceManager>sm(defaultServiceManager());

returnsm->addService(String16(SERVICE::getServiceName()), new SERVICE(),allowIsolated);

}


static void publishAndJoinThreadPool(boolallowIsolated = false) {

sp<IServiceManager>sm(defaultServiceManager());

sm->addService(String16(SERVICE::getServiceName()),new SERVICE(), allowIsolated);

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}

staticvoid instantiate(){ publish(); }

static status_t shutdown() {

return NO_ERROR;

}

};


可以发现在publish()函数中,CameraService完成服务的注册。这里面有个SERVICE,源码中有说明

template<typenameSERVICE>

这表示SERVICE是个模板,这里是注册CameraService,所以可以用CameraService代替
sm->addService(String16(SERVICE::getServiceName()),new SERVICE(), allowIsolated);

这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。

Main_MediaServer主函数由init.rc在启动是调用,所以在设备开机的时候Camera就会注册一个服务,用作binder通信。

servicemedia /system/bin/mediaserver

class main

user media

group audio camera inetnet_bt net_bt_admin net_bw_acct drmrpc

ioprio rt 4

Binder服务已注册,那接下来就看看client如何连上server端,并打开camera模块。

咱们先从testingcameraapp的源码入手。在setUpCamera()函数中专门有一个open(mCameraId)函数进入framework层,调用frameworks/base/core/java/android/hardware/Camera.java类的open方法。

publicstatic Camera open(int cameraId) {

return newCamera(cameraId);

}

这里调用了Camera的构造函数,在看看构造函数

Camera(int cameraId) {

mShutterCallback = null;

mRawImageCallback = null;

mJpegCallback = null;

mPreviewCallback = null;

mPostviewCallback = null;

mZoomListener = null;

Looper looper;

if ((looper =Looper.myLooper()) != null) {

mEventHandler = newEventHandler(this, looper);

} else if ((looper =Looper.getMainLooper()) != null) {

mEventHandler = newEventHandler(this, looper);

} else {

mEventHandler = null;

}

native_setup(newWeakReference<Camera>(this), cameraId);

}


好,终于来到JNI了,继续看camera的JNI文件frameworks/base/core/jni/android_hardware_Camera.cpp

// connect to cameraservice

static voidandroid_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,

jobject weak_this,jint cameraId)

{

sp<Camera>camera = Camera::connect(cameraId);



if (camera == NULL) {

jniThrowRuntimeException(env,"Fail to connect to camera service");

return;

}



// make sure camerahardware is alive

if(camera->getStatus() != NO_ERROR) {

jniThrowRuntimeException(env,"Camera initialization failed");

return;

}



jclass clazz =env->GetObjectClass(thiz);

if (clazz == NULL) {

jniThrowRuntimeException(env,"Can't find android/hardware/Camera");

return;

}



// We use a weakreference so the Camera object can be garbage collected.

// The reference isonly used as a proxy for callbacks.

sp<JNICameraContext>context = new JNICameraContext(env, weak_this, clazz, camera);

context->incStrong(thiz);

camera->setListener(context);



// save context inopaque field

env->SetIntField(thiz,fields.context, (int)context.get());

}

JNI函数里面,我们找到CameraC/S架构的客户端了,它调用connect函数向服务器发送连接请求。JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息

看看客户端的connect函数有什么

===>>>frameworks/av/camera/Camera.cpp

sp<Camera>Camera::connect(int cameraId)

{

ALOGV("connect");

sp<Camera> c = new Camera();

const sp<ICameraService>& cs =getCameraService();

if (cs != 0) {

c->mCamera = cs->connect(c,cameraId);

}

if (c->mCamera != 0) {

c->mCamera->asBinder()->linkToDeath(c);

c->mStatus = NO_ERROR;

} else {

c.clear();

}

return c;

}

constsp<ICameraService>& cs =getCameraService();通过getCameraService()函数获取一个Camera服务实例。

// establish binder interface to cameraservice

const sp<ICameraService>&Camera::getCameraService()

{

Mutex::Autolock _l(mLock);

if (mCameraService.get() == 0) {

sp<IServiceManager> sm =defaultServiceManager();

sp<IBinder> binder;

do {

binder =sm->getService(String16("media.camera"));

if (binder != 0)

break;

ALOGW("CameraServicenot published, waiting...");

usleep(500000); // 0.5 s

} while(true);

if (mDeathNotifier == NULL) {

mDeathNotifier = newDeathNotifier();

}

binder->linkToDeath(mDeathNotifier);

mCameraService= interface_cast<ICameraService>(binder);

}

ALOGE_IF(mCameraService==0, "noCameraService!?");

return mCameraService;

}


可以看出,该CameraService实例是通过binder获取的,由binder机制可以知道,该服务就是CameraService一个实例。

c->mCamera= cs->connect(c, cameraId);

然后执行服务端的connect()函数,并返回一个ICamera对象赋值给Camera的mCamera,服务端connect()返回的其实是它内部类client的一个实例。

sp<ICamera>CameraService::connect(

const sp<ICameraClient>&cameraClient, int cameraId) {

int callingPid = getCallingPid();


LOG1("CameraService::connect E(pid %d, id %d)", callingPid, cameraId);


if(!mModule) {

ALOGE("Camera HAL module not loaded");

return NULL;

}


sp<Client> client;

if (cameraId < 0 || cameraId >=mNumberOfCameras) {

ALOGE("CameraService::connectX (pid %d) rejected (invalid cameraId %d).",

callingPid, cameraId);

return NULL;

}


char value[PROPERTY_VALUE_MAX];

property_get("sys.secpolicy.camera.disabled", value, "0");

if (strcmp(value, "1") ==0) {

// Camera is disabled byDevicePolicyManager.

ALOGI("Camera is disabled.connect X (pid %d) rejected", callingPid);

return NULL;

}


Mutex::Autolock lock(mServiceLock);

if (mClient[cameraId] != 0) {

client =mClient[cameraId].promote();

if (client != 0) {

if(cameraClient->asBinder() ==client->getCameraClient()->asBinder()) {

LOG1("CameraService::connect X (pid %d) (the same client)",

callingPid);

return client;

} else {

ALOGW("CameraService::connect X (pid %d) rejected (existingclient).",

callingPid);

return NULL;

}

}

mClient[cameraId].clear();

}

if (mBusy[cameraId]) {

ALOGW("CameraService::connectX (pid %d) rejected"

" (camera %d isstill busy).", callingPid, cameraId);

return NULL;

}

struct camera_info info;

if(mModule->get_camera_info(cameraId, &info) != OK) {

ALOGE("Invalid camera id%d", cameraId);

return NULL;

}


int deviceVersion;

if(mModule->common.module_api_version ==CAMERA_MODULE_API_VERSION_2_0) {

deviceVersion =info.device_version;

} else {

deviceVersion =CAMERA_DEVICE_API_VERSION_1_0;

}


switch(deviceVersion) {

caseCAMERA_DEVICE_API_VERSION_1_0:

client = new CameraClient(this,cameraClient, cameraId,

info.facing,callingPid, getpid());

break;

caseCAMERA_DEVICE_API_VERSION_2_0:

client = newCamera2Client(this, cameraClient, cameraId,

info.facing,callingPid, getpid());

break;

default:

ALOGE("Unknown cameradevice HAL version: %d", deviceVersion);

return NULL;

}


if(client->initialize(mModule) != OK) {

return NULL;

}


cameraClient->asBinder()->linkToDeath(this);


mClient[cameraId] = client;

LOG1("CameraService::connect X(id %d, this pid is %d)", cameraId, getpid());

return client;

}


在函数client->initialize(mModule)中实例化CameraHal接口hardware,hardware调用initialize()进入HAL层打开Camear驱动

status_tCameraClient::initialize(camera_module_t *module) {

int callingPid = getCallingPid();

LOG1("CameraClient::initialize E (pid %d, id %d)",callingPid, mCameraId);


char camera_device_name[10];

status_t res;

snprintf(camera_device_name, sizeof(camera_device_name), "%d",mCameraId);


mHardware= new CameraHardwareInterface(camera_device_name);

res =mHardware->initialize(&module->common);

if (res != OK) {

ALOGE("%s: Camera %d: unable to initialize device: %s(%d)",

__FUNCTION__, mCameraId, strerror(-res), res);

mHardware.clear();

return NO_INIT;

}


mHardware->setCallbacks(notifyCallback,

dataCallback,

dataCallbackTimestamp,

(void *)mCameraId);


// Enable zoom, error, focus, and metadata messages by default

enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM |CAMERA_MSG_FOCUS |

CAMERA_MSG_PREVIEW_METADATA |CAMERA_MSG_FOCUS_MOVE);


LOG1("CameraClient::initialize X (pid %d, id %d)",callingPid, mCameraId);

return OK;

}


hardware调用initialize()进入HAL层打开Camear驱动

status_t initialize(hw_module_t *module)

{

ALOGI("Opening camera %s", mName.string());

int rc = module->methods->open(module, mName.string(),

(hw_device_t**)&mDevice); //这一句作用就是打开Camera底层驱动

if (rc != OK) {

ALOGE("Could not open camera %s: %d",mName.string(), rc);

return rc;

}

initHalPreviewWindow();

return rc;

}


hardware->initialize(&mModule->common)中mModule模块是一个结构体camera_module_t,他是怎么初始化的呢?我们发现CameraService里面有个函数

voidCameraService::onFirstRef()

{

BnCameraService::onFirstRef();


if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,

(const hw_module_t **)&mModule) < 0) {

ALOGE("Could not load camera HAL module");

mNumberOfCameras = 0;

}

else {

mNumberOfCameras = mModule->get_number_of_cameras();

if (mNumberOfCameras > MAX_CAMERAS) {

ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",

mNumberOfCameras, MAX_CAMERAS);

mNumberOfCameras = MAX_CAMERAS;

}

for (int i = 0; i < mNumberOfCameras; i++) {

setCameraFree(i);

}

}

}


CameraService调用

hw_get_module(CAMERA_HARDWARE_MODULE_ID,(const hw_module_t **)&mModule)

来装载fakecamera HAL module:camera.duck.so

inthw_get_module(const char *id, const struct hw_module_t **module)

{

returnhw_get_module_by_class(id, NULL, module);

}

inthw_get_module_by_class(const char *class_id, const char *inst,

const struct hw_module_t **module)

{

int status;

int i;

const structhw_module_t *hmi = NULL;

charprop[PATH_MAX];

charpath[PATH_MAX];

charname[PATH_MAX];

if (inst)

snprintf(name, PATH_MAX, "%s.%s", class_id, inst);

else

strlcpy(name, class_id, PATH_MAX);


/*

* Here werely on the fact that calling dlopen multiple times on

* the same.so will simply increment a refcount (and not load

* a new copyof the library).

* We alsoassume that dlopen() is thread-safe.

*/

/* Loopthrough the configuration variants looking for a module */

for (i=0 ;i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {

if (i <HAL_VARIANT_KEYS_COUNT) {

if(property_get(variant_keys[i], prop, NULL) == 0) {

continue;

}

snprintf(path, sizeof(path), "%s/%s.%s.so",

HAL_LIBRARY_PATH2, name, prop);

if(access(path, R_OK) == 0) break;

snprintf(path, sizeof(path), "%s/%s.%s.so",

HAL_LIBRARY_PATH1, name, prop);

if(access(path, R_OK) == 0) break;

} else {

snprintf(path, sizeof(path), "%s/%s.default.so",

HAL_LIBRARY_PATH1, name);

if(access(path, R_OK) == 0) break;

}

}


camera.duck.somodule 的代码在development/tools/emulator/system/camera/

====>development/tools/emulator/system/camera/Android.mk

LOCAL_SRC_FILES :=\

EmulatedCameraHal.cpp \

EmulatedCameraFactory.cpp \

EmulatedBaseCamera.cpp \

EmulatedCamera.cpp \

EmulatedCameraDevice.cpp \

EmulatedQemuCamera.cpp \

EmulatedQemuCameraDevice.cpp \

EmulatedFakeCamera.cpp \

EmulatedFakeCameraDevice.cpp \

Converters.cpp \

PreviewWindow.cpp \

CallbackNotifier.cpp \

QemuClient.cpp \

JpegCompressor.cpp \

EmulatedCamera2.cpp \

EmulatedFakeCamera2.cpp \

EmulatedQemuCamera2.cpp \

fake-pipeline2/Scene.cpp \

fake-pipeline2/Sensor.cpp \

fake-pipeline2/JpegCompressor.cpp



ifeq($(TARGET_PRODUCT),vbox_x86)

LOCAL_MODULE :=camera.vbox_x86

else

LOCAL_MODULE :=camera.duck

endif


了解HAL层的都知道hw_get_module函数就是用来获取模块的Halstub,这里是通过CAMERA_HARDWARE_MODULE_ID获取CameraHal层的代理stub,并赋值给mModule,后面就可通过操作mModule完成对Camera模块的控制。那么onFirstRef()函数又是何时调用的?

onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数时调用,什么意思?就是当有sp包装的类初始化的时候调用,那么camera是何时调用的呢?可以发现在

客户端发起连接时候

sp<Camera>Camera::connect(int cameraId)
{
LOGV("connect");
sp<Camera> c = new Camera();
constsp<ICameraService>& cs = getCameraService();

}

这个时候初始化了一个CameraService实例,且用Sp包装,这个时候sp将新增计数,相应的CameraService实例里面onFirstRef()函数完成调用。
CameraService::connect()返回client的时候,就表明客户端和服务端连接建立。Camera完成初始化,可以进行拍照和preview等动作。




    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3