2017-07-06 3 views
-1

J'essaie de mettre en place un simple lecteur vidéo pour les vidéos stockées au format RAW. Ces vidéos sont éventuellement transmises via un filtre de convolution. Ma classe CWinApp a trois méthodes pertinentes. Tout d'abord, lorsqu'une vidéo est sélectionnée et placée dans le pointeur viewingVideo, j'allouer deux bitmaps:Scintillement sur lecteur vidéo bitmap

void CMyApp::setBitmaps() { 
    if (viewingVideo == NULL) 
     return; 


    bmp1 = CreateDIBSection(dc, viewingVideo->bmi, DIB_RGB_COLORS, NULL, NULL, 0); 
    bmp2 = CreateDIBSection(dc, viewingVideo->bmi, DIB_RGB_COLORS, NULL, NULL, 0); 
} 

Puis, lors de la lecture l'utilisateur appuie, j'initialiser minuteries qui appellent les deux méthodes suivantes jamais 33 ms, 30 images par seconde lecture:

void CMyApp::updateVideoFrame() { 
    if (viewingVideo == NULL) 
     return; 

    if (viewingKernel != NULL) { 
     applyKernelFFT(viewingKernel, viewingVideo, currentFrame); 
    } 

    if (viewingKernel == NULL) 
     SetDIBits(dc, bmpToggle ? bmp2 : bmp1, 0, viewingVideo->height, (char*)(viewingVideo->data) + currentFrame*viewingVideo->bpp*viewingVideo->width*viewingVideo->height, viewingVideo->bmi, DIB_RGB_COLORS); 
    else 
     SetDIBits(dc, bmpToggle ? bmp2 : bmp1, 0, viewingVideo->height, (char*)(viewingVideo->filtered_data), viewingVideo->bmi, DIB_RGB_COLORS); 
    bmpToggle = !bmpToggle; 
} 

void CMyApp::updateVideoScreen() { 
    CMyView* view = CMyView::GetView(); //returns the active view 
    view->m_Video.SetBitmap(bmpToggle ? bmp1 : bmp2); 
    CRect update; 
    view->m_Video.GetWindowRect(&update); 
    view->ScreenToClient(&update); 
    //update.DeflateRect(update.Width()/2-1, update.Height()/2 - 1); 
    InvalidateRect(*AfxGetMainWnd(), update, FALSE); 
} 

À un moment donné, les méthodes devraient utiliser différentes bitmaps. Il y a pas mal de scintillement sur l'écran lorsque je démarre ces minuteries. Lorsque je décommente l'appel DeflateRect, ce qui rend update un rectangle de 2x2 pixels, il devient clair qu'il existe deux sources de scintillement: parfois l'image entière scintille, et parfois seulement le rectangle 2x2 au centre.

J'ai essayé les correctifs courants suggérés par ailleurs, comme la transmission de WM_ERASEBKGND dans CMyView. Cela n'a pas aidé. Comment puis-je empêcher ce scintillement?

+0

Et à quoi ressemble votre gestionnaire WM_PAINT? –

+0

Peut-être que c'est le problème, je ne gère pas actuellement WM_PAINT. Ai-je besoin d'un double tampon? Si oui, quelle est la bonne façon de le faire dans MFC? – srossd

+0

Vous invalidez la fenêtre principale dans updateVideoScreen, qui va déclencher un WM_PAINT. J'ai supposé que c'est à ce moment-là que l'on écrirait le bitmap à l'écran. –

Répondre

0

Pour tous ceux qui veulent supprimer l'avertissement d'épilepsie de leur logiciel, voici ce qu'il a fallu pour corriger le scintillement. La suggestion d'Adrian McCarthy était exactement exacte. Dans updateVideoScreen, j'ai remplacé view->m_Video.SetBitmap(bmpToggle ? bmp1 : bmp2); avec SelectObject(dc, bmpToggle ? bmp1 : bmp2);, de sorte que les données bitmap est envoyé à ma mémoire DC et non au contrôle. Ensuite, je l'emporterait sur OnPaint() appeler BitBlt pour écrire le bitmap à l'écran où le contrôle vidéo aurait été:

void CMTFBoostView::OnPaint() 
{ 
    CRect rect; 
    m_Video.GetWindowRect(&rect); 
    ScreenToClient(&rect); 

    video* v = ((CMTFBoostApp*)AfxGetApp())->viewingVideo; 
    CDC* src = ((CMTFBoostApp*)AfxGetApp())->cdc; 

    CDC* dc = GetDC(); 
    if (v != NULL && dc->RectVisible(rect)) { 
     dc->BitBlt(rect.left, rect.top, v->width, v->height, src, 0, 0, SRCCOPY); 
    } 
    ReleaseDC(dc); 
    CFormView::OnPaint(); 
} 

Les premières lignes sont un peu un hack pour mettre la vidéo où je l'avais avant - il serait probablement plus propre à supprimer complètement le contrôle CStatic de la vue. Peu importe, cela affiche la vidéo sans scintillement.

+0

Quelle est la raison pour laquelle vous n'utilisez pas CPaintDC dans votre gestionnaire OnPaint? – IInspectable

+0

Il n'y a pas de raison particulière - peut-être qu'un 'CPaintDC' serait sémantiquement plus correct, ou juste une meilleure pratique. Plus important encore, j'ai oublié d'appeler 'ReleaseDC (dc)', ce qui a causé des problèmes après l'affichage de plusieurs milliers d'images. J'ai modifié le code avec ce changement. – srossd

+0

L'utilisation d'un 'CPaintDC' n'est pas seulement sémantiquement plus correcte. C'est fonctionnellement correct. Le fait de ne pas utiliser 'CPaintDC' échoue à valider la région invalide, provoquant la génération d'un flux constant de messages' WM_PAINT' superflus. En outre, votre code mis à jour ne compile pas. L'appel à 'ReleaseDC' est en dehors du corps de la fonction. S'il vous plaît ne pas poster de faux code. – IInspectable