WKInterfaceDevice caching optimization - watchkit

I am trying to cache rendered animations to the apple watch (these are generated at run time). I have saved the frames of each animation as JPEG #1x with compression of 0.1. The sum of all the frames is less then 1.2 MB. I clear the cache before I start caching. However only about half the animations are cached. The documentation says that the cache is 5MB. What am I doing wrong?

If you want to send image data to the Watch programmatically (i.e. not at compile time), WKInterfaceDevice provides two methods:
addCachedImage:name: accepts a UIImage, encodes it as PNG image data, and transmits it to the cache. So, if you create a UIImage from JPEG data, you are actually decoding the JPEG data into an image, then re-encoding it as PNG before it's sent to the cache (thereby negating the effects of JPEG-encoding in the first place).
addCachedImageWithData:name: accepts NSData and transmits the unaltered data directly to the cache. So, if you encode your image to NSData using UIImageJpegRepresentation and pass it to this method, you'll transmit and store less in the cache. I use this technique for all of my images, unless I need the benefits of a PNG image; in that case, I actually encode my own NSData using UIImagePngRepresentation and send it using this method.
For debugging purposes, it's helpful to use the [[WKInterfaceDevice currentDevice] cachedImages] dictionary to find the size of the cached image data. The dictionary returns a NSNumber with the size (in bytes) of the cache entry.

