/* * Generate default attribute. */ static pj_status_t openh264_default_attr( pjmedia_vid_codec_factory *factory, const pjmedia_vid_codec_info *info, pjmedia_vid_codec_param *attr ) { const openh264_codec_desc *desc; unsigned i; PJ_ASSERT_RETURN(factory==&openh264_factory.base, PJ_EINVAL); PJ_ASSERT_RETURN(info && attr, PJ_EINVAL); desc = find_codec_desc_by_info(info); if (!desc) { return PJMEDIA_CODEC_EUNSUP; } pj_bzero(attr, sizeof(pjmedia_vid_codec_param)); /* Scan the requested packings and use the lowest number */ attr->packing = 0; for (i=0; i<15; ++i) { unsigned packing = (1 << i); if ((desc->info.packings & info->packings) & packing) { attr->packing = (pjmedia_vid_packing)packing; break; } } if (attr->packing == 0) { /* No supported packing in info */ return PJMEDIA_CODEC_EUNSUP; } /* Direction */ attr->dir = desc->info.dir; /* Encoded format */ pjmedia_format_init_video(&attr->enc_fmt, desc->info.fmt_id, desc->size.w, desc->size.h, desc->fps.num, desc->fps.denum); /* Decoded format */ pjmedia_format_init_video(&attr->dec_fmt, desc->info.dec_fmt_id[0], desc->size.w, desc->size.h, desc->fps.num, desc->fps.denum); /* Decoding fmtp */ attr->dec_fmtp = desc->dec_fmtp; /* Bitrate */ attr->enc_fmt.det.vid.avg_bps = desc->avg_bps; attr->enc_fmt.det.vid.max_bps = desc->max_bps; /* Encoding MTU */ attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE; return PJ_SUCCESS; }
static pj_status_t alt_vid_codec_default_attr( pjmedia_vid_codec_factory *factory, const pjmedia_vid_codec_info *info, pjmedia_vid_codec_param *attr ) { const struct alt_codec_desc *desc = find_codec_desc_by_info(info); unsigned i; if (!desc) return PJMEDIA_CODEC_EUNSUP; pj_bzero(attr, sizeof(pjmedia_vid_codec_param)); /* Scan the requested packings and use the lowest number */ attr->packing = 0; for (i=0; i<15; ++i) { unsigned packing = (1 << i); if ((desc->info.packings & info->packings) & packing) { attr->packing = (pjmedia_vid_packing)packing; break; } } if (attr->packing == 0) { /* No supported packing in info */ return PJMEDIA_CODEC_EUNSUP; } /* Direction */ attr->dir = desc->info.dir; /* Encoded format */ pjmedia_format_init_video(&attr->enc_fmt, desc->info.fmt_id, 720, 480, 30000, 1001); /* Decoded format */ pjmedia_format_init_video(&attr->dec_fmt, desc->info.dec_fmt_id[0], //352, 288, 30000, 1001); 720, 576, 30000, 1001); /* Decoding fmtp */ attr->dec_fmtp = desc->dec_fmtp; /* Bitrate */ attr->enc_fmt.det.vid.avg_bps = desc->avg_bps; attr->enc_fmt.det.vid.max_bps = desc->max_bps; /* MTU */ attr->enc_mtu = PJMEDIA_MAX_MTU; return PJ_SUCCESS; }
/* API: init factory */ static pj_status_t opengl_factory_init(pjmedia_vid_dev_factory *f) { struct opengl_factory *qf = (struct opengl_factory*)f; struct opengl_dev_info *qdi; unsigned l; /* Initialize input and output devices here */ qf->dev_info = (struct opengl_dev_info*) pj_pool_calloc(qf->pool, 1, sizeof(struct opengl_dev_info)); qf->dev_count = 0; qdi = &qf->dev_info[qf->dev_count++]; pj_bzero(qdi, sizeof(*qdi)); strcpy(qdi->info.name, "OpenGL renderer"); strcpy(qdi->info.driver, "OpenGL"); qdi->info.dir = PJMEDIA_DIR_RENDER; qdi->info.has_callback = PJ_FALSE; qdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT; qdi->info.fmt_cnt = PJ_ARRAY_SIZE(opengl_fmts); qdi->info.caps |= pjmedia_vid_dev_opengl_imp_get_cap(); for (l = 0; l < PJ_ARRAY_SIZE(opengl_fmts); l++) { pjmedia_format *fmt = &qdi->info.fmt[l]; pjmedia_format_init_video(fmt, opengl_fmts[l], DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS, 1); } PJ_LOG(4, (THIS_FILE, "OpenGL device initialized")); return PJ_SUCCESS; }
/* API: create default device parameter */ static pj_status_t ffmpeg_factory_default_param(pj_pool_t *pool, pjmedia_vid_dev_factory *f, unsigned index, pjmedia_vid_dev_param *param) { ffmpeg_factory *ff = (ffmpeg_factory*)f; ffmpeg_dev_info *info; PJ_ASSERT_RETURN(index < ff->dev_count, PJMEDIA_EVID_INVDEV); PJ_UNUSED_ARG(pool); info = &ff->dev_info[index]; pj_bzero(param, sizeof(*param)); param->dir = PJMEDIA_DIR_CAPTURE; param->cap_id = index; param->rend_id = PJMEDIA_VID_INVALID_DEV; param->clock_rate = 0; /* Set the device capabilities here */ param->flags = PJMEDIA_VID_DEV_CAP_FORMAT; param->clock_rate = 90000; pjmedia_format_init_video(¶m->fmt, 0, 320, 240, 25, 1); param->fmt.id = info->base.fmt[0].id; return PJ_SUCCESS; }
/* * Generate default attribute. */ static pj_status_t pj_vpx_default_attr(pjmedia_vid_codec_factory *factory, const pjmedia_vid_codec_info *info, pjmedia_vid_codec_param *attr) { PJ_ASSERT_RETURN(factory==&vpx_factory.base, PJ_EINVAL); PJ_ASSERT_RETURN(info && attr, PJ_EINVAL); TRACE_((THIS_FILE, "vpx default attr")); pj_bzero(attr, sizeof(pjmedia_vid_codec_param)); /* Scan the requested packings and use the lowest number */ attr->packing = 1; /* Direction */ attr->dir = PJMEDIA_DIR_ENCODING_DECODING; /* Encoded format */ pjmedia_format_init_video(&attr->enc_fmt, PJMEDIA_FORMAT_VP8, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS, 1); /* Decoded format */ pjmedia_format_init_video(&attr->dec_fmt, PJMEDIA_FORMAT_I420, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS, 1); /* Decoding fmtp */ attr->dec_fmtp.cnt = 0; /* Bitrate */ attr->enc_fmt.det.vid.avg_bps = DEFAULT_AVG_BITRATE; attr->enc_fmt.det.vid.max_bps = DEFAULT_MAX_BITRATE; attr->enc_fmtp.cnt = 0; /* Encoding MTU */ attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE; return PJ_SUCCESS; }
/* 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); } }
static int vidport_test(void) { int i, j, k, l; int cap_id, rend_id; pjmedia_format_id test_fmts[] = { PJMEDIA_FORMAT_RGBA, PJMEDIA_FORMAT_I420 }; PJ_LOG(3, (THIS_FILE, " Video port tests:")); /* Capturer's role: active/passive. */ for (i = 1; i >= 0; i--) { /* Capturer's device has_callback: TRUE/FALSE. */ for (j = 1; j >= 0; j--) { cap_id = find_device(PJMEDIA_DIR_CAPTURE, j); if (cap_id < 0) continue; /* Renderer's device has callback: TRUE/FALSE. */ for (k = 1; k >= 0; k--) { rend_id = find_device(PJMEDIA_DIR_RENDER, k); if (rend_id < 0) continue; /* Check various formats to test format conversion. */ for (l = 0; l < PJ_ARRAY_SIZE(test_fmts); ++l) { pjmedia_format fmt; PJ_LOG(3,(THIS_FILE, "capturer %s (stream: %s) ===> " "renderer %s (stream: %s)", (i? "active": "passive"), (j? "active": "passive"), (i? "passive": "active"), (k? "active": "passive"))); pjmedia_format_init_video(&fmt, test_fmts[l], 640, 480, 25, 1); capture_render_loopback(i, cap_id, rend_id, &fmt); } } } } return 0; }
static int aviplay(pj_pool_t *pool, const char *fname) { pjmedia_vid_port *renderer=NULL; pjmedia_vid_port_param param; const pjmedia_video_format_info *vfi; pjmedia_video_format_detail *vfd; pjmedia_snd_port *snd_port = NULL; pj_status_t status; int rc = 0; pjmedia_avi_streams *avi_streams; pjmedia_avi_stream *vid_stream, *aud_stream; pjmedia_port *vid_port = NULL, *aud_port = NULL; pjmedia_vid_codec *codec=NULL; avi_port_t avi_port; pj_bzero(&avi_port, sizeof(avi_port)); status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams); if (status != PJ_SUCCESS) { PJ_PERROR(2,("", status, " Error playing %s", fname)); rc = 210; goto on_return; } vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams, 0, PJMEDIA_TYPE_VIDEO); vid_port = pjmedia_avi_stream_get_port(vid_stream); if (vid_port) { pjmedia_vid_port_param_default(¶m); status = pjmedia_vid_dev_default_param(pool, PJMEDIA_VID_DEFAULT_RENDER_DEV, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 220; goto on_return; } /* Create renderer, set it to active */ param.active = PJ_TRUE; param.vidparam.dir = PJMEDIA_DIR_RENDER; vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt, PJ_TRUE); pjmedia_format_init_video(¶m.vidparam.fmt, vid_port->info.fmt.id, vfd->size.w, vfd->size.h, vfd->fps.num, vfd->fps.denum); vfi = pjmedia_get_video_format_info( pjmedia_video_format_mgr_instance(), vid_port->info.fmt.id); /* Check whether the frame is encoded */ if (!vfi || vfi->bpp == 0) { /* Yes, prepare codec */ pj_str_t codec_id_st; unsigned info_cnt = 1, i, k; const pjmedia_vid_codec_info *codec_info; pj_str_t port_name = {"codec", 5}; pj_uint8_t *enc_buf = NULL; pj_size_t enc_buf_size = 0; pjmedia_vid_dev_info rdr_info; pjmedia_port codec_port; codec_port_data_t codec_port_data; pjmedia_vid_codec_param codec_param; struct codec_fmt *codecp = NULL; /* Lookup codec */ for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) { if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) { codecp = &codec_fmts[i]; break; } } if (!codecp) { rc = 242; goto on_return; } pj_cstr(&codec_id_st, codecp->codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, &info_cnt, &codec_info, NULL); if (status != PJ_SUCCESS) { rc = 245; goto on_return; } status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); if (status != PJ_SUCCESS) { rc = 246; goto on_return; } pjmedia_format_copy(&codec_param.enc_fmt, ¶m.vidparam.fmt); pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info); for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) { for (k=0; k<rdr_info.fmt_cnt; ++k) { if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id) { param.vidparam.fmt.id = codec_info->dec_fmt_id[i]; i = codec_info->dec_fmt_id_cnt; break; } } } /* Open codec */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec); if (status != PJ_SUCCESS) { rc = 250; goto on_return; } status = pjmedia_vid_codec_init(codec, pool); if (status != PJ_SUCCESS) { rc = 251; goto on_return; } pjmedia_format_copy(&codec_param.dec_fmt, ¶m.vidparam.fmt); codec_param.dir = PJMEDIA_DIR_DECODING; codec_param.packing = PJMEDIA_VID_PACKING_WHOLE; status = pjmedia_vid_codec_open(codec, &codec_param); if (status != PJ_SUCCESS) { rc = 252; goto on_return; } /* Alloc encoding buffer */ enc_buf_size = codec_param.dec_fmt.det.vid.size.w * codec_param.dec_fmt.det.vid.size.h * 4 + 16; /*< padding, just in case */ enc_buf = pj_pool_alloc(pool,enc_buf_size); /* Init codec port */ pj_bzero(&codec_port, sizeof(codec_port)); status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234, PJMEDIA_DIR_ENCODING, &codec_param.dec_fmt); if (status != PJ_SUCCESS) { rc = 260; goto on_return; } pj_bzero(&codec_port_data, sizeof(codec_port_data)); codec_port_data.codec = codec; codec_port_data.src_port = vid_port; codec_port_data.enc_buf = enc_buf; codec_port_data.enc_buf_size = enc_buf_size; codec_port.get_frame = &codec_get_frame; codec_port.port_data.pdata = &codec_port_data; /* Check whether we need to convert the decoded frame */ if (codecp->need_conversion) { pjmedia_conversion_param conv_param; pjmedia_format_copy(&conv_param.src, ¶m.vidparam.fmt); pjmedia_format_copy(&conv_param.dst, ¶m.vidparam.fmt); conv_param.dst.id = codecp->dst_fmt; param.vidparam.fmt.id = conv_param.dst.id; status = pjmedia_converter_create(NULL, pool, &conv_param, &codec_port_data.conv); if (status != PJ_SUCCESS) { rc = 270; goto on_return; } } status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 230; goto on_return; } status = pjmedia_vid_port_connect(renderer, &codec_port, PJ_FALSE); } else { status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 230; goto on_return; } /* Connect avi port to renderer */ status = pjmedia_vid_port_connect(renderer, vid_port, PJ_FALSE); } if (status != PJ_SUCCESS) { rc = 240; goto on_return; } } aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams, 0, PJMEDIA_TYPE_AUDIO); aud_port = pjmedia_avi_stream_get_port(aud_stream); if (aud_port) { /* Create sound player port. */ status = pjmedia_snd_port_create_player( pool, /* pool */ -1, /* use default dev. */ PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate. */ PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels. */ PJMEDIA_PIA_SPF(&aud_port->info), /* samples per frame. */ PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample. */ 0, /* options */ &snd_port /* returned port */ ); if (status != PJ_SUCCESS) { rc = 310; goto on_return; } /* Connect file port to the sound player. * Stream playing will commence immediately. */ status = pjmedia_snd_port_connect(snd_port, aud_port); if (status != PJ_SUCCESS) { rc = 330; goto on_return; } } if (vid_port) { pjmedia_vid_dev_cb cb; pj_bzero(&cb, sizeof(cb)); avi_port.snd_port = snd_port; avi_port.vid_port = renderer; avi_port.is_running = PJ_TRUE; pjmedia_vid_port_set_cb(renderer, &cb, &avi_port); /* subscribe events */ pjmedia_event_subscribe(NULL, &avi_event_cb, &avi_port, renderer); if (snd_port) { /* Synchronize video rendering and audio playback */ pjmedia_vid_port_set_clock_src( renderer, pjmedia_snd_port_get_clock_src( snd_port, PJMEDIA_DIR_PLAYBACK)); } /* Start video streaming.. */ status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) { rc = 270; goto on_return; } } while (!avi_port.is_quitting) { pj_thread_sleep(100); } on_return: if (snd_port) { pjmedia_snd_port_disconnect(snd_port); /* Without this sleep, Windows/DirectSound will repeteadly * play the last frame during destroy. */ pj_thread_sleep(100); pjmedia_snd_port_destroy(snd_port); } if (renderer) { pjmedia_event_unsubscribe(NULL, &avi_event_cb, &avi_port, renderer); pjmedia_vid_port_destroy(renderer); } if (aud_port) pjmedia_port_destroy(aud_port); if (vid_port) pjmedia_port_destroy(vid_port); if (codec) { pjmedia_vid_codec_close(codec); pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec); } return rc; }
/* Scan V4L2 devices */ static pj_status_t v4l2_scan_devs(vid4lin_factory *f) { vid4lin_dev_info vdi[V4L2_MAX_DEVS]; char dev_name[32]; unsigned i, old_count; pj_status_t status; if (f->dev_pool) { pj_pool_release(f->dev_pool); f->dev_pool = NULL; } pj_bzero(vdi, sizeof(vdi)); old_count = f->dev_count; f->dev_count = 0; f->dev_pool = pj_pool_create(f->pf, DRIVER_NAME, 500, 500, NULL); for (i=0; i<V4L2_MAX_DEVS && f->dev_count < V4L2_MAX_DEVS; ++i) { int fd; vid4lin_dev_info *pdi; pj_uint32_t fmt_cap[8]; int j, fmt_cnt=0; pdi = &vdi[f->dev_count]; snprintf(dev_name, sizeof(dev_name), "/dev/video%d", i); if (!pj_file_exists(dev_name)) continue; fd = v4l2_open(dev_name, O_RDWR, 0); if (fd == -1) continue; status = xioctl(fd, VIDIOC_QUERYCAP, &pdi->v4l2_cap); if (status != PJ_SUCCESS) { PJ_PERROR(4,(THIS_FILE, status, "Error querying %s", dev_name)); v4l2_close(fd); continue; } if ((pdi->v4l2_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { v4l2_close(fd); continue; } PJ_LOG(5,(THIS_FILE, "Found capture device %s", pdi->v4l2_cap.card)); PJ_LOG(5,(THIS_FILE, " Enumerating formats:")); for (j=0; fmt_cnt<PJ_ARRAY_SIZE(fmt_cap); ++j) { struct v4l2_fmtdesc fdesc; unsigned k; pj_bzero(&fdesc, sizeof(fdesc)); fdesc.index = j; fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; status = xioctl(fd, VIDIOC_ENUM_FMT, &fdesc); if (status != PJ_SUCCESS) break; for (k=0; k<PJ_ARRAY_SIZE(v4l2_fmt_maps); ++k) { if (v4l2_fmt_maps[k].v4l2_fmt_id == fdesc.pixelformat) { fmt_cap[fmt_cnt++] = v4l2_fmt_maps[k].pjmedia_fmt_id; PJ_LOG(5,(THIS_FILE, " Supported: %s", fdesc.description)); break; } } if (k==PJ_ARRAY_SIZE(v4l2_fmt_maps)) { PJ_LOG(5,(THIS_FILE, " Unsupported: %s", fdesc.description)); } } v4l2_close(fd); if (fmt_cnt==0) { PJ_LOG(5,(THIS_FILE, " Found no common format")); continue; } strncpy(pdi->dev_name, dev_name, sizeof(pdi->dev_name)); pdi->dev_name[sizeof(pdi->dev_name)-1] = '\0'; strncpy(pdi->info.name, (char*)pdi->v4l2_cap.card, sizeof(pdi->info.name)); pdi->info.name[sizeof(pdi->info.name)-1] = '\0'; strncpy(pdi->info.driver, DRIVER_NAME, sizeof(pdi->info.driver)); pdi->info.driver[sizeof(pdi->info.driver)-1] = '\0'; pdi->info.dir = PJMEDIA_DIR_CAPTURE; pdi->info.has_callback = PJ_FALSE; pdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT; pdi->info.fmt_cnt = fmt_cnt; for (j=0; j<fmt_cnt; ++j) { pjmedia_format_init_video(&pdi->info.fmt[j], fmt_cap[j], DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS, 1); } if (j < fmt_cnt) continue; f->dev_count++; } if (f->dev_count == 0) return PJ_SUCCESS; if (f->dev_count > old_count || f->dev_info == NULL) { f->dev_info = (vid4lin_dev_info*) pj_pool_calloc(f->dev_pool, f->dev_count, sizeof(vid4lin_dev_info)); } pj_memcpy(f->dev_info, vdi, f->dev_count * sizeof(vid4lin_dev_info)); return PJ_SUCCESS; }
/* API: refresh the list of devices */ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff) { and_factory *f = (and_factory*)ff; pj_status_t status = PJ_SUCCESS; JNIEnv *jni_env; pj_bool_t with_attach, found_front = PJ_FALSE; int i, dev_count = 0; /* Clean up device info and pool */ f->dev_count = 0; pj_pool_reset(f->dev_pool); with_attach = jni_get_env(&jni_env); /* dev_count = PjCameraInfo::GetCameraCount() */ dev_count = (*jni_env)->CallStaticIntMethod(jni_env, jobjs.cam_info.cls, jobjs.cam_info.m_get_cnt); if (dev_count < 0) { PJ_LOG(3, (THIS_FILE, "Failed to get camera count")); status = PJMEDIA_EVID_SYSERR; goto on_return; } /* Start querying device info */ f->dev_info = (and_dev_info*) pj_pool_calloc(f->dev_pool, dev_count, sizeof(and_dev_info)); for (i = 0; i < dev_count; i++) { and_dev_info *adi = &f->dev_info[f->dev_count]; pjmedia_vid_dev_info *vdi = &adi->info; jobject jdev_info; jobject jtmp; int facing, max_fmt_cnt = PJMEDIA_VID_DEV_INFO_FMT_CNT; /* jdev_info = PjCameraInfo::GetCameraInfo(i) */ jdev_info = (*jni_env)->CallStaticObjectMethod( jni_env, jobjs.cam_info.cls, jobjs.cam_info.m_get_info, i); if (jdev_info == NULL) continue; /* Get camera facing: 0=back 1=front */ facing = (*jni_env)->GetIntField(jni_env, jdev_info, jobjs.cam_info.f_facing); if (facing < 0) goto on_skip_dev; /* Set device ID, direction, and has_callback info */ adi->dev_idx = i; vdi->id = f->dev_count; vdi->dir = PJMEDIA_DIR_CAPTURE; vdi->has_callback = PJ_TRUE; vdi->caps = PJMEDIA_VID_DEV_CAP_SWITCH | PJMEDIA_VID_DEV_CAP_ORIENTATION; /* Set driver & name info */ pj_ansi_strncpy(vdi->driver, "Android", sizeof(vdi->driver)); adi->facing = facing; if (facing == 0) { pj_ansi_strncpy(vdi->name, "Back camera", sizeof(vdi->name)); } else { pj_ansi_strncpy(vdi->name, "Front camera", sizeof(vdi->name)); } /* Get supported sizes */ jtmp = (*jni_env)->GetObjectField(jni_env, jdev_info, jobjs.cam_info.f_sup_size); if (jtmp) { jintArray jiarray = (jintArray*)jtmp; jint *sizes; jsize cnt, j; cnt = (*jni_env)->GetArrayLength(jni_env, jiarray); sizes = (*jni_env)->GetIntArrayElements(jni_env, jiarray, 0); adi->sup_size_cnt = cnt/2; adi->sup_size = pj_pool_calloc(f->dev_pool, adi->sup_size_cnt, sizeof(adi->sup_size[0])); for (j = 0; j < adi->sup_size_cnt; j++) { adi->sup_size[j].w = sizes[j*2]; adi->sup_size[j].h = sizes[j*2+1]; } (*jni_env)->ReleaseIntArrayElements(jni_env, jiarray, sizes, 0); (*jni_env)->DeleteLocalRef(jni_env, jtmp); } else { goto on_skip_dev; } /* Get supported formats */ jtmp = (*jni_env)->GetObjectField(jni_env, jdev_info, jobjs.cam_info.f_sup_fmt); if (jtmp) { jintArray jiarray = (jintArray*)jtmp; jint *fmts; jsize cnt, j; pj_bool_t has_i420 = PJ_FALSE; cnt = (*jni_env)->GetArrayLength(jni_env, jiarray); fmts = (*jni_env)->GetIntArrayElements(jni_env, jiarray, 0); for (j = 0; j < cnt; j++) { int k; pjmedia_format_id fmt = and_fmt_to_pj((pj_uint32_t)fmts[j]); /* Check for any duplicate */ for (k = 0; k < vdi->fmt_cnt; k++) { if (fmt == 0 || fmt == vdi->fmt[k].id) { fmt = 0; break; } } /* Make sure we recognize this format */ if (fmt == 0) continue; /* Check formats for I420 conversion */ if (fmt == PJMEDIA_FORMAT_I420) has_i420 = PJ_TRUE; else if (fmt == PJMEDIA_FORMAT_YV12) adi->has_yv12 = PJ_TRUE; else if (fmt == PJMEDIA_FORMAT_NV21) adi->has_nv21 = PJ_TRUE; for (k = 0; k < adi->sup_size_cnt && vdi->fmt_cnt < max_fmt_cnt-1; k++) { /* Landscape video */ pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], fmt, adi->sup_size[k].w, adi->sup_size[k].h, DEFAULT_FPS, 1); /* Portrait video */ pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], fmt, adi->sup_size[k].h, adi->sup_size[k].w, DEFAULT_FPS, 1); } } (*jni_env)->ReleaseIntArrayElements(jni_env, jiarray, fmts, JNI_ABORT); (*jni_env)->DeleteLocalRef(jni_env, jtmp); /* Pretend to support I420/IYUV, only if we support YV12/NV21 */ if (!has_i420 && (adi->has_yv12 || adi->has_nv21) && vdi->fmt_cnt < PJ_ARRAY_SIZE(vdi->fmt)) { int k; adi->forced_i420 = PJ_TRUE; for (k = 0; k < adi->sup_size_cnt && vdi->fmt_cnt < max_fmt_cnt-1; k++) { pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], PJMEDIA_FORMAT_I420, adi->sup_size[k].w, adi->sup_size[k].h, DEFAULT_FPS, 1); pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], PJMEDIA_FORMAT_I420, adi->sup_size[k].h, adi->sup_size[k].w, DEFAULT_FPS, 1); } } } else { goto on_skip_dev; } /* If this is front camera, set it as first/default (if not yet) */ if (facing == 1) { if (!found_front && f->dev_count > 0) { /* Swap this front cam info with one whose idx==0 */ and_dev_info tmp_adi; pj_memcpy(&tmp_adi, &f->dev_info[0], sizeof(tmp_adi)); pj_memcpy(&f->dev_info[0], adi, sizeof(tmp_adi)); pj_memcpy(adi, &tmp_adi, sizeof(tmp_adi)); f->dev_info[0].info.id = 0; f->dev_info[f->dev_count].info.id = f->dev_count; } found_front = PJ_TRUE; } f->dev_count++; on_skip_dev: (*jni_env)->DeleteLocalRef(jni_env, jdev_info); } PJ_LOG(4, (THIS_FILE, "Android video capture initialized with %d device(s):", f->dev_count)); for (i = 0; i < f->dev_count; i++) { and_dev_info *adi = &f->dev_info[i]; char tmp_str[2048], *p; int j, plen, slen; PJ_LOG(4, (THIS_FILE, "%2d: %s", i, f->dev_info[i].info.name)); /* Print supported formats */ p = tmp_str; plen = sizeof(tmp_str); for (j = 0; j < adi->info.fmt_cnt; j++) { char tmp_str2[5]; const pjmedia_video_format_detail *vfd = pjmedia_format_get_video_format_detail(&adi->info.fmt[j], 0); pjmedia_fourcc_name(adi->info.fmt[j].id, tmp_str2); slen = pj_ansi_snprintf(p, plen, "%s/%dx%d ", tmp_str2, vfd->size.w, vfd->size.h); if (slen < 0 || slen >= plen) break; plen -= slen; p += slen; } PJ_LOG(4, (THIS_FILE, " supported format = %s", tmp_str)); } on_return: jni_detach_env(with_attach); return status; }
int CCameraPjsip::OnOpen(VideoInfo* pVideoInfo) { int nRet = 0; pj_status_t status = PJ_FALSE; if (m_pVidDevStream) { LOG_MODEL_ERROR("CCamera", "camera has opened"); return -1; } pj_caching_pool_init(&m_Caching_pool, &pj_pool_factory_default_policy, 0); pj_pool_t* pPool = pj_pool_create(&m_Caching_pool.factory, "carmeraPara", 1000, 1000, NULL); if (NULL == pPool) { LOG_MODEL_ERROR("CCamera", "pj_pool_create fail"); return -2; } pjmedia_vid_dev_param param; status = pjmedia_vid_dev_default_param(pPool, m_nIndex, ¶m); if (PJ_SUCCESS != status) { LOG_MODEL_ERROR("CCamera", "pjmedia_vid_dev_default_param fail"); pj_pool_release(pPool); return -3; } pj_pool_release(pPool); if (param.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) { LOG_MODEL_ERROR("CCamera", "deivce isn't video capture"); return -4; } if (pVideoInfo) { pjmedia_format fmt; pjmedia_format_init_video(&fmt, pVideoInfo->Format, pVideoInfo->nWidth, pVideoInfo->nHeight, pVideoInfo->nRatio, 1 ); param.fmt = fmt; m_VideoInfo = *pVideoInfo; } param.dir = PJMEDIA_DIR_CAPTURE; status = pjmedia_vid_dev_stream_create(¶m, &m_VidDevCb, this, &m_pVidDevStream); if (PJ_SUCCESS != status) { LOG_MODEL_ERROR("CCamera", "pjmedia_vid_dev_stream_create faile"); return -5; } //检查设备指定的格式 pjmedia_video_format_detail *vfd; vfd = pjmedia_format_get_video_format_detail(¶m.fmt, PJ_FALSE); if (vfd == NULL) { LOG_MODEL_ERROR("CCamera", "deivce don't contains the format"); Close(); return -6; } m_VideoInfo.nWidth = vfd->size.w; m_VideoInfo.nHeight = vfd->size.h; m_VideoInfo.nRatio = vfd->fps.num; m_VideoInfo.Format = (VideoFormat) param.fmt.id; return nRet; }