Ticket #2259: 2259_imp_java.patch
File 2259_imp_java.patch, 13.7 KB (added by meddle, 15 years ago) |
---|
-
modules/org.sophie2.main.media.natlib/src/test/java/org/sophie2/main/media/natlib/demo/AudioDemo.java
### Eclipse Workspace Patch 1.0 #P sophie2
38 38 * streams. 39 39 * 40 40 * @author stefan 41 * 41 * @author milo, meddle 42 42 */ 43 @SuppressWarnings("serial")44 43 public class AudioDemo extends Component { 45 44 45 private static final long serialVersionUID = 444592419471524579L; 46 46 47 private BinData binData; 47 48 private int time = 0; 48 49 … … 59 60 try { 60 61 img = this.videoHandler.getFrame(this.time); 61 62 } catch (RuntimeException e) { 62 img = new ImmImage(new BufferedImage((int) this.info 63 .getDimensions().getWidth(),(int) this.info.getDimensions() 64 .getHeight(), ImmImage.PREFERRED_BI_TYPE)); 63 int width = (int) this.info.getDimensions().getWidth(); 64 int height = (int) this.info.getDimensions().getHeight(); 65 BufferedImage source = 66 new BufferedImage(width, height, ImmImage.PREFERRED_BI_TYPE); 67 68 img = new ImmImage(source); 65 69 } 66 70 img.draw((Graphics2D) g, 0, 0); 67 71 } … … 126 130 */ 127 131 protected AudioChunk getAudio(int millis) { 128 132 AudioChunk audio = this.getAudioHandler().getAudio(millis); 133 129 134 return audio; 130 135 } 131 136 132 137 /** 138 * The main routine of the demo. 139 * 133 140 * @param args 134 141 * Full path to media file. 135 142 * @throws IOException … … 140 147 */ 141 148 @SuppressWarnings("unchecked") 142 149 public static void main(final String[] args) throws IOException, 143 150 InterruptedException, InvocationTargetException { 144 151 System.setProperty("sophie2.development", "true"); 145 152 FakeModuleRegistry.start(BaseNatlibModule.class, MainMediaNatlibModule.class, BaseMediaModule.class); 146 153 SophieLog.setMinLevel("", LogLevel.DEBUG); 147 154 SophieLog.debug("starting"); 148 // String path = "/home/stefan/Desktop/41_30secMP3pro-64.mp3"; 149 // String path = "/home/stefan/Desktop/93613 (copy).mpg"; 155 156 // String path = "/home/stefan/Desktop/41_30secMP3pro-64.mp3"; 157 // String path = "/home/stefan/Desktop/93613 (copy).mpg"; 150 158 //String path = "/home/pavel/Desktop/6jfzqz42iz0i2u3jwwx2ax1ts.mov"; 151 159 //String path = "/home/milo/Desktop/07 - The Mirror.mp3"; 152 160 // String path = "/home/stefan/11k16bitpcm.wav"; … … 158 166 //String path = "/home/stefan/media samples/41_30secWMA8-64.wma"; 159 167 //String path = "/home/stefan/media samples/RhinoCommercial.mov"; 160 168 // String path = "/home/stefan/media samples/may16_99.mpg"; 161 // String path = "/home/stefan/Desktop/Video/";162 // path += "2007-10-31 - Carling Cup - LIVERPOOL FC 2-1 Cardiff - Gerrard.avi";163 // path += "Banda Bassotti - Carabina.avi";164 // path += "Mike's New Car - High.avi";165 // path += "RhinoCommercial.mov";166 // path += "Umbro Commercial.avi";169 // String path = "/home/stefan/Desktop/Video/"; 170 // path += "2007-10-31 - Carling Cup - LIVERPOOL FC 2-1 Cardiff - Gerrard.avi"; 171 // path += "Banda Bassotti - Carabina.avi"; 172 // path += "Mike's New Car - High.avi"; 173 // path += "RhinoCommercial.mov"; 174 // path += "Umbro Commercial.avi"; 167 175 //audio 168 176 169 177 //String path = "/home/stefan/Desktop/Audio/"; 170 178 //path += "Autotamponneuse.ogg"; 171 // path += "Bugs Bunny.wav";172 // String path = "/home/stefan/Desktop/tempFile15139tempFile44832tempFile26989tempFile26966CanadaGeese.wav";173 179 // path += "Bugs Bunny.wav"; 180 // String path = "/home/stefan/Desktop/tempFile15139tempFile44832tempFile26989tempFile26966CanadaGeese.wav"; 181 174 182 //String path = "/home/pavel/Desktop/res/carcass - swansong - 03 - blackstar.mp3"; 175 // String path = "/home/pavel/Desktop/res/two.divx6.avi";176 // String path = "/media/other/Music/Marduk/1999 - Panzer Division Marduk/01 - Marduk - Panzer Division Marduk.mp3";177 // String path = "/home/pavel/Desktop/res/alice in chains - junkhead-singlesreleaseparty.mpg";183 // String path = "/home/pavel/Desktop/res/two.divx6.avi"; 184 // String path = "/media/other/Music/Marduk/1999 - Panzer Division Marduk/01 - Marduk - Panzer Division Marduk.mp3"; 185 // String path = "/home/pavel/Desktop/res/alice in chains - junkhead-singlesreleaseparty.mpg"; 178 186 //String path = "/home/pavel/Desktop/res/02 - Hype! (bonus performances).avi"; 179 // String path = "/home/pavel/Desktop/res/8uksomunz336d4ai7414zfhkx.mov"; 180 // String path = "/home/pavel/Desktop/res/6jfzqz42iz0i2u3jwwx2ax1ts.mov"; 181 String path = "/home/pavel/Desktop/res/ulica_sezam_mana_mana_vbox7.avi"; 187 //String path = "/home/meddle/Movies/02 - Hype! (bonus performances).avi"; 188 //String path = "/home/meddle/nicotine/ulica_sezam_mana_mana_vbox7.avi"; 189 String path = "/home/meddle/two.divx6.avi"; 190 //String path = "/home/meddle/Umbro Commercial.avi"; 191 //String path = "/home/meddle/nicotine/zwan - number of the beast.mp3"; 182 192 183 193 final AudioDemo audioDemo = new AudioDemo(path); 184 194 final NativeAudioOutput output = new NativeAudioOutput(); 185 195 SwingUtilities.invokeAndWait(new Runnable() { 186 196 187 197 public void run() { 188 SophieLog.debug(" VideoDemo created");189 JFrame f = new JFrame(190 "AudioDemo - Java Wrapper of C++ application that uses ffmpeg");198 SophieLog.debug("MediaDemo created"); 199 JFrame frame = new JFrame( 200 "Media Demo - Java Wrapper of C++ application that uses ffmpeg"); 191 201 192 f .addWindowListener(new WindowAdapter() {202 frame.addWindowListener(new WindowAdapter() { 193 203 @Override 194 204 public void windowClosing(WindowEvent e) { 195 205 audioDemo.stop(); 196 206 System.exit(0); 197 207 } 198 208 }); 199 f.add(audioDemo); 200 f.pack(); 201 f.setVisible(true); 202 f.pack(); 209 210 frame.add(audioDemo); 211 frame.pack(); 212 frame.setVisible(true); 213 frame.pack(); 214 203 215 output.start(); 204 216 output.registerComposite(new MediaComposite() { 205 217 … … 209 221 210 222 AudioChunk last = AudioChunk.SILENCE; 211 223 212 public void getAudioChunks(List<AudioChunk> res, 213 TimePos time) { 224 public void getAudioChunks(List<AudioChunk> res, TimePos time) { 214 225 this.last = audioDemo.getAudio(localTime(time)); 215 226 res.add(this.last); 216 227 } 217 228 218 229 int localTime(TimePos time) { 219 double d = audioDemo.getAudioHandler().getInfo() 220 .getDuration(); 230 double d = audioDemo.getAudioHandler().getInfo().getDuration(); 221 231 int hundreds = (int) (d * 100) - 1; 222 232 return (int) (time.getMillis() / 10 % hundreds) * 10; 223 233 } … … 232 242 } 233 243 234 244 /** 235 * Getter for {@link MediaHandler} that is contained in the demo.245 * Getter for the video {@link MediaHandler} that is contained in the demo. 236 246 * 237 * @return current demo's {@link MediaHandler}. 247 * @return 248 * The current demo's video {@link MediaHandler}. 238 249 */ 239 250 MediaHandler getVideoHandler() { 240 251 return this.videoHandler; 241 252 } 242 253 243 254 /** 244 * Getter for {@link MediaHandler} that is contained in the demo.255 * Getter for the audio {@link MediaHandler} that is contained in the demo. 245 256 * 246 * @return current demo's {@link MediaHandler}. 257 * @return 258 * The current demo's audio {@link MediaHandler}. 247 259 */ 248 260 MediaHandler getAudioHandler() { 249 261 return this.audioHandler; 250 262 } 251 252 263 } 253 No newline at end of file -
modules/org.sophie2.base.media/src/main/java/org/sophie2/base/media/MediaInfo.java
7 7 /** 8 8 * Immutable class for media meta data. 9 9 * 10 * @author Mira10 * @author mira 11 11 */ 12 // TODO: Add kind if this is persistable, or remove this comment if not.13 12 @Immutable 14 13 public class MediaInfo { 15 14 -
modules/org.sophie2.main.media.natlib/src/main/java/org/sophie2/main/media/natlib/decoder/NativeMediaHandler.java
1 1 package org.sophie2.main.media.natlib.decoder; 2 2 3 import org.sophie2.base.commons.util.bindata.BinData; 3 import java.util.Collections; 4 import java.util.HashMap; 5 import java.util.LinkedHashMap; 6 import java.util.Map; 7 import java.util.Map.Entry; 8 import java.util.concurrent.BlockingQueue; 9 import java.util.concurrent.LinkedBlockingQueue; 10 4 11 import org.sophie2.base.commons.util.ImmImage; 12 import org.sophie2.base.commons.util.bindata.BinData; 5 13 import org.sophie2.base.commons.util.position.ImmSize; 6 14 import org.sophie2.base.media.AudioChunk; 7 15 import org.sophie2.base.media.MediaHandler; … … 15 23 * This class is responsible for controlling the lifetime of the native bridge. 16 24 * 17 25 * @author milo 18 * 26 * @author meddle 19 27 */ 20 28 public class NativeMediaHandler implements MediaHandler { 21 29 30 /** 31 * Thread that reads audio output from the natives and puts 32 * it into a buffer. That way Sophie has asynchronous audio. 33 * 34 * @author milo, meddle 35 */ 36 private class AudioThread extends Thread { 37 38 /** 39 * Capacity of the cache meaning that the stored 40 * chunks are for 0.01ms * CACHE_CAPACITY time ahead. 41 */ 42 private static final int CACHE_CAPACITY = 1000; 43 private static final int PREFETCH_COUNT = 400; 44 45 private final MediaNativeBridge bridge; 46 // Requests and responses queues: 47 private final BlockingQueue<Integer> requestsQueue; 48 private final BlockingQueue<AudioChunk> responsesQueue; 49 private final Map<Integer, AudioChunk> audioCache; 50 51 private final int audioDuration; 52 53 protected AudioThread(MediaNativeBridge audioBridge, int audioDuration) { 54 this.bridge = audioBridge; 55 this.requestsQueue = new LinkedBlockingQueue<Integer>(); 56 this.responsesQueue = new LinkedBlockingQueue<AudioChunk>(); 57 HashMap<Integer, AudioChunk> map = new LinkedHashMap<Integer, AudioChunk>(CACHE_CAPACITY) { 58 59 private static final long serialVersionUID = 5345763680957046630L; 60 61 @Override 62 protected boolean removeEldestEntry(Entry<Integer, AudioChunk> eldest) { 63 return size() > CACHE_CAPACITY; 64 } 65 }; 66 67 this.audioCache = Collections.synchronizedMap(map); 68 this.audioDuration = audioDuration; 69 setDaemon(true); 70 } 71 72 public synchronized AudioChunk getAudio(int millis) { 73 AudioChunk res = this.audioCache.get(millis); 74 if (res != null) { 75 return res; 76 } 77 this.requestsQueue.add(millis); 78 79 try { 80 return this.responsesQueue.take(); 81 } catch (InterruptedException e) { 82 throw new RuntimeException(e); 83 } 84 } 85 86 private AudioChunk getNativeAudio(int millis) { 87 assert millis >= 0; 88 89 AudioChunk res = this.bridge.getAudio(millis); 90 return res; 91 } 92 93 @Override 94 public void run() { 95 BlockingQueue<Integer> reqQueue = this.requestsQueue; 96 BlockingQueue<AudioChunk> resQueue = this.responsesQueue; 97 98 int lastRequest = -1; 99 while (true) { 100 101 // If there are some requests for AudioChunks... 102 if (!reqQueue.isEmpty()) { 103 lastRequest = reqQueue.poll(); 104 SophieLog.debug("Fetching request for position " + lastRequest); 105 106 // If the requested chunk is not in the cache retrieve it 107 // from the natives and put it in the cache. 108 if (!this.audioCache.containsKey(lastRequest)) { 109 this.audioCache.put(lastRequest, getNativeAudio(lastRequest)); 110 } 111 112 // Add the requested chunk into the queue with the responses. 113 resQueue.add(this.audioCache.get(lastRequest)); 114 } else { 115 int len = AudioChunk.MILLIS_LEN; 116 int limit = lastRequest + PREFETCH_COUNT * len; 117 118 // Taking in mind audio duration: 119 limit = (limit > this.audioDuration) ? this.audioDuration : limit; 120 121 int nextNeeded = -1; 122 123 // Check if there is need to prefetch something: 124 for (int t = lastRequest; t < limit; t += len) { 125 if (!this.audioCache.containsKey(t)) { 126 nextNeeded = t; 127 break; 128 } 129 } 130 131 //Prefetch: 132 if (nextNeeded != -1) { 133 SophieLog.debug("Prefetching: " + nextNeeded); 134 this.audioCache.put(nextNeeded, getNativeAudio(nextNeeded)); 135 } else { 136 // If there is no request yet just sleep for a while... 137 if (reqQueue.isEmpty()) { 138 try { 139 sleep(1000 / 200); 140 continue; 141 } catch (InterruptedException e) { 142 SophieLog.error("The Audio thread was interrupted", e); 143 throw new RuntimeException(e); 144 } 145 } 146 } 147 } 148 } 149 } 150 151 } 152 22 153 private BinData mediaData; 23 154 24 155 // lazy … … 27 158 28 159 // lazy 29 160 private MediaInfo info; 161 162 private final AudioThread audioThread; 163 164 30 165 31 166 /** 32 167 * Constructs by the file data. … … 36 171 */ 37 172 public NativeMediaHandler(BinData mediaData) { 38 173 this.mediaData = mediaData; 39 174 this.audioThread = new AudioThread(getAudioBridge(), getModLen()); 175 this.audioThread.start(); 40 176 } 41 177 42 178 private MediaNativeBridge getAudioBridge() { … … 88 224 } 89 225 90 226 public AudioChunk getAudio(long millis) { 91 assert millis >= 0 && millis <= Integer.MAX_VALUE;92 // TODO: temporary just loop 227 int correctMillis = (int) millis % getModLen(); 228 93 229 if (getInfo().hasAudio()) { 94 return getAudioBridge().getAudio((int) millis % getModLen());230 return this.audioThread.getAudio(correctMillis); 95 231 } 96 232 return AudioChunk.SILENCE; 97 233 } 98 234 99 235 private ImmImage lastFrame = null; 100 236 private long lastFrameMillis = Long.MAX_VALUE / 5; 101 102 237 238 103 239 public ImmImage getFrame(long millis) { 104 240 assert millis >= 0 && millis <= Integer.MAX_VALUE; 105 241 // TODO: temporary just loop