如何在ffmpeg中捕获stdout流,然后将其导管到v4l2loopback [英] How to catch stdout stream in ffmpeg then pipe it to v4l2loopback

查看:597
本文介绍了如何在ffmpeg中捕获stdout流,然后将其导管到v4l2loopback的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将我的h264流管道传输到ffmpeg,然后再管理到我的v4l2loopback设备。问题是我对linux来说是相当新鲜的,所以只是不能让它工作。
流可以输出到stdout,但我不知道如何用ffmpeg再次捕获它,然后再次将其传输到我的v4l2loopback设备。有没有人知道如何做到这一点,或者可能指出如何解决它?



这是捕获程序:



PS!您可以在代码底部找到捕获程序的选项。

  / * 
* V4L2视频捕获示例,由Derek Molloy修改为Logitech C920相机
*修改,添加-F模式为H264捕获和相关帮助详细信息
* www.derekmolloy.ie
*
* V4L2视频捕获示例
*
*此程序可以无限制地使用和分发。
*
*此程序随V4L2 API一起提供
*有关详细信息,请参阅http://linuxtv.org/docs.php
* /

#include< stdio.h>
#include< stdlib.h>
#include< string.h>
#include< assert.h>

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

#include< fcntl.h> / *低级别i / o * /
#include< unistd.h>
#include< errno.h>
#include< sys / stat.h>
#include< sys / types.h>
#include< sys / time.h>
#include< sys / mman.h>
#include< sys / ioctl.h>

#include< linux / videodev2.h>

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

枚举io_method {
IO_METHOD_READ,
IO_METHOD_MMAP,
IO_METHOD_USERPTR,
};

struct buffer {
void * start;
size_t length;
};

static char * dev_name;
static enum io_method io = IO_METHOD_MMAP;
static int fd = -1;
struct buffer * buffers;
static unsigned int n_buffers;
static int out_buf;
static int force_format = 0;
static int frame_count = 100;

static void errno_exit(const char * s)
{
fprintf(stderr,%s error%d,%s\\\
,s,errno,strerror错误号));
exit(EXIT_FAILURE);
}

static int xioctl(int fh,int request,void * arg)
{
int r;

do {
r = ioctl(fh,request,arg);
} while(-1 == r&& EINTR == errno);

return r;


static void process_image(const void * p,int size)
{
if(out_buf)
fwrite(p,size,1,标准输出);

fflush(stderr);
fprintf(stderr,。);
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)){
开关(errno){
case EAGAIN:
return 0;

case EIO:
/ *可以忽略EIO,请参阅规格。 * /

/ * fall through * /

default:
errno_exit(read);
}
}

process_image(buffers [0] .start,buffers [0] .length);
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:
/ *可以忽略EIO,请参阅规格。 * /

/ * fall through * /

default:
errno_exit(VIDIOC_DQBUF);
}
}

assert(buf.index< n_buffers);

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

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:
/ *可以忽略EIO,请参阅规格。 * /

/ * 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);

process_image((void *)buf.m.userptr,buf.bytesused);

if(-1 == xioctl(fd,VIDIOC_QBUF,& buf))
errno_exit(VIDIOC_QBUF);
break;
}

return 1;
}

static void mainloop(void)
{
unsigned int count;
unsigned int loopIsInfinite = 0;

if(frame_count == 0)loopIsInfinite = 1; //无限循环
count = frame_count;

while((count--> 0)|| loopIsInfinite){
for(;;){
fd_set fds;
struct timeval tv;
int r;

FD_ZERO(& fds);
FD_SET(fd,& fds);

/ *超时。 * /
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\\\
);
exit(EXIT_FAILURE);
}

if(read_frame())
break;
/ * EAGAIN - 继续选择循环。 * /
}
}
}

static void stop_capturing(void)
{
enum v4l2_buf_type type;

switch(io){
case IO_METHOD_READ:
/ *无关紧要* /
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;
枚举v4l2_buf_type类型;

switch(io){
case IO_METHOD_READ:
/ *无关紧要* /
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\\\
);
exit(EXIT_FAILURE);
}

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

if(!buffers [0] .start){
fprintf(stderr,Out of memory\\\
);
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不支持
内存映射\,dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit(VIDIOC_REQBUFS);
}
}

if(req.count< 2){
fprintf(stderr,%s\\\
上的缓冲区不足,
dev_name);
exit(EXIT_FAILURE);
}

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

