How to use MTLBlitCommandEncoder for copying interlaced video fields into a MTLBuffer - swift

We are working with interlaced HD video. The metal color attachment I use for rendering has the dimensions of one field (1920*540 RGBA).
When I try to copy two rendered fields into the same MTLBuffer that has the size of 1920*1080*4 = 8294400 bytes it works only if the destination offset is zero.
let commandBuffer = commandQueue.makeCommandBuffer()
let blitEncoder = commandBuffer.makeBlitCommandEncoder()
blitEncoder.copy(from: attachmentTexture,
sourceSlice: 0,
sourceLevel: 0,
sourceOrigin: MTLOriginMake(0, 0, 0),
sourceSize: MTLSizeMake(attachmentTexture.width, attachmentTexture.height, 1),
to: destinationBuffer,
destinationOffset: 1920*4,
destinationBytesPerRow: 1920*4*2,
destinationBytesPerImage: destinationBuffer.length)
blitEncoder.endEncoding()
commandBuffer.commit()
For the first field where the destination offset is zero the function works well. The destination buffer is filled for every second row.
But when I want to write the second field with the same code into the same MTLBuffer object only with the destinationOffset set to 1920*4 like you see in the code above (to start with the second row in the buffer) then I get an assertion like this:
-[MTLDebugBlitCommandEncoder validateCopyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:options:]:677:
failed assertion `totalBytesUsed(8302080) must be <=
destinationBuffer length.'
The totalBytesUsed are exactly the destination buffer length in bytes plus the offset. So every offset I use in this function will result in this assertion error.
Can someone explain me how to use this function correctly because the other way around like creating two MTLTexture objects (odd and even fields) for an incoming video frame works well with similar parameters.

I ran into something like this recently, too.
You're passing destinationBuffer.length to the destinationBytesPerImage: parameter. As you've noticed, Metal is adding together the offset and the bytes-per-image value and comparing that against the length of the to: destination buffer (destinationBuffer). It's noticing that offset plus bytes-per-image won't fit into the buffer and refusing to accept that.
You may be able to simply pass 0 for destinationBytesPerImage:, since you're not working with a 3D or 2D array texture. If that doesn't work, pass destinationBuffer.length - 1920*4.

Related

Reading STEP file into Open Cascade loses size information

I'm working on reading a STEP file into my C++ application, translating it into OCCT shapes, and displaying them using VTK. Everything seems to be working fine EXCEPT the scale. The shape I'm importing is just under 20 mm in diameter according to a 3D viewer (which matches what it was when I exported it from my app), but when I import it, it displays as the expected shape but at just under 20 meters in diameter. The program uses meters internally; OCCT appears to be ignoring units during import.
My program runs the following on initialization:
STEPControl_Controller::Init();
Interface_Static::SetCVal("xstep.cascade.unit","M");
The import code is:
STEPControl_Reader rdr;
IFSelect_ReturnStatus ret = rdr.ReadFile(filname);
if (ret == IFSelect_RetDone)
{
int navail = rdr.NbRootsForTransfer();
debugPrint("Found ",std::to_string(navail)," roots available");
int nroots = rdr.TransferRoots();
debugPrint("Transferred ",std::to_string(nroots)," roots");
TopoDS_Shape s = rdr.OneShape();
// Process the returned shape for display after this...
}
I've tried changing the value of "xstep.cascade.unit", and it has no effect on the size of the imported shape. It works as expected when exporting OCCT shapes to a STEP file, but not importing. Is there some parameter or initialization step I'm missing? We're using OCCT version 7.6.0.
ADDENDUM: I did check inside the STEP file, and the units are recorded with lines like:
#68 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
So it shouldn't be a matter of not knowing what it's translating from.

How to generate grayscale bitmap image using HEX data in XML on MacOS (Swift)

I have image source in XML format (the image size is variable therefore I will need to change the image placeholder size). The image source is individual pixel data written in HEX format as string. It is grayscale BMP image data (without header).
I would like to know how to work with the data in order to be able to convert the text HEX pixel data into an image to be displayed in MacOS app using Xcode and Swift.
I have achieved similar thing years back using Action Script for AIR app.
The image source can look like:
<Signature t="8209">000200010000000203435A4B03000000C8010205410....
So first thing is to convert the text HEX string into actual binary data, in Action Script I have used this code (part of cycle to read the whole known length of image data):
var pixelData:uint = parseInt(imgdata.substr((j-1)*2,2),16);
In this example, part of the "signature" XML key is also information about the actual image size, so I would like to be able to change the image size based on that data and be safe not to over/under run the byte stream length needed for the actual image.
So the whole looping through the image pixel data and constructing byte array with alpha, red, green, blue values looked like:
var bx2:ByteArray = new ByteArray();
if(img2_w!=0){
for (var j:Number = 0; j <imgdata.length / 2; j++)
{
var pixelData:uint = parseInt(imgdata.substr((j-1)*2,2),16);
bx2.writeByte(255);
bx2.writeByte(pixelData);
bx2.writeByte(pixelData);
bx2.writeByte(pixelData);
}
}
then it was about linking the byte array image data to the image itself:
var b_image1:ByteArray = new ByteArray();
var bmd_image1:BitmapData = new BitmapData(img1_w,img1_h, false, 0xFFCC00);
//getting the parsed XML data off selected item in the displayed grid - P6Grid
b_image1 = sigData[P6Grid.selectedIndex].sig1;
b_image1.position=0;
bmd_image1.setPixels(bmd_image1.rect,b_image1);
//reference to the visual component placed on the UI
img_sn1.source = bmd_image1;
Would anyone know how to do this using Swift and Xcode on MacOS app. Currently I am using sotory boards and figured out how to handle the file drop, check if that is XML document and parse the key values, so I can get to the XML data, but don't know how to turn them into the image.
Many thanks for your thoughts,
JendaDH

Fastest way to see which pixel has changed when using a listener

I am trying to get EDS spectra on every scanned pixel using STEM.
I am using the EDSStartAcquisition( 2048, 10,fexposure*2, 1) command and
I have attached the following simple listener object into the shown 1D spectrum image:
string messagemap = "data_value_changed:MyImageAction"
Class MyListenerClass1
{
String event_desc;
MyListenerClass1(Object self); //Result("\n");
~MyListenerClass1(Object self);// Result("\n");
Void MyImageAction(Object self, Number e_fl, Image Img)
{
ImageGetEventMap().DeconstructEventFlags( e_fl, event_desc )
Result(GetTime(1)+": Image message : " + event_desc + " 0x" + Binary(e_fl) + "\n" )
}
}
ListenerID1 = EDSIm.ImageAddEventListener( Listener1, messagemap)
Since speed is the issue here, I figured to try the continuous mode of the EDS acquisition. But then I would need to listen which counts belong to each scanned pixel. The following topic (How to getting acquired frames at full speed ? - Image Event Listener does not seem to be executing after every event) shows how to listen to the last pixel change of an image. But what would be the fastest way to directly see which slice of the 1D spectrum has changed on every event? Without going through every slice...
thanks in advance!
An images' data_value_changed is fired whenever a) an image locker (the object that ensures there is single access to the memory) is released, or b) a specific update-call is made in the code.
As such, when a cumulative EDS spectrum is acquired, the whole array gets "locked", then modified (on one or more positions) and then 'updated'. There is no specific information carried on where the array was modified.
Therefore, the only way to find out where the spectrum changed is by comparing a copy of the "before" with the "now" - which is not super efficient.

Cannot identify image file io.BytesIO on raspberry Pi using PiCamera library and PIL

I am having trouble using the output from PiCamera capture function (directed in a BytesIO stream) and opening it using the PIL library. Here is the code (based on the PiCamera basic examples):
#Camera stuff
camera = PiCamera()
camera.resolution = (640, 480)
stream = io.BytesIO()
sleep(2)
try:
for frame in camera.capture_continuous(stream, format = "jpeg", use_video_port = True):
frame.seek(0)
image = Image.open(frame) //THIS IS WHERE IS CRASHES
#OTHER STUFF THAT IS NON IMPORTANT GOES HERE
frame.truncate(0)
finally:
camera.close()
stream.close()
The error is : PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0xaa01cf00>
Any help would be greatly appreciated :)
Have a nice day!
The problem is simple but I am wondering why the io library works that way.
One simply needs to seek back the stream to 0 after truncating it or seek to 0 and then simply call truncate with no parameter (all after you are done opening the image). Like so:
for frame in camera.capture_continuous(stream, format = "jpeg", use_video_port = True):
stream.seek(0)
image = Image.open(stream)
#Do stuff with image
stream.seek(0)
stream.truncate()
Basically when you open the image and do some operation on it, the pointer of the BytesIO can move around and end up somewhere else than the zero position. After that when you call truncate(0) it does not move the pointer back to zero as I thought it would (seems logical to me to move the pointer back to where the truncation occurs). When to code runs once more, the capture writes in the stream but this time it does not start writing at the beginning and everything breaks after that.
Hope this can help someone in the future :)

Create a certain size file and filled with no data on iOS

I'm developing an iphone app, I need to create a certain size file on filesystem and filled with NO data first, then seek to a offset and write data when get data from somewhere else
How can I do it?
The lseek BSD function is explicitly capable of that.
man lseek:
The lseek() function allows the file offset to be set beyond the end of the
existing end-of-file of the file. If data is later written at this point,
subsequent reads of the data in the gap return bytes of zeros (until data is
actually written into the gap).
NSMutableData or fseek is probably what you want