by Srijeeb Roy

Mobile video with JME and MMAPI, Part 2

how-to
Sep 13, 200723 mins

Send and receive video files in your Java mobile applications

In the first half of this article, you learned how to use JME and the Mobile Media API to build a Java application capable of taking advantage of the video cameras built in to many popular mobile devices today. Now author Srijeeb Roy shows you how to extend the application to upload video files to a remote server and download them back to the device. The result is a Java application that allows video-enabled devices to communicate with the wider world.

This article is the second half of an introduction to using JSR-135 and the Mobile Media API (MMAPI) to support video recording on a Java-enabled mobile device. In the first part of this article, you learned the basics of the MMAPI. You also learned about the MMAPI-specific system properties, and saw how to record a video on a mobile device. You also saw how to use the PlayerListener interface to trap the events generated by a Player at different stages in the application’s life cycle.

In this article, we will upload a video recorded on a mobile device to a server, and will fetch that video back from the server to play it on the mobile device. Before you start, you should have already read “Mobile video with JME and MMAPI, Part 1” and have handy the code you developed in the course of that article. You can also download this article’s sample code for use in the following examples.

Uploading the recorded video to a server

In this section, we’ll see how to upload our recorded video to a server. To do this, on the MIDlet side we will use the Generic Connection Framework (GCF) to establish a HTTP connection; on the server side, we will host a servlet through which we will upload our recorded video to the server. We’ll use the same servlet later in this article to fetch the stored video and play it on the mobile device.

Changes required on the MIDlet side

We will need an address for the server to which we will connect. Thus, on the Options screen, we will add a TextField where we will accept the server address as input. Also, to make the HTTP connection using GCF, we will use a Java class called HttpCommandExecuter (this file is supplied in the source code that accompanies this article). Together with the files already discussed, you also need to copy the classes that are used to transfer the data from the mobile device to the server (our Data Transfer Objects, or DTOs):

  • Copy PropertyForm.java and HttpCommandExecuter.java from the supplied source to the /apps/MobileVideoApp/src/com/srijeeb/jme directory. (Remember, throughout this tutorial, represents the directory where you installed the Sun Java Wireless Toolkit; see Resources for a link.) Your current PropertyForm.java should be replaced by the same file supplied in the source.

  • Copy work-offline.png from the supplied source to /apps/MobileVideoApp/res/images.

  • Copy DTOMediaStoreIn.java, DTOMediaStoreOut.java, DTOMediaRetrieveIn.java, and DTOMediaRetrieveOut.java from the supplied source to the /apps/MobileVideoApp/src/com/srijeeb/dto directory. You will not need DTOMediaRetrieveIn.java and DTOMediaRetrieveOut.java for uploading the recorded video to the server, but HttpCommandExecuter.java has references to these objects, so you’ll need them for compilation.

  • Copy VideoRecordingForm.java from the supplied source and replace your current VideoRecordingForm.java.

In the commandAction() method of the PropertyForm, you will find some extra steps that set the server address for the HttpCommandExecuter class and our MIDlet class, as shown in Listing 1.

Listing 1. Extra steps in commandAction() to set the server address

 HttpCommandExecuter.setServiceURL("http://" + 
   serverAddress.getString().trim() + "/MMAWeb/MMAServlet");
parentMidlet.setServerAddress(serverAddress.getString().trim());

When you run the revised application in the Wireless Toolkit, you will see an initial screen like the one displayed in Figure 1. You will find another option, named Work Offline. If the application were deployed on a real device without a wireless Internet connection, you would select this option; however, remember that you won’t be able to test the server functionality we’ll explore here on such device.

Wireless Toolkit emulator displaying revised PropertyForm
Figure 1. Wireless Toolkit emulator displaying revised PropertyForm

Now let’s have a look into the new version of VideoRecordingForm.java and explore the extra functionality added for uploading the recorded video to a server. Because we need to use GCF for this purpose, we have to write a separate thread again so that the main thread does not hang if there’s a problem uploading our video over the wireless connection. Listing 2 illustrates the UploadToServerThread class. This is an inner class of VideoRecordingForm.