if(!buffers){
fprintf(stderr,Out of memory\\\
);
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 / *从任何地方开始* /,
buf.length,
PROT_READ | PROT_WRITE / *必需* /,
MAP_SHARED / *推荐* /,
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;

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不支持
用户指针i / o\\\
,dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit(VIDIOC_REQBUFS);
}
}

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

if(!buffers){
fprintf(stderr,Out of memory\\\
);
exit(EXIT_FAILURE);
}

(n_buffers = 0; n_buffers< 4; ++ n_buffers){
buffers [n_buffers] .length = buffer_size;
buffers [n_buffers] .start = malloc(buffer_size);

if(!buffers [n_buffers] .start){
fprintf(stderr,Out of memory\\\
);
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否V4L2 device\\\

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\\\

dev_name);
exit(EXIT_FAILURE);
}

switch(io){
case IO_METHOD_READ:
if(!(cap.capabilities& V4L2_CAP_READWRITE)){
fprintf(stderr, %s不支持读取i / o\\\

dev_name);
exit(EXIT_FAILURE);
}
break;

case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
if(!(cap.capabilities& V4L2_CAP_STREAMING)){
fprintf(stderr,%s不支持流i / o\\\

dev_name);
exit(EXIT_FAILURE);
}
break;
}


/ *选择视频输入,视频标准并在此调整。 * /


CLEAR(cropcap);

cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(0 == xioctl(fd,VIDIOC_CROPCAP,& cropcap)){
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; / * reset to default * /

if(-1 == xioctl(fd,VIDIOC_S_CROP,& crop)){
switch(errno){
case EINVAL:
/ *裁剪不支持。 * /
break;
默认值:
/ *忽略错误。 * /
break;
}
}
} else {
/ *错误忽略。 * /
}


CLEAR(fmt);

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fprintf(stderr,强制格式%d\\\
,force_format);
if(force_format){
if(force_format == 2){
fmt.fmt.pix.width = 1920;
fmt.fmt.pix.height = 1080;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
}
else if(force_format == 1){
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
}

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

/ *注意VIDIOC_S_FMT可能会更改宽度和高度。 * /
} else {
/ *保留由v4l2-ctl设置的原始设置,例如* /
if(-1 == xioctl(fd,VIDIOC_G_FMT,& fmt))
errno_exit(VIDIOC_G_FMT);
}

/ *越野车司机偏执狂。 * /
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;

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 关);

fd = -1;
}

static void open_device(void)
{
struct stat st;

if(-1 == stat(dev_name,& st)){
fprintf(stderr,无法识别'%s':%d,%s\\\

dev_name,errno,strerror(errno));
exit(EXIT_FAILURE);
}

if(!S_ISCHR(st.st_mode)){
fprintf(stderr,%s is no device\\\
,dev_name);
exit(EXIT_FAILURE);
}

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

如果(-1 == fd){
fprintf(stderr,无法打开'%s':%d,%s\\\

dev_name,errno ,strerror(errno));
exit(EXIT_FAILURE);
}
}

static void usage(FILE * fp,int argc,char ** argv)
{
fprintf(fp,
用法:%s [options] \\\
\\\

版本1.3\\\

选项:\\\

-d | - 设备名称视频设备名称[%s] \\\

-h | --help打印此消息\
-m | --mmap使用内存映射缓冲区[default] \\\

-r | --read使用read()calls\\\

-u | --userp使用应用程序分配的buffers \
-o | - 输出将流输出到stdout\\\

-f | - 格式强制格式为640x480 YUYV\\\

-F | --formatH264强制格式为1920x1080 H264\\\

-c | --count要抓取的帧数[%i] - 对于无穷大使用0
\\\

示例用法:capture -F -o -c 300> output.raw\\\

在1920x1080捕获300帧H264 - 使用raw2mpg4脚本转换为mpg4\\\

argv [0],dev_name,frame_count);
}

static const char short_options [] =d:hmruofFc:;

static const struct option
long_options [] = {
{设备,required_argument,NULL,'d'},
{help,no_argument,NULL,'h'},
{mmap,no_argument,NULL,'m'},
{read,no_argument,NULL,'r'},
{userp,no_argument,NULL,'u'},
{output,no_argument,NULL,'o' },
{format,no_argument,NULL,'f'},
{formatH264,no_argument,NULL,'F'},
{count,required_argument,NULL ,'c'},
{0,0,0,0}
};

