WaterMark: add gif support

GitLab: #23

Change-Id: I8dc9708315097a46e1f3b5359a86d399da680b13
diff --git a/WaterMark/WatermarkVideoSubscriber.cpp b/WaterMark/WatermarkVideoSubscriber.cpp
index c53d0de..dbf79b5 100644
--- a/WaterMark/WatermarkVideoSubscriber.cpp
+++ b/WaterMark/WatermarkVideoSubscriber.cpp
@@ -71,12 +71,14 @@
     if (avformat_open_input(&ctx, logoPath_.c_str(), NULL, NULL) != 0) {
         avformat_free_context(ctx);
         Plog::log(Plog::LogPriority::INFO, TAG, "Couldn't open input stream.");
+        validLogo_ = false;
         return {};
     }
     pFormatCtx_.reset(ctx);
     // Retrieve stream information
     if (avformat_find_stream_info(pFormatCtx_.get(), NULL) < 0) {
         Plog::log(Plog::LogPriority::INFO, TAG, "Couldn't find stream information.");
+        validLogo_ = false;
         return {};
     }
 
@@ -92,6 +94,7 @@
 
     if (videoStream_ == -1) {
         Plog::log(Plog::LogPriority::INFO, TAG, "Didn't find a video stream.");
+        validLogo_ = false;
         return {};
     }
 
@@ -124,7 +127,6 @@
     logoFilter_.initialize(logoDescription_, {logoStream_});
 
     AVCodecContext* pCodecCtx;
-    AVPacket* packet;
 
     const AVCodec* pCodec = avcodec_find_decoder(
         pFormatCtx_->streams[videoStream_]->codecpar->codec_id);
@@ -144,7 +146,8 @@
         return;
     }
 
-    packet = av_packet_alloc();
+    AVPacket* packet = av_packet_alloc();
+
     if (av_read_frame(pFormatCtx_.get(), packet) < 0) {
         avcodec_close(pCodecCtx);
         avcodec_free_context(&pCodecCtx);
@@ -292,13 +295,18 @@
     if (std::abs(angle_) == 90)
         rotateSides = ":out_w=ih:out_h=iw";
 
+    auto gifDescription = "movie='" + logoPath_ + "':loop=0,setpts=N/(FR*TB)[logo]," + logoDescription_ + "[loop],";
+
     if (angle_ != 0)
-        pluginFilterDescription_ = "[input]rotate=" + rotation[angle_] + rotateSides
-                                   + "[rot],[rot][mark]overlay=" + std::to_string(points_[0].first)
+        pluginFilterDescription_ = gifDescription
+                                   + "[input]rotate=" + rotation[angle_] + rotateSides
+                                   + "[rot],[rot][loop]overlay=" + std::to_string(points_[0].first)
                                    + ":" + std::to_string(points_[0].second)
                                    + ",rotate=" + rotation[-angle_] + rotateSides;
     else
-        pluginFilterDescription_ = "[input][mark]overlay=" + std::to_string(points_[0].first) + ":"
+        pluginFilterDescription_ = gifDescription
+                                   + "[input][loop]overlay="
+                                   + std::to_string(points_[0].first) + ":"
                                    + std::to_string(points_[0].second);
 
     std::string baseInfosDescription = "[input]rotate=" + rotation[angle_] + rotateSides
@@ -329,6 +337,8 @@
 void
 WatermarkVideoSubscriber::setMarkPosition()
 {
+    if (!validLogo_)
+        return;
     // 1, 2, 3, and 4 are cartesian positions
     int margin = 10;
     int markWidth = showLogo_ ? mark_->width : 0;
@@ -370,7 +380,7 @@
 void
 WatermarkVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pluginFrame)
 {
-    if (!observable_ || !pluginFrame || (!validLogo_ && showLogo_))
+    if (!observable_ || !pluginFrame || (showLogo_ && !validLogo_))
         return;
 
     AVFrameSideData* side_data = av_frame_get_side_data(pluginFrame, AV_FRAME_DATA_DISPLAYMATRIX);
@@ -390,7 +400,13 @@
     rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
     if (!rgbFrame.get())
         return;
-    rgbFrame->pts = 1;
+
+    if (sourceTimeBase_.num != pluginFrame->time_base.num || sourceTimeBase_.den != pluginFrame->time_base.den)
+        firstRun = true;
+
+    rgbFrame->pts = pluginFrame->pts;
+    rgbFrame->time_base = pluginFrame->time_base;
+    sourceTimeBase_ = pluginFrame->time_base;
 
     if (firstRun) {
         pluginFilter_.clean();
@@ -401,7 +417,7 @@
 
         setFilterDescription();
 
-        rational<int> fr(rgbFrame->pts, 1);
+        rational<int> fr(sourceTimeBase_.den, sourceTimeBase_.num);
         pluginstream_ = MediaStream("input",
                                     rgbFrame->format,
                                     1 / fr,
@@ -410,17 +426,8 @@
                                     0,
                                     fr);
 
-        if (showLogo_) {
-            MediaStream markstream_ = MediaStream("mark",
-                                                  mark_->format,
-                                                  logoStream_.timeBase,
-                                                  mark_->width,
-                                                  mark_->height,
-                                                  0,
-                                                  logoStream_.frameRate);
-            pluginFilter_.initialize(pluginFilterDescription_, {markstream_, pluginstream_});
-            pluginFilter_.feedInput(mark_.get(), "mark");
-            pluginFilter_.feedEOF("mark");
+        if (showLogo_ && validLogo_) {
+            pluginFilter_.initialize(pluginFilterDescription_, {pluginstream_});
         }
 
         infosFilter_.initialize(infosDescription_, {pluginstream_});
@@ -430,7 +437,7 @@
     if (!infosFilter_.initialized_ && !pluginFilter_.initialized_)
         return;
 
-    if (showLogo_) {
+    if (showLogo_ && validLogo_) {
         if (pluginFilter_.feedInput(rgbFrame.get(), "input") == 0) {
             uniqueFramePtr filteredFrame = {pluginFilter_.readOutput(), frameFree};
             if (filteredFrame.get())