Listing 2. Thread to upload the video to the server

 class UploadToServerThread extends Thread {

   public void run() {
      uploadVideo();
   }
   public void uploadVideo() {
      try {
         if ( output != null ) {
            byte[] bytes = output.toByteArray();
            DTOMediaStoreIn aDTOMediaStoreIn 
               = new DTOMediaStoreIn();
            aDTOMediaStoreIn.inpByteArray = bytes;
            aDTOMediaStoreIn.extension = 
               JMEUtility.findFileExtension(contentType);

            DTOMediaStoreOut aDTOMediaStoreOut =
               HttpCommandExecuter.getInstance().
                  executeHttp(aDTOMediaStoreIn);

            if ( aDTOMediaStoreOut != null ) {
               if ( aDTOMediaStoreOut.successFlag != null &&
                  aDTOMediaStoreOut.successFlag.equals("S") ) {
                  //Show success alert
               }
               else {
                  //...
               }
            }
            else {
               //...
            }
         }
         else {
            //...
         }
      }catch(Exception e) {
         e.printStackTrace();
         //...
      }

   }

}

In the uploadVideo() method, we first retrieve the byte array from the ByteArrayOutputStream (which holds our recorded video). Then we populate the DTOMediaStoreIn class. DTOMediaStoreIn is the data transfer object that carries our recorded media data to the server over the HTTP protocol. You might have noticed that we are populating the extension property of DTOMediaStoreIn. We are sending the extension to the server because we will store the recorded video with that extension. To determine the extension property, we have written a small function that looks into the content type and returns the possible extensions for the media. Have a look into the findFileExtension() method of the JMEUtility class. (Remember, this is a small class that I have written to perform some utility tasks — loading images, showing the error messages, and so on; it’s part of the source code supplied with this article.) Listing 3 is a code snippet of the findFileExtension() method.

Listing 3. findFileExtension() method, which accepts the content type and returns the probable file extension

 public static String findFileExtension(String contentType) {

   String ext = "";
   //...
   } else if (contentType.equals("video/3gpp")) {
    ext = "3gp";
   } else if (contentType.equals("audio/x-wav")) {
   //...
}

For example, if the contentType is returned by the mobile device as video/3gpp, we return the extension as 3gp.

After populating the inpByteArray and extension properties, we call the executeHttp() method on the HttpCommandExecuter class.

Inside the executeHttp() method of the HttpCommandExecuter class, we serialize the data of our DTO and write it to the DataOutputStream object of the HTTP connection. (The details of HttpCommandExecuter are beyond the scope of this article.) Also note that the supplied HttpCommandExecuter does not contain any code related to session tracking or proper error handling. For the time being, assume that when we call executeHttp() method, our DTO is transferred to the server side with our recorded video’s byte array, along with the file extension.

Server-side code: Writing the servlet

Deploy the Web application achieve (WAR) file MMAWeb.war, supplied in this article’s sample code, to your favorite Web container. This can be Apache Tomcat (see Resources) or some other application server, such as IBM WebSphere or BEA WebLogic. Whichever you choose, keep in mind that the supplied server-side code needs a Web container that supports version 2.4 or later of the Servlet specification. For the purposes of our examples, we’ll assume that we’re using Apache Tomcat 5.x. In my case, I have installed Tomcat 5.x under the C:/Tomcat5_0 directory.

Inside MMAWeb.war, you will find a servlet named MMAServlet.java. In the init() method of this servlet, we retrieve the fileLocation property, which is defined in the init parameter of the Servlet. This location is used to store our recorded video on the server, as shown in Listing 4.

Listing 4. MMAServlet’s init() method

 public void init() throws ServletException {
   fileLocationBase = this.getInitParameter("fileLocation");
}

Listing 5 contains a snippet from web.xml that includes the the init parameter of MMAServlet.

Listing 5. web.xml snippet that includes the the init parameter of MMAServlet

 <init-param>
   <description></description>
   <param-name>fileLocation</param-name>
   <param-value>C:/Tomcat5_0/webapps/MMAWeb/MMAFiles</param-value>