int main(int argc,char ** argv)
{
dev_name =/ dev / video0;

for(;;){
int idx;
int c;

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

if(-1 == c)
break;

switch(c){
case 0:/ * getopt_long()flag * /
break;

case'd':
dev_name = optarg;
break;

case'h':
用法(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;

case'o':
out_buf ++;
break;

case'f':
force_format = 1;
break;

case'F':
force_format = 2;
break;

case'c':
errno = 0;
frame_count = strtol(optarg,NULL,0);
if(errno)
errno_exit(optarg);
break;

默认值:
用法(stderr,argc,argv);
exit(EXIT_FAILURE);
}
}

open_device();
init_device();
start_capturing();
mainloop();
stop_capturing();
uninit_device();
close_device();
fprintf(stderr,\\\
);
return 0;
}

这是V4L2视频捕获示例的修改版本。
然后我知道如果我已经将streame输出到一个文件,我将不得不运行此命令将原始格式转换为mp4格式:

  ffmpeg -f h264 -i output.raw -vcodec copy output.mp4 

我使用的v4l2loopback程序是foud这里:
https://github.com/umlaeute/ v4l2loopback



------------------更新----------- -------



好的。所以我从捕获程序的管道到ffmpeg工作。它捕获,解码h264,我可以使用以下命令将其写入mp4文件:



./ capture -F -d / dev / video0 -o | ffmpeg -f h264 -i - -vcodec copy out.mp4



现在我试图让最后一个管道使用这个命令: / p>

  ./ capture -F -d / dev / video0 -o | ffmpeg -f h264 -i  -  -vcodec copy -f mp4  -  | gst-launch-0.10 -v fdsrc! v4l2sink device = / dev / video3 

我收到以下错误:




  • muxer不支持不可寻求输出

  • 无法为输出文件#0写入头(编码错误参数不正确):无效参数



任何想法?

解决方案

在你的最后一个命令中,你正在向GStreamer发送一个 MP4 。请参阅 -f mp4 - 部分:



./ capture -F -d / dev / video0 -o | ffmpeg -f h264 -i - -vcodec copy -f mp4 - | gst-launch-0.10 -v fdsrc! v4l2sink device = / dev / video3



你想要做的是管理 H.264



事实上,你可能完全可以跳过MP4的创建,只需执行以下操作:



./ capture -F -d / dev / video0 -o | gst-launch-0.10 -v fdsrc! v4l2sink device = / dev / video3



因为 -F 264。


I'm trying to pipe my h264 stream to ffmpeg and then to my v4l2loopback device. Problem is that I'm fairly new to linux, so just can't get it working. The stream can be outputted to stdout, but I do not know how to catch it again with ffmpeg and then again pipe it to my v4l2loopback device.

Does anybody know how this could be done or maybe a pointer on how to solve it?

This is the capture program:

PS! You can find the options for the capture program almost in the bottom of the code.

/*
 *  V4L2 video capture example, modified by Derek Molloy for the Logitech C920 camera
 *  Modifications, added the -F mode for H264 capture and associated help detail
 *  www.derekmolloy.ie
 *
 *  V4L2 video capture example
 *
 *  This program can be used and distributed without restrictions.
 *
 *      This program is provided with the V4L2 API
 * see http://linuxtv.org/docs.php for more information
 */

#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 <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <linux/videodev2.h>

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

enum io_method {
        IO_METHOD_READ,
        IO_METHOD_MMAP,
        IO_METHOD_USERPTR,
};

struct buffer {
        void   *start;
        size_t  length;
};

static char            *dev_name;
static enum io_method   io = IO_METHOD_MMAP;
static int              fd = -1;
struct buffer          *buffers;
static unsigned int     n_buffers;
static int              out_buf;
static int              force_format = 0;
static int              frame_count = 100;

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 fh, int request, void *arg)
{
        int r;

        do {
                r = ioctl(fh, request, arg);
        } while (-1 == r && EINTR == errno);

        return r;
}

static void process_image(const void *p, int size)
{
        if (out_buf)
                fwrite(p, size, 1, stdout);

        fflush(stderr);
        fprintf(stderr, ".");
        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");
                        }
                }

                process_image(buffers[0].start, buffers[0].length);
                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);

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

                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);

                process_image((void *)buf.m.userptr, buf.bytesused);

                if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
                        errno_exit("VIDIOC_QBUF");
                break;
        }

        return 1;
}

