Fix Video Player that support generate black image when finish playing video (reach the end of video)

This commit is contained in:
2026-04-23 08:08:34 +10:00
parent f068eb716f
commit c625898f61
4 changed files with 24 additions and 17 deletions

View File

@@ -92,7 +92,10 @@
"Bash(git submodule *)", "Bash(git submodule *)",
"Bash(git rm *)", "Bash(git rm *)",
"Bash(rm -rf .git/modules/3rdparty/libyuv)", "Bash(rm -rf .git/modules/3rdparty/libyuv)",
"Bash(git add *)" "Bash(git add *)",
"Read(//c/ProgramData/Jh7O7nUe7vS/Models/EngineModels/B-IN_ANS_VehicleDetection_v2.0_67345015/**)",
"Bash(xxd)",
"Bash(icacls \"C:\\\\ProgramData\\\\Jh7O7nUe7vS\\\\Models\\\\EngineModels\\\\B-IN_ANS_VehicleDetection_v2.0_67345015\\\\train_last.onnx\")"
] ]
} }
} }

View File

@@ -253,7 +253,7 @@ namespace ANSCENTER {
_hwPlayer->play(); // starts read/video/audio threads _hwPlayer->play(); // starts read/video/audio threads
_hwEOF = false; _hwEOF = false;
_hwFrameCount = 0; _hwFrameCount = 0;
_hwLastPts = 0; _hwLastElapseMs = 0;
_isPlaying = true; _isPlaying = true;
// Wait for first frame outside the mutex to let decode threads run // Wait for first frame outside the mutex to let decode threads run
@@ -311,7 +311,7 @@ namespace ANSCENTER {
_hwCudaAccel = false; _hwCudaAccel = false;
_hwEOF = false; _hwEOF = false;
_hwFrameCount = 0; _hwFrameCount = 0;
_hwLastPts = 0; _hwLastElapseMs = 0;
} }
else { else {
// --- cv::VideoCapture fallback --- // --- cv::VideoCapture fallback ---
@@ -525,10 +525,14 @@ namespace ANSCENTER {
__FILE__, __LINE__); __FILE__, __LINE__);
} }
// EOF detection: CFilePlayer auto-loops, but ANSVideoPlayer should stop. // EOF detection: CFilePlayer auto-loops via av_seek_frame on AVERROR_EOF
// Detect when PTS wraps backwards (CFilePlayer seeked to start for looping). // (file_player.cpp:434), so ANSVideoPlayer must detect the wrap itself.
if (_hwFrameCount > 10 && _hwLastPts > 0 && imgPts < _hwLastPts - 1000) { // imgPts from getImage() is a monotonic call-counter, not a real PTS —
// Position wrapped back to start → video reached end // use getElapse() (ms of real video position, updated from packet.pts
// in file_player.cpp:608). When the file loops, elapse drops back to ~0.
const int64_t elapseMs = _hwPlayer->getElapse();
if (_hwFrameCount > 10 && _hwLastElapseMs > 0 &&
elapseMs + 500 < _hwLastElapseMs) {
_hwEOF = true; _hwEOF = true;
if (_resHeight <= 0 || _resWidth <= 0) { _resHeight = imgH; _resWidth = imgW; } if (_resHeight <= 0 || _resWidth <= 0) { _resHeight = imgH; _resWidth = imgW; }
_previousImage = cv::Mat(_resHeight, _resWidth, CV_8UC3, cv::Scalar(0, 0, 0)); _previousImage = cv::Mat(_resHeight, _resWidth, CV_8UC3, cv::Scalar(0, 0, 0));
@@ -540,7 +544,7 @@ namespace ANSCENTER {
return _previousImage; return _previousImage;
} }
_hwLastPts = imgPts; // track for EOF detection (PTS wrap) _hwLastElapseMs = elapseMs;
cv::Mat result = frame; // CFilePlayer returns owned Mat (already cloned internally) cv::Mat result = frame; // CFilePlayer returns owned Mat (already cloned internally)

View File

@@ -17,6 +17,7 @@
namespace ANSCENTER namespace ANSCENTER
{ {
// This class only allow to run 1 (to the end of video) then it will generate blank dark image
class ANSVIDEOPLAYER_API ANSVIDEOPLAYER class ANSVIDEOPLAYER_API ANSVIDEOPLAYER
{ {
protected: protected:
@@ -49,7 +50,7 @@ namespace ANSCENTER
bool _hwCudaAccel = false; // true = NVIDIA CUDA zero-copy available bool _hwCudaAccel = false; // true = NVIDIA CUDA zero-copy available
bool _hwEOF = false; // true when video reached end of file bool _hwEOF = false; // true when video reached end of file
int64_t _hwFrameCount = 0; // frame counter for EOF detection int64_t _hwFrameCount = 0; // frame counter for EOF detection
int64_t _hwLastPts = 0; // last video PTS for EOF wrap detection int64_t _hwLastElapseMs = 0; // last CFilePlayer elapse (ms); EOF detected when it wraps backwards
ANSVIDEOPLAYER(); ANSVIDEOPLAYER();
~ANSVIDEOPLAYER() noexcept; ~ANSVIDEOPLAYER() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string url); [[nodiscard]] bool Init(std::string licenseKey, std::string url);

View File

@@ -1491,11 +1491,11 @@ int VideoPlayerClientTest() {
while (true) { while (true) {
index++; index++;
std::cout << "Index=" << index << std::endl; std::cout << "Index=" << index << std::endl;
if ((index == 200) || (index == 800) || (index == 1200)) { StopVideoPlayer(&videoClient); } /*if ((index == 200) || (index == 800) || (index == 1200)) { StopVideoPlayer(&videoClient); }
if ((index == 400) || (index == 1000) || (index == 1500)) { StartVideoPlayer(&videoClient); } if ((index == 400) || (index == 1000) || (index == 1500)) { StartVideoPlayer(&videoClient); }
if ((index == 1800) || (index == 2200) || (index == 2500)) { StopVideoPlayer(&videoClient); } if ((index == 1800) || (index == 2200) || (index == 2500)) { StopVideoPlayer(&videoClient); }
if ((index == 2000) || (index == 2300) || (index == 2700)) { StartVideoPlayer(&videoClient); } if ((index == 2000) || (index == 2300) || (index == 2700)) { StartVideoPlayer(&videoClient); }
if (index > 20000) break; if (index > 20000) break;*/
auto start = std::chrono::system_clock::now(); auto start = std::chrono::system_clock::now();
cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image cv::Mat* image = nullptr; // ✅ Use a pointer to hold the allocated image
GetVideoPlayerCVImage(&videoClient, width, height, pts,&image); GetVideoPlayerCVImage(&videoClient, width, height, pts,&image);
@@ -1574,11 +1574,11 @@ int FilePlayerClientCVTest() {
while (true) { while (true) {
index++; index++;
std::cout << "Index=" << index << std::endl; std::cout << "Index=" << index << std::endl;
if ((index == 200) || (index == 800) || (index == 1200)) { StopFilePlayer(&filePlayerClient); } /*if ((index == 200) || (index == 800) || (index == 1200)) { StopFilePlayer(&filePlayerClient); }
if ((index == 400) || (index == 1000) || (index == 1500)) { StartFilePlayer(&filePlayerClient); } if ((index == 400) || (index == 1000) || (index == 1500)) { StartFilePlayer(&filePlayerClient); }
if ((index == 1800) || (index == 2200) || (index == 2500)) { StopFilePlayer(&filePlayerClient); } if ((index == 1800) || (index == 2200) || (index == 2500)) { StopFilePlayer(&filePlayerClient); }
if ((index == 2000) || (index == 2300) || (index == 2700)) { StartFilePlayer(&filePlayerClient); } if ((index == 2000) || (index == 2300) || (index == 2700)) { StartFilePlayer(&filePlayerClient); }
if (index > 20000) break; if (index > 20000) break;*/
auto start = std::chrono::system_clock::now(); auto start = std::chrono::system_clock::now();
cv::Mat* image = nullptr; cv::Mat* image = nullptr;
GetFilePlayerCVImage(&filePlayerClient, width, height, pts, &image); GetFilePlayerCVImage(&filePlayerClient, width, height, pts, &image);
@@ -1645,17 +1645,16 @@ int main()
// so this works without the unit test having to link FFmpeg itself. // so this works without the unit test having to link FFmpeg itself.
//ANSCV_PrintFFmpegLicense_S(); //ANSCV_PrintFFmpegLicense_S();
//FilePlayerClientDoubleDestroy(); //FilePlayerClientDoubleDestroy();
//FilePlayerClientCVTest(); FilePlayerClientCVTest();
// VideoPlayerClientDoubleDestroy();
//VideoPlayerClientTest(); //VideoPlayerClientTest();
//VideoPlayerClientDoubleDestroy();
// VideoPlayerClientTest();
//OpenCVFunctionTest(); //OpenCVFunctionTest();
//GenerateVideo(); //GenerateVideo();
//VideoTestClient(); //VideoTestClient();
// TestGetImage(); // TestGetImage();
//PureOpenCV(); //PureOpenCV();
// RSTPTestClient(); // RSTPTestClient();
RSTPTestCVClient(); //RSTPTestCVClient();
//TestCreateImageFromJpegStringFile(); //TestCreateImageFromJpegStringFile();
//TestCreateImageFromFile(); //TestCreateImageFromFile();
//for (int i = 0; i < 100; i++) { //for (int i = 0; i < 100; i++) {