</init-param>

Note that the value under the param-value tag in Listing 5 starts with C:/Tomcat5_0/webapps/. You need to set this value as appropriate for your Web container.

Two other important methods in MMAServlet are doProcess() and handleCall(). doProcess() is called from doGet() and doPost(). doProcess() internally calls the handleCall() method, shown in Listing 6. It’s in this method that we first find out the operation type requested. There are two possible operation types (or method types) in our sample scenario: one for storing the media and one for retrieving the media.

Listing 6. handleCall() method snippet

 public int handleCall(...) {
   ...
   ...
   method = call.readByte();
   if ( method == 1 ) {//Store Media   
      System.out.println("Going to store Media...");
      DTOMediaStoreIn inDTO = DTOMediaStoreIn.deserialize(call);
      DTOMediaStoreOut outDTO = storeMedia(inDTO);
      outDTO.serialize(successfulResult);         
   }
   else if ( method == 2 ) {//Retrieve Media
      System.out.println("Going to retrieve Media...");
      DTOMediaRetrieveIn inDTO = DTOMediaRetrieveIn.deserialize(call);
      DTOMediaRetrieveOut outDTO = retrieveMedia(inDTO);
      outDTO.serialize(successfulResult);         
   }
   ...
   ...
}

In Listing 6, you can see that, when the value of method variable is 1, after deserializing the stream to DTOMediaStoreIn, we call the storeMedia() method to store the media. (The details of serializing and deserializing the DTO and the other details of handleCall() are beyond the scope of this discussion, as there’s nothing here unique to mobile video processing; any enterprise mobile application can use a similar design pattern to interact with a server over HTTP.)

Let us now look at the storeMedia() method of the MMAServlet, shown in Listing 7. This method is called when we choose the Upload to Server command on our mobile device. storeMedia() stores our recorded video to a server.

Listing 7. Snippet from storeMedia()

 private DTOMediaStoreOut storeMedia(DTOMediaStoreIn inDTO) {
      
   System.out.println("Inside Media Store...");
   DTOMediaStoreOut ret = new DTOMediaStoreOut();
   ret.successFlag = "X";
   if ( inDTO != null ) {
         
      String currentNo = getCurrentNo();
         
      FileOutputStream aFileOutputStream ;
      try {
         aFileOutputStream = 
            new FileOutputStream(fileLocationBase + "/" + 
                  currentNo + "." + inDTO.extension);
         aFileOutputStream.write(inDTO.inpByteArray);
         aFileOutputStream.close();
         ret.successFlag = "S";
         System.out.println("Successfully stored the content");
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }         
   }      
   return ret;
}


In Listing 7, we first retrieve the sequence number of the file, which is used to determine the name of the file. For example, our video files will be stored on the server with names like 1.gp and 2.gp, or 1.mpg and 2.mpg. After retrieving the sequence number, we create a FileOutputStream and write the byte array received over HTTP with the extension supplied in DTO.

Have a look into the supplied MMAServlet.java file to see the implementation of the getCurrentNo() method. Overall, this is pretty simple. We use a file named SEQUENCE.txt to track the sequence number. We read the sequence number from the file and return the it back to the storeMedia() method after adding 1 to its previous value. Before returning the number, we also update SEQUENCE.txt with the new sequence number, so that the next time getCurrentNo() is called, the incremented sequence number can be returned.

This completes the server-side code that stores the recorded media to our server. Now we can test our application in the Wireless Toolkit. Before doing so, let us first set up Tomcat to deploy our application. Assume that you have installed Tomcat in . Unzip the supplied file MMAWeb.zip and put the MMAWeb directory under /webapps. Your directory structure will look something like Figure 2.

If your Tomcat installation directory is something other than C:Tomcat5_0, then open the web.xml file and change the value of the fileLocation init parameter accordingly, as shown in Listing 8.

