Monday 5 November 2012

Using Flazr as a Streaming Media Server

I'm no expert on streaming video, but I've been experimenting with Flazr on Windows.  Flazr can stream .flv and .f4v streams.  Here is my adventures with FLV.

I've used Tomcat and JWPlayer to create a web client to consume the flash video stream.  FFMpeg also gets used at various points.

Streaming Video-on-Demand (VOD)

  • Download Flazr from flazr.com, unzip into a folder and run server-start.bat.
  • Download a binary distribution of Tomcat from tomcat.apache.org, unzip into a folder and run bin\startup.bat.
  • Download JWPlayer from longtailvideo.com and unzip it.
  • Within the Tomcat's webapps\ROOT directory create a folder called streaming, and copy jwplayer.js, player.swf and preview.jpg from the JWPlayer bundle into it.
  • Copy a sample .flv file into the home\apps\vod folder.  Call it video.flv or change the following HTML.
    Example flv files are a bit hard to find so you may need to convert a .mp4 with FFMpeg.  Try converting the video.mp4 file that came with JWPlayer:
    ffmpeg -i video.mp4 -f flv video.flv
  • Create the following HTML file as webapps\ROOT\streaming\vodtest.html within the Tomcat directory.  (See the JWPlayer setup wizard for other configuration options)
<html>
  <head>
    <script type='text/javascript' src='jwplayer.js'>
    </script>

  </head>
  <body>
    <div id='mediaspace'>This text will be replaced</div>
    <script type='text/javascript'>
      jwplayer('mediaspace').setup({
        'flashplayer': 'player.swf',
        'image': 'preview.jpg',
        'file': 'video.flv',
        'streamer': 'rtmp://localhost/vod',
        'controlbar': 'over',
        'duration': '34',
        'fullscreen': 'true',
        'stretching': 'fill',
        'width': '470',
        'height': '320'
      });
    </script>
  </body>
</html>

Streaming a Live Video Stream

Here we use a client to stream a video to the Flazr server which it then relays to connected clients.

  • Create the following HTML file as webapps\ROOT\streaming\livetest.html within the Tomcat directory.
<html>
  <head>
    <script type='text/javascript' src='jwplayer.js'>
    </script>

  </head>
  <body>
    <div id='mediaspace'>This text will be replaced</div>
    <script type='text/javascript'>
      jwplayer('mediaspace').setup({
        'flashplayer': 'player.swf',
        'image': 'preview.jpg',
        'file': 'mystream',
        'streamer': 'rtmp://localhost/myapp',
        'controlbar': 'none',
        'autostart': 'true',
        'width': '470',
        'height': '320'
      });
    </script>
  </body>
</html>
  • Publish the FLV file as a stream to server using the Flazr client:
    client.bat -live -host localhost -app myapp mystream video.flv You can send it multiple times:
    client.bat -loop 100 -live -host localhost -app myapp mystream video.flv
  • Now browse to http://localhost:8080/streaming/livetest.html. You should see the stream playing.

You can use FFMpeg to do the same thing, and we need to use it in the next section:
    ffmpeg -i video.flv -re -f flv rtmp://localhost/myapp/mystream

For more information see the FFMpeg Streaming Guide.

Streaming a Webcam

This re-uses the stream we set up above.
  • List the devices on your machine using FFMpeg to find the name of your webcam and microphone:
    ffmpeg -f dshow -list_devices true -i dummy
  • List the options on your webcam device using its name - this will tell you what sizes and frame rates it supports:
    ffmpeg -y -f dshow -list_options true -i video="<webcam-name>"
  • Stream your webcam using FFMpeg in the following way:
    ffmpeg -y -loglevel warning -f dshow
      -i video="<webcam-name>":audio="<mic-name>"
      -r <frame-rate> -s <width>x<height> -threads 2
      -f flv rtmp://localhost/myapp/mystream
  • Browse to http://localhost:8080/streaming/livetest.html and you should see your webcam output.

