三、V4L2的demo

capture.c是官方示例程序。

capture.c 程序中的 process_image 函数:

capture.c 程序主要是用来演示怎样使用 v4l2 接口,并没有对采集到的视频帧数据做任何实际的处理,仅仅用 process_image 函数表示了处理图像的代码位置。

process_image 函数只有一个参数,就是存储视频帧的内存的地址指针,但是在真正的应用中,通常还需要知道该指针指向的数据的大小。

因此可以修改函数,改成 void process_image ( const void * p, int len ) ,但是每次调用 process_image 的时候,第 2 个参数该传递什么值?

考虑到程序中对 buffer 的定义

struct buffer {

void * start;

size_t length};

如果将 buffer.length 作为第 2 个参数传递到修改后的 process_image 函数中,这样做是不正确的。 process_image 需要的第二个参数应该是每帧图像的大小,仔细阅读代码后会发现, buffer.length 并不一定就等于图像帧的大小。 (buffer 的大小,还需要考虑其他的一些因素,比如内存对齐等 )。

capture.c只是一个示例程序,仅仅是演示怎样使用v4l2中最基本的接口。尤其是在main函数中的那几个函数调用,表明了在使用v4l2时的最基本的一个流程,包括 open_device,init_device,start_capturing,mainloop,stop_capturing,uninit_device,close_device。在写程序的时候,可以充分的利用这几个基本模块,把他们分散在不同的代码位置上,灵活的调用,有兴趣的可以看一下gstreamer中v4l2src的源代码或者其他的大型程序的相关部分。

总之一句话,capture.c仅仅是一个演示程序,不要局限于它的代码结构,要灵活的使用。

下面是capture.c的源代码:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <getopt.h>             /* getopt_long() */

#include <fcntl.h>              /* low-level i/o */

#include <unistd.h>

#include <errno.h>

#include <malloc.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/time.h>

#include <sys/mman.h>

#include <sys/ioctl.h>

#include <asm/types.h>          /* for videodev2.h */

#include <linux/videodev2.h>

#define CLEAR(x) memset (&(x), 0, sizeof (x))

typedef enum {

IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR,

} io_method;

struct buffer {

void * start;

size_t length;//buffer's length is different from cap_image_size

};

static char * dev_name = NULL;

static io_method io = IO_METHOD_MMAP;//IO_METHOD_READ;//IO_METHOD_MMAP;

static int fd = -1;

struct buffer * buffers = NULL;

static unsigned int n_buffers = 0;

static FILE * outf = 0;

static unsigned int cap_image_size = 0;//to keep the real image size!!

//////////////////////////////////////////

static void errno_exit(const char * s) {

fprintf(stderr, "%s error %d, %s/n", s, errno, strerror(errno));

exit(EXIT_FAILURE);

}

static int xioctl(int fd, int request, void * arg) {

int r;

do

r = ioctl(fd, request, arg);

while (-1 == r && EINTR == errno);

return r;

}

static void process_image(const void * p, int len) {

//  static char[115200] Outbuff ;

fputc('.', stdout);

if (len > 0) {

fputc('.', stdout);

fwrite(p, 1, len, outf);

}

fflush(stdout);

}

static int read_frame(void) {

struct v4l2_buffer buf;

unsigned int i;

switch (io) {

case IO_METHOD_READ:

if (-1 == read(fd, buffers[0].start, buffers[0].length)) {

switch (errno) {

case EAGAIN:

return 0;

case EIO:

/* Could ignore EIO, see spec. */

/* fall through */

default:

errno_exit("read");

}

}

//      printf("length = %d/r", buffers[0].length);

//      process_image(buffers[0].start, buffers[0].length);

printf("image_size = %d,/t IO_METHOD_READ buffer.length=%d/r",

cap_image_size, buffers[0].length);

process_image(buffers[0].start, cap_image_size);

break;

case IO_METHOD_MMAP:

CLEAR (buf);

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {

switch (errno) {

case EAGAIN:

return 0;

case EIO:

/* Could ignore EIO, see spec. */

/* fall through */

default:

errno_exit("VIDIOC_DQBUF");

}

}

assert(buf.index < n_buffers);

//      printf("length = %d/r", buffers[buf.index].length);

//      process_image(buffers[buf.index].start, buffers[buf.index].length);

printf("image_size = %d,/t IO_METHOD_MMAP buffer.length=%d/r",

cap_image_size, buffers[0].length);

process_image(buffers[0].start, cap_image_size);

if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))

