Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过execve/l WIN'在C程序上执行omxplayer;t在fork()之后的子进程上的非X控制台上输出视频_C_Linux_Video_Raspberry Pi_Execve - Fatal编程技术网

通过execve/l WIN'在C程序上执行omxplayer;t在fork()之后的子进程上的非X控制台上输出视频

通过execve/l WIN'在C程序上执行omxplayer;t在fork()之后的子进程上的非X控制台上输出视频,c,linux,video,raspberry-pi,execve,C,Linux,Video,Raspberry Pi,Execve,Hy 我试图通过execve或execl函数在C fork()之后对Raspberry Pi执行omxplayer(),这样我就可以为视频播放过程保存PID(这样系统就不会做这项工作)。如果我在X控制台/终端上执行程序,它可以工作,但如果通过标准终端(不启动X),它将运行,但不会将视频输出到屏幕上,如果在子进程上调用Exeve。顺便说一下,通过控制台中的“omxplayer…”命令执行播放器将播放视频并输出到屏幕。我对这类事情有点陌生,所以这是一种我无法解决或找到答案的情况。这里有人对如何解决这

Hy

我试图通过execve或execl函数在C fork()之后对Raspberry Pi执行omxplayer(),这样我就可以为视频播放过程保存PID(这样系统就不会做这项工作)。如果我在X控制台/终端上执行程序,它可以工作,但如果通过标准终端(不启动X),它将运行,但不会将视频输出到屏幕上,如果在子进程上调用Exeve。顺便说一下,通过控制台中的“omxplayer…”命令执行播放器将播放视频并输出到屏幕。我对这类事情有点陌生,所以这是一种我无法解决或找到答案的情况。这里有人对如何解决这个问题有想法,或者给我一个方向,让我找到一个可能的解决方案吗

注意:该代码只是一个execve调用,我知道它是正确的,因为在X中它工作得很好。

该调用为执行的程序提供了一个新的环境。为了让程序能够访问X显示屏,您需要至少保留某些环境变量--
display
。您是否无意中遗漏了新环境中的
显示

要使OMXPlayer在没有X的情况下工作,它必须能够访问视频设备本身(
/dev/video
,在本例中;有关详细信息,请参见第页)。它通常配置为允许
视频
组的所有成员访问它

您可以在程序中使用
popen(“id-Gn”,“r”)
来运行
id-Gn
命令,该命令列出了当前的组成员身份。(从文件句柄以字符串形式读取列表,然后使用
pclose()
将其关闭)如果列表不包含
video
,则问题在于运行原始程序的用户的权限不包括对视频设备的访问。解决方法很简单:将
视频
添加到用户所属的组中


下面是一个示例程序,
run.c
,用于说明
execvp()
的基本用法:

请注意,
run()
函数不会尝试检查命令是否实际执行;它只返回子进程PID,如果
fork()
失败,则返回
(PID_t)-1

许多实现,包括gnuclibrary
popen()
,都使用127退出状态作为执行失败的指示。也就是说,它不是由本应执行的命令返回,而是由子进程返回,因为命令执行失败。上面的
run()
也会这样做


您可以在
run()
函数中的父进程和子进程之间使用close-on-exec管道,让父进程知道子进程是否成功启动了所需的命令,如果没有,原因是什么。然后,父进程还可以立即获取不存在的子进程。这使得调用者在出现错误时几乎不需要额外的努力,因此我个人强烈推荐这种方法。下面是一个示例实现:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>

/* Helper function: Close file descriptor, without modifying errno.
 * Returns 0 if successful, otherwise the errno reported by close().
*/
static int closefd(const int fd)
{
    int saved_errno, result;

    /* Invalid descriptor? */
    if (fd == -1)
        return EINVAL;

    /* Save errno. It's thread-local, so as long as we restore
     * it before returning, no-one will notice any change in it. */
    saved_errno = errno;

    /* Close descriptor, and save errno (or 0) in result. */
    do {
        result = close(fd);
    } while (result == -1 && errno == EINTR);
    if (result == -1)
        result = errno;
    else
        result = 0;

    /* Restore errno. Done. */
    errno = saved_errno;

    return result;
}

