• How to get thumbnail images from Wowza Transcoder with an HTTP Provider

    This article describes two methods for requesting a bitmap image of a frame from Wowza Transcoder. For this to work, Wowza Transcoder must be running and actively transcoding the video portion of a stream.

    Note: Wowza Media Server™ 3 or later is required.

    HTTP Provider

    You can use a built-in HTTP provider that is configured on the admin port 8086 to retrieve a bitmap image of a running transcoder stream over HTTP. The format of the URL is:
    http://[wowza-ip-address]:8086/transcoderthumbnail?application=[application-name]&streamname=[stream-name]&format=[jpeg or png]&size=[widthxheight]
    Where:
    • [wowza-ip-address]: The IP address of the server running the Wowza media server software
    • application-name: The application name the stream is running on
    • stream-name: The stream name of the source stream being transcoded. Do not use the name of your resultant transcoded stream or Stream Name Group.
    • format: Format of the image: either jpeg or png
    • size: Size of the thumbnail you wish returned. If not specified, the full frame size will be returned.


    To use this HTTP Provider, it's easiest to edit [install-dir]/conf/VHost.xml and for com.wowza.wms.transcoder.httpprovider.HTTPTranscoderThumbnail set AuthenticationMethod to none. It will turn off the need for a user name and password when using this HTTP Provider.

    Next, configure the Wowza media server to transcode an incoming live stream. Instructions for how to set up and run Wowza Transcoder are in this tutorial, How to set up and run Wowza Transcoder for live streaming.

    For this example, assume we are transcoding the stream named myStream that is being sent to the application named live. To retrieve a thumbnail for this stream enter the following URL into a browser:

    http://[wowza-ip-address]:8086/transcoderthumbnail?application=live&streamname=myStream&format=jpeg&size=320x240
    Note: The URL is case-sensitive.
    Logging
    For each bitmap image capture, you'll see a log message in [install-dir]/logs/wowzamediaserver_access.log
    comment	server	INFO	200	-	HTTPTranscoderThumbnail#GrabResult.onGrabFrame[live/_definst_/myStream]: Image result: format:jpeg size:320x240 timecode:107633

    Server-side API

    Below is sample code for a module to grab frames from an encoder based on client-to-server calls named grabFrame([stream-name]):
    package com.wowza.wms.plugin.test.module;
    
    import java.awt.image.*;
    import javax.imageio.*;
    import java.io.*;
    
    import com.wowza.wms.amf.*;
    import com.wowza.wms.client.*;
    import com.wowza.wms.request.*;
    import com.wowza.wms.module.*;
    import com.wowza.wms.application.*;
    import com.wowza.wms.stream.*;
    import com.wowza.wms.transcoder.model.*;
    import com.wowza.wms.transcoder.util.*;
    
    public class ModuleTestTranscoderFrameGrab extends ModuleBase
    {
    	private IApplicationInstance appInstance = null;
    	
    	class GrabResult implements ITranscoderFrameGrabResult
    	{
    		public void onGrabFrame(TranscoderNativeVideoFrame videoFrame)
    		{			
    			BufferedImage image = TranscoderStreamUtils.nativeImageToBufferedImage(videoFrame);
    			if (image != null)
    			{
    			
    				getLogger().info("ModuleTestTranscoderFrameGrab#GrabResult.onGrabFrame: "+image.getWidth()+"x"+image.getHeight());
    				
    				String storageDir = appInstance.getStreamStoragePath();
    				
    				File pngFile = new File(storageDir+"/thumbnail.png");
    				File jpgFile = new File(storageDir+"/thumbnail.jpg");
    				
    				try
    				{
    					if (pngFile.exists())
    						pngFile.delete();
    					ImageIO.write(image, "png", pngFile);
    					getLogger().info("ModuleTestTranscoderFrameGrab#GrabResult.onGrabFrame: Save image: "+pngFile);
    				}
    				catch(Exception e)
    				{
    					getLogger().error("ModuleTestTranscoderFrameGrab.grabFrame: File write error: "+pngFile);
    				}
    				
    				try
    				{
    					if (jpgFile.exists())
    						jpgFile.delete();
    					ImageIO.write(image, "jpg", jpgFile);
    					getLogger().info("ModuleTestTranscoderFrameGrab#GrabResult.onGrabFrame: Save image: "+jpgFile);
    				}
    				catch(Exception e)
    				{
    					getLogger().error("ModuleTestTranscoderFrameGrab.grabFrame: File write error: "+jpgFile);
    				}
    			}
    		}
    	}
    	
    	public void onAppStart(IApplicationInstance appInstance)
    	{
    		getLogger().info("ModuleTestTranscoderFrameGrab.onAppStart["+appInstance.getContextStr()+"]");
    		this.appInstance = appInstance;
    	}
    	
    	public void grabFrame(IClient client, RequestFunction function, AMFDataList params)
    	{
    		getLogger().info("ModuleTestTranscoderFrameGrab.grabFrame");
    
    		while(true)
    		{
    			String streamName = params.getString(PARAM1);
    			if (streamName == null)
    			{
    				getLogger().warn("ModuleTestTranscoderFrameGrab.grabFrame: No streamName");
    				break;
    			}
    			
    			IApplicationInstance appInstance = client.getAppInstance();
    			if (appInstance == null)
    			{
    				getLogger().warn("ModuleTestTranscoderFrameGrab.grabFrame: No appInstance");
    				break;
    			}
    			
    			IMediaStream stream = appInstance.getStreams().getStream(streamName);
    			if (stream == null)
    			{
    				getLogger().warn("ModuleTestTranscoderFrameGrab.grabFrame: No stream");
    				break;
    			}
    			
    			LiveStreamTranscoder liveStreamTranscoder = (LiveStreamTranscoder)stream.getLiveStreamTranscoder("transcoder");
    			if (liveStreamTranscoder == null)
    			{
    				getLogger().warn("ModuleTestTranscoderFrameGrab.grabFrame: No liveStreamTranscoder");
    				break;
    			}
    			
    			TranscoderStream transcodingStream = liveStreamTranscoder.getTranscodingStream();
    			if (transcodingStream == null)
    			{
    				getLogger().warn("ModuleTestTranscoderFrameGrab.grabFrame: No transcodingStream");
    				break;
    			}
    			
    			TranscoderStreamSourceVideo sourceVideo = transcodingStream.getSource().getVideo();
    			if (sourceVideo == null)
    			{
    				getLogger().warn("ModuleTestTranscoderFrameGrab.grabFrame: No sourceVideo");
    				break;
    			}
    			
    			getLogger().info("ModuleTestTranscoderFrameGrab.grabFrame: Call grabFrame");
    			sourceVideo.grabFrame(new GrabResult(), 426, 240);
    			break;
    		}
    	}
    }
    To call this function from Flash, build a Flash application that connects to the Wowza media server using RTMP and then makes the following call:
    nc.call(grabFrame, null, "[stream-name]");
    Where [stream-name] is the name of the stream you want to grab a frame from.


    Originally Published: 10-08-2011.

    If you're having problems or want to discuss this article, post in our forum.