Renate Schaaf 64 Posted November 6, 2020 This is my video-project on GitHub: https://github.com/rmesch/Bitmaps2Video I am presenting it here, because it is useful as it is, but could use some ideas for improvement. Features: A Delphi-class to support encoding of a series of bitmaps and video clips to a video file Requires the ffmpeg-library and is intended as an easy to use interface to this library Versions for Win32/Win64 and a cross-platform version currently supporting Win32/Win64/Android32/Android64 Most popular file formats and codecs supported, more codecs contained in FFMpeg can be registered Rudimentary support for adding an audio-stream Demos for both versions, set up to compile and run "out of the box", as library files and support for their deployment to Android are included There are some problem areas though, the most important one in my opinion being threading issues with TBitmap under Android. For more see the readme and the demos. Critique, ideas, bug reports most welcome, maybe someone would even like to contribute, that would be delightful. There have been valuable contributions so far, but there are some areas which could use the input of an expert. Thanks for reading, Renate 4 1 Share this post Link to post
prodeldpen 0 Posted October 19, 2023 Hello, Thanks for this work, I was looking form something like this. More precisely, I want to make a movie from animated 3D scenes in a TViewport3D in Firemonkey. So I took your UMultidemo example. I put a Tviewport3D on the form, and in it a TCube, with an associated TFloatanimation making it rotate around an axis for 7 seconds. With an additional TImagelist on the form, I make a list of bitmaps with TForm1.FloatAnimation1Process ... BM:=Viewport3D1.MakeScreenshot; Imagelist1.Add(BM); CX:=BM.Size.cx; CY:=BM.Size.cy; ... CX and CY being vars of the unit. Yes, they're rewritten each time with the same value, but I can improve that later. The Imagelist1.Add is taken from the TImageListHelper here : https://stackoverflow.com/questions/36013186/how-to-insert-images-to-timagelist-in-firemonkey-programmaticaly adding FMX.ImgList and FMX.MultiResBitmap to "uses". And then, I just modified TForm1.MakeSlideshow by replacing // 23 sec of movie I := 1; while I < 4 do begin if I > 1 then bme.CrossFade(am, bm, 1000); bme.AddStillImage(bm, 3000); bme.CrossFade(bm, am, 1000); bme.AddStillImage(am, 3000); inc(I); end; // Hold end frame for 2 seconds bme.Freeze(2000); with for j :=0 to Imagelist1.Count-1 do begin am.Assign(Imagelist1.Bitmap(TSizef.Create(CX,CY),j)); bme.AddStillImage(am, 17); end; Since the Timer on animations is 60 times per second and 1000/60 = 16.6666 And then, I start the animation in TForm1.Create, excute the program, wait till the animation is over, press the "Make a simple slideshow" without changing the options combos and I get a movie with the rotating cube in the viewport. Exactly what I wanted. ... almost. I'm supposed to have 60 bitmaps per second, and with an animation lasting 7 seconds Imagelist1.Count is 400 instead of 420. No idea why. Other times it's 397... But the movie lasts 13 seconds. Yes, the frame rate combo was on 30 frames per second, so I changed for 60, tried again... and another movie lasting 13 seconds. I tried the other way round by leaving 30 frames per seconds the combo and instead writing in the code : bme.AddStillImage(am, 8); The movie still lasted 13 seconds ! Finally, I did both : 8 milliseconds in AddStillImage and 60 frames per second in the combo, and I got a movie lasting 6 seconds. I suppose there are effects of "round"ing that lead to this uncertainty. Now for the size. I thought it would be even better having a movie with the same size as the viewport. So I thought I could replace in MakeSlideshow Height := MovieHeights[HeightCombo.ItemIndex]; with Height := CY; But this time it fails. By debugging, I found that in TBitmapEncoderM.Create in UBitmaps2VideoM.pas it's avcodec_open2(c, codec, @CodecSetup.OptionsDictionary); that fails. and this time it's a function of a dll of FFMPEG, and for the time being, I don't want to dive deep into the specs... Is there a relatively easy way (other than making my own DLLs and rewriting FFMEG, and from within Delphi, not by using some "MS DOS command line" tricks "ffmpeg -option1 -option2...") to customize the size of my movie to anything like 123 x 456 or should I stick to 720, 540 or 1080 for the height and the predifined aspect ratios ? And eventually, is there an easy way to write meta data (author, etc.) to the file. I have seen a few things in the comments of FFMPEG.pas, but no syntax guidelines. Share this post Link to post
Renate Schaaf 64 Posted October 19, 2023 30 minutes ago, prodeldpen said: I suppose there are effects of "round"ing that lead to this uncertainty. Right. You want to add 1 frame of your animation at a time, but you use bme.addStillImage, which is meant for adding the same image for multiple frames. So it will only work (roughly) correctly if the ShowTime is much larger than the frame time of the movie. Try to use bme.AddFrame instead. 36 minutes ago, prodeldpen said: customize the size of my movie to anything like 123 x 456 That just won't work, it's a codec limitation. You have to use at least even numbers, for some codecs the sizes might even have to be multiples of 4. I would stick to multiples of 4 to be on the safe side. Another thing you might consider is to shorten the chain from animation to movie. To show the animation and make screenshots seems a bit roundabout to me, there must be a shorter way. 45 minutes ago, prodeldpen said: And eventually, is there an easy way to write meta data (author, etc.) to the file. There must be, but I haven't yet bothered to look at it 🙂, maybe I will. 1 Share this post Link to post
prodeldpen 0 Posted October 19, 2023 Thanks for your answer. I will try with AddFrame. I wish I knew how to bypass "makescreenshot", I would even prefer Embarcadero to provide a nice native "makemovie" ! Share this post Link to post
prodeldpen 0 Posted October 21, 2023 Just in case you might be interested, I found out how to easily add metadata : In TBitmapEncoderM.Create in UBitmaps2VideoM.pas Just between the lines Assert(ret >= 0, 'avformat_alloc.. error' + inttostr(ret)); and stream := avformat_new_stream(oc, nil); I only need to add something like av_dict_set(@oc.metadata, 'title', 'test metadata', 0); av_dict_set(@oc.metadata, 'composer', 'me', 0); av_dict_set(@oc.metadata, 'genre', 'programming', 0); And it appears in Windows explorer with a right click and properties, or with the adequate displayed headers in Windows explorer. For the size of the video, multiples of 4 are fine, it works perfectly with Height := (CY div 4) * 4; Width := (CX div 4) * 4; so i have "almost" the size of the viewport. I Share this post Link to post