diff --git a/include/petrack.h b/include/petrack.h
index 0ddd8dbfbfdaf31535997d214a95e7fb450265f7..468976444e17705015ec85ab166565bf79efa4e8 100644
--- a/include/petrack.h
+++ b/include/petrack.h
@@ -484,6 +484,7 @@ private:
     QAction *mSetTo1p50;
     QAction *mSetTo1p75;
     QAction *mSetTo2p00;
+    QAction *mPlayerLooping;
     QAction *mDelPastAct;
     QAction *mDelFutureAct;
     QAction *mDelAllRoiAct;
diff --git a/include/player.h b/include/player.h
index 9b85afd5c93067dc113a1b3da58e2d416ad1e047..86ef443bae8f935f15d30121a7fe9600160f7a50 100644
--- a/include/player.h
+++ b/include/player.h
@@ -73,6 +73,7 @@ public slots:
     void setPlayerSpeedLimited(bool fixed);
     bool getPlayerSpeedLimited();
     void setPlayerSpeedFixed(bool fixed);
+    void setLooping(bool looping);
     void setFrameInNum(int in=-1.);
     void setFrameOutNum(int out=-1.);
     int getFrameInNum();
@@ -94,6 +95,7 @@ private:
     PlayerState mState = PlayerState::PAUSE;
     bool mPlayerSpeedLimited;
     bool mPlayerSpeedFixed = false;
+    bool mLooping = false;
     bool mSliderSet;
     bool mRec;
 
diff --git a/src/petrack.cpp b/src/petrack.cpp
index 28de3c9ffdb981d14a7894154223000e4ee40bff..1ace3dd288b73acce4f1cec3aeaa42440c3caf85 100644
--- a/src/petrack.cpp
+++ b/src/petrack.cpp
@@ -1762,6 +1762,10 @@ void Petrack::createActions()
     connect(mSetTo0p50, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(0.5);});
     mSetTo0p25 = new QAction(tr("&x0.25"));
     connect(mSetTo0p25, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(0.25);});
+
+    mPlayerLooping = new QAction(tr("&Loop"));
+    mPlayerLooping->setCheckable(true);
+    connect(mPlayerLooping, &QAction::triggered, mPlayerWidget, &Player::setLooping);
     // -------------------------------------------------------------------------------------------------------
 
     QSignalMapper* signalMapper = new QSignalMapper(this);
@@ -1836,6 +1840,7 @@ void Petrack::createMenus()
     mPlaybackSpeedMenu->addAction(mSetTo0p75);
     mPlaybackSpeedMenu->addAction(mSetTo0p50);
     mPlaybackSpeedMenu->addAction(mSetTo0p25);
+    mViewMenu->addAction(mPlayerLooping);
     mViewMenu->addSeparator();
     mViewMenu->addAction(mFitViewAct);
     mViewMenu->addAction(mFitROIAct);
diff --git a/src/player.cpp b/src/player.cpp
index e9921c0efd237325291e7db65a824a162c378e9f..1c6f0374845a37b1f595b196779cbcd6b341ebed 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -213,6 +213,11 @@ void Player::setPlayerSpeedFixed(bool fixed)
     mPlayerSpeedFixed = fixed;
 }
 
+void Player::setLooping(bool looping)
+{
+    mLooping = looping;
+}
+
 void Player::setSpeedRelativeToRealtime(double factor)
 {
     setFPS(mAnimation->getOriginalFPS()*factor);
@@ -376,7 +381,7 @@ void Player::playVideo(){
                     if(overtime >= supposedDiff){
                         mAnimation->skipFrame(static_cast<int>(overtime / supposedDiff));
                         overtime = overtime % supposedDiff;
-                        currentFrame = mAnimation->getCurrentFrameNum() + 1;
+                        currentFrame = std::min(mAnimation->getCurrentFrameNum() + 1, mAnimation->getSourceOutFrameNum());
                     }
                 }
 
@@ -405,8 +410,25 @@ void Player::playVideo(){
 
         if(!updateImage()){
             mState = PlayerState::PAUSE;
-            if(mState == PlayerState::FORWARD && mAnimation->getCurrentFrameNum() != mAnimation->getSourceOutFrameNum()){
-                debout << "Warning: video unexpected finished." << std::endl;
+            if( mAnimation->getCurrentFrameNum() != 0 && mAnimation->getCurrentFrameNum() != mAnimation->getSourceOutFrameNum()){
+                debout << "Warning: video unexpectedly finished." << std::endl;
+            }
+        }else{
+            if(mMainWindow->getControlWidget()->trackOnlineCalc->checkState() == Qt::Checked)
+            {
+                QMessageBox::warning(this, "Error: No tracking while looping", "Looping and tracking are incompatible. Please disable one first.");
+                mState = PlayerState::PAUSE;
+                break;
+            }
+            if(mLooping)
+            {
+                if(mState == PlayerState::FORWARD && mAnimation->getCurrentFrameNum() == mAnimation->getSourceOutFrameNum())
+                {
+                    currentFrame = 0;
+                }else if(mState == PlayerState::BACKWARD && mAnimation->getCurrentFrameNum() == 0)
+                {
+                    currentFrame = mAnimation->getSourceOutFrameNum();
+                }
             }
         }
     }