errno_exit("VIDIOC_QBUF");

break;

case IO_METHOD_USERPTR:

CLEAR (buf);

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_USERPTR;

if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {

switch (errno) {

case EAGAIN:

return 0;

case EIO:

/* Could ignore EIO, see spec. */

/* fall through */

default:

errno_exit("VIDIOC_DQBUF");

}

}

for (i = 0; i < n_buffers; ++i)

if (buf.m.userptr == (unsigned long) buffers[i].start && buf.length

== buffers[i].length)

break;

assert(i < n_buffers);

//      printf("length = %d/r", buffers[i].length);

//      process_image((void *) buf.m.userptr, buffers[i].length);

printf("image_size = %d,/t IO_METHOD_USERPTR buffer.length=%d/r",

cap_image_size, buffers[0].length);

process_image(buffers[0].start, cap_image_size);

if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))

errno_exit("VIDIOC_QBUF");

break;

}

return 1;

}

static void mainloop(void) {

unsigned int count;

count = 100;

while (count-- > 0) {

for (;;) {

fd_set fds;

struct timeval tv;

int r;

FD_ZERO(&fds);

FD_SET(fd, &fds);

/* Timeout. */

tv.tv_sec = 2;

tv.tv_usec = 0;

r = select(fd + 1, &fds, NULL, NULL, &tv);

if (-1 == r) {

if (EINTR == errno)

continue;

errno_exit("select");

}

if (0 == r) {

fprintf(stderr, "select timeout/n");

exit(EXIT_FAILURE);

}

if (read_frame())

break;

/* EAGAIN - continue select loop. */

}

}

}

static void stop_capturing(void) {

enum v4l2_buf_type type;

switch (io) {

case IO_METHOD_READ:

/* Nothing to do. */

break;

case IO_METHOD_MMAP:

case IO_METHOD_USERPTR:

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))

errno_exit("VIDIOC_STREAMOFF");

break;

}

}

static void start_capturing(void) {

unsigned int i;

enum v4l2_buf_type type;

switch (io) {

case IO_METHOD_READ:

/* Nothing to do. */

break;

case IO_METHOD_MMAP:

for (i = 0; i < n_buffers; ++i) {

struct v4l2_buffer buf;

CLEAR (buf);

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

buf.index = i;

if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))

errno_exit("VIDIOC_QBUF");

}

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))

errno_exit("VIDIOC_STREAMON");

break;

case IO_METHOD_USERPTR:

for (i = 0; i < n_buffers; ++i) {

struct v4l2_buffer buf;

CLEAR (buf);

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_USERPTR;

buf.index = i;

buf.m.userptr = (unsigned long) buffers[i].start;

buf.length = buffers[i].length;

if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))

errno_exit("VIDIOC_QBUF");

}

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))

errno_exit("VIDIOC_STREAMON");

break;

}

}

static void uninit_device(void) {

unsigned int i;

switch (io) {

case IO_METHOD_READ:

free(buffers[0].start);

break;

case IO_METHOD_MMAP:

for (i = 0; i < n_buffers; ++i)

if (-1 == munmap(buffers[i].start, buffers[i].length))

errno_exit("munmap");

break;

case IO_METHOD_USERPTR:

for (i = 0; i < n_buffers; ++i)

free(buffers[i].start);

break;

}

free(buffers);

}

static void init_read(unsigned int buffer_size) {

buffers = calloc(1, sizeof(*buffers));

if (!buffers) {

fprintf(stderr, "Out of memory/n");

exit(EXIT_FAILURE);

}

buffers[0].length = buffer_size;

buffers[0].start = malloc(buffer_size);

if (!buffers[0].start) {

fprintf(stderr, "Out of memory/n");

exit(EXIT_FAILURE);

}

}

static void init_mmap(void) {

struct v4l2_requestbuffers req;

CLEAR (req);

req.count = 4;

req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory = V4L2_MEMORY_MMAP;

if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {

if (EINVAL == errno) {

fprintf(stderr, "%s does not support "

"memory mapping/n", dev_name);

exit(EXIT_FAILURE);

} else {

errno_exit("VIDIOC_REQBUFS");

}

}

if (req.count < 2) {

fprintf(stderr, "Insufficient buffer memory on %s/n", dev_name);

exit(EXIT_FAILURE);

}

buffers = calloc(req.count, sizeof(*buffers));

if (!buffers) {

fprintf(stderr, "Out of memory/n");

exit(EXIT_FAILURE);

}

for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {

struct v4l2_buffer buf;

CLEAR (buf);

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

buf.index = n_buffers;

if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))

