domenica 25 agosto 2013

Converting video with JAVE

JAVE is a java library developed by sauronsoftware, it's a wrapper of FFmpeg and it's an easy way to converting video from a format to another. The main class of jave is it.sauronsoftware.jave.Encoder, Encoder objects have methods that transcode multimedia files.
First thing to do is adding JAVE to your CLASSPATH, if you are using eclipse simply import jave-1.0.jar in your project. Now in your code create an object of Encoder:
Encoder encoder = new Encoder();
Now you just call encode() to do the work, let's see it's signature:
public void encode(java.io.File source,
                   java.io.File target,
                   it.sauronsoftware.jave.EncodingAttributes attributes)
            throws java.lang.IllegalArgumentException,
                   it.sauronsoftware.jave.InputFormatException,
                   it.sauronsoftware.jave.EncoderException
the first argument (source) is the file you want to transcode, the second one (target) is the file you want to create on the machine. The argument attributes of type it.sauronsoftware.jave.EncodingAttributes is a structure that has all the propriety we want to give to our video. Attention: the method is syn, it returns after the video transcoding. Let's see how it's possible to convert a video by setting VideoAttributes and AudioAttributes:
 public static void convertVideo(String videoInput, String videoName) throws IllegalArgumentException, InputFormatException, EncoderException
 {
  String videoOutput = videoName + ".flv";
  Encoder encoder = new Encoder();
  
  File source = new File(videoInput);
  File target = new File(videoOutput);
  AudioAttributes audio = new AudioAttributes();
  audio.setCodec("libmp3lame");
  audio.setBitRate(new Integer(Config.AUDIO_BITRATE * 1000));
  audio.setChannels(new Integer(Config.AUDIO_CHANNELS));
  audio.setSamplingRate(new Integer(Config.AUDIO_SAMPLINGRATE));
  VideoAttributes video = new VideoAttributes();
  video.setCodec("flv");
  video.setBitRate(new Integer(Config.VIDEO_BITRATE*10000));
  video.setFrameRate(new Integer(Config.VIDEO_FRAMERATE));
  video.setSize(new VideoSize(Config.VIDEO_WIDTH, Config.VIDEO_HEIGHT));
  EncodingAttributes attrs = new EncodingAttributes();
  attrs.setFormat("flv");
  
  attrs.setAudioAttributes(audio);
  attrs.setVideoAttributes(video);
  
  encoder.encode(source, target, attrs);
 }
The video is converted in .flv format with given framerate, width, height and bitrate. The audio is transcoded in libmp3lame with given samplingrate. The values I've used to make a not so heavy .flv file are the following:
public class Config {
 public static int VIDEO_WIDTH = 640;
 public static int VIDEO_HEIGHT = 360;
 public static int VIDEO_FRAMERATE = 15;
 public static int VIDEO_BITRATE = 128;
 
 public static int AUDIO_SAMPLINGRATE = 22050;
 public static int AUDIO_CHANNELS = 1;
 public static int AUDIO_BITRATE = 64;
}
That's all, for media manipulation I suggest you to see FFmpeg and my previous post to give you the idea of how to do it in java. --------------------------------------------------------------------
ITA
La documentazione di JAVE è disponibile in italiano sul sito, il mio esempio si occupa di codificare un video da un formato input compatibile a .flv con le configurazioni date nella classe Config.

martedì 20 agosto 2013

Transcoding and Media Modification > Java - FFmpeg

Nel corso di un lavoro mi è capitato di dover scrivere del codice che permettesse di effettuare delle veloci modifiche ad un filmato, quali conversioni tra formati e tagli. Dopo aver guardato diverse librerie mi sono accorto che la migliore soluzione è quella di utilizzare ffmpeg.exe, un eseguibile che permette di effettuare semplici operazioni su file multimediali, tagli, merge, cattura di un immagine.

Per effettuare delle elaborazioni video è necessario richiamare ffmpeg.exe da linea di comando, passati i corretti parametri, ad esmpio:
ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo.jpeg
Questa riga permette di ottenere un immagine .jpeg di dimensioni WxH del primo frame del filmato.
La documentazione di ffmpeg può essere trovata a questo indirizzo, tra i comandi più importanti voglio citare:

  • -r fps -> specifica il frame rate in output
  • -s size -> specifica la dimensione del filmato con sintassi LarghezzaxAltezza
  • -vcodec codec -> specifica il codec in output