static void mainloop(void)
{
        unsigned int count;
    unsigned int loopIsInfinite = 0;

        if (frame_count == 0) loopIsInfinite = 1; //infinite loop
    count = frame_count;

        while ((count-- > 0) || loopIsInfinite) {
                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;

        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 = malloc(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;
        }


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


        CLEAR(cropcap);

        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                crop.c = cropcap.defrect; /* reset to default */

                if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
                        switch (errno) {
                        case EINVAL:
                                /* Cropping not supported. */
                                break;
                        default:
                                /* Errors ignored. */
                                break;
                        }
                }
        } else {
                /* Errors ignored. */
        }


        CLEAR(fmt);

        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fprintf(stderr, "Force Format %d\n", force_format);
        if (force_format) {
        if (force_format==2){
                    fmt.fmt.pix.width       = 1920;     
                fmt.fmt.pix.height      = 1080;  
            fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
                    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
        }
        else if(force_format==1){
            fmt.fmt.pix.width   = 640;
            fmt.fmt.pix.height  = 480;
            fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
            fmt.fmt.pix.field   = V4L2_FIELD_INTERLACED;
        }

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

                /* Note VIDIOC_S_FMT may change width and height. */
        } else {
                /* Preserve original settings as set by v4l2-ctl for example */
                if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
                        errno_exit("VIDIOC_G_FMT");
        }

        /* 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;

        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"
                 "Version 1.3\n"
                 "Options:\n"
                 "-d | --device name   Video device name [%s]\n"
                 "-h | --help          Print this message\n"
                 "-m | --mmap          Use memory mapped buffers [default]\n"
                 "-r | --read          Use read() calls\n"
                 "-u | --userp         Use application allocated buffers\n"
                 "-o | --output        Outputs stream to stdout\n"
                 "-f | --format        Force format to 640x480 YUYV\n"
         "-F | --formatH264    Force format to 1920x1080 H264\n"
                 "-c | --count         Number of frames to grab [%i] - use 0 for infinite\n"
                 "\n"
         "Example usage: capture -F -o -c 300 > output.raw\n"
         "Captures 300 frames of H264 at 1920x1080 - use raw2mpg4 script to convert to mpg4\n",
                 argv[0], dev_name, frame_count);
}

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

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' },
        { "output", no_argument,       NULL, 'o' },
        { "format", no_argument,       NULL, 'f' },
    { "formatH264", no_argument,   NULL, 'F' },
        { "count",  required_argument, NULL, 'c' },
        { 0, 0, 0, 0 }
};

int main(int argc, char **argv)
{
        dev_name = "/dev/video0";

        for (;;) {
                int idx;
                int c;

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

                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;

                case 'o':
                        out_buf++;
                        break;

                case 'f':
                        force_format=1;
                        break;

        case 'F':
            force_format=2;
            break;

                case 'c':
                        errno = 0;
                        frame_count = strtol(optarg, NULL, 0);
                        if (errno)
                                errno_exit(optarg);
                        break;

                default:
                        usage(stderr, argc, argv);
                        exit(EXIT_FAILURE);
                }
        }

        open_device();
        init_device();
        start_capturing();
        mainloop();
        stop_capturing();
        uninit_device();
        close_device();
        fprintf(stderr, "\n");
        return 0;
}

It's a modified version of a V4L2 video capture example. Then I know that if I have outputed the streame to a file I would have to run this command to convert the raw format to mp4 format:

ffmpeg -f h264 -i output.raw -vcodec copy output.mp4

And the v4l2loopback program I'm using is foud here: https://github.com/umlaeute/v4l2loopback

------------------Update------------------

Okay. So I got the pipe from the capture program to ffmpeg working. It captures, decodes the h264 and I can write it to a mp4 file with this command:

./capture -F -d /dev/video0 -o | ffmpeg -f h264 -i - -vcodec copy out.mp4

Now I am trying to get the last pipe working with this command:

./capture -F -d /dev/video0 -o | ffmpeg -f h264 -i - -vcodec copy -f mp4 - | gst-launch-0.10 -v fdsrc ! v4l2sink device=/dev/video3

I get these errors:

  • muxer does not support non seekable output
  • Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument

Any ideas?

解决方案

In your last command you are piping an MP4 to GStreamer. See the -f mp4 - part:

./capture -F -d /dev/video0 -o | ffmpeg -f h264 -i - -vcodec copy -f mp4 - | gst-launch-0.10 -v fdsrc ! v4l2sink device=/dev/video3

What you want to do is pipe the H.264 stream inside the MP4 instead.

Try replacing -f mp4 - with -f h264 -.

In fact you could probably skip entirely the creation of an MP4 and just do:

./capture -F -d /dev/video0 -o | gst-launch-0.10 -v fdsrc ! v4l2sink device=/dev/video3

since the -F option forces H.264.

这篇关于如何在ffmpeg中捕获stdout流,然后将其导管到v4l2loopback的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