Direct Show Java

Esta página está voltada para filmagem através da webcam, após intensa pesquisa, conclui que a maneira mais fácil de trabalhar com webcam na plataforma java é através da biblioteca DirectShow Java. Portanto, este trabalho se fundamenta na consulta da documentação do pacote de.humatic.dsj, o link http://www.humatic.de/htools, foi acessado pelo google afim de fazer a tradução, está tradução não foi corrigida, porém, para quem não domina a lingua inglesa, essa tradução ajuda muito.

Há bastante matéria ainda a ser abordada a respeito deste assunto, tal matéria é difícil de ser encontrada, há poucos tutoriais e livros, os assuntos aqui abordados são uma boa introdução.

Recomendo que acesse a documentação original, conforme os passos abaixo:

1. http://www.humatic.de/htools/

2. Libraries Escolha DSJ

3. No final da página que abrirá clique no link browse javadocs, escolha o package de.humatic.dsj


Sugestão  de pesquisa:
http://code.google.com/p/runwalkvideo/source/browse/runwalk-video/trunk/src/main/java/com/?r=379#com%2Frunwalk%2Fvideo%2Fmedia%2Fdsj  Esta página fornece vários códigos fontes, verifiquei os mesmos, parecem que tais códigos estão bem evoluídos.          

Comentários:

- A DSFiltergraph  é classe principal deste pacote.
- A classe DCapture realiza a captura de vídeo com a webcam disponível.

- Com o Web Start voce executa uma applet fora do navegador de internet, é pode inclusive publicar uma aplicação desktop, tal qual baixá-la ou executá-la via Web, o que já é um avanço, bastando tão somente você configura as permissões de segurança no Policytool.

- Caso você esteja utilizando caixas de som em seu computador e tiver ativado a gravação de áudio e vídeo, você ficará muito irritado pois haverá um problema de microfonia caso a webcam ou dispositivo de captura de áudio capture o áudio reproduzido pelas caixas de som.
Para solucionar esse problema basta que você desligue a reprodução do áudio durante a captura de áudio e vídeo, faça da seguinte forma.

DSFilterInfo[][] dsiVideo = DSCapture.queryDevices();
DSCapture graph = new DSCapture(DSFiltergraph.RENDER_NATIVE,
                   dsiVideo[0][dispositivo_de_video],
                   false, //Capturar audio do dispositivo de video
                   dsiVideo[0][dispositivo_de_audio], //Dispositivo de audio
                   this); //Instância de objeto que implemente PropertyChangeListener
graph.lockVolume(0f);
graph.setPreview();

A solução DirectShow

- DirectShow sincroniza a reprodução através do encapsulamento de dados de mídia em amostras tempo estampadas. Para lidar com a variedade de fontes, formatos e dispositivos de hardware que são possíveis, DirectShow usa uma arquitetura modular, em que a aplicação mistura e combina componentes de software diferentes chamados filtros.

- DirectShow fornece filtros que capturam apoio e dispositivos de ajuste baseado no Windows Driver Model (WDM), bem como filtros que suportam legado de vídeo para (VFW) placas de captura do Windows e codecs escritos para o Audio Compression Manager (ACM) e Gerenciador de compactação de vídeo (VCM) de interfaces.

- O diagrama a seguir mostra a relação entre uma aplicação, os componentes do DirectShow, e alguns dos componentes de hardware e software que suporta DirectShow. 


Como ilustrado aqui, filtros DirectShow comunicar e controla, uma ampla variedade de dispositivos, incluindo o sistema de arquivos local, sintonizador de TV e placas de captura de vídeo, VfW codecs, o monitor de vídeo (através de DirectDraw ou GDI) e da placa de som (através de DirectSound). Assim, DirectShow isola a aplicação de muitas das complexidades destes dispositivos. DirectShow também oferece compressão nativa e filtros de descompressão para determinados formatos de arquivo.


Instalação da biblioteca DSJ