Una volta capito come funziona l'eseguibile è facile creare un wrapper in Java, basta utilizzare la classe Runtime per ottenere il runtime di sistema. Di seguito vediamo da codice una funzione che presi in input due istanti di tempo, il percorso del video in input e in output utilizza ffmpeg per creare un video tagliato.


	public static void singleCut(double start, double end,String videoPathIn, String videoPathOut) throws IllegalArgumentException, InputFormatException, EncoderException, IOException, InterruptedException
	{
		String cmd = Config.FFMPEG+" -i "+ videoPathIn +" -q 5 -ss "+ start +" -to "+ end +" -y "+videoPathOut;
		//System.out.print(cmd);
		Runtime runtime = Runtime.getRuntime();
		Process p = runtime.exec(cmd);
		p.waitFor();
	}
Nel codice sovrastante Config.FFMPEG non è altro che una variabile statica con il percorso relativo al nostro file ffmpeg.exe .
Per effettuare delle conversioni ai filmati via codice vorrei anche segnalare questa libreria sviluppata da un italiano chiamata JAVE.
----------------------------------------------------------------------
ENG:
To transcode and execute single tasks on multimedia files by code the best way I found myself using is to create a wrapper around FFmpeg.exe. As you can see by the documentation this tool permits to do anything on video and audio files, things like extrapolate images or perform single cuts, are really easy and only require to read how to do it. For example the following line permits to take an image from the first frame in the video with width and height as WxH:
ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo.jpeg
To easily call FFmpeg in Java simply use Runtime class to perform what you usually do in the command line.

	public static void singleCut(double start, double end,String videoPathIn, String videoPathOut) throws IllegalArgumentException, InputFormatException, EncoderException, IOException, InterruptedException
	{
		String cmd = Config.FFMPEG+" -i "+ videoPathIn +" -q 5 -ss "+ start +" -to "+ end +" -y "+videoPathOut;
		//System.out.print(cmd);
		Runtime runtime = Runtime.getRuntime();
		Process p = runtime.exec(cmd);
		p.waitFor();
	}
The string cmd is the line we want the code to execute by doing runtime.exec(cmd), Config.FFMPEG is just a static string with the absolute path of FFmpeg.exe.
I would recommend to take a look at JAVE if you just want to do simple video trascoding, it's quite nice and fast to use.

lunedì 19 agosto 2013

Blogger > Posting Code

Quando mi sono registrato su blogger mi aspettavo che non ci fosse nessuno strumento per permettere di postare cascate di codice che risulti poi leggibile. Fortunatamente è possibile integrare qualsiasi cosa nel modello del blog semplicemente modificandone l'html.
Per ottenere lo stesso effetto usato nel blog andate in I miei blog > modello > modifica html , successivamente copiate quanto segue dopo la chiusura del tag head ( </head> ).

 
 
 




Adesso ogni volta che effettuate un nuovo post andate su HTML e utilizzate:

//Put your Java code here

per scrivere codice Java e

//Put your xml code here

per l'Xml

------------------------
ENG: 1-Go to your blog.
2-Then click on Template
3-The click on Edit Html
4-And copy paste the first code before closing Head tag
5-Use the last writed tag while posting

Credits to SyntaxHighlighter

domenica 18 agosto 2013

Equalizer > Android > Java

Chi di voi ha già programmato per android avrà notato quanto è vasto l'ambiente di sviluppo, Google mette a disposizione classi ben documentate per qualsiasi componente presente nel telefono. Tempo fa mi è capitato di utilizzare il componente Equalizer e BassBoost, dei quali però trovai poca documentazione, di seguito vediamo come ottenere questi oggetti e come gestire le loro proprietà in un Activity separata.

