打印
[i.MX]

mxc_v4l2_capture和mxc_v4l2_output不能一起用,有人碰到过吗?

[复制链接]
9303|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wsk311728|  楼主 | 2014-6-24 17:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
有人将mxc_v4l2_capture和mxc_v4l2_output结合用过吗
这是我的代码,单独cature或output都没有问题,怎么结合在一起就出问题了呢?
/* Standard Include Files */
#include <errno.h>

/* Verification Test Environment Include Files */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <string.h>
#include <malloc.h>

#include <linux/mxcfb.h>
#include <linux/mxc_v4l2.h>
#include <linux/ipu.h>

#define DISPLAY
//#define        ONLY_DISPLAY
#define CAPTURE


#define TEST_BUFFER_NUM 4
#define PASS    0
#define FAIL    -1

struct testbuffer
{
    unsigned char *start;
    size_t offset;
    unsigned int length;
};

struct testbuffer capture_buffers[TEST_BUFFER_NUM];
struct testbuffer display_buffers[TEST_BUFFER_NUM];

int capture_in_width = 640;
int capture_in_height = 480;
int capture_in_top = 0;
int capture_in_left = 0;
int capture_out_width = 640;
int capture_out_height = 480;
#ifdef ONLY_DISPLAY
int display_in_width = 640;//352;
int display_in_height = 480;//288;
#else
int display_in_width = 640;
int display_in_height = 480;
#endif
int display_out_width = 1024;
int display_out_height = 768;
int display_out_top = 0;
int display_out_left = 0;
int capture_count = 100;
int capture_input = 0;
int camera_framerate = 30;
int capture_fmt = V4L2_PIX_FMT_YUV420;
int display_fmt = V4L2_PIX_FMT_YUV420;

int mem_mmap_type = V4L2_MEMORY_MMAP;
int g_num_buffers = 0;
int capture_mode = 0;

int capture_frame_size;

char capture_device[100] = "/dev/video0";
char display_device[100] = "/dev/video17";

FILE * fd_file = 0;

int fd_capture = 0;
int fd_display = 0;


int capture_open(void)
{
    if ((fd_capture = open(capture_device, O_RDWR, 0)) < 0)
    {
        printf("Unable to open %s\n", capture_device);
        return FAIL;
    }
    return PASS;
}

int display_open(void)
{
    if ((fd_display = open(display_device, O_RDWR, 0)) < 0)
    {
        printf("Unable to open %s\n", display_device);
        return FAIL;
    }

    return PASS;
}

static void print_pixelformat(char *prefix, int val)
{
    printf("%s: %c%c%c%c\n", prefix ? prefix : "pixelformat",
           val & 0xff,
           (val >> 8) & 0xff,
           (val >> 16) & 0xff,
           (val >> 24) & 0xff);
}