Depois de ter feito o download do DSJ no site da Humatic, que se encontra na versão 0_8_61, copie os arquivos "dsj.jar" e "dsj.dll" para seu classpath de preferência (jre do kdk), no meu caso utilizei "C:\java\jdk17017\jre\lib\ext
Observações:

1) A figura abaixo mostra a biblioteca descompactada e os arquivos dsj.dll e dsj.jar.



2) Os arquivos dsj.jar e dsj.dll foram incluidos em C:\java\jdk17017\jre\lib\ext (utilizado em tempo de execução), e no C:\java\jre7\lib\ext, ressalta-se que poderia ter sido copiado para o jdk do netbeans. 

A figura abaixo mostra a instalação do Java (jdk).

Com as pastas abertas:


Sem a inclusão de tais arquivos a webcam simplesmente não era detectada, gerando oerro abaixo no netbeans:

run:
java.lang.UnsatisfiedLinkError: no dsj in java.library.path
Exception in thread "main" java.lang.UnsatisfiedLinkError: de.humatic.dsj.DSFiltergraph.initMethodIDs()V
    at de.humatic.dsj.DSFiltergraph.initMethodIDs(Native Method)
    at de.humatic.dsj.DSFiltergraph.<clinit>(SourceFile:144)
    at SimpleCapture.createGraph(SimpleCapture.java:31)
    at SimpleCapture.main(SimpleCapture.java:111)
Java Result: 1

3) Após a inclusão dos dois arquivo conforme explicado acima, deve-se adicionar o arquivo dsj.jar na biblioteca do respectivo projeto, podendo apontar  para o diretório onde foi colado, C:\java\jdk17017\jre\lib\ext, embora o arquivo dsj.jar possa estar arquivado (armazenado) em qualquer diretório.


Tarefas básicas DirectShow

Esta seção descreve algumas tarefas básicas no DirectShow. Estas tarefas são relevantes em muitos cenários de aplicação, pois eles não são específicos para qualquer um domínio. Esta seção contém os seguintes tópicos:

    Processamento de vídeo
    Respondendo a eventos
    Enumerando Aparelhos e filtros
    Enumerando objetos em um filtro gráfico
    Técnicas gerais Graph-construção
    Buscando o filtro gráfico
    Definir o Graph Relógio
    Depuração no DirectShow

O bloco básico compilação do DirectShow é uma unidade do software chamado um filtro. Um filtro geralmente executa uma operação única em uma multimídia transmitir. De exemplo, existem filtros DirectShow que fazem o seguinte.
Ler arquivos.
Decodificar um formato específico transmitir, such as MPEG-1 vídeo.
Passar dados para o cartão, elementos gráficos ou som. 


Filtros receber entrada e gera saída. Por exemplo, se um filtro decodifica vídeo MPEG-1, a entrada é a transmitir MPEG-encoded e a saída é um vídeo RGB descompactado transmitir.
Para executar uma determinada tarefa, um aplicativo se conecta vários filtros de modo que a saída de um filtro se torne a entrada para outro. Um conjunto de filtros conectados é chamado um filtro gráfico.
Seu aplicativo não precisa gerenciar o individual filtros em um filtro gráfico. Em vez disso, o DirectShow oferece um chamado auxiliar de alto nível de Filtrar Graph Manager. O Filter Graph Manager controla o fluxo de dados por meio do gráfico. Seu aplicativo faz chamadas API de alto nível, como 'Executar' (Para mover dados por meio do gráfico) ou "Finalizar" (Para parar o fluxo de dados). Se você precisar direcionar mais controle das operações transmitir, você pode acessar os filtros diretamente pelo COM interfaces. O Filter Graph Manager também passa notificações evento para o aplicativo, de forma que seu aplicativo pode responder a eventos, tais como o final de um transmitir.
Além disso, o Filter Graph Manager simplifica o processo de compilação um filtro gráfico. De exemplo, você pode especificar um nome arquivo e o será Filter Graph Manager compilar um gráfico para Play desse arquivo.


Etapas:

