Skip to content

Using environment variable to store capture options#9292

Merged
vpisarev merged 4 commits intoopencv:masterfrom
adamrankin:ffmpeg_capture_options
Sep 19, 2017
Merged

Using environment variable to store capture options#9292
vpisarev merged 4 commits intoopencv:masterfrom
adamrankin:ffmpeg_capture_options

Conversation

@adamrankin
Copy link
Copy Markdown
Contributor

String is parsed by av_dict_parse_string(ENV{OPENCV_FFMPEG_CAPTURE_OPTIONS}, ";", "|")

resolves #9290

This pullrequest changes

Allows configuration of ffmpeg capture options via environment variable. If variable is not set or OpenCV cannot read env variables, defaults to TCP as per previous behaviour.

@adamrankin
Copy link
Copy Markdown
Contributor Author

Hello, I'm having trouble identifying which version of ffmpeg is used for the build. I set up a linux build of FFMPEG/OpenCV and I don't get any compile issues.

Any help would be appreciated.

@berak
Copy link
Copy Markdown
Contributor

berak commented Aug 2, 2017

from here (quite at the bottom), that's the failed one:

--   Video I/O:
--     DC1394 1.x:                  NO
--     DC1394 2.x:                  NO
--     FFMPEG:                      YES
--       avcodec:                   YES (ver 54.35.1)
--       avformat:                  YES (ver 54.20.4)
--       avutil:                    YES (ver 52.3.0)
--       swscale:                   YES (ver 2.1.1)
--       avresample:                NO
--     GStreamer:                   NO

while the linux opencl bot (success) has:

--     FFMPEG:                      YES
--       avcodec:                   YES (ver 56.60.100)
--       avformat:                  YES (ver 56.40.101)
--       avutil:                    YES (ver 54.31.100)
--       swscale:                   YES (ver 3.1.101)
--       avresample:                NO

@alalek
Copy link
Copy Markdown
Member

alalek commented Aug 2, 2017

These builders are based on Ubuntu 14.04 (failed) and Ubuntu 16.04 (passed).
You need to determine related API changes from ffmpeg and libav and specify proper "#ifdef" guards to use av_dict_parse_string.

#endif

#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
#if LIBAVFORMAT_BUILD > CALC_FFMPEG_VERSION(51,11,0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change here?

  • Condition must be ">=". ">" should not be used at all for version checks.
  • Perhaps we should check for 53.4.0 (avformat_open_input)
  • These change must be propagated to many places with "dict" (av_dict_free / declaration / etc)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah crap, this is a mistake. Sorry about the sloppy commits.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With regards to 53.4.0, that makes sense to me. However, I am already making mistakes with regards to ffmpeg version checks, so ideally I would make as few changes as possible.

}
else
{
#if LIBAVUTIL_BUILD > CALC_FFMPEG_VERSION(52,6,0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"lavu 52.17.100 / 52.7.0"

#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 ? CALC_FFMPEG_VERSION(52, 17, 100) : CALC_FFMPEG_VERSION(52, 7, 0))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I am unfamiliar with the ffmpeg versioning. Fixes incoming.

Copy/paste error due to coder mistake reverted
Proper version checking for LIBAVUTIL_BUILD
@adamrankin
Copy link
Copy Markdown
Contributor Author

New code usage could be as follows:

#if WIN32
  _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp");
#else
  setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp");
#endif

auto capture = cv::VideoCapture(someURL, cv::CAP_FFMPEG);

#if WIN32
  _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "");
#else
  unsetenv("OPENCV_FFMPEG_CAPTURE_OPTIONS");
#endif

@PhilLab
Copy link
Copy Markdown
Contributor

PhilLab commented Aug 7, 2017

Definitely interesting, thanks a lot 👍
Was the old idea of using an enum not applicable for this patch? I.e. an enum CV_FFMPEG_CAP_TRANSPORT_UDP which can be set to 0.0 or 1.0.

And is there a place in the documentation where your latest comment could be added?

@adamrankin
Copy link
Copy Markdown
Contributor Author

