Procedure ExitX;
begin
WriteLN(' ');
WriteLN('-----ERROR-------------');
WriteLN('Press any key to Exit...');
ReadLN;
Halt(0);
end;
function alloc_avframe(pix_fmt: AVPixelFormat; width, height: integer): PAVFrame;
var
picture: PAVFrame;
picture_buf: PByte;
size: integer;
begin
Result := nil;
picture := av_frame_alloc();
if (picture = nil) then
Exit;
size := av_image_get_buffer_size(pix_fmt, width, height, 1);
picture_buf := av_malloc(size);
if (picture_buf = nil) then
begin
av_frame_free(picture);
Exit;
end;
av_image_fill_arrays(@picture^.data[0], @picture^.linesize[0], picture_buf, pix_fmt, width, height, 1);
Result := picture;
end;
libSDL2_Load(curDir + SDL_LibName);
If libSDL2_IsLoaded = False Then
Begin
WriteLn('Unable to Load SDL2 Library');
ExitX;
End;
FLoaderFFmpeg := TLoaderFFmpeg.Create(Nil);
FLoaderFFmpeg.Active := true;
If (FLoaderFFmpeg.IslibavCodec_Loaded = False) Or
(FLoaderFFmpeg.IslibavDevice_Loaded = False) Then
Begin
WriteLn('Unable to Load libavCodec Library');
ExitX;
End;
Try
av_register_all();
avformat_network_init();
pFormatCtx:=avformat_alloc_context();
// Open video file
pFormatCtx := avformat_alloc_context();
err := avformat_open_input(pFormatCtx, PAnsiChar(filename), Nil, xoptions);
If (err < 0) Then
Begin
WriteLn('ffmpeg: Unable to open input file');
ExitX;
End;
// Retrieve stream information
err := avformat_find_stream_info(pFormatCtx, xoptions);
If (err < 0) Then
Begin
WriteLn('ffmpeg: Unable to find stream info');
ExitX;
End;
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, PAnsiChar(filename), 0);
// Find the first video stream
videoStream:=-1;
For i := 0 To pFormatCtx^.nb_streams - 1 Do
If (pFormatCtx^.streams^[i].codec^.codec_type = AVMEDIA_TYPE_VIDEO) Then
begin
videoStream:=i;
break;
end;
If (videoStream <0) Then
Begin
WriteLn('ffmpeg: Unable to find video stream');
ExitX;
End;
// Get a pointer to the codec context for the video stream
pCodecCtx := pFormatCtx^.streams^[videoStream].codec;
// Find the decoder for the video stream
pCodec := Nil;
pCodec := avcodec_find_decoder(pCodecCtx^.codec_id);
if pCodec=nil then
begin
WriteLn('Unsupported codec!');
ExitX;
end;
// Open codec
err := avcodec_open2(pCodecCtx, pCodec, Nil);
If (err < 0) Then
Begin
WriteLn('ffmpeg: Unable to open codec');
ExitX;
End;
sdlWindow := SDL_CreateWindow('demo', 0, 0, pCodecCtx^.width, pCodecCtx^.height, SDL_WINDOW_OPENGL);
sdlRenderer := SDL_CreateRenderer(sdlWindow, -1, 0);
sdlTexture := SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pCodecCtx^.width, pCodecCtx^.height);
img_convert_context := sws_getCachedContext(
Nil,
pCodecCtx^.width,
pCodecCtx^.height,
AVPixelFormat(pCodecCtx^.pix_fmt),
pCodecCtx^.width,
pCodecCtx^.height,
AVPixelFormat(AV_PIX_FMT_YUV420P),
SWS_BICUBIC,
Nil, Nil, Nil);
If (img_convert_context = Nil) Then
Begin
WriteLn('Cannot initialize the conversion context');
ExitX;
End;
frame := av_frame_alloc();
pFrameYUV420P := alloc_avframe(AV_PIX_FMT_YUV420P, pCodecCtx^.width, pcodecctx^.height);
While (av_read_frame(pFormatCtx, packet) >= 0) Do
Begin
If (packet.stream_index = videoStream) Then
Begin
avcodec_decode_video2(pCodecCtx, frame, frame_finished, @packet);
If (frame_finished <> 0) Then
Begin
sws_scale(img_convert_context, @frame^.data, @frame^.linesize, 0, pCodecCtx^.height, @pFrameYUV420P^.data[0], @pFrameYUV420P^.linesize[0]);
SDL_UpdateTexture(sdlTexture, nil, pFrameYUV420P^.data[0], pFrameYUV420P^.linesize[0]);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, nil, nil);
SDL_RenderPresent(sdlRenderer);
End;
End;
av_packet_unref(packet);
End;
sws_freeContext(img_convert_context);
av_free(frame);
avcodec_close(pCodecCtx);
avformat_close_input(pFormatCtx);
avformat_network_deinit;
SDL_QUIT();
Except
On E: Exception Do
WriteLn(E.ClassName, ': ', E.Message);
End;
FLoaderFFmpeg.free;
WriteLN(' ');
WriteLN('Press any key to Exit...');
ReadLN;
End.
运行环境如题,详细如图。简单的调用ffmpeg 动态库解码1080P h264文件,结果解码每帧要40-70毫秒,正常应该是10毫秒左右。
同样的机器,同样的ffmpeg库和调用逻辑,换做qt creator就效率正常。求助各位,看有哪些因素导致。谢谢。
后附主要代码。解码函数avcodec_decode_video2耗时40-70毫秒。
Program ffmpeg_sample_player;
Uses
//Windows,
SysUtils,
Classes,
libSDL2,
ffmpeg_loader,
ffmpeg_types,
libavcodec,
libavdevice,
libavfilter,
libavformat,
libavutil,
libpostproc,
libswresample,
libswscale;
Var
err: Integer;
filename: AnsiString;
pFormatCtx: pAVFormatContext = Nil;
pCodecCtx: pAVCodecContext;
pCodec: pAVCodec;
screen: pSDL_Surface;
//bmp: pSDL_Overlay;
sdlWindow: PSDL_Window;
sdlRenderer: PSDL_Renderer;
sdlTexture: PSDL_Texture;
img_convert_context: pSwsContext;
frame: pAVFrame;
pFrameYUV420P: pAVFrame;
packet: AVPacket;
frame_finished: Integer;
pict: AVPicture;
rect: TSDL_Rect;
event: TSDL_Event;
FLoaderFFmpeg: TLoaderFFmpeg;
i,videoStream:Integer;
xoptions: pAVDictionary = nil;
curDir: string;
h264File: THandle;
itick: cardinal;
Procedure ExitX;
begin
WriteLN(' ');
WriteLN('-----ERROR-------------');
WriteLN('Press any key to Exit...');
ReadLN;
Halt(0);
end;
function alloc_avframe(pix_fmt: AVPixelFormat; width, height: integer): PAVFrame;
var
picture: PAVFrame;
picture_buf: PByte;
size: integer;
begin
Result := nil;
picture := av_frame_alloc();
if (picture = nil) then
Exit;
size := av_image_get_buffer_size(pix_fmt, width, height, 1);
picture_buf := av_malloc(size);
if (picture_buf = nil) then
begin
av_frame_free(picture);
Exit;
end;
av_image_fill_arrays(@picture^.data[0], @picture^.linesize[0], picture_buf, pix_fmt, width, height, 1);
Result := picture;
end;
Begin
curDir := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0)));
filename := curDir + 'video.h264';
{$if defined(windows)}
curDir := curDir + 'windows_sdl2' + DirectorySeparator;
{$else}
curDir := curDir + 'linux_sdl' + DirectorySeparator;
{$ifend}
libSDL2_Load(curDir + SDL_LibName);
If libSDL2_IsLoaded = False Then
Begin
WriteLn('Unable to Load SDL2 Library');
ExitX;
End;
FLoaderFFmpeg := TLoaderFFmpeg.Create(Nil);
FLoaderFFmpeg.Active := true;
If (FLoaderFFmpeg.IslibavCodec_Loaded = False) Or
(FLoaderFFmpeg.IslibavDevice_Loaded = False) Then
Begin
WriteLn('Unable to Load libavCodec Library');
ExitX;
End;
Try
Except
On E: Exception Do
WriteLn(E.ClassName, ': ', E.Message);
End;
FLoaderFFmpeg.free;
WriteLN(' ');
WriteLN('Press any key to Exit...');
ReadLN;
End.