diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index cda32be873..ed1d99bdb0 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -607,6 +607,7 @@ struct CvCapture_FFMPEG int hw_device; int use_opencl; int extraDataIdx; + int requestedThreads; }; void CvCapture_FFMPEG::init() @@ -658,6 +659,7 @@ void CvCapture_FFMPEG::init() hw_device = -1; use_opencl = 0; extraDataIdx = 1; + requestedThreads = cv::getNumberOfCPUs(); } @@ -993,13 +995,7 @@ inline void fill_codec_context(AVCodecContext * enc, AVDictionary * dict) if (!enc->thread_count) { int nCpus = cv::getNumberOfCPUs(); - int requestedThreads = std::min(nCpus, 16); // [OPENCV:FFMPEG:24] Application has requested XX threads. Using a thread count greater than 16 is not recommended. - std::string threads_option = utils::getConfigurationParameterString("OPENCV_FFMPEG_THREADS"); - if (!threads_option.empty()) - { - requestedThreads = atoi(threads_option.c_str()); - } - enc->thread_count = requestedThreads; + enc->thread_count = std::min(nCpus, 16); // [OPENCV:FFMPEG:24] Application has requested XX threads. Using a thread count greater than 16 is not recommended. } AVDictionaryEntry* avdiscard_entry = av_dict_get(dict, "avdiscard", NULL, 0); @@ -1120,7 +1116,7 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr& str #endif if (params.has(CAP_PROP_N_THREADS)) { - nThreads = params.get(CAP_PROP_N_THREADS); + nThreads = requestedThreads = params.get(CAP_PROP_N_THREADS); } if (params.warnUnusedParameters()) { @@ -1129,6 +1125,15 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr& str } } + if (params.empty() || !params.has(CAP_PROP_N_THREADS)) + { + std::string threads_option = utils::getConfigurationParameterString("OPENCV_FFMPEG_THREADS"); + if (!threads_option.empty()) + { + nThreads = requestedThreads = atoi(threads_option.c_str()); + } + } + #if USE_AV_INTERRUPT_CALLBACK /* interrupt callback */ interrupt_metadata.timeout_after_ms = open_timeout; @@ -1748,6 +1753,51 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, frame.height != video_st->CV_FFMPEG_CODEC_FIELD->height || frame.data == NULL ) { +#if LIBSWSCALE_BUILD >= CALC_FFMPEG_VERSION(6, 4, 100) + int buffer_width = video_st->CV_FFMPEG_CODEC_FIELD->width; + int buffer_height = video_st->CV_FFMPEG_CODEC_FIELD->height; + + // Reproduce sws_getCachedContext but with threads option + int64_t src_h_chr_pos = -513, dst_h_chr_pos = -513, + src_v_chr_pos = -513, dst_v_chr_pos = -513; + if (img_convert_ctx) + { + av_opt_get_int(img_convert_ctx, "src_h_chr_pos", 0, &src_h_chr_pos); + av_opt_get_int(img_convert_ctx, "src_v_chr_pos", 0, &src_v_chr_pos); + av_opt_get_int(img_convert_ctx, "dst_h_chr_pos", 0, &dst_h_chr_pos); + av_opt_get_int(img_convert_ctx, "dst_v_chr_pos", 0, &dst_v_chr_pos); + sws_freeContext(img_convert_ctx); + img_convert_ctx = NULL; + } + + img_convert_ctx = sws_alloc_context(); + if (img_convert_ctx == NULL) + return false;//CV_Error(0, "Cannot initialize the conversion context!"); + + av_opt_set_int(img_convert_ctx, "sws_flags", SWS_BICUBIC, 0); + av_opt_set_int(img_convert_ctx, "threads", requestedThreads, 0); + + if (swscale_version() < CALC_FFMPEG_VERSION(8, 12, 100)) + { + av_opt_set_int(img_convert_ctx, "src_h_chr_pos", src_h_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "src_v_chr_pos", src_v_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "dst_h_chr_pos", dst_h_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "dst_v_chr_pos", dst_v_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "srcw", buffer_width, 0); + av_opt_set_int(img_convert_ctx, "srch", buffer_height, 0); + av_opt_set_int(img_convert_ctx, "dstw", buffer_width, 0); + av_opt_set_int(img_convert_ctx, "dsth", buffer_height, 0); + av_opt_set_pixel_fmt(img_convert_ctx, "src_format", (AVPixelFormat)sw_picture->format, 0); + av_opt_set_pixel_fmt(img_convert_ctx, "dst_format", result_format, 0); + av_opt_set_double(img_convert_ctx, "param0", SWS_PARAM_DEFAULT, 0); + av_opt_set_double(img_convert_ctx, "param1", SWS_PARAM_DEFAULT, 0); + + if (sws_init_context(img_convert_ctx, NULL, NULL) < 0) { + sws_freeContext(img_convert_ctx); + img_convert_ctx = NULL; + } + } +#else // Some sws_scale optimizations have some assumptions about alignment of data/step/width/height // Also we use coded_width/height to workaround problem with legacy ffmpeg versions (like n0.8) int buffer_width = context->coded_width, buffer_height = context->coded_height; @@ -1761,6 +1811,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, SWS_BICUBIC, NULL, NULL, NULL ); +#endif if (img_convert_ctx == NULL) return false;//CV_Error(0, "Cannot initialize the conversion context!"); @@ -1790,6 +1841,9 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, frame.step = rgb_picture.linesize[0]; } +#if LIBSWSCALE_BUILD >= CALC_FFMPEG_VERSION(6, 4, 100) + sws_scale_frame(img_convert_ctx, &rgb_picture, sw_picture); +#else sws_scale( img_convert_ctx, sw_picture->data, @@ -1798,6 +1852,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, rgb_picture.data, rgb_picture.linesize ); +#endif *data = frame.data; *step = frame.step;