Renate Schaaf
Members-
Content Count
126 -
Joined
-
Last visited
-
Days Won
4
Everything posted by Renate Schaaf
-
I took sigma = 0.2*Radius, but it's easy to change that to something more common. I just took a value for which the integral is very close to 1. With respect to other implementations, I'm ready to learn. I just implemented it as accurately as I could think of without being overly slow. Performance is quite satisfying to me, but I bet with your input it'll get faster 🙂
-
I just uploaded a new version to https://github.com/rmesch/Parallel-Bitmap-Resampler Newest addition: a parallel unsharp-mask using Gaussian blur. Can be used to sharpen or blur images. Dedicated VCL-demo "Sharpen.dproj" included. For FMX the effect can be seen in the thumbnail-viewer-demo (ThreadsInThreadsFMX.dproj). This is for the "modern" version, 10.4 and up. I haven't ported the unsharp-mask to the legacy version (Delphi 2006 and up) yet, requires more work, but I plan on doing so. Renate
-
I did a quick test with the demo of the fmx-version of my resampler, just doing "Enable Skia" on the project. In the demo I compare my results to TCanvas.DrawBitmap with HighSpeed set to false. I see that the Skia-Canvas is being used, and that HighSpeed=False results in Skia-resampling set to SkSamplingOptionsHigh : TSkSamplingOptions = (UseCubic: True; Cubic: (B: 1 / 3; C: 1 / 3); Filter: TSkFilterMode.Nearest; Mipmap: TSkMipmapMode.None); So, some form of cubic resampling, if I see that right. Result: Timing is slightly slower than native fmx-drawing, but still a lot faster than my parallel resampling. I see no improvement in quality over plain fmx, which supposedly uses bilinear resampling with this setting. Here are two results: (How do you make this browser use the original pixel size, this is scaled!) This doesn't look very cubic to me. As a comparison, here are the results of my resampler using the bicubic filter: I might not have used Skia to its most favorable advantage. Renate
-
OK, I'll stop thinking about it. Time to get some sleep:)
-
Hi Anders, Thanks for explaining. I had a feeling that the compression is too "global" for parallelizing. But .. From what I have meanwhile read, it seems that parts of the decompression could be done in parallel. This link is about compression, but couldn't it apply to decompression too? (not that I know anything about it 🙂 https://stackoverflow.com/questions/61850421/how-to-perform-jpeg-encoding-of-a-big-rgb-image-in-parallel Anyway, there are research papers which claim that they got a speedup from doing the decoding partly in parallel.
-
Sorry, no, but it sounds like a good idea. Naively. I have no idea how parallelizable jpeg-decoding is 🙂
-
Sure you can.
-
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
The use of TVirtualImageList is totally unessential, just cosmetics. I have replaced it by the old TImageList now. Hope it works, and thanks! -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
I think I know what you mean, I'll play around with it some. Problem is that I really need to have a well defined video-frame-rate, otherwise the user can't time the input. I have meanwhile figured out the audio-sample-duration for given sample-rate and use it for the amount of audio-samples to be read ahead. Audio-sync is now acceptable to me. Problem is now, that some decoders are sloppyly implemented in Windows, like .mpg. I'm not sure I even have control over that. Isn't the encoder just using everything that is in the leaky bucket to write the segments in what it thinks is the right way? Why can't you compile the code? I think your feedback would be very valuable to me. Did you try the latest version on GitHub? https://github.com/rmesch/Bitmaps2Video-for-Media-Foundation (there's one silly bit of code still in there that I need to take out, but it usually doesn't hurt anything) I was hoping to have eliminated some code that prevented it to run on versions earlier than 11.3. Or have you meanwhile developed an aversion against the MF-headers? 🙂 -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
A first version of TBitmapEncoderWMF is now available at https://github.com/rmesch/Bitmaps2Video-for-Media-Foundation It only supports .mp4 and codecs H264 and HEVC(H265) at the moment. See the readme for more details. I had some problems getting the video-stream to use the correct timing. Apparently the encoder needs to have the video- and audio-samples fed to it in just the right way, otherwise it drops frames or changes timestamps at its own unfathomable judgement. I think I solved it by artificially slowing down the procedure that encodes the same frame repeatedly, and by reading ahead in the audio-file for "just the right amount". Would be interested in how it fares on other systems than mine. -
Please support Stack Overflow moderators strike against AI content policy
Renate Schaaf replied to Dalija Prasnikar's topic in Tips / Blogs / Tutorials / Videos
What makes you so negative about this? I certainly have my problems with participation on stackoverflow. After having received some unfair downvotes, I've stopped asking questions, and I only answer, if I'm dead sure of what I say, maybe a good thing. But stackoverflow has been a valuable and mostly reliable source of information, and I would have to spend much more time finding good info, if I couldn't rely on content being mostly accurate anymore, or it the moderators would stop doing their job. I upvote every answer that has been useful, and I downvote every blatantly wrong answer, just to keep the quality up. I would hate for ChatGPT flooding the answers. -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
Well, I must have written lots of sloppy code yesterday, but I can now encode audio to AAC together with video to H264 or H265. I'm using the CheckFail approach wherever possible. I wish I could keep all these attribute names in my head. Wonder whether it would be possible collecting them into records, so you could consult code completion about them. -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
No thanks 🙂. But I've already translated parts of C++-code to Delphi. They could use stuff like Break_On_Fail(hr) and more, made me a bit jealous. You wouldn't per chance know why I can't mux any audio into an HEVC-encoded video? The video stream is all there, but it seems to be missing the correct stream header. So only the audio is being played. -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
You are right. But then I have to think about whether or not a call is likely to produce havoc, and declare several new variables. BTW: WriteSample pushes the sample to the sinkwriter and does not just set an index. What do you think about the following construct instead: procedure TBitmapEncoderWMF.WriteOneFrame; var pSample: IMFSample; Count: integer; const ProcName = 'TBitmapEncoderWMF.WriteOneFrame'; procedure CheckFail(hr: HResult); begin inc(Count); if not succeeded(hr) then raise Exception.Create('Fail in call nr. ' + IntToStr(Count) + ' of ' + ProcName + ' with result ' + IntToStr(hr)); end; begin Count := 0; // Create a media sample and add the buffer to the sample. CheckFail(MFCreateSample(pSample)); CheckFail(pSample.AddBuffer(pSampleBuffer)); CheckFail(pSample.SetSampleTime(fWriteStart)); CheckFail(pSample.SetSampleDuration(fSampleDuration)); // Send the sample to the Sink Writer. CheckFail(pSinkWriter.WriteSample(fstreamIndex, pSample)); inc(fWriteStart, fSampleDuration); fVideoTime := fWriteStart div 10000; inc(fFrameCount); end; -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
@programmerdelphi2k What if hrSampleBuffer is not S_Ok, causing pSinkWriter.WriteSample to fail with an AV or such? You would get an exception the source of which would be harder to trace. Or am I just too dense to understand :). (It's late) -
Bitmaps2Video for Windows Media Foundation
Renate Schaaf replied to Renate Schaaf's topic in I made this
Thanks, sounds like it's just the thing needed. Just need to figure out how. Error: uToolsWMF uses a unit Z_prof. Entry can be safely deleted. Comes from having too much stuff in the path. Meanwhile I think I figured out how to improve the encoding quality. Around line 270 in uBitmaps2VideoWMF.pas make the following changes: if succeeded(hr) then hr := MFCreateAttributes(attribs, 4); //<--------- change to 4 here // this enables hardware encoding, if the GPU supports it if succeeded(hr) then hr := attribs.SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, UInt32(True)); // this seems to improve the quality of H264 and H265-encodings: {*************** add this *********************************} // this enables the encoder to use quality based settings if succeeded(hr) then hr := attribs.SetUINT32(CODECAPI_AVEncCommonRateControlMode, 3); {**************** /add this *******************************} if succeeded(hr) then hr := attribs.SetUINT32(CODECAPI_AVEncCommonQuality, 100); if succeeded(hr) then hr := attribs.SetUINT32(CODECAPI_AVEncCommonQualityVsSpeed, 100); Besides, I'm getting sick and tired of all those if succeeded... -
I'm building a Directory-tree for FMX as a descendent of TTreeview. Because reading in the full directory-tree of a root-directory takes way too long, I only read in the first 2 levels. After that I only want to create sub-items as necessary for any item that the user selects or expands. In the VCL-version this can be done by overriding TTreeview.Change and TTreeview.CanExpand. For the FMX-version I can override TTreeview.DoChange, but I can't find an analogue of CanExpand. So I tried to override MouseDown. But the Treeview never gets the MouseDown when the user clicks the expand-button. Is there anything else I could do? Here some of the relevant code: procedure TDirectoryTree.CreateSubNodesToLevel2(aItem: TTreeViewItem); var DirArraySize1, DirArraySize2, i, j: integer; DirArray1, DirArray2: TStringDynArray; TreeItem, TreeItem2: TTreeViewItem; NewName: string; begin DirArray1 := TDirectory.GetDirectories(GetFullFolderName(aItem)); DirArraySize1 := Length(DirArray1); if DirArraySize1 > 0 then begin for i := 0 to DirArraySize1 - 1 do begin NewName := DirArray1[i]; if aItem.Count = i then begin TreeItem := TTreeViewItem.Create(self); fDirectoryDict.Add(NativeUInt(TreeItem), NewName); TreeItem.Text := ExtractFilename(NewName); TreeItem.ImageIndex := 0; TreeItem.Parent := aItem; end else TreeItem := aItem.Items[i]; DirArray2 := TDirectory.GetDirectories(NewName); DirArraySize2 := Length(DirArray2); for j := 0 to DirArraySize2 - 1 do begin if TreeItem.Count = j then begin TreeItem2 := TTreeViewItem.Create(self); fDirectoryDict.Add(NativeUInt(TreeItem2), DirArray2[j]); TreeItem2.Text := ExtractFilename(DirArray2[j]); TreeItem2.ImageIndex := 0; TreeItem2.Parent := TreeItem; end; end; end; end; end; function TDirectoryTree.GetFullFolderName(aItem: TTreeViewItem): string; begin Result := fDirectoryDict.Items[NativeUInt(aItem)]; end; procedure TDirectoryTree.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin if (HoveredItem <> nil) then CreateSubNodesToLevel2(HoveredItem); inherited; end;
-
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
Good idea. Going back to FindFirst/FindNext might have been the better design right from the beginning, but right now I'm satisfied with the speed. I just had to fix the VCL-tree, because I forgot that the darn thing recreates its Window-handle on any DPI-change. Arghh! -
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
You can see the brandnew explorer-trees in action here: https://github.com/rmesch/Parallel-Bitmap-Resampler. See the demos ThreadsInThreads* Renate -
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
Yes, it works, but it is still too slow to be useable as an explorer tree. Let me make a bold statement: You will never be able to create a functioning explorer tree with the plain TTreeview in FMX, if you insist on reading in the full directory tree of a root directory. Yes, that's why I want to scan 2 levels at a time, so the correct expand buttons are always shown. But for this I need to also know when the user expands a node without actually selecting it. By defining an interposer class for TTreeViewItem, which overrides TTreeViewItem.SetIsExpanded, I can now intercept this event. I would have been interested in learning, whether anybody sees a problem with this approach. I don't see any in the use case I need it for. Renate -
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
Nevermind, I have it working my way, it's fast, and I can also avoid all those errors. But thanks for your time. Renate -
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
The speed isn't too bad, certainly better than filling the nodes recursively. But it still takes several minutes to display the content of my personal folder, whereas in my version you'd see it almost instantly. There must be something wrong with the logic in your MyFillTreeView. It never displays sibling nodes right. This is for example the output I get when I choose the Embarcadero folder under documents as root: I also really want to avoid reading in all directories in the root. -
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
There was a reason I didn't do that, but I can't remember :). What do you think about using the interposer class for TTreeViewItem? Meanwhile I excluded Directories which have faHidden or faSystem, because that was creating errors. Other than that it seems to be working OK, unless you try to expand something like the Windows-folder, that still takes forever. I would have liked to use TTreeView.ItemExpanded, but as you say, I can't. -
FMX-TTreeview: Intercept click on Expand-button
Renate Schaaf replied to Renate Schaaf's topic in FMX
I got it to "work" by defining an interposer class for TTreeViewItem type TTreeViewItem = class(FMX.TreeView.TTreeViewItem) protected procedure SetIsExpanded(const Value: Boolean); override; end; ... procedure TTreeViewItem.SetIsExpanded(const Value: Boolean); begin inherited; if IsExpanded then if TreeView is TDirectoryTree then TDirectoryTree(TreeView).CreateSubNodesToLevel2(self); end; It doesn't seem to interfere with the inner workings of TTreeView, but it makes me feel a bit uneasy. Also whenever you now use an item of the treeview you have to do a typecast TTreeviewItem(aTreeviewItem). I have attached the a small test project. Tested for Windows platforms only. DirectoryTest.zip -
I'm not all that familiar with FMX. So I'm trying to have a TImage display a TBitmap so I see the "exact" original, and I also want the image to resize to the correct dimensions of the bitmap. This is what I have come up with, but it seems overly complicated: procedure DisplayInOriginalSize_AndSizeToFit(const bmp: TBitmap; im: TImage); var ScaleInv: single; begin im.WrapMode := TImageWrapMode.Original; ScaleInv := 1 / im.Scene.GetSceneScale; // ScaleInv:=1/Screen.Displays[0].Scale; im.SetBounds(im.Position.X, im.Position.Y, bmp.Width * ScaleInv, bmp.Height * ScaleInv); im.Bitmap.Assign(bmp); im.Bitmap.BitmapScale := 1; end; The commented line works too for me, but it wouldn't in a multiple-monitor-setting. There must be an easier way to set the exact pixel dimensions of a control. Thanks, Renate