int capture_set(void)
{
    struct v4l2_dbg_chip_ident chip;
    struct v4l2_frmsizeenum fsize;
    struct v4l2_fmtdesc ffmt;
    struct v4l2_streamparm parm;
    struct v4l2_crop crop;
    struct v4l2_format fmt;

    if (ioctl(fd_capture, VIDIOC_DBG_G_CHIP_IDENT, &chip))//获取摄像头名字
    {
        printf("VIDIOC_DBG_G_CHIP_IDENT failed.\n");
        return FAIL;
    }
    printf("sensor chip is %s\n", chip.match.name);

    printf("sensor supported frame size:\n");
    fsize.index = 0;
    while (ioctl(fd_capture, VIDIOC_ENUM_FRAMESIZES, &fsize) >= 0)// 枚举所有帧大小(即像素宽度和高度),给定像素的设备支持的格式。
    {
        printf(" %dx%d\n", fsize.discrete.width,
               fsize.discrete.height);
        fsize.index++;
    }

    ffmt.index = 0;
    while (ioctl(fd_capture, VIDIOC_ENUM_FMT, &ffmt) >= 0) //获取当前驱动支持的视频格式
    {
        print_pixelformat("sensor frame format", ffmt.pixelformat);
        ffmt.index++;
    }

    parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    parm.parm.capture.timeperframe.numerator = 1;
    parm.parm.capture.timeperframe.denominator = camera_framerate;
    parm.parm.capture.capturemode = capture_mode;

    if (ioctl(fd_capture, VIDIOC_S_PARM, &parm) < 0)    //设置Stream信息。如帧数等。
    {
        printf("VIDIOC_S_PARM failed\n");
        return FAIL;
    }

    if (ioctl(fd_capture, VIDIOC_S_INPUT, &capture_input) < 0)//选择视频输入
    {
        printf("VIDIOC_S_INPUT failed\n");
        return FAIL;
    }

    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd_capture, VIDIOC_G_CROP, &crop) < 0) //读取视频信号的边框
    {
        printf("VIDIOC_G_CROP failed\n");
        return FAIL;
    }

    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c.width = capture_in_width;
    crop.c.height = capture_in_height;
    crop.c.top = capture_in_top;
    crop.c.left = capture_in_left;
    if (ioctl(fd_capture, VIDIOC_S_CROP, &crop) < 0) //设置视频信号的边框
    {
        printf("VIDIOC_S_CROP failed\n");
        return FAIL;
    }

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat = capture_fmt;
    fmt.fmt.pix.width = capture_out_width;
    fmt.fmt.pix.height = capture_out_height;
    fmt.fmt.pix.bytesperline = capture_out_width;
    fmt.fmt.pix.priv = 0;
    fmt.fmt.pix.sizeimage = 0;


    if (ioctl(fd_capture, VIDIOC_S_FMT, &fmt) < 0) //设置捕获格式
    {
        printf("set format failed\n");
        return FAIL;
    }

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd_capture, VIDIOC_G_FMT, &fmt) < 0) //读取当前驱动的频捕获格式
    {
        printf("get format failed\n");
        return FAIL;
    }
    else
    {
        printf("\t Width = %d\n", fmt.fmt.pix.width);
        printf("\t Height = %d\n", fmt.fmt.pix.height);
        printf("\t Image size = %d\n", fmt.fmt.pix.sizeimage);
        printf("\t pixelformat = %d\n", fmt.fmt.pix.pixelformat);
    }
    capture_frame_size = fmt.fmt.pix.sizeimage;
        printf("**********capture frame size=%d\n",fmt.fmt.pix.sizeimage);
    return PASS;
}

int display_set(void)
{
//   struct v4l2_control ctrl;
    struct v4l2_fmtdesc fmtdesc;
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    struct v4l2_format fmt;
    struct v4l2_capability cap;
    struct v4l2_framebuffer fb;

    if (!ioctl(fd_display, VIDIOC_QUERYCAP, &cap))
    {
        printf("driver=%s, card=%s, bus=%s, "
               "version=0x%08x, "
               "capabilities=0x%08x\n",
               cap.driver, cap.card, cap.bus_info,
               cap.version,
               cap.capabilities);
    }

    fmtdesc.index = 0;
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    while (!ioctl(fd_display, VIDIOC_ENUM_FMT, &fmtdesc))
    {
        printf("fmt %s: fourcc = 0x%08x\n",
               fmtdesc.description,
               fmtdesc.pixelformat);
        fmtdesc.index++;
    }

    memset(&cropcap, 0, sizeof(cropcap));
    cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    if (ioctl(fd_display, VIDIOC_CROPCAP, &cropcap) < 0)
    {
        printf("get crop capability failed\n");
        return FAIL;
    }
    printf("cropcap.bounds.width = %d\ncropcap.bound.height = %d\n" \
           "cropcap.defrect.width = %d\ncropcap.defrect.height = %d\n",
           cropcap.bounds.width, cropcap.bounds.height,
           cropcap.defrect.width, cropcap.defrect.height);

    crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    crop.c.top = display_out_top;
    crop.c.left = display_out_left;
    crop.c.width = display_out_width;
    crop.c.height = display_out_height;
    if (ioctl(fd_display, VIDIOC_S_CROP, &crop) < 0)
    {
        printf("set crop failed\n");
        return FAIL;
    }
    fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
    fb.flags = V4L2_FBUF_FLAG_PRIMARY;
    ioctl(fd_display, VIDIOC_S_FBUF, &fb);

    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    fmt.fmt.pix.width=display_in_width;
    fmt.fmt.pix.height=display_in_height;
    fmt.fmt.pix.pixelformat = display_fmt;
    fmt.fmt.pix.priv = 0;
    if (ioctl(fd_display, VIDIOC_S_FMT, &fmt) < 0)
    {
        printf("set format failed\n");
        return FAIL;
    }

    if (ioctl(fd_display, VIDIOC_G_FMT, &fmt) < 0)
    {
        printf("get format failed\n");
        return FAIL;
    }

  printf("**********display frame size=%d\n",fmt.fmt.pix.sizeimage);

    return PASS;
}

void capture_munmap()
{
    int i;

    for (i = 0; i < TEST_BUFFER_NUM; i++)
    {
        munmap (capture_buffers[i].start, capture_buffers[i].length);
    }
}

