移植mjpg_streamer使其支持拍照功能

移植mjpg_streamer使其支持拍照功能



修改代码

下面是修改之后的完整代码
/mjpg-streamer/mjpg-streamer/plugins/output_file.c

/*******************************************************************************
#                                                                              #
#      MJPG-streamer allows to stream JPG frames from an input-plugin          #
#      to several output plugins                                               #
#                                                                              #
#      Copyright (C) 2007 Tom St?veken                                         #
#                                                                              #
# This program is free software; you can redistribute it and/or modify         #
# it under the terms of the GNU General Public License as published by         #
# the Free Software Foundation; version 2 of the License.                      #
#                                                                              #
# This program is distributed in the hope that it will be useful,              #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with this program; if not, write to the Free Software                  #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    #
#                                                                              #
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <pthread.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>

#include <dirent.h>

#include "../../utils.h"
#include "../../mjpg_streamer.h"

#define OUTPUT_PLUGIN_NAME "FILE output plugin"

static pthread_t worker;
static globals *pglobal;
static int fd, delay, ringbuffer_size = -1, ringbuffer_exceed = 0, max_frame_size;
static char *folder = "/tmp";
static unsigned char *frame = NULL;
static char *command = NULL;
static int input_number = 0;

/******************************************************************************
Description.: print a help message
Input Value.: -
Return Value: -
******************************************************************************/
void help(void)
{
    fprintf(stderr, " ---------------------------------------------------------------\n" \
            " Help for output plugin..: "OUTPUT_PLUGIN_NAME"\n" \
            " ---------------------------------------------------------------\n" \
            " The following parameters can be passed to this plugin:\n\n" \
            " [-f | --folder ]........: folder to save pictures\n" \
            " [-m | --mjpeg ]........: save the stream to an mjpeg file\n" \
            " [-d | --delay ].........: delay after saving pictures in ms\n" \
            " [-s | --size ]..........: size of ring buffer (max number of pictures to hold)\n" \
            " [-e | --exceed ]........: allow ringbuffer to exceed limit by this amount\n" \
            " [-c | --command ].......: execute command after saving picture\n\n" \
            " [-i | --input ].......: read frames from the specified input plugin\n\n" \
            " ---------------------------------------------------------------\n");
}

/******************************************************************************
Description.: clean up allocated ressources
Input Value.: unused argument
Return Value: -
******************************************************************************/
void worker_cleanup(void *arg)
{
    static unsigned char first_run = 1;

    if(!first_run) {
        DBG("already cleaned up ressources\n");
        return;
    }

    first_run = 0;
    OPRINT("cleaning up ressources allocated by worker thread\n");

    if(frame != NULL) {
        free(frame);
    }
    close(fd);
}

/******************************************************************************
Description.: compares a directory entry with a pattern
Input Value.: directory entry
Return Value: 0 if string do not match, 1 if they match
******************************************************************************/
int check_for_filename(const struct dirent *entry)
{
    int rc;

    int year, month, day, hour, minute, second;
    unsigned long long number;

    /*
     * try to scan the string using scanf
     * I would like to use a define for this format string later...
     */
    rc = sscanf(entry->d_name, "%d_%d_%d_%d_%d_%d_picture_%09llu.jpg", &year, \
                &month, \
                &day, \
                &hour, \
                &minute, \
                &second, \
                &number);

    DBG("%s, rc is %d (%d, %d, %d, %d, %d, %d, %llu)\n", entry->d_name, \
        rc, \
        year, \
        month, \
        day, \
        hour, \
        minute, \
        second, \
        number);

    /* if scanf could find all values, it matches our filenames */
    if(rc != 7) return 0;

    return 1;
}

