KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > media > Transcoder


1 /******************************************************************************
2  * Transcoder.java
3  * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.media;
11
12 import java.io.InputStream JavaDoc;
13 import java.io.FileInputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.BufferedInputStream JavaDoc;
16 import java.io.FileNotFoundException JavaDoc;
17 import java.io.File JavaDoc;
18 import java.awt.geom.Rectangle2D JavaDoc;
19 import java.util.Properties JavaDoc;
20
21 // JGenerator APIs
22
import org.openlaszlo.iv.flash.api.*;
23 import org.openlaszlo.iv.flash.api.action.*;
24 import org.openlaszlo.iv.flash.api.sound.*;
25 import org.openlaszlo.iv.flash.api.image.*;
26 import org.openlaszlo.iv.flash.util.*;
27
28 import org.openlaszlo.utils.SWFUtils;
29 import org.openlaszlo.utils.FileUtils;
30 import org.openlaszlo.server.LPS;
31
32 import org.openlaszlo.sc.ScriptCompiler;
33
34 // Logger
35
import org.apache.log4j.*;
36
37 /**
38  * Simple Media Transcoder
39  *
40  * Someday this should get build out.
41  */

42 public class Transcoder {
43
44     /** Logger */
45     private static Logger mLogger = Logger.getLogger(Transcoder.class);
46
47     /**
48      * @return true if the transcoder can do the requested transcode
49      * @param in input mime type
50      * @param out output mime type
51      */

52     public static boolean canTranscode(String JavaDoc in, String JavaDoc out) {
53
54         if (!out.equalsIgnoreCase(MimeType.SWF)) {
55
56             if (out.equalsIgnoreCase(FontType.FFT) &&
57                 in.equalsIgnoreCase(FontType.TTF)) {
58                 return true;
59             }
60             return false;
61         }
62
63         if (in.equalsIgnoreCase(MimeType.JPEG) ||
64             in.equalsIgnoreCase(MimeType.PNG) ||
65             in.equalsIgnoreCase(MimeType.GIF) ||
66             in.equalsIgnoreCase(MimeType.MP3) ||
67             in.equalsIgnoreCase(MimeType.XMP3) ||
68             in.equalsIgnoreCase(MimeType.SWF)) {
69             return true;
70         }
71         return false;
72     }
73
74     /**
75      * @param input buffer of data to be transcoded, caller is responsible
76      * for closing this stream someday.
77      * @param from type of input data
78      * @param to type of output data
79      * @param doStream true if transcode should create streaming audio
80      * @throws TranscoderException if there is no transcoder for the request from/to
81      * types.
82      */

83     public static InputStream JavaDoc transcode(InputStream JavaDoc stream,
84             String JavaDoc from, String JavaDoc to, boolean doStream)
85         throws TranscoderException, IOException JavaDoc {
86
87         if (!to.equalsIgnoreCase(MimeType.SWF)) {
88             throw new TranscoderException("Unknown output mime-type: " + to);
89         }
90
91         mLogger.debug("Transcoding from " + from + " to " + to);
92
93         // We assume this mime type is correct if we get it
94
// NOTE: This will keep us from copying big swf video files
95
// an extra time for now...
96
if (from.equalsIgnoreCase(MimeType.SWF)) {
97             return stream;
98         }
99
100         // Try images
101
if (from.equalsIgnoreCase(MimeType.JPEG) ||
102             from.equalsIgnoreCase(MimeType.PNG) ||
103             from.equalsIgnoreCase(MimeType.GIF) ||
104             from.indexOf("image") != -1 ) {
105             return convertImageToSWF(stream);
106         } else if (from.equalsIgnoreCase(MimeType.MP3) ||
107                    from.equalsIgnoreCase(MimeType.XMP3) ||
108                    from.indexOf("audio") != -1) {
109             // Try audio
110
return convertAudioToSWF(stream, doStream);
111         }
112
113         BufferedInputStream JavaDoc bis = null;
114         try {
115             if (!stream.markSupported()) {
116                 bis = new BufferedInputStream JavaDoc(stream);
117                 stream = bis;
118             }
119             String JavaDoc mime = guessSupportedMimeTypeFromContent(stream);
120             if (mime != null) {
121                 InputStream JavaDoc out = null;
122                 if (mime.equals(MimeType.SWF)) {
123                     out = bis;
124                 } else {
125                     out = transcode(bis, mime, to, doStream);
126                 }
127                 // Keep us from closing the stream
128
if (bis == out) {
129                     bis = null;
130                 }
131                 return out;
132             } else {
133                 throw new TranscoderException("can't guess a supported mime-type from content");
134             }
135         } finally {
136             FileUtils.close(bis);
137         }
138     }
139
140     /**
141      * @return mime type based on stream
142      */

143     public static String JavaDoc guessSupportedMimeTypeFromContent(String JavaDoc fileName)
144         throws IOException JavaDoc {
145         InputStream JavaDoc is = null;
146         try {
147             is = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(fileName));
148             return guessSupportedMimeTypeFromContent(is);
149         } finally {
150             FileUtils.close(is);
151         }
152     }
153
154     /**
155      * @return mime type based on stream
156      * stream must be rewindable or we can't guess
157      */

