Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Aug 05, 2021 21:54

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 5 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: PBitmap --> Textur
BeitragVerfasst: Mi Apr 21, 2021 21:22 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 67
Hallo,
ich habe mal wieder ein kompliziertes Anliegen, und vor allem: keine Ahnung von der Materie.

Ich verwende Delphi 10.4.2 mit der aktuellen Version von dglOpenGL und glBitmap.

Aufgabe: Zeichne den Frame eines Videos als Textur.

Über die Demo-Version von FFMPEG http://www.delphiffmpeg.com kann ich z.B. mit der TFFDecoder-Komponente mir die einzelnen Frames meiner .mp4-Datei holen:

Code:
  1. var
  2.   bmp: Graphics.TBitmap;
  3.   bmp32: TBitmap32;
  4. begin
  5.   FFDecoder.Decode;
  6.  
  7.   bmp := graphics.TBitmap.create;
  8.   FFDecoder.CopyToBitmap(bmp);
  9.  
  10.   bmp32 := TBitmap32.Create;
  11.   bmp32.Assign(bmp);
  12.  
  13.   FTextur.LoadFromBitmap32(bmp32);
  14.  
  15.   FreeAndNil(bmp);
  16.   FreeAndNil(bmp32);
  17.  


In diesem Beispiel hole ich mir den Frame über CopyToBitmap. In "bmp" ist dann schon alles gespeichert, was ich brauche. Jetzt noch einmal in TBitmap32 umwandeln (wenn ich die Textur mit TBitmap erstellen will, ist nix zu sehen??), das wird dann intern nochmal auf PowerOf2 vergrößert und dann hochgeladen, danach gerendet. Geht auch alles soweit.

Problem: Mit meiner Tech-Demo (Rendern alle 30ms über Timer) habe ich auf meinem High-End-System eine stete Prozessorlast von 25%, auf den PCs der potentiellen Kunden > 60%. Laut Support liegt das daran, das die Umwandlung in TBitmap sehr rechenaufwändig ist. Die reine "Player"-Demo vom Hersteller braucht ~ 2% Auslastung, was vollkommen okay wäre.

Zitat:
And CurrentFrame() will cost much more CPU for calculation. FFPlayer reads packets and decodes to YUV frames and then renders YUV frames via SDL. CurrentFrame() is just a convenience for Delphi to use TBitmap. YUV2RGB takes a lot of calculation. To CurrentFrame() is slow. And assigning a Bitmap to a Image also costs much more time then rendering YUV directly. (Hier ist zwar der FFPlayer genannt, nicht der o.g. FFDecoder, aber das Problem ist das gleiche.)


Da FFMpeg ja eh schon alles mit SDL darstellt, kann ich nicht irgendwie auf diese Textur oder "diesen Arbeitsspeicherbereich" zugreifen und das selbe Bild, was der Player rendert nochmal bei mir rendern lassen? Kann ich irgendwie die Textur-ID rausbekommen oder sowas? Verwendet mein Programm SDL? Keine Ahnung! Ich denke nicht. Ich kenne SDL nicht, habe nur schon mal davon gehört...

Der FFDecoder bietet "FFDecoder.GetBitmapPtr", was ein PBitmap zurück gibt. Kann man damit etwas anfangen? Ich bekomme zum Thema PBitmap + Delphi partout auch über Google nichts sinnvolles raus, und habe keine Ahnung, wie ich mit glBitmap oder notfalls nativ dglOpenGL daraus eine Textur erzeugen kann. Wahrscheinlich ist das nur ein Handle auf ein TBitmap, und es würde keinen Geschwindigkeitsvorteil bringen, selbst wenn ich darauf zugreifen könnte? Oder doch?
Edit: Habe mittlerweile herausgefunden, dass ich über
Code:
  1.   bmp := graphics.TBitmap.create;
  2.   Bmp.Handle := CreateBitmapIndirect(ffdecoder.GetBitmapPtr^);
  3.   bmp.PixelFormat := pf32bit;
  4.   FTextur.LoadFromBitmap(bmp);

Auf den Frame als Bitmap zugreifen kann. Dürfte aber letztendlich nichts anderes sein, als CurrentFrame(), was ja auch bei TBitmap zurück gibt. Von der Geschwindigkeit/Auslastung bringt es leider keine Besserung.

Der Support meint weiter:
Zitat:
Or use FFDecoder.FrameInfo.Picture to access the original decoded frames.

FFDecoder.FrameInfo.Picture ist vom Typ TAvPicture https://ffmpeg.org/doxygen/4.0/structAVPicture.html und bietet die Eigenschaften
Code:
  1. data: array[0..7] of Pbyte
  2. linesize: array[0..7] of integer

Ich habe absolut keine Ahnung, wie ich da irgendwelche Daten draus entnehmen soll.
Edit: Hier: https://stackoverflow.com/questions/30218922/ffmpeg-how-to-get-yuv-data-from-avframe-and-draw-it-using-opengl erhalte ich diesen Code-Schnippsel:
Code:
  1. glPixelStorei(GL_UNPACK_ROW_LENGTH,  FFDecoder.FrameInfo.Picture.linesize[0]);
  2. glActiveTexture(GL_TEXTURE0 + FTextur.id);
  3. glBindTexture(GL_TEXTURE_2D, FTextur.id);
  4. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, FFDecoder.FrameInfo.width, FFDecoder.FrameInfo.Height,
  5.              0, GL_LUMINANCE, GL_UNSIGNED_BYTE, FFDecoder.FrameInfo.Picture.data[0]);
  6.  

Dort heißt es weiter:
Zitat:
Upload data[1] and [2] in the same way but apply chroma subsamplings to width/height (e.g. uvwidth = (width + 1) >> 1). This code also assumes that you've created 3 textures in an array called texture[]. In your drawing loop, you can then refer to these texture ids to link them to uniform textures in your shaders, which you eventually use to draw. Shader examples that do YUV-to-RGB conversion can be found virtually anywhere.

Ich soll also drei Texturen erzeugen (wie auch immer sich dann die parameter unterscheiden sollen...) und dann in jedem Rendervorgang alle drei Texturen zeichnen... In welchem Blend/Wie-auch-Immer-Modus. Kann hier jemand mit einem Codebeispiel aushelfen?

Vorschläge?
Danke im Voraus!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: PBitmap --> Textur
BeitragVerfasst: Do Apr 22, 2021 11:55 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Ich weiß nicht, ob es hilft.
Hier habe ich mal was zu TBitmap32 und glBitmap gemacht:
https://delphigl.com/forum/viewtopic.php?f=14&t=7457&p=100076&hilit=glbitmap#p100074


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: PBitmap --> Textur
BeitragVerfasst: Do Apr 22, 2021 12:08 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Zitat:
Jetzt noch einmal in TBitmap32 umwandeln (wenn ich die Textur mit TBitmap erstellen will, ist nix zu sehen??), das wird dann intern nochmal auf PowerOf2 vergrößert und dann hochgeladen, danach gerendet. Geht auch alles soweit.

Warum Du das von TBitmap in TBitmap32 umwandelst verstehe ich nicht so ganz. Das wird aber auch kein Problem sein.

Könnte es aber auch sein, dass Deine PowerOf2 Vergrößerung sehr viel Prozessorlast kostet?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: PBitmap --> Textur
BeitragVerfasst: Do Apr 22, 2021 12:25 
Offline
DGL Member

Registriert: Mo Jul 17, 2006 13:16
Beiträge: 67
> Warum Du das von TBitmap in TBitmap32 umwandelst verstehe ich nicht so ganz.
Das war nur ein kurzer Workaround, weil mein LoadFromBitmap() (ohne 32) kurzzeitig nicht funktioniert hatte, ist aber ein internes Problem und hat in der Tat nichts hiermit zu tun. Einfach ignorieren.

PowerOf2 erstellt einfach nur ein neues TBitmap(32) und in der Größe PowerOf2(Width bzw. Height) und zeichnet das Bild drauf, das kostet aber auch keine Zeit.

Was aktuell am meisten interessiert:
Mit der oben im Edit verlinkten Seite: https://stackoverflow.com/questions/302 ... ing-opengl könnte ich ggf. direkt auf den Frame zugreifen. Aber ich schaffe es nicht, das in eine sinnvolle Renderanweisung umzuwandeln...


Hier ist noch ein Beispiel wie man den Frame in eine Textur bekommt, aber die verwenden SDL. Und ich wüsste wieder nicht, was ich alles mit SDL machen müsste (initialisieren, cleanup etc.), nur um diesen einen Frame so auszuwerten, dass ich ihn in OpenGL rendern kann...
Code:
  1. function TForm1.queue_picture(var is_: PVideoState; pFrame: PAVFrame; pts: double): integer;
  2. var
  3.   vp    : PVideoPicture;
  4.   pict  : TAVPicture;
  5.   event : TDataMessage;
  6.  
  7. begin
  8.  
  9.   (* wait until we have space for a new pic *)
  10.   SDL_LockMutex(is_.pictq_mutex);
  11.   try
  12.     while ((is_.pictq_size >= VIDEO_PICTURE_QUEUE_SIZE) and (not is_.quit)) do
  13.     begin
  14.       SDL_CondWait(is_.pictq_cond, is_.pictq_mutex);
  15.     end;
  16.   finally
  17.     SDL_UnlockMutex(is_.pictq_mutex);
  18.   end;
  19.  
  20.   if (is_.quit) then
  21.   begin
  22.     result:=-1;
  23.     exit;
  24.   end;
  25.  
  26.   // windex is set to 0 initially
  27.   vp := @is_.pictq[is_.pictq_windex];
  28.  
  29.   (* allocate or resize the buffer! *)
  30.   if ((not assigned(vp.bmp)) or
  31.      (vp.width <> is_.video_st.codec.width) or
  32.      (vp.height <> is_.video_st.codec.height)) then
  33.   begin
  34.  
  35.  
  36.     vp.allocated := 0;
  37.  
  38.  
  39.     (* we have to do it in the main thread *)
  40.     event.Msg:=FF_ALLOC_EVENT;
  41.     event.Data:=Pointer(is_);
  42.     self.Dispatch(event);
  43.  
  44.     (* wait until we have a picture allocated *)
  45.     SDL_LockMutex(is_.pictq_mutex);
  46.     try
  47.       while ((vp.allocated=0) and (not is_.quit)) do
  48.       begin
  49.         SDL_CondWait(is_.pictq_cond, is_.pictq_mutex);
  50.       end;
  51.     finally
  52.       SDL_UnlockMutex(is_.pictq_mutex);
  53.     end;
  54.  
  55.     if (is_.quit) then
  56.     begin
  57.       result:=-1;
  58.       exit;
  59.     end;
  60.   end;
  61.   (* We have a place to put our picture on the queue *)
  62.   (* If we are skipping a frame, do we set this to null
  63.      but still return vp->allocated = 1? *)
  64.  
  65.   if assigned(vp.bmp) then
  66.   begin
  67.  
  68.  
  69.     pict.data[0] := vp.pFrameYUV420P.data[0];
  70.     pict.data[1] := vp.pFrameYUV420P.data[2];
  71.     pict.data[2] := vp.pFrameYUV420P.data[1];
  72.  
  73.     pict.linesize[0] := vp.pFrameYUV420P.linesize[0];
  74.     pict.linesize[1] := vp.pFrameYUV420P.linesize[2];
  75.     pict.linesize[2] := vp.pFrameYUV420P.linesize[1];
  76.  
  77.  
  78.     // Convert the image into YUV format that SDL uses
  79.     sws_scale
  80.     (
  81.     is_.sws_ctx,
  82.     @pFrame.data,
  83.     @pFrame.linesize,
  84.     0,
  85.     is_.video_st.codec.height,
  86.     @pict.data,
  87.     @pict.linesize
  88.     );
  89.  
  90.  
  91.     SDL_UpdateTexture(vp.bmp, nil, vp.buffer, is_.video_st.codec.width);
  92.  
  93.     vp.pts := pts;
  94.  
  95.     (* now we inform our display thread that we have a pic ready *)
  96.     inc(is_.pictq_windex);
  97.     if(is_.pictq_windex = VIDEO_PICTURE_QUEUE_SIZE) then
  98.       is_.pictq_windex := 0;
  99.  
  100.     SDL_LockMutex(is_.pictq_mutex);
  101.     try
  102.       inc(is_.pictq_size);
  103.     finally
  104.       SDL_UnlockMutex(is_.pictq_mutex);
  105.     end;
  106.   end;
  107.   result:=0;
  108. end;


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: PBitmap --> Textur
BeitragVerfasst: Do Apr 22, 2021 14:30 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Genaues kann ich Dir da nicht sagen. Ich weiß auch nicht, was Du da gerade alles benutzt.
Aber.. glBitmap von Bergmann hat da ein :
LoadFromFunc(..) in der Klasse TglBitmapData
damit könnte Deine Sache vllt gelöst werden.

Zitat:
FFDecoder.FrameInfo.Picture ist vom Typ TAvPicture https://ffmpeg.org/doxygen/4.0/structAVPicture.html und bietet die Eigenschaften
Wenn ich das dort im Link richtig verstehe, dann ist die Methode deprecated.

Diese "PowerOf2 Vergrößerung" , setzt Du nur ein Bitmap in ein anderes ein oder vergrößerst Du es bzw ziehst Du es groß?


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 5 Beiträge ] 
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: Google [Bot] und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.039s | 18 Queries | GZIP : On ]