Pergunta

Gostaria de abrir um pequeno arquivo de vídeo e mapear todos os quadros da memória (para aplicar algum filtro personalizado).Não quero lidar com o codec de vídeo, prefiro deixar a biblioteca cuidar disso para mim.

Tentei usar o Direct Show com o filtro SampleGrabber (usando este exemplo http://msdn.microsoft.com/en-us/library/ms787867(VS.85).aspx), mas só consegui capturar alguns frames (não todos os frames!).Sou muito novo em programação de software de vídeo, talvez não esteja usando a melhor biblioteca ou esteja fazendo errado.

Colei uma parte do meu código (principalmente um copiar/colar modificado do exemplo do msdn), infelizmente ele não captura os 25 primeiros frames como esperado...

[...]

hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE);

pControl->Run(); // Run the graph.
pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done.

// Find the required buffer size.
long cbBuffer = 0;
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);

for( int i = 0 ; i < 25 ; ++i )
{
    pControl->Run(); // Run the graph.
    pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done.

    char *pBuffer = new char[cbBuffer];
    hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);

    AM_MEDIA_TYPE mt;
    hr = pGrabber->GetConnectedMediaType(&mt);
    VIDEOINFOHEADER *pVih;
    pVih = (VIDEOINFOHEADER*)mt.pbFormat;

    [...]
}

[...]

Existe alguém com experiência em software de vídeo que possa me aconselhar sobre código ou outra biblioteca mais simples?

Obrigado

Editar:Os links do Msdn parecem não funcionar (veja o bug)

Foi útil?

Solução

Atualmente estes são os frameworks de vídeo mais populares disponíveis em plataformas Win32:

  1. Vídeo para Windows:estrutura antiga do Windows proveniente da era Win95, mas ainda amplamente utilizada porque é muito simples de usar.Infelizmente, ele suporta apenas arquivos AVI para os quais o codec VFW adequado foi instalado.

  2. DirectShow:estrutura WinXP padrão, ele pode basicamente carregar todos os formatos que você pode reproduzir com o Windows Media Player.Bastante difícil de usar.

  3. Ffmpeg:mais precisamente libavcodec e libavformat que vem com o utilitário multimídia de código aberto Ffmpeg.É extremamente poderoso e pode ler muitos formatos (quase tudo com que você pode brincar VLC) mesmo se você não tiver o codec instalado no sistema.É bastante complicado de usar, mas você sempre pode se inspirar no código do ffplay que vem com ele ou em outras implementações em software de código aberto.De qualquer forma, acho que ainda é muito mais fácil de usar que o DS (e muito mais rápido).Precisa ser compilado pelo MinGW no Windows, mas todos os passos estão muito bem explicados aqui (neste momento o link está fora do ar, espero que não esteja morto).

  4. Tempo rápido:o framework Apple não é a melhor solução para a plataforma Windows, pois necessita da instalação do aplicativo QuickTime e também do codec QuickTime adequado para cada formato;ele não suporta muitos formatos, mas é bastante comum no campo profissional (portanto, alguns codecs são, na verdade, apenas para QuickTime).Não deve ser muito difícil de implementar.

  5. Gstreamer:mais recente estrutura de código aberto.Não sei muito sobre isso, acho que envolve alguns dos outros sistemas (mas não tenho certeza).

Todos esses frameworks foram implementados como backend no OpenCv Highgui, exceto DirectShow.O framework padrão para Win32 OpenCV está usando VFW (e portanto capaz apenas de abrir alguns arquivos AVI), se você quiser usar os outros você deve baixar o CVS em vez do lançamento oficial e ainda hackear o código e de qualquer maneira não é muito completo, por exemplo, o backend do FFMPEG não permite buscar no stream.Se você quiser usar QuickTime com OpenCV esse pode ajudá-lo.

Outras dicas

Eu tenho usado OpenCV para carregar arquivos de vídeo e processá-los.Também é útil para muitos tipos de processamento de vídeo, incluindo aqueles úteis para visão computacional.

Usar o modelo "Callback" do SampleGrabber pode fornecer melhores resultados.Veja o exemplo em Samples\C++\DirectShow\Editing\GrabBitmaps.

Também há muitas informações em Samples\C++\DirectShow\Filters\Grabber2\grabber_text.txt e readme.txt.

Eu sei que é muito tentador em C++ obter uma análise adequada dos arquivos de vídeo e fazer você mesmo.Mas, embora as informações estejam disponíveis, é um processo tão demorado criar classes para lidar com cada formato de arquivo e torná-lo facilmente alterável para levar em consideração futuras mudanças na estrutura, que francamente não vale a pena o esforço.

Em vez disso, recomendo o ffmpeg.Teve uma menção acima, mas diz que é difícil, não é difícil.Há muito mais opções do que a maioria das pessoas precisaria, o que faz com que pareça mais difícil do que é.Para a maioria das operações, você pode simplesmente deixar o ffmpeg resolver isso sozinho.