158     public static String JavaDoc guessSupportedMimeTypeFromContent(InputStream JavaDoc stream)
159         throws IOException JavaDoc {
160         if (!stream.markSupported()) {
161             return null;
162         }
163     
164         try {
165             stream.mark(stream.available());
166             
167             mLogger.debug("trying swf");
168             if (SWFUtils.hasSWFHeader(stream)) {
169                 return MimeType.SWF;
170             }
171
172             stream.reset();
173             if (GIF.is(stream)) {
174                 return MimeType.GIF;
175             }
176
177             stream.reset();
178             if (JPEG.is(stream)) {
179                 return MimeType.JPEG;
180             }
181
182             stream.reset();
183             if (PNG.is(stream)) {
184                 return MimeType.PNG;
185             }
186
187             stream.reset();
188             if (MP3.is(stream)) {
189                 return MimeType.MP3;
190             }
191         } finally {
192             stream.reset();
193         }
194
195         return null;
196     }
197
198     /**
199      * @param input File to be transcoded
200      * @param from type of input data
201      * @param to type of output data
202      * @throws TranscoderException if there is no transcoder for
203      * the request from/to
204      */

205     public static InputStream JavaDoc transcode(File JavaDoc input, String JavaDoc from, String JavaDoc to)
206         throws TranscoderException, IOException JavaDoc {
207
208         if (to.equalsIgnoreCase(FontType.FFT)) {
209             if (from.equalsIgnoreCase(FontType.TTF)) {
210                 return TTF2FFT.convert(input);
211             } else {
212                 throw new TranscoderException("Unknown input font type: "
213                         + from);
214             }
215         } else {
216             InputStream JavaDoc fis = new FileInputStream JavaDoc(input);
217             InputStream JavaDoc out = null;
218             try {
219                 out = transcode(fis, from , to,
220                         /* non-streaming media */false);
221                 return out;
222             } finally {
223                 if (fis != null && fis != out) {
224                     fis.close();
225                 }
226             }
227         }
228     }
229
230     /**
231      * @param stream image input stream
232      */

233     private static final InputStream JavaDoc convertImageToSWF(InputStream JavaDoc stream)
234         throws IOException JavaDoc, TranscoderException {
235
236         try {
237             mLogger.debug("converting image to SWF");
238     
239             Bitmap bitmap = Bitmap.newBitmap(new FlashBuffer(stream));
240             if (bitmap == null) {
241                 String JavaDoc msg = "corrupt image or unknown image type";
242                 throw new TranscoderException(msg);
243             }
244             mLogger.debug("done bitmap file");
245             Instance inst = bitmap.newInstance();
246             Script script;
247             script = new Script(1);
248             script.setMain();
249             script.newFrame().addInstance(inst, 1);
250             FlashFile file = FlashFile.newFlashFile();
251             file.setVersion(5);
252             file.setFrameSize(inst.getBounds());
253             file.setMainScript(script);
254             mLogger.debug("starting generate");
255             FlashOutput out = file.generate();
256             mLogger.debug("ending generate");
257             return out.getInputStream();
258         } catch (IVException e) {
259             throw new TranscoderException("iv exception:" + e.getMessage());
260         }
261     }
262
263     /**
264      * @param stream audio input stream
265      * @param doStream if true, convert to streaming audio output
266      */