errno_exit("VIDIOC_QUERYBUF");

buffers[n_buffers].length = buf.length;

buffers[n_buffers].start = mmap(NULL /* start anywhere */, buf.length,

PROT_READ | PROT_WRITE /* required */,

MAP_SHARED /* recommended */, fd, buf.m.offset);

if (MAP_FAILED == buffers[n_buffers].start)

errno_exit("mmap");

}

}

static void init_userp(unsigned int buffer_size) {

struct v4l2_requestbuffers req;

unsigned int page_size;

page_size = getpagesize();

buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);

CLEAR (req);

req.count = 4;

req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory = V4L2_MEMORY_USERPTR;

if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {

if (EINVAL == errno) {

fprintf(stderr, "%s does not support "

"user pointer i/o/n", dev_name);

exit(EXIT_FAILURE);

} else {

errno_exit("VIDIOC_REQBUFS");

}

}

buffers = calloc(4, sizeof(*buffers));

if (!buffers) {

fprintf(stderr, "Out of memory/n");

exit(EXIT_FAILURE);

}

for (n_buffers = 0; n_buffers < 4; ++n_buffers) {

buffers[n_buffers].length = buffer_size;

buffers[n_buffers].start = memalign(/* boundary */page_size,

buffer_size);

if (!buffers[n_buffers].start) {

fprintf(stderr, "Out of memory/n");

exit(EXIT_FAILURE);

}

}

}

static void init_device(void) {

struct v4l2_capability cap;

struct v4l2_cropcap cropcap;

struct v4l2_crop crop;

struct v4l2_format fmt;

unsigned int min;

if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {

if (EINVAL == errno) {

fprintf(stderr, "%s is no V4L2 device/n", dev_name);

exit(EXIT_FAILURE);

} else {

errno_exit("VIDIOC_QUERYCAP");

}

}

if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {

fprintf(stderr, "%s is no video capture device/n", dev_name);

exit(EXIT_FAILURE);

}

switch (io) {

case IO_METHOD_READ:

if (!(cap.capabilities & V4L2_CAP_READWRITE)) {

fprintf(stderr, "%s does not support read i/o/n", dev_name);

exit(EXIT_FAILURE);

}

break;

case IO_METHOD_MMAP:

case IO_METHOD_USERPTR:

if (!(cap.capabilities & V4L2_CAP_STREAMING)) {

fprintf(stderr, "%s does not support streaming i/o/n", dev_name);

exit(EXIT_FAILURE);

}

break;

}

//////not all capture support crop!!!!!!!

/* Select video input, video standard and tune here. */

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

CLEAR (cropcap);

cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {

crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

#ifndef CROP_BY_JACK

crop.c = cropcap.defrect; /* reset to default */

#else

crop.c.left = cropcap.defrect.left;

crop.c.top = cropcap.defrect.top;

crop.c.width = 352;

crop.c.height = 288;

#endif

printf("----->has ability to crop!!/n");

printf("cropcap.defrect = (%d, %d, %d, %d)/n", cropcap.defrect.left,

cropcap.defrect.top, cropcap.defrect.width,

cropcap.defrect.height);

if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {

switch (errno) {

case EINVAL:

/* Cropping not supported. */

break;

default:

/* Errors ignored. */

break;

}

printf("-----!!but crop to (%d, %d, %d, %d) Failed!!/n",

crop.c.left, crop.c.top, crop.c.width, crop.c.height);

} else {

printf("----->sussess crop to (%d, %d, %d, %d)/n", crop.c.left,

crop.c.top, crop.c.width, crop.c.height);

}

} else {

/* Errors ignored. */

printf("!! has no ability to crop!!/n");

}

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("/n");

////////////crop finished!

//////////set the format

CLEAR (fmt);

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt.pix.width = 640;

fmt.fmt.pix.height = 480;

//V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420 — Planar formats with 1/2 horizontal and vertical chroma resolution, also known as YUV 4:2:0

//V4L2_PIX_FMT_YUYV — Packed format with 1/2 horizontal chroma resolution, also known as YUV 4:2:2

fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YUV420;//V4L2_PIX_FMT_YUYV;

fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

{

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("=====will set fmt to (%d, %d)--", fmt.fmt.pix.width,

fmt.fmt.pix.height);

if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {

printf("V4L2_PIX_FMT_YUYV/n");

} else if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {

printf("V4L2_PIX_FMT_YUV420/n");

} else if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {

printf("V4L2_PIX_FMT_NV12/n");

}

}

if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))