Por exemplo, uma conversão de arquivo ffmpeg -i inputFile.mp4 outputFile.avi

Decida desde o início que as operações ffmpeg serão executadas em um thread ou, mais precisamente, em uma biblioteca de threads.Mas tenha sua própria classe de thread para que você possa ter seus próprios EventAgs e métodos para verificar se o thread foi concluído.Algo como :-

ThreadLibManager()
{
  List<MyThreads> listOfActiveThreads;
  public AddThread(MyThreads);
}
Your thread class is something like:-
class MyThread
{
 public Thread threadForThisInstance { get; set; }
 public MyFFMpegTools mpegTools { get; set; }
}
MyFFMpegTools performs many different video operations, so you want your own event  
args to tell your parent code precisely what type of operation has just raised and 
event.
enum MyFmpegArgs
{
public int thisThreadID { get; set; } //Set as a new MyThread is added to the List<>
public MyFfmpegType operationType {get; set;}
//output paths etc that the parent handler will need to find output files
}
enum MyFfmpegType
{
  FF_CONVERTFILE = 0, FF_CREATETHUMBNAIL, FF_EXTRACTFRAMES ...
}

Aqui está um pequeno trecho da minha classe de ferramenta ffmpeg, esta parte coletando informações sobre um vídeo.Coloquei o FFmpeg em um local específico e, no início do software em execução, ele garante que esteja lá.Para esta versão, mudei-o para a área de trabalho, tenho quase certeza de que escrevi o caminho corretamente para você (eu realmente odeio o sistema de pastas especiais da MS, então o ignoro tanto quanto posso).

De qualquer forma, é um exemplo de uso do ffmpeg sem janelas.

        public string GetVideoInfo(FileInfo fi)
    {
        outputBuilder.Clear();
        string strCommand = string.Concat(" -i \"", fi.FullName, "\"");
        string ffPath =   
  System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\ffmpeg.exe";
        string oStr = "";

        try
        {
            Process build = new Process();
            //build.StartInfo.WorkingDirectory = @"dir";
            build.StartInfo.Arguments = strCommand;
            build.StartInfo.FileName = ffPath;

            build.StartInfo.UseShellExecute = false;
            build.StartInfo.RedirectStandardOutput = true;
            build.StartInfo.RedirectStandardError = true;
            build.StartInfo.CreateNoWindow = true;
            build.ErrorDataReceived += build_ErrorDataReceived;
            build.OutputDataReceived += build_ErrorDataReceived;
            build.EnableRaisingEvents = true;
            build.Start();
            build.BeginOutputReadLine();
            build.BeginErrorReadLine();
            build.WaitForExit();


            string findThis = "start";
            int offset = 0;
            foreach (string str in outputBuilder)
            {
                if (str.Contains("Duration"))
                {
                    offset = str.IndexOf(findThis);
                    oStr = str.Substring(0, offset);
                }
            }
        }
        catch
        {
            oStr = "Error collecting file information";
        }

        return oStr;
    }
    private void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        string strMessage = e.Data;
        if (outputBuilder != null && strMessage != null)
        {
            outputBuilder.Add(string.Concat(strMessage, "\n"));
        }
    } 

Tente usar o OpenCV biblioteca.Definitivamente tem os recursos que você precisa.

Este guia tem uma seção sobre como acessar quadros de um arquivo de vídeo.

Se for para arquivos AVI, eu mesmo leria os dados do arquivo AVI e extrairia os quadros.Agora use o gerenciador de compactação de vídeo para descompactá-lo.

O formato do arquivo AVI é bem simples, veja: http://msdn.microsoft.com/en-us/library/dd318187(VS.85).aspx (e use o Google).

Depois de abrir o arquivo, basta extrair cada quadro e passá-lo para ICDecompress() para descompactá-lo.

Parece muito trabalhoso, mas é a maneira mais confiável.

Se isso for muito trabalhoso ou se você quiser mais do que arquivos AVI, use o ffmpeg.

OpenCV é a melhor solução se o vídeo no seu caso precisar apenas levar a uma sequência de imagens.Se você deseja fazer processamento de vídeo real, então ViDeo é igual a "Áudio Visual", você precisa acompanhar os oferecidos por "martjno".Novas soluções Windows também para Win7 incluem 3 novas possibilidades adicionais:

  1. Fundação Windows Media:Sucessor do DirectShow;interface limpa
  2. Codificador do Windows Media 9:Não inclui apenas o programa, também fornece bibliotecas para codificação
  3. Expressão do Windows 4:Sucessor de 2.

As duas últimas são soluções apenas comerciais, mas a primeira é gratuita.Para codificar o WMF, você precisa instalar o SDK do Windows.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top