/* Get the supported size */ static void v4l2_get_supported_size(int fd, pj_uint32_t fmt_id, pjmedia_vid_dev_info *info) { int i=0; pjmedia_rect_size v4l_sizes[] = { /* Some webcam doesn't work well using size below 320x240 */ /*{ 128, 96 }, { 176, 144 },*/ { 320, 240 }, { 352, 240 }, { 352, 288 }, { 352, 480 }, { 352, 576 }, { 640, 480 }, { 704, 480 }, { 720, 480 }, { 704, 576 }, { 720, 576 }, { 800, 600 }, { 1024, 768 }, { 1280, 720 }, { 1280, 960 }, { 1280, 1024 }, { 1408, 960 }, { 1408, 1152 }, { 1600, 1200 }, { 1920, 1080 }/*, { 1920, 1088 }, { 2048, 1024 }, { 2048, 1080 }, { 2048, 1088 }, { 2048, 1536 }, { 2560, 1920 }, { 3616, 1536 }, { 3672, 1536 }, { 3680, 1536 }, { 3840, 2160 }, { 4096, 2048 }, { 4096, 2160 }, { 4096, 2304 }*/ }; const vid4lin_fmt_map *fmt_map = get_v4l2_format_info(fmt_id); if (fmt_map == NULL) return; for (;i<PJ_ARRAY_SIZE(v4l_sizes) && info->fmt_cnt<PJMEDIA_VID_DEV_INFO_FMT_CNT; i++) { struct v4l2_format v4l2_fmt; pj_status_t status; pj_bzero(&v4l2_fmt, sizeof(v4l2_fmt)); v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2_fmt.fmt.pix.width = v4l_sizes[i].w; v4l2_fmt.fmt.pix.height = v4l_sizes[i].h; v4l2_fmt.fmt.pix.pixelformat = fmt_map->v4l2_fmt_id; v4l2_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; status = xioctl(fd, VIDIOC_TRY_FMT, &v4l2_fmt); if (status != PJ_SUCCESS || v4l2_fmt.fmt.pix.pixelformat != fmt_map->v4l2_fmt_id || v4l2_fmt.fmt.pix.width != v4l_sizes[i].w || v4l2_fmt.fmt.pix.height != v4l_sizes[i].h) { continue; } pjmedia_format_init_video(&info->fmt[info->fmt_cnt++], fmt_id, v4l_sizes[i].w, v4l_sizes[i].h, DEFAULT_FPS, 1); } }
/* API: create stream */ static pj_status_t vid4lin_factory_create_stream(pjmedia_vid_dev_factory *f, pjmedia_vid_dev_param *param, const pjmedia_vid_dev_cb *cb, void *user_data, pjmedia_vid_dev_stream **p_vid_strm) { vid4lin_factory *cf = (vid4lin_factory*)f; pj_pool_t *pool; vid4lin_stream *stream; vid4lin_dev_info *vdi; const vid4lin_fmt_map *fmt_map; const pjmedia_video_format_info *fmt_info; pjmedia_video_format_detail *vfd; pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL); PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO && param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO && param->dir == PJMEDIA_DIR_CAPTURE, PJ_EINVAL); PJ_ASSERT_RETURN(param->cap_id >= 0 && param->cap_id < cf->dev_count, PJMEDIA_EVID_INVDEV); fmt_info = pjmedia_get_video_format_info(NULL, param->fmt.id); if (!fmt_info || (fmt_map=get_v4l2_format_info(param->fmt.id))==NULL) return PJMEDIA_EVID_BADFORMAT; vdi = &cf->dev_info[param->cap_id]; vfd = pjmedia_format_get_video_format_detail(¶m->fmt, PJ_TRUE); /* Create and Initialize stream descriptor */ pool = pj_pool_create(cf->pf, vdi->info.name, 512, 512, NULL); PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); stream = PJ_POOL_ZALLOC_T(pool, vid4lin_stream); pj_memcpy(&stream->param, param, sizeof(*param)); stream->pool = pool; pj_memcpy(&stream->vid_cb, cb, sizeof(*cb)); strncpy(stream->name, vdi->info.name, sizeof(stream->name)); stream->name[sizeof(stream->name)-1] = '\0'; stream->user_data = user_data; stream->fd = INVALID_FD; stream->fd = v4l2_open(vdi->dev_name, O_RDWR, 0); if (stream->fd < 0) goto on_error; status = vid4lin_stream_init_fmt(stream, param, fmt_map->v4l2_fmt_id); if (status != PJ_SUCCESS) goto on_error; if (vdi->v4l2_cap.capabilities & V4L2_CAP_STREAMING) status = vid4lin_stream_init_streaming(stream); if (status!=PJ_SUCCESS && vdi->v4l2_cap.capabilities & V4L2_CAP_STREAMING) status = vid4lin_stream_init_streaming_user(stream); if (status!=PJ_SUCCESS && vdi->v4l2_cap.capabilities & V4L2_CAP_READWRITE) status = vid4lin_stream_init_read_write(stream); if (status != PJ_SUCCESS) { PJ_LOG(1,(THIS_FILE, "Error: unable to initiate I/O on %s", stream->name)); goto on_error; } /* Done */ stream->base.op = &stream_op; *p_vid_strm = &stream->base; return PJ_SUCCESS; on_error: if (status == PJ_SUCCESS) status = PJ_RETURN_OS_ERROR(errno); vid4lin_stream_destroy(&stream->base); return status; }