Recent

Author Topic: The move procedure in the loop is not working properly  (Read 1148 times)

RedCat

  • New member
  • *
  • Posts: 9
The move procedure in the loop is not working properly
« on: April 04, 2020, 10:18:07 pm »
Such a question, I need to copy data from one variable of type Pbyte to another type of Pointer in a loop with some changes, I sketched this code:
Code: Pascal  [Select][+][-]
  1. while icnt<codec_context^.height - 1 do
  2.  begin
  3.   move(pByte(integer(pFrameYUV420P^.data[0])+ codec_context^.width * 4 * icnt)^,pData, codec_context^.width * 4);
  4.   inc(icnt);
  5.  end;  
but after move, the icnt variable is set to -16777216 how to deal with this? And if, instead of:
 
Code: Pascal  [Select][+][-]
  1. codec_context ^ .width * 4
enter a value less than 16 the cycle starts to work normally, but not all data is copied.
P.S.
Sorry for my english.
« Last Edit: April 04, 2020, 10:23:00 pm by RedCat »

jamie

  • Hero Member
  • *****
  • Posts: 2901
Re: The move procedure in the loop is not working properly
« Reply #1 on: April 04, 2020, 10:33:09 pm »
maybe this ?

Code: Pascal  [Select][+][-]
  1. while icnt<codec_context^.height - 1 do
  2.  begin
  3.   move(pByte(UintPtr(@pFrameYUV420P^.data[0])+ codec_context^.width * 4 * icnt)^,pData^, codec_context^.width * 4);
  4.   inc(icnt);
  5.  end;  
  6.  
  7.  
Number 1 at blue screen app creations!

jamie

  • Hero Member
  • *****
  • Posts: 2901
Re: The move procedure in the loop is not working properly
« Reply #2 on: April 04, 2020, 10:38:21 pm »
You may also need to increment pData after each loop..

Inc(pData, codec_context^.width * 4);
Number 1 at blue screen app creations!

winni

  • Hero Member
  • *****
  • Posts: 1341
Re: The move procedure in the loop is not working properly
« Reply #3 on: April 04, 2020, 10:40:10 pm »
Hi!

You must have an integer overflow for icnt:

-16777216 is  -(256*256*256)

Winni

RedCat

  • New member
  • *
  • Posts: 9
Re: The move procedure in the loop is not working properly
« Reply #4 on: April 06, 2020, 11:07:40 am »
maybe this ?

Code: Pascal  [Select][+][-]
  1. while icnt<codec_context^.height - 1 do
  2.  begin
  3.   move(pByte(UintPtr(@pFrameYUV420P^.data[0])+ codec_context^.width * 4 * icnt)^,pData^, codec_context^.width * 4);
  4.   inc(icnt);
  5.  end;  
  6.  
  7.  

and

You may also need to increment pData after each loop..

Inc(pData, codec_context^.width * 4);

