From 3f9b8c175408a8b7cbc4ca5dd1b81599db2d3352 Mon Sep 17 00:00:00 2001
From: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Tue, 17 Sep 2013 23:47:04 +0300
Subject: [PATCH] Fixes a failure to generate key frames in the H.264 encoder.

---
 .../neomedia/codec/video/h264/JNIEncoder.java | 50 +++++++++++++++++--
 1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/src/org/jitsi/impl/neomedia/codec/video/h264/JNIEncoder.java b/src/org/jitsi/impl/neomedia/codec/video/h264/JNIEncoder.java
index d3e65894..e979b362 100644
--- a/src/org/jitsi/impl/neomedia/codec/video/h264/JNIEncoder.java
+++ b/src/org/jitsi/impl/neomedia/codec/video/h264/JNIEncoder.java
@@ -121,7 +121,7 @@ public class JNIEncoder
      * The name of the integer <tt>ConfigurationService</tt> property which
      * specifies the maximum GOP (group of pictures) size i.e. the maximum
      * interval between keyframes. FFmpeg calls it <tt>gop_size</tt>, x264
-     * refers to it <tt>keyint</tt> or <tt>i_keyint_max</tt>.
+     * refers to it as <tt>keyint</tt> or <tt>i_keyint_max</tt>.
      */
     public static final String KEYINT_PNAME
         = "org.jitsi.impl.neomedia.codec.video.h264.keyint";
@@ -223,6 +223,19 @@ else if(HIGH_PROFILE.equalsIgnoreCase(profile))
 
     private KeyFrameControl.KeyFrameRequestee keyFrameRequestee;
 
+    /**
+     * The maximum GOP (group of pictures) size i.e. the maximum interval
+     * between keyframes (with which {@link #open()} has been invoked without an
+     * intervening {@link #close()}). FFmpeg calls it <tt>gop_size</tt>, x264
+     * refers to it as <tt>keyint</tt> or <tt>i_keyint_max</tt>.
+     */
+    private int keyint;
+
+    /**
+     * The number of frames processed since the last keyframe.
+     */
+    private int lastKeyFrame;
+
     /**
      * The time in milliseconds of the last request for a key frame from the
      * remote peer to this local peer.
@@ -424,7 +437,16 @@ private boolean isKeyFrame()
                 forceKeyFrame = false;
         }
         else
-            keyFrame = false;
+        {
+            /*
+             * In order to be sure that keyint will be respected, we will
+             * implement it ourselves (regardless of the fact that we have told
+             * FFmpeg and x264 about it). Otherwise, we may end up not
+             * generating keyframes at all (apart from the two generated after
+             * open).
+             */
+            keyFrame = (lastKeyFrame == keyint);
+        }
 
         return keyFrame;
     }
@@ -650,6 +672,16 @@ else if ("h264.profile".equals(k))
                 sizeInBytes / 4);
         FFmpeg.avframe_set_linesize(avFrame, width, width / 2, width / 2);
 
+        /*
+         * In order to be sure that keyint will be respected, we will implement
+         * it ourselves (regardless of the fact that we have told FFmpeg and
+         * x264 about it). Otherwise, we may end up not generating keyframes at
+         * all (apart from the two generated after open).
+         */
+        forceKeyFrame = true;
+        this.keyint = keyint;
+        lastKeyFrame = 0;
+
         /*
          * Implement the ability to have the remote peer request key frames from
          * this local peer.
@@ -714,7 +746,19 @@ public synchronized int process(Buffer inBuffer, Buffer outBuffer)
                 (byte[]) inBuffer.getData(), inBuffer.getOffset(),
                 rawFrameLen);
 
-        FFmpeg.avframe_set_key_frame(avFrame, isKeyFrame());
+        boolean keyFrame = isKeyFrame();
+
+        FFmpeg.avframe_set_key_frame(avFrame, keyFrame);
+        /*
+         * In order to be sure that keyint will be respected, we will implement
+         * it ourselves (regardless of the fact that we have told FFmpeg and
+         * x264 about it). Otherwise, we may end up not generating keyframes at
+         * all (apart from the two generated after open).
+         */
+        if (keyFrame)
+            lastKeyFrame = 0;
+        else
+            lastKeyFrame++;
 
         // Encode avFrame into the data of outBuffer.
         byte[] out
-- 
GitLab