Get duration of video with AVFoundation - ios

To get the duration of an AVPlayerItem I could do: player.currentItem.duration.
Instead of this, I could also get the duration from my backend as an Int. Then I can convert this to a Float to be used anywhere I need the duration for. I think this might be better in terms of performance and less work on my end to get the duration.
For example Apple says this about getting duration:
“A vital concept in AV Foundation is that initializing an asset or a
track does not necessarily mean that it is ready for use. It may
require some time to calculate even the duration of an item (an MP3
file, for example, may not contain summary information). Rather than
blocking the current thread while a value is being calculated, you ask
for values and get an answer back asynchronously through a callback
that you define using a block.”
Any thoughts on things that could go wrong if I decide to hardcode the duration by getting it from the server? Is this good practice?

If you already know the value on your backend, and you're already making call to say get the video URL, retrieving the duration seems a reasonable idea.
Although - is there any chance of a mismatch? If you do it client side it's "guaranteed" to be correct.
If you have to make a special call to get it, I wouldn't as it's likely to take much longer than determining it during asset initialisation.

Related

Playwright: how to wait until there is no animation on the page?

I'm trying to figure out how to check whether the page has fully loaded in Playwright. await page.waitForLoadState('networkidle'); doesn't always work for me on Javascript-heavy sites. I've resorted to taking a screenshot base64, waiting 100 ms, taking a new screenshot, and comparing whether those are the same. However this doesn't seem ideal, is there any way to ask Playwright when the last animation frame was redrawn?
There are several options that may help you.
1. Solution 1:
First, you can maybe determine which element is loading last, and then go with
page.waitForSelector('yourselector')
or even wait for multiple selectors to appear
page.waitForSelector('yourselector1','yourselector2')
2. Solution 2
page.waitForLoadState('domcontentloaded')
Because
page.waitForLoadState('networkidle')
by default will wait for network event and if 0.5 seconds nothing is network trafficking it will say, I am no longer need to wait. And that is why you maybe have stohastic beh.
If the given solution doesn't work for you, you can try with locator.
page.locator(selector[, options])
It has multiple api like locator.isDisabled or locator.waitFor([options]) or locator.isVisible([options]) or locator.frameLocator(selector) ....... a lot more.
see the below link here:
https://playwright.dev/docs/api/class-locator

UIImpactFeedbackGenerator impactOccurred Slight Delay

I'm using UIImpactFeedbackGenerator as described in Apple's developer docs, but there seems to be a slight delay -- maybe a tenth of a second or similar -- between when I invoke impactOccurred and when you feel the haptic. This is especially evident when I am playing a sound at the same time - the sound clearly precedes the haptic.
Someone else wrote about the same thing in Apple Developer Forums, but no resolution.
I initialize the UIImpactFeedbackGenerator with:
// Set up impact
UIImpactFeedbackStyle sty = UIImpactFeedbackStyleMedium;
impactFeedbackGen = [[UIImpactFeedbackGenerator alloc] initWithStyle:sty];
Immediately call prepare, and call repeatedly during the few seconds that pass before the impact occurs:
[impactFeedbackGen prepare];
Then finally play the haptic, with:
[impactFeedbackGen impactOccurred];
Not sure if it's related, but I am using UISelectionFeedbackGenerator in the same app, but not at the same time.
Thoughts?
Thanks!
I think the trick with avoiding delay with UIImpactFeedbackGenerator is when to call prepare.
Obviously you can't simply call prepare and then immediate trigger the impact, since the engine needs time to actually prepare.
On the other hand, once prepare is called, the taptic engine will only stay in a prepared state for a short duration (a matter of seconds), in order to conserve power.
It is possible to extend the prepared state by calling prepare multiple times, however you have to be careful here as well, since after a certain threshold, the system will put the engine back to an idle state, and ignore further calls to prepare until after an impact is triggered.

EKAlarms with relativeOffset

I'm currently trying to write a method to compare EKAlarms to one another. The problem with this is between absoluteDate and relativeOffset. Comparing two alarms each with an absoluteDate is easy, but if one or both have a relativeOffset, you need to know what event they're relatively offset from. As per the documentation,
relativeOffset: The offset from the start of an event, at which the alarm fires.
Yet, I see no documentation on setting the trigger for a relativeOffset alarm. Can anyone help me figure out what I'm missing? How can I compare two EKAlarms with relativeOffsets?
Thanks for the help!
As you rightly say:
if one or both have a relativeOffset, you need to know what event they're relatively offset from
Quite so. But how can you possibly not know that? EKAlarms do not float around loose, falling from the sky like snowflakes. If not attached to an EKCalendarItem, a relative EKAlarm is meaningless; there is nothing to compare. If it is attached to an EKCalendarItem, then you clearly know that fact - otherwise, where would you have gotten the alarm from??? Either you just created the alarm, and are about to attach it to an EKCalendarItem yourself, or you have started with the EKCalendarItem and have looked at its alarms property, in which case you also know the EKCalendarItem's startDate and can calculate from there.