/* Helper function: Create a close-on-exec pipe.
 * Return 0 if success, errno otherwise.
*/
int close_on_exec_pipe(int fds[2])
{
    int result;

    result = pipe(fds);
    if (result == -1) {
        fds[0] = -1;
        fds[1] = -1;
        return errno;
    }

    do {

        do {
            result = fcntl(fds[0], F_SETFD, FD_CLOEXEC);
        } while (result == -1 && errno == EINTR);
        if (result == -1)
            break;

        do {
            result = fcntl(fds[1], F_SETFD, FD_CLOEXEC);
        } while (result == -1 && errno == EINTR);
        if (result == -1)
            break;

        /* Success. */
        return 0;

    } while (0);

    /* Failed. */
    closefd(fds[0]);
    closefd(fds[1]);
    fds[0] = -1;
    fds[1] = -1;

    return errno;
}

/* Run an external command in a child process.
 * command[0] is the path or name of the command,
 * and the array must be terminated with a NULL.
 *
 * If successful, this function will return the PID
 * of the child process. Otherwise, it will return
 * (pid_t)-1, with errno indicating the error.
*/
pid_t run(char *const command[])
{
    pid_t   child, p;
    int     commfd[2], errcode;

    /* Create a close-on-exec pipe between the parent and child. */
    if (close_on_exec_pipe(commfd))
        return (pid_t)-1;

    /* Fork the new child process. */
    child = fork();
    if (child == (pid_t)-1) {
        closefd(commfd[0]);
        closefd(commfd[1]);
        return (pid_t)-1;
    }

    if (!child) {
        /* Child process: */

        /* Close the read/parent end of the pipe. */
        closefd(commfd[0]);

        /* In case of C library bugs, prepare errno. */
        errno = EINVAL;

        /* Execute the desired command. */
        execvp(command[0], command);

        /* Failed. errno describes why. */
        errcode = errno;

        /* Send it to the parent via the pipe. */
        {
            const char       *p = (char *)&errcode;
            const char *const q = (char *)&errcode + sizeof errcode;
            ssize_t           n;

            while (p < q) {
                n = write(commfd[1], p, (size_t)(q - p));
                if (n > (ssize_t)0)
                    p += n;
                else
                if (n != (ssize_t)-1)
                    break;
                else
                if (errno != EINTR)
                    break;
            }
        }

        /* Close write/child end of the pipe. */
        closefd(commfd[1]);

        /* Exit with a failure (127). */
        _exit(127);
    }

    /* Parent: */

    /* Close the write/child end of the pipe. */
    closefd(commfd[1]);

    /* Try to read the execution error. */
    {
        char       *p = (char *)&errcode;
        char *const q = (char *)&errcode + sizeof errcode;
        ssize_t     n;

        errcode = 0;

        while (p < q) {
            n = read(commfd[0], p, (size_t)(q - p));
            if (n > (ssize_t)0)
                p += n;
            else
            if (n != (ssize_t)-1)
                break; /* n == 0 is pipe closed */
            else
            if (errno != EINTR)
                break;
        }

        /* Close the read/parent end of the pipe. */
        closefd(commfd[0]);

        /* Pipe closed (on exec), no data read? */
        if (n == (ssize_t)0 && p == (char *)&errcode) {
            /* Yes, success! */
            errno = 0;
            return child;
        }

        /* Execution failed.
         * If we didn't get the reason, use EINVAL. */
        if (!errcode || p != q)
            errcode = EINVAL;
    }

    /* Reap the child process. */
    do {
        p = waitpid(child, NULL, 0);
        if (p == (pid_t)-1) {
            if (errno == EINTR)
                continue;
            else
                break;
        }
    } while (p != child);

    /* Return with failure. */
    errno = errcode;
    return (pid_t)-1;
}
根据Phidgets RFID示例,标记和标记丢失处理程序是

int CCONV TagHandler(CPhidgetRFIDHandle RFID, void *usrptr, char *TagVal, CPhidgetRFID_Protocol proto)
{
    return add_event(RFID, proto, RFID_TAG_READ, TagVal, usrptr);
}

