gpt4 book ai didi

Delphi, TBitmap (rgb) 到 YCbCr 颜色格式

转载 作者:行者123 更新时间:2023-12-04 23:08:34 25 4
gpt4 key购买 nike

有一个来自 http://www.delphiffmpeg.com 的视频编码示例- 需要将一组TBitmaps转换成YCbCr(YUV),我们应该怎么做呢?该示例包含虚拟颜色:

  (* encode 1 second of video *)
idx := 1;
for i := 0 to 25 - 1 do
begin
av_init_packet(@pkt);
pkt.data := nil; // packet data will be allocated by the encoder
pkt.size := 0;

//fflush(stdout);
(* prepare a dummy image *)
(* Y *)
for y := 0 to c.height - 1 do
for x := 0 to c.width - 1 do
PByte(@PAnsiChar(frame.data[0])[y * frame.linesize[0] + x])^ := x + y + i * 3;

(* Cb and Cr *)
for y := 0 to c.height div 2 - 1 do
for x := 0 to c.width div 2 - 1 do
begin
PByte(@PAnsiChar(frame.data[1])[y * frame.linesize[1] + x])^ := 128 + y + i * 2;
PByte(@PAnsiChar(frame.data[2])[y * frame.linesize[2] + x])^ := 64 + x + i * 5;
end;

frame.pts := i;

(* encode the image *)
ret := avcodec_encode_video2(c, @pkt, frame, @got_output);
if ret < 0 then
begin
Writeln(ErrOutput, 'Error encoding frame');
ExitCode := 1;
Exit;
end;

if got_output <> 0 then
begin
Writeln(Format('Write frame %d (size=%d)', [idx, pkt.size]));
FileWrite(f, pkt.data^, pkt.size);
av_packet_unref(@pkt);
Inc(idx);
end;
end;

但是我们需要将位图转换为 YCbCr..而不是用虚拟图像填充像素。这是完整的源代码:
(*
* Video encoding example
*)
procedure video_encode_example(const filename: string; codec_id: TAVCodecID);
const
endcode: array[0..3] of Byte = ( 0, 0, 1, $b7 );
var
codec: PAVCodec;
c: PAVCodecContext;
idx, i, ret, x, y, got_output: Integer;
f: THandle;
frame: PAVFrame;
pkt: TAVPacket;
begin
Writeln(Format('Encode video file %s', [filename]));

(* find the mpeg1 video encoder *)
codec := avcodec_find_encoder(codec_id);
if not Assigned(codec) then
begin
Writeln(ErrOutput, 'Codec not found');
ExitCode := 1;
Exit;
end;

c := avcodec_alloc_context3(codec);
if not Assigned(c) then
begin
Writeln(ErrOutput, 'Could not allocate video codec context');
ExitCode := 1;
Exit;
end;

(* put sample parameters *)
c.bit_rate := 400000;
(* resolution must be a multiple of two *)
c.width := 352;
c.height := 288;
(* frames per second *)
c.time_base.num := 1;
c.time_base.den := 25;
(* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*)
c.gop_size := 10;
c.max_b_frames := 1;
c.pix_fmt := AV_PIX_FMT_YUV420P;

if codec_id = AV_CODEC_ID_H264 then
av_opt_set(c.priv_data, 'preset', 'slow', 0);

(* open it *)
if avcodec_open2(c, codec, nil) < 0 then
begin
Writeln(ErrOutput, 'Could not open codec');
ExitCode := 1;
Exit;
end;

f := FileCreate(filename);
if f = INVALID_HANDLE_VALUE then
begin
Writeln(ErrOutput, Format('Could not open %s', [filename]));
ExitCode := 1;
Exit;
end;

frame := av_frame_alloc();
if not Assigned(frame) then
begin
Writeln(ErrOutput, 'Could not allocate video frame');
ExitCode := 1;
Exit;
end;
frame.format := Ord(c.pix_fmt);
frame.width := c.width;
frame.height := c.height;

(* the image can be allocated by any means and av_image_alloc() is
* just the most convenient way if av_malloc() is to be used *)
ret := av_image_alloc(@frame.data[0], @frame.linesize[0], c.width, c.height,
c.pix_fmt, 32);
if ret < 0 then
begin
Writeln(ErrOutput, 'Could not allocate raw picture buffer');
ExitCode := 1;
Exit;
end;

