- Timestamp:
- Sep 29, 2016 4:04:22 AM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia-videodev/ffmpeg_dev.c
r5399 r5441 90 90 pjmedia_vid_dev_param param; 91 91 AVFormatContext *ff_fmt_ctx; 92 void *frame_buf; 92 93 } ffmpeg_stream; 93 94 … … 162 163 { 163 164 PJ_UNUSED_ARG(ptr); 164 PJ_UNUSED_ARG(level); 165 166 /* Custom callback needs to filter log level by itself */ 167 if (level > av_log_get_level()) 168 return; 169 165 170 vfprintf(stdout, fmt, vl); 166 171 } … … 200 205 #if LIBAVFORMAT_VER_AT_LEAST(53,2) 201 206 /* Init ffmpeg dictionary */ 207 /* 202 208 snprintf(buf, sizeof(buf), "%d/%d", vfd->fps.num, vfd->fps.denum); 203 209 av_dict_set(&format_opts, "framerate", buf, 0); … … 205 211 av_dict_set(&format_opts, "video_size", buf, 0); 206 212 av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(av_fmt), 0); 207 213 */ 208 214 /* Open capture stream */ 209 215 err = avformat_open_input(ctx, dev_name, ifmt, &format_opts); … … 283 289 } 284 290 291 292 #if (defined(PJ_WIN32) && PJ_WIN32!=0) || \ 293 (defined(PJ_WIN64) && PJ_WIN64!=0) 294 295 #ifdef _MSC_VER 296 # pragma warning(push, 3) 297 #endif 298 299 #define COBJMACROS 300 #include <DShow.h> 301 #pragma comment(lib, "Strmiids.lib") 302 303 #ifdef _MSC_VER 304 # pragma warning(pop) 305 #endif 306 307 #define MAX_DEV_NAME_LEN 80 308 309 static pj_status_t dshow_enum_devices(unsigned *dev_cnt, 310 char dev_names[][MAX_DEV_NAME_LEN]) 311 { 312 unsigned max_cnt = *dev_cnt; 313 ICreateDevEnum *dev_enum = NULL; 314 IEnumMoniker *enum_cat = NULL; 315 IMoniker *moniker = NULL; 316 HRESULT hr; 317 ULONG fetched; 318 unsigned i = 0; 319 320 CoInitialize(0); 321 322 *dev_cnt = 0; 323 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, 324 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum, 325 (void**)&dev_enum); 326 if (FAILED(hr) || 327 ICreateDevEnum_CreateClassEnumerator(dev_enum, 328 &CLSID_VideoInputDeviceCategory, &enum_cat, 0) != S_OK) 329 { 330 PJ_LOG(4,(THIS_FILE, "Windows found no video input devices")); 331 if (dev_enum) 332 ICreateDevEnum_Release(dev_enum); 333 334 return PJ_SUCCESS; 335 } 336 337 while (IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK && 338 *dev_cnt < max_cnt) 339 { 340 (*dev_cnt)++; 341 } 342 343 if (*dev_cnt == 0) { 344 IEnumMoniker_Release(enum_cat); 345 ICreateDevEnum_Release(dev_enum); 346 return PJ_SUCCESS; 347 } 348 349 IEnumMoniker_Reset(enum_cat); 350 while (i < max_cnt && 351 IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK) 352 { 353 IPropertyBag *prop_bag; 354 355 hr = IMoniker_BindToStorage(moniker, 0, 0, &IID_IPropertyBag, 356 (void**)&prop_bag); 357 if (SUCCEEDED(hr)) { 358 VARIANT var_name; 359 360 VariantInit(&var_name); 361 hr = IPropertyBag_Read(prop_bag, L"FriendlyName", &var_name, 362 NULL); 363 if (SUCCEEDED(hr) && var_name.bstrVal) { 364 char tmp[MAX_DEV_NAME_LEN] = {0}; 365 WideCharToMultiByte(CP_ACP, 0, var_name.bstrVal, 366 (int)wcslen(var_name.bstrVal), 367 tmp, MAX_DEV_NAME_LEN, NULL, NULL); 368 pj_ansi_snprintf(dev_names[i++], MAX_DEV_NAME_LEN, 369 "video=%s", tmp); 370 } 371 VariantClear(&var_name); 372 IPropertyBag_Release(prop_bag); 373 } 374 IMoniker_Release(moniker); 375 } 376 377 IEnumMoniker_Release(enum_cat); 378 ICreateDevEnum_Release(dev_enum); 379 380 PJ_LOG(4, (THIS_FILE, "DShow has %d devices:", *dev_cnt)); 381 for (i = 0; i < *dev_cnt; ++i) { 382 PJ_LOG(4, (THIS_FILE, " %d: %s", (i+1), dev_names[i])); 383 } 384 385 return PJ_SUCCESS; 386 } 387 388 #endif /* PJ_WIN32 or PJ_WIN64 */ 389 390 285 391 /* API: refresh the list of devices */ 286 392 static pj_status_t ffmpeg_factory_refresh(pjmedia_vid_dev_factory *f) … … 288 394 ffmpeg_factory *ff = (ffmpeg_factory*)f; 289 395 AVInputFormat *p; 290 ffmpeg_dev_info *info;291 396 292 397 av_log_set_callback(&print_ffmpeg_log); 293 av_log_set_level(AV_LOG_ DEBUG);398 av_log_set_level(AV_LOG_ERROR); 294 399 295 400 if (ff->dev_pool) { … … 298 403 } 299 404 300 /* TODO: this should enumerate devices, now it enumerates host APIs */301 405 ff->dev_count = 0; 302 406 ff->dev_pool = pj_pool_create(ff->pf, "ffmpeg_cap_dev", 500, 500, NULL); 303 407 304 p = av_iformat_next(NULL); 305 while (p) { 306 AVFormatContext *ctx; 307 AVCodecContext *codec = NULL; 308 pjmedia_format_id fmt_id; 309 pj_status_t status; 310 unsigned i; 311 408 /* Iterate host APIs */ 409 p = av_input_video_device_next(NULL); 410 while (p && ff->dev_count < MAX_DEV_CNT) { 411 char dev_names[MAX_DEV_CNT][MAX_DEV_NAME_LEN]; 412 unsigned dev_cnt = MAX_DEV_CNT; 413 unsigned dev_idx; 414 312 415 if ((p->flags & AVFMT_NOFILE)==0 || p->read_probe) { 313 416 goto next_format; 314 417 } 315 418 316 info = &ff->dev_info[ff->dev_count];317 pj_bzero(info, sizeof(*info));318 pj_ansi_strncpy(info->base.name, "default",319 sizeof(info->base.name));320 pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver),321 "%s (ffmpeg)", p->name);322 info->base.dir = PJMEDIA_DIR_CAPTURE;323 info->base.has_callback = PJ_FALSE;324 325 info->host_api = p;326 327 419 #if (defined(PJ_WIN32) && PJ_WIN32!=0) || \ 328 420 (defined(PJ_WIN64) && PJ_WIN64!=0) 329 info->def_devname = "0"; 421 if (pj_ansi_strcmp(p->name, "dshow") == 0) { 422 dshow_enum_devices(&dev_cnt, dev_names); 423 } else if (pj_ansi_strcmp(p->name, "vfwcap") == 0) { 424 dev_cnt = 1; 425 pj_ansi_snprintf(dev_names[0], MAX_DEV_NAME_LEN, "0"); 426 } else { 427 dev_cnt = 0; 428 } 330 429 #elif defined(PJ_LINUX) && PJ_LINUX!=0 331 info->def_devname = "/dev/video0"; 430 dev_cnt = 1; 431 pj_ansi_snprintf(dev_names[0], MAX_DEV_NAME_LEN, "/dev/video0"); 432 #else 433 dev_cnt = 0; 332 434 #endif 333 435 334 ctx = avformat_alloc_context(); 335 if (!ctx || avformat_open_input(&ctx, info->def_devname, p, NULL)!=0) 336 goto next_format; 337 338 for(i = 0; i < ctx->nb_streams; i++) { 339 if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 340 codec = ctx->streams[i]->codec; 341 break; 436 /* Iterate devices (only DirectShow devices for now) */ 437 for (dev_idx = 0; dev_idx < dev_cnt && ff->dev_count < MAX_DEV_CNT; 438 ++dev_idx) 439 { 440 ffmpeg_dev_info *info; 441 AVFormatContext *ctx; 442 AVCodecContext *codec = NULL; 443 pjmedia_format_id fmt_id; 444 pj_str_t dev_name; 445 pj_status_t status; 446 unsigned i; 447 448 ctx = avformat_alloc_context(); 449 if (!ctx || avformat_open_input(&ctx, dev_names[dev_idx], p, NULL)!=0) 450 continue; 451 452 for(i = 0; i < ctx->nb_streams; i++) { 453 if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 454 codec = ctx->streams[i]->codec; 455 break; 456 } 342 457 } 458 if (!codec) { 459 av_close_input_stream(ctx); 460 continue; 461 } 462 463 status = PixelFormat_to_pjmedia_format_id(codec->pix_fmt, &fmt_id); 464 if (status != PJ_SUCCESS) { 465 av_close_input_stream(ctx); 466 continue; 467 } 468 469 info = &ff->dev_info[ff->dev_count++]; 470 pj_bzero(info, sizeof(*info)); 471 pj_ansi_strncpy(info->base.name, "default", 472 sizeof(info->base.name)); 473 pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver), 474 "ffmpeg %s", p->name); 475 476 pj_strdup2_with_null(ff->pool, &dev_name, dev_names[dev_idx]); 477 info->def_devname = dev_name.ptr; 478 info->base.dir = PJMEDIA_DIR_CAPTURE; 479 info->base.has_callback = PJ_FALSE; 480 481 info->host_api = p; 482 483 /* Set supported formats */ 484 info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT; 485 info->base.fmt_cnt = 1; 486 for (i = 0; i < info->base.fmt_cnt; ++i) { 487 pjmedia_format *fmt = &info->base.fmt[i]; 488 pjmedia_format_init_video(fmt, fmt_id, 489 codec->width, codec->height, 15, 1); 490 } 491 492 av_close_input_stream(ctx); 343 493 } 344 if (!codec) {345 av_close_input_stream(ctx);346 goto next_format;347 }348 349 status = PixelFormat_to_pjmedia_format_id(codec->pix_fmt, &fmt_id);350 if (status != PJ_SUCCESS) {351 av_close_input_stream(ctx);352 goto next_format;353 }354 355 /* Set supported formats */356 info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT;357 info->base.fmt_cnt = 1;358 for (i = 0; i < info->base.fmt_cnt; ++i) {359 pjmedia_format *fmt = &info->base.fmt[i];360 pjmedia_format_init_video(fmt, fmt_id,361 codec->width, codec->height, 15, 1);362 }363 364 av_close_input_stream(ctx);365 366 ff->dev_count++;367 494 368 495 next_format: 369 p = av_i format_next(p);496 p = av_input_video_device_next(p); 370 497 } 371 498 … … 456 583 pj_memcpy(&strm->param, param, sizeof(*param)); 457 584 585 /* Allocate frame buffer */ 586 { 587 const pjmedia_video_format_info *vfi; 588 pjmedia_video_apply_fmt_param vafp; 589 590 vfi = pjmedia_get_video_format_info(NULL, param->fmt.id); 591 if (!vfi) goto on_error; 592 593 pj_bzero(&vafp, sizeof(vafp)); 594 vafp.size = param->fmt.det.vid.size; 595 vfi->apply_fmt(vfi, &vafp); 596 597 strm->frame_buf = pj_pool_alloc(pool, vafp.framebytes); 598 } 599 458 600 /* Done */ 459 601 strm->base.op = &stream_op; … … 461 603 462 604 return PJ_SUCCESS; 605 606 on_error: 607 pj_pool_release(pool); 608 return PJMEDIA_EVID_INVCAP; 463 609 } 464 610 … … 532 678 { 533 679 ffmpeg_stream *strm = (ffmpeg_stream*)s; 534 AVPacket p ;680 AVPacket p = {0}; 535 681 int err; 536 682 … … 543 689 pj_bzero(frame, sizeof(*frame)); 544 690 frame->type = PJMEDIA_FRAME_TYPE_VIDEO; 545 frame->buf = p.data;691 frame->buf = strm->frame_buf; 546 692 frame->size = p.size; 693 pj_memcpy(frame->buf, p.data, p.size); 694 av_free_packet(&p); 547 695 548 696 return PJ_SUCCESS;
Note: See TracChangeset
for help on using the changeset viewer.