int CCONV TagLostHandler(CPhidgetRFIDHandle RFID, void *usrptr, char *TagVal, CPhidgetRFID_Protocol proto)
{
    return add_event(RFID, proto, RFID_TAG_LOST, TagVal, usrptr);
}
您不必在所有设置完成后等待按键,而是创建一个循环,如

    pid_t         child = (pid_t)-1; /* Not running */
    pid_t         p;
    rfid_event_t *event;

    /* Infinite loop */
    while (1) {

        /* Do we have a player child process? */
        if (child != (pid_t)-1) {

            /* Yes. Has it exited yet? */
            p = waitpid(child, NULL, WNOHANG);
            if (p == child) {
                /* Yes. No more player. */
                child == (pid_t)-1;
            }
        }

        /* Check for a new event.
         * If we have a child, only wait one second only
         * for the event; otherwise, wait up to 30 secs.
        */
        if (child == (pid_t)-1)
            event = get_event(30L);
        else
            event = get_event(1L);

        /* If no event yet, start at the beginning of the loop. */
        if (!event)
            continue;

        /*
         * TODO: Handle the event.
         *       You can stop the existing player via e.g.
         *       if (child != (pid_t)-1)
         *           kill(child, SIGKILL);
         *       and then start a new one.
        */

        /* Discard the event. It's dynamically allocated. */
        free(event);
    }
如果启动播放器,上面的循环会检测到它在一秒钟内没有播放。如果没有播放器在运行,那么循环可以等待RFID信号,等待时间可以任意长——我用了30秒。

调用为执行的程序提供了一个新的环境。为了让程序能够访问X显示屏,您需要至少保留某些环境变量--
display
。您是否无意中遗漏了新环境中的
显示

要使OMXPlayer在没有X的情况下工作,它必须能够访问视频设备本身(
/dev/video
,在本例中;有关详细信息,请参见第页)。它通常配置为允许
视频
组的所有成员访问它

您可以在程序中使用
popen(“id-Gn”,“r”)
来运行
id-Gn
命令,该命令列出了当前的组成员身份。(从文件句柄以字符串形式读取列表,然后使用
pclose()
将其关闭)如果列表不包含
video
,则问题在于运行原始程序的用户的权限不包括对视频设备的访问。解决方法很简单:将
视频
添加到用户所属的组中


下面是一个示例程序,
run.c
,用于说明
execvp()
的基本用法:

请注意,
run()
函数不会尝试检查命令是否实际执行;它只返回子进程PID,如果
fork()
失败,则返回
(PID_t)-1

许多实现,包括gnuclibrary
popen()
,都使用127退出状态作为执行失败的指示。也就是说,它不是由本应执行的命令返回,而是由子进程返回,因为命令执行失败。上面的
run()
也会这样做


您可以在
run()
函数中的父进程和子进程之间使用close-on-exec管道,让父进程知道子进程是否成功启动了所需的命令,如果没有,原因是什么。然后,父进程还可以立即获取不存在的子进程。这使得调用者在出现错误时几乎不需要额外的努力,因此我个人强烈推荐这种方法。下面是一个示例实现:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>

/* Helper function: Close file descriptor, without modifying errno.
 * Returns 0 if successful, otherwise the errno reported by close().
*/
static int closefd(const int fd)
{
    int saved_errno, result;

    /* Invalid descriptor? */
    if (fd == -1)
        return EINVAL;

    /* Save errno. It's thread-local, so as long as we restore
     * it before returning, no-one will notice any change in it. */
    saved_errno = errno;

    /* Close descriptor, and save errno (or 0) in result. */
    do {
        result = close(fd);
    } while (result == -1 && errno == EINTR);
    if (result == -1)
        result = errno;
    else
        result = 0;

    /* Restore errno. Done. */
    errno = saved_errno;

    return result;
}

/* Helper function: Create a close-on-exec pipe.
 * Return 0 if success, errno otherwise.
*/
int close_on_exec_pipe(int fds[2])
{
    int result;

    result = pipe(fds);
    if (result == -1) {
        fds[0] = -1;
        fds[1] = -1;
        return errno;
    }

    do {

        do {
            result = fcntl(fds[0], F_SETFD, FD_CLOEXEC);
        } while (result == -1 && errno == EINTR);
        if (result == -1)
            break;

        do {
            result = fcntl(fds[1], F_SETFD, FD_CLOEXEC);
        } while (result == -1 && errno == EINTR);
        if (result == -1)
            break;

        /* Success. */
        return 0;

    } while (0);

    /* Failed. */
    closefd(fds[0]);
    closefd(fds[1]);
    fds[0] = -1;
    fds[1] = -1;

    return errno;
}