1. Listando dispositivos de áudio e vídeo

DSFilterInfo[][] dsi = DSCapture.queryDevices();

O dsj retornará um array multi-dimensional no qual o primeiro vetor [0][x] estarão todos os dispositivos de vídeo e no segundo [1][x] todos os dispositivos de áudio.

2. Para filtrar a busca para retornar somente os dispositivos de vídeo.

DSFilterInfo[][] dsiVideo = DSCapture.queryDevices(DSCapture.SKIP_AUDIO);

skip (skɪp): v. 1. saltar, pular. 2. to skip class matar aula (informal), to skip breakfast/lunch etc: não tomar café/não almoçar etc., 3. skip over: pular (um capítulo, uma parte, etc.), 4. skip rope: pular corda; s. pulo.

3. E para retornar somente os dispositivos de audio.

DSFilterInfo[][] dsiAudio = DSCapture.queryDevices(DSCapture.SKIP_VIDEO);

4. Feito a busca dos dispositivos, o próximo passo é iniciá-los

DSCapture graph = new DSCapture(DSFiltergraph.RENDER_NATIVE, dsi[0][0], false, null, this);

O código acima, instanciará a classe passando o primeiro dispositivo de vídeo, solicitando que não inicie com áudio e também não passa o canal de áudio para ser iniciado.

5. Para cada dispositivo retornado durante a busca, é possível ver com quais formatos estão disponíveis para que eles funcionem.

DSFilterInfo.DSPinInfo[] pins = graph.getActiveVideoDevice().getFilterInfo().getPins();
for(DSFilterInfo.DSPinInfo pin : pins) {
DSMediaType[] dSMediaTypes = pin.getFormats();
for(DSMediaType dSMediaType : dSMediaTypes) {
System.out.println(dSMediaType);
}
}

6. O código acima lista os formatos aceitos pelo dispositivo de vídeo que foi ativado. Para listar os formatos do dispositivo de audio, faça da seguinte forma:

DSFilterInfo.DSPinInfo[] pins = graph.getActiveAudioDevice().getFilterInfo().getPins();
for(DSFilterInfo.DSPinInfo pin : pins) {
DSMediaType[] dSMediaTypes = pin.getFormats();
for(DSMediaType dSMediaType : dSMediaTypes) {
System.out.println(dSMediaType);
}
}

7. E finalmente para escolher o formato a ser trabalhado com o dispositivo escolhido

//Para o dispositivo de vídeo
//onde indexVideo é o valor inteiro no qual o formato escolhido apareceu durante a listagem de formatos para o dispositivo de vídeo
dsi[0][video].setPreferredFormat(indexVideo);
//Para o dispositivo de audio
//onde indexAudio é o valor inteiro no qual o formato escolhido apareceu durante a listagem de formatos para o dispositivo de vídeo
dsi[1][audio].setPreferredFormat(indexAudio);

8. Após fazer a configuração inicial dos dispositivos de audio e vídeo, agora é hora de executar a gravação em arquivo. O formato que o arquivo será gerado é escolhido pela extensão do arquivo passado em setCaptureFile.

//Verifica se o dispositivo está no status PREVIEW
if (graph.getState() == DSCapture.PREVIEW) {
File f = new File("Video.asf");
graph.setCaptureFile(f.getAbsolutePath(), null, null, true);
graph.record();
//Se não estiver, muda o status atual para PREVIEW
} else {
graph.setPreview();
}

9. Para capturar uma foto da webcam.

ImageIO.write(graph.getImage(), "jpeg", new File(nome_arquivo))

10. Para desligar o dispositivo.

graph.dispose();

11. Caso queira configurar o dispositivo de forma mais fácil, o DSJ tem uma telinha de configuração já pronta, que busca todos os dispositivos, métodos de captura e formatos de gravação.

DSCapture graph = DSCapture.fromUserDialog(frame, DSFiltergraph.DD7, this);

12. Considerações

