I would like to playback buffered audio samples with variable speed, forward or reverse.
I'm aware of the isReversed attribute of AudioPlayer but am not succeeding in playing sounds in reverse.
Can anyone point me to an example or a hint?
This can be achieved via the reverse method of a buffer:
myBufferReversed = myBuffer.reverse()
Then, a player instance can be set to use myBufferReversed instead.
I believe but have not confirmed that this can also be achieved by setting the isReversed attribute to true as described on this wiki page:
https://github.com/AudioKit/AudioKit/wiki/AudioPlayer
Related
I'm using AVCaptureSession to record a video with audio. Everything seems to work properly for short videos, but for some reason, if I record a video that is longer than about 12 seconds, the audio doesn't work.
Edit (because this answer is still getting upvotes): This answer works to mitigate the problem but the likely root cause for the issue is addressed in #jfeldman's answer.
I found the solution as an answer to a completely different question.
The issue is the movieFragmentInterval property in AVCaptureMovieFileOutput.
The documentation for this property explains what these fragments are:
A QuickTime movie is comprised of media samples and a sample table
identifying their location in the file. A movie file without a sample
table is unreadable.
In a processed file, the sample table typically appears at the
beginning of the file. It may also appear at the end of the file, in
which case the header contains a pointer to the sample table at the
end. When a new movie file is being recorded, it is not possible to
write the sample table since the size of the file is not yet known.
Instead, the table is must be written when recording is complete. If
no other action is taken, this means that if the recording does not
complete successfully (for example, in the event of a crash), the file
data is unusable (because there is no sample table). By periodically
inserting “movie fragments” into the movie file, the sample table can
be built up incrementally. This means that if the file is not written
completely, the movie file is still usable (up to the point where the
last fragment was written).
It also says:
The default is 10 seconds. Set to kCMTimeInvalid to disable movie
fragment writing (not typically recommended).
So for some reason my recording is getting messed up whenever a fragment is written. I just added the line movieFileOutput.movieFragmentInterval = kCMTimeInvalid; (where movieFileOutput is the AVCaptureMovieFileOutput I've added to the AVCaptureSession) to disable fragment writing, and the audio now works.
We also experienced this issue. Basically disabling movie fragment writing will work but it doesn't actually explain the issue. Most likely you are recording to an output file using a file extension that does not support this feature, like mp4. If you pass an output file with the extension mov you should have no issues using movie fragment writing and the output file will have audio.
Updating videoFileOutput.movieFragmentInterval = kCMTimeInvalid solved this for me.
However, I accidentally set the movieFragmentInterval after calling startRecordingToOutputFileURL. An agonizing hour later I realized my mistake. For newbies like me, note this obvious sequence.
videoFileOutput.movieFragmentInterval = kCMTimeInvalid
videoFileOutput.startRecordingToOutputFileURL(filePath, recordingDelegate: recordingDelegate)
kCMTimeInvalid is now deprecated. This is how to assign it now:
videoFileOutput?.movieFragmentInterval = CMTime.invalid
From the player documentation: "When the player first loads a video, it will broadcast an unstarted (-1) event."
What's the intended use of this event? That is, what would my host code do differently, as a consequence of seeing it, than it would if the state didn't exist? The example code I've seen does nothing but log it.
I don't imagine that it's very useful. I don't think there's some deeper truth that you're missing out on. I assume it reflects a state that's mainly used internally by the player itself and it was exposed in the API for the sake of completeness.
Might be a good way to detect if autoplay is enabled. I.e. "unstarted" would happen on platforms that don't support autoplay but was attempted, but "playing" would be the event for other systems.
I've been finding the -1 tripping up some of my logic so decided to just ignore it and hope for the best.
I actually see a sequence of -1, 3, -1 with less than 1ms between each event. So if your logic depends any sort of state machine transitions between states you may need to consider that.
Also watch out for this if you explicitly use stopVideo()
Important: Unlike the pauseVideo function, which leaves the player in
the paused (2) state, the stopVideo function could put the player into
any not-playing state, including ended (0), paused (2), video cued (5)
or unstarted (-1).
Generally you should use pauseVideo() which according to this won't result in -1.
I'm trying to figure out how I can specify a custom end time for an embedded YouTube video. I know that I can customize the start time by adding &start=30, but I haven't seen anything relating to the end time.
I need to be able to do this for a web app I'm building, so if there is no way provided by YouTube, how might I be able to accomplish this anyway?
I've skimmed over the documentation to no avail. Thanks!
I just found out that the following works:
https://www.youtube.com/embed/[video_id]?start=[start_at_second]&end=[end_at_second]
Note: the time must be an integer number of seconds (e.g. 119, not 1m59s).
I tried the method of #mystic11 ( https://stackoverflow.com/a/11422551/506073 ) and got redirected around. Here is a working example URL:
http://youtube.googleapis.com/v/WA8sLsM3McU?start=15&end=20&version=3
If the version=3 parameter is omitted, the video starts at the correct place but runs all the way to the end. From the documentation for the end parameter I am guessing version=3 asks for the AS3 player to be used. See:
end (supported players: AS3, HTML5)
Additional Experiments
Autoplay
Autoplay of the clipped video portion works:
http://youtube.googleapis.com/v/WA8sLsM3McU?start=15&end=20&version=3&autoplay=1
Looping
Adding looping as per the documentation unfortunately starts the second and subsequent iterations at the beginning of the video:
http://youtube.googleapis.com/v/WA8sLsM3McU?start=15&end=20&version=3&loop=1&playlist=WA8sLsM3McU
To do this properly, you probably need to set enablejsapi=1 and use the javascript API.
FYI, the above video looped: http://www.infinitelooper.com/?v=WA8sLsM3McU&p=n#/15;19
Remove Branding and Related Videos
To get rid of the Youtube logo and the list of videos to click on to at the end of playing the video you want to watch, add these (&modestBranding=1&rel=0) parameters:
http://youtube.googleapis.com/v/WA8sLsM3McU?start=15&end=20&version=3&autoplay=1&modestBranding=1&rel=0
Remove the uploader info with showinfo=0:
http://youtube.googleapis.com/v/WA8sLsM3McU?start=15&end=20&version=3&autoplay=1&modestBranding=1&rel=0&showinfo=0
This eliminates the thin strip with video title, up and down thumbs, and info icon at the top of the video. The final version produced is fairly clean and doesn't have the downside of giving your viewers an exit into unproductive clicking around Youtube at the end of watching the video portion that you wanted them to see.
Use parameters(seconds) i.e. youtube.com/v/VIDEO_ID?start=4&end=117
Live DEMO:
https://puvox.software/software/youtube_trimmer.php
Youtube doesn't provide any option for an end time, but there alternative sites that provide this, like
Tubechop. Otherwise try writing a function that either pauses video/skips to next
when your when your video has played its desired duration.
OR: using the Youtube Javascript player API, you could do something like this:
function onPlayerStateChange(evt) {
if (evt.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
Youtube API blog
Today I found, that the old ways are not working very well.
So I used:
"Customize YouTube Start and End Time - Acetrot.com"
from http://www.youtubestartend.com/
They provide a link into
https://xxxx.app.goo.gl/yyyyyyyyyy
e.g. https://v637g.app.goo.gl/Cs2SV9NEeoweNGGy9
Link contain forward to format like this
https://www.youtube.com/embed/xyzabc123?start=17&end=21&version=3&autoplay=1
I was just trying to look up how and found there is a CLIP feature now added by Youtube right under the video that I had never noticed before!
I use this signature:
youtube.com/embed/[YOUR_VIDEO_ID]?start=[TIME_IN_SEC]&end=[TIME_IN_SEC]&autoplay=1
https://www.youtube.com/embed/2EWejmkKlxs?start=1230&end=1246&autoplay=1
I have an HTML5 video player with a custom seek bar, that's working great on the iPhone (playing inline) and on the browser.
It plays great on the iPad too and the seek bar is updated as the movie plays, but for some reason, I can't seek.
All of the values are correct and I'm trying to set:
myPlayer.currentTime = XX;
Unfortunately, the iPad refuses to set the .currentTime attribute.
From what I can gather the difference between the browser and iPad is that on the browser I get:
myPlayer.networkState = 3
myPlayer.readyState = 4
On the iPad I get:
myPlayer.networkState = 2
myPlayer.readyState = 3
It's exactly the same code, running a local MP4 video.
Any idea why this is happening?
Cheers,
Andre
I've had all kinds of problems getting JavaScript to control audio elements, and a lot of frustration with the currentTime property, along with Apple's restrictions on what constitutes direct user initiation of events.
It wouldn't surprise me if there were some kind of weird bug with JavaScript & HTML5 video playback on the iPad (or "feature" that's undocumented), which requires a workaround. From my experience, the iPad has a unique way of doing things than what's in the official documentation.
You should check the error, buffered, seekable, and seeking properties of the video element. Looking at your readyState & networkState values, the iPad seems to think that the video has not been completely loaded - which is odd for a local resource.
buffered and seekable should be equal to the time range of your entire video. seeking should be TRUE. That should at least give you a little more information about the problem.
Have you tested it with other videos? It might be that there is some kind of encoding problem with the video that the iPad has a problem with.
Other than that - there was a bug in a previous iPad OS version that broke the ability to set the currentTime property. Are you using the latest OS version?
This issue is related with value used on the video.currentTime property. On my specific case I fixed the problem by always making sure I was using floating point numbers with 1 decimal digit during the seek.
Setting video.currentTime to ZERO on iOS 3.2 will indeed seek the video to the beginning but the value won't update after that - timeupdate event is still dispatched normally but if you try to read currentTime it will always return the same value.
To seek to the begin of the video use 0.1 instead of 0, to seek to 12.2345 use 12.2.
PS: you can use (+(12.2345).toFixed(1)) to limit the number of decimal digits to 1.
Kyle's answer is a good one. I would add, you can't assume the seekable attribute is filled in after any particular event. This means you can't wait for events like loadedmetadata, canplay, or any other and assume that you're able to set currentTime safely at that point.
It seems the safest way to do it is to check seekable after every video-related event, and if it encompasses the time you want to seek to, set currentTime at that point. On iPad, seekable may not be filled until after the canplaythrough event, which is quite late.
See my blog post for more on this.
I am having the same issue - here are the properties in my case:
UIWebView - iPad Simulator
duration=4.861666679382324
startTime=0
currentTime=4.861666679382324
buffered(1)=[0-0]
seekable(0)=
seeking=false
error=null
readystate=4
networkstate=3
Chrome:
duration=4.9226298332214355
startTime=0
currentTime=4.9226298332214355
buffered(1)=[0-4.9226298332214355]
seekable(1)=[0-4.9226298332214355]
seeking=false
error=null
readystate=4
networkstate=1
so - nothing is getting buffered and nothing is seekable. i am playing a local clip from the resources directory of an iPad bundle, via a UIWebView.
In my case, all i need is to reset to the top of the video after each play, and I was able to accomplish this via a call to "load()"
Using the youtube javascript api (http://code.google.com/apis/youtube/js_api_reference.html), I am trying to allow a user to embed a video into some content he creates in my app. I have gotten everything working, except for being able to detect and handle the case that embedding is not allowed for the video.
Currently, the player loads and shows a thumbnail of the disallowed video, and it only gives an error once the user tries to play it. This is bad because the user may not play the video before saving / sending his content. I would like to preemptively detect that the video is not allowed to be embedded, and display a helpful message to the user.
The only solution I can see is to actually play it (programmatically) and handle the error that is raised at that point.
Existing workaround:
Embed player (embedSWF)
onYouTubePlayerReady(): add onError onStateChange event listeners.
onStateChange(newState): when the video finishes loading, try to play it.
e.g. if (newState == 5 /* CUED */) { player.mute(); player.playVideo(); player.stopVideo(); player.unMute(); }
onError(error): if the video failed to play in onStateChange, will receive error here.
Is there a better way?
Thanks!
-Rob
You can grab the JSON feed for that video entry before you embed it and see if "yt$format":5 exists, which is the embed SWF. It won't be there if embedding is disabled.
http://gdata.youtube.com/feeds/api/videos/video_id?v=2&alt=json-in-script
I think that you might be looking for the videoSyndicated or the videoEmbeddable parameter. The API documentation says:
videoEmbeddable
The videoEmbeddable parameter lets you to restrict a search to only videos that can be embedded into a webpage. If you specify a value for this parameter, you must also set the type parameter's value to video.
Reference: https://developers.google.com/youtube/v3/docs/search/list#videoEmbeddable
videoSyndicated
The videoSyndicated parameter lets you to restrict a search to only videos that can be played outside youtube.com. If you specify a value for this parameter, you must also set the type parameter's value to video.
Reference: https://developers.google.com/youtube/v3/docs/search/list#videoSyndicated
Example Call
With both:
GET https://www.googleapis.com/youtube/v3/search?&part=snippet,statistics&videoSyndicated=true&videoEmbeddable=true&key=${yourKey}
I know this isn't directly to the question, but in case someone using PHP stumbles upon this problem, there's a method getNoEmbed() in a Zend_Gdata_YouTube_VideoEntry.
Taken from the docs:
If the return value is an instance of Zend_Gdata_YouTube_Extension_NoEmbed, this video cannot be embedded.