YUV420P用SDL显示问题.

cp1982 2014-02-07 10:42:57
代码如下,显示出来一个大概的图像,应该是YUV数据的Y显示了,但是出来的效果是花屏的,有没有大神指点一二.

unit testUnit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,sdl;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses
avformat, avcodec, avutil, mem, swscale;

{$R *.dfm}
var
packet: TAVPacket;
bytesRemaining: integer = 0;
rawData: PByte;
fFirstTime: boolean = true;
pOverlay : PSDL_Overlay;
surface : PSDL_Surface;
rect : TSDL_Rect;

procedure mem_copy( src, dest : PUint8; src_width, dest_width : word; lines : word );
var
c : word;
begin
for c := 1 to lines do
begin
move( src^, dest^, src_width );
inc( src, src_width );
inc( dest, dest_width );
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
filename = 'd:\mp4.mp4';
// filename = 'd:\1.avi';
//filename = 'D:\MyTestAll_ffmpeg_sdl\MyTestAll\vs\MyTestAll\mp4.mp4';
//D:\MyTestAll_ffmpeg_sdl\MyTestAll\vs\MyTestAll
var
pAVFCtx: PAVFormatContext;
pCodecCtx: PAVCodecContext;
pCodec: PAVCodec;
pFrame,pFrameRGB: PAVFrame;
pScaleCtx: PSwsContext;
pitch : PUInt16;
plane : PPUInt8;

i, videoStream,hasVideo: integer;
picture:TAVPicture;
f,w,h:integer;
begin
av_register_all();
if SDL_Init( SDL_INIT_VIDEO or SDL_INIT_AUDIO or SDL_INIT_TIMER ) > 0 then
raise exception.Create ( 'yp_init_sdl: SDL_Init failed' );

if av_open_input_file ( pAVFCtx, filename, nil, 0, nil ) <> 0 then
raise exception.Create ( 'WTF?! Couldn''t open file!!!' );

if av_find_stream_info ( pAVFCtx ) < 0 then
raise exception.Create ( 'WTF?! Couldn''t find stream information!!!' );

dump_format ( pAVFCtx, 0, filename, 0 );

videoStream := -1;
for i := 0 to pAVFCtx.nb_streams - 1 do
begin
if pAVFCtx.streams [i].codec.codec_type = CODEC_TYPE_VIDEO then
begin
videoStream := i;
break;
end;
end;

if videoStream = -1 then
raise exception.Create ( 'WTF?! Didn''t find a video stream!' );

pCodecCtx := pAVFCtx.streams [videoStream].codec;

pCodec := avcodec_find_decoder ( pCodecCtx.codec_id );
if pCodec = nil then
raise exception.Create ( 'WTF?! Codec not found!' );

if ( pCodec.capabilities and CODEC_CAP_TRUNCATED ) = CODEC_CAP_TRUNCATED then
pCodecCtx.flags := pCodecCtx.flags or CODEC_FLAG_TRUNCATED;

if avcodec_open ( pCodecCtx, pCodec ) < 0 then
raise exception.Create ( 'WTF?! Could not open codec!' );

surface := SDL_SetVideoMode( pCodecCtx.width, pCodecCtx.height, 0, 0 );
if surface = nil then
raise exception.Create ( 'yp_init_sdl: SDL_SetVideoMode failed' );

pOverlay := SDL_CreateYUVOverlay(pCodecCtx.width, pCodecCtx.height, SDL_YV12_OVERLAY, surface);
if pOverlay = nil then
raise exception.Create ( 'yp_init_sdl: SDL_CreateYUVOverlay failed' );
pFrame := avcodec_alloc_frame();
pFrameRGB:= avcodec_alloc_frame();
avpicture_alloc (PAVPicture(pFrameRGB), PIX_FMT_YUV420P, pCodecCtx.width, pCodecCtx.height );
// fillchar(picture,sizeof(picture),0);
while(av_read_frame(pAVFCtx, @packet)=0) do
begin
if packet.stream_index=videoStream then
begin
avcodec_decode_video(pCodecCtx, pFrame, @hasVideo, packet.data, packet.size );
if hasVideo<>0 then
begin
SDL_LockYUVOverlay(pOverlay);
pScaleCtx := sws_getContext ( pCodecCtx.width, pCodecCtx.height, pCodecCtx.pix_fmt,
pCodecCtx.width, pCodecCtx.height, PIX_FMT_RGB32, SWS_BICUBIC, nil, nil, nil );
sws_scale ( pScaleCtx, @pFrame.data, @pFrame.linesize,0, pCodecCtx.height,@pFrameRGB.data, @pFrameRGB.linesize );
pitch := poverlay^.pitches; //set to first pitch
plane := PPUInt8( poverlay^.pixels ); //set to first plane
mem_copy( PUInt8(pFrameRGB.data[0]), plane^, pCodecCtx.width, pitch^, pCodecCtx.height ); //copy y plane to overlay
inc( pitch ); //next pitch
inc( plane ); //next plane
mem_copy( PUInt8(pFrameRGB.data[1]), plane^, pCodecCtx.width div 4, pitch^, pCodecCtx.height div 4 ); //copy
inc( pitch );
inc( plane );
mem_copy( PUInt8(pFrameRGB.data[2]), plane^, pCodecCtx.width div 4, pitch^, pCodecCtx.height div 4 );
// // CopyMemory ( bmp.ScanLine [i], pointer (integer (pFrameRGB.data [0]) + bmp.Width * 4 * i), bmp.Width * 4 );
//CopyMemory ( @poverlay^.pixels, pointer (integer (pFrameRGB.data [0])), pCodecCtx.height );
SDL_UnlockYUVOverlay( pOverlay );
rect.x := 0;
rect.y := 0;
rect.h := pCodecCtx.height;
rect.w := pCodecCtx.width ;
SDL_DisplayYUVOverlay( pOverlay, @rect );
end;
end;
end;
av_free ( pFrame );
avcodec_close ( pCodecCtx );
av_close_input_file ( pAVFCtx );
sws_freeContext ( pScaleCtx );
end;
end.
...全文
968 6 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
leejunokokok 2014-06-12
  • 打赏
  • 举报