267     private static final InputStream JavaDoc convertAudioToSWF(InputStream JavaDoc stream, boolean doStream)
268         throws IOException JavaDoc, TranscoderException {
269
270         // Stream and add a stop play command.
271
try {
272             return convertAudioToSWF(stream, doStream, true, 0, 0);
273         } catch (IVException e) {
274             throw new TranscoderException("iv exception:" + e.getMessage());
275         }
276     }
277
278     /**
279      * @param stream audio input stream
280      */

281     private static final InputStream JavaDoc convertAudioToSWF(InputStream JavaDoc in, boolean stream, boolean stopAction, int delay, int startframe)
282         throws IOException JavaDoc, IVException {
283
284         Script script;
285         script = new Script(1);
286
287         FlashFile file = FlashFile.newFlashFile();
288
289         // 30 FPS gets us 16000/30/60 = 8 minutes 53 sec max
290
final int MAX_SWF_FRAMES = 16000;
291         int mFrameRate = 30;
292         try {
293             String JavaDoc f = LPS.getProperty("lps.swf.audio.framerate", "30");
294             mFrameRate = Integer.parseInt(f);
295         } catch (Exception JavaDoc e) {
296             mLogger.error("Can't read property file for lps.swf.audio.framerate");
297         }
298
299         file.setFrameRate(mFrameRate << 8);
300
301         Frame stopFrame = null;
302
303         FlashBuffer fib = new FlashBuffer(in);
304         
305         if( stream ) {
306             mLogger.debug("transcoding streaming mp3");
307             SoundStreamBuilder ssb = SoundStreamBuilder.newSoundStreamBuilder(fib, file.getFrameRate());
308             SoundStreamHead head = ssb.getSoundStreamHead();
309
310             // Add the SoundStreamHead to the current startframe in the script
311
script.getFrameAt( startframe ).addFlashObject( head );
312
313             int frameCount = script.getFrameCount();
314             int f = startframe;
315             SoundStreamBlock block;
316
317             while( ( block = ssb.getNextSoundStreamBlock() ) != null ) {
318                 if( f >= frameCount ) {
319                     script.newFrame().addFlashObject( block );
320                 } else {
321                     script.getFrameAt( f ).addFlashObject( block );
322                 }
323
324                 f++;
325                 if (f >= MAX_SWF_FRAMES) {
326                     String JavaDoc msg =
327                             "LPS hit max SWF frame count when converting this clip"
328                             + "; truncating it at " + MAX_SWF_FRAMES + " frames";
329                     mLogger.warn(msg);
330                     script.getFrameAt(0).addFlashObject(WarningProgram(msg));
331                     break;
332                 }
333             }
334
335             stopFrame = script.getFrameAt( f - 1 );
336         } else {
337             mLogger.debug("transcoding non-streaming mp3");
338             MP3Sound sound = MP3Sound.newMP3Sound(fib);
339             // Set the delay if provided
340
if( delay != 0 ) {
341                 sound.setDelaySeek( delay );
342             }
343
344             SoundInfo soundInfo = SoundInfo.newSoundInfo( 0 );
345             StartSound startSound = StartSound.newStartSound( sound, soundInfo );
346
347             Frame newFrame = script.newFrame();
348             newFrame.addFlashObject( startSound );
349
350             stopFrame = newFrame;
351         }
352
353         if( stopAction ) {
354             stopFrame.addStopAction();
355         }
356
357         file.setVersion(5);
358         file.setFrameSize(GeomHelper.newRectangle(0,0,0,0));
359         file.setMainScript(script);
360         FlashOutput out = file.generate();
361         return out.getInputStream();
362     }
363
364     /**
365      * Return a FlashObject that contains a program that
366      * will print an LFC warning to the debugger
367      */

368     private static FlashObject WarningProgram(String JavaDoc msg) {
369         String JavaDoc p = "_root.debug.write('" + msg + "');";
370         byte[] action = ScriptCompiler.compileToByteArray(p, new Properties JavaDoc());
371         return new DoAction(new Program(action, 0, action.length));
372     }
373 }
374
Popular Tags