É muito importante que seja definido o formato padrão o qual o dispositivo irá fazer a manipulação da imagem ou vídeo. Caso isso não seja feito, é provável que ao parar a gravação e iniciá-la novamente, o novo arquivo gerado irá conter uma falha de gravação, uma aceleração quando reproduzido para ser mais exato.


Fluxos de mídia e Filtros, comentário em linguagem C, afim de enriquecer o assunto:

Fluxos de vídeo digitais são sequências de quadros de vídeo que podem ser não compactada ou bitmaps RGB, se o fluxo é comprimida, de um conjunto de valores numéricos que permitem que um descodificador para reconstruir a imagem final. O conteúdo exato dos dados variam de acordo com o formato de vídeo. Em todos os formatos de vídeo full-motion é tipicamente jogado para trás (renderizada) em cerca de 25 ou 30 quadros por segundo. Fluxos de áudio digital não comprimida consistir em sequências de amostras, cada um dos quais é um número inteiro que representa o quantizado (arredondada) de amplitude de um sinal analógico para um determinado ponto no tempo. Para qualidade de CD de áudio, as amostras têm uma precisão de 16 bits e são gravados e reproduzidos em 44,1 KHz. A stream de áudio comprimido não contém seqüências reais de amostras, mas, como acontece com streams de vídeo, contém valores o decodificador utiliza para reconstruir o fluxo original antes de passá-lo à placa de som.

Além de compressão e descompressão, que são realmente apenas um mal necessário neste mundo de armazenamento e largura de banda limitada, áudio digital e streams de vídeo podem ser processados ​​em variados e interessantes maneiras. Streams podem ser combinados, analisados ​​reorganizada, copiado, gerado, e modificado em maneiras que são impossíveis ou muito mais complexo do mundo analógico. E a riqueza da mídia digital está justamente nesse potencial aparentemente ilimitado para as operações de processamento de fluxo de todos os tipos.

No DirectShow, todas e quaisquer operações de fluxo são encapsulados como filtros, objetos que têm um comportamento padrão junto com o que as capacidades personalizados podem ser dadas. Arquivo leitores, desmultiplexadores, compressores e descompressores, prestadores de áudio e vídeo, até mesmo os drivers de dispositivo são filtros no sentido de que eles sabem como se comunicar com-e dados de fluxo a outros filtros.

Os aplicativos são construídos ligando esses filtros em conjunto para executar uma determinada tarefa.

Filtros vêm em três tipos básicos: filtros de origem para a entrada, filtros para transformar qualquer etapa de processamento intermediário e filtros de representantes para a saída.

Um filtro de fonte introduz dados no fluxo. Estes dados podem ser originários de um arquivo ou em um dispositivo, como uma câmera de vídeo, Web cam, sintonizador de TV, fluxo de rede, ou qualquer tipo de dispositivo existente ou ainda a ser inventado. DirectShow está intimamente ligado com o Windows Driver Model (WDM); qualquer dispositivo de mídia com um driver WDM corretamente implementado é automaticamente expostos a aplicativos em modo de usuário como um filtro DirectShow fonte, completo com tudo o que as interfaces o fornecedor de hardware expôs para permitir que aplicações para obter e defina as propriedades do dispositivo. DirectShow também fornece filtros de origem para inserção de dados de arquivos, de DVDs, e para dispositivos VFW.

Um filtro transformar, recebe dados de entrada de algum outro filtro, realizar alguma operação sobre os dados e, em seguida, passa os dados para outro a jusante do filtro. Transformações podem ser de análise de fluxos, a codificação ou decodificação, sobreposição de texto, ou qualquer tipo de análise ou manipulação do áudio ou pedaços de vídeo. DirectShow fornece muitas transformar filtros para lidar com vários formatos de compressão e arquivo, incluindo sinais de televisão analógica e digital.