For me the capture command is:
  ffmpeg -y -loglevel warning -f dshow -i
    video="HP HD Webcam [Fixed]":audio="Integrated Microphone Array (ID"
    -r 15 -s 320x240 -threads 2
    -f flv rtmp://localhost/myapp/mystream

For more info see: FFMpeg Guide to Capturing Webcam Input.

Things to bear in mind

  • Licenses -Flazr is LGPL.  JWPlayer has a number of conditions attached to its commercial use.  FFMpeg is mainly LGPL but some options are GPL.
  • No security implications has been looked at.  Without further work (firewalls etc) anyone could send and receive streams with your Flazr server.

Thursday 27 September 2012

Outputting CDATA sections with JAXB

Here is a non-deprecated way to output a JAXB object model with some elements wrapped in CDATA sections.

Previously you could do this with an Apache OutputFormat as shown on the JAXB site.  This class which was non-standard, is now deprecated with a message about using the DOM Level 3 LSSerializer which is part of the Load and Save API.  I tried and tried, but I can not see a way to use that to output CDATA sections, so I have come up with a different way.

The secret is to marshal your JAXB object into a DOM and then use a null XSLT transformer.  Transformers allow you to name the elements you want wrapped in CDATA tags.

// Generating context uses resources - do it once and reuse across threads
JAXBContext jaxbContext = JAXBContext.newInstance(FWCoreContainer.class);

// Marshaller is not thread-safe
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

// If validating using a schema
SchemaFactory factory = SchemaFactory.newInstance(
    XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(xsd.getURL());
jaxbMarshaller.setSchema(schema);

// Create an empty DOM document
// DocumentBuilderFactory is not thread-safe
DocumentBuilderFactory docBuilderFactory =
    DocumentBuilderFactory.newInstance();
Document document =
    docBuilderFactory.newDocumentBuilder().newDocument();

// Marshall the feed object into the empty document.
jaxbMarshaller.marshal(jaxbObject, document);

// Transform the DOM to the output stream
// TransformerFactory is not thread-safe
TransformerFactory transformerFactory =
    TransformerFactory.newInstance();
Transformer nullTransformer = transformerFactory.newTransformer();
nullTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
nullTransformer.setOutputProperty(
    OutputKeys.CDATA_SECTION_ELEMENTS,
     "myElement myOtherElement");
nullTransformer.transform(new DOMSource(document),
     new StreamResult(writer/stream));

Tuesday 21 August 2012

How to use JavaMail to Send EMail with Embedded Images

A lot of us use email clients that are setup to not display external images by default.  We do this so that those senders of spam don't know that we have read the email.  The downside is that a lot of our incoming email looks rubbish.

I assume that most of the email that gets through the spam filter is not trying to track me, and that the use of external images is simply a lack of understanding of how to use embedded images.


Here is my example of using JavaMail to send email with embedded inline images:
// HTML we want to send.
// Note the "cid:" that precedes the image reference.
String html =
        "<html>" +
        "  <head>" +
        "    <style type='text/css'>" +
        "      body {background-color:blue}" +
        "      p {color:white}" +
        "    </style>" +
        "  </head>" +
        "  <body>" +
        "    <p><img src='cid:icon'></p>" +
        "    <p>Dear Bill</p>\n" +
        "    <p>This is a test mail.</p>" +
        "  </body>" +
        "</html>";

// Create Email content
// Use related (rather than mixed) mime subtype,
// otherwise Thunderbird will not display images inline.
Multipart multipart = new MimeMultipart("related");

// Create the HTML message part and add it to the email content.
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(html, "text/html");
multipart.addBodyPart(messageBodyPart);

// Read the image from a file and add it to the email content.
// Note the "<>" added around the content ID used in the HTML above.
// Setting Content-Type does not seem to be required.
// I guess it is determined from the file type
MimeBodyPart iconBodyPart = new MimeBodyPart();
DataSource iconDataSource = new FileDataSource(new File("./icon.jpg"));
iconBodyPart.setDataHandler(new DataHandler(iconDataSource));
iconBodyPart.setDisposition(Part.INLINE);
iconBodyPart.setContentID("<icon>");
iconBodyPart.addHeader("Content-Type", "image/jpeg");
multipart.addBodyPart(iconBodyPart);

// Create the connection to the SMTP server to send the email.
final String smtpAccountUsername = "myUsername";
final String smtpAccountPassword = "myPassword";
final String smtpServer = "smtp.mymailserver.com";
final String smtpServerPort = "587";

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", smtpServer);
props.put("mail.smtp.port", smtpServerPort);

Session session = Session.getInstance(props,
    new javax.mail.Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(
                    smtpAccountUsername, smtpAccountPassword);
        }
    });