void display_munmap(void)
{
    int i;

    for (i = 0; i < g_num_buffers; i++)
    {
        munmap (display_buffers[i].start, display_buffers[i].length);
    }

}

int capture_mmap(void)
{
    unsigned int i;
    struct v4l2_buffer buf;
    struct v4l2_requestbuffers req;

    memset(&req, 0, sizeof (req));
    req.count = TEST_BUFFER_NUM;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = mem_mmap_type;
    if (ioctl(fd_capture, VIDIOC_REQBUFS, &req) < 0) //向驱动提出申请内存的请求
    {
        printf("v4l_capture_setup: VIDIOC_REQBUFS failed\n");
        return FAIL;
    }
    for (i = 0; i < TEST_BUFFER_NUM; i++)
    {
        memset(&buf, 0, sizeof (buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = mem_mmap_type;
        buf.index = i;
        if (ioctl(fd_capture, VIDIOC_QUERYBUF, &buf) < 0) //把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
        {
            printf("VIDIOC_QUERYBUF error\n");
            capture_munmap();
            return FAIL;
        }

        capture_buffers[i].length = buf.length;
        capture_buffers[i].offset = (size_t) buf.m.offset;
        capture_buffers[i].start = mmap (NULL, capture_buffers[i].length,
                                 PROT_READ | PROT_WRITE, MAP_SHARED,
                                 fd_capture, capture_buffers[i].offset);
        memset(capture_buffers[i].start, 0xFF, capture_buffers[i].length);
    }

    for (i = 0; i < TEST_BUFFER_NUM; i++)
    {
        memset(&buf, 0, sizeof (buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = mem_mmap_type;
        buf.index = i;
        buf.m.offset = capture_buffers[i].offset;
        if (ioctl (fd_capture, VIDIOC_QBUF, &buf) < 0) //把缓冲区放回缓存队列
        {
            printf("VIDIOC_QBUF error\n");
            capture_munmap();
            return FAIL;
        }
    }
    return PASS;
}
int display_mmap(void)
{
    struct v4l2_requestbuffers buf_req;
    struct v4l2_buffer buf;
    int i;

    memset(&buf_req, 0, sizeof(buf_req));
    buf_req.count = TEST_BUFFER_NUM;
    buf_req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    buf_req.memory = mem_mmap_type;
    if (ioctl(fd_display, VIDIOC_REQBUFS, &buf_req) < 0)
    {
        printf("request display_buffers failed\n");
        return FAIL;
    }
    g_num_buffers = buf_req.count;
    printf("v4l2_output test: Allocated %d display_buffers\n", buf_req.count);

    memset(&buf, 0, sizeof(buf));

    for (i = 0; i < g_num_buffers; i++)
    {
        memset(&buf, 0, sizeof (buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        buf.memory = mem_mmap_type;
        buf.index = i;
        if (ioctl(fd_display, VIDIOC_QUERYBUF, &buf) < 0)
        {
            printf("VIDIOC_QUERYBUF error\n");
            display_munmap();
            return FAIL;
        }

        display_buffers[i].length = buf.length;
        display_buffers[i].offset = (size_t) buf.m.offset;
        printf("VIDIOC_QUERYBUF: length = %d, offset = %d\n",
               display_buffers[i].length, display_buffers[i].offset);
        display_buffers[i].start = mmap (NULL, display_buffers[i].length,
                                 PROT_READ | PROT_WRITE, MAP_SHARED,
                                 fd_display, display_buffers[i].offset);
        if (display_buffers[i].start == NULL)
        {
            printf("v4l2_out test: mmap failed\n");
            display_munmap();
            return FAIL;
        }
    }
    return PASS;
}

int capture_starting()
{
    enum v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl (fd_capture, VIDIOC_STREAMON, &type) < 0) //开始视频显示函数
    {
        printf("VIDIOC_STREAMON error\n");
        return FAIL;
    }
    return PASS;
}

void fb_setup(void)
{
    struct mxcfb_gbl_alpha alpha;
    int fd;

    fd = open("/dev/fb0",O_RDWR);

    alpha.alpha = 0;
    alpha.enable = 1;
    if (ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha) < 0)
    {
        printf("set alpha %d failed for fb0\n",  alpha.alpha);
    }

    close(fd);
}

int display_starting(void)
{
    int i;
    enum v4l2_buf_type type;
    struct v4l2_buffer buf;

    type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    if (ioctl (fd_display, VIDIOC_STREAMON, &type) < 0)
    {
        printf("Could not start stream\n");
        display_munmap();
        return FAIL;
    }
    /*simply set fb0 alpha to 0*/
    fb_setup();

    for (i = 0; i < g_num_buffers; i++)
    {
        buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        buf.memory = mem_mmap_type;
        buf.index = i;
        if ((ioctl(fd_display, VIDIOC_QBUF, &buf)) < 0)
        {
            printf("VIDIOC_QBUF failed\n");
            display_munmap();
            return FAIL;
        }
    }
    return PASS;

}

int capture_and_display()
{
        struct v4l2_buffer capture_buf;
        struct v4l2_buffer display_buf;
    int count = capture_count;
    int retval = PASS;
       
    while (count-- > 0)
    {
#ifdef CAPTURE
                memset(&capture_buf, 0, sizeof (capture_buf));
        capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        capture_buf.memory = mem_mmap_type;
        if (ioctl (fd_capture, VIDIOC_DQBUF, &capture_buf) < 0)//将已经捕获好视频的内存拉出已捕获视频的队列
        {
            printf("capture VIDIOC_DQBUF failed.\n");
            retval = FAIL;
            break;
        }
#endif
#ifdef DISPLAY
                display_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        display_buf.memory = mem_mmap_type;
        if (ioctl(fd_display, VIDIOC_DQBUF, &display_buf) < 0)
        {
            printf("display VIDIOC_DQBUF failed\n");
            retval = -1;
            break;
        }
#ifndef        ONLY_DISPLAY
                memcpy(display_buffers[display_buf.index].start,capture_buffers[capture_buf.index].start, capture_frame_size);
#endif
#endif

#ifdef         CAPTURE
                fwrite(capture_buffers[capture_buf.index].start, capture_frame_size, 1, fd_file);
#endif
#ifdef        ONLY_DISPLAY
                retval = fread(display_buffers[display_buf.index].start, 1, capture_frame_size, fd_file);
                if(retval < capture_frame_size)
                        {
                                printf("read file over!\n");
                                break;
                        }
#endif                       
#ifdef DISPLAY
                if ((retval = ioctl(fd_display, VIDIOC_QBUF, &display_buf)) < 0)
        {
            printf("display VIDIOC_QBUF failed %d\n", retval);
            retval = -1;
            break;
        }
#endif
#ifdef        CAPTURE
        if (count >= TEST_BUFFER_NUM)
        {
            if (ioctl (fd_capture, VIDIOC_QBUF, &capture_buf) < 0)  //投放一个空的视频缓冲区到视频缓冲区输入队列中
            {
                printf("capture VIDIOC_QBUF failed\n");
                retval = FAIL;
                break;
            }
        }
        else
            printf("buf.index %d\n", capture_buf.index);
#endif
        }
    return retval;
}

void capture_stop(void)
{
    enum v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl (fd_capture, VIDIOC_STREAMOFF, &type); //结束视频显示函数
}

void display_stop(void)
{
    enum v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    ioctl (fd_display, VIDIOC_STREAMOFF, &type);
}

int main(int argc, char *argv[])
{
    int retval = PASS;
#ifdef        CAPTURE
        if((retval = capture_open())<0)
        goto err0;
#endif
#ifdef DISPLAY
    if((retval = display_open())< 0)
        goto err0;
#endif       
#ifdef        CAPTURE
        fd_file = fopen(argv[argc-1], "wb");
#else
        fd_file = fopen(argv[argc-1], "rb");
#endif
    if (fd_file == NULL)
    {       
            retval = FAIL;
            goto err0;
    }
#ifdef CAPTURE
        if((retval = capture_set())<0)
        goto err0;
#endif
#ifdef DISPLAY
        if((retval = display_set())< 0)
        goto err0;
#endif
#ifdef CAPTURE       
        if((retval = capture_mmap())< 0)
        goto err1;
#endif
#ifdef DISPLAY
    if((retval = display_mmap())< 0)
        goto err1;
#endif
#ifdef CAPTURE
    if ((retval = capture_starting()) < 0)
        goto err1;
#endif
#ifdef DISPLAY
        if((retval = display_starting())< 0)
        goto err1;
#endif
        if((retval = capture_and_display()) < 0)
                goto err1;

#ifdef CAPTURE
    capture_stop();
#endif
#ifdef DISPLAY
        display_stop();
#endif
err1:
#ifdef        CAPTURE
    capture_munmap();
#endif
#ifdef DISPLAY
        display_munmap();
#endif
    printf("*****capture_and_display_exit*******\n");
err0:
#ifdef CAPTURE
    close(fd_capture);
#endif
#ifdef DISPLAY
        close(fd_display);
#endif
    return retval;
}

相关帖子

沙发
lqland| | 2014-6-24 20:52 | 只看该作者
高深,帮顶

使用特权

评论回复
板凳
wsk311728|  楼主 | 2014-6-25 15:52 | 只看该作者
怎么没人回呀,都没有用到吗?

使用特权

评论回复
地板
FSL_TICS_Rita| | 2014-6-25 17:20 | 只看该作者
楼主你好,确实没有用过,请问你结合在一起用的目的是什么?

使用特权

评论回复
5
wsk311728|  楼主 | 2014-6-30 15:35 | 只看该作者
FSL_TICS_Rita 发表于 2014-6-25 17:20
楼主你好,确实没有用过,请问你结合在一起用的目的是什么?

在摄像的时候可以显示呀

使用特权

评论回复
6
ningmeng4345| | 2014-7-28 11:05 | 只看该作者
楼主,你好!请问你用的什么开发板,装得什么系统啊???
我使用freescale i.mx6q sabre 开发板安装yocto linux操作系统,然后并没有以下的头文件啊???
#include <linux/mxcfb.h>
#include <linux/mxc_v4l2.h>
#include <linux/ipu.h>
请问我是少安装了一些功能包吗???

使用特权

评论回复
7
FSL_TICS_Rita| | 2014-7-28 14:53 | 只看该作者
ningmeng4345 发表于 2014-7-28 11:05
楼主,你好!请问你用的什么开发板,装得什么系统啊???
我使用freescale i.mx6q sabre 开发板安装yocto  ...

楼主你好,有问题欢迎创建新帖提问哈~~有我们的工程师给您回复的。

使用特权

评论回复
8
zgrztzy| | 2014-12-19 16:55 | 只看该作者
capture和output是必须的吗,不移植可不可以获取/dev/video0

使用特权

评论回复
9
leifenger| | 2014-12-19 17:11 | 只看该作者
mxc_v4l2_tvin测试程序就是这个功能啊,
从v4l2取视频,显示在/dev/fb0,hdmi连接的监视器上。
mxc_vpu_test测试程序也有这个功能。
^_^LZ贴的代码好长^_^

使用特权

评论回复
10
dongtengfei| | 2014-12-23 13:15 | 只看该作者
9楼说的是mxc_v4l2_tvin就是capture+output

使用特权

评论回复
11
wsk311728|  楼主 | 2015-1-17 16:39 | 只看该作者
本帖最后由 wsk311728 于 2015-1-17 16:41 编辑
leifenger 发表于 2014-12-19 17:11
mxc_v4l2_tvin测试程序就是这个功能啊,
从v4l2取视频,显示在/dev/fb0,hdmi连接的监视器上。
mxc_vpu_tes ...

照你的方法测试,提示如下错误:
[root@hisilc /]$ /unit_tests/mxc_v4l2_tvin.out -ow 640 -oh 480
TV decoder chip is ov5640_cameraERROR: unrecognized std! 0 (PAL=ff, NTSC=b000

ERROR: v4l2 capture: width or height too small.
/dev/video0 iformat not supported
Setup v4l capture failed.
而用mxc_v4l2_overlay.out测试是正常的
[root@hisilc /]$ /unit_tests/mxc_v4l2_overlay.out
g_display_width = 240, g_display_height = 320
g_display_top = 0, g_display_left = 0
sensor chip is ov5640_camera
sensor supported frame size:
640x480
320x240
720x480
720x576
1280x720
1920x1080
1024x768
2048x1536
sensor frame format: UYVY
sensor frame format: UYVY
sensor frame format: UYVY
sensor frame format: UYVY
sensor frame format: UYVY
sensor frame format: UYVY
sensor frame format: UYVY
sensor frame format: UYVY
frame_rate is 30XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

BGR32

frame buffer width 1024, height 768, bytesperline 4096

使用特权

评论回复
12
王乃汉| | 2017-9-6 21:47 | 只看该作者
wsk311728 发表于 2015-1-17 16:39
照你的方法测试,提示如下错误:
[root@hisilc /]$ /unit_tests/mxc_v4l2_tvin.out -ow 640 -oh 480
TV de ...

尊敬的工程师您好,我也遇到同样的问题,用mxc_v4l2_overlay.out显示屏正常显示画面,但用mxc_v4l2_tvin.out -ow 640 -oh 480出现unrecognized std! 错误,显示屏无法显示画面,请问后面是怎么解决的呢?谢谢!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

27

帖子

0

粉丝