- Timestamp:
- Dec 28, 2016 3:40:07 AM (8 years ago)
- Location:
- pjproject/branches/projects/uwp
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/uwp
- Property svn:mergeinfo changed
/pjproject/trunk (added) merged: 5209,5212-5234,5237-5253,5255,5257-5292,5294-5297,5299-5332,5334-5394,5396-5438,5440-5469,5471-5496,5498-5510
- Property svn:mergeinfo changed
-
pjproject/branches/projects/uwp/pjmedia/src/pjmedia-videodev/ffmpeg_dev.c
r4722 r5513 40 40 41 41 #if defined(PJMEDIA_HAS_VIDEO) && PJMEDIA_HAS_VIDEO != 0 && \ 42 defined(PJMEDIA_HAS_LIBAVDEVICE) && PJMEDIA_HAS_LIBAVDEVICE != 0 && \ 42 43 defined(PJMEDIA_VIDEO_DEV_HAS_FFMPEG) && PJMEDIA_VIDEO_DEV_HAS_FFMPEG != 0 43 44 44 45 45 46 #define THIS_FILE "ffmpeg.c" 47 48 #define LIBAVFORMAT_VER_AT_LEAST(major,minor) (LIBAVFORMAT_VERSION_MAJOR > major || \ 49 (LIBAVFORMAT_VERSION_MAJOR == major && \ 50 LIBAVFORMAT_VERSION_MINOR >= minor)) 46 51 47 52 #include "../pjmedia/ffmpeg_util.h" 48 53 #include <libavdevice/avdevice.h> 49 54 #include <libavformat/avformat.h> 55 #if LIBAVFORMAT_VER_AT_LEAST(53,2) 56 # include <libavutil/pixdesc.h> 57 #endif 50 58 51 59 #define MAX_DEV_CNT 8 60 61 #ifndef PJMEDIA_USE_OLD_FFMPEG 62 # define av_close_input_stream(ctx) avformat_close_input(&ctx) 63 #endif 64 52 65 53 66 typedef struct ffmpeg_dev_info … … 77 90 pjmedia_vid_dev_param param; 78 91 AVFormatContext *ff_fmt_ctx; 92 void *frame_buf; 79 93 } ffmpeg_stream; 80 94 … … 149 163 { 150 164 PJ_UNUSED_ARG(ptr); 151 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 152 170 vfprintf(stdout, fmt, vl); 153 171 } … … 159 177 const pjmedia_vid_dev_param *param) 160 178 { 179 #if LIBAVFORMAT_VER_AT_LEAST(53,2) 180 AVDictionary *format_opts = NULL; 181 char buf[128]; 182 enum AVPixelFormat av_fmt; 183 #else 161 184 AVFormatParameters fp; 185 #endif 162 186 pjmedia_video_format_detail *vfd; 187 pj_status_t status; 163 188 int err; 164 189 … … 167 192 PJ_EINVAL); 168 193 194 status = pjmedia_format_id_to_PixelFormat(param->fmt.id, &av_fmt); 195 if (status != PJ_SUCCESS) { 196 avformat_free_context(*ctx); 197 return status; 198 } 199 169 200 vfd = pjmedia_format_get_video_format_detail(¶m->fmt, PJ_TRUE); 170 201 … … 172 203 *ctx = avformat_alloc_context(); 173 204 205 #if LIBAVFORMAT_VER_AT_LEAST(53,2) 206 /* Init ffmpeg dictionary */ 207 /* 208 snprintf(buf, sizeof(buf), "%d/%d", vfd->fps.num, vfd->fps.denum); 209 av_dict_set(&format_opts, "framerate", buf, 0); 210 snprintf(buf, sizeof(buf), "%dx%d", vfd->size.w, vfd->size.h); 211 av_dict_set(&format_opts, "video_size", buf, 0); 212 av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(av_fmt), 0); 213 */ 214 /* Open capture stream */ 215 err = avformat_open_input(ctx, dev_name, ifmt, &format_opts); 216 #else 174 217 /* Init ffmpeg format param */ 175 218 pj_bzero(&fp, sizeof(fp)); … … 177 220 fp.width = vfd->size.w; 178 221 fp.height = vfd->size.h; 179 fp.pix_fmt = PIX_FMT_BGR24;222 fp.pix_fmt = av_fmt; 180 223 fp.time_base.num = vfd->fps.denum; 181 224 fp.time_base.den = vfd->fps.num; … … 183 226 /* Open capture stream */ 184 227 err = av_open_input_stream(ctx, NULL, dev_name, ifmt, &fp); 228 #endif 185 229 if (err < 0) { 186 230 *ctx = NULL; /* ffmpeg freed its states on failure, do we must too */ … … 245 289 } 246 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 247 391 /* API: refresh the list of devices */ 248 392 static pj_status_t ffmpeg_factory_refresh(pjmedia_vid_dev_factory *f) … … 250 394 ffmpeg_factory *ff = (ffmpeg_factory*)f; 251 395 AVInputFormat *p; 252 ffmpeg_dev_info *info;253 396 254 397 av_log_set_callback(&print_ffmpeg_log); 255 av_log_set_level(AV_LOG_ DEBUG);398 av_log_set_level(AV_LOG_ERROR); 256 399 257 400 if (ff->dev_pool) { … … 260 403 } 261 404 262 /* TODO: this should enumerate devices, now it enumerates host APIs */263 405 ff->dev_count = 0; 264 406 ff->dev_pool = pj_pool_create(ff->pf, "ffmpeg_cap_dev", 500, 500, NULL); 265 407 266 p = av_iformat_next(NULL); 267 while (p) { 268 if (p->flags & AVFMT_NOFILE) { 269 unsigned i; 270 271 info = &ff->dev_info[ff->dev_count++]; 272 pj_bzero(info, sizeof(*info)); 273 pj_ansi_strncpy(info->base.name, "default", 274 sizeof(info->base.name)); 275 pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver), 276 "%s (ffmpeg)", p->name); 277 info->base.dir = PJMEDIA_DIR_CAPTURE; 278 info->base.has_callback = PJ_FALSE; 279 280 info->host_api = p; 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 415 if ((p->flags & AVFMT_NOFILE)==0 || p->read_probe) { 416 goto next_format; 417 } 281 418 282 419 #if (defined(PJ_WIN32) && PJ_WIN32!=0) || \ 283 420 (defined(PJ_WIN64) && PJ_WIN64!=0) 284 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 } 285 429 #elif defined(PJ_LINUX) && PJ_LINUX!=0 286 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; 287 434 #endif 288 435 289 /* Set supported formats, currently hardcoded to RGB24 only */ 290 info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT; 291 info->base.fmt_cnt = 1; 292 for (i = 0; i < info->base.fmt_cnt; ++i) { 293 pjmedia_format *fmt = &info->base.fmt[i]; 294 295 fmt->id = PJMEDIA_FORMAT_RGB24; 296 fmt->type = PJMEDIA_TYPE_VIDEO; 297 fmt->detail_type = PJMEDIA_FORMAT_DETAIL_NONE; 298 } 299 } 300 p = av_iformat_next(p); 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 } 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); 493 } 494 495 next_format: 496 p = av_input_video_device_next(p); 301 497 } 302 498 … … 387 583 pj_memcpy(&strm->param, param, sizeof(*param)); 388 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 389 600 /* Done */ 390 601 strm->base.op = &stream_op; … … 392 603 393 604 return PJ_SUCCESS; 605 606 on_error: 607 pj_pool_release(pool); 608 return PJMEDIA_EVID_INVCAP; 394 609 } 395 610 … … 463 678 { 464 679 ffmpeg_stream *strm = (ffmpeg_stream*)s; 465 AVPacket p ;680 AVPacket p = {0}; 466 681 int err; 467 682 … … 474 689 pj_bzero(frame, sizeof(*frame)); 475 690 frame->type = PJMEDIA_FRAME_TYPE_VIDEO; 476 frame->buf = p.data;691 frame->buf = strm->frame_buf; 477 692 frame->size = p.size; 693 pj_memcpy(frame->buf, p.data, p.size); 694 av_free_packet(&p); 478 695 479 696 return PJ_SUCCESS;
Note: See TracChangeset
for help on using the changeset viewer.