How can I encode a real-time video from dynamically spaced frames? - delphi

I'm trying to create a video from a series of screenshots. The screenshots are in a database and have dynamic FPS (1-3 FPS). How can I create a video file with constant FPS?
Before performing av_packet_rescale_ts I tried to change the st^.codec.time_base.den value on the fly between 1 and 3.
This is the basic cycle of encoding of one picture:
repeat
fillchar(pkt, sizeof(TAVPacket), #0);
av_init_packet(#pkt);
(* encode the image *)
ret := avcodec_encode_video2(st^.codec, #pkt, frame, got_packet);
if (ret < 0) then
begin
writeln(format('Error encoding video frame: %s', [av_err2str(ret)]));
exit;
end;
if (got_packet > 0) then
begin
(* rescale output packet timestamp values from codec to stream timebase *)
av_packet_rescale_ts(#pkt, st^.codec.time_base, st^.time_base);
pkt.stream_index := st^.index;
log_packet(oc, #pkt);
(* Write the compressed frame to the media file. *)
av_interleaved_write_frame(oc, #pkt);
end;
inc(frame.pts);
until (av_compare_ts(frame.pts, st^.codec^.time_base, 1, av_make_q(1, 1)) >= 0);
Changing the FPS on the fly causes the video output to fail. If I don't change the st^.codec.time_base.den value the video speeds up and slows down.

There is no notion in ffmpeg of a dynamic timebase, so changing it during encoding is forbidden. But you are free to set the PTS of your frames before encoding to anything monotonically increasing.
You are not showing how you set the PTS in your example code. If you want a constant framerate, just ignore the timestamps from your database, count the frames and calculate a PTS according to the frame number (probably this is what ffmpeg is doing when you don't give it any PTS).
If your frames were recorded with a varying framerate, but you didn't record any timestamps for them, you cannot get a smooth looking video anymore.

Related

Howto draw on every pixel, the min and max values of huge TeeChart FastLine series while DrawAllPoints:= false?

With Delphi 10.3, VCL and build-in standard TeeChart. Windows 10 x64.
I've a huge data samples, few millions, to view.
My target is to show the minimum and maximum values related to each pixel.
i.e the minimum and maximum values in a data segment which are drawn due to a screen decimation in one pixel.
Due to processing time response, I tried DrawAllPoints := false.It is x30 faster!
I think in this case, TeeChart is drawing the value of the first sample from the relevant segment.
Thus the min/max values are not drawn.
With DrawAllPoints := true, everything is fine.
I'm also allowing the user to Zoom/Unzoom.
I could define my own short TeeChart series, limited to the number of pixels myself.
However, it is not so trivial due to the user's Zoom option.
Is there any feature in TeeChart for that? i.e DrawAllPoints := false while drawing min and max of a segment on each pixel.
Maybe there is a call back routine or heritage routine I could force this behavior?
Thanks.
Set DrawAllPointsStyle property of series into daMinMax.
Seems some difference does exist.
for var i := 1 to 100000 do begin
Series1.Add(Sin(i/10000) + Random); // left one, daMinMax is set
FastLineSeries1.Add(Sin(i/10000) + Random);
end;

Change in NAL_REF_IDC value for P frames in x264 encoding

By changing nal_ref_idc value from 2 to 0 for all P frames in x264 encoding, I have observed the size of the P frames gets changed. Is it because of all P frames are now only referenced to a single I frame in GOP?
But the size of the first P frame after I frame should be independent of both the situation (whether direct encoding, nal_ref_idc = 0 or cumulative encoding, nal_ref_idc = 2), but I am getting a change of size in first P frame also after the I frame. Can anyone please tell me the possible reason or explanation behind this?

Buffer data in Simulink in continuous time

I need to buffer some signals for a fixed duration to be used within the simulation. The use of buffer block in Simulink requires the frame rate to be known. However, I am using a continuous time solver (with defined maximum step size) so I don't really know how much should I put the buffer size as. There does not seem to be any option wherein a trigger based on time can be used. Can someone suggest how this can be done?
A simple buffer, made using a MATLAB Function Block, that would always have the most recent element at the top, would be,
function y = buffer(x)
% initialize the buffer
y = zeros(100,1);
% Shuffle the elements down
y(2:end) = y(1:end-1);
% add the new element
y(1) = x;

From Percentage in Non Decimal Numbers

I have this code to record a video in my program:
pbVideoProgress.Percent := Round((vidrec / MAX_REC) * 100);
Now my problem is I want to put a label on my program that will display a timer before the next video will be shown, I tried this:
Label1.Caption :=inttostr(pbVideoProgress.Percent) ;
But it will display the percentage from 100% until it reaches 0% (so next video will be shown).
How can I chang that percentage from % in a real number such as from 10, 9... until 0?
The code line you showed is not valid Delphi syntax. You have to use separate statements:
pbVideoProgress.Percent := Round((vidrec / MAX_REC) * 100);
...
Label1.Caption := IntToStr(100 - pbVideoProgress.Percent);

Dynamic arrays as parameters to API functions and Delphi

In my application (Delphi 2010, OpenGL, windows XP), I need to read back the pixels of variable portions of the framebuffer.
The area of interest is input by the user through a selection rectangle (x1, y1, x2, y2).
With this coordinates I do this:
var
pixels : PGLUByte; //pointer to unsigned bytes
begin
[Transformation of coordinates to Opengl viewport offsets]
//reserve a block of memory for readpixels to write to
ReallocMem(pixels, width * height* sizeof(GLUByte)*3); //<<< crash on this line after a few iterations
if not assigned(pixels) then exit;
//read the pixels
glReadPixels(startx, viewport[3] - (starty+height),
width , height,
GL_RGB, GL_UNSIGNED_BYTE,
pixels);
//Processing of the pixel data follows here...
//when done, release the memory
ReallocMem(pixels, 0);
end;
This function seems to work as intended at the first few tries, but after a few calls to it, the application crashes with an Access violation at $0000000 on the first ReallocMem.
I tried using Getmem, Finalize and Freemem, but these functions lead to the same behaviour.
Is my design principially correct? I tried to debug it, but i could not identify the cause of trouble. width and height always have plausible values, and allocating 5-10 blocks of 30 to 120 KiB should not be an issue on a machine with 3 GB of RAM.
Update
Between the calls to this function, The render pipeline might Draw a few frames, objects may be added to the scene - in principle anything the application is capable of, as this function is called when the user decided to select a rectangular portion of my scene for capture through dragging a seelction box over my Canvas.
Here is a sample of widths and heights from a debug session of mine
width : 211 height: 484 size: 306372
width : 162 height: 395 size: 191970
width : 123 height: 275 size: 101475
width : 14 height: 346 size: 14532
The fourth Selection failed in this session. in Other session, more succesive selections were possible, others crashed when trying the second, but none on the first.
Another thing: when I comment out glReadPixels, no more crashes appear.
I found it after all.
My calculation for width and height were of by one, so i needed to change my reallocmem-line to
ReallocMem(pixels, (width+1) * (height+1) * sizeof(GLUByte)*3);
Thank you for you consideration
Do you initialize pixels to nil?
begin
pixels := nil;
...
Do you allocate enough memory? This example
allocates nWidth + 1, nHeight + 1
mentions that OpenGL might align memory to 4 bytes by default (see GL_PACK_ALIGNMENT).

Resources