.net core 装了没生效_还在纠结在校期间没做过项目?今天先给大家推荐一个!...

d3b2420d50fd2a99803a66bd2ef2aa70.png

a395f90bf5c1059985ddd61d76aee885.png

过完这个暑假,又到了一年一度的秋招季节。很多同学已经开始了准备工作,制作简历、疯狂刷题、或者就是回顾在校期间做过的项目。但是每年都有很多同学在校期间没做过项目,简历上不知道怎么写。今天就来给大家推荐一个,非常适合嵌入式开发方向的同学。

项目名称:基于web的远程视频传输

软件平台:Ubuntu

硬件平台:NanoPi Duo2

备注:硬件平台选择性很多,mini2440、NanoPi系列、树莓派等等。

mjpg-streamer

MJPG-streamer是一款开源基于IP地址的视频流服务器,它的输入插件从摄像头读取视频数据,这个输入插件产生视频数据并将视频数据复制到内存中。它有多个输出插件将这些视频数据经过处理,其中最重要的输出插件是网站服务器插件,它将视频数据传送到用户浏览器中。MJPG-streamer的工作就是将其中的一个输入插件和多个输出插件绑定在一起,所有的工作都是通过它的各个插件完成的。

第一步:下载源码

源码地址:

https://sourceforge.net/p/mjpg-streamer/code/HEAD/tree/

可以直接下载源码包的压缩文件:

mjpg-streamer-code-r182.zip

或者通过 svn 下载:

svn checkout https://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code

备注:环境中需要先安装 svn

如果不想麻烦,公众号后台【mjpg】,直接获取! 安装 mjpg-streamer  需要先安装 libjpeg,libjpeg源码地址
https://sourceforge.net/projects/libjpeg/
可以使用 wget 直接下载。

第二步:交叉编译

1、安装交叉编译环境(以NanoPi Duo2平台为例)

  • 下载交叉编译器 

arm-cortexa9-linux-gnueabihf-4.9.3-20160512.tar.xz

注:NanoPi官网提供下载链接

  • 放至 Ubuntu 的 opt 目录下,并且解压

tar -xf arm-cortexa9-linux-gnueabihf-4.9.3-20160512.tar.xz
  • 修改文件 /root/.bashrc,在最后加上

export PATH=$PATH:/opt/4.9.3/bin
  • 使修改的文件生效

source /root/.bashrc

2、编译 libjpeg

  • 解压后进入目录;

  • 配置编译环境

./configure --host=arm-linux- --prefix=/home/jpeg-install
  • 编译

make
  • 安装

make install

安装完毕会在 /home 目录下看见 jpeg-install 目录。

3、编译 mjpg-streamer

  • 修改顶层 Makefile

CC=arm-linux-gcc
  • 修改插件的 Makefile(plugins/input_uvc/Makefile)

CC=arm-linux-gcc

以及动态库路径

$(CC) $(CFLAGS) -L /home/jpeg-install -ljpeg -o $@ input_uvc.so
  • 修改插件 Makefile (plugins/output_http/Makefile)

CC=arm-linux-gcc
  • 编译

make

最终生成的文件打包复制到开发板上,需要安装 libjpeg,mjpg-streamer不需要安装。

第三步:运行

1、配置网络,保证 NanoPi 和电脑可以组成一个局域网;

ifconfigwlan0     Link encap:Ethernet  HWaddr c0:84:7d:a0:27:14            inet addr:192.168.0.105  Bcast:192.168.0.255  Mask:255.255.255.0          inet6 addr: fe80::9e9a:8bbc:69f1:24f0/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1          RX packets:8731 errors:0 dropped:0 overruns:0 frame:0          TX packets:3727 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1000           RX bytes:6593454 (6.5 MB)  TX bytes:502413 (502.4 KB)

开发板的地址是:192.168.0.105,这个很重要。

2、打开笔记本的浏览器,输入:

http://192.168.0.105:8080/

1d3dae1ff442d812a4422b3056524735.png

选择 Stream

23d956df0a37daaa0552f82ccd3837ef.png

源码分析

1、几个重要文件

  • input_testpicture.so:这是一个图像测试插件,它将预设好的图像编译成一个头文件,可以在没有摄像头的情况下传输图像,从而方便调试程序。

  • input_uvc.so:此文件调用USB摄像头驱动程序 V4L2,从摄像头读取视频数据。

  • output_http.so:这是一个功能齐全的网站服务器,它不仅可以从单一文件夹中处理文件,还可以执行一定的命令,它可以从输入插件中处理一幅图像,也可以将输入插件的视频文件根据现有M-JPEG标准以HTTP视频数据服务流形式输出。

  • input_control.so:这个文件实现对摄像头参数的控制。

  • output_file.so:这个插件的功能是将输入插件的JPEG图像存储到特定的文件夹下,它可以用来抓取图像。

2、命令解析

