| 445 | ~GenericDecodeReader() { Close(); } |
| 446 | |
| 447 | void Open() { |
| 448 | CheckAv(avformat_open_input(&format_context_, options_.video_path.c_str(), nullptr, nullptr), |
| 449 | "avformat_open_input"); |
| 450 | CheckAv(avformat_find_stream_info(format_context_, nullptr), "avformat_find_stream_info"); |
| 451 | |
| 452 | video_stream_index_ = av_find_best_stream(format_context_, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); |
| 453 | CheckAv(video_stream_index_, "av_find_best_stream"); |
| 454 | |
| 455 | stream_ = format_context_->streams[video_stream_index_]; |
| 456 | codec_ = avcodec_find_decoder(stream_->codecpar->codec_id); |
| 457 | if (!codec_) { |
| 458 | throw std::runtime_error("Unable to find decoder for input video stream"); |
| 459 | } |
| 460 | |
| 461 | codec_context_ = avcodec_alloc_context3(codec_); |
| 462 | if (!codec_context_) { |
| 463 | throw std::runtime_error("Unable to allocate codec context"); |
| 464 | } |
| 465 | |
| 466 | CheckAv(avcodec_parameters_to_context(codec_context_, stream_->codecpar), |
| 467 | "avcodec_parameters_to_context"); |
| 468 | codec_context_->thread_count = std::min(8, std::max(1, static_cast<int>(std::thread::hardware_concurrency()))); |
| 469 | if (decode_kind_ == DecodeKind::Vulkan) { |
| 470 | // Frame-threaded decode has shown stalls with Vulkan hw surfaces on some drivers. |
| 471 | // Keep multi-threading enabled via slice threads while disabling frame threading. |
| 472 | codec_context_->thread_type &= ~FF_THREAD_FRAME; |
| 473 | if (codec_context_->thread_type == 0) |
| 474 | codec_context_->thread_type = FF_THREAD_SLICE; |
| 475 | } |
| 476 | codec_context_->pkt_timebase = stream_->time_base; |
| 477 | |
| 478 | AVHWDeviceType hw_device_type = AV_HWDEVICE_TYPE_NONE; |
| 479 | const char* device_name = nullptr; |
| 480 | if (decode_kind_ == DecodeKind::Cuda) { |
| 481 | hw_device_type = AV_HWDEVICE_TYPE_CUDA; |
| 482 | } else if (decode_kind_ == DecodeKind::Vaapi) { |
| 483 | hw_device_type = AV_HWDEVICE_TYPE_VAAPI; |
| 484 | device_name = options_.vaapi_device.c_str(); |
| 485 | } else if (decode_kind_ == DecodeKind::Vulkan) { |
| 486 | hw_device_type = AV_HWDEVICE_TYPE_VULKAN; |
| 487 | } |
| 488 | |
| 489 | if (hw_device_type != AV_HWDEVICE_TYPE_NONE && |
| 490 | av_hwdevice_ctx_create(&hw_device_context_, hw_device_type, device_name, nullptr, 0) >= 0) { |
| 491 | codec_context_->opaque = this; |
| 492 | codec_context_->get_format = &GenericDecodeReader::SelectPixelFormat; |
| 493 | codec_context_->hw_device_ctx = av_buffer_ref(hw_device_context_); |
| 494 | } |
| 495 | |
| 496 | CheckAv(avcodec_open2(codec_context_, codec_, nullptr), "avcodec_open2"); |
| 497 | } |
| 498 | |
| 499 | void Close() { |
| 500 | if (codec_context_) { |
no test coverage detected