/******************************************************************************
Description.: delete oldest files, just keep "size" most recent files
              This funtion MAY delete the wrong files if the time is not valid
Input Value.: how many files to keep
Return Value: -
******************************************************************************/
void maintain_ringbuffer(int size)
{
    struct dirent **namelist;
    int n, i;
    char buffer[1<<16];

    /* do nothing if ringbuffer is not set or wrong value is set */
    if(size < 0) return;

    /* get a sorted list of directory items */
    n = scandir(folder, &namelist, check_for_filename, alphasort);
    if(n < 0) {
        perror("scandir");
        return;
    }

    DBG("found %d directory entries\n", n);

    /* delete the first (thus oldest) number of files */
    for(i = 0; i < (n - size); i++) {

        /* put together the folder name and the directory item */
        snprintf(buffer, sizeof(buffer), "%s/%s", folder, namelist[i]->d_name);

        DBG("delete: %s\n", buffer);

        /* mark item for deletion */
        if(unlink(buffer) == -1) {
            perror("could not delete file");
        }

        /* free allocated memory for name */
        free(namelist[i]);
    }

    /* keep the rest, but we still have to free every result */
    for(i = MAX(n - size, 0); i < n; i++) {
        DBG("keep: %s\n", namelist[i]->d_name);
        free(namelist[i]);
    }

    /* free last just allocated ressources */
    free(namelist);
}