Is NSData + (id)dataWithContentsOfURL:(NSURL *)aURL options:(NSDataReadingOptions)mask error:(NSError **)errorPtr: cached automatically?

When I read the section on
NSDataReadingOptions
Options for methods used to read NSData objects.
enum {
NSDataReadingMappedIfSafe = 1UL << 0,
NSDataReadingUncached = 1UL << 1,
NSDataReadingMappedAlways = 1UL << 3,
};
typedef NSUInteger NSDataReadingOptions;
It says that
NSDataReadingUncached
A hint indicating the file should not be stored in the file-system caches.
For data being read once and discarded, this option can improve performance.
Available in OS X v10.6 and later.
Declared in NSData.h.
So I am assuming that by default these URL requests are cached and there is no need to implement NSURLRequest to cache data if I want to use shared global cache ? Is this understanding correct ?
Let me start off by saying that dataWithContentsOfURL:options:error: and its ilk are probably the worst APIs for getting something from network. They are very alluring to developers because they can get a resource from network in a single line of code, but they come with some very pernicious side-effects:
First, they block the thread on which they are called. This means that if you execute this on the main thread (the only thread on which your UI can be updated), then your application will appear frozen to the user. This is a really big 'no no' from a user experience perspective.
Second, you cannot cancel these requests, so even if you put this request on a background thread, it will continue to download even though the data may no longer be useful. For example, if your user arrives on a view controller and you execute this request and the user subsequently decides to hit a back button, that data will continue to download, even though it is no longer relevant.
Bottom line: DO NOT USE THESE APIs.
Please use async networking like NSURLConnection or AFNetworking. These classes were designed to get data efficiently and in a way that doesn't impact the user experience. What's even better is that they handle the specific use case you originally asked: how do I stop it from caching on disk?.
There is no answer to your specific question which refer to the caches managed by the URL loading system.
The reading options in method dataWithContentsOfFile:options:error: refer solely to reading from the file system (please consult to the official documentation of NSDataReadingOptions).
Unfortunately, the documentation gives no hint about the behavior when reading from remote resources. Whether the response is cached in the URL cache is unspecified - that is, we don't know, and the internal behavior and implementation can change with each new OS version.
IMHO, we should generally avoid to use the "convenient methods" to read from remote resources. It appears, these methods work only by "accident" when accessing remote resources. So, I strongly agree with #Wayne Hartman ;)

CAB file API clarification

Since I'm not really seeing any content anywhere that doesn't point back to the original Microsoft documents on this matter, or source code that really doesn't seem to answer the questions I'm having, I thought I might ask a few things here. (Delphi tag is there because that's what my dev environment is on the code I'm making from this)
That said, I had a few questions the API document wasn't answering. First one: fdi_notify messages. What is "my responsibility" is in coding these: fdintCABINET_INFO: fdintPARTIAL_FILE: fdintNEXT_CABINET: fdintENUMERATE: ? I'll illustrate what I mean by an example. For fdintCLOSE_FILE_INFO, "my responsibility" is to Close a file related to handle given me, and set the file's date and time according to the data passed in fdi_notify.
I figure I'm missing something since my code isn't handling extracting spanned CAB files...any thoughts on how to do this?
What you're more than likely running into is that FDICopy only reads the cab you passed in. It will use fdintNEXT_CABINET to get spanned data for any files you extract in response to fdintCOPY_FILE, but it only calls fdintCOPY_FILE for files that start on that first cab.
To get a directory listing for the entire set, you need to call FDICopy in a loop. Every time you get a fdintCABINET_INFO event, save off the psz1 parameter (next cab name). When FDICopy returns, check that. If it's an empty string you're done, if not call FDICopy again with the next cab as the new path.
fdintCABINET_INFO: The only responsibility for this is returning 0 to continue processing. You can use the information provided (the path of the next cabinet, next disk, path name, nad set ID), but you don't need to.
fdintPARTIAL_FILE: Depending on how you're processing your cabs, you can probably ignore this. You'll only see it for the second and later images in a set, and it's to tell you that the particular entry is continued from a previous cab. If you started at the first cab in the set you'll have already seen an fdintCOPY_FILE for the file. If you're processing random .cabs, you won't really be able to use it either, since you won't have the start of the file to extract.
fdintNEXT_CABINET: You can use this to prompt the user for a new directory for the next cabinet, but for simple spanning support just return 0 if the passed in filename is valid or -1 if it isn't. If you return 0 and the cab isn't valid, or is the wrong one, this will get called again. The easiest approach (if you don't request a new disk/directory), is just to check pfdin^.fdie. If it's FDIError_None it's equal the first time being called for the requested cab, so you can return 0. If it's anything else it's already tried to open the requested cab at least once, so you can return -1 as an error.
fdintENUMERATE: I think you can ignore this. It isn't covered in the documentation, and the two cab libraries I've looked at don't use it. It may be a leftover from a previous API version.

Resources