Insert keyframes into transcoded streams
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
If
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:
In Wowza Streaming Engine Manager, click the Applications tab, and then click the name of your live application in the contents panel.
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.
In the Custom area, click Edit.
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.
- 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
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
- Streaming Starter Guide
- Live Event Streaming Guide
- Interactive Streaming Guide
- Streaming Protocols
- Transcoding
- Low Latency
- Security
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)
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)
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)
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)
X - Form Filled Type
© 2007–2025 Wowza Media Systems™, LLC. All rights reserved. Security & Privacy Policy | Legal | System Status
reCAPTCHA