# Insert keyframes into a transcoded stream with the Wowza Streaming Engine Java API

Updated on 07/13/2021 12:23 pm PDT

This article describes how to use the Wowza Streaming Engine™ Java API to plug into the live stream transcoder pipeline to control when keyframes are inserted into a transcoded stream. Through this API, you can both force additional keyframes and stop keyframes from being inserted.

> **Note:** Wowza Streaming Engine media server software version 4.5.0.03 or later is required.

The following is module example code that shows this API in action:

Copy

```
import java.util.*;

import com.wowza.util.*;
import com.wowza.wms.application.*;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.stream.livetranscoder.*;
import com.wowza.wms.transcoder.model.*;

public class ModuleTranscoderVideoKeyFrameControl extends ModuleBase
{
	private static final Class<ModuleTranscoderVideoKeyFrameControl> CLASS = ModuleTranscoderVideoKeyFrameControl.class;
	private static final String CLASSNAME = "ModuleTranscoderVideoKeyFrameControl";

private IApplicationInstance appInstance = null;

class MyTranscoderCreateNotifier extends LiveStreamTranscoderNotifyBase
	{
		private IApplicationInstance appInstance = null;

public MyTranscoderCreateNotifier(IApplicationInstance appInstance)
		{
			this.appInstance = appInstance;
		}

public void onLiveStreamTranscoderCreate(ILiveStreamTranscoder liveStreamTranscoder, IMediaStream stream)
		{
			getLogger().info(CLASSNAME+"#MyTranscoderCreateNotifier.onLiveStreamTranscoderCreate["+appInstance.getContextStr()+"]: "+stream.getName());

// Add a live stream transcoder action listener so we can plug into the transcoding pipeline
			((LiveStreamTranscoder)liveStreamTranscoder).addActionListener(new MyTranscoderActionNotifier(appInstance, liveStreamTranscoder, stream));
		}
	}

class MyTranscoderActionNotifier extends LiveStreamTranscoderActionNotifyBase
	{
		private IApplicationInstance appInstance = null;
		private ILiveStreamTranscoder liveStreamTranscoder = null;
		private IMediaStream stream = null;

public MyTranscoderActionNotifier(IApplicationInstance appInstance, ILiveStreamTranscoder liveStreamTranscoder, IMediaStream stream)
		{
			this.appInstance = appInstance;
			this.liveStreamTranscoder = liveStreamTranscoder;
			this.stream = stream;
		}

// Called when the transcoding session is setup and ready to start
		public void onInitStop(LiveStreamTranscoder liveStreamTranscoder)
		{
			getLogger().info(CLASSNAME+"#MyTranscoderActionNotifier.onInitStop["+appInstance.getContextStr()+"/"+liveStreamTranscoder.getStreamName()+"]");

try
			{
				while(true)
				{
					TranscoderStream transcoderStream = liveStreamTranscoder.getTranscodingStream();
					if (transcoderStream == null)
						break;

TranscoderSession transcoderSession = liveStreamTranscoder.getTranscodingSession();
					TranscoderSessionVideo transcoderVideoSession = transcoderSession.getSessionVideo();

List<TranscoderSessionVideoEncode> videoEncodes = transcoderVideoSession.getEncodes();
					for(TranscoderSessionVideoEncode videoEncode : videoEncodes)
					{
						getLogger().info(CLASSNAME+"#MyTranscoderActionNotifier.onInitStop["+appInstance.getContextStr()+"/"+liveStreamTranscoder.getStreamName()+"] Add frame listener: rendition:"+videoEncode.getName());

// add a transcoder video frame listener
						videoEncode.addFrameListener(new MyTranscoderVideoEncoderNotifier(appInstance, liveStreamTranscoder, stream));
					}
					break;
				}
			}
			catch(Exception e)
			{
				getLogger().error(CLASSNAME+"#MyTranscoderActionNotifier.onInitStop["+appInstance.getContextStr()+"/"+liveStreamTranscoder.getStreamName()+"]  ", e);
			}
		}
	}

class MyTranscoderVideoEncoderNotifier extends TranscoderVideoEncoderNotifyBase2
	{
		private IApplicationInstance appInstance = null;
		private LiveStreamTranscoder liveStreamTranscoder = null;
		private IMediaStream stream = null;
		private long extraKeyFrames = 0;

public MyTranscoderVideoEncoderNotifier(IApplicationInstance appInstance, LiveStreamTranscoder liveStreamTranscoder, IMediaStream stream)
		{
			this.appInstance = appInstance;
			this.liveStreamTranscoder = liveStreamTranscoder;
			this.stream = stream;
		}

public void onBeforeEncodeFrame(TranscoderSessionVideoEncode sessionVideoEncode, TranscoderStreamDestinationVideo destinationVideo, TranscoderVideoEncodeFrameContext frameContext)
		{
			TranscoderDecodedFrame decodedFrame = frameContext.getFrameHolder().getEncoderNextFrame();
			if (decodedFrame != null)
			{
				int frameType = FLVUtils.FLV_PFRAME;

// every 10 frames we are going to force a keyframe
				if ((extraKeyFrames%10) == 0)
				{
					frameType = FLVUtils.FLV_KFRAME;
					getLogger().info(CLASSNAME+"#MyTranscoderVideoEncoderNotifier.onBeforeEncodeFrame["+appInstance.getContextStr()+"/"+liveStreamTranscoder.getStreamName()+"("+destinationVideo.getDestination().getName()+")"+"]  Insert key frame: frameType[source]:"+FLVUtils.frameTypeToString((int)decodedFrame.getFrameType())+" timecode:"+decodedFrame.getTimecode());
				}

frameContext.setFrameType(frameType);

extraKeyFrames++;
			}
		}

public void onAfterEncodeFrame(TranscoderSessionVideoEncode sessionVideoEncode, TranscoderStreamDestinationVideo destinationVideo, TranscoderVideoEncodeFrameContext frameContext)
		{
		}
	}

public void onAppStart(IApplicationInstance appInstance)
	{
		getLogger().info(CLASSNAME+".onAppStart["+appInstance.getContextStr()+"]");

this.appInstance = appInstance;

// Add a live stream transcoder listener (called each time a transcoder session is started)
		appInstance.addLiveStreamTranscoderListener(new MyTranscoderCreateNotifier(appInstance));
	}
}
```