/* Run an external command in a child process.
 * command[0] is the path or name of the command,
 * and the array must be terminated with a NULL.
 *
 * If successful, this function will return the PID
 * of the child process. Otherwise, it will return
 * (pid_t)-1, with errno indicating the error.
*/
pid_t run(char *const command[])
{
    pid_t   child, p;
    int     commfd[2], errcode;

    /* Create a close-on-exec pipe between the parent and child. */
    if (close_on_exec_pipe(commfd))
        return (pid_t)-1;

    /* Fork the new child process. */
    child = fork();
    if (child == (pid_t)-1) {
        closefd(commfd[0]);
        closefd(commfd[1]);
        return (pid_t)-1;
    }

    if (!child) {
        /* Child process: */

        /* Close the read/parent end of the pipe. */
        closefd(commfd[0]);

        /* In case of C library bugs, prepare errno. */
        errno = EINVAL;

        /* Execute the desired command. */
        execvp(command[0], command);

        /* Failed. errno describes why. */
        errcode = errno;

        /* Send it to the parent via the pipe. */
        {
            const char       *p = (char *)&errcode;
            const char *const q = (char *)&errcode + sizeof errcode;
            ssize_t           n;

            while (p < q) {
                n = write(commfd[1], p, (size_t)(q - p));
                if (n > (ssize_t)0)
                    p += n;
                else
                if (n != (ssize_t)-1)
                    break;
                else
                if (errno != EINTR)
                    break;
            }
        }

        /* Close write/child end of the pipe. */
        closefd(commfd[1]);

        /* Exit with a failure (127). */
        _exit(127);
    }

    /* Parent: */

    /* Close the write/child end of the pipe. */
    closefd(commfd[1]);

    /* Try to read the execution error. */
    {
        char       *p = (char *)&errcode;
        char *const q = (char *)&errcode + sizeof errcode;
        ssize_t     n;

        errcode = 0;

        while (p < q) {
            n = read(commfd[0], p, (size_t)(q - p));
            if (n > (ssize_t)0)
                p += n;
            else
            if (n != (ssize_t)-1)
                break; /* n == 0 is pipe closed */
            else
            if (errno != EINTR)
                break;
        }

        /* Close the read/parent end of the pipe. */
        closefd(commfd[0]);

        /* Pipe closed (on exec), no data read? */
        if (n == (ssize_t)0 && p == (char *)&errcode) {
            /* Yes, success! */
            errno = 0;
            return child;
        }

        /* Execution failed.
         * If we didn't get the reason, use EINVAL. */
        if (!errcode || p != q)
            errcode = EINVAL;
    }

    /* Reap the child process. */
    do {
        p = waitpid(child, NULL, 0);
        if (p == (pid_t)-1) {
            if (errno == EINTR)
                continue;
            else
                break;
        }
    } while (p != child);

    /* Return with failure. */
    errno = errcode;
    return (pid_t)-1;
}
根据Phidgets RFID示例,标记和标记丢失处理程序是

int CCONV TagHandler(CPhidgetRFIDHandle RFID, void *usrptr, char *TagVal, CPhidgetRFID_Protocol proto)
{
    return add_event(RFID, proto, RFID_TAG_READ, TagVal, usrptr);
}

int CCONV TagLostHandler(CPhidgetRFIDHandle RFID, void *usrptr, char *TagVal, CPhidgetRFID_Protocol proto)
{
    return add_event(RFID, proto, RFID_TAG_LOST, TagVal, usrptr);
}
您不必在所有设置完成后等待按键,而是创建一个循环,如

    pid_t         child = (pid_t)-1; /* Not running */
    pid_t         p;
    rfid_event_t *event;

    /* Infinite loop */
    while (1) {

        /* Do we have a player child process? */
        if (child != (pid_t)-1) {

            /* Yes. Has it exited yet? */
            p = waitpid(child, NULL, WNOHANG);
            if (p == child) {
                /* Yes. No more player. */
                child == (pid_t)-1;
            }
        }

        /* Check for a new event.
         * If we have a child, only wait one second only
         * for the event; otherwise, wait up to 30 secs.
        */
        if (child == (pid_t)-1)
            event = get_event(30L);
        else
            event = get_event(1L);

        /* If no event yet, start at the beginning of the loop. */
        if (!event)
            continue;

        /*
         * TODO: Handle the event.
         *       You can stop the existing player via e.g.
         *       if (child != (pid_t)-1)
         *           kill(child, SIGKILL);
         *       and then start a new one.
        */

        /* Discard the event. It's dynamically allocated. */
        free(event);
    }
如果启动播放器,上面的循环检测到它没有播放