📄 mediastoreimpl.java
字号:
/* MediaStoreImpl.java
*
* This file contains the implementation of the MediaStore methods
* for storing/accessing video to/from a database using JDBC.
*
* Methods are made synchronized so that two competing requests don't
* access the resources at the same time. For example, accessing the
* database at the same time causes JDBC or ODBC exceptions.
*
* Copyright (C) 2002 by Frank McCown
* University of Arkansas at Little Rock
* July 2002
*/
import javax.media.*;
import javax.media.protocol.*;
import javax.media.rtp.*;
import javax.media.rtp.event.*;
import org.omg.PortableServer.*;
import java.io.*;
import java.util.*;
import java.sql.*;
import rowc.*;
import rowc.event.MediaArchiveListener;
import rowc.event.MediaArchiveEvent;
import rowc.MediaStorePackage.*;
public class MediaStoreImpl extends rowc.MediaStorePOA
{
private Set mediaArchiveListeners; // Stores listeners for NewVideo events
private Hashtable mediaListeners; // Stores remote listeners for media events
// NOTE: Events are not possible with CORBA unless using Event or Notification Services
// or callback methods. Callbacks are implemented in ROWC for sending events from
// remote objects.
public MediaStoreImpl()
{
mediaArchiveListeners = new HashSet(1); // Only Media Server should get events
mediaListeners = new Hashtable();
}
public void addMediaArchiveListener(MediaArchiveListener listener)
{
mediaArchiveListeners.add(listener); // Register the listener
}
// Iterate through list of NewVideoListeners and generate a new event for each
private void sendAddVideoEvents(String location)
{
Iterator i = mediaArchiveListeners.iterator();
while (i.hasNext())
{
MediaArchiveListener listener = (MediaArchiveListener) i.next();
listener.addVideo(new MediaArchiveEvent(location));
}
}
private void sendRemoveVideoEvents(String location)
{
Iterator i = mediaArchiveListeners.iterator();
while (i.hasNext())
{
MediaArchiveListener listener = (MediaArchiveListener) i.next();
listener.removeVideo(new MediaArchiveEvent(location));
}
}
/***************************************************************************
*
* Implementation of remote methods
*
***************************************************************************/
//
public synchronized void addMediaArchiveListener(String hostName, MediaArchiveCallback callback)
{
System.out.println("addMediaArchiveListener called for " + hostName);
mediaListeners.put(hostName, callback);
}
//
public synchronized void removeMediaArchiveListener(String hostName)
{
System.out.println("removeMediaArchiveListener called for "+hostName);
mediaListeners.remove(hostName);
}
private void notifyAddMedia(String location)
{
Enumeration enum = mediaListeners.elements();
System.out.println("Notifying all cam controllers of new media from "+ location);
while(enum.hasMoreElements())
{
MediaArchiveCallback callback = (MediaArchiveCallback)enum.nextElement();
callback.addVideo(location);
}
}
private void notifyDeleteMedia(String location)
{
Enumeration enum = mediaListeners.elements();
System.out.println("Notifying all cam controllers to delete media from "+ location);
while(enum.hasMoreElements())
{
MediaArchiveCallback callback = (MediaArchiveCallback)enum.nextElement();
callback.removeVideo(location);
}
}
public synchronized String[] getArchiveLocations() throws LocationsUnavailable
{
String[] loc = {""};
try
{
// Get unique list of locations
Statement statement = Server.connection.createStatement();
String query = "SELECT DISTINCT location FROM media";
ResultSet rs = statement.executeQuery(query);
// Since there is an unknown number of locations, store each location
// in a vector and later convert vector to an array
Vector v = new Vector(10);
while (rs.next())
v.addElement(rs.getString(1));
rs.close();
statement.close();
// Convert vector to array
loc = new String[v.size()];
v.copyInto(loc);
}
catch (SQLException e)
{
System.err.println("Error retrieving data from database.");
e.printStackTrace();
throw new LocationsUnavailable();
}
catch (Exception e)
{
System.err.println("General error retrieving data from database.");
e.printStackTrace();
throw new LocationsUnavailable();
}
return loc;
}
public void getAllVideoDetails(String location, ClipsHolder videos)
{
// Put into videos all video data from database
//VideoClip[] clips;
Vector clips = new Vector();
try
{
Statement statement = Server.connection.createStatement();
String query = "SELECT name, size, length, timestamp FROM media WHERE " +
"location = '" + location + "' ORDER BY timestamp";
ResultSet rs = statement.executeQuery(query);
while (rs.next())
{
VideoClip video = new VideoClip();
video.location = location;
video.name = rs.getString(1);
video.size = rs.getInt(2);
video.length = rs.getInt(3);
video.timeStamp = rs.getLong(4);
clips.addElement(video);
}
rs.close();
// Puts clips vector into output parameter
videos.value = new VideoClip[clips.size()];
clips.copyInto(videos.value);
}
catch (SQLException e)
{
System.err.println("Error retrieving data from database.");
e.printStackTrace();
return;
}
catch (Exception e)
{
System.err.println("General error retrieving data from database.");
e.printStackTrace();
return;
}
}
public synchronized void storeVideo(VideoClip videoRec)
{
// Store video data in database and store video as a file so it can be
// more quickly transported to listeners using getVideo
System.out.println("sendVideo received new video:");
System.out.println("name: " + videoRec.name);
System.out.println("location: " + videoRec.location);
System.out.println("size: " + videoRec.size);
System.out.println("length: " + videoRec.length);
System.out.println("timestamp: " + videoRec.timeStamp);
// Change name of video file according to timestamp.
// Example: COMPLAB_Mon_Oct_12_02_55_13_CST_2002.mov
// May need to wait until Server socket thread is able to completely download
String fileName = "video/" + videoRec.location + ".mov";
File videoFile = new File(fileName);
String newName = "video/" + videoRec.location + "_" + videoRec.name + ".mov";
boolean rename = false;
try
{
rename = videoFile.renameTo(new File(newName));
int tries = 0;
while (tries < 5 && !rename)
{
Thread.sleep(1000);
tries++;
rename = videoFile.renameTo(new File(newName));
}
}
catch (InterruptedException ex)
{
System.out.println("Error while trying to wait for file to download.");
ex.printStackTrace();
}
if (!rename)
{
System.out.println("Error trying to rename file from " + videoFile + " to " + newName);
return; // Don't save to database
}
if (!Server.connectedToDB)
{
System.out.println("Can't store media file... not connected to database.");
return;
}
try
{
String template = "insert INTO media (location, name, size, length, timestamp) " +
"VALUES (?, ?, ?, ?, ?)";
PreparedStatement statement = Server.connection.prepareStatement(template);
statement.setString(1, videoRec.location);
statement.setString(2, videoRec.name);
statement.setInt(3, videoRec.size);
statement.setInt(4, videoRec.length);
statement.setLong(5, videoRec.timeStamp);
statement.execute();
statement.close();
}
catch (SQLException e)
{
System.err.println("Error saving to database.");
e.printStackTrace();
}
// Update MediaServer's archive video list
sendAddVideoEvents(videoRec.location);
// Notify all cam processors of new media from this location
notifyAddMedia(videoRec.location);
System.out.println("sendVideo is done.");
}
public synchronized boolean deleteVideos(String location, String[] names)
{
System.out.println("deleteVideos with location: " +location);
boolean success = true;
try
{
// Get unique list of locations
String template = "DELETE FROM media WHERE location=? AND name=?";
PreparedStatement statement = Server.connection.prepareStatement(template);
for (int i=0; i < names.length && success; i++)
{
statement.setString(1, location);
statement.setString(2, names[i]);
int rowsAffected = statement.executeUpdate();
if (rowsAffected != 1)
success = false;
if (success)
{
// Delete file from video directory
File f = new File("video/" + location + "_" + names[i] + ".mov");
success = f.delete();
if (!success)
System.err.println("Error deleting file: " + f.getAbsolutePath());
}
else
System.err.println("Error trying to delete from database using command: "+
template + "\nDeleted " + rowsAffected + " rows.");
}
statement.close();
}
catch (Exception e)
{
e.printStackTrace();
}
// Notify the MediaServer
sendRemoveVideoEvents(location);
// Notify all cam processors of deleted media from this location
notifyDeleteMedia(location);
return success;
}
// Return the RTP URL for accessing the streaming video that is sent to the
// given destination IP address.
public synchronized String getVideoStream(String location, String name, String destIPaddr)
{
// Find a free port number on which to stream video
int port = findOpenPort();
String rtp = "rtp://" + destIPaddr + ":" + port + "/video";
// Get current directory. File is named like this: c:/rowc/video/location_name.mov
String currentDir = System.getProperty("user.dir");
String fileName = currentDir + "/video/" + location + "_" + name + ".mov";
System.out.println("About to transmit file: " + fileName);
// Start tansmitting this video to this IP address
TransmitterThread transThread = new TransmitterThread(destIPaddr, port, fileName);
transThread.start();
return rtp;
}
// Finds a port number on the server which is not being used. This would not
// be necessary if only one CamController was running at a time on the same
// computer as the server. But since 2 or more CamControllers could be running
// and accessing video at the same time, they would both need to access video
// on different ports.
/* NOTE: Actually it's not the server's port that we need to find but a free
* port on the CamController that we need to find. Implement this later.
*
*/
private int findOpenPort()
{
int port = 0;
boolean freePort = false;
while (!freePort)
{
try
{
// Test each port until we find one that is open for rtp transmission
//java.net.ServerSocket s = new java.net.ServerSocket(port);
// Get free port from the system automatically
java.net.ServerSocket s = new java.net.ServerSocket(0);
port = s.getLocalPort();
s.close();
// Port is only acceptable if it's even. Odd numbered ports don't work with JMF video.
if (port % 2 == 0)
freePort = true;
}
catch (Exception e)
{
System.out.println(e);
System.out.println("Port " + port + " is taken. Try next one...");
// Try next one
port += 2;
}
}
System.out.println("Free port: " + port);
return port;
}
/*********************** Inner class *********************************/
class TransmitterThread extends Thread
{
private String ipAddr;
private int port;
private String fileName;
TransmitterThread(String ipAddr, int port, String fileName)
{
this.ipAddr = ipAddr;
this.port = port;
this.fileName = fileName;
}
public void run()
{
System.out.println("About to start VideoTransmitter...");
DataSource ds;
try
{
ds = Manager.createDataSource(new MediaLocator("file:/" + fileName));
}
catch (Exception e)
{
System.out.println("Error creating data source from file: " + fileName);
e.printStackTrace();
return;
}
VideoTransmitter vt = new VideoTransmitter(ds, ipAddr, Integer.toString(port));
String result = vt.start();
if (result != null)
System.err.println("Failed to start VideoTransmitter: " + result);
else
System.out.println("Started VideoTransmitter.");
javax.media.Time duration = vt.processor.getDuration();
if (duration == javax.media.Duration.DURATION_UNKNOWN)
{
System.out.println("Unknown duration... run for 20 seconds.");
duration = new javax.media.Time(duration.ONE_SECOND * 20);
}
System.out.println("getDuration = " + duration.getNanoseconds());
// Loop until we've exceeded the media's duration or media time is no longer incerementing.
// This happens ofter when media time stops just short of duration time
// NOTE: There's probobaly a better way to do this when RTPing a video file, but I haven't
// been able to figure it out.
long oldNano = -1;
long nanos = vt.processor.getMediaNanoseconds();
int numStucks = 0;
while (nanos < duration.getNanoseconds() && oldNano != nanos && numStucks < 5)
{
System.out.println("getMediaTime = " + nanos);
oldNano = vt.processor.getMediaNanoseconds();
try
{
Thread.currentThread().sleep(1000);
}
catch (InterruptedException ie) {}
nanos = vt.processor.getMediaNanoseconds();
if (nanos == 0)
{
// Taking a bit longer to get going
nanos = 1;
// Keep track of how many times we try this. If we do it 5 times, there must
// be something really wrong, and we should terminate the loop.
numStucks++;
}
}
// Must disconnect in order to release system lock on file. Otherwise we won't be able to
// delete the file later if the user wants the video deleted.
ds.disconnect();
ds = null;
System.out.println("About to stop vt...");
vt.stop(); // Stop transmission thread CAUSING PROBLEMS
System.out.println("Stopped transThread");
}
} // end TransmitterThread class
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -