DirectShow - obraz z kilku zrodel do jednego pliku, jak?

0

Witam,

Temat daje do nietuzinkowych, bo dotyczy dość zaawansowanego programowania. Rzecz dotyczy pobierania obrazu z kamery.

To, co musze zrobic to pobrac obraz z 2 kamer i zapisac wynik do jednego pliku (np. ekran podzielony pionowo na 2 części).

O ile z samym pobraniem obrazu z kamery, jak tez i z kontrolowaniem zawartosci ekranu na podgladzie/w zapisanym wyniku specjalnych trudnosci nie mam (kwestia odpowiedniego uzycia interfejsow IGraphBuilder, ICaptureGraphBuilder2 oraz ISampleGrabber), to problem jest w tym jak pobrac obraz z kilku zrodel jednoczesnie i jak to "wrzucic" do ISampleGrabber chociazby...

Jak sie to w ogole robi?

I jeszcze jedno pytanko - mam urzadzenie typu DVR (czyli przejsciowka 3xCAM -> USB). W sterowniku tego urzadzenia jest dialog ustawien, gdzie moge wybrac uzywane aktualnie wejscie (czyli z ktorej kamery czytac obraz).

To jest ok, ale problem pojawia sie, gdy:

  • chce programowo wybrac uzywane wejscie (na tym etapie musze wyswietlic dialog ustawien sterownika i wyklikac to - to mi nie pasuje).
  • chce pobierac obraz z kilku kamer jednoczesnie (tak jak pisalem na poczatku mojego posta - tyle ze jedno urzadzenie). Problem w tym, ze aktywne jest tylko jedno wejscie - jak czytac z kilku?
    Czy da sie to osiagnac poprzez manipulowanie pinami urzadzenia (jak?).

Nie zdziwie sie, jezeli nikt nie bedzie znal odopwiedzi (bo pewnie malo kto sie tym zajmowal), jezeli tak to moze znacie jakies dobre forum programistow DirectX?

Dodam, ze w sieci jest pelno przykladow jak pobierac obraz z kamery, ale brak takich, ktore ilustruja to co chce osiagnac... :/

0

A nie ma jakichś gotowych filtrów multipleksujących? Szukałeś coś pod tym kątem? Jeśli nie ma nic gotowego, to podejrzewam, że zostaje pisanie własnego filtru.

Ewentualnie może filtr VMR będzie potrafił coś takiego.

Daj znać jak znajdziesz odpowiedź, sam jestem ciekaw.

0

Hmm jest avi mux http://msdn2.microsoft.com/en-us/library/ms779633(VS.85).aspx, teoretrycznie sie nada - zobaczymy co z tego wyjdzie

Znalazlem jeszcze cos takiego:
http://medialooks-video-mixer.medialooks.qarchive.org/_download2.html

No ale to z kolei płatne..

0

AviSynth ?

0

Jeżeli chcesz przykleić "bokiem" obraz z kilku kamer, to nie widzę nic prostszego jak kopiowanie bitów do częsci odpowiednio dużej bitmapy DIB

// g_cam1bits - pointer do bitów bitmapy DIB o rozmiarze camera1.video.size
// cam1bitslen - rozmiar sekcji DIB dla kamery 1
// g_cam1Hdc - tu siedzi bitmapa dla kamery 1
// g_bigHdc - tu siedzi odpowiednio duża bitmapa DIB która ma zmieścić obraz ze wszystkich kamer
void camera1OnFrame(VIDEOHDR *hdr)
{
   MoveMemory(g_cam1bits, hdr->lpData, g_cam1bitslen); // skopiuj do małej HBITMAP
   BitBlt(g_bigHdc, lewy górny róg, g_cam1Hdc, 0, 0) // z małej do dużej
}
void camera2OnFrame(VIDEOHDR *hdr)
{
   MoveMemory(g_cam2bits, hdr->lpData, g_cam2bitslen);
   BitBlt(g_bigHdc, lewy dolny róg, g_cam2Hdc, 0, 0)
}

Lub też w pętli for{} skopiuj bity bezpośrednio z VIDEOHDR do dużej bitmapy.
Akurat posiadam tylko jedną kamerkę więc nie mam jak sprawdzić.

0

@sapero

Mozesz napisac troche wiecej? Akurat w DX nie mam duzego doswiadczenia, a jest mi to cholernie potrzebne. Dokladnie chodzi mi o to, co to za funkcje void camera1OnFrame(VIDEOHDR *hdr) i void camera2OnFrame(VIDEOHDR *hdr) ?

Czy to na pewno korzysta z DirectShow a nie vfw? W DirectShow wiem tylko jak skorzystac z interfejsu ISampleGrabber - tak robie np. nakładanie logo na wideo:

int ISampleGrabberCB.BufferCB( double SampleTime, IntPtr pBuffer, int BufferLen )
        {
            lock (this)
            {
                if (m_bmdLogo != null)
                {
                    IntPtr ipSource = m_bmdLogo.Scan0;
                    IntPtr ipDest = pBuffer;

                    for (int x=0; x < m_bmdLogo.Height; x++)
                    {
                        CopyMemory(ipDest, ipSource, (uint)m_bmdLogo.Stride);
                        ipDest = (IntPtr)(ipDest.ToInt32() + m_stride);
                        ipSource = (IntPtr)(ipSource.ToInt32() + m_bmdLogo.Stride);
                    }
                }
            }

            return 0;

Czyli: mamy sobie jakies logo w bitmapce i w callabacku wrzucamy je na przechwytywany obraz. Wszystko jest ok, dopoki jest to statyczna bitmapa, ale chcac zamiast tego dac obraz z drugiej kamerki, zamiast m_bmdLogo musze dac pbuffer z drugiej kamery i to odpowiednio zmiejszony.

Wiec probowalbym tak:
Czyli w callbacku pierwszej kamery zmniejszam bitmape pBuffer, w drugiej analogicznie i zapisuje to do 2 skladowych klasy, przykladowo cam1_bmp i cam2_bmp - to sie da zrobic. Wtedy w tych dwoch zmiennych mialbym zmieniajace sie przeskalowane obrazy z kazdej kamery.

Tylko jest jeden problem - w ktorym momencie i gdzie wrzucac to na jedna duza bitmape i jak spowodowac, zeby ta bitmapa byla "traktowana jak wynik"? Do dwoch kamer musze miec chyba dwa interfejsy CaptureGraphBuilder, a trzeci zdefiniowac do zapisu? Tylko ze trzeci CaptureGraphBuilder nie mialby urzadzenia wejsciowego, a zamiast tego trzeba mu przekazac dane z mojej wynikowej bitmapy (a konkretnie do FlieWritera) - jak to zrobic?

Sory ze tak sie rozpisuje, ale temat nie jest trywialny... jezeli zle mysle to jak inaczej moge to zrealizowac?

Co do uzycia zewnetrznych filtrow - korzystam z nieoficjalnego portu DirectShow do C# (bo oficjalnego nie ma) i cos mi sie wydaje, ze ta biblioteka nie wsystko wspiera - i chyba nie ma wlasnie mozliwosci dodania dowolnego zainstalowanego w systemu filtra DirectShow :|

1 użytkowników online, w tym zalogowanych: 0, gości: 1