Olá galera,

Após muitos post e tutoriais pela internet, de tanto quebrar a cabeça para gerar FLV apartir dos formatos AVI,MPEG, MPG, WMV e MOV, criei uma classe para conversão de vídeos e geração de imagens a partir do vídeo ( crop de um frame do vídeo), segue abaixo o código compartilar com vocês.

Primeiramente você precisa ter instalado em seu sistema (Linux) as seguintes bibliotecas, execute o comando abaixo como root em seu console:


sudo apt-get install libfaad-dev libmp3lame-dev libmp3lame0 libfaac-dev libfaad2-dev

Lembrando que estas bibliotecas foram instaladas em ambiente 32 bits, se você instalar em ambiente 64bits os nomes das bibliotecas podem mudar.

Só agora instale o ffmpeg:


sudo apt-get install ffmpeg

A classe abaixo utiliza o Design Pattern Singleton, onde apenas uma única instância do conversor de vídeos ficará ativa por se tratar de um processo que utiliza muitos recursos do sistema operacional foi optado por criar uma Thread interna que converterá um único vídeo por vez, os restantes ficarão na fila de espera.

Segue abaixo classe em questão, lembrando que não foi abordado aqui o JavaBean Midia, que contem apenas dois atributos "caminho" e "destino" com seus respectivos getters e setters. Crie você mesmo este bean e modifique a lista de pool de vídios a converter.

package br.com.ronaldorigoni.videoconverter.util;

import br.gov.mec.portaldoprofessor.client.cms.JornalRemote;
import br.gov.mec.portaldoprofessor.client.vo.MidiaAProcessar;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.naming.InitialContext;
import org.apache.log4j.Logger;