Listing 8. Changing the fileLocation parameter in web.xml

 <init-param>
   <description></description>
   <param-name>fileLocation</param-name>
   <param-value>CHANGE-ME/webapps/MMAWeb/MMAFiles</param-value>

</init-param>

Next, you need to start the Tomcat server. Open a command prompt. Change the current directory to /bin, then type startup.bat and press Enter.

Your command prompt should display something like the text in Listing 9. The output will vary depending on your Tomcat installation directory and your JDK version. If you are new to Tomcat, note that the JAVA_HOME variable needs to be set for Tomcat to run. If your JAVA_HOME variable is not set in the environment, then before running startup.bat, type set JAVA-HOME=<Your-JDK-Installation-Directory> and press Enter.

Listing 9. Starting up Tomcat

 C:Tomcat5_0bin>startup.bat
Using CATALINA_BASE:   C:Tomcat5_0
Using CATALINA_HOME:   C:Tomcat5_0
Using CATALINA_TMPDIR: C:Tomcat5_0temp
Using JAVA_HOME:       C:jdk1.5.0_07
C:Tomcat5_0bin>

This action will open a new command prompt, where you will actually be able to see the server logs. Watch for the lines in Listing 10.

Listing 10. Tomcat log entries indicating that our MMAPI application has been installed

 INFO: Installing web application at context path /MMAWeb from URL 
file:C:Tomcat5_0webappsMMAWeb


Again, the output will vary depending on your Tomcat installation directory.

Let’s go back to the Wireless Toolkit. Run the application again using the emulator. In the first screen, change the port of the server address if required, as shown in Figure 3. Tomcat by default uses port 8080 for HTTP communication.

Next, move to the next page by choosing the OK command, and record some video as described in the first half of this article. This time, when you stop the recording, you will be given the option to upload the recorded video to the server, as shown in Figure 4.

Select the Upload to Server option. A confirmation message will appear indicating that your emulator is going to use airtime, as shown in Figure 5. Don’t panic: it’s just emulating the actual behavior of a mobile device. Select the Yes option.

Once you select Yes, the mobile device will try to contact the Tomcat server to upload the video that you have recorded.

What’s happening on the server side? If you check your Tomcat log, it should look something like Figure 6. You can see that the video file has been uploaded successfully.

Tomcat log confirming that the recorded video has been uploaded successfully
Figure 6. Tomcat log confirming that the recorded video has been uploaded successfully

Back in the emulator, you should find a message telling you that the movie was successfully uploaded to a server, as shown in Figure 7.

If you look into your /webapps/MMAWeb/MMAFiles folder, you should be able to see that a file named 0.mpg been created.

Testing in a real environment

I have used a Nokia 3230 in a real-life environment to deploy this specific application. I used AirTel Mobile Office Service (in Kolkata, India) for my mobile phone’s Internet connection, which is built upon GSM/GPRS. Windows XP Media Edition was the operating system for my server deployment. You can try it using your own mobile service provider, so long as you have access to a server that you can expose to the Internet.

Retrieving the recorded video from the server

In this article, we will discuss two ways to retrieve the recorded video from the server and play it back on our mobile device:

  • First, we will retrieve the stored video as a byte array and then use the Manager.createPlayer(java.io.InputStream stream, java.lang.String type) method to create the Player object to play back our recorded video.

  • Next, we will retrieve the video content by supplying the URI directly. We will use the Manager.createPlayer(java.lang.String locator) method to create the Player object to play back our recorded video.

From the supplied source code, copy StoredVideoViewForm.java and put it under the appsMobileVideoAppsrccomsrijeebjme directory. Now let’s step through the important sections of this file.

To view the video, we will once again create a separate thread, for the reasons discussed in the first half of this article: to prevent the video processing from blocking the entire application. To fetch the video from the server and to view the video, we will write VideoOpenThread, an inner class of StoredVideoViewForm, as shown in Listing 11.

Listing 11. VideoOpenThread

 class VideoOpenThread extends Thread {
   public void run() {
      openStoredVideoFromServer();
   }
}

