在linux下所有设备都是文件。所以对摄像头的操作其实就是对文件的操作。USB摄像头的设备文件就是在/dev目录下的video0(假如只有一个摄像头)。在linux下操作摄像头就是使用v4l2对摄像头进行的操作,操作步骤如下
打开设备文件。
int fd=open(”/dev/video0″,O_RDWR);
2. 取得设备的capability,看看设备具有什么功能,比如是否具有输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
v4l2_std_id std;
do {
ret= ioctl(fd, VIDIOC_QUERYSTD, std);
} while (ret == -1 errno == EAGAIN);
switch (std) {
case V4L2_STD_NTSC:
//……
case V4L2_STD_PAL:
//……
}
3. 选择输入,一个设备可以有多个输入。VIDIOC_S_INPUT,struct v4l2_input(可不要)
4. 设置的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
struct v4l2_format fmt;
memset ( fmt, 0, sizeof(fmt) );
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 320;
fmt.fmt.pix.height = 240;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
if (ioctl(fd, VIDIOC_S_FMT, fmt) < 0)
{
printf("set format failed ");
//return 0;
}
5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
struct v4l2_requestbuffers req;
memset(req, 0, sizeof (req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd,VIDIOC_REQBUFS,req) == -1)
{
perror("VIDIOC_REQBUFS error ");
//return -1;
}
6.申请物理内存
将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
VideoBuffer* buffers = calloc( req.count, sizeof(VideoBuffer) );
printf("sizeof(VideoBuffer) is %d ",sizeof(VideoBuffer));
struct v4l2_buffer buf;
for (numBufs = 0; numBufs < req.count; numBufs++)
{
memset( buf, 0, sizeof(buf) );
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = numBufs;
if (ioctl(fd, VIDIOC_QUERYBUF, buf) < 0)
{
printf("VIDIOC_QUERYBUF error ");
//return -1;
}
printf("buf len is %d ",sizeof(buf));
//内存映射
buffers[numBufs].length = buf.length;
buffers[numBufs].offset = (size_t) buf.m.offset;
buffers[numBufs].start = mmap (NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
printf("buffers.length = %d,buffers.offset = %d ,buffers.start[0] = %d ",buffers[numBufs].length,buffers[numBufs].offset,buffers[numBufs].start[0]);
printf("buf2 len is %d ",sizeof(buffers[numBufs].start));
if (buffers[numBufs].start == MAP_FAILED)
{
perror("buffers error ");
//return -1;
}
if (ioctl (fd, VIDIOC_QBUF, buf) < 0)
{
printf("VIDIOC_QBUF error ");
//return -1;
}
}
7. 开始的采集。
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (fd, VIDIOC_STREAMON, type) < 0)
{
printf("VIDIOC_STREAMON error ");
// return -1;
}
8. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF, 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
if (ioctl(fd, VIDIOC_DQBUF, buf) < 0)
{
perror("VIDIOC_DQBUF failed. ");
//return -1;
}
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
unsigned char *ptcur = buffers[numBufs].start;
DEBUG("buf.bytesused = %d ",buf.bytesused);
int i1;
for(i1=0; i1<buf.bytesused; i1++)
{
if((buffers[numBufs].start[i1] == 0xFF) (buffers[numBufs].start[i1+1] == 0xC4))
{
DEBUG("huffman table finded! buf.bytesused = %d FFC4 = %d ",buf.bytesused,i1);
break;
}
}
if(i1 == buf.bytesused)printf("huffman table don't exist! ");
int i;
for(i=0; i<buf.bytesused; i++)
{
if((buffers[numBufs].start[i] == 0xFF) (buffers[numBufs].start[i+1] == 0xD8)) break;
ptcur++;
}
DEBUG("i=%d,FF=%02x,D8=%02x ",i,buffers[numBufs].start[i],buffers[numBufs].start[i+1]);
int imagesize =buf.bytesused - i;
DEBUG("buf.bytesused = %d ",buf.bytesused);
DEBUG ("imagesize = %d ",imagesize);
9. 停止的采集。VIDIOC_STREAMOFF
10. 关闭设备。close(fd);
❷ Linux v4l2图片采集问题
源码中:
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ioctl (fd, VIDIOC_S_FMT, &fmt);
指定了采集图像的格式为YUYV格式。
要像采集成JPEG图像,得查询一下摄像头是否有相应功能,如果没有相应功能即使将fmt设置为jpeg最终采集到的还是yuyv格式。
yuyv可以转换为bmp数据,然后调用jpeglib库转换为jpg图像,稍稍有些麻烦,但没办法硬件不足就要用软件来弥补了。
至于你说的read没读到数据,我现在没有开发环境,没法测试。
❸ fmt(2)是什么意思
Slice重传。
fmt(2)是Slice重传的意思。
fmt是一种Linux命令,用来编排文本文件,也是指用可编程、多功能的数字控制设备更换刚性自动化设备,用易编程、易修改、易扩展、易更换的软件控制代替刚性联结的工序过程,使刚性生产线实现软性化和柔性化,能够快速响应市场的需求,多快好省地完成多品种、中小批量地生产任务。
fmt命令用于编排文本文件,其会从指定的文件里读取内容,将其依照指定格式重新编排后,输出到标准输出设备。
❹ Linux中与安全审计有关的函数
我的答案是最正确的 请采纳我的内核审计系统的接口函数在Linux内核需要输出审计信息时,它先调用函数audit_log_start创建缓冲区。接着,调用函数audit_log或audit_log_format写缓冲区写入审计信息,最后调用函数audit_log_end发送审计信息,并释放缓冲区。这三个函数分别说明如下:1.函数audit_log_start 函数audit_log_start申请审计缓冲区,如果任务当前在系统调用中,系统调用被标识为可审计的,并在系统调用退出时,产生一条审计记录。函数audit_log_start的参数ctx为审计上下文结构实例;参数gfp_mask为分配内存的类型,如:__GFP_WAIT表示可以等待和重调度;参数type为审计消息类型。如果缓存区申请成功,它返回审计缓冲区的指针,否则返回NULL表示错误。函数audit_log_start申请审计缓冲区,当审计缓冲区链表的缓冲区个数超过上限时,当前进程需要等待用户空间的后台进程将审计消息写入log文件,直到缓冲区个数小于上限值为止。函数audit_log_start在申请并初始化审计缓冲区后,给缓冲区加时间戳和审计记录序列号。函数audit_log_start列出如下(在linux26/kernel/audit.c中)://声明等待队列头,用于等待审计消息被后台进程写入log文件static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,int type){struct audit_buffer*ab= NULL;struct timespect;unsigned intserial;int reserve;unsigned long timeout_start = jiffies; //开始的时间if (!audit_initialized)//如果已初始化,就直接退出return NULL;if (unlikely(audit_filter_type(type)))return NULL;if (gfp_mask & __GFP_WAIT)reserve = 0;elsereserve = 5; /*允许调用者多出5个条目*/ //当链表中审计缓冲区数超出上限时,进程等待auditd处理链表中缓冲区while (audit_backlog_limit&& skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) {if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time && time_before(jiffies, timeout_start + audit_backlog_wait_time)) {/* 等待后台进程auditd从队列中处理部分缓冲区 */DECLARE_WAITQUEUE(wait, current);set_current_state(TASK_INTERRUPTIBLE); //设置当前进程的状态为可中断等待状态add_wait_queue(&audit_backlog_wait, &wait); //将当前进程加入等待队列if (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit)schele_timeout(timeout_start + audit_backlog_wait_time - jiffies);//调度__set_current_state(TASK_RUNNING);//设置当前进程为运行状态remove_wait_queue(&audit_backlog_wait, &wait);continue;} //检查每秒发送的记录数不能超过上限,以防止受非法攻击if (audit_rate_check())printk(KERN_WARNING "audit: audit_backlog=%d > " "audit_backlog_limit=%d\n", skb_queue_len(&audit_skb_queue), audit_backlog_limit);audit_log_lost("backlog limit exceeded");audit_backlog_wait_time = audit_backlog_wait_overflow;wake_up(&audit_backlog_wait);return NULL;}ab = audit_buffer_alloc(ctx, gfp_mask, type);//申请审计缓冲区if (!ab) {audit_log_lost("out of memory in audit_log_start");return NULL;}//得到当前时间存入t,计算审计记录的序列号,存入serialaudit_get_stamp(ab->ctx, &t, &serial); //将时间戳和序列号写入审计记录audit_log_format(ab, "audit(%lu.%03lu:%u): ", t.tv_sec, t.tv_nsec/1000000, serial);return ab;}函数audit_buffer_alloc申请审计缓冲区,先尝试从空闲链表上取下一个缓冲区,如果空闲链表中没有,就分配一个缓冲区。然后,填充netlink消息头。该函数列出如下: static DEFINE_SPINLOCK(audit_freelist_lock);//定义自旋锁,用于锁住链表audit_freeliststatic struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,gfp_t gfp_mask, int type){unsigned long flags;struct audit_buffer *ab = NULL;struct nlmsghdr *nlh; //从空闲链表中得到一个缓冲区spin_lock_irqsave(&audit_freelist_lock, flags);//加锁if (!list_empty(&audit_freelist)) {ab = list_entry(audit_freelist.next,struct audit_buffer, list);list_del(&ab->list);--audit_freelist_count;}spin_unlock_irqrestore(&audit_freelist_lock, flags);//释放锁 //如果空闲链表中没有空闲缓冲区成员,就分配一个缓冲区if (!ab) {ab = kmalloc(sizeof(*ab), gfp_mask);if (!ab)goto err;}ab->skb = alloc_skb(AUDIT_BUFSIZ, gfp_mask);//分配套接字缓冲区if (!ab->skb)goto err;ab->ctx = ctx;ab->gfp_mask = gfp_mask; //扩展套接字缓冲区skb的已使用数据区,将netlink消息头数据nlmsghdr加到skbnlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));nlh->nlmsg_type = type;nlh->nlmsg_flags = 0;nlh->nlmsg_pid = 0;nlh->nlmsg_seq = 0;return ab;err:audit_buffer_free(ab);return NULL;}2.函数audit_log_format函数audit_log_format将一个审计消息按格式写入审计缓冲区,参数ab为审计缓冲区,参数fmt为格式化的字符串。其列出如下:void audit_log_format(struct audit_buffer *ab, const char *fmt, ...){va_list args;if (!ab)return;va_start(args, fmt);audit_log_vformat(ab, fmt, args);va_end(args);}函数audit_log_vformat将一个审计消息按格式写入套接字缓冲区中,如果审计缓冲区没有足够的空间,就扩展套接字缓冲区的数据域。由于printk缓冲区为1024,扩展的套接字缓冲区最小应为1024。函数audit_log_vformat列出如下: static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args){int len, avail;struct sk_buff *skb;va_list args2;if (!ab)return;BUG_ON(!ab->skb);skb = ab->skb;avail = skb_tailroom(skb);//计算套接字缓冲区的空闲数据空间if (avail == 0) {//如果套接字缓冲区没有空闲数据空间,扩展空间avail = audit_expand(ab, AUDIT_BUFSIZ);// AUDIT_BUFSIZ为1024,if (!avail)goto out;}va_(args2, args);len = vsnprintf(skb->tail, avail, fmt, args);//将信息写入到缓冲区if (len >= avail) {//如果实际信息长度比可用的缓冲区大,扩展空间/* 由于printk缓冲区是1024,因此,扩展空间最少为1024 */avail = audit_expand(ab,max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));if (!avail)goto out;len = vsnprintf(skb->tail, avail, fmt, args2); //将审计信息写入到缓冲区}if (len > 0)skb_put(skb, len); //将写入信息的数据缓冲区附加到skb上out:return;}
函数audit_expand扩展在审计缓冲区中的套接字缓冲区,扩展成功,返回可用的空间大小,扩展失败返回0,表示没有空间。参数ab表示审计缓冲区的指针,参数extra表示加到套接字缓冲区skb尾部的缓冲区空间大小。函数audit_expand列出如下:static inline int audit_expand(struct audit_buffer *ab, int extra){struct sk_buff *skb = ab->skb;int ret = pskb_expand_head(skb, skb_headroom(skb), extra, ab->gfp_mask);if (ret < 0) {audit_log_lost("out of memory in audit_expand");return 0;}return skb_tailroom(skb);//返回可用的缓冲区空间大小}3.函数audit_log_end当进程完成了将审计记录写入审计缓冲区的操作时,它调用函数audit_log_end将套接字缓冲区中的审计记录数据发送给用户空间后台进程,由后台进程写入到log文件。如果审计后台进程存在,使用netlink机制传输数据,由审计后台将套接字缓冲区中的审计记录数据写入审计文件audit.log中;如果审计后台不存在,使用函数printk记录数据,然后由日志后台进程将数据写入到日志文件中。当数据发送完成后,函数audit_log_end唤醒等待队列kauditd_wait。有些进程因为审计套接字缓冲区链表上的缓冲区数量超过上限而在队列kauditd_wait等待,当其他进程发送了数据时,应唤醒这些等待进程。函数audit_log_end列出如下:void audit_log_end(struct audit_buffer *ab){if (!ab)return;if (!audit_rate_check()) {//检查审计系统的传输速度,如果netlink机制传输速度超过上限,则返回错误audit_log_lost("rate limit exceeded");} else {if (audit_pid) {//如果审计后台的进程ID存在,使用netlink机制传输数据struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);skb_queue_tail(&audit_skb_queue, ab->skb);ab->skb = NULL;wake_up_interruptible(&kauditd_wait);//发送了数据,唤醒等待队列} else {//使用printk记录数据printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));}}audit_buffer_free(ab);}
❺ Linux下常用文本处理命令
Linux下常用文本处理命令大全
Linux下面有很多经典的非常有用的命令,其中处理文本的命令就有很多。下面就让我们一起看看这些经典的Linux文本处理命令有哪些吧。
一. sort
文件排序, 通常用在管道中当过滤器来使用. 这个命令可以依据指定的关键字或指定的字符位置, 对文件行进行排序. 使用-m选项, 它将会合并预排序的输入文件. 想了解这个命令的全部参数请参考这个命令的info页.
二. tsort
拓扑排序, 读取以空格分隔的有序对, 并且依靠输入模式进行排序.
三. uniq
这个过滤器将会删除一个已排序文件中的重复行. 这个命令经常出现在sort命令的管道后边.
四. expand, unexpand
expand命令将会把每个tab转化为一个空格. 这个命令经常用在管道中.
unexpand命令将会把每个空格转化为一个tab. 效果与expand命令相反.
五. cut
一个从文件中提取特定域的工具. 这个命令与awk中使用的print $N命令很相似, 但是更受限. 在脚本中使用cut命令会比使用awk命令来得容易一些. 最重要的选项就是-d(字段定界符)和-f(域分隔符)选项.
六. paste
将多个文件, 以每个文件一列的形式合并到一个文件中, 合并后文件中的每一列就是原来的一个文件. 与cut结合使用, 经常用于创建系统log文件.
七. join
这个命令与paste命令属于同类命令. 但是它能够完成某些特殊的目地. 这个强力工具能够以一种特殊的形式来合并两个文件, 这种特殊的形式本质上就是一个关联数据库的简单版本.
join命令只能够操作两个文件. 它可以将那些具有特定标记域(通常是一个数字标签)的行合并起来, 并且将结果输出到stdout. 被加入的文件应该事先根据标记域进行排序以便于能够正确的匹配.
八. head
把文件的头部内容打印到stdout上(默认为10行, 可以自己修改). 这个命令有一些比较有趣的选项.
九. tail
将一个文件结尾部分的内容输出到stdout中(默认为10行). 通常用来跟踪一个系统logfile的.修改情况, 如果使用-f选项的话, 这个命令将会继续显示添加到文件中的行.
十. wc
wc可以统计文件或I/O流中的”单词数量”:
十一. fold
将输入按照指定宽度进行折行. 这里有一个非常有用的选项-s, 这个选项可以使用空格进行断行(译者: 事实上只有外文才需要使用空格断行, 中文是不需要的)(请参考例子 12-23和例子 A-1).
十二. fmt
一个简单的文件格式器, 通常用在管道中, 将一个比较长的文本行输出进行”折行”.
十三. col
这个命令用来滤除标准输入的反向换行符号. 这个工具还可以将空白用等价的tab来替换. col工具最主要的应用还是从特定的文本处理工具中过滤输出, 比如groff和tbl. (译者: 主要用来将man页转化为文本.)
十四. column
列格式化工具. 通过在合适的位置插入tab, 这个过滤工具会将列类型的文本转化为”易于打印”的表格式进行输出.
十五. colrm
列删除过滤器. 这个工具将会从文件中删除指定的列(列中的字符串)并且写到文件中, 如果指定的列不存在, 那么就回到stdout. colrm 2 4 <filename将会删除filename文件中每行的第2到第4列之间的所有字符. p=""> </filename将会删除filename文件中每行的第2到第4列之间的所有字符.>
Caution: 如果这个文件包含tab和不可打印字符, 那将会引起不可预期的行为. 在这种情况下, 应该通过管道的手段使用expand和unexpand来预处理colrm.
十六. nl
计算行号过滤器. nl filename将会把filename文件的所有内容都输出到stdout上, 但是会在每个非空行的前面加上连续的行号. 如果没有filename参数, 那么就操作stdin.
nl命令的输出与cat -n非常相似, 然而, 默认情况下nl不会列出空行.
十七. pr
格式化打印过滤器. 这个命令会将文件(或stdout)分页, 将它们分成合适的小块以便于硬拷贝打印或者在屏幕上浏览. 使用这个命令的不同的参数可以完成好多任务, 比如对行和列的操作, 加入行, 设置页边, 计算行号, 添加页眉, 合并文件等等. pr命令集合了许多命令的功能, 比如nl, paste, fold, column, 和expand.
pr -o 5 –width=65 fileZZZ | more 这个命令对fileZZZ进行了比较好的分页, 并且打印到屏幕上. 文件的缩进被设置为5, 总宽度设置为65.
一个非常有用的选项-d, 强制隔行打印(与sed -G效果相同).
十八. gettext
GNU gettext包是专门用来将程序的输出翻译或者本地化为不同国家语言的工具集. 在最开始的时候仅仅支持C语言, 现在已经支持了相当数量的其它程序语言和脚本语言.
想要查看gettext程序如何在shell脚本中使用. 请参考info页.
十九. msgfmt
一个产生二进制消息目录的程序. 这个命令主要用来本地化.
二十. iconv
一个可以将文件转化为不同编码格式(字符集)的工具. 这个命令主要用来本地化.
二十一. recode
可以认为这个命令是上边iconv命令的专业版本. 这个非常灵活的并可以把整个文件都转换为不同编码格式的工具并不是Linux标准安装的一部分.
二十二. TeX, gs
TeX和Postscript都是文本标记语言, 用来对打印和格式化的视频显示进行预拷贝.
TeX是Donald Knuth精心制作的排版系统. 通常情况下, 通过编写脚本的手段来把所有的选项和参数封装起来一起传到标记语言中是一件很方便的事情.