/******************************************************************************
Description.: this is the main worker thread
              it loops forever, grabs a fresh frame and stores it to file
Input Value.:
Return Value:
******************************************************************************/
void *worker_thread(void *arg)
{
    int ok = 1, frame_size = 0, rc = 0;
    char buffer1[1024] = {0}, buffer2[1024] = {0};
    unsigned long long counter = 0;
    time_t t;
    struct tm *now;
    unsigned char *tmp_framebuffer = NULL;
	
	char buf[10];   //用于存放从管道读取的命令
	int flags = 0;   //拍照标志,1:表示11张照片,2:表示1张照片
	int fd_com = 0; //打开管道的文件描述符

	int stop_num = 0; //拍照计数

	if ( access("/tmp/webcom",F_OK) < 0 )    //创建有名管道用于接收拍照命令
	{
		if ( mkfifo("/tmp/webcom",0666 ) < 0)
		{
			printf("photo fifo create failed\n");
		}
	}

	fd_com = open ("/tmp/webcom",O_RDONLY,0666);
	if (fd_com < 0)
	{
		perror ("open the file webcom error");
	}


    /* set cleanup handler to cleanup allocated ressources */
    pthread_cleanup_push(worker_cleanup, NULL);

    while(ok >= 0 && !pglobal->stop) {
    
		if (flags == 0)
		{
			while(1)
			{
				read(fd_com,buf,sizeof(buf));
				if (strncmp(buf,"danger",6) == 0)    //拍11张照片
				{
					flags = 1;
					bzero(buf,sizeof(buf));
					break;
				}

				if (strncmp(buf,"one",3) == 0)   //拍1张照片
				{
					flags = 2;
					bzero(buf,sizeof(buf));
					break;
				}
			}
		}



	    DBG("waiting for fresh frame\n");
        pthread_mutex_lock(&pglobal->in[input_number].db);
        pthread_cond_wait(&pglobal->in[input_number].db_update, &pglobal->in[input_number].db);

        /* read buffer */
        frame_size = pglobal->in[input_number].size;

        /* check if buffer for frame is large enough, increase it if necessary */
        if(frame_size > max_frame_size) {
            DBG("increasing buffer size to %d\n", frame_size);

            max_frame_size = frame_size + (1 << 16);
            if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) {
                pthread_mutex_unlock(&pglobal->in[input_number].db);
                LOG("not enough memory\n");
                return NULL;
            }

            frame = tmp_framebuffer;
        }

        /* copy frame to our local buffer now */
        memcpy(frame, pglobal->in[input_number].buf, frame_size);

        /* allow others to access the global buffer again */
        pthread_mutex_unlock(&pglobal->in[input_number].db);

        /* prepare filename */
        memset(buffer1, 0, sizeof(buffer1));
        memset(buffer2, 0, sizeof(buffer2));

        /* get current time */
        t = time(NULL);
        now = localtime(&t);
        if(now == NULL) {
            perror("localtime");
            return NULL;
        }

        /* prepare string, add time and date values */
        if(strftime(buffer1, sizeof(buffer1), "%%s/%Y_%m_%d_%H_%M_%S_picture_%%09llu.jpg", now) == 0) {
            OPRINT("strftime returned 0\n");
            free(frame); frame = NULL;
            return NULL;
        }

        /* finish filename by adding the foldername and a counter value */
        snprintf(buffer2, sizeof(buffer2), buffer1, folder, counter);

        counter++;

        DBG("writing file: %s\n", buffer2);

        /* open file for write */
        if((fd = open(buffer2, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
            OPRINT("could not open the file %s\n", buffer2);
            return NULL;
        }

        /* save picture to file */
        if(write(fd, frame, frame_size) < 0) {
            OPRINT("could not write to file %s\n", buffer2);
            perror("write()");
            close(fd);
            return NULL;
        }

        close(fd);

        /* call the command if user specified one, pass current filename as argument */
        if(command != NULL) {
            memset(buffer1, 0, sizeof(buffer1));

            /* buffer2 still contains the filename, pass it to the command as parameter */
            snprintf(buffer1, sizeof(buffer1), "%s \"%s\"", command, buffer2);
            DBG("calling command %s", buffer1);

            /* in addition provide the filename as environment variable */
            if((rc = setenv("MJPG_FILE", buffer2, 1)) != 0) {
                LOG("setenv failed (return value %d)\n", rc);
            }

            /* execute the command now */
            if((rc = system(buffer1)) != 0) {
                LOG("command failed (return value %d)\n", rc);
            }
        }

        /*
         * maintain ringbuffer
         * do not maintain ringbuffer for each picture, this saves ressources since
         * each run of the maintainance function involves sorting/malloc/free operations
         */
        if(ringbuffer_exceed <= 0) {
            /* keep ringbuffer excactly at specified size */
            maintain_ringbuffer(ringbuffer_size);
        } else if(counter == 1 || counter % (ringbuffer_exceed + 1) == 0) {
            DBG("counter: %llu, will clean-up now\n", counter);
            maintain_ringbuffer(ringbuffer_size);
        }

        /* if specified, wait now */
        if(delay > 0) {
            usleep(1000 * delay);
        }
		stop_num++;
		if (flags == 1)        //判断拍照的数量
		{
			if  ( stop_num > 9)
			{
				stop_num = 0;
				flags = 0;
			}
		}
		else if (flags == 2)
		{
			stop_num = 0;
			flags = 0;
		}


    }

    /* cleanup now */
    pthread_cleanup_pop(1);

    return NULL;
}

/*** plugin interface functions ***/
/******************************************************************************
Description.: this function is called first, in order to initialize
              this plugin and pass a parameter string
Input Value.: parameters
Return Value: 0 if everything is OK, non-zero otherwise
******************************************************************************/
int output_init(output_parameter *param)
{
	int i;
    delay = 0;

    param->argv[0] = OUTPUT_PLUGIN_NAME;

    /* show all parameters for DBG purposes */
    for(i = 0; i < param->argc; i++) {
        DBG("argv[%d]=%s\n", i, param->argv[i]);
    }

    reset_getopt();
    while(1) {
        int option_index = 0, c = 0;
        static struct option long_options[] = {
            {"h", no_argument, 0, 0
            },
            {"help", no_argument, 0, 0},
            {"f", required_argument, 0, 0},
            {"folder", required_argument, 0, 0},
            {"d", required_argument, 0, 0},
            {"delay", required_argument, 0, 0},
            {"s", required_argument, 0, 0},
            {"size", required_argument, 0, 0},
            {"e", required_argument, 0, 0},
            {"exceed", required_argument, 0, 0},
            {"c", required_argument, 0, 0},
            {"command", required_argument, 0, 0},
            {"m", required_argument, 0, 0},
            {"mjpeg", required_argument, 0, 0},
            {"i", required_argument, 0, 0},
            {"input", required_argument, 0, 0},
            {0, 0, 0, 0}
        };

        c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index);

        /* no more options to parse */
        if(c == -1) break;

        /* unrecognized option */
        if(c == '?') {
            help();
            return 1;
        }

        switch(option_index) {
            /* h, help */
        case 0:
        case 1:
            DBG("case 0,1\n");
            help();
            return 1;
            break;

            /* f, folder */
        case 2:
        case 3:
            DBG("case 2,3\n");
            folder = malloc(strlen(optarg) + 1);
            strcpy(folder, optarg);
            if(folder[strlen(folder)-1] == '/')
                folder[strlen(folder)-1] = '\0';
            break;

            /* d, delay */
        case 4:
        case 5:
            DBG("case 4,5\n");
            delay = atoi(optarg);
            break;

            /* s, size */
        case 6:
        case 7:
            DBG("case 6,7\n");
            ringbuffer_size = atoi(optarg);
            break;

            /* e, exceed */
        case 8:
        case 9:
            DBG("case 8,9\n");
            ringbuffer_exceed = atoi(optarg);
            break;

            /* c, command */
        case 10:
        case 11:
            DBG("case 10,11\n");
            command = strdup(optarg);
            break;
        case 12:
        case 13:
            DBG("case 12,13\n");
            input_number = atoi(optarg);
            break;
        }
    }

    pglobal = param->global;
    if(!(input_number < pglobal->incnt)) {
        OPRINT("ERROR: the %d input_plugin number is too much only %d plugins loaded\n", input_number, pglobal->incnt);
        return 1;
    }

    OPRINT("output folder.....: %s\n", folder);
    OPRINT("input plugin.....: %d: %s\n", input_number, pglobal->in[input_number].plugin);
    OPRINT("delay after save..: %d\n", delay);
    if(ringbuffer_size > 0) {
        OPRINT("ringbuffer size...: %d to %d\n", ringbuffer_size, ringbuffer_size + ringbuffer_exceed);
    } else {
        OPRINT("ringbuffer size...: %s\n", "no ringbuffer");
    }
    OPRINT("command...........: %s\n", (command == NULL) ? "disabled" : command);
    return 0;
}