Um filtro processador aceita dados de uma fonte ou transformar filtro e gera-lo para a tela, os alto-falantes, um arquivo, um dispositivo, ou algum outro local. O "Direct" no DirectShow reflete o fato de que os filtros de representantes utilizar as tecnologias DirectSound ® DirectDraw ® e para transmitir dados em gráficos e placas de som de forma eficiente. Além disso, suporta DirectShow capacidades de streaming de kernel, que permite que dispositivos de captura, como sintonizadores de TV e DVD para passar dados para os dispositivos de saída inteiramente em modo kernel para salvar à custa de transições de modo kernel para usuário em situações em que a aplicação não requer eles.

A divisão do trabalho em módulos de filtragem independentes, obviamente, maximiza a reutilização de código. Por exemplo, em qualquer cenário de reprodução de arquivos, haverá duas operações de leitura comum do fluxo de bytes do arquivo RAW e produzir os resultados finais para os gráficos e / ou placa de som. Não importa qual seja o formato de arquivo pode ser, você sempre pode usar os mesmos filtros DirectShow para realizar essas tarefas. Todas as mudanças que são os filtros intermédios.

Modelo de Aplicação

DirectShow é projetado para tornar a vida tão fácil quanto possível para os desenvolvedores e ainda dando-lhes a capacidade para controlar as operações de nível inferior, quando necessário. DirectShow simplifica o desenvolvimento, localizando praticamente todos os streaming de mídia e inteligência de processamento de filtros individuais, a principal tarefa de uma aplicação é fazer com que esses filtros trabalhando juntos. Para essa tarefa, os aplicativos usam um objeto de alto nível chamada Filter Graph Manager (FGM) para conectar filtros juntos em qualquer combinação é necessária para executar uma determinada tarefa, seja a reprodução simples ou tarefas mais complexas, como a conversão de formato, análise de vídeo , correção de cor, e assim por diante. O conjunto de filtros ligados é chamado um filtro gráfico. Os dados de um filtro gráfico move sempre a jusante do filtro para o processador de origem.

Você pode usar a FGM adicionar filtros individualmente, ou você pode usar a lógica Conexão inteligente construído na FGM para automatizar o processo de construção de gráfico. Usando o Intelligent Connect, você pode criar gráficos filtro complexas com apenas uma ou duas chamadas de método. Uma vez que o gráfico é construído, a aplicação controla a sua operação através de Run, Stop, e os métodos de pausa do FGM, que lida com os detalhes de sincronização de baixo nível. Os FGM relés eventos do filtro gráfico de volta para a aplicação.

DirectShow dá-lhe a capacidade de controlar as operações de streaming de nível inferior ao expor interfaces em filtros individuais. Normalmente, os aplicativos usam essas interfaces para configurar um filtro antes de streaming começa. Por exemplo, o filtro Encoder DV expõe a interface IDVEnc, que permite que um aplicativo para configurar vários parâmetros de codificação (como NTSC ou PAL) e as dimensões do retângulo de saída de vídeo.

Detecção de dispositivos disponíveis:

final DSFilterInfo [ ] [ ] dsi = DSCapture. queryDevices ( ) ;
for ( final DSFilterInfo [ ] dsFilterInfos : dsi )
{
for ( final DSFilterInfo dsFilterInfo : dsFilterInfos )
{
System . out . println ( dsFilterInfo. getName ( ) ) ;
}
}

Tire uma foto:

DSFilterInfo geraet = ... see above...
DSCapture graph = new DSCapture ( DSFiltergraph. DD7 , geraet, false , DSFilterInfo. doNotRender ( ) , this ) ;
graph. setPreferredSize ( new Dimension ( 640 , 480 ) ) ;
//The resolution must be set according to the abilties of the actual camera.
graph. setPreview ( ) ;
BufferedImage i = graph. getImage ( ) ;


Com DSJ é muito fácil criar um componente GUI para mostrar um preview da imagem da câmara:

DSFilterInfo geraet = ... see above...
DSCapture graph = new DSCapture ( DSFiltergraph. DD7 , geraet, false , DSFilterInfo. doNotRender ( ) , this ) ;
graph. setPreview ( ) ;
final Component component = graph. asComponent ( ) ; //java.awt.component
return component ;