In the run() method of VideoOpenThread, we call the openStoredVideoFromServer() method, shown in Listing 12, which is implemented inside the StoredVideoViewForm class.

Listing 12. openStoredVideoFromServer()

 private void openStoredVideoFromServer() {

   try {

      DTOMediaRetrieveIn aDTOMediaRetrieveIn 
         = new DTOMediaRetrieveIn();

      aDTOMediaRetrieveIn.mediaId = videoId.getString();

      //Here we are executing the http request 
      //to fetch the recorded video from Server
      DTOMediaRetrieveOut aDTOMediaRetrieveOut =
         HttpCommandExecuter.getInstance().
            executeHttp(aDTOMediaRetrieveIn);

      if ( aDTOMediaRetrieveOut != null ) {
         if ( aDTOMediaRetrieveOut.successFlag != null &&
            aDTOMediaRetrieveOut.successFlag.equals("S") &&
            aDTOMediaRetrieveOut.outByteArray != null &&
            aDTOMediaRetrieveOut.outByteArray.length > 0 ) {


            releaseResources();
            //creating an inputstream from byte array
            InputStream is =
            new ByteArrayInputStream(aDTOMediaRetrieveOut.outByteArray);
                  //Creating the player object from inputstream
            player = Manager.createPlayer(is, 
                              aDTOMediaRetrieveOut.contentType);

            player.realize();
            videoControl = (VideoControl)player.getControl("VideoControl");
            if ( videoControl == null ) {
               JMEUtility.showErrorAlert
                  ("ERROR", "Video not Supported!!!", 
                     4000, this, parentMidlet);
               return;
            }
            VideoCanvas aVideoCanvas = new VideoCanvas();
            aVideoCanvas.initControls(videoControl, player);

            ...
            ...
            player.start();

         }

      }
   }
   ...
}

In Listing 12, we first populate our DTO with the particular video ID. This ID will be entered by the user on the mobile device screen. (See the supplied code for the user interface part of StoredVideoViewForm.java, which takes the video ID as input.)

Next, we execute the executeHttp() method on the HttpCommandExecuter class to fetch the recorded video by its video ID. Say our first recorded video was stored as 0.mpg. If we pass 0 in as the video ID, then 0.mpg will be retrieved from the server and played back on the mobile device.

We receive a byte array and the video content type from the server. From the byte array received, we create a ByteArrayInputStream object. Then we pass this object and the contentType to the Manager‘s createPlayer(java.io.InputStream stream, java.lang.String type) method. From here, the code is quite similar to the code in the first half of this article that plays back the recorded media just after recording it.

Now we need to enhance the commandAction() method of OptionForm.java so that we can open our StoredVideoViewForm, as shown in Listing 13.

Listing 13. Enhanced commandAction() method

 public void commandAction(Command c, Displayable d) {
    if (c == CMD_EXIT) {
      parentMidlet.destroyApp(true);
      parentMidlet.notifyDestroyed();
   }
   else if (c == CMD_OK) {
      if ( options.isSelected(0)) {
         // we will implement this part later
      }
      else if ( options.isSelected(1)) {
         StoredVideoViewForm aStoredVideoViewForm =
            new StoredVideoViewForm("",parentMidlet,this);
         parentMidlet.getDisplay().
            setCurrent(aStoredVideoViewForm);
      }
      else if ( options.isSelected(2)) {
         VideoRecordingForm aVideoRecordingForm =
            new VideoRecordingForm("",parentMidlet,this);
         parentMidlet.getDisplay().
            setCurrent(aVideoRecordingForm);
      }
   }
   else if (c == CMD_BACK){
      parentMidlet.getDisplay().setCurrent(parentForm);
   }
}

In Listing 13, we have added the code that opens the StoredVideoViewForm when we select the second radio button on our Option screen.

Now let’s look into the server-side code used to return the video when we pass the video ID. Let’s go back to the handleCall() method of MMAServlet, shown in Listing 14.