errno_exit("VIDIOC_S_FMT");

{

printf("=====after set fmt/n");

printf("    fmt.fmt.pix.width = %d/n", fmt.fmt.pix.width);

printf("    fmt.fmt.pix.height = %d/n", fmt.fmt.pix.height);

printf("    fmt.fmt.pix.sizeimage = %d/n", fmt.fmt.pix.sizeimage);

cap_image_size = fmt.fmt.pix.sizeimage;

printf("    fmt.fmt.pix.bytesperline = %d/n", fmt.fmt.pix.bytesperline);

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("/n");

}

cap_image_size = fmt.fmt.pix.sizeimage;

/* Note VIDIOC_S_FMT may change width and height. */

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

/* Buggy driver paranoia. */

min = fmt.fmt.pix.width * 2;

if (fmt.fmt.pix.bytesperline < min)

fmt.fmt.pix.bytesperline = min;

min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;

if (fmt.fmt.pix.sizeimage < min)

fmt.fmt.pix.sizeimage = min;

printf("After Buggy driver paranoia/n");

printf("    >>fmt.fmt.pix.sizeimage = %d/n", fmt.fmt.pix.sizeimage);

printf("    >>fmt.fmt.pix.bytesperline = %d/n", fmt.fmt.pix.bytesperline);

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("/n");

switch (io) {

case IO_METHOD_READ:

init_read(fmt.fmt.pix.sizeimage);

break;

case IO_METHOD_MMAP:

init_mmap();

break;

case IO_METHOD_USERPTR:

init_userp(fmt.fmt.pix.sizeimage);

break;

}

}

static void close_device(void) {

if (-1 == close(fd))

errno_exit("close");

fd = -1;

}

static void open_device(void) {

struct stat st;

if (-1 == stat(dev_name, &st)) {

fprintf(stderr, "Cannot identify '%s': %d, %s/n", dev_name, errno,

strerror(errno));

exit(EXIT_FAILURE);

}

if (!S_ISCHR(st.st_mode)) {

fprintf(stderr, "%s is no device/n", dev_name);

exit(EXIT_FAILURE);

}

fd = open(dev_name, O_RDWR /* required */| O_NONBLOCK, 0);

if (-1 == fd) {

fprintf(stderr, "Cannot open '%s': %d, %s/n", dev_name, errno,

strerror(errno));

exit(EXIT_FAILURE);

}

}

static void usage(FILE * fp, int argc, char ** argv) {

fprintf(fp, "Usage: %s [options]/n/n"

"Options:/n"

"-d | --device name   Video device name [/dev/video0]/n"

"-h | --help          Print this message/n"

"-m | --mmap          Use memory mapped buffers/n"

"-r | --read          Use read() calls/n"

"-u | --userp         Use application allocated buffers/n"

"", argv[0]);

}

static const char short_options[] = "d:hmru";

static const struct option long_options[] = { { "device", required_argument,

NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "mmap", no_argument,

NULL, 'm' }, { "read", no_argument, NULL, 'r' }, { "userp",

no_argument, NULL, 'u' }, { 0, 0, 0, 0 } };

int main(int argc, char ** argv) {

dev_name = "/dev/video0";

outf = fopen("out.yuv", "wb");

for (;;) {

int index;

int c;

c = getopt_long(argc, argv, short_options, long_options, &index);

if (-1 == c)

break;

switch (c) {

case 0: /* getopt_long() flag */

break;

case 'd':

dev_name = optarg;

break;

case 'h':

usage(stdout, argc, argv);

exit(EXIT_SUCCESS);

case 'm':

io = IO_METHOD_MMAP;

break;

case 'r':

io = IO_METHOD_READ;

break;

case 'u':

io = IO_METHOD_USERPTR;

break;

default:

usage(stderr, argc, argv);

exit(EXIT_FAILURE);

}

}

open_device();

init_device();

start_capturing();

mainloop();

printf("/n");

stop_capturing();

fclose(outf);

uninit_device();

close_device();

exit(EXIT_SUCCESS);

return 0;

}

