Programando vídeo para Windows por E. J. Bantz, tradução: David M. Machado
Passo 1 - Criando uma nova janela
Passo 2 - Conectando a janela
Passando Strings para a função SendMessage
Passando Estruturas para a função SendMessage
Processando Imagens de Stream de Vídeo
Passo
1 - Criando uma nova janela
O processo de captura
de vídeo começa com a função capCreateCaptureWindowA. Quando
chamada, esta função retorna um handle(identificador) para a nova janela. O
handle(identificador) é um número de 32-bits que é usado para referenciar um
objeto (neste caso, uma janela). Este handle(identificador)
é o fundamento para o restante do seu programa, e deve ser mantido em um local
seguro.
Você pode customizar o visual desta nova janela mudando os parâmetros de estilo. Neste exemplo, a janela será Child(filha, ou seja, ela abre dentro da janela principal e recebe seus atributos) e visível após a criação.
lwndC = capCreateCaptureWindowA("My Capture Window", WS_CHILD Or WS_VISIBLE, 0, 0, 160, 120, Me.hwnd, 0)
Todos os comandos
futuros serão emitidos enviando-se uma Mensagem parametrizada para aquela nova
janela. A mensagem parametrizada é enviada com a função SendMessage
que é pertecente às APIs padrões do Win32. Você passa para esta função:
1 - O handle(identificador) da janela que você gostaria de enviar a mensagem;
2 - O comando;
3 - A mensagem de 32-bits;
4 - O parâmetro de 16-bits;
5 - E finalmente o parâmetro de 32-bits.
As mensagens de 32-bits são trocadas por uma constante de fácil entendimento.
Todas as mensagens usadas pela captura de vídeo estão definidas dentro do módulo
VBAVICAP.BAS.
PS: A palavra mensagem neste caso, representa uma conversa do programa com a API de modo que eles possam se entender/comunicar.
Passo 2 - Conectando a janela
Uma vez que a janela
de captura é criada, você pode conectar a janela ao driver de vídeo. O driver
de vídeo é instalado juntamente com sua câmera de vídeo. A conexão é feita com
a mensagem WM_CAP_DRIVER_CONNECT. Isto irá "preencher"
a janela com o primeiro driver de vídeo encontrado (índice 0). Tenha em mente
que poderia enviar esta mensagem para qualquer janela, mas somente esta janela
especialmente criada com a capCreateCaptureWindow
entenderá o que você está falando.
SendMessage lwnd, WM_CAP_DRIVER_CONNECT, 0, 0
O módulo VBAVICAP.BAS providencia funções para tornar o envio destas mensagens um pouco mais simples. Fazer uma chamada é exatamente como o demonstrado abaixo:
capDriverConnect lwnd, 0
As funções são usadas ao invés da SendMessage para evitar confusão da ordem de qual parâmetro são passados. Você deve sempre usar as funções disponibilizadas ao invés de SendMessage.
Passando
Strings para a função SendMessage
A API SendMessage é sempre chamada passando-se 4 coisas:
1 - Um handle(identificador) de janela (hwnd);
2 - Alguma mensagem para enviar à esta janela (wMsg);
3 - Um curto parâmetro (wParam) - 16-bits.
4 - E um longo parâmetro (lParam) - 32-bits.
O w no wParam representa "WORD(palavra)" e o l no
lParam representa "LONG". WORD e LONG são tipos de
dados da linguagem C. Uma WORD é um número de 16bits, e um LONG é um número
de 32bits. No VB, Eles são chamados repectivamente de INTEGER e LONG. A declaração
se parece com isso:
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Long) As Long
Para passar uma string para esta função, você precisa redefinir lParam para String ao invés de Long. Agora, tenha em mente que enviar informações de tipos incorretos à DLL causaria grandes problemas. Normalmente, enviamos para a função exatamente o que ela espera. Veja você, em Visual Basic, quando você passa uma STRING usando byval para um função externa, enviará um ponteiro indicando a localização dessa STRING.
Um ponteiro é um número de 32bits, do tipo LONGO, com o que é esperado. Então deveríamos passar o tipo correto de dados, antes de tudo. Uma coisa mais, não podemos apenas mudar a declaração de SendMessage pois alguns chamadas NECESSITAM que lParam seja LONG. Então, você pode apenas criar uma nova declaração e chamá-la de algo ligeiramente diferente. Aqui está a nova declaração:
Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As String) As Long
Passando Estruturas para
a função SendMessage
Estruturas (Tipos
definidos pelo usuário) não são diretamente passadas para as funções. A passagem
de estrutura é um pouco mais simples que a passagem de strings. Desta vez, ao
invés de deixar o Visual Basic passar o ponteiro para você, faça isto você mesmo.
VARPTR() é uma função construtora que retornará a localização
na memória (um ponteiro) onde a variável que você passou está armazenada. Em
nosso caso, a variável será um User Defined Type(Tipo definido
pelo usuário/estrutura). Novamente, um ponteiro é um número de 32bits, ou LONG,
o qual nós podemos passar como lParam.
Aqui está um rápido exemplo de como obter os parâmetros de captura.
Dim CAP_PARAMS As CAPTUREPARMS
capCaptureGetSetup lwndC, VarPtr(CAP_PARAMS), Len(CAP_PARAMS)
Processando Imagens de Stream de Vídeo
A questão mais comum
que tenho recebido é, "Como eu pego os dados durante a captura de streaming
de vídeo?" A resposta está nas funções de chamadas de retorno (call back
functions). Use
capSetCallbackonFrame
para processar os quadros durante a visualização, e capSetCallbackOnVideoStream
para processar quadros durante a captura. Aqui está um exemplo:
capSetCallbackOnFrame lwndC, AddressOf MyFrameCallback
MyFrameCallback é uma função que você criou para sua aplicação. Deve estar localizada em um módulo não em um formulário. Esta será a função que será chamada toda vez que um novo quadro for recebido do driver de vídeo. Esta passa a identificação (handle) do VIDEOHDR o qual deve ser declarado da seguinte forma:
Type VIDEOHDR
lpData As Long '// Endereço do buffer de vídeo
dwBufferLength As Long '// tamanho, em bytes, do buffer de dados
dwBytesUsed As Long '// veja abaixo
dwTimeCaptured As Long '// veja abaixo
dwUser As Long '// dados específicos do usuário
dwFlags As Long '// veja abaixo
dwReserved(3) As Long '// reservado; não useEnd Type
lpData é o dado atual do dispositivo. Você terá de manipular a estrutura do VIDEOHDR para obter-lo. Aqui está algum um exemplo de código para copiar a estrutura da memória em uma estrutura(User Defined Type) real do Visual Basic.
Function MyFrameCallback(ByVal lwnd As Long, ByVal lpVHdr As Long) As Long
Debug.Print "FrameCallBack"
Dim VideoHeader As VIDEOHDR
Dim VideoData() As Byte
'//Preenche o cabeçalho de vídeo(VideoHeader) com os dados de lpVHdr
RtlMoveMemory VarPtr(VideoHeader), lpVHdr, Len(VideoHeader)
'// Reserva espaço para os dados
ReDim VideoData(VideoHeader.dwBytesUsed)
'//Copia os dados no array(vetor)
RtlMoveMemory VarPtr(VideoData(0)), VideoHeader.lpData, VideoHeader.dwBytesUsed
Debug.Print VideoHeader.dwBytesUsed
Debug.Print VideoDataEnd Function
Neste exemplo, RtlMoveMemory deve ser declarado como a seguir:
Declare Sub RtlMoveMemory Lib "kernel32" (ByVal hpvDest As Long, ByVal hpvSource As Long, ByVal cbCopy As Long)
Última Atualização: 21/07/02
E. J. Bantz
http://ej.bantz.com
ej@bantz.com
davidmachado@gmail.com
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? |
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Super DVD C# - Recursos de aprendizagens e vídeo aulas para C#
Curso Fundamentos da Programação Orientada a Objetos com VB .NET