后来看到了此博客http://blog.csdn.net/ghostyu/article/details/7921179
也是通过c结构体相互引用来实现的。
标题不好取,所以再啰嗦补充下,等以后想到好的表述了再更改。
在dvr项目中,不同的chip初始化和设置也是不同的,例如gm8187/gm8210等。这些初始化都是以以库的形式出现的,所以用c来实现。之前没有融入"对象"的概念之前,
一般的实现就是if/else或者switch/case来兼容不同的产品,每次有新的设置都会在有差异的地方修改代码。
一、c的"对象"
大概形态,要包含函数指针
{
int a;
void (*pfunc)(void);
}
二、实际实现
就是参考的ffmpeg里的enc/dec 注册来实现的。
待续
接上,给出精彩的代码。
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <fcntl.h>
#if 1 //来自ffmpeg,祛除了些变量
typedef int offset_t;
#ifdef ENOENT
#undef ENOENT
#endif
#define ENOENT 2
#ifdef ENOMEM
#undef ENOMEM
#endif
#define ENOMEM 12
#define URL_RDONLY 0
#define URL_WRONLY 1
#define URL_RDWR 2
#define INT_MAX 2147483647
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
void *av_malloc(unsigned int size)
{
void *ptr;
if (size > INT_MAX)
return NULL;
ptr = malloc(size);
return ptr;
}
void *av_realloc(void *ptr, unsigned int size)
{
if (size > INT_MAX)
return NULL;
return realloc(ptr, size);
}
void av_free(void *ptr)
{
if (ptr)
free(ptr);
}
//具体和抽象通过指针互相引用来建立联系
//对客户/调用角度来看,只关心抽象(URLProtocol)即可
//具体的实现都可以封装为.a,详情看本demo代码
//抽象
typedef struct URLContext
{
struct URLProtocol *prot;
int flags;
int max_packet_size; // if non zero, the stream is packetized with this max packet size
void *priv_data;
char filename[1]; // specified filename
} URLContext;
//具体
typedef struct URLProtocol
{
const char *name;
int(*url_open)(URLContext *h, const char *filename, int flags);
int(*url_read)(URLContext *h, unsigned char *buf, int size);
int(*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t(*url_seek)(URLContext *h, offset_t pos, int whence);
int(*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;
#endif
///
//以下以应用代码来演示,为了方便,就放在一个.c中了
//抽象
typedef struct DVRContext
{
struct DVRProduct *prot;
int flags;
int max_packet_size; // if non zero, the stream is packetized with this max packet size
void *priv_data;
int type;
char dvrname[1]; // specified filename
} DVRContext;
//具体
typedef struct DVRProduct
{
const char *name;
int(*dvr_open)(DVRContext *h, const char *filename, int flags);
int(*dvr_read)(DVRContext *h, unsigned char *buf, int size);
int(*dvr_write)(DVRContext *h, unsigned char *buf, int size);
int(*dvr_close)(DVRContext *h);
struct DVRProduct *next;
} DVRProduct;
//带gm8210的单独放在gm8210.c中,其他gmxx仿写gm8210即可
//gm8210_open/gm8210_read等沿用了ffmpeg里的URLProtocol,仅demo
static int gm8210_open(DVRContext *h, const char *filename, int flags)
{
printf("gm8210_open,%s jiu zheyang bei ni open\n",h->dvrname);
int access;
int fd;
access = O_CREAT | O_TRUNC | O_RDWR;
fd = open(filename, access, 0666);
if (fd < 0)
{
return - ENOENT;
}
//可以看出,priv_data就是具体对象的私有数据,此处为fd
//不同的具体对象可以用不同的私有数据,依赖自己的应用
h->priv_data = (void*)(size_t)fd;
return 0;
}
static int gm8210_read(DVRContext *h, unsigned char *buf, int size)
{
int fd = (size_t)h->priv_data;
return read(fd, buf, size);
}
static int gm8210_write(DVRContext *h, unsigned char *buf, int size)
{
int fd = (size_t)h->priv_data;
return write(fd, buf, size);
}
static int gm8210_close(DVRContext *h)
{
printf("gm8210_close,%s jiu zheyang bei ni close\n",h->dvrname);
int fd = (size_t)h->priv_data;
return close(fd);
}
DVRProduct gm8210_dvr =
{
"gm8210",
gm8210_open,
gm8210_read,
gm8210_write,
gm8210_close,
};
//8287
static int gm8287_open(DVRContext *h, const char *filename, int flags)
{
printf("gm8287_open,%s jiu zheyang bei ni open\n",h->dvrname);
int access;
int fd;
access = O_CREAT | O_TRUNC | O_RDWR;
fd = open(filename, access, 0666);
if (fd < 0)
{
return - ENOENT;
}
h->priv_data = (void*)(size_t)fd;
return 0;
}
static int gm8287_close(DVRContext *h)
{
printf("gm8287_close,%s jiu zheyang bei ni close\n",h->dvrname);
int fd = (size_t)h->priv_data;
return close(fd);
}
DVRProduct gm8287_dvr =
{
"gm8287",
gm8287_open,
NULL,
NULL,
gm8287_close,
};
DVRProduct *first_dvr = NULL;
//也可以不创建链表,直接first_dvr = gmxx_dvr
int register_product(DVRProduct *pdvr)
{
DVRProduct **pp;
pp = &first_dvr;
while (*pp != NULL)
{
pp = &(*pp)->next;
}
*pp = pdvr;
pdvr->next = NULL;
return 0;
}
int gmdvr_open(DVRContext **puc, const char *filename, int flags)
{
DVRContext *uc;
DVRProduct *up;
const char *p;
int err;
p = filename;
up = first_dvr;
while (up != NULL)
{
if (!strcmp(p, up->name))
{
goto found; //找到对应的
}
up = up->next;
}
err = -ENOENT;
goto fail;
found:
uc = av_malloc(sizeof(DVRContext) + strlen(filename));
if (!uc)
{
err = - ENOMEM;
goto fail;
}
//抽象/具体关联
strcpy(uc->dvrname, filename);
uc->prot = up;
uc->flags = flags;
uc->max_packet_size = 0; // default: stream file
err = up->dvr_open(uc, filename, flags); //具体的gmxx_dvr.dvr_open
if (err < 0)
{
av_free(uc);
*puc = NULL;
return err;
}
*puc = uc; //带出已确定的上下文(抽象)
return 0;
fail:
*puc = NULL;
return err;
}
DVRContext *g_dvrctx = NULL;
int gmdvr_getctx(const char *filename)
{
if(!g_dvrctx)
{
return -1;
}
const char *p;
p = filename;
if (!strcmp(p, g_dvrctx->dvrname))
{
printf("gmdvr_getctx,for %s\n",g_dvrctx->dvrname);
return 0;
}
else
{
return -2;
}
return 0;
}
int gmdvr_init(const char *filename)
{
int err;
err = gmdvr_open(&g_dvrctx, filename, URL_RDWR);
if (err < 0)
{
return err;
}
return 0;
}
int gmdvr_uninit(const char *filename)
{
int err;
err = gmdvr_getctx(filename);
if (err < 0)
{
return err;
}
g_dvrctx->prot->dvr_close(g_dvrctx);
return 0;
}
int main(int argc, char* argv[])
{
//可以全部注册好
register_product(&gm8210_dvr);
register_product(&gm8287_dvr);
//char* name/int id来自上层app,或者register && init都可以暴露给上层app
gmdvr_init("gm8210");
gmdvr_uninit("gm8210");
printf("\n#########\n");
gmdvr_init("gm8287");
gmdvr_uninit("gm8287");
return 0;
}
#ifdef __cplusplus
extern "C"
}
#endif
重新思考了下,感觉应该是这样的
DVRContext //抽象
DVRProduct //具体