Este componente AWT pode ser usado em cada GUI Java.


Exemplo:

A biblioteca dsj possui três demos, serão mostrados a execução da classe SimpleCapture e da classe DSJDemo, a figura abaixo mostra a estrutura de pastas da biblioteca dsj descompactada.

Abra o Eclipse JEE:

- Crie um projeto com o nome DSJava.
- Crie uma classe com o nome SimpleCapture e copie o código do demo (SimpleCapture) e cole nesta classe.
- Adicione a biblioteca dsj.jar no projeto:

Dê um clique com o botão direito no projeto (DSJava) > Build Path > Configure Build Path... > Libraries (aba) > Add External JARs... >C:\tomcat7\webapps\dsj

Neste exemplo a biblioteca DSJ foi descompactado em C:\tomcat7\webapps\dsj.
A figura abaixo mostra como ficou a estrutura do projeto.



Arquivo: SimpleCapture.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
48
50
51
52
53
54
55
56
57
58
59
60
61
62
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113


import de.humatic.dsj.*;


public class SimpleCapture implements java.beans.PropertyChangeListener {

    private DSCapture graph;

    public SimpleCapture() {}

    public void createGraph() {

        javax.swing.JFrame f = new javax.swing.JFrame("dsj SimpleCapture");

        /** queryDevices returns video device infos in slot 0 / audio device infos in slot 1 **/

        DSFilterInfo[][] dsi = DSCapture.queryDevices();

        /** this sample only uses video **/

        graph = new DSCapture(DSFiltergraph.DD7, dsi[0][0], false, DSFilterInfo.doNotRender(), this);

        f.add(java.awt.BorderLayout.CENTER, graph.asComponent());

        f.add(java.awt.BorderLayout.SOUTH, new SwingMovieController(graph));

        final javax.swing.JButton toFile = new javax.swing.JButton("set capture file");

        toFile.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent e) {

                if (graph.getState() == DSCapture.PREVIEW) {

                    /* capture to a Windows Media file using the default profile */

                    graph.setCaptureFile("captureTest.asf", DSFilterInfo.doNotRender(), DSFilterInfo.doNotRender(), true);

                    toFile.setText("set preview");

                    /* start recording right away. Outcomment to control this from GUI */

                    graph.record();

                } else {

                    graph.setPreview();

                    toFile.setText("set capture file");

                }

            }

        });

        f.add(java.awt.BorderLayout.NORTH, toFile);

        f.pack();

        f.setVisible(true);

        javax.swing.JFrame jf = new javax.swing.JFrame("Device control");

        jf.setLayout(new java.awt.GridLayout(0,1));

        if (graph.getActiveVideoDevice() != null && graph.getActiveVideoDevice().getControls() != null) {

            for (int i = CaptureDeviceControls.BRIGHTNESS; i < CaptureDeviceControls.LT_FINDFACE; i++) try {
                jf.add(graph.getActiveVideoDevice().getControls().getController(i, 0, true));
                }catch (Exception ex){}

        }

        if (graph.getActiveAudioDevice() != null) for (int i = CaptureDeviceControls.MASTER_VOL; i < CaptureDeviceControls.TREBLE; i++) try {
            jf.add(graph.getActiveAudioDevice().getControls().getController(i, 0, true));
            }catch (Exception ex){}

        if (jf.getContentPane().getComponentCount() == 0) return;

        jf.pack();

        jf.setVisible(true);

        /**
        Don't do this at home. This demo relies on dsj closing and disposing off filtergraphs when the JVM exits. This is
        OK for a "open graph, do something & exit" style demo, but real world applications should take care of calling
        dispose() on filtergraphs they're done with themselves.
        **/

        f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    }

    public void propertyChange(java.beans.PropertyChangeEvent pe) {

        switch(DSJUtils.getEventType(pe)) {

        }

    }

    public static void main(String[] args){

        new SimpleCapture().createGraph();

    }


}

Exeução: