[UOS] 飞腾2000+UOS+lazarus+ffmpeg解码效率奇低
Tofloor
poster avatar
vster
deepin
2024-02-23 12:31
Author

运行环境如题,详细如图。简单的调用ffmpeg 动态库解码1080P h264文件,结果解码每帧要40-70毫秒,正常应该是10毫秒左右。

同样的机器,同样的ffmpeg库和调用逻辑,换做qt creator就效率正常。求助各位,看有哪些因素导致。谢谢。

后附主要代码。解码函数avcodec_decode_video2耗时40-70毫秒。
图片.png

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

  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.

Reply Favorite View the author
All Replies
流浪的加菲
deepin
2024-02-23 16:58
#1

不知道为什么有差异,但是既然已经用UOS系统了,本身也是推荐大家在UOS上使用Qt Creator,而且看你说的使用Qt 解码效率是正常的,那就用Qt来干活咯😂

Reply View the author