Did not help :(

Hi!

You must have an integer overflow for icnt:

-16777216 is  -(256*256*256)

Winni

I do not quite understand, can you explain in more detail?


jwdietrich

  • Hero Member
  • *****
  • Posts: 1112
    • formatio reticularis
Re: The move procedure in the loop is not working properly
« Reply #5 on: April 06, 2020, 01:32:14 pm »
The data to be read may be too long to fit an integer. Try to define icnt as a longint rather than as an integer.
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.0.8 | FPC 3.0.4 | PPC, Intel, ARM | macOS, Windows, Linux

RedCat

  • New member
  • *
  • Posts: 9
Re: The move procedure in the loop is not working properly
« Reply #6 on: April 06, 2020, 02:13:20 pm »
The data to be read may be too long to fit an integer. Try to define icnt as a longint rather than as an integer.

I tried but nothing has changed

jamie

  • Hero Member
  • *****
  • Posts: 2901
Re: The move procedure in the loop is not working properly
« Reply #7 on: April 06, 2020, 11:56:12 pm »
Code: Pascal  [Select][+][-]
  1. Var
  2.  pReadData:Pbyte;
  3.  S :Integer;
  4. Begin
  5.  PReadData := @pFrameYUV420P^.data[0];
  6.  S := codec_context^.Width * 4; //You may need to round this up to a even boundary.
  7.  inct := 0;
  8. while icnt<=codec_context^.height - 1 do
  9.  begin
  10.   move(pReadData^,pData^, S);
  11.   inc(icnt);
  12.   inc(pData,S);
  13.   inc(pReadData,S);
  14.  end;
  15.  
  16.  
Number 1 at blue screen app creations!

Warfley

  • Full Member
  • ***
  • Posts: 120
Re: The move procedure in the loop is not working properly
« Reply #8 on: April 07, 2020, 12:56:12 am »
Code: Pascal  [Select][+][-]
  1. while icnt<codec_context^.height - 1 do
  2.  begin
  3.   move(pByte(integer(pFrameYUV420P^.data[0])+ codec_context^.width * 4 * icnt)^,pData, codec_context^.width * 4);
  4.   inc(icnt);
  5.  end;  
Assuming from the name you've given pData its a pointer, then you should dereference it with pData^. Otherwise the contents of pdata will be overwritten, which means, as it is most certinly smaller than the size you are moving, you will override your stack variables, which results in icnt being overwritten. You can turn on Memory Range checks to avoid something like this.

Also this construct is interesting. First of all you convert your pointer into an integer, which does only work on an x86 cpu. For sizes there are the types SizeUInt and SizeInt. Second you can use pointers as arrays to ease access and lastly for iterating an integer there exists the for loop:
Code: Pascal  [Select][+][-]
  1. copyLen := codec_context^.width * 4;
  2. for icnt:=0 to codec_context^.height-2 do
  3.   Move(PByte(pFrameYUV420P^.data[0])[copyLen*icnt], pData^, copyLen);

But if you don't want to override pData in each iteration, but rather extend it:
Code: Pascal  [Select][+][-]
  1. Move(PByte(pFrameYUV420P^.data[0])[copyLen*icnt], pData[copyLen*icnt], copyLen);
And then the whole thing can be done with a single move instruction:
Code: Pascal  [Select][+][-]
  1. Move(PByte(pFrameYUV420P^.data[0])^, pData^, codec_context^.width * 4 * (codec_context^.height-1));
« Last Edit: April 07, 2020, 12:59:24 am by Warfley »

RedCat

  • New member
  • *
  • Posts: 9
Re: The move procedure in the loop is not working properly
« Reply #9 on: April 08, 2020, 08:56:45 am »
Like this :
Code: Pascal  [Select][+][-]
  1. Var
  2.  pReadData:Pbyte;
  3.  S :Integer;
  4. Begin
  5.  PReadData := @pFrameYUV420P^.data[0];
  6.  S := codec_context^.Width * 4; //You may need to round this up to a even boundary.
  7.  inct := 0;
  8. while icnt<=codec_context^.height - 1 do
  9.  begin
  10.   move(pReadData^,pData^, S);
  11.   inc(icnt);
  12.   inc(pData,S);
  13.   inc(pReadData,S);
  14.  end;
  15.  
  16.  

so

Code: Pascal  [Select][+][-]
  1. while icnt<codec_context^.height - 1 do
  2.  begin
  3.   move(pByte(integer(pFrameYUV420P^.data[0])+ codec_context^.width * 4 * icnt)^,pData, codec_context^.width * 4);
  4.   inc(icnt);
  5.  end;  
Assuming from the name you've given pData its a pointer, then you should dereference it with pData^. Otherwise the contents of pdata will be overwritten, which means, as it is most certinly smaller than the size you are moving, you will override your stack variables, which results in icnt being overwritten. You can turn on Memory Range checks to avoid something like this.

Also this construct is interesting. First of all you convert your pointer into an integer, which does only work on an x86 cpu. For sizes there are the types SizeUInt and SizeInt. Second you can use pointers as arrays to ease access and lastly for iterating an integer there exists the for loop:
Code: Pascal  [Select][+][-]
  1. copyLen := codec_context^.width * 4;
  2. for icnt:=0 to codec_context^.height-2 do
  3.   Move(PByte(pFrameYUV420P^.data[0])[copyLen*icnt], pData^, copyLen);

But if you don't want to override pData in each iteration, but rather extend it:
Code: Pascal  [Select][+][-]
  1. Move(PByte(pFrameYUV420P^.data[0])[copyLen*icnt], pData[copyLen*icnt], copyLen);
And then the whole thing can be done with a single move instruction:
Code: Pascal  [Select][+][-]
  1. Move(PByte(pFrameYUV420P^.data[0])^, pData^, codec_context^.width * 4 * (codec_context^.height-1));

the cycle works correctly, but for some reason the result is not the one that I needed.
the code that I quoted above worked well in Delphi 7, this is the video display code using ffmpeg, the only difference is that in Delfi I drew using GDI, and here using OpenLEN On the delphi, the picture after copying the bytes with the shift was drawn correctly, but if in some garbage is drawn in the loop, and if you use copying without a loop: then the picture is copied as is in the buffer, i.e. not right here is the whole rendering code:
Code: Pascal  [Select][+][-]
  1. procedure RenderScene; cdecl;
  2. var
  3.   i,  icnt2, j,tst, numBytes, CopyLen : LongInt;
  4.   icnt:LongInt;
  5.    pData : Pointer;
  6.    tmp,tmp2,mybuffer:Pbyte;
  7.    pReadData:Pbyte;
  8.  S :Integer;
  9. begin
  10.  
  11.  while (av_read_frame(format_context, @packet) >= 0) do
  12.  
  13.     begin
  14.        WriteLn(IntToStr(packet.stream_index));
  15.  
  16.       if (packet.stream_index = video_stream) then
  17.       begin
  18.         // Video stream packet
  19.         avcodec_decode_video2(codec_context, frame, @frame_finished, @packet);
  20.  
  21.         if (frame_finished <> 0) then
  22.         begin
  23.           pFrameYUV420P:= av_frame_alloc();
  24.             numBytes:=avpicture_get_size(AV_PIX_FMT_RGB24, codec_context^.width, codec_context^.height);
  25.           mybuffer:=av_malloc(numBytes*sizeof(cardinal));
  26.           avpicture_fill(PAVPicture(pFrameYUV420P), mybuffer, AV_PIX_FMT_RGB32, codec_context^.width, codec_context^.height);
  27.           if not assigned(pFrameYUV420P) then
  28.            begin
  29.              writeln('Could not Allocate AVFrame structure');
  30.              exit;
  31.            end;
  32.           GetMem(pData, codec_context^.width*codec_context^.height*4);    
  33.           sws_scale(img_convert_context,@frame^.data,@frame^.linesize,0,codec_context^.height,@pFrameYUV420P^.data,@pFrameYUV420P^.linesize);
  34.     Move(PByte(pFrameYUV420P^.data[0])^, pData^, codec_context^.width * 4 * (codec_context^.height-1));
  35.     if pData<>nil then;
  36.     Texture :=CreateTexture(codec_context^.width, codec_context^.height, GL_RGB, pData);
  37.            glLoadIdentity();
  38.     gluLookAt( posX, 0.0, posZ,0.0, 0.0, 0.0,0.0, 1.0, 0.0);
  39.   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  40.  
  41.    av_free(pFrameYUV420P);
  42.   glutSwapBuffers;
  43.         end;
  44.       end;
  45.       av_free_packet(@packet);
  46.     end;
  47. end;
  48.  
  49. //Init
  50.  
  51. begin
  52.   try
  53.     if (ParamCount < 1) then
  54.       filename := std_filename
  55.     else
  56.       filename := ParamStr(1);
  57.     glutInit(@argc,argv);
  58.   glutInitDisplayMode(GLUT_RGBA or GLUT_DOUBLE or GLUT_DEPTH);
  59.   glutInitWindowSize(AppWidth, AppHeight);
  60.   ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);
  61.   ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);
  62.   glutInitWindowPosition((ScreenWidth - AppWidth) div 2, (ScreenHeight - AppHeight) div 2);
  63.   glutCreateWindow('Lazarus OpenGL Tutorial');
  64.  
  65.   glutKeyboardFunc ( @pressKey );
  66.  
  67.   InitScene;
  68.  
  69.   glutDisplayFunc(@RenderScene);
  70.   glutReshapeFunc(@Reshape);
  71.   glutTimerFunc(40, @Timer, 0);
  72.  
  73.     av_register_all();
  74.     avformat_network_init();
  75.  
  76.     err := avformat_open_input(@format_context, PAnsiChar(filename), nil, nil);
  77.     if (err < 0) then
  78.     begin
  79.       WriteLn('ffmpeg: Unable to open input file');
  80.       Halt(1);
  81.     end;
  82.  
  83.  
  84.     err := avformat_find_stream_info(format_context, nil);
  85.     if (err < 0) then
  86.     begin
  87.       WriteLn('ffmpeg: Unable to find stream info');
  88.       Halt(1);
  89.     end;
  90.  
  91.     av_dump_format(format_context, 0, PAnsiChar(filename), 0);
  92.     for video_stream := 0 to format_context^.nb_streams - 1 do
  93.       if (format_context^.streams[video_stream]^.codec^.codec_type = AVMEDIA_TYPE_VIDEO) then
  94.         break;
  95.     if (video_stream = format_context^.nb_streams) then
  96.     begin
  97.       WriteLn('ffmpeg: Unable to find video stream');
  98.       Halt(1);
  99.     end;
  100.  
  101.     codec_context := format_context^.streams[video_stream]^.codec;
  102.     codec := avcodec_find_decoder(codec_context^.codec_id);
  103.     err := avcodec_open2(codec_context, codec, nil);
  104.     if (err < 0) then
  105.     begin
  106.       WriteLn('ffmpeg: Unable to open codec');
  107.       Halt(1);
  108.     end;
  109.           img_convert_context := sws_getContext(
  110.           codec_context^.width,
  111.           codec_context^.height,
  112.           codec_context^.pix_fmt,
  113.           codec_context^.width,
  114.           codec_context^.height,
  115.           AV_PIX_FMT_RGB24,
  116.           SWS_BILINEAR,
  117.           nil,
  118.           nil,
  119.           nil
  120.       );
  121.     if (img_convert_context = nil) then
  122.     begin
  123.       WriteLn('Cannot initialize the conversion context');
  124.       Halt(1);
  125.     end;
  126.     frame := av_frame_alloc();
  127.     glutMainLoop;
  128.     sws_freeContext(img_convert_context);
  129.     av_free(frame);
  130.     avcodec_close(codec_context);
  131.     avformat_close_input(@format_context);
  132.     avformat_network_deinit;
  133.   except
  134.     on E: Exception do
  135.       WriteLn(E.ClassName, ': ', E.Message);
  136.   end;                            
  137.  
  138.  

