I am implementing a media streaming source in c# windows phone 8 for streaming schoutcast urls.
I can play the buffered stream from the URLs. Now I have to implement seeking over the buffered audio data.
I tried setting forward and backward by 1 seconds from the GUI. Below is the code for rewinding
if(BackgroundAudioPlayer.Instance.CanSeek)
{
TimeSpan position = BackgroundAudioPlayer.Instance.Position;
BackgroundAudioPlayer.Instance.Position = new TimeSpan(0, 0, (int)(position.Seconds - 1));
}
But the player stops for long time and starts playing.
I think I have to implement the following method found in Media Stream Source implementation.
protected override void SeekAsync(long seekToTime)
{
ReportSeekCompleted(seekToTime);
}
I would like to know how to implement forward and backward seeking using Media Streaming Source without the delay?
Related
Is it possible to create a cache for hls type videos when playing in exoplayer , so that once video completely streamed then no need to load again, and start playing immediately for the next time when play button clicked, If possible please provide any solution? The video format is .m3u8 type.
For non ABR streams, i.e. not HLS or DASH etc
There is a well used library which provides video caching functionality:
https://github.com/danikula/AndroidVideoCache
Bear in mind that large videos will use a lot of memory so you may want to consider when and where you want to cache.
Update for ABR streams
Adaptive Bit Rate Streaming protocols like HLS or DASH typically have segmented multiple bit rate versions of the video, and the player will download the video segment by segment, choosing the bitrate for the next segment depending on the network conditions and the device capabilities.
For this reason, simply storing what you are viewing may not give you the result you want - for example if you have some network congestion part way through the video you may receive lower quality segments, which you probably don't want for a video you will watch multiple times.
You can download or play a video, forcing the stream to always select from one specific resolution by using a track selector. ExoPlayer documentation includes some info here:
https://exoplayer.dev/downloading-media.html
In an older blog post (2 years old but the DownloadHelper part is still relevant, I think), Google provide info on how to use the DownloadHelper - https://medium.com/google-exoplayer/downloading-adaptive-streams-37191f9776e.
This includes the example:
// Replace with HlsDownloaderHelper or SsDownloadHelper if the stream is HLS or SmoothStreaming
DownloadHelper downloadHelper =
new DashDownloadHelper(manifestUri, manifestDataSourceFactory);
downloadHelper.prepare(
new Callback() {
#Override
public void onPrepared(DownloadHelper helper) {
// Preparation completes. Now other DownloadHelper methods can be called.
List<TrackKey> trackKeys = new ArrayList<>();
for (int i = 0; i < downloadHelper.getPeriodCount(); i++) {
TrackGroupArray trackGroups = downloadHelper.getTrackGroups(i);
for (int j = 0; j < trackGroups.length; j++) {
TrackGroup trackGroup = trackGroups.get(j);
for (int k = 0; k < trackGroup.length; k++) {
Format track = trackGroup.getFormat(k);
if (shouldDownload(track)) {
trackKeys.add(new TrackKey(i, j, k));
}
}
}
}
DownloadAction downloadAction = downloadHelper.getDownloadAction(null, trackKeys);
DownloadService
.startWithAction(context, MyDownloadService.class, downloadAction, true);
}
private boolean shouldDownload(Format track) {...}
#Override
public void onPrepareError(DownloadHelper helper, IOException e) {...}
});
The code above look at the manifest file - this is the index file for DASH or HLS which lists the individual tracks and provides info, e.g. URLs, of there to find them.
It loops through each track that it finds and calls a function which you can define as you want to decide whether to include or exclude this track from the download.
To use track selection when playing back a streamed video, you can control this programatically using the DefaultTrackSelector: https://exoplayer.dev/track-selection.html. This link includes an example to select SD video and German Audio track:
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setMaxVideoSizeSd()
.setPreferredAudioLanguage("deu"));
The standard player also allows a user select the track from the controls if you are displaying controls - the ExoPlayer demo app () includes this functionality and the user view should look something like:
One note - ABR streaming is quite complex and requires extra processing and storage on the server side. If you expect to only use one quality level then it may make more sense to simply stream or download the videos as mp4 etc.
I am using a periodicTimeObserverForInterval to update a plot to reflect my current audio waveform. This works great and has been giving me no trouble. It stays in sync with pausing and starting. However, when I tried to introduce arbitrary seeking into my code, the waveform visual becomes out of sync with the playing audio. This doesn't make sense to me unless the time sent to my observer is wrong after calling the seek function.
// timeScale = 22050 = sampleRate
let timeScale = self.player.currentItem.asset.duration.timescale;
self.player.seekToTime(CMTimeMakeWithSeconds(Float64(time), timeScale), toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero, completionHandler: {
(Bool) -> Void in
self.player.play();
});
I can't figure out why this function is causing the visual to get out of sync.
We have been working on a streaming application for raw H.264 and AAC content. We are using MediaStreamSource to feed samples to MediaElement and observe no issues when we use PC SilverLight (on IE9) for audio/video playback. Audio-only stream also works fine on WP7. However, we face following problems with video playback on WP7:
•When video stream attribute for MediaStreamSource is initialized without CodecPrivateData, MediaElement "Failed" event handler is called with error code 3100. Video Stream attribute is initialized as:
Dictionary<MediaStreamAttributeKeys, string> videoStreamAttributes = new Dictionary<MediaStreamAttributeKeys, string>();
videoStreamAttributes[MediaStreamAttributeKeys.VideoFourCC] = "H264";
this.videoStreamDescription = new MediaStreamDescription(MediaStreamType.Video, videoStreamAttributes);
•When video stream attribute for MediaStreamSource is initialized with CodecPrivateData ([start code] [sps] [startcode] [pps]) the video plays but seems to be playing at a much faster rate - 2 to 3 times the specified FPS. Video Stream attribute is initialized as:
Dictionary<MediaStreamAttributeKeys, string> videoStreamAttributes = new Dictionary<MediaStreamAttributeKeys, string>();
videoStreamAttributes[MediaStreamAttributeKeys.VideoFourCC] = "H264";
videoStreamAttributes[MediaStreamAttributeKeys.CodecPrivateData] = "000000012742000D96540A0FD8080F162EA00000000128CE060C88";
this.videoStreamDescription = new MediaStreamDescription(MediaStreamType.Video, videoStreamAttributes);
Note that the same streams play fine on PC SilverLight with and without CodecPrivateData with audio as well as video.
Is there something wrong in which video stream attribute is initialized? What could be causing this problem and how can we resolve it?
Regards,
NKS.
The problem here was the clock that was being used for the timestamp. Our application used to calculate the timestamp as per 90Khz, the expected timestamp was in terms of 1 Mhz. So all the frames appeared after the time was elapsed and hence the player would play the frames as fast as it could (I had seen something around 120 fps also). after fixing the timestamp clock, it works fine
I am recording audio using the XNA Microphone class and saving the recorded data in isolated storage in wav format.If the length of audio is small my app is working fine.But as it increases the memory consumed by the app also increases,which drastically slows down the device.The following code is used to play the audio
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = isoStore.OpenFile(AudioFilePath, FileMode.Open))
{
sound = SoundEffect.FromStream(FileStream);
sound.Play();
}
}
Any suggestion on how to handle the memory issue while playing large audio files.Or how can i save the PCM in other formats (wma,mp3) to reduce the size.
SoundEffect isn't intended for playing long pieces of audio. As the name suggests it is intended for short pieces and also playing lots of them, possibly at the same time.
To play longer pieces of audio you shoudl consider the MediaElement.
i'm currently reading the documentation of MSDN to render a stream to an audio renderer..
or in other word, to play my captured data from microphone.
http://msdn.microsoft.com/en-us/library/dd316756%28v=vs.85%29.aspx
this example provides example.
My problem now is that i couldn't really understand the project flow.
I currently have a different class storing the below parameters which i obtained from the capture process.
these parameters will be continuously re-written as the program captures streaming audio data from the microphone.
BYTE data;
UINT32 bufferframecount;
DWORD flag;
WAVEFORMATEX *pwfx;
My question is,
How does really the loadData() function works.
is it suppose to grab the parameter i'm writing from capture process?
how does the program sends the data to audio renderer, and play it in my speaker.
The loadData() function fills in audio pointed to by pData. The example abstracts the audio source, so this could be anything from a .wav file to the microphone audio that you already captured.
So, if you are trying to build from that example, I would implement the MyAudioSource class, and have it just read PCM or float samples from a file, whenever loadData() is called. Then, if you run that program, it should play the audio from the file out the speaker.