# Custom module to create single frame snapshots of live and VOD stream

**URL:** <https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38>\
**Category:** Wowza Streaming Engine\
**Created:** [November 7, 2007, 7:44am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38 "2007-11-07T07:44:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/system/32/447_2.png) [@system](https://community.wowza.com/u/system)\
**Post date:** [November 7, 2007, 7:44am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/1 "2007-11-07T07:44:04Z")

</div>

Below is a sample Wowza Pro custom module to create a single key frame .flv file (snapshot) of either a live or video on demand stream. To use this code, download and install the Wowza Pro IDE and follow the instructions in the included User’s Guide.

```auto
package com.wowza.wms.plugin.test.module;

import java.io.*;

import com.wowza.util.*;
import com.wowza.wms.module.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.application.*;
import com.wowza.wms.client.IClient;
import com.wowza.wms.stream.*;
import com.wowza.wms.vhost.*;
import com.wowza.wms.request.*;

public class CreateSnapshot extends ModuleBase
{
	Object lock = new Object();
	
	public void createSnapshotLive(IClient client, RequestFunction function, AMFDataList params) 
	{
		String streamName = params.getString(PARAM1);
		
		String fileName = "";
		IApplicationInstance appInstance = client.getAppInstance();
		MediaStreamMap streams = appInstance.getStreams();
		IMediaStream stream = streams.getStream(streamName);
		if (stream != null)
		{
			AMFPacket packet = stream.getLastKeyFrame();
			if (packet != null)
			{
				fileName = streamName + "_" + packet.getAbsTimecode() + ".flv";
				File newFile = stream.getStreamFileForWrite(streamName, null, null);
				
				String filePath = newFile.getPath().substring(0, newFile.getPath().length()-4) + "_" + packet.getAbsTimecode() + ".flv";
								
				try
				{
					synchronized(lock)
					{
						BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(filePath), false));
						FLVUtils.writeHeader(out, 0, null);
						
						AMFPacket codecConfig = stream.getVideoCodecConfigPacket(packet.getAbsTimecode());
						if (codecConfig != null)
							FLVUtils.writeChunk(out, codecConfig.getDataBuffer(), codecConfig.getSize(), 0, (byte)codecConfig.getType());
						
						FLVUtils.writeChunk(out, packet.getDataBuffer(), packet.getSize(), 0, (byte)packet.getType());
						out.close();
					}
					
					getLogger().info("snapshot created: "+filePath);
				}
				catch (Exception e)
				{
					getLogger().error("createSnapshot: "+e.toString());
				}
			}
		}
		
		sendResult(client, params, fileName);
	}
	
	public void createSnapshotVOD(IClient client, RequestFunction function, AMFDataList params) 
	{
		String streamName = params.getString(PARAM1);
		int timecode = params.getInt(PARAM2);
		
		String fileName = "";
		IApplicationInstance appInstance = client.getAppInstance();
		
		String flvFilePath = appInstance.getStreamStoragePath() + "/" + streamName + ".flv";
		File flvFile = new File(flvFilePath);
		
		if (flvFile.exists())
		{
			AMFPacket lastVideoKeyFrame = null;
			try
			{
				BufferedInputStream is = new BufferedInputStream(new FileInputStream(flvFile));
				FLVUtils.readHeader(is);
				AMFPacket amfPacket;
				while ((amfPacket = FLVUtils.readChunk(is)) != null)
				{
					if (lastVideoKeyFrame != null && amfPacket.getTimecode() > timecode)
						break;
					if (amfPacket.getType() != IVHost.CONTENTTYPE_VIDEO)
						continue;
					if (FLVUtils.isVideoKeyFrame(amfPacket)) //if (FLVUtils.getFrameType(amfPacket.getFirstByte()) == FLVUtils.FLV_KFRAME)
						lastVideoKeyFrame = amfPacket;
				}
				is.close();
			}
			catch (Exception e)
			{
				getLogger().error("Error: createSnapshotVOD: reading flv: "+e.toString());
			}
			
			if (lastVideoKeyFrame != null)
			{
				try
				{
					fileName = streamName + "_" + timecode;
					String filePath = appInstance.getStreamStoragePath() + "/" + fileName + ".flv";
					BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(filePath), false));
					FLVUtils.writeHeader(out, 0, null);
					FLVUtils.writeChunk(out, lastVideoKeyFrame.getDataBuffer(), lastVideoKeyFrame.getSize(), 0, (byte)lastVideoKeyFrame.getType());
					out.close();
					
					getLogger().info("snapshot created: "+filePath);
				}
				catch (Exception e)
				{
					getLogger().error("Error: createSnapshotVOD: writing flv: "+e.toString());
				}
			}
		}
		
		sendResult(client, params, fileName);
	}
}

```

You will need to add this module definition to the Application.xml file of any applications you wish to have use this module:

```auto
<Module>
	<Name>snapshot</Name>
	<Description>Create Snapshot</Description>
	<Class>com.wowza.wms.plugin.test.module.CreateSnapshot</Class>
</Module>

```

Here is the code to call it from the client side:

```auto
// live
var resultObj:Object = new Object();
resultObj.onResult = function(fileName:String)
{
	trace("result: "+fileName);
}
nc.call("createSnapshotLive", resultObj, "test");

// video on demand
var resultObj:Object = new Object();
resultObj.onResult = function(fileName:String)
{
	trace("result: "+fileName);
}
nc.call("createSnapshotVOD", resultObj, "merry_melodies_falling_hare", 30000); // 30 seconds into the video

```

A compiled version of this module is included in a collection of utility modules that you can download here:

[http://community.wowza.com/t/-/237](http://community.wowza.com/t/-/237)

FFMPEG can be used to turn the .flv thumbnail into a PNG thumbnail. Here is an FFMPEG command line that works for me.

```auto
ffmpeg -i thumbnail.flv -vcodec png -vframes 1 -an -f rawvideo -s 320x240 thumbnail.png

```

_Note: To learn how to compile and link this code into a customer server module, download and install the [Wowza IDE](https://www.wowza.com/labs.html#wowzaide) and follow the instructions in the included User’s Guide._

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [May 7, 2008, 7:13am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/2 "2008-05-07T07:13:40Z")

</div>

At this time you cannot take snapshots of H.264 streams. The file it generates will not be recoginzed by any of the usual tools.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [January 23, 2009, 7:23pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/3 "2009-01-23T19:23:42Z")

</div>

It is not super simple. Flash supports basically 3 different video formats; Sorenson Spark (variant of H.263), On2 VP6 and H.264. Decoding these formats is not super simple. It requires a bunch of math transformations and pre-defined matrixes. You can look at source code from project like ffmpeg, x264 to see how it is done. It is pretty difficult to extract out just the subset needed to decode a key frame.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [March 6, 2009, 1:50pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/4 "2009-03-06T13:50:43Z")

</div>

I just tried it with H.264 and it worked for me. I think your ffmpeg command line is wrong. I used:

```auto
ffmpeg -i myStream_45135.flv -vcodec png -vframes 1 -an -f rawvideo -s 320x240 myStream_45135.png

```

Worked great!!!

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [March 7, 2009, 4:55am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/5 "2009-03-07T04:55:36Z")

</div>

I downloaded the latest version for Windows from here:

[http://ffmpeg.arrozcru.org/builds/](http://ffmpeg.arrozcru.org/builds/)

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [March 9, 2009, 3:43am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/6 "2009-03-09T03:43:11Z")

</div>

Excellent, Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [July 26, 2010, 6:53am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/7 "2010-07-26T06:53:56Z")

</div>

Or take a look at this post:

Web service API:

[http://community.wowza.com/t/-/52](http://community.wowza.com/t/-/52)

Charlie

---

<div class="post-metadata">

**Author:** ![Tac\_Tacelosky](https://avatars.discourse-cdn.com/v4/letter/t/b487fb/32.png) [@Tac\_Tacelosky](https://community.wowza.com/u/Tac_Tacelosky)\
**Post date:** [November 11, 2007, 5:10pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/8 "2007-11-11T17:10:14Z")

</div>

Thanks, Charlie. Would you consider modifying this to create a jpg file from one or more keyframes? I realize that another tool (ffmpeg?) may need to be installed, and I know there’s some code on another thread that addresses this, but I still don’t quite see how to do this.

We’re also have a hard time installing the second custom module using the Eclipse IDE. The first one (Hello World) works, but the second one didn’t even trying on two different machines and OS’s. We’re java novices, but experienced coders.

Thx,

Tac

---

<div class="post-metadata">

**Author:** ![robert\_lebreux](https://avatars.discourse-cdn.com/v4/letter/r/47e85d/32.png) [@robert\_lebreux](https://community.wowza.com/u/robert_lebreux)\
**Post date:** [April 7, 2008, 1:53pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/9 "2008-04-07T13:53:02Z")

</div>

I search a way to extract a snapshot not at the beginning or a fixed time but in the middle of a flv. So i made a little try :

```auto
//Find duration of the file
try{
BufferedInputStream is = new BufferedInputStream(new FileInputStream(f.getAbsoluteFile()));
   FLVUtils.readHeader(is);
   int a = FLVUtils.getFrameType(FLVUtils.FLV_CHUNKHEADER_ITIMECODE);
   is.close();
   System.out.println("duration : "+a);
}catch(Exception e){
   e.printStackTrace();
}

//extract the snapshot
String lCommand = "ffmpeg.exe -i \""+flvPath+"\" -vcodec mjpeg -vframes 1 -an -f rawvideo -y \""+jpgPath+"\"";
try{
   Runtime.getRuntime().exec(lCommand);
}catch(Exception e){
   System.err.println(e.toString());
}

```

The method to extract snapshot with ffmpeg works fine, I just need to put ‘ss’ argument to specify which image extract. But I don’t arrive to get the duration of a flv file.

With stream object, it’s possible to use stream.getMaxTimecode() but i don’t find any equivalent with File, FLVUtils, AMFPacket & co.

P.S. In FLVUtils, writeDuration(file, duration) allow to custom this value but there is no getter to easy get this value.

---

<div class="post-metadata">

**Author:** ![Tal\_Pink](https://avatars.discourse-cdn.com/v4/letter/t/f6c823/32.png) [@Tal\_Pink](https://community.wowza.com/u/Tal_Pink)\
**Post date:** [April 4, 2009, 5:47pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/10 "2009-04-04T17:47:22Z")

</div>

Can this method be used to convert flv to various other video formats with ffmpeg using a custom module? Can it be called as soon as an flv is published?

---

<div class="post-metadata">

**Author:** ![Kishore\_Kopalle](https://avatars.discourse-cdn.com/v4/letter/k/bbe5ce/32.png) [@Kishore\_Kopalle](https://community.wowza.com/u/Kishore_Kopalle)\
**Post date:** [November 6, 2009, 3:59pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/11 "2009-11-06T15:59:15Z")

</div>

Greetings to Everyone!

I am trying to use the snapshot code posted in this forum, for capturing a snapshot from a web camera. I have made the appropriate changes to create server side module as well as changes to Application.xml and the flash side code.

I am invoking snapshot live when a button is clicked. However there is no desired action on clicking the button. No file is created with the snapshot. It seems as though nothing happened.

It would be a great help if someone could comment on this towards resolution of the problem.

Thanks & Regards,

Kishore

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [November 11, 2007, 9:26am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/12 "2007-11-11T09:26:39Z")

</div>

What happens when you try the second module? Are you getting error messages? The second module is truely a second module. So make sure you add an additional reference for it in Application.xml. So you need both of these module definitions to make it work:

```auto
<Module>
	<Name>MyFirstModule</Name>
	<Description>MyCompany MyFirstModule</Description>
	<Class>com.mycompany.wms.module.MyFirstModule</Class>
</Module>
<Module>
	<Name>ModuleServerSide</Name>
	<Description>MyCompany ModuleServerSide</Description>
	<Class>com.mycompany.wms.module.ModuleServerSide</Class>
</Module>

```

BTW, I will think about the ffmpeg thing but it seems beyond the scope of this site.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [November 20, 2007, 7:44am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/13 "2007-11-20T07:44:13Z")

</div>

I don’t have a pure Java way to do this. In the past I have used ffmeg to generate thumbnails from a .flv file. It seems like the more recent versions of ffmpeg have a different command line interface then I am used to. So I am not sure exactly how to do it.

Does anyone else have experience with using ffmpeg to generate JPG or PNG from .flv files?

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [April 7, 2008, 1:55pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/14 "2008-04-07T13:55:14Z")

</div>

FLVUtils.getLastTC(File file)

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [March 4, 2009, 7:14am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/15 "2009-03-04T07:14:22Z")

</div>

If you are trying to do this with H.264 video it will not work. We do not have a similar system for H.264.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [March 5, 2009, 2:16pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/16 "2009-03-05T14:16:34Z")

</div>

I modified the Java code in the first post. See if that does the trick. I did not have time to test it.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [April 27, 2009, 1:29pm UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/17 "2009-04-27T13:29:29Z")

</div>

Your code does not included the modification for H.264. It is this section:

```auto
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(filePath), false));
FLVUtils.writeHeader(out, 0, null);
AMFPacket codecConfig = stream.getVideoCodecConfigPacket(packet.getAbsTimecode());
if (codecConfig != null)
	FLVUtils.writeChunk(out, codecConfig.getDataBuffer(), codecConfig.getSize(), 0, (byte)codecConfig.getType());
FLVUtils.writeChunk(out, packet.getDataBuffer(), packet.getSize(), 0, (byte)packet.getType());
out.close();

```

It is where it is dealing with the codecConfig packet that is needed for H.264.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [April 28, 2009, 5:30am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/18 "2009-04-28T05:30:45Z")

</div>

Now I am lost. What exactly are you trying to do? If you are just using the code in this first post of this thread just update your code to the most recent version of this code and it should support H.264. If you are doing something else please describe in detail.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [April 28, 2009, 6:17am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/19 "2009-04-28T06:17:26Z")

</div>

If the file is already saved you should be able to grab a key frame without re-creating your own mini .flv file by using ffmpeg on the longer video. Just be sure you grab the most recent ffmpeg version you can find. The version I use is here: [http://ffmpeg.arrozcru.org/builds](http://ffmpeg.arrozcru.org/builds). It will support H.264 in FLV. You should be able to use a command line similar to the one in the first post of this thread.

Charlie

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [August 6, 2009, 3:28am UTC](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38/20 "2009-08-06T03:28:21Z")

</div>

I don’t understand the question. FLVUtils does not offer this feature.

Charlie

[Next page](https://community.wowza.com/t/custom-module-to-create-single-frame-snapshots-of-live-and-vod-stream/38.md?page=2)