Main Activity
package it.test.equalizertest;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

 MediaPlayer mp;
 public static Equalizer equalizer;
 public static BassBoost bassboost;
 String SONG_PATH = "/storage/sdcard0/media/audio/06-soft-rock-star.mp3";
 //Stringa con il percorso della canzone
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  //MediaPlayer
     mp = new MediaPlayer();
     equalizer = new Equalizer(99999999, mp.getAudioSessionId()); //Ottengo l'Equalizer con alta priorità
     bassboost = new BassBoost(999999, mp.getAudioSessionId()); //Ottengo il bassboost con priorità 99999

     setVolumeControlStream(AudioManager.STREAM_MUSIC);

  //Abilita Equalizer
  int val = equalizer.setEnabled(true);
     if(val != Equalizer.SUCCESS)
      Log.v("A", "EQUALIZER NON ATTIVO" + val);
     val = bassboost.setEnabled(true);
     if(val != Equalizer.SUCCESS)
      Log.v("A", "BASSBOOST NON ATTIVO" + val);
     else
      Log.v("A", "SUCCESS!");
     
     //Button Play plays a song in SONG_PATH
     Button btn_play = (Button) findViewById(R.id.button_play);
     btn_play.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    try{
      mp.reset();
      mp.setDataSource(SONG_PATH); //setto il file audio come datasource
      mp.prepare();
      mp.start(); //faccio partire il mediaplayer
     }
    catch(Exception ex){};
   }
  });
     
     Button btn_eq = (Button) findViewById(R.id.button_equalizer);
     btn_eq.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    openEqualizer(); //apro una nuova activity
   }
  });
 }

 @Override
 public void onDestroy()
 {
   super.onDestroy();
   
   if(mp != null){
    mp.release(); //rilascio il media player
   }
   if(equalizer != null)
    equalizer.release();
   if(bassboost != null)
    bassboost.release();
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }
 
 public void openEqualizer()
 {
  Intent i = new Intent(MainActivity.this, EqualizerActivity.class);
  startActivity(i); //apre l'equalizer
  //l'oggetto equalizer è passato come statico
 }

}
Quello che abbiamo fatto fin ora è ottenere dal dispositivo gli oggetti Equalizer e BassBoost, i quali sono unici e per questo motivo va specificata la priorità con la quale li richiamiamo, applicazioni come n7Player hanno processi che mantengono il controllo su equalizer, bassboost e altro con massima priorità, per cui è indispensabile in un applicazione mettere un controllo per specificare se il programma ha i privilegi per modificare le proprieà dell'equalizer. Tramite la costante Equalizer.SUCCESS possiamo verificare quanto detto precedentemente, basta guardare il codice in alto.
In una nuova activity creiamo via codice gli slider necessari per il controllo dell'Equalizer:
EqualizerActivity
package it.test.equalizertest;

import android.app.Activity;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

public class EqualizerActivity extends Activity {

    private Equalizer equalizer;
    private BassBoost bassboost;
    private short bbs = 0;
    TextView bbTextView;
    private static final short BASSBOOST_MAX_STRENGTH = 1000; //MIN = 0

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        equalizer = MainActivity.equalizer; //preso dall'activity -> sempre attivo
        bassboost = MainActivity.bassboost;
        int val = equalizer.setEnabled(true);
        if(val != Equalizer.SUCCESS)
         Log.v("A", "EQUALIZER NON ATTIVO " + val);
        setupEqualizerFXandUI();
        
    }
    
    
    //generato dinamicamente a seconda delle bande percepite
    private void setupEqualizerFXandUI()
    {
     TextView eqTextView = new TextView(this);
     eqTextView.setText("Equalizer:");
     LinearLayout ll = new LinearLayout(this);
     ll.setOrientation(LinearLayout.VERTICAL);
     ll.addView(eqTextView);
     
     setContentView(ll);
     
      short bands = equalizer.getNumberOfBands(); //numero di bande di frequenza modificabili
      final short minEQLevel = equalizer.getBandLevelRange()[0]; //minimo per banda
      final short maxEQLevel = equalizer.getBandLevelRange()[1]; //massimo per banda
      
      LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
   layoutParams.weight = 1;
      
      for(short i = 0; i< bands; i++)
      {
       final short band = i;
       //Log.v("A", "B "+ band);
       TextView freqTv = new TextView(this);
       freqTv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       freqTv.setGravity(Gravity.CENTER_HORIZONTAL);
       freqTv.setText((equalizer.getCenterFreq(band) /1000) + " Hz");
       ll.addView(freqTv);
       
       LinearLayout row = new LinearLayout(this);
       row.setOrientation(LinearLayout.HORIZONTAL);
       
       TextView minDbTv = new TextView(this);
       minDbTv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       minDbTv.setText((minEQLevel / 100) + " dB");
       
       TextView maxDbTv = new TextView(this);
       maxDbTv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
       maxDbTv.setText((maxEQLevel / 100) + " dB");
       
       SeekBar bar = new SeekBar(this);
       bar.setLayoutParams(layoutParams);
       bar.setMax(maxEQLevel - minEQLevel);
       bar.setProgress(equalizer.getBandLevel(band)); // Volume della banda
       
       bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }
    
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
     
    }
    
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
      boolean fromUser) {
     equalizer.setBandLevel(band, (short)(progress + minEQLevel));
     Log.v("A", "LEVEL: " + (progress + minEQLevel));
    }
   });
       
       row.addView(minDbTv);
       row.addView(bar);
       row.addView(maxDbTv);
       
       ll.addView(row);
      }
      
     //BASS BOOST
     bbs = bassboost.getRoundedStrength();
     bbTextView = new TextView(this);
      bbTextView.setText("BassBoost: " + bbs);
      
      SeekBar bar = new SeekBar(this);
   bar.setLayoutParams(layoutParams);
   bar.setMax(BASSBOOST_MAX_STRENGTH);
   bar.setProgress(bassboost.getRoundedStrength());
   
   bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    bbs = (short) progress;
    bassboost.setStrength(bbs);
    bbTextView.setText("BassBoost: " + bbs);
   }
  });
      
      LinearLayout row = new LinearLayout(this);
  row.setOrientation(LinearLayout.HORIZONTAL);
  
  row.addView(bbTextView);
  row.addView(bar);
  ll.addView(row);
    }
}