Where:

- **onAppStart** \- Inserts a live stream transcoder listener that listens for new live stream transcoder sessions.

- **MyTranscoderCreateNotifier.onLiveStreamTranscoderCreate** \- Is called when a transcoder session is created and inserts an action listener to monitor for transcoder session events.

- **MyTranscoderActionNotifier.onInitStop** \- Is called when the session setup is completed and inserts a video frame listener for each encoding rendition that's being generated.

- **MyTranscoderVideoEncoderNotifier.onBeforeEncodeFrame** \- Is called before each frame is sent to the encoder, which provides a chance to control the keyframe insertion.

In the example above, a keyframe is forced every 10 seconds. The **decodedFrame.getFrameType()** returns the frame type of the source stream. In your transcoder template, if you've set **<KeyFrameInterval>**/ **<FollowSource>** to **true**, the **frameContext.getFrameType()** is always set to **FLVUtils.FLV\_UFRAME** (undefined) by default. This signals to the encoder that it should set the frame type of the encoded stream to the same frame type as the source stream.

If **<KeyFrameInterval>**/ **<FollowSource>** is set to **false**, then the **frameContext.getFrameType()** is set to either **FLVUtils.FLV\_PFRAME** (progressive) or **FLVUtils.FLV\_KFRAME** (key) based on the **KeyFrameInterval/Interval** (keyframe interval) setting.

In either case, you can force the frame to be either a **key** or a **progressive** frame by calling **frameContext.setFrameType(frameType)** with the appropriate frame type.

