Я бы не использовал RawDataSourceHandler лично.По сути, это просто запись захваченных данных в массив памяти, что объясняет, почему у вас не хватает памяти, особенно запись 24-битного RGB.
Вместо этого я бы порекомендовал создать временный файл, записав вDataSink, затем переименование файла на место позже.Вот моя предложенная последовательность:
File tempFile = File.createTempFile("something",".someFormat");
MediaLocator dest = new MediaLocator(tempFile.toURI().toURL());
DataSink sink = Manager.createDataSink(p.getDataOutput(),dest);
sink.open();
sink.start();
p.start();
// Later:
p.stop();
tempFile.renameTo("SomeNewName.someFormat");
Если вы не можете сделать это из-за недостаточного разрешения на запись в файлы из JMF (что отличается от разрешения, требуемого для записи в файлы с использованием потока), я бы по крайней меререкомендуем использовать меньший формат, чем несжатый RGB.(Могу ли я предложить H263 вместо этого?)
Кроме того, у вас есть некоторые странности кода относительно источника обработчика:
try {
handler.setSource(ods); // <-- You set the source once here
} catch (IncompatibleSourceException e) {
System.err.println("Cannot handle the output DataSource from the processor: " + ods);
//return false;
}
System.err.println("Start datasource handler ");
handler.addDataSinkListener(this);
try{
handler.setSource(ds); // <-- Then change it again quickly here to the raw output from the capture device!
handler.start();
}
catch(IncompatibleSourceException ioe){
ioe.printStackTrace();
}
Наконец, неочевидное примечание о закрытии процессоров / проигрывателей.Последовательность закрытия: stop () deallocate () close ()
Состояние происходит следующим образом:
State: Controller.Running
stop()
State: Controller.Prefetched
deallocate()
State: Controller.Realized
close()
State: Controller.Unrealized
Да, вам следует подождать, пока процессор / игрок достигнет каждого состоянияупоминается, прежде чем продолжить.Вы будете сожалеть, если проигнорируете этот совет, так как JMF теряет память, как вы не поверите, если не закроете все правильно, особенно в Windows.
Вот мой код, который позаботится об этом автоматически:
public class PlayerUtils {
static public void cleanupPlayer(Player player) {
if (player != null) {
if (player.getState() == Player.Started) {
player.stop();
waitForState(player, Player.Prefetched);
}
if (player.getState() == Player.Prefetched) {
player.deallocate();
waitForState(player, Player.Realized);
}
player.close();
}
}
static public void cleanupPlayer(MediaPlayer player) {
if (player != null) {
cleanupPlayer(player.getPlayer());
}
}
static private void waitForState(Player player, int state) {
// Fast abort
if (player.getState() == state) {
return;
}
long startTime = new Date().getTime();
long timeout = 5 * 1000;
final Object waitListener = new Object();
ControllerListener cl = new ControllerListener() {
@Override
public void controllerUpdate(ControllerEvent ce) {
synchronized (waitListener) {
waitListener.notifyAll();
}
}
};
try {
player.addControllerListener(cl);
// Make sure we wake up every 500ms to check for timeouts and in case we miss a signal
synchronized (waitListener) {
while (player.getState() != state && new Date().getTime() - startTime < timeout) {
try {
waitListener.wait(500);
}
catch (InterruptedException ex) {
Logger.getLogger(PlayerUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
if (new Date().getTime() - startTime > timeout) {
Logger.getLogger(PlayerUtils.class.getName()).log(Level.SEVERE, "Timed out waiting for state change from {0} to {1}", new Object[]{player.getState(), state});
}
}
finally {
// No matter what else happens, we want to remove this
player.removeControllerListener(cl);
}
}
}