first of all changing volume is working but i got some problems while changing the volume so 1) after changing the volume like setting it to 0 (no volume) you still hearing parts of the song in the default value of the volume 2)after song changed the volume getting back to the default value of the volume
public static void setVolume(double value) {
System.out.println();
int CHANGE_VOLUME = 7;
midivol =(value);
try {
if (synthesizer.getDefaultSoundbank() == null) {
System.out.println(444);
ShortMessage volumeMessage = new ShortMessage();
for (int i = 0; i < 16; i++) {
volumeMessage.setMessage(ShortMessage.CONTROL_CHANGE, i, CHANGE_VOLUME,(int)(value * 127.0));
volumeMessage.setMessage(ShortMessage.CONTROL_CHANGE, i, 39, (int)(value * 127.0));
MidiSystem.getReceiver().send(volumeMessage, -1);
}
} else {
MidiChannel[] channels = synthesizer.getChannels();
for( int c = 0; c < channels.length; c++ ) {
if(channels[c] != null) channels[c].controlChange( 7, (int)( value*127.0) );
}
}
music.setSequence(sequence);
} catch (Exception e) {
e.printStackTrace();
}
}
playing midi:
private void playMidi(String location) {
double gain =Slider.musicvolume;
music = null;
//synthesizer = null;
sequence = null;
File midiFile = new File(location);
try {
sequence = MidiSystem.getSequence(midiFile);
music = MidiSystem.getSequencer(false);
music.open();
music.setSequence(sequence);
} catch (Exception e) {
System.err.println("Problem loading MIDI file.");
e.printStackTrace();
return;
}
if (music instanceof Synthesizer) {
synthesizer = (Synthesizer) music;
} else {
try {
synthesizer = MidiSystem.getSynthesizer();
synthesizer.open();
if (synthesizer.getDefaultSoundbank() == null) {
music.getTransmitter().setReceiver(MidiSystem.getReceiver());
} else {
music.getTransmitter().setReceiver(synthesizer.getReceiver());
}
} catch (Exception e) {
e.printStackTrace();
return;
}
}
MidiChannel[] channels = synthesizer.getChannels();
for (int i = 0; i < channels.length; i++) {
channels[i].controlChange(7, (int) (gain * 127.0));
}
try {
music.setSequence(sequence);
} catch (InvalidMidiDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
music.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
music.start();
}
volumeMessage.setMessage(ShortMessage.CONTROL_CHANGE, i, CHANGE_VOLUME,(int)(value * 127.0));
volumeMessage.setMessage(ShortMessage.CONTROL_CHANGE, i, 39, (int)(value * 127.0));
MidiSystem.getReceiver().send(volumeMessage, -1);
This code sends one message. The contents of that message are the values set by the second setMessage call, so the volume MSB is not changed at all.
(And this is the wrong way of computing the LSB.)
Controller 7 is indeed for volume, but there is no exact standard for how the values are to be interpreted. Apparently, your synthesizer does not mute itself when it receives a volume of zero.
Many MIDI files do their own changes to controller 7. If your synthesizer supports Master Volume, you should send that instead.
Related
I am trying in retrieving and writing signal from thirty-part machine (EEG headset) into file.csv through bluetooth. Now, i connect successfully with headset but while recording signal i met a fatal signal that i had no idea about.
Here is the code i possiply think might be the problem:
IEE_DataChannel_t[] Channel_list;
String[] Name_Channel = {"AF3","T7","Pz","T8","AF4"};
and the function to retrieve data
case 2:
if(bp_writer == null) return;
for(int i=0; i < Channel_list.length; i++)
{
SWIGTYPE_p_double ptheta = edkJava.new_double_p();
SWIGTYPE_p_double palpha = edkJava.new_double_p();
SWIGTYPE_p_double plow_beta = edkJava.new_double_p();
SWIGTYPE_p_double phigh_beta = edkJava.new_double_p();
SWIGTYPE_p_double pgamma = edkJava.new_double_p();
int result = -1;
result = edkJava.IEE_GetAverageBandPowers(userId, Channel_list[i], ptheta, palpha, plow_beta, phigh_beta, pgamma);
if(result == edkJava.EDK_OK){
Log.e("FFT", "GetAverageBandPowers");
try {
bp_writer.write(Name_Channel[i] + ",");
addData(edkJava.double_p_value(ptheta));
addData(edkJava.double_p_value(palpha));
addData(edkJava.double_p_value(plow_beta));
addData(edkJava.double_p_value(phigh_beta));
addData(edkJava.double_p_value(pgamma));
bp_writer.newLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
edkJava.delete_double_p(ptheta);
edkJava.delete_double_p(palpha);
edkJava.delete_double_p(plow_beta);
edkJava.delete_double_p(phigh_beta);
edkJava.delete_double_p(pgamma);
}
break;
}
}
};
there is the function for add data and set the file.csv:
private void setDataFile() {
try {
String eeg_header = "Channel , Theta ,Alpha ,Low beta ,High beta , Gamma ";
File root = Environment.getExternalStorageDirectory();
String file_path = root.getAbsolutePath()+ "/FFTSample/";
File folder=new File(file_path);
if(!folder.exists())
{
folder.mkdirs();
}
bp_writer = new BufferedWriter(new FileWriter(file_path+"bandpowerValue.csv"));
bp_writer.write(eeg_header);
bp_writer.newLine();
} catch (Exception e) {
Log.e("","Exception"+ e.getMessage());
}
}
public void addData(double data) {
if (bp_writer == null) {
return;
}
String input = "";
input += (String.valueOf(data) + ",");
try {
bp_writer.write(input);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It added user successfully, but when started recording, i met
A/libc: Invalid address 0xda9739b8 passed to free: value not allocated
A/libc: Invalid address 0xda973068 passed to free: value not allocated
A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 3969 (motiv.fftsample)
A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 3938 (motiv.fftsample)
I/libc: Another thread contacted debuggerd first; not contacting debuggerd.
So, how do i track errors, i am just a beginner on building app. Thanks
I would like to change the color (background) from one picture to the background which comes from another picture.
Here is my code but it doesn´t work 100 %.
Here is my current output:
http://www.bilder-upload.eu/upload/48a6b6-1471634776.jpg
This are the images:
Original:
https://github.com/vincentclee/csci1302-software_development/blob/master/p1_green_screen/submission/sagar.jpg?raw=true
New background:
https://github.com/vincentclee/csci1302-software_development/blob/master/p1_green_screen/submission/india.jpg?raw=true
public class StartGreenScreen2 {
public static void main(String[] args) throws IOException {
String inputFile = "/Users/testGreenscreen/sagar.jpg";
String backgroundFile = "/Users/testGreenscreen/india.jpg";
exceptions(inputFile, backgroundFile, ".jpg", "green");
}
/**
* The exceptions method accepts a String array argument. This method
* handles exceptions that might bring up.
*
* #param args
* Contains parameters for program execution.
* #throws IOException
* For catching file problems.
*/
public static void exceptions(String inputFile, String backgroundFile, String outputFileType, String color) throws IOException {
// Creates 7 boolean variables, all of which have to be true for the
// colorChanger & colorWriter to execute.
boolean[] bool = new boolean[6];
// args[0] try & catch statements
try {
new FileReader(inputFile);
bool[0] = true;
} catch (FileNotFoundException e) {
System.out.println("Input file for color swap not found.");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("No input file specified.");
} catch (Exception e) {
System.out.println("There is a problem with the inputfile.");
}
// args[1] try & catch statements
try {
new FileReader(backgroundFile);
bool[1] = true;
} catch (FileNotFoundException e) {
System.out.println("Input File not Found");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("No input file specified.");
} catch (Exception e) {
System.out.println("There is a problem with the inputfile.");
}
// args[2] try & catch statements
try {
if (outputFileType.contains("."))
bool[2] = true;
else
System.out.println("Outfile name invalid.");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Output file not specified.");
} catch (Exception e) {
System.out.println("There is a problem with the outputfile.");
}
// args[3] try & catch statements
try {
if (inputFile.endsWith(".png") && backgroundFile.endsWith(".png") && outputFileType.equalsIgnoreCase(".png")) {
bool[3] = true;
} else if (inputFile.endsWith(".jpg") && backgroundFile.endsWith(".jpg") && outputFileType.equalsIgnoreCase(".jpg")) {
bool[3] = true;
} else
System.out.println("The extension of all input files do not match!");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Extension not specified.");
} catch (Exception e) {
System.out.println("There is a problem with the extension.");
}
// args[4] try & catch statements
try {
if (color.equalsIgnoreCase("green") || color.equalsIgnoreCase("white")
|| color.equalsIgnoreCase("auto"))
bool[4] = true;
else
System.out.println("The spedified color is not valid.");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Color of replacement not specified.");
} catch (Exception e) {
System.out.println("There is a problem with the color of replacement.");
}
// Checks the dimensions of both the input and output image for same
// dimensions.
if (bool[0] && bool[1] && bool[2] && bool[3] && bool[4]) {
BufferedImage imageIn = ImageIO.read(new File(inputFile));
BufferedImage imageOut = ImageIO.read(new File(backgroundFile));
if (imageIn.getWidth() == imageOut.getWidth() && imageIn.getHeight() == imageOut.getHeight())
bool[5] = true;
else
System.out.println("The imgaes are not the same dimensions.");
}
// All arguments and dimensions have to be true for this to execute.
// Just to be safe, this has a general exception built in.
try {
if (bool[0] && bool[1] && bool[2] && bool[3] && bool[4] && bool[5])
// colorWriter(colorChanger(inputFile), backgroundFile, color);
colorWriter(colorChanger(inputFile,backgroundFile, color), outputFileType) ;
else
System.out.println("Program Terminated.");
} catch (Exception e) {
System.out.println("General Program Failure");
}
}
/**
* The color Changer method accepts a String array argument. This method
* changes the colors in the picture.
*
* #param args
* Contains parameters for program execution.
* #return imageIn BufferedImage stream for output
* #throws IOException
* For catching file problems.
*/
public static BufferedImage colorChanger(String normalFile, String backgroundFile, String color) throws IOException {
// Open file for replacement through Buffered Image stream.
BufferedImage imageIn = ImageIO.read(new File(normalFile));
// Open file background through Buffered Image stream.
BufferedImage imageOut = ImageIO.read(new File(backgroundFile));
// Array to store pixel information for calculation on extra credit
int[][] pixels = new int[imageIn.getHeight()][imageIn.getWidth()];
// Determines each pixel color and stores it into a 2D array to a
// corresponding location.
for (int col = 0; col < imageIn.getWidth(); col++) {
for (int row = 0; row < imageIn.getHeight(); row++) {
pixels[row][col] = imageIn.getRGB(col, row);
}
}
// Array to store different colors and their pixel counts.
int[][] colors = new int[10000][2];
colors[0][0] = pixels[0][0]; // Sets color value at position (0,0) to
// first array.
// Gets color information and stores it in a array, then it checks the
// array for color, and adds count.
// If the color does not exists, it goes down to a empty space, and
// creates a new entry, and sets one for count.
for (int col = 0; col < imageIn.getWidth(); col++) {
for (int row = 0; row < imageIn.getHeight(); row++) {
boolean bool = true;
int counter = 0;
for (int i = 0; i < colors.length; i++) {
if (pixels[row][col] == colors[i][0]) {
colors[i][1]++;
bool = false;
}
if (colors[i][0] == 0) {
counter = i;
break;
}
}
if (bool) {
colors[counter][0] = pixels[row][col];
colors[counter][1]++;
}
}
}
// Prints out array of color, and number of hits greater than 10.
System.out.println("Top Colors:");
for (int row = 0; row < colors.length; row++) {
if (colors[row][0] != 0 && colors[row][1] > 10)
System.out.println(colors[row][0] + " " + colors[row][1]);
}
// Determine's the color with the highest pixel count.
int high = colors[0][1];
int backgroundColor = colors[0][0];
for (int row = 0; row < colors.length; row++) {
if (colors[row][1] > high) {
backgroundColor = colors[row][0];
high = colors[row][1];
}
}
System.out.println("Color: " + backgroundColor + " Count: " + high);
// Override for args[4] color selector
if (color.equalsIgnoreCase("green")) {
backgroundColor = -16711935;
}
if (color.equalsIgnoreCase("white")) {
backgroundColor = -1;
}
// Color Changer
// If the pixel on the image to be changed is the same as the color to
// be changed, it changes the color.
// There is also a 50 point tolerance.
for (int col = 0; col < imageIn.getWidth(); col++) {
for (int row = 0; row < imageIn.getHeight(); row++) {
if (imageIn.getRGB(col, row) > (backgroundColor - 8388608)
&& imageIn.getRGB(col, row) < (backgroundColor + 8388608))
imageIn.setRGB(col, row, imageOut.getRGB(col, row));
}
}
return imageIn;
}
/**
* The colorWriter method accepts a BufferedImage stream, and a String array
* argument.
*
* #param imageIn
* A BufferedImage stream for inputImage.
* #param args
* Contains parameters for program execution.
* #throws IOException
* For catching file problems.
*/
public static void colorWriter(BufferedImage imageIn, String ouputPath) throws IOException {
// Generates a *.extension String.
String outputFile = ouputPath + ".jpg";
String testFile = "/Users/test.jpg";
// Writes output File
ImageIO.write(imageIn, "jpg", new File(testFile));
}
How can I solve this? Or does anybody has an idea to change the code?
You lost informations by JPEG compression, better use PNG.
Not all pixels in your picture have same green color in background.
Not replaced green pixels
Your tolerance check isn't good, better use square deviation.
I wrote an Android app that plays multi-track audio files and it works completely in the simulator. On the device, it plays for a few seconds and then starts skipping and popping every few seconds. If I continuously tap the screen in the dead space of the app, the skipping doesn't occur and then recurs about 5 seconds after screen tapping ceases. I presume that this has something to do with thread priority, but I log the thread priority in the play loop and it never changes.
I'm hoping that somebody can tell me either:
a hack where I can simulate a screen tap every second so that I can run a beta test without the app skipping
explain a way to debug activity/thread/etc priority when it seems that my thread priority isn't changing when it seems like it is.
Here is how the player code is executed:
private class DecodeOperation extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... values) {
AudioTrackPlayer.this.decodeLoop();
return null;
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Here is the relevant player code:
private void decodeLoop()
{
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
// extractor gets information about the stream
extractor = new MediaExtractor();
try {
extractor.setDataSource(this.mUrlString);
} catch (Exception e) {
mDelegateHandler.onRadioPlayerError(AudioTrackPlayer.this);
return;
}
MediaFormat format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);
// the actual decoder
codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
// get the sample rate to configure AudioTrack
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
Log.i(LOG_TAG,"mime "+mime);
Log.i(LOG_TAG,"sampleRate "+sampleRate);
// create our AudioTrack instance
audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRate,
AudioFormat.CHANNEL_OUT_5POINT1,
AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.getMinBufferSize (
sampleRate,
AudioFormat.CHANNEL_OUT_5POINT1,
AudioFormat.ENCODING_PCM_16BIT
),
AudioTrack.MODE_STREAM
);
// start playing, we will feed you later
audioTrack.play();
extractor.selectTrack(0);
// start decoding
final long kTimeOutUs = 10000;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
int noOutputCounter = 0;
int noOutputCounterLimit = 50;
while (!sawOutputEOS && noOutputCounter < noOutputCounterLimit && !doStop) {
//Log.i(LOG_TAG, "loop ");
noOutputCounter++;
if (!sawInputEOS) {
inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
bufIndexCheck++;
// Log.d(LOG_TAG, " bufIndexCheck " + bufIndexCheck);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize =
extractor.readSampleData(dstBuf, 0 /* offset */);
//Log.d(LOG_TAG, "SampleLength = " + String.valueOf(sampleSize));
long presentationTimeUs = 0;
if (sampleSize < 0) {
Log.d(LOG_TAG, "saw input EOS.");
sawInputEOS = true;
sampleSize = 0;
} else {
presentationTimeUs = extractor.getSampleTime();
}
// can throw illegal state exception (???)
codec.queueInputBuffer(
inputBufIndex,
0 /* offset */,
sampleSize,
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
extractor.advance();
}
}
else
{
Log.e(LOG_TAG, "inputBufIndex " +inputBufIndex);
}
}
int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
if (res >= 0) {
//Log.d(LOG_TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
if (info.size > 0) {
noOutputCounter = 0;
}
int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
final byte[] chunk = new byte[info.size];
buf.get(chunk);
buf.clear();
audioTrack.write(chunk,0,chunk.length);
if(this.mState != State.Playing)
{
mDelegateHandler.onRadioPlayerPlaybackStarted(AudioTrackPlayer.this);
}
this.mState = State.Playing;
}
codec.releaseOutputBuffer(outputBufIndex, false /* render */);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(LOG_TAG, "saw output EOS.");
sawOutputEOS = true;
}
} else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
Log.d(LOG_TAG, "output buffers have changed.");
} else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat oformat = codec.getOutputFormat();
Log.d(LOG_TAG, "output format has changed to " + oformat);
} else {
Log.d(LOG_TAG, "dequeueOutputBuffer returned " + res);
}
}
Log.d(LOG_TAG, "stopping...");
relaxResources(true);
this.mState = State.Stopped;
doStop = true;
// attempt reconnect
if(sawOutputEOS)
{
try {
AudioTrackPlayer.this.play();
return;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(noOutputCounter >= noOutputCounterLimit)
{
mDelegateHandler.onRadioPlayerError(AudioTrackPlayer.this);
}
else
{
mDelegateHandler.onRadioPlayerStopped(AudioTrackPlayer.this);
}
}
Have you monitored the CPU frequency while your application is running? The CPU governor is probably scaling the CPU up on touch and scaling back down on a timer. Increasing the priority on your background thread to THREAD_PRIORITY_DEFAULT will probably fix the issue, the default priority for AsyncTask is quite low and not appropriate for Audio.
You could also increase the size of the AudioTrack's buffer to some multiple of the value returned by getMinBufferSize, that method only returns the minimum possible buffer for the Class to operate, it does not guarantee smooth playback.
First I instantiate a gamestate
class GameState extends state{
ArrayList<Level> levels;
int currentLevelID;
public GameState() {
stateID = 2;
levels = new ArrayList<Level>();
createLevels();
currentLevelID = 0;
}
which creates levels
public void createLevels(){
try {
this.levels.add(new NormalLevel(0, 10, 10, null, null, new EmptyTile(1, 1, 1, 1, null) ));
} catch (IOException e) {
e.printStackTrace();
}
}
using this bit of code (forgot the technical term lol)
//level is the superclass of normallevel or whatever i named the default level
public Level(int id, int height, int width, ArrayList<TileEntity> tiles, ArrayList<MobileEntity> mobiles, TileEntity fillBlock){
this.height = height;
this.levelID = id;
this.width = width;
if(tiles != null){
this.tiles = tiles;
} else {
tiles = new ArrayList<TileEntity>();
try {
tiles.add(new EmptyTile(-50,-50,1,1,null));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(mobiles != null){
this.mobiles = mobiles;
} else {
mobiles = new ArrayList<MobileEntity>();
try {
mobiles.add(new DefaultEntity(-50,-50,1,1,null));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(fillBlock != null){
this.tiles = new ArrayList<TileEntity>();
this.fillWith(fillBlock);
}
}
public void fillWith(TileEntity tile){
for(int i = 0; i < this.height; i++){
for(int j = 0; j < this.width; j++){
for(int k = 0; k < this.tiles.size(); k++){
if (this.tiles.get(k).y == i && this.tiles.get(k).x == j){
break;
}
if(k == this.tiles.size()){
tile.x = j;
tile.y = i;
this.tiles.add(tile);
}
}
}
}
}
Then I try to update the level
public void update(){
this.draw();
for(int i = 0; i < this.tiles.size(); i++){
this.tiles.get(i).update();
}
for(int i = 0; i < this.mobiles.size(); i++){ //nullpointerexception here
this.mobiles.get(i).update();
}
this.specialUpdate();
}
But I get an error on the commented line. I'm confused as hell, help would be appreciated :)
Your mobiles object is null because in the following code
if(mobiles != null){
this.mobiles = mobiles;
} else {
mobiles = new ArrayList<MobileEntity>();
in the else case your assigning the local variable mobiles rather than this.mobiles
if(mobiles != null){
this.mobiles = mobiles;
} else {
mobiles = new ArrayList<MobileEntity>();
try {
mobiles.add(new DefaultEntity(-50,-50,1,1,null));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
If mobiles != null you assign the instance variable (this.mobiles), yet if they are, you create a new List, but assign it to the local variable (mobiles), which is why the list never reaches the instance variable.
I have a program and that captures the screen and then takes those images and turns them into a movie. (Using the JpegImagesToMovies.java that was customized to work with .png) I have tried multiple extensions: .mov, .mp4, .avi (I am open to trying others). However, regardless of what extension I use, when I try to open the file with Windows Media Player I get the following error:
Windows Media Player encountered a problem while playing the file.
Error code C00D11B1
I've also tried opening the file using VLC but that produces the following error:
No suitable decoder module:
VLC does not support the audio or video format "twos". Unfortunately there is no way for you to fix this.
Opening the file using QuickTime does work.
So the question is, how can I produce a video file that can be opened with most if not all media players.
Here is my JpegImagesToMovie.java
package maple;
/*
* #(#)JpegImagesToMovie.java 1.3 01/03/13
*
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or
* redistribute the Software for such purposes.
*/
import java.io.*;
import java.util.*;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.media.datasink.*;
import javax.media.format.RGBFormat;
import javax.media.format.VideoFormat;
/**
* This program takes a list of JPEG image files and convert them into a
* QuickTime movie.
*/
public class JpegImagesToMovie implements ControllerListener, DataSinkListener {
static private Vector<String> getImageFilesPathsVector(
String imagesFolderPath) {
File imagesFolder = new File(imagesFolderPath);
String[] imageFilesArray = imagesFolder.list();
Vector<String> imageFilesPathsVector = new Vector<String>();
for (String imageFileName : imageFilesArray) {
if (!imageFileName.toLowerCase().endsWith("png"))
continue;
imageFilesPathsVector.add(imagesFolder.getAbsolutePath()
+ File.separator + imageFileName);
}
return imageFilesPathsVector;
}
public boolean doIt(int width, int height, int frameRate,
Vector<String> inFiles, MediaLocator outML) {
ImageDataSource ids = new ImageDataSource(width, height, frameRate,
inFiles);
Processor p;
try {
System.err
.println("- create processor for the image datasource ...");
p = Manager.createProcessor(ids);
} catch (Exception e) {
System.err
.println("Yikes! Cannot create a processor from the data source.");
return false;
}
p.addControllerListener(this);
// Put the Processor into configured state so we can set
// some processing options on the processor.
p.configure();
if (!waitForState(p, Processor.Configured)) {
System.err.println("Failed to configure the processor.");
return false;
}
// Set the output content descriptor to QuickTime.
p.setContentDescriptor(new ContentDescriptor(
FileTypeDescriptor.QUICKTIME));// FileTypeDescriptor.MSVIDEO
// Query for the processor for supported formats.
// Then set it on the processor.
TrackControl tcs[] = p.getTrackControls();
Format f[] = tcs[0].getSupportedFormats();
if (f == null || f.length <= 0) {
System.err.println("The mux does not support the input format: "
+ tcs[0].getFormat());
return false;
}
tcs[0].setFormat(f[0]);
System.err.println("Setting the track format to: " + f[0]);
// We are done with programming the processor. Let's just
// realize it.
p.realize();
if (!waitForState(p, Controller.Realized)) {
System.err.println("Failed to realize the processor.");
return false;
}
// Now, we'll need to create a DataSink.
DataSink dsink;
if ((dsink = createDataSink(p, outML)) == null) {
System.err
.println("Failed to create a DataSink for the given output MediaLocator: "
+ outML);
return false;
}
dsink.addDataSinkListener(this);
fileDone = false;
System.err.println("start processing...");
// OK, we can now start the actual transcoding.
try {
p.start();
dsink.start();
} catch (IOException e) {
System.err.println("IO error during processing");
return false;
}
// Wait for EndOfStream event.
waitForFileDone();
// Cleanup.
try {
dsink.close();
} catch (Exception e) {
}
p.removeControllerListener(this);
System.err.println("...done processing.");
return true;
}
/**
* Create the DataSink.
*/
DataSink createDataSink(Processor p, MediaLocator outML) {
DataSource ds;
if ((ds = p.getDataOutput()) == null) {
System.err
.println("Something is really wrong: the processor does not have an output DataSource");
return null;
}
DataSink dsink;
try {
System.err.println("- create DataSink for: " + outML);
dsink = Manager.createDataSink(ds, outML);
dsink.open();
} catch (Exception e) {
System.err.println("Cannot create the DataSink: " + e);
return null;
}
return dsink;
}
Object waitSync = new Object();
boolean stateTransitionOK = true;
/**
* Block until the processor has transitioned to the given state. Return
* false if the transition failed.
*/
boolean waitForState(Processor p, int state) {
synchronized (waitSync) {
try {
while (p.getState() < state && stateTransitionOK)
waitSync.wait();
} catch (Exception e) {
}
}
return stateTransitionOK;
}
/**
* Controller Listener.
*/
public void controllerUpdate(ControllerEvent evt) {
if (evt instanceof ConfigureCompleteEvent
|| evt instanceof RealizeCompleteEvent
|| evt instanceof PrefetchCompleteEvent) {
synchronized (waitSync) {
stateTransitionOK = true;
waitSync.notifyAll();
}
} else if (evt instanceof ResourceUnavailableEvent) {
synchronized (waitSync) {
stateTransitionOK = false;
waitSync.notifyAll();
}
} else if (evt instanceof EndOfMediaEvent) {
evt.getSourceController().stop();
evt.getSourceController().close();
}
}
Object waitFileSync = new Object();
boolean fileDone = false;
boolean fileSuccess = true;
/**
* Block until file writing is done.
*/
boolean waitForFileDone() {
synchronized (waitFileSync) {
try {
while (!fileDone)
waitFileSync.wait();
} catch (Exception e) {
}
}
return fileSuccess;
}
/**
* Event handler for the file writer.
*/
public void dataSinkUpdate(DataSinkEvent evt) {
if (evt instanceof EndOfStreamEvent) {
synchronized (waitFileSync) {
fileDone = true;
waitFileSync.notifyAll();
}
} else if (evt instanceof DataSinkErrorEvent) {
synchronized (waitFileSync) {
fileDone = true;
fileSuccess = false;
waitFileSync.notifyAll();
}
}
}
public static void main(String args[]) {
// changed this method a bit
if (args.length == 0)
prUsage();
// Parse the arguments.
int i = 0;
int width = -1, height = -1, frameRate = -1;
Vector<String> inputFiles = new Vector<String>();
String rootDir = null;
String outputURL = null;
while (i < args.length) {
if (args[i].equals("-w")) {
i++;
if (i >= args.length)
prUsage();
width = new Integer(args[i]).intValue();
} else if (args[i].equals("-h")) {
i++;
if (i >= args.length)
prUsage();
height = new Integer(args[i]).intValue();
} else if (args[i].equals("-f")) {
i++;
if (i >= args.length)
prUsage();
// new Integer(args[i]).intValue();
frameRate = Integer.parseInt(args[i]);
} else if (args[i].equals("-o")) {
i++;
if (i >= args.length)
prUsage();
outputURL = args[i];
} else if (args[i].equals("-i")) {
i++;
if (i >= args.length)
prUsage();
rootDir = args[i];
} else {
System.out.println(".");
prUsage();
}
i++;
}
if (rootDir == null) {
System.out
.println("Since no input (-i) forder provided, assuming this JAR is inside JPEGs folder.");
rootDir = (new File(".")).getAbsolutePath();
}
inputFiles = getImageFilesPathsVector(rootDir);
if (inputFiles.size() == 0)
prUsage();
if (outputURL == null) {
outputURL = (new File(rootDir)).getAbsolutePath() + File.separator
+ "pngs2movie.mov";
}
if (!outputURL.toLowerCase().startsWith("file:///")) {
outputURL = "file:///" + outputURL;
}
// Check for output file extension.
if (!outputURL.toLowerCase().endsWith(".mov")) {
prUsage();
outputURL += ".mov";
System.out
.println("outputURL should be ending with mov. Making this happen.\nNow outputURL is: "
+ outputURL);
}
if (width < 0 || height < 0) {
prUsage();
System.out.println("Trying to guess movie size from first image");
BufferedImage firstImageInFolder = getFirstImageInFolder(rootDir);
width = firstImageInFolder.getWidth();
height = firstImageInFolder.getHeight();
System.out.println("width = " + width);
System.out.println("height = " + height);
}
// Check the frame rate.
if (frameRate < 1)
frameRate = 30;
// Generate the output media locators.
MediaLocator oml;
if ((oml = createMediaLocator(outputURL)) == null) {
System.err.println("Cannot build media locator from: " + outputURL);
System.exit(0);
}
JpegImagesToMovie imageToMovie = new JpegImagesToMovie();
imageToMovie.doIt(width, height, frameRate, inputFiles, oml);
System.exit(0);
}
private static BufferedImage getFirstImageInFolder(String rootDir) {
File rootFile = new File(rootDir);
String[] list = (rootFile).list();
BufferedImage bufferedImage = null;
for (String filePath : list) {
if (!filePath.toLowerCase().endsWith(".png")
&& !filePath.toLowerCase().endsWith(".png")) {
continue;
}
try {
bufferedImage = ImageIO.read(new File(rootFile
.getAbsoluteFile() + File.separator + filePath));
break;
} catch (IOException e) {
e.printStackTrace();
}
}
return bufferedImage;
}
static void prUsage() {
System.err
.println("Usage: java JpegImagesToMovie [-w <width>] [-h <height>] [-f <frame rate>] [-o <output URL>] -i <input JPEG files dir Path>");
// System.exit(-1);
}
/**
* Create a media locator from the given string.
*/
#SuppressWarnings("unused")
public static MediaLocator createMediaLocator(String url) {
MediaLocator ml;
if (url.indexOf(":") > 0 && (ml = new MediaLocator(url)) != null)
return ml;
if (url.startsWith(File.separator)) {
if ((ml = new MediaLocator("file:" + url)) != null)
return ml;
} else {
String file = "file:" + System.getProperty("user.dir")
+ File.separator + url;
if ((ml = new MediaLocator(file)) != null)
return ml;
}
return null;
}
// /////////////////////////////////////////////
//
// Inner classes.
// /////////////////////////////////////////////
/**
* A DataSource to read from a list of JPEG image files and turn that into a
* stream of JMF buffers. The DataSource is not seekable or positionable.
*/
class ImageDataSource extends PullBufferDataSource {
ImageSourceStream streams[];
ImageDataSource(int width, int height, int frameRate,
Vector<String> images) {
streams = new ImageSourceStream[1];
streams[0] = new PngImageSourceStream(width, height, frameRate, images);
}
public void setLocator(MediaLocator source) {
}
public MediaLocator getLocator() {
return null;
}
/**
* Content type is of RAW since we are sending buffers of video frames
* without a container format.
*/
public String getContentType() {
return ContentDescriptor.RAW;
}
public void connect() {
}
public void disconnect() {
}
public void start() {
}
public void stop() {
}
/**
* Return the ImageSourceStreams.
*/
public PullBufferStream[] getStreams() {
return streams;
}
/**
* We could have derived the duration from the number of frames and
* frame rate. But for the purpose of this program, it's not necessary.
*/
public Time getDuration() {
return DURATION_UNKNOWN;
}
public Object[] getControls() {
return new Object[0];
}
public Object getControl(String type) {
return null;
}
}
/**
* The source stream to go along with ImageDataSource.
*/
class ImageSourceStream implements PullBufferStream {
Vector<String> images;
int width, height;
VideoFormat format;
int nextImage = 0; // index of the next image to be read.
boolean ended = false;
public ImageSourceStream(int width, int height, int frameRate,
Vector<String> images) {
this.width = width;
this.height = height;
this.images = images;
format = new VideoFormat(VideoFormat.JPEG, new Dimension(width,
height), Format.NOT_SPECIFIED, Format.byteArray,
(float) frameRate);
}
/**
* We should never need to block assuming data are read from files.
*/
public boolean willReadBlock() {
return false;
}
/**
* This is called from the Processor to read a frame worth of video
* data.
*/
public void read(Buffer buf) throws IOException {
// Check if we've finished all the frames.
if (nextImage >= images.size()) {
// We are done. Set EndOfMedia.
System.err.println("Done reading all images.");
buf.setEOM(true);
buf.setOffset(0);
buf.setLength(0);
ended = true;
return;
}
String imageFile = (String) images.elementAt(nextImage);
nextImage++;
System.err.println(" - reading image file: " + imageFile);
// Open a random access file for the next image.
RandomAccessFile raFile;
raFile = new RandomAccessFile(imageFile, "r");
byte data[] = null;
// Check the input buffer type & size.
if (buf.getData() instanceof byte[])
data = (byte[]) buf.getData();
// Check to see the given buffer is big enough for the frame.
if (data == null || data.length < raFile.length()) {
data = new byte[(int) raFile.length()];
buf.setData(data);
}
// Read the entire JPEG image from the file.
raFile.readFully(data, 0, (int) raFile.length());
System.err.println(" read " + raFile.length() + " bytes.");
buf.setOffset(0);
buf.setLength((int) raFile.length());
buf.setFormat(format);
buf.setFlags(buf.getFlags() | Buffer.FLAG_KEY_FRAME);
// Close the random access file.
raFile.close();
}
/**
* Return the format of each video frame. That will be JPEG.
*/
public Format getFormat() {
return format;
}
public ContentDescriptor getContentDescriptor() {
return new ContentDescriptor(ContentDescriptor.RAW);
}
public long getContentLength() {
return 0;
}
public boolean endOfStream() {
return ended;
}
public Object[] getControls() {
return new Object[0];
}
public Object getControl(String type) {
return null;
}
}
class PngImageSourceStream extends ImageSourceStream {
public PngImageSourceStream(int width, int height, int frameRate,
Vector<String> images) {
super(width, height, frameRate, images);
// configure the new format as RGB format
format = new RGBFormat(new Dimension(width, height),
Format.NOT_SPECIFIED, Format.byteArray, frameRate,
24, // 24 bits per pixel
1, 2, 3); // red, green and blue masks when data are in the form of byte[]
}
public void read(Buffer buf) throws IOException {
// Check if we've finished all the frames.
if (nextImage >= images.size()) {
// We are done. Set EndOfMedia.
System.err.println("Done reading all images.");
buf.setEOM(true);
buf.setOffset(0);
buf.setLength(0);
ended = true;
return;
}
String imageFile = (String) images.elementAt(nextImage);
nextImage++;
System.err.println(" - reading image file: " + imageFile);
// read the PNG image
BufferedImage image = ImageIO.read(new File(imageFile));
boolean hasAlpha = image.getColorModel().hasAlpha();
Dimension size = format.getSize();
// convert 32-bit RGBA to 24-bit RGB
byte[] imageData = convertTo24Bit(hasAlpha, image.getRaster().getPixels(0, 0, size.width, size.height, (int[]) null));
buf.setData(imageData);
System.err.println(" read " + imageData.length + " bytes.");
buf.setOffset(0);
buf.setLength(imageData.length);
buf.setFormat(format);
buf.setFlags(buf.getFlags() | Buffer.FLAG_KEY_FRAME);
}
private void convertIntByteToByte(int[] src, int srcIndex, byte[] out, int outIndex) {
// Note: the int[] returned by bufferedImage.getRaster().getPixels()
// is an int[]
// where each int is the value for one color i.e. the first 4 ints
// contain the RGBA values for the first pixel
int r = src[srcIndex];
int g = src[srcIndex + 1];
int b = src[srcIndex + 2];
out[outIndex] = (byte) (r & 0xFF);
out[outIndex + 1] = (byte) (g & 0xFF);
out[outIndex + 2] = (byte) (b & 0xFF);
}
private byte[] convertTo24Bit(boolean hasAlpha, int[] input) {
int dataLength = input.length;
int newSize = (hasAlpha ? dataLength * 3 / 4 : dataLength);
byte[] convertedData = new byte[newSize];
// for every 4 int values of the original array (RGBA) write 3
// bytes (RGB) to the output array
// if there is no alpha (i.e. RGB image) then just convert int to byte
for (int i = 0, j = 0; i < dataLength; i += 3, j += 3) {
convertIntByteToByte(input, i, convertedData, j);
if (hasAlpha) {
i++; // skip an extra byte if the original image has an
// extra int for transparency
}
}
return convertedData;
}
}
}
And I make the video doing the following
public void makeVideo (String movFile) throws MalformedURLException {
JpegImagesToMovie imageToMovie = new JpegImagesToMovie();
Vector<String> imgList = new Vector <String>();
File f = new File(JavCapture.tmpLocation + "\\tmp\\");
File[] fileList = f.listFiles();
for (int i = 0; i < fileList.length; i++) {
imgList.add(fileList[i].getAbsolutePath());
}
MediaLocator ml;
if ((ml = imageToMovie.createMediaLocator(movFile)) == null) {
System.exit(0);
}
setWidth();
setHeight();
imageToMovie.doIt(width, height, (1000/125), imgList, ml);
}