Listing 14. handleCall() method code snippet

 public int handleCall(...) {
    ...
    ...
    method = call.readByte();
    if ( method == 1 ) {//Store Media   
        //Existing code as is       
    }
    else if ( method == 2 ) {//Retrieve Media
        System.out.println("Going to retrieve Media...");
        DTOMediaRetrieveIn inDTO = DTOMediaRetrieveIn.deserialize(call);
        DTOMediaRetrieveOut outDTO = retrieveMedia(inDTO);
        outDTO.serialize(successfulResult);         
    }
    ...
    ...

}

In Listing 14, our method variable gets a value of 2, and after de-serializing the DTO (DTOMediaRetrieveIn), we call the retrieveMedia() method, shown in Listing 15.

Listing 15. MMAServlet’s retrieveMedia() method, which retrieves the recorded video

 private DTOMediaRetrieveOut retrieveMedia(DTOMediaRetrieveIn inDTO) {

   System.out.println("Inside media retrieve...");
   DTOMediaRetrieveOut ret = new DTOMediaRetrieveOut();
   ret.successFlag = "X";

   if ( inDTO != null ) {
      try {

         String ext = findFileExtension(inDTO.mediaId);
         BufferedInputStream bf = 
            new BufferedInputStream(
               new FileInputStream(
                  fileLocationBase + 
                  "/" + inDTO.mediaId + 
                  "." + ext));
         int available = bf.available();
         byte[] bytes = new byte[available];
         bf.read(bytes);
         bf.close();
         ret.outByteArray = bytes;
         ret.successFlag = "S";
         ret.contentType = findContentType(ext);
         System.out.println("Successfully Read the content");

      } catch (FileNotFoundException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }

   return ret;
}


In retrieveMedia(), we invoke a method named findFileExtension() to find the extension of the file. Once we have the extension, we read the file content from the directory where our recorded videos have been stored. Next, we assign the byte array (that is, the content of the video file) that we read to the return DTO. Then we find the content type from the extension, as shown in Listing 16. This is exactly the reverse of the process that we used earlier to determine the file extension from the content type on the MIDlet side of our application.

Listing 16. findContentType() method, which returns the content type of the video by examining the extension

 private String findContentType(String ext) {
   // guess content type
   String ct = "";
   if (ext.equals("mpg") || ext.equals("avi") ) {
      ct = "video/mpeg";
   } else if (ext.equals("3gp")) {
      ct = "video/3gpp";
   } 
   return ct;
}

We are now done with the server-side code. Let us try to test our newly updated application. Start Tomcat up again, and build and run the application from the Wireless Toolkit. Make sure that you provide the correct port in the server address field. On the next screen, select the second option (Open Video by Id) and then select OK, as shown in Figure 8.

You will see a screen like Figure 9. Enter a number. Remember, there needs to be a video file on the server whose file name matches the number you specify. In our case, the 0.mpg file from /webapps/MMAWeb/MMAFiles folder will be retrieved by MMAServlet and the byte array will be sent over HTTP.

Providing the video ID in the emulator and retrieving the video from the server
Figure 9. Providing the video ID in the emulator and retrieving the video from the server

When you select the OK option, a confirmation message will appear. Select the Yes option. After some time, you will be able to view 0.mpg in the emulator, as shown in Figure 10.

You can package and deploy the application and test the application on a real JSR 135-supported mobile device now.

Next, we will see how you supply the stored video’s URI and player it directly in the Player In this scenario, our servlet plays no role. If you have a Web server (a Web container is not needed), then the video can be retrieved from the server and played on the mobile device as follows:

  1. Copy VideoFromDirectServerForm.java from the supplied source to the appsMobileVideoAppsrccomsrijeebjme directory.
  2. Copy OptionForm.java from the supplied source to the appsMobileVideoAppsrccomsrijeebjme directory. This will replace your old OptionForm.java.

Let’s have a look at VideoFromDirectServerForm.java, shown in Listing 17. As mentioned earlier, we will perform all MMAPI-related operations in a separate thread, so we have written an inner class, VideoOpenThread, that extends Thread. From the run() method of VideoOpenThread, we call the openVideoFromServer() method.

Listing 17. VideoOpenThread

 class VideoOpenThread extends Thread {
   public void run() {
      openVideoFromServer();
   }
}

Now let’s have a look at the openVideoFromServer() method, shown in Listing 18.

Listing 18. openVideoFromServer(): Opening the stored video from the server directly using the video URI

 private void openVideoFromServer() {

   try {
      releaseResources();

      String fileURL 
         = "http://" + parentMidlet.getServerAddress() + 
         "/MMAWeb/MMAFiles/" 
         + videoName.getString().trim();
      player = Manager.createPlayer(fileURL);

      player.realize();

      videoControl = 
         (VideoControl)player.getControl("VideoControl");
      if ( videoControl == null ) {
         JMEUtility.showErrorAlert
            ("ERROR", "Video not Supported!!!", 
               4000, this, parentMidlet);
         return;
      }
      VideoCanvas aVideoCanvas = new VideoCanvas();
      aVideoCanvas.initControls(videoControl, player);

      ...
      ...
      player.start();
   } catch(Exception e) {
      JMEUtility.showErrorAlert("ERROR", e.getMessage(), 
         4000, this, parentMidlet);
   }

}


In Listing 18, we first call the releaseResources() method to stop and close the Player. Then we create the URL string, like so:

 "http://" + parentMidlet.getServerAddress() + "/MMAWeb/MMAFiles/" + videoName.getString().trim();

The video name will be supplied by the user on the mobile device’s screen, in the videoName field. So, if the user has entered 0.mpg in this field, then the URL will look like the following at runtime:

 http://localhost:8080/MMAWeb/MMAFiles/0.mpg

Now when we create the Player from the Manager, we are directly passed this URL, like so:

player = Manager.createPlayer(fileURL);

The player will load the file denoted by the user from the server and play it on the mobile device. The other methods of the Player class, like realize() and start(), have already been discussed.

You can test this code on the emulator; however, when deploying it to a real device, you need to take some extra care. For instance, the Nokia 3230 records video in video/3gpp format. So, when the video is stored on a server and fetched back with the file name of, say, 0.3gp, then the MIME type mapping to a server should make sure that our Player object understands the content type. In Tomcat 5.x, you can go to /conf and edit the web.xml file to make sure of this. Find the area where the other MIME definitions are defined and add the mime-mapping snippet in Listing 19.

Listing 19. MIME mapping snippet to support the 3gp file extension

 <mime-mapping>
   <extension>3gp</extension>
   <mime-type>video/3gpp</mime-type>

</mime-mapping>

Alternately, you can add this mapping to your application-specific web.xml file.

In conclusion

In this article, I have shown how to record a video on a JSR 135-supported mobile device and upload that recorded video to a server. I have also shown you how to play the video back on the mobile device after fetching it back from the sever. You have also learned how to use the PlayerListener interface to trap the events emitted by Player. And now you also know how to find out the specific system properties of a JSR 135-supported device.

There are other options available in JSR 135 that I have not discussed in this article. For example, you can take a snapshot from the video and store it as an image. This functionality can be easily obtained using the getSnapShot(String imageType) method on the VideoControl object. As an exercise, you can try to modify our example to take such a snapshot and then try to upload the image to the server. In the HTTPCommandExecuter and in our MMAServlet, we have hard-coded several parts to make this example simpler. With proper care, a very good MVC framework could be written for JME HTTP communication to replace this hard-coding.

With more and more mobile phones coming equipped with video-recording capabilities, users will expect to be able to create video content and share it with others over the Internet. I hope this article has gotten you started with designing and developing mobile video applications using Java ME and the MMAPI.

Srijeeb Roy holds a bachelor’s degree in computer science and engineering from Jadavpur University, Kolkata, India. He is currently working as a technical architect at Tata Consultancy Services Limited on a Java EE-based project. He has been working with Java SE and EE for more than eight years, and more has than nine years of experience in the IT industry. He has developed several in-house frameworks and reusable components in Java for his company and clients. He has also worked in several other areas, such as Forte, CORBA, and Java ME.