概述
- 从一篇博客中看到的代码,觉得很有用,暂时没时间研究就先转载保存先。参考http://blog.csdn.net/yakimin/article/details/19284467
- 后面可以通过tcp传输等,在pc上或者开发板上把yuv视频解码,然后再把yuv转RGB播放出来。同时之前找了个解码的播放器有源码,可以结合两者实现此功能。链接:
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <linux/videodev2.h>
- #include <libavcodec/avcodec.h>
- #include <libavformat/avformat.h>
- #include <libavformat/avio.h>
- #include <libavutil/opt.h>
- #include <libswscale/swscale.h>
- #include <libavutil/mathematics.h>
- #define VIDEO_WIDTH 640
- #define VIDEO_HEIGHT 480
- #define VIDEO_FORMAT V4L2_PIX_FMT_YUYV
- #define BUFFER_COUNT 4
- #define URL_WRONLY 1
- struct fimc_buffer {
- int length;
- void *start;
- } framebuf[BUFFER_COUNT];
- int fd;
- unsigned char yuv4200[1000000] = { 0 };
- unsigned char yuv4220[1000000] = { 0 };
- AVFormatContext* pFormatCtxEnc;
- AVCodecContext* pCodecCtxEnc;
- AVFrame* pFrameEnc;
- void register_init();
- int open_device();
- int capability();
- int set_v4l2_format();
- int request_buffers();
- int get_camera_data();
- void unregister_all();
- void video_encode_init();
- int yuv422_2_yuv420(unsigned char* yuv420, unsigned char* yuv422, int width,
- int height);
- void register_init() {
- avcodec_register_all();
- av_register_all();
- }
- int open_device() {
- char camera_device[20];
- struct stat buf;
- int i;
- for (i = 0; i < 10; i++) {
- sprintf(camera_device, "/dev/video%i", i);
- if (stat(camera_device, &buf) == 0) {
- break;
- }
- }
- fd = open(camera_device, O_RDWR, 0); //设备以非阻塞方式打开
- if (fd < 0) {
- printf("Cannot open camera_devicen");
- return -1;
- }
- }
- int set_v4l2_format() {
- int ret;
- struct v4l2_format fmt; //设置视频制式和帧格式
- memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = VIDEO_WIDTH;
- fmt.fmt.pix.height = VIDEO_HEIGHT;
- fmt.fmt.pix.pixelformat = VIDEO_FORMAT;
- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
- ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
- if (ret < 0) {
- printf("VIDIOC_S_FMT failedn");
- return ret;
- }
- ret = ioctl(fd, VIDIOC_G_FMT, &fmt); //获取视频制式和帧格式的实际值,看是否设置正确
- if (ret < 0) {
- printf("VIDIOC_G_FMT failed (%d)/n", ret);
- return ret;
- }
- }
- int request_buffers() {
- int ret;
- int i;
- struct v4l2_requestbuffers reqbuf; //向驱动申请帧缓冲
- reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- reqbuf.memory = V4L2_MEMORY_MMAP;
- reqbuf.count = BUFFER_COUNT;
- ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
- if (ret < 0) {
- printf("VIDIOC_REQBUFS failed n");
- return ret;
- }
- struct v4l2_buffer buf; //获取帧缓冲地址
- for (i = 0; i < BUFFER_COUNT; i++) {
- buf.index = i;
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);
- if (ret < 0) {
- printf("VIDIOC_QUERYBUF failedn");
- return ret;
- }
- framebuf[i].length = buf.length;
- framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, buf.m.offset); //将申请到的帧缓冲映射到用户空间,>就能直接操作采集的帧
- if (framebuf[i].start == MAP_FAILED) {
- printf("mmap (%d) failed: %s/n", i, strerror(errno));
- return -1;
- }
- ret = ioctl(fd, VIDIOC_QBUF, &buf); //将申请到的帧缓冲全部入队列,以便存放数据
- if (ret < 0) {
- printf("VIDIOC_QBUF (%d) failed (%d)/n", i, ret);
- return -1;
- }
- }
- }
- int get_camera_data() {
- int ret;
- int i, k;
- struct v4l2_buffer buf; //获取帧缓冲地址
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //开始视频采集
- ret = ioctl(fd, VIDIOC_STREAMON, &type);
- if (ret < 0) {
- printf("VIDIOC_STREAMON failed (%d)n", ret);
- return ret;
- }
- video_encode_init();
- i = 0;
- while (1) {
- static int delayFrame = 0;
- int got_packet = 0;
- printf("-----------seconds = %d----------n", ++i);
- for (k = 0; k < 25; k++) {
- ret = ioctl(fd, VIDIOC_DQBUF, &buf); //出队列以取得已采集数据的帧缓冲,取得原始数据
- if (ret < 0) {
- printf("VIDIOC_DQBUF failed (%d)/n", ret);
- return ret;
- }
- strncpy(yuv4220, framebuf[buf.index].start,
- framebuf[buf.index].length);
- yuv422_2_yuv420(yuv4200, yuv4220, 640, 480);
- av_image_alloc(pFrameEnc->data, pFrameEnc->linesize,
- pCodecCtxEnc->width, pCodecCtxEnc->height,
- pCodecCtxEnc->pix_fmt, 1);
- pFrameEnc->data[0] = yuv4200;
- pFrameEnc->data[1] = pFrameEnc->data[0]
- + pCodecCtxEnc->width * pCodecCtxEnc->height;
- pFrameEnc->data[2] = pFrameEnc->data[1]
- + pCodecCtxEnc->width * pCodecCtxEnc->height / 4;
- pFrameEnc->linesize[0] = pCodecCtxEnc->width;
- pFrameEnc->linesize[1] = pCodecCtxEnc->width / 2;
- pFrameEnc->linesize[2] = pCodecCtxEnc->width / 2;
- pFrameEnc->pts = (k + (i - 1) * 25) * 40;
- pFrameEnc->width = 640;
- pFrameEnc->height = 480;
- if (!pFormatCtxEnc->nb_streams) {
- printf("output file does not contain any streamn");
- exit(0);
- }
- AVPacket pkt;
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
- printf("encoding frame %d-------", k);
- ret = avcodec_encode_video2(pCodecCtxEnc, &pkt, pFrameEnc,
- &got_packet);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Video encoding failedn");
- }
- if (got_packet) {
- printf("output frame %d size = %dn", k - delayFrame, pkt.size);
- ret = av_interleaved_write_frame(pFormatCtxEnc, &pkt);
- if (ret != 0) {
- fprintf(stderr, "write frame into file is failedn");
- } else {
- printf("encode and write one frame successn");
- }
- } else {
- delayFrame++;
- printf("no frame outputn");
- }
- av_free_packet(&pkt);
- ret = ioctl(fd, VIDIOC_QBUF, &buf); //将缓冲重新入对尾,可以循环采集
- if (ret < 0) {
- printf("VIDIOC_QBUF failed (%d)n", ret);
- return ret;
- }
- }
- /* get the delayed frames */
- for (got_packet = 1; got_packet; k++) {
- fflush(stdout);
- AVPacket pkt;
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
- ret = avcodec_encode_video2(pCodecCtxEnc, &pkt, NULL, &got_packet);
- if (ret < 0) {
- fprintf(stderr, "error encoding framen");
- exit(1);
- }
- if (got_packet) {
- printf("output delayed frame %3d (size=%5d)n", k - delayFrame,
- pkt.size);
- av_interleaved_write_frame(pFormatCtxEnc, &pkt);
- av_free_packet(&pkt);
- }
- }
- }
- av_write_trailer(pFormatCtxEnc);
- if (!(pFormatCtxEnc->flags & AVFMT_NOFILE))
- avio_close(pFormatCtxEnc->pb);
- for (i = 0; i < BUFFER_COUNT; i++) {
- munmap(framebuf[i].start, framebuf[i].length); //取消映射,释放内存
- }
- close(fd);
- return 0;
- }
- int capability() {
- int ret;
- struct v4l2_capability cap;
- ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); //摄像头主要获取功能
- if (ret < 0) {
- printf("VIDIOC_QUERYCAP failed n");
- return ret;
- }
- }
- int yuv422_2_yuv420(unsigned char* yuv420, unsigned char* yuv422, int width,
- int height) {
- int imgSize = width * height * 2;
- int widthStep422 = width * 2;
- unsigned char* p422 = yuv422;
- unsigned char* p420y = yuv420;
- unsigned char* p420u = yuv420 + imgSize / 2;
- unsigned char* p420v = p420u + imgSize / 8;
- int i, j;
- for (i = 0; i < height; i += 2) {
- p422 = yuv422 + i * widthStep422;
- for (j = 0; j < widthStep422; j += 4) {
- *(p420y++) = p422[j];
- *(p420u++) = p422[j + 1];
- *(p420y++) = p422[j + 2];
- }
- p422 += widthStep422;
- for (j = 0; j < widthStep422; j += 4) {
- *(p420y++) = p422[j];
- *(p420v++) = p422[j + 3];
- *(p420y++) = p422[j + 2];
- }
- }
- return 0;
- }
- void unregister_all() {
- int i;
- for (i = 0; i < BUFFER_COUNT; i++) {
- munmap(framebuf[i].start, framebuf[i].length); //取消映射,释放内存
- }
- close(fd);
- printf("Camera test Done.n");
- }
- void video_encode_init() {
- char* filename = "./264.flv";
- AVCodec* pCodecEnc;
- AVOutputFormat* pOutputFormat;
- AVStream* video_st;
- int i;
- int ret;
- av_register_all();
- pOutputFormat = av_guess_format(NULL, filename, NULL);
- if (pOutputFormat == NULL) {
- fprintf(stderr, "Could not guess the format from filen");
- exit(0);
- } else {
- printf("guess the format from file successn");
- }
- pFormatCtxEnc = avformat_alloc_context();
- if (pFormatCtxEnc == NULL) {
- fprintf(stderr, "could not allocate AVFormatContexn");
- exit(0);
- } else {
- printf("allocate AVFormatContext successn");
- }
- pFormatCtxEnc->oformat = pOutputFormat;
- sprintf(pFormatCtxEnc->filename, "%s", filename);
- printf("filename is %sn", pFormatCtxEnc->filename);
- video_st = avformat_new_stream(pFormatCtxEnc, 0);
- if (!video_st) {
- fprintf(stderr, "could not allocate AVstreamn");
- exit(0);
- } else {
- printf("allocate AVstream successn");
- }
- pCodecCtxEnc = video_st->codec;
- pCodecCtxEnc->codec_id = pOutputFormat->video_codec;
- pCodecCtxEnc->codec_type = AVMEDIA_TYPE_VIDEO;
- pCodecCtxEnc->bit_rate = 1000000;
- pCodecCtxEnc->bit_rate_tolerance = 300000000; //表示有多少bit的视频流可以偏移出目前的设定.这里的"设定"是指的cbr或者vbr.
- pCodecCtxEnc->width = 640;
- pCodecCtxEnc->height = 480;
- pCodecCtxEnc->time_base = (AVRational) {1,25};
- //pCodecCtxEnc->time_base.num = 1;
- //pCodecCtxEnc->time_base.den = 25;
- pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
- pCodecCtxEnc->gop_size = 10;
- pCodecCtxEnc->max_b_frames = 0;
- av_opt_set(pCodecCtxEnc->priv_data, "preset", "superfast", 0);
- av_opt_set(pCodecCtxEnc->priv_data, "tune", "zerolatency", 0);
- pCodecCtxEnc->pre_me = 2;
- pCodecCtxEnc->lmin = 10;
- pCodecCtxEnc->lmax = 50;
- pCodecCtxEnc->qmin = 20;
- pCodecCtxEnc->qmax = 80;
- pCodecCtxEnc->qblur = 0.0;
- pCodecCtxEnc->spatial_cplx_masking = 0.3;
- pCodecCtxEnc->me_pre_cmp = 2;
- pCodecCtxEnc->rc_qsquish = 1;
- pCodecCtxEnc->b_quant_factor = 4.9;
- pCodecCtxEnc->b_quant_offset = 2;
- pCodecCtxEnc->i_quant_factor = 0.1;
- pCodecCtxEnc->i_quant_offset = 0.0;
- pCodecCtxEnc->rc_strategy = 2;
- pCodecCtxEnc->b_frame_strategy = 0;
- pCodecCtxEnc->dct_algo = 0;
- pCodecCtxEnc->lumi_masking = 0.0;
- pCodecCtxEnc->dark_masking = 0.0;
- if (!strcmp(pFormatCtxEnc->oformat->name, "flv")) {
- pCodecCtxEnc->flags |= CODEC_FLAG_GLOBAL_HEADER;
- } else {
- printf("output format is %sn", pFormatCtxEnc->oformat->name);
- }
- pCodecEnc = avcodec_find_encoder(pCodecCtxEnc->codec_id);
- if (!pCodecEnc) {
- fprintf(stderr, "could not find suitable video encodern");
- exit(0);
- } else {
- printf("find the encoder successn");
- }
- if (avcodec_open2(pCodecCtxEnc, pCodecEnc, NULL) < 0) {
- fprintf(stderr, "could not open video codecn");
- exit(0);
- } else {
- printf("open the video codec successn");
- }
- pFrameEnc = avcodec_alloc_frame();
- if (pFrameEnc == NULL) {
- fprintf(stderr, "could not allocate pFrameEncn");
- exit(0);
- } else {
- printf("allocate pFrameEnc successn");
- }
- ret = avio_open(&pFormatCtxEnc->pb, filename, AVIO_FLAG_WRITE);
- if (ret < 0) {
- fprintf(stderr, "could not open '%s': %sn", filename, av_err2str(ret));
- exit(0);
- } else {
- printf("open filename = %s successn", filename);
- }
- ret = avformat_write_header(pFormatCtxEnc, NULL);
- if (ret < 0) {
- fprintf(stderr, "error occurred when opening outputfile: %sn",
- av_err2str(ret));
- exit(0);
- } else {
- printf("write the header successn");
- }
- }
- int main() {
- register_init();
- open_device();
- capability();
- set_v4l2_format();
- request_buffers();
- get_camera_data();
- unregister_all();
- return 0;
- }
最后
以上就是苗条乌冬面为你收集整理的基于USB摄像头视频数据采集和利用FFMPEG库函数进行视频数据压缩的全部内容,希望文章能够帮你解决基于USB摄像头视频数据采集和利用FFMPEG库函数进行视频数据压缩所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复