Skip to content

Automatically write RTSP streams to file during VideoCapture Decode with FFmpeg#20444

Closed
cudawarped wants to merge 9 commits intoopencv:4.xfrom
cudawarped:add_rtsp_video_write
Closed

Automatically write RTSP streams to file during VideoCapture Decode with FFmpeg#20444
cudawarped wants to merge 9 commits intoopencv:4.xfrom
cudawarped:add_rtsp_video_write

Conversation

@cudawarped
Copy link
Copy Markdown
Contributor

@cudawarped cudawarped commented Jul 22, 2021

It is really common these days to live stream directly from IP camera's and perform image processing on the decoded frames. Because the data is live it is also desirable to save the original data somewhere for archival and/or later processing. Currently the only way to do this is to re-encode the decoded frames, which has a significant overhead and will not be produce an exact duplicate of the source, due to encoding differences.

The pull request adds the functionality to write the raw bitstream to a given file during the calls to read()/grab(). It seemed appropriate to place this functionality there because it can also be utilized when reading raw data only, currently used by cudacodec.

Additionally I added the capacity for raw reads to append the side info which is commonly provided when streaming from and RTSP source to the beginning of the stream. This will mostly be a duplicate but some IP cameras, from memory axis is one, don't send the SPS and PPS in band.

In loop restart of recording cannot be tested because there are no media test file with more than one key frame. If this pull request is suitable for inclusion it may be worth including an extra media file and test.

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch
  • There is reference to original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

…ng frames with ffmpeg backend.

Plugins not compiled or tested.
@asmorkalov
Copy link
Copy Markdown
Contributor

OpenCV_contrib contains cudacodec module that utilizes cv::VideoCapture to grub frames with FFmpeg and decode it with hardware codec on NVIDIA GPU. OpenCV cv::VideoCapture already has functionality to get RAW stream. Please take a look at the module source code: https://github.com/opencv/opencv_contrib/tree/master/modules/cudacodec

@cudawarped
Copy link
Copy Markdown
Contributor Author

I understand that the raw stream can be retrieved, however it cannot be decoded on the CPU with FFMPEG at the same time as being written to disk without re-encoding. This would be useful when reading from an IP camera, processing the recieved video and archiving the footage. Currently to do this would require the overhead of wastefully re-encoding the decoded frames. This would also not result in an exact copy of the streamed data due to re-encoding.

This functionality could be added directly to cudacodec, however I thought it might be easier to add it directly to VideoCapture so that it can be seamlessly used by cudacodec, any class like cudacodec with reads the raw stream for decoding and VideoCapture. Additionaly it removes the need for querying when a new key frame occurs and/or manually parsing the raw stream for the frame type.

@cudawarped
Copy link
Copy Markdown
Contributor Author

@asmorkalov
Just to confirm the expected functionality for this pull request is, given a srcUrl and a filename VideoCapture() can be called as

VideoCapture cap(filename,CAP_FFMPEG);
cap.writeToFile(filename);

and then any subsequent calls to
cap.read(img)
will retrieve the decoded frame to img and at the same time archive the raw encoded data to the file named filename. This raw data is then "exactly" the same as the source and can therefore be interogated at a later date should it be necessary. If instead the img is re-encoded using VideoWriter() any analytics run on that frame are not guaranteed to yield the same results.

Additionaly if a newFilename is given as
cap.writeToFile(newFilename);
VideoCapture() will wait until the next iFrame before closing the the first file (filename) and writing to the new file (newFilename).

From your comments I assume it is not desirable to add these extra api calls to VideoCapture(), if possible can you suggest a different way to achieve the same outcome?

If not I can just leave this feature out from VideoCapture() add it only to cv::cudacodec::VideoReader() as you suggested above. This would just require a small modification to VideoCapture::grab(img) (in addition to changes to cv::cudacodec::VideoReader()) to enable the returned img to indicate whether it contains the encoded data for an iframe and/or whether it additionaly contains the parameter sets (stored internally by ffmpeg for rtsp streams in AVFormatContext::streams[i]->codec->extradata). I was thinking that the channel parameter img.cn could be used for this, with img.cn == 0 indicating non iframe, img.cn > 0 indicating an iframe and img.cn == N indicating that the first N bytes of raw data contained in img are the parameter set (this will always be an iframe as it will only occur on the first call to VideoCapture::read()).

Would this alternative be acceptable?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants