Registriert seit: 11. Aug 2007
357 Beiträge
|
AW: YUV2 unter Firemonkey
4. Dez 2017, 13:02
Stimmt, ich denke wir reden etwas aneinander vorbei:
Delphi-Quellcode:
vertices[0] := vr.left;
vertices[1] := vr.bottom;
vertices[2] := vr.right;
vertices[3] := vr.bottom;
vertices[4] := vr.left;
vertices[5] := vr.top;
vertices[6] := vr.right;
vertices[7] := vr.top;
texcoords[0] := tr.left;
texcoords[1] := tr.bottom;
texcoords[2] := tr.right;
texcoords[3] := tr.bottom;
texcoords[4] := tr.left;
texcoords[5] := tr.top;
texcoords[6] := tr.right;
texcoords[7] := tr.top;
if FProgram = 0 then
LoadShader;
glUseProgram(FProgram);
glUniformMatrix4fv(FuniformMatrix, 1, GLboolean(0), @FModelviewProj);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture.Handle);
glUniform1i(FUniformSamplers[0], 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Texture.UHandle);
glUniform1i(FUniformSamplers[1], 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, Texture.VHandle);
glUniform1i(FUniformSamplers[2], 2);
glVertexAttribPointer(ATTRIBUTE_VERTEX, 2, GL_FLOAT,
{$IFDEF MSWINDOWS}false{$ELSE}0{$ENDIF}, 0, @vertices);
glEnableVertexAttribArray(ATTRIBUTE_VERTEX);
glVertexAttribPointer(ATTRIBUTE_TEXCOORD, 2, GL_FLOAT,
{$IFDEF MSWINDOWS}false{$ELSE}0{$ENDIF}, 0, @texcoords);
glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glUseProgram(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
...
function LoadShader: Boolean;
var
vertShader, fragShader: GLUInt;
status: GLint;
begin
result := false;
if not FInitialized then
exit;
if FProgram <> 0 then // Already Loaded
begin
result := true;
exit;
end;
vertShader := 0;
fragShader := 0;
FProgram := glCreateProgram();
try
vertShader := compileShader(GL_VERTEX_SHADER, vertexShaderString);
if vertShader = 0 then
exit;
fragShader := compileShader(GL_FRAGMENT_SHADER, fragmentShaderString);
if fragShader = 0 then
exit;
glAttachShader(FProgram, vertShader);
glAttachShader(FProgram, fragShader);
glBindAttribLocation(FProgram, ATTRIBUTE_VERTEX, 'position');
glBindAttribLocation(FProgram, ATTRIBUTE_TEXCOORD, 'texcoord');
glLinkProgram(FProgram);
glGetProgramiv(FProgram, GL_LINK_STATUS, @status);
if status = 0 then
exit;
result := validateProgram(FProgram);
FuniformMatrix := glGetUniformLocation(FProgram,
'modelViewProjectionMatrix');
FUniformSamplers[0] := glGetUniformLocation(FProgram, 's_texture_y');
FUniformSamplers[1] := glGetUniformLocation(FProgram, 's_texture_u');
FUniformSamplers[2] := glGetUniformLocation(FProgram, 's_texture_v');
finally
glDeleteShader(vertShader);
glDeleteShader(fragShader);
if not result then
begin
glDeleteProgram(FProgram);
FProgram := 0;
end;
end;
end;
Im Prinzip machst du nichts anderes als das du 3 Texturen für Y, U und die V Werte hast und diese in der GPU mittels eines Shaders direkt im Grafikspeicher in RGB umwandelst. Du kannst das ganze auch so wie du vorschlagen willst machen:
Delphi-Quellcode:
const
YUV_FIX2 = 6;
YUV_MASK2 = (256 shl YUV_FIX2) - 1;
function MultHi(const v, coeff: integer): integer; inline;
begin
result := (v * coeff) shr 8;
end;
function VP8Clip8(const v: integer): Byte; inline;
begin
if (v and not YUV_MASK2) = 0 then
result := v shr YUV_FIX2
else if v < 0 then
result := 0
else
result := 255;
end;
function VP8YUVToR(const y, v: integer): Byte; inline;
begin
result := VP8Clip8(MultHi(y, 19077) + MultHi(v, 26149) - 14234);
end;
function VP8YUVToG(const y, u, v: integer): Byte; inline;
begin
result := VP8Clip8(MultHi(y, 19077) - MultHi(u, 6419) - MultHi(v,
13320) + 8708);
end;
function VP8YUVToB(const y, u: integer): Byte; inline;
begin
result := VP8Clip8(MultHi(y, 19077) + MultHi(u, 33050) - 17685);
end;
procedure VP8YuvToRgb(y, u, v: integer; argb: PCardinal); inline;
begin
argb^ := $FF000000 or VP8YUVToR(y, v) shl 16 or VP8YUVToG(y, u, v) shl 8 or
VP8YUVToB(y, u);
end;
type
TPacket = record
srcY, srcU, srcV: PByte;
LineSize: Array [0 .. 2] of integer;
end;
procedure copyYuv(Packet: TPacket; Bitmap: TBitmap); overload;
var
x, y: integer;
ptr: PByte;
dst: PCardinal;
Data: TBitmapData;
begin
Bitmap.Map(TMapAccess.Write, Data);
try
ptr := Data.Data;
with Packet do
for y := 0 to Bitmap.height - 1 do
begin
dst := PCardinal(ptr);
for x := 0 to Bitmap.width - 1 do
begin
VP8YuvToRgb(srcY[x], srcU[x shr 1], srcV[x shr 1], dst);
inc(dst);
end;
inc(srcY, LineSize[0]);
inc(ptr, Data.Pitch);
if ((y + 1) mod 2) = 0 then
begin
inc(srcU, LineSize[1]);
inc(srcV, LineSize[2]);
end;
end;
finally
Bitmap.Unmap(Data);
end;
end;
Wie ich aber schon im Eingangspost erwähnt habe ist das auf mobilen Geräten nicht gangbar. Die Umwandlung bei einem 1080i Bild ist mit 25fps nicht realisierbar.
Die einzige Alternative für mich wäre das mit einem, so wie ich das bei Firemonkey verstanden habe soll das ja gehen, GPU unterstützten TFilter zu machen. Das ganze würde dann zwar auch bedeuten, dass du was in der GPU warst wieder in eine Bitmap schiebst, aber es ist denke ich schneller, als die Umwandlung mittels CPU.
|