In attachments, the rendering result and the original image

jamie

  • Hero Member
  • *****
  • Posts: 2901
Re: The move procedure in the loop is not working properly
« Reply #10 on: April 08, 2020, 01:55:10 pm »
Like a lot of images in Bitmap format, the image is upside-down …

The first scan line you read is actually the last one.

This was done years ago with analog equipment so you wouldn't see flicker. The output being drawn to the video adapter would draw at the bottom first and work its way up to the top. So incoming image data would start at the bottom of the image.

  You need to treat the first line of data as the last line of data and so on..

 Also you have a miss phasing of the RBG channels by the looks of it. You are starting the data read at the wrong position.

 Also keep in mind that color channels in the hardware end of things could be backwards, in other words the Red and Blue channels could be flipped. So you'll need to address that too..

 All of this information should be in the Specifications of the video format you are decoding.
Number 1 at blue screen app creations!

RedCat

  • New member
  • *
  • Posts: 9
Re: The move procedure in the loop is not working properly
« Reply #11 on: April 25, 2020, 11:40:35 am »
Dear experts, please help me deal with the move procedure. The problem now is that the procedure copies the same section of memory the whole cycle and I can not make it move through the memory fragments
here is my Lazarus code:

Code: Pascal  [Select][+][-]
  1. procedure SwapTB(dataIN,dataOUT : Pointer;SizeX,SizeY : Integer);
  2. var
  3.   x,y:GLint;//(=integer=longint)
  4. begin
  5.     for y := 0 to (SizeY)-1 do
  6.    begin
  7.      Move(PByte(dataIN)[y], PByte(dataOUT)[y], SizeX * 4);
  8.     end;
  9.  end;
  10.  

Here is the code once written by Delphi that worked:

Code: Pascal  [Select][+][-]
  1.  for i := 0 to SizeY - 1 do
  2.       CopyMemory ( vp.bmp.ScanLine[i], pointer(integer(dataIN) + SizeX * 4 * i), SizeX * 4);
  3.  

I can’t understand what is the reason, the original frame and what happens in the attached pictures. If you look at the rendered frame, you can see that from below it seems to start copying correctly

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8375
  • FPC developer.
Re: The move procedure in the loop is not working properly
« Reply #12 on: April 25, 2020, 01:31:58 pm »
Your code indexes a single pointer byte wise. All your copying happens in the same row, since the

Probably you need to do

Code: Pascal  [Select][+][-]
  1.  Move(PByte(dataIN)[ SizeX * 4 * y], PByte(dataOUT)[ SizeX * 4 * y], SizeX * 4);

Note that code depends on the meaning of sizeX. Typically it should be the number of pixels rounded up to a multiple of 4.

So if SizeX is the true size of the pixels, you might need to implement the rounding too.

RedCat

  • New member
  • *
  • Posts: 9
Re: The move procedure in the loop is not working properly
« Reply #13 on: April 25, 2020, 01:59:51 pm »
Your code indexes a single pointer byte wise. All your copying happens in the same row, since the

Probably you need to do

Code: Pascal  [Select][+][-]
  1.  Move(PByte(dataIN)[ SizeX * 4 * y], PByte(dataOUT)[ SizeX * 4 * y], SizeX * 4);

Note that code depends on the meaning of sizeX. Typically it should be the number of pixels rounded up to a multiple of 4.

So if SizeX is the true size of the pixels, you might need to implement the rounding too.

Your option really works, but copies the frame one to one, but I still need to equalize the phasing of the frame. Therefore, if I repeat the code of the working version in Delphi, then I need to execute
Code: Pascal  [Select][+][-]
  1. Move (PByte (dataIN) [SizeX * 4 * y], PByte (dataOUT) [y], SizeX * 4);
  2.  
but again, only one line is copied in this way and the colors get lost, I can’t understand why even though I specify the output index
Code: Pascal  [Select][+][-]
  1. PByte (dataOUT) [y]
, does it still fill one line? After all, CopyMemory in Delphi is Move:
Code: Pascal  [Select][+][-]
  1. procedure CopyMemory (Destination: Pointer; Source: Pointer; Length: DWORD);
  2. begin
  3.    Move (Source ^, Destination ^, Length);
  4. end;
  5.  
In the attachment, the rendering result if I copy the frame in your way
« Last Edit: April 25, 2020, 02:07:52 pm by RedCat »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8375
  • FPC developer.
Re: The move procedure in the loop is not working properly
« Reply #14 on: April 25, 2020, 02:02:57 pm »
That can't be explained from the shown code. The images should be set up correctly, both dimensions and pixelformat. (probably 32-bit colors since you do a lot of "times 4").

I think I was wrong btw with the alignment. The alignment is in bytes (rowsize rounded up to a multiple of 4 bytes), not pixels, but I usually work with 1-byte pixels :-)

 

TinyPortal © 2005-2018