To debug the keyframe insertion, add the following custom property:

1. In Wowza Streaming Engine Manager, click the **Applications** tab, and then click the name of your live application in the contents panel.

2. On the live application page **Properties** tab, click **Custom** in the **Quick Links** bar.

> **Note:** Access to the **Properties** tab is limited to administrators with advanced permissions. For more information, see [Manage credentials](/content/docs/How-to-get-started-as-a-Wowza-Streaming-Engine-Manager-administrator#signinManager/index.html).

3. In the **Custom** area, click **Edit**.

4. Click **Add Custom Property**, specify the following settings in the **Add Custom Property** dialog box, and then click **Add**:

- **Path** \- Select **/Root/Application/Streams**.

- **Name** \- Enter **debugKeyFrameTimecodes**.

- **Type** \- Select **Boolean**.

- **Value** \- Enter **true**.
5. Click **Save**, and then restart the live application to apply the changes.

Was this article helpful?

[Helpful](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api# "Helpful"/index.html)

Thank you for your feedback!

300 characters remaining

Name

Email

reCAPTCHA

Recaptcha requires verification.

I'm not a robot

reCAPTCHA

[Submit](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api# "Submit comment"/index.html)

Thank you for providing feedback to help us improve our documentation!

##### Popular Video Topics [Copy to clipboard](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api\#popular-video-topics "Copy to clipboard"/index.html)

- [The Future of Video Tech](/content/blog/future-of-video-technology/index.html)
- [Streaming Starter Guide](/content/blog/complete-guide-to-live-streaming/index.html)
- [Live Event Streaming Guide](/content/blog/live-event-streaming-guide/index.html)
- [Interactive Streaming Guide](/content/blog/low-latency-streaming-technologies-the-key-to-interactive-video/index.html)
- [Streaming Protocols](/content/blog/streaming-protocols/index.html)
- [Transcoding](/content/blog/what-is-transcoding-and-why-its-critical-for-streaming/index.html)
- [Low Latency](/content/blog/what-is-low-latency/index.html)
- [Security](/content/blog/secure-video-streaming/index.html)

##### Video Resources [Copy to clipboard](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api\#video-resources "Copy to clipboard"/index.html)

- [APIs & SDKs](/content/docs/wowza-developer-apis-and-sdks/index.html)
- [Developer IDE](/content/docs/how-to-extend-wowza-streaming-engine-using-the-wowza-ide/index.html)
- [Test Players](/content/testplayers/index.html)
- [Wowza System Status](https://status.wowza.com/)

##### Partners [Copy to clipboard](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api\#partners "Copy to clipboard"/index.html)

- [Partners Overview](/content/partners/index.html)
- [Find a Partner](/content/partners/preferred-international-resellers/index.html)
- [Channel Program](/content/partners/channel-partner-program/index.html)
- [OEM Program](/content/partners/oem/index.html)
- [Partner Portal](/content/partners/resources/index.html)

##### Company [Copy to clipboard](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api\#company "Copy to clipboard"/index.html)

- [About Us](/content/company/index.html)
- [Blog](/content/blog/category/blog/index.html)
- [News](/content/news/index.html)
- [Events & Webinars](/content/company/events/index.html)
- [Careers](/content/careers/index.html)
- [Customers](/content/customers/index.html)
- [Contact Us](/content/contact/index.html)

##### Stay Connected [Copy to clipboard](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api\#stay-connected "Copy to clipboard"/index.html)

##### Stay Up to Date with the Blog [Copy to clipboard](/content/docs/how-to-insert-key-frames-into-a-transcoded-stream-using-server-side-api\#stay-up-to-date-with-the-blog "Copy to clipboard"/index.html)

Email

X - Form Filled Type

© 2007–2025 Wowza Media Systems™, LLC. All rights reserved.   [Security & Privacy Policy](/content/legal/privacy/index.html) \| [Legal](/content/legal/index.html) \| [System Status](https://status.wowza.com/)

reCAPTCHA