(* encode 1 second of video *)
idx := 1;
for i := 0 to 25 - 1 do
begin
av_init_packet(@pkt);
pkt.data := nil; // packet data will be allocated by the encoder
pkt.size := 0;

//fflush(stdout);
(* prepare a dummy image *)
(* Y *)
for y := 0 to c.height - 1 do
for x := 0 to c.width - 1 do
PByte(@PAnsiChar(frame.data[0])[y * frame.linesize[0] + x])^ := x + y + i * 3;

(* Cb and Cr *)
for y := 0 to c.height div 2 - 1 do
for x := 0 to c.width div 2 - 1 do
begin
PByte(@PAnsiChar(frame.data[1])[y * frame.linesize[1] + x])^ := 128 + y + i * 2;
PByte(@PAnsiChar(frame.data[2])[y * frame.linesize[2] + x])^ := 64 + x + i * 5;
end;

frame.pts := i;

(* encode the image *)
ret := avcodec_encode_video2(c, @pkt, frame, @got_output);
if ret < 0 then
begin
Writeln(ErrOutput, 'Error encoding frame');
ExitCode := 1;
Exit;
end;

if got_output <> 0 then
begin
Writeln(Format('Write frame %d (size=%d)', [idx, pkt.size]));
FileWrite(f, pkt.data^, pkt.size);
av_packet_unref(@pkt);
Inc(idx);
end;
end;

(* get the delayed frames *)
repeat
//fflush(stdout);

ret := avcodec_encode_video2(c, @pkt, nil, @got_output);
if ret < 0 then
begin
Writeln(ErrOutput, 'Error encoding frame');
ExitCode := 1;
Exit;
end;

if got_output <> 0 then
begin
Writeln(Format('Write frame %d (size=%d)', [idx, pkt.size]));
FileWrite(f, pkt.data^, pkt.size);
av_packet_unref(@pkt);
Inc(idx);
end;
until got_output = 0;

(* add sequence end code to have a real mpeg file *)
FileWrite(f, endcode[0], SizeOf(endcode));
FileClose(f);

avcodec_close(c);
av_free(c);
av_freep(@frame.data[0]);
av_frame_free(@frame);
Writeln('');
end;

是的,我们知道这个公式,但是我们应该如何处理 (* Cb and Cr *) 循环到 c.height div 2 - 1 和 c.width div 2 - 1 ?我们所有的实验都制作了正确的图像几何形状但颜色不正确......这是我们所拥有的:
( Y )
for y := 0 to c.height - 1 do
begin
Line := image.ScanLine[y];
for x := 0 to c.width - 1 do
begin
Yy := Round(Line[x].R*0.29900 + Line[x].G*0.58700 + Line[x].B*0.11400);
PByte(@PAnsiChar(frame.data[0])[y * frame.linesize[0] + x])^ := Yy;
end;
end;
( Cb and Cr )
for y := 0 to c.height div 2 - 1 do
begin
Pixels := image.ScanLine[y];
for x := 0 to c.width div 2 - 1 do
begin
Cb := Round(Line[x].R -0.16874 - Line[x].G 0.33126 + Line[x].B * 0.50000) + 128;
Cr := Round(Line[x].R 0.50000 - Line[x].G 0.41869 - Line[x].B * 0.08131) + 64;
PByte(@PAnsiChar(frame.data[1])[y * frame.linesize[1] + x])^ := Cr;
PByte(@PAnsiChar(frame.data[2])[y * frame.linesize[2] + x])^ := Cb;
//PByte(@PAnsiChar(frame.data[1])[y frame.linesize[1] + x])^ := 128 + y + i 2;
//PByte(@PAnsiChar(frame.data[2])[y frame.linesize[2] + x])^ := 64 + x + i 5;
end;
end;

这应该如何解决?

最佳答案

不难找到 RGB-YCbCr 转换的公式:

Y  = R *  0.29900 + G *  0.58700 + B *  0.11400
Cb = R * -0.16874 + G * -0.33126 + B * 0.50000 + 128
Cr = R * 0.50000 + G * -0.41869 + B * -0.08131 + 128

它已准备好在代码中实现。使用 Scanline用于快速访问每个像素的 R、G、B 分量的属性

关于Delphi, TBitmap (rgb) 到 YCbCr 颜色格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44659567/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com