// Create email, set the content and send.
MimeMessage mail = new MimeMessage(session);
mail.setRecipients(RecipientType.TO, InternetAddress.parse("bill@example.com"));
mail.setSubject("Mail Subject Line");
mail.setContent(multipart);

Transport.send(mail);

Sunday 19 August 2012

How to use XInclude in XSLT stylesheets

XInclude is not enabled by default when using the built-in XSLT processor in Java 1.6.  The underlying Apache Xalan uses Apache Xerces which does support it, but this is not directly accessible through the standard API.

Here is an example of how we would normally use XSLT:

// During app startup
TransformerFactory transformerFactory =
                TransformerFactory.newInstance();
Templates stylesheet = transformerFactory.newTemplates(
                new StreamSource("stylesheet.xsl"));

// Transformation
Source source = new StreamSource(new File("input.xml"));
Result result = new StreamResult(new File("output.xml"));
stylesheet.newTransformer().transform(source, result);
To use XInclude within an XSLT stylesheet we need to read it using a DocumentBuilder which has been created a DocumentBuilderFactory.  This has the methods that allows us to enable XInclude.
// During app startup
DocumentBuilderFactory documentBuilderFactory =
                DocumentBuilderFactory.newInstance(); documentBuilderFactory.setXIncludeAware(true);
documentBuilderFactory.setNamespaceAware(true);
// We don't want xml:base and xml:lang attributes in the output.
documentBuilderFactory.setFeature(
                "http://apache.org/xml/features/xinclude/fixup-base-uris", false);
documentBuilderFactory.setFeature(
                "http://apache.org/xml/features/xinclude/fixup-language", false);

DocumentBuilder docBuilder =
                documentBuilderFactory.newDocumentBuilder();
Document stylesheetDoc = docBuilder.parse("stylesheet.xsl");
Source stylesheetSource = new DOMSource(stylesheetDoc);

TransformerFactory transformerFactory =
                TransformerFactory.newInstance();
Templates stylesheet =
                transformerFactory.newTemplates(stylesheetSource);

// Transformation
Source source = new StreamSource(new File("input.xml"));
Result result = new StreamResult(new File("output.xml"));
stylesheet.newTransformer().transform(source, result);
It is bit more verbose than the orginal, but this is the only way I have found to do this.
The stylesheet this uses might look like this:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      exclude-result-prefixes="xi xsl xml">
  <xsl:output method="html" />

  <xsl:template match="/myRootElement">
        <xi:include href="mail.html" parse="xml" />
  </xsl:template>

</xsl:stylesheet>
And the included sub-stylesheet that uses the data elements within the myRootElements might be:
  <html xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <body>
     <p><xsl:value-of select="name"/></p>
     <p><xsl:value-of select="email"/></p>
     <ul>
       <xsl:for-each select="list/a">
         <li><xsl:value-of select="."/></li>
       </xsl:for-each>
     </ul>
   </body>
  </html>
Of course you may wish to use XInclude within the input XML, in which case you need to build a DOMSource for the transformation in the same way.