Il codice sovrastante è autoesplicativo, per chi non ha troppa confidenza con android consiglio di vedere come si creano dinamicamente i layout e le view, con equalizer.setEnabled ricontrolliamo che l'oggetto sia in funzione per la nostra app,  equalizer.getNumberOfBands() ritorna il numero di bande che possiamo modificare, con equalizer.setBandLevel possiamo settare il volume bassato uno specifico id di banda.


La documentazione completa per questa classe è disponibile a questa pagina.
L'esempio completo può essere scaricato al seguente link: https://dl.dropboxusercontent.com/u/23802589/EqualizerTest.rar

About me

Apro questo blog sperando di poter condividere con qualche appassionato di informatica i miei lavori. Onestamente ho sempre sdegnato questo mezzo per condividere informazioni, però per evitare di essere troppo restrittivo ho voluto fare una prova. Mi occupo di informatica e da un pò di anni studio presso l'università di Bologna, ho ancora molto da imparare, ma mi farebbe un gran piacere poter condividere informazioni che potrebbero risultare utili a qualche programmatore che come me in passato non sa dove andare a sbattere la testa. Principalmente tratterò le materie che più ritengo "divertenti", ultimamente ho fatto parecchia conoscenza con Java e il mondo Android, quindi inizierò a parlare soprattutto di questo, negli ultimi mesi ho sviluppato a tempo libero un applicazione chiamata Gesture Player, un lettore musicale che funziona tramite i gesti, provatelo se avete voglia.
Come hobby ho sempre cercato di programmare nell'ambito dei videogiochi, negli anni ho sviluppato una conoscenza base dell'engine Unity3D, quindi credo che tratterò anche di quest'ultimo, magari soffermandomi anche sugli aspetti grafici di un gioco, aspetto che ho imparato a gestire da poco.
Non credo che utilizzerò il blog per sfogarmi come fanno le ragazzine quindicenni, però mi piacerebbe di tanto in tanto parlare di videogames, fumetti e se avessi una tavoletta grafica magari potrei postare anche qualche mio fumetto, insomma un pò di off topic.

In conclusione, tante belle cose, spero che il blog risulti utile in futuro, a prescindere da quello che diventerà spero che chi interessato continui a seguirmi.

---------------

Hi all, I'm Pievis, I'm opening this blog hoping this would be useful for someone, I'll discuss about my personal code and give some people advice. For now I'll start showing some basic stuff in Java, my hobby is to make videgames and so far I think I can show some trick with Unity3D.
I'm not that good writing in english, so don't really expect too much, I hope my code is enough.

In the end, welcome to my blog, enjoy your stay.