I just discovered that if you use this line of code:
[self.image setImageNamed:#"number"]
Your images should be named:
number1.png
number2.png
number3.png
number4.png
I was running into a similar error when I had my images named:
number001.png
number002.png
number003.png
number004.png

Related

MediaRecorder API chunks as an independent videos

I'm trying to build simple app that would stream video from camera using browser to the remote server.
For the camera access from browser I've found a wonderful WebRTC API: getUserMedia.
Now for the streaming it to the server IIUC the best way would be to use some of the WebRTC_API for transporting and then use some server side library to deal with it.
However, at first I went with a bit different approach:
I've user MediaRecorder based on the stream from camera. And then I was setting the timeslice for the MediaRecorder.start() to be few hundred Ms, e.g. 200. And I had some assumptions in wrt MediaRecorder which are not in sync with what I was observing:
I've observed weird behaviour(wrt to my assumptions about MediaRecorder):
If there was only 1 chunk uploaded to server -> it opens just fine.
If there are multiple chunks -> none of them loads correctly, they give errors: Could not determine type of stream. But then if I use ffmpeg to concat all the chunks - resulting file is fine. Same happens if I'm concatenating the blobs from MediaRecorder.ondataavailable on the client.
Thus the question:
Can the chunks in theory be independent video files? Or it is not what MediaRecorder was designed for? If it is not - then why do we even have the option to give timeslice parameter in its start() method?
Bonus question
If we're setting timeslice comparatively small, e.g. 10ms -> lots of data blobs that are sent to MediaRecorder.ondataavailable are of size 0. Where we can find some sort of guarantees/specs on the minimal timeslice that we can use, so that the data blobs are meaningful?
In the documentation there are the following:
If timeslice is not undefined, then once a minimum of timeslice milliseconds of data have been collected, or some minimum time slice imposed by the UA, whichever is greater, start gathering data into a new Blob blob, and queue a task, using the DOM manipulation task source, that fires a blob event named dataavailable at recorder with blob.
So, my guess is that it is somehow related to some data blobs being of 0 size. What does it "some minimum time slice imposed by the UA" mean?
PS
Happy to provide code if needed. But the question is not about some specific code. It is to get understanding of the assumptions behind the MediaRecorder API and why they are there.
The timeslice parameter does not allow to create independent media chunks; instead, it gives an opportunity to save data (e.g. on the filesystem, or uploaded to a server) on a regular basis, rather than holding potentially large media content in memory.

Download Only A Part of a JPG with HTTP request

With the HTTP header Range clients can request only a certain range of bytes from a server.
GET myfile.jpg HTTP/1.1
"http://myhost"
Range=bytes=1000-1200
If the server supports this response feature and maybe even shows that by a Accept-Range header, the above request will return only the 200 bytes from byte 1000 onwards.
Is it possible to get usable parts from an JPG image with this method? Say the actual JPG measures 800x1197 pixels. What would have to be done in order to request only a sub image between the pixels 200x200 and 400x400?
To me it looks like it's only possible receive horizontally cut slices of the image. But this would already be better than getting the full image file. So in the example above I'd say one could try to download: the slice from 200 (y-axis) to 400 (y-axis) and then crop the result on the client side accordingly.
Assume we already know the content-length of the file as well as its actual image size, which may have been determined by a preceding HTTP request:
content length in bytes: 88073
jpg size: 800x1197
Which byte range would I have to request for this image? I assume that JPG has some meta data, which has to be taken in account as well. Or does the compression of jpg render this attempt impossible? It would be ok if the final cut out does not contain any metadata from the original.
But still it might be necessary to have an initial request, which takes some bytes from the beginning hoping to fetch the metadata. and based on this the actual byte range might be determined.
Would be very nice if someone could give me a hint how to approach this.
JPEG encodes compressed data in one or more scans. The scans do not indicate their length. You have to actually decode to get to the end of the scan. The scans span the entire image.
If the JPEG stream is progressively encoded you can read the stream blocks at at a time, decode the scans, update the output image, and get successively refined views of the image.

IMediaSample(DirectShow) to IDirect3DSurface9/IMFSample(MediaFoundation)

I am working on a custom video player. I am using a mix of DirectShow/Media Foundation in my architecture. Basically, I'm using DS to grab VOB frames(unsupported by MF). I am able to get a sample from DirectShow but am stuck on passing it to the renderer. In MF, I get a Direct3DSurface9 (from IMFSample), and present it on the backbuffer using the IDirect3D9Device.
Using DirectShow, I'm getting IMediaSample as my data buffer object. I don't know how to convert and pass this as IMFSample. I found others getting bitmap info from the sample and use GDI+ to render. But my video data may not always have RGB data. I wish to get a IDirect3DSurface9 or maybe IMFSample from IMediaSample and pass it for rendering, where I will not have to bother about color space conversion.
I'm new to this. Please correct me if I'm going wrong.
Thanks
IMediaSample you have from upstream decoder in DirectShow is nothing but a wrapper over memory backed buffer. There is no and cannot be any D3D surface behind it (unless you take care of it on your own and provide a custom allocator, in which case you would not have a question in first place). Hence, you are to memory-copy data from this buffer into MF sample buffer.
There you come to the question that you want buffer formats (media types) match, so that you could copy without conversion. One of the ways - and there might be perhaps a few - is to first establish MF pipeline and find out what exactly pixel type you are offered with buffers on the video hardware. Then make sure you have this pixel format and media type in DirectShow pipeline, by using respective grabber initialization or color space conversion filters, or via color space conversion DMO/MFT.

High Resolution Capture and Encoding

I'm using two custom push filters to inject audio and video (uncompressed RGB) into a DirectShow graph. I'm making a video capture application, so I'd like to encode the frames as they come in and store them in a file.
Up until now, I've used the ASF Writer to encode the input to a WMV file, but it appears the renderer is too slow to process high resolution input (such as 1920x1200x32). At least, FillBuffer() seems to only be able to process around 6-15 FPS, which obviously isn't fast enough.
I've tried increasing the cBuffers count in DecideBufferSize(), but that only pushes the problem to a later point, of course.
What are my options to speed up the process? What's the right way to do live high res encoding via DirectShow? I eventually want to end up with a WMV video, but maybe that has to be a post-processing step.
You have great answers posted here to your question: High resolution capture and encoding too slow. The task is too complex for the CPU in your system, which is just not fast enough to perform realtime video encoding in the configuration you set it to work.

Base64 string Compression

I have got an ActiveX Control that gets an image from a fingerprint device as base64 string. The Active works great and I could transfer the returned base64 string to the server to be converted to a binary data and then to be saved to a database. I use ASP.NET as server side technology and JavaScript as client side technology. The problem is that the base64 string is tool large and it would take from 30 to 40 seconds for the string to be transferred to the server. My question is: Is there any way to compress this base64 string on client (Browser) and deflate it back on server.
If the base64 image is really a jpeg or some other compressed image format, I wouldn't expect you to be able to get much extra compression out of it in the first place. You'd also need to work out a way of posting the binary compressed data afterwards in a portable way, which may not be terribly easy. (You may be able to pretend it's a file or something like that.)
Just how large is this image? 30 seconds is a very long time...
on my linux system, using the bzip2 utility (which uses burrows-wheeler transform and then compresses), I reduce a jpg encoded in Base64 from 259.6KB to 194.5KB.
Using gzip (which uses an LZ algorithm of some variety), I reduce it to 194.4KB.
So, yes you can compress it. the question is why do you want to? It sounds as though your problems are really lying elsewhere.
Base64 is a format that is usually only used to get around technical limitaions of sending binary data. For example, a base64 string could be used in a GET request, like "website.com/page?q=BASE64ENCODED".
You have two options:
Figure out how to send/recieve binary data in a POST request, then send the data in a different form and convert it appropriately on the server.
-OR-
Since this is a fingerprint device, I assume you're using it as a password, so you actually don't have to send the raw fingerprint data every time. Just make an SHA-1 hash of it, and compare it to a stored hash on the server. This is just as secure and will take a fraction of a second to upload.
Hope I helped!

Resources