adamrankin commented Aug 7, 2017

Hmm, that does seem cleaner. The only pro to this method (I was inspired by another bug report of a similar topic) is that now you can pass any option(s) to ffmpeg.

I'm happy to write it up, but I'm not familiar with the docs. I'd appreciate any pointer to the right spot!

@PhilLab
Copy link
Copy Markdown
Contributor

PhilLab commented Aug 7, 2017

Both ways have their pros/cons. I'm unsure which one to prefer.
Regarding the enum way, I would place it like the device-specific flags which are documented by //!< (cf. the videoio.hpp)

@adamrankin
Copy link
Copy Markdown
Contributor Author

I think I would stay with the current implementation. Is this mergeable?

@vpisarev vpisarev self-assigned this Sep 13, 2017
@vpisarev
Copy link
Copy Markdown
Contributor

vpisarev commented Sep 13, 2017

how robust is the solution? Assume that there are 2 apps on a system, one just uses opencv + ffmpeg to read videos from disk, another one reads videos via network and so the options are relevant. This solution is global and so the first app will stop working. Shall we come up with some better solution?

@adamrankin
Copy link
Copy Markdown
Contributor Author

@vpisarev I'm open to other solutions, but this solution is only global if the env variable is set permanently. Given my code example above, the options can be set in the code (more advanced code could cache any pre-existing options, and then restore them after connecting) without applying to other programs.

@alalek
Copy link
Copy Markdown
Member

alalek commented Sep 13, 2017

Environment variables have process scope, so solution/workaround is fine until we have some configuration API in OpenCV.
Looks good to me 👍

@vpisarev vpisarev removed their assignment Sep 19, 2017
@vpisarev vpisarev merged commit fb8143d into opencv:master Sep 19, 2017
dkurt pushed a commit to dkurt/opencv that referenced this pull request Sep 23, 2017
* Using environment variable to store options parsed by av_dict_parse_string(ENV{OPENCV_FFMPEG_CAPTURE_OPTIONS}, ";", "|")

* Adding missing mandatory flags parameter

* Guarding against missing function via LIBAVUTIL version

* Code review fixes

Copy/paste error due to coder mistake reverted
Proper version checking for LIBAVUTIL_BUILD
@alalek alalek mentioned this pull request Oct 9, 2017
@golden0080
Copy link
Copy Markdown

Hey, Guys, I'm happy to find out that TCP issue is fixed in this patch. But only by reading code, I'm a little bit confused how to tell OpenCV to use UDP whenever reading RTSP streams. Can you guys kindly provide a simple example?

@adamrankin
Copy link
Copy Markdown
Contributor Author

You'll have to set an environment variable when creating the device

#if WIN32
  _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp");
#else
  setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp");
#endif

auto capture = cv::VideoCapture(someURL, cv::CAP_FFMPEG);

#if WIN32
  _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "");
#else
  unsetenv("OPENCV_FFMPEG_CAPTURE_OPTIONS");
#endif

@think-free
Copy link
Copy Markdown

This solution doesn't work on windows when using a dynamic library. Something like this seems to occure.
Ffmpeg parameters should be passed as parameters or configured by calling a function before the open.

The use case is when mixing several rtsp stream with mixed protocol (udp,tcp) in the same executable. The environment variable set by code isn't reflected in the opencv library.

Works fine on linux ...

@adamrankin
Copy link
Copy Markdown
Contributor Author

What a pain, thank you for catching this. I recommend opening a new issue to change the env var approach!

@osmantoker
Copy link
Copy Markdown

You'll have to set an environment variable when creating the device

#if WIN32
  _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp");
#else
  setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp");
#endif

auto capture = cv::VideoCapture(someURL, cv::CAP_FFMPEG);

#if WIN32
  _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "");
#else
  unsetenv("OPENCV_FFMPEG_CAPTURE_OPTIONS");
#endif

hi, how can I set this env. on Java OpenCV?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffmpeg capture forced to TCP, even if UDP is desired

8 participants