回复
引用 5 楼 fang098 的回复:
先贴下你的ffmpeg版本,SDL是可以直接显示yuv数据的,去找一个能显示的YUV数据, 再用楼主显示YUV数据的处理方式看看, 看了下楼主的显示处理,感觉是你的UV分量处理有问题, mem_copy( PUInt8(pFrameRGB.data[1]), plane^, pCodecCtx.width div 4, pitch^, pCodecCtx.height div 4 ); //copy inc( pitch ); inc( plane ); mem_copy( PUInt8(pFrameRGB.data[2]), plane^, pCodecCtx.width div 4, pitch^, pCodecCtx.height
嗯 ,赞同
fang 2014-06-11
  • 打赏
  • 举报
回复
先贴下你的ffmpeg版本,SDL是可以直接显示yuv数据的,去找一个能显示的YUV数据, 再用楼主显示YUV数据的处理方式看看, 看了下楼主的显示处理,感觉是你的UV分量处理有问题, mem_copy( PUInt8(pFrameRGB.data[1]), plane^, pCodecCtx.width div 4, pitch^, pCodecCtx.height div 4 ); //copy inc( pitch ); inc( plane ); mem_copy( PUInt8(pFrameRGB.data[2]), plane^, pCodecCtx.width div 4, pitch^, pCodecCtx.height
wangzongze1015 2014-03-07
  • 打赏
  • 举报
回复
引用 3 楼 cp1982 的回复:
做播放器,现在用的方案是FFMPEG+SDL,图像出来了,但是花屏了一部分,静态图像正常,主要是动态图像显示花掉了
我也采用的是这样的方式,花屏的话除了自己找到问题了,但还是效果不理想,还是有点花屏 sws_getContext ( pCodecCtx.width, pCodecCtx.height, pCodecCtx.pix_fmt,pCodecCtx.width, pCodecCtx.height, PIX_FMT_RGB32, SWS_BICUBIC, nil, nil, nil );这句要改为sws_getContext ( pCodecCtx.width, pCodecCtx.height, pCodecCtx.pix_fmt, pCodecCtx.width, pCodecCtx.height, PIX_FMT_YUV420P, SWS_BICUBIC, nil, nil, nil );还有你用的ffmpeg是哪个版本的?我换成最新的版本就没有花屏的出现了
cp1982 2014-02-08
  • 打赏
  • 举报
回复
做播放器,现在用的方案是FFMPEG+SDL,图像出来了,但是花屏了一部分,静态图像正常,主要是动态图像显示花掉了
sololie 2014-02-07
  • 打赏
  • 举报
回复
做手游么? 还没玩过sdl
cp1982 2014-02-07
  • 打赏
  • 举报
回复
自己找到问题了,但还是效果不理想,还是有点花屏 sws_getContext ( pCodecCtx.width, pCodecCtx.height, pCodecCtx.pix_fmt,pCodecCtx.width, pCodecCtx.height, PIX_FMT_RGB32, SWS_BICUBIC, nil, nil, nil );这句要改为sws_getContext ( pCodecCtx.width, pCodecCtx.height, pCodecCtx.pix_fmt, pCodecCtx.width, pCodecCtx.height, PIX_FMT_YUV420P, SWS_BICUBIC, nil, nil, nil );

1,185

社区成员

发帖
与我相关
我的任务
社区描述
Delphi GAME,图形处理/多媒体
社区管理员
  • GAME,图形处理/多媒体社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