/******************************************************************************
Description.: calling this function stops the worker thread
Input Value.: -
Return Value: always 0
******************************************************************************/
int output_stop(int id)
{
    DBG("will cancel worker thread\n");
    pthread_cancel(worker);
    return 0;
}

/******************************************************************************
Description.: calling this function creates and starts the worker thread
Input Value.: -
Return Value: always 0
******************************************************************************/
int output_run(int id)
{
    DBG("launching worker thread\n");
    pthread_create(&worker, 0, worker_thread, NULL);
    pthread_detach(worker);
    return 0;
}

int output_cmd(int plugin, unsigned int control_id, unsigned int group, int value)
{
    DBG("command (%d, value: %d) for group %d triggered for plugin instance #%02d\n", control_id, value, group, plugin);
    return 0;
}

2.修改后测试

先重新编译

make

在这里插入图片描述
如果出现make: Nothing to be done for ‘all’.那么先清理掉之前编译的内容,然后再编译

make clean
make

在这里插入图片描述
执行脚本文件start.sh

sudo ./start.sh 

重新打开一个终端来实现拍照功能
在这里插入图片描述
单拍

sudo echo one > /tmp/webcom 

连拍

echo danger > /tmp/webcom 

拍照保存的照片位于/www/pice
在这里插入图片描述

在这里插入图片描述
拍照成功,连拍时,由于我的电脑性能,及其网络环境,连拍太卡,实际连拍一次拍10多张,我这因配置没能体现。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
mjpg_streamer是一个开源的多线程实时流媒体服务器,可用于将应用程序产生的多种形式的视频流(如MJPEG,JPEG以及YUV等)转换为HTTP流的格式,可通过网络从任何支持流媒体的设备或程序进行接收和播放。LCD则是液晶显示屏的简称,它是一种常用的显示设备,可以在各种电子设备中使用。 mjpg_streamer可以与LCD配合使用,通过将LCD设备与mjpg_streamer服务器连接,我们可以将来自摄像头或其他视频源的实时图像流转发到LCD显示屏上,从而实现图像的实时显示。 使用mjpg_streamer连接LCD的具体步骤如下: 1. 配置mjpg_streamer服务器,确保其能够接收并处理来自摄像头或其他视频源的流数据。 2. 将LCD连接到计算机或嵌入式设备,确保其正常工作。 3. 在mjpg_streamer服务器的配置文件中,指定将视频流输出到LCD设备。 4. 启动mjpg_streamer服务器,开始传输视频流到LCD设备。 5. 在LCD设备上,显示传输过来的视频流。可以根据需要进行调整和优化。 通过将mjpg_streamer和LCD结合使用,可以实现在LCD设备上显示来自摄像头或其他视频源的实时图像流。这在监控系统、视讯会议、机器视觉等领域具有广泛应用,为用户提供了方便快捷的图像展示方式。同时,通过调整mjpg_streamer服务器和LCD设备的配置,还可以实现多种不同的显示效果和功能,满足用户的个性化需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦梨甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值