/**
* Classe utilitária para conversão de vídeos usando a biblioteca natíva <code>ffmpeg</code> * Utiliza o mecanismo de pool de conversão.
* Para um correto funcionamento deve-se instalar a biblioteca com as seguintes dependências.
* ffmpeg - A própria biblioteca
* libfaad-dev - Biblioteca de desenvolvimento de áudio é vídeo.
* libfaac-dev  - Biblioteca de desenvolvimento para otimizaçãoes no streaming de áudio.
* libfaad2-dev - Biblioteca de desenvolvimento de áudio e vídeo versão dois.
* Testado em ambiente Ubuntu - Debian
* @author Ronaldo Rigoni
*/
public class VideoConverter {

/**
* Logger statico para o Conversor de Vídeo
*/
private static final Logger logger = Logger.getLogger(VideoConverter.class);
/**
* Pool de mídias a converter.
*/
private static final List<Midia> midiasAProcessar = new ArrayList<Midia>();

/**
* Adiciona uma midia no pool.
* @param midia Midia a converter.
*/
public void addMediaInPool(MidiaAProcessar midia) {
midiasAProcessar.add(midia);
}
/**
* Thread responsável por verificar a todo momento se existem vídeos a serem convertidos
* Caso possuir algum vídeo, efetua a conversão gera as imágens do respectivo vídeo,
* atualiza em banco as informaçãoes da mídia e notifica ao usuário que inseriu este vídeo.
*/
private Runnable worker = new Runnable() {
public void run() {
while (true) {
if (!midiasAProcessar.isEmpty() &amp;amp;amp;&amp;amp;amp; midiasAProcessar.get(0) != null) {
MidiaAProcessar midiaAProcessar = midiasAProcessar.get(0);
String command = command(midiaAProcessar.getCaminho(), midiaAProcessar.getDestino());
String commandCropImagemMedia = commandImagemMedia(midiaAProcessar.getDestino());
String commandCropImagemMicro = commandImagemMicro(midiaAProcessar.getDestino());
Process videoProcess = null;
Process imageMediaProcess = null;
Process imageMicroProcess = null;
try {
videoProcess = Runtime.getRuntime().exec(command);
int code = videoProcess.waitFor();
if (code == 0) {
logger.debug("Gerado video com sucesso.");
} else {
logger.error("Erro ao converter video");
processConsoleOut(videoProcess.getErrorStream());
}
if (code == 0) {
imageMediaProcess = Runtime.getRuntime().exec(commandCropImagemMedia);
int imageMediaCode = imageMediaProcess.waitFor();
if (imageMediaCode == 0) {
logger.debug("Imagem media gerada com sucesso.");
} else {
logger.error("Erro ao gerar imagem media." );
processConsoleOut(imageMediaProcess.getErrorStream());
}
}
logger.debug(" Executando:"  + commandCropImagemMicro);
if (code == 0) {
imageMicroProcess = Runtime.getRuntime().exec(commandCropImagemMicro);
int imageMicroCode = imageMediaProcess.waitFor();
if (imageMicroCode == 0) {
logger.debug(" Imagem micro gerada com sucesso." );
} else {
logger.error(" Erro ao gerar imagem micro." );
processConsoleOut(imageMicroProcess.getErrorStream());
}
}
// codigo de saida igual a zero significa sucesso.
if (code == 0) {
// aqui voce pode notificar o usuário que solicitou ao conversão do vídeo
// de que o mesmo ja se encontra disponível, ou tratar de alguma forma
// a conversao com sucesso.
}
} catch (Exception e) {
e.printStackTrace();
}
midiasAProcessar.remove(0);
}
}
}
};
private static VideoConverter instance;

private VideoConverter() {
init();
}

/**
* Inicializa o mecanizmo de conversão de videos.
*/
private void init() {
new Thread(worker).start();
logger.info(" Mecanizmo de vídeos inicializado com sucesso." );
}

/**
* Retorna uma instância singleton do conversor de vídeos.
* @return Instancia singleton VideoConverter
*/
public static synchronized VideoConverter getInstance() {
if (instance == null) {
instance = new VideoConverter();
}
return instance;
}
/**
* Formato MPEG
*/
public static final String MPEG_FORMAT = " mpeg";
/**
* Formato MPG
*/
public static final String MPG_FORMAT = "mpg";
/**
* Formato AVI
*/
public static final String AVI_FORMAT = "avi";
/**
* Formato MOV
*/
public static final String MOV_FORMAT = "mov";

/**Formato WMV **/
public static final String WMV_FORMAT = "wmv";
/**
* Representa o comando para conversão de vídeos AVI
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* Importante: para otimizar qualidade apenas modifique os parâmetros -qmin e -qmax
* -qmin 0 a 30
* -qmax 0 a 30
* Em todas as hipotezes -qmax deve ser um valor maior que -qmin, -qmin reduz o tamanho do video
* e -qmax assegura manter a qualidade, portando deve ser alto e alterar prefeferivelmente -qmin.
*/
private static final String COMMAND_AVI = "ffmpeg -i   {0}  -qmin 6 -qmax 26 -ar 22050 -f flv -y  {1}";
/**
* Representa o comando para converter um vídeo no formato MOV para FLV.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* Apenas altere os parâmetros -qmin e -qmax.
* -qmin 0 a 30
* -qmax 0 a 30
* -s significa o tamanho da saida do vídeo, resolução.
*/
private static final String COMMAND_MOV = " ffmpeg -y -i  {0}  -vcodec flv -b 400kb -s 500x376 -qmin 10 -qmax 30 -ar 22050 -ac 1  {1} ";
/**
* Representa o comando para converter um vídeo no formato MPG ou MPEG para FLV.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -r frames por segundo
* -s tamanho de saida do vídeo.
*/
private static final String COMMAND_MPG_MPEG = " ffmpeg -i  {0}  -y -r 25 -b 500k -ar 22050 -s 500x376 -ab 24k  {1}";
/**
* Representa o comando para efetuar o crop da imagem media de um vídeo.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -itsoffset representa o segundo em que será efetuado o crop
* -vframes significa o respectivo frame para o segundo expecificado acima
* -s tamanho da imagem. Só aceita medidas pares.
*/
private static final String COMMAND_CROP_VIDEO_IMAGEM_MEDIA = "ffmpeg  -itsoffset -10  -i  {0}  -vcodec mjpeg -vframes 1 -an -f rawvideo -s 130x96 -y {1}";
/**
* Representa o comando para efetuar o crop da imagem pequena de um vídeo.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -itsoffset representa o segundo em que será efetuado o crop
* -vframes significa o respectivo frame para o segundo expecificado acima
* -s tamanho da imagem. Só aceita medidas pares.
*/
private static final String COMMAND_CROP_VIDEO_MICRO_IMAGEM = "ffmpeg  -itsoffset -10  -i  {0}  -vcodec mjpeg -vframes 1 -an -f rawvideo -s 60x46 -y {1}";

/**
* Representa comando de conversão de videos WMV para FLV.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -s = Tamanho do vídeo ( resolução), só aceita medidas pares.
* -qmin e -qmax são parâmetros de qualidade.
* -qmin 0 a 30
* -qmax 0 a 30
*/
private static final String COMMAND_WMV = "ffmpeg -y -i {0} -ar 22050 -ab 32 -s 500x376 -qmin 6 -qmax 26 -f flv -s 320x320 {1}";

/**
* Gera o comando expecífico de acordo com a extenção do arquivo.
* @param videoIn Caminho de entrada do vídeo.
* @param videoOut Caminho de saída do video.
* @return O comando formatado.
*/
private static String command(String videoIn, String videoOut) {
String command = &amp;amp;quot;&amp;amp;quot;;
String fileName = videoIn.substring(videoIn.lastIndexOf("/") + 1, videoIn.length());
String extension = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
// formato AVI
if (extension.equalsIgnoreCase(AVI_FORMAT)) {
command = new MessageFormat(COMMAND_AVI).format(new Object[]{videoIn, videoOut});
// formato MOV
} else if (extension.equalsIgnoreCase(MOV_FORMAT)) {
command = new MessageFormat(COMMAND_MOV).format(new Object[]{videoIn, videoOut});
// formato MPEG ou MPG
} else if (extension.equalsIgnoreCase(MPEG_FORMAT) || extension.equalsIgnoreCase(MPG_FORMAT)) {
command = new MessageFormat(COMMAND_MPG_MPEG).format(new Object[]{videoIn, videoOut});
// formato WMV
}else if(extension.equalsIgnoreCase(WMV_FORMAT)){
command = new MessageFormat(COMMAND_WMV).format(new Object[]{videoIn, videoOut});
}else {
throw new IllegalArgumentException("Formato de arquivo não suportado:"+extension);
}
return command;
}

/**
* Processa o stream de saída de erros caso alguma conversão não tenha ocorrido com sucesso.
* @param is InputStream
* @throws java.io.IOException Em caso de excessão de IO
*/
private void processConsoleOut(InputStream is) throws IOException {
byte[] buffer = new byte[512];
int bytes = 0;
StringBuffer stringBuffer = new StringBuffer();
do {
buffer = new byte[512];
bytes = is.read(buffer);
if (bytes > 0) {
stringBuffer.append(new String(Arrays.copyOf(buffer, bytes)));
}
} while (bytes >= buffer.length);
String output = stringBuffer.toString();
logger.error(output);
}

/**
* Gera o comando de crop para uma imagem tamanho médio.
* IMPORTANTE: Altere o tamanho para geraçao da sua imagem média para -s alturaXlargura
* @param videoOut Caminho do vídeo.
* @return Comando formatado para crop de imagem média.
*/
private static String commandImagemMedia(String videoOut) {
String imagenOut = videoOut + ".media.jpeg";
String commandImagemMedia = new MessageFormat(COMMAND_CROP_VIDEO_IMAGEM_MEDIA).format(new Object[]{videoOut, imagenOut});
return commandImagemMedia;
}

/**
* Gera o comando de crop para uma imagem micro.
* @param videoOut O caminho completo do vídeo de entrada.
* @return O Comando de crop de imagem micro formatado.
*/
private static String commandImagemMicro(String videoOut) {
String imageOut = videoOut + ".micro.jpeg";
String commandImagemMicro = new MessageFormat(COMMAND_CROP_VIDEO_MICRO_IMAGEM).format(new Object[]{videoOut, imageOut});
return commandImagemMicro;
}

}

Espero ajudar de alguma forma e que você tenha sucesso em suas conversões de vídeos.

Qualquer dúvida ronaldo at ronaldorigoni.com.br

  • Português Português
  • Italiano Italiano
  • English English