int main(int argc, char *argv[]){  char *input  = "input_uvc.so --resolution 640x480 --fps 5 --device /dev/video0";  char *output[MAX_OUTPUT_PLUGINS];//10  int daemon=0, i;  size_t tmp=0;  output[0] = "output_http.so --port 8080";  global.outcnt = 0;  global.control = control;  /* parameter parsing */  while(1) {    int option_index = 0, c=0;    static struct option long_options[] = \    {    {"h", no_argument, 0, 0},    {"help", no_argument, 0, 0},    {"i", required_argument, 0, 0},    {"input", required_argument, 0, 0},    {"o", required_argument, 0, 0},    {"output", required_argument, 0, 0},    {"v", no_argument, 0, 0},    {"version", no_argument, 0, 0},    {"b", no_argument, 0, 0},    {"background", no_argument, 0, 0},    {0, 0, 0, 0}  };  c = getopt_long_only(argc, argv, "", long_options, &option_index);

这里主要遇到一个功能函数getopt_long_only(),该函数功能主要是解析命令行选项,也就是将 input 中的-h -i -o -v -b的参数解析出来,该函数具体如何使用,可参照getopt_long_only。

3、调用输入插件

  /* open input plugin */  tmp = (size_t)(strchr(input, ' ')-input);  global.in.plugin = (tmp > 0)?strndup(input, tmp):strdup(input);  global.in.handle = dlopen(global.in.plugin, RTLD_LAZY);  if ( !global.in.handle ) {    LOG("ERROR: could not find input plugin\n");    LOG("       Perhaps you want to adjust the search path with:\n");    LOG("       # export LD_LIBRARY_PATH=/path/to/plugin/folder\n");    LOG("       dlopen: %s\n", dlerror() );    closelog();    exit(EXIT_FAILURE);  }  global.in.init = dlsym(global.in.handle, "input_init");  if ( global.in.init == NULL ) {    LOG("%s\n", dlerror());    exit(EXIT_FAILURE);  }  global.in.stop = dlsym(global.in.handle, "input_stop");  if ( global.in.stop == NULL ) {    LOG("%s\n", dlerror());    exit(EXIT_FAILURE);  }  global.in.run = dlsym(global.in.handle, "input_run");  if ( global.in.run == NULL ) {    LOG("%s\n", dlerror());    exit(EXIT_FAILURE);  }

dlopen()函数负责打开 *.so 插件,dlsym() 负责调用插件中的相关函数。当输入

./mjpg_streamer -i "./input_uvc.so"

系统将会调用 input_uvc.so 中的 input_init 函数,对输入设备进行初始化。

4、调用输出插件

/* open output plugin */  for (i=0; i<global.outcnt; i++) {    tmp = (size_t)(strchr(output[i], ' ')-output[i]);    global.out[i].plugin = (tmp > 0)?strndup(output[i], tmp):strdup(output[i]);    global.out[i].handle = dlopen(global.out[i].plugin, RTLD_LAZY);    if ( !global.out[i].handle ) {      LOG("ERROR: could not find output plugin %s\n", global.out[i].plugin);      LOG("       Perhaps you want to adjust the search path with:\n");      LOG("       # export LD_LIBRARY_PATH=/path/to/plugin/folder\n");      LOG("       dlopen: %s\n", dlerror() );      closelog();      exit(EXIT_FAILURE);    }    global.out[i].init = dlsym(global.out[i].handle, "output_init");    if ( global.out[i].init == NULL ) {      LOG("%s\n", dlerror());      exit(EXIT_FAILURE);    }    global.out[i].stop = dlsym(global.out[i].handle, "output_stop");    if ( global.out[i].stop == NULL ) {      LOG("%s\n", dlerror());      exit(EXIT_FAILURE);    }    if ( global.out[i].stop == NULL ) {      LOG("%s\n", dlerror());      exit(EXIT_FAILURE);    }    global.out[i].run = dlsym(global.out[i].handle, "output_run");    if ( global.out[i].run == NULL ) {      LOG("%s\n", dlerror());      exit(EXIT_FAILURE);    }

5、输入功能分析

int input_init(input_parameter *param)

这个函数代码实现对 usb 摄像头的格式、帧、请求buf,队列buf等的一些设置,主要实现也是在函数

init_videoIn(videoIn, dev, width, height, fps, format, 1)
int input_stop(void) {  DBG("will cancel input thread\n");  pthread_cancel(cam);    return 0;}

 输入停止,主要是取消线程。

6、输出功能

int output_init(output_parameter *param)
int output_stop(int id)
int output_run(int id)

81bae2e0e39a9322f7464d5954b0f78a.png

备战秋招

刻不容缓

暑期智能硬件实训火热招生

有需要的同学抓紧锁定席位

4511c47991c882e9cf2641d878166d99.png

1c0f761ece91f2271232a0d443c78b30.png

07a82652f90d258eaedf63af865df408.png

714a022af39119ae1ae0d6de39c8e793.png

10a19a3ab71032ca607167be0cb77a63.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值