V4L2驱动的移植与应用(三)的更多相关文章

  1. V4L2驱动的移植与应用(二+三)【转】

    转自:http://blog.chinaunix.net/uid-10747583-id-298489.html 原文地址:http://blog.csdn.net/wxzking/archive/2 ...

  2. V4L2驱动的移植与应用(一)

    V4L2(video for linux) 可以支持多种设备,它可以有以下5种接口: 1.视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2 ...

  3. V4L2驱动的移植与应用(二)

    二.V4L2的应用 下面简单介绍一下V4L2驱动的应用流程. 1.  视频采集的基本流程 一般的,视频采集都有如下流程: 2.  打开视频设备 在V4L2中,视频设备被看做一个文件.使用open函数打 ...

  4. v4l2驱动编写篇【转】

    转自:http://blog.csdn.net/michaelcao1980/article/details/53008418 大部分所需的信息都在这里.作为一个驱动作者,当挖掘头文件的时候,你可能也 ...

  5. WIFI驱动的移植 realtek 8188

    一般我们拿到的android源代码中wifi应用层部分是好的, 主要是wifi芯片的驱动要移植并添加进去. wifi驱动的移植, 以realtek的8188etv为例到官网下载相应的驱动, 解压后可以 ...

  6. V4L2驱动内核文档翻译(一)

    随着一些视频或者图像硬件的复杂化,V4L2驱动也越来越趋于复杂.许多硬件有多个IC,在/dev下生成多个video设备或者其他的诸如,DVB,ALSA,FB,I2C ,IR等等非V4L2的设备.所以, ...

  7. 2.1 摄像头V4L2驱动框架分析

    学习目标:学习V4L2(V4L2:vidio for linux version 2)摄像头驱动框架,分析vivi.c(虚拟视频硬件相关)驱动源码程序,总结V4L2硬件相关的驱动的步骤:  一.V4L ...

  8. Android wifi驱动的移植 realtek 8188

    Android wifi驱动的移植 一般我们拿到的android源代码中wifi应用层部分是好的, 主要是wifi芯片的驱动要移植并添加进去. wifi驱动的移植, 以realtek的8188etv为 ...

  9. 【Linux开发】V4L2驱动框架分析学习

    Author:CJOK Contact:cjok.liao#gmail.com SinaWeibo:@廖野cjok 1.概述 Video4Linux2是Linux内核中关于视频设备的内核驱动框架,为上 ...

随机推荐

  1. SpringMVC 知识整理

    SpringMVC架构设计 MVC是一种架构模式,它把业务的实现和展示相分离. SpringMVC与struts2的区别 Struts2是类级别的拦截, 一个类对应一个request上下文,Sprin ...

  2. oracle pl/sql如何定义变量

    目的:如何在pl/sql中定义基本类型,引用类型,记录型变量? 以下plsql程序用的scott用户的dept,emp表. 定义基本类型的变量 set serveroutput on ; --使用基本 ...

  3. 面向切面编程之手动JDK代理方式

    需求描述: 抽取dao层开启和提交事物交由代理类一并执行 分析: 假如UserDao接口中有很多方法,例如addUser().deleteUser().updateUser()等等,需要频繁的和数据库 ...

  4. HTML核心标签之表格标签(二)

    基本用法: <ul type="cir"> <li>显示数据</li> <li>显示数据</li> </ul> ...

  5. IntelliJ IDEA使用心得之插件篇

    今天和大家分享下插件的安装方法,顺便推荐几个非常好用的插件. 1.安装插件 在工具栏中,点击进入IDE设置界面. 插件仓库界面: 值得注意的是,每次安装/卸载插件后,需要重启IDE. 2.好用的插件 ...

  6. VUE 2.0 引入高德地图,自行封装组件

    1. 高德地图官网 申请帐号, 申请相应(JavaScript API)的 Key 2. 在项目中引入, 这里和其他的引入不同的是 直接在 index.html, 不是在 main.js 引入, 博主 ...

  7. AJAX入门第一篇就够了

    什么是Ajax Ajax(Asynchronous JavaScript and XML) 异步JavaScript和XML Ajax实际上是下面这几种技术的融合: (1)XHTML和CSS的基于标准 ...

  8. 使用requireJS

    什么是require? require是AMD模块化规范的具体实现. 目前,通行的js模块化规范有两种,CommonJS和AMD. CommonJS和AMD有什么不同呢? CommonJS主要用于服务 ...

  9. PHP 5.6 微信上传临时素材的坑

    /** * 上传素材 */ function add_material($url){ $access_token = wx_access_token(); $wx_url = "https: ...

  10. Ajax简单总结

    Ajax=异步JS和XML: 主要是局部的数据更新,即不需要刷新整个页面: 首先,需要新建一个XMLHttpRequest对象[这里注意如果是ie7以下的就是创建ActiveXObject]: var ...