iOS video edge down--cache play data stream

Source: Internet
Author: User

To achieve the video edge of the broadcast, where the side of the next broadcast is not a separate sub-thread to download, but the video playback of the data to save to local. In short, it is the traffic that is used once, which plays both video and video.

用到的框架:<AVFoundation/AVFoundation.h>用到的播放器:AVplayer

First of all, let's talk about the principle of avplayer itself, when we set the player URL and other parameters, the player will send a request to the server where the URL is located (the request parameter has two values, an offset offset, and the length of the other, is actually equivalent to Nsrange ), the server returns data to the player based on the range parameter. This is the general principle, of course, the actual process is slightly more complex.

Below to enter the theme product requirements:
    • 1. Support all functions of normal player, including pause, play and drag

    • 2. If the video load is complete and complete, save the video file to the local cache, play the video in the local cache the next time, and no longer request network data

    • 3. If the video is not loaded (halfway down or dragged) it is not saved to the local cache
      <br/>

      Implementation scenarios:
    • 1. Need to add a layer of agent-like mechanism between the video player and the server, the video player no longer directly access the server, but instead access the proxy object, the proxy object to access the server to obtain data, and then return to the video player, while the proxy object according to a certain policy cache data.

    • 2.AVURLAsset in the Resourceloader can implement this mechanism, Resourceloader delegate is the above proxy object.

    • 3. The video player first detects if the video is in the local cache before it starts playing, and if it does not get the data through the proxy, then directly plays the video in the local cache.
      <br/>

      What the video player needs to achieve
    • 1. There is a start pause button

    • 2. Show playback progress and total duration

    • 3. You can start video playback from any position by dragging

    • 4. The process and load failures in video loading need to be prompted accordingly
      <br/>

      Functions that the proxy object needs to implement
    • 1. Receive the request from the video player and request the data not obtained locally from the server according to the requested range

    • 2. Cache the data requested back to the server locally

    • 3. If an error occurs to the server request, you need to notify the video player so that the video player can prompt the user

<br/>

Specific flowchart
 

Video player Processing flow

    • 1. When the video starts playing, the video URL determines whether the current video is already cached in the local cache, and if so, plays the video directly in the local cache

    • 2. If there is no video in the local cache, the video player requests data from the proxy

    • 3. Show the prompt that is loading when the video is loaded (mum to go)

    • 4. If the video can play properly, remove the load prompt, play the video, if the load fails, remove the load prompt and display the failure prompt

    • 5. If the data is not played when the network is too slow or dragged during playback, go to step 4th to show the loading prompt.

<br/>

Agent Object Processing Flow

    • 1. When the video player requests Datarequest to the proxy, determine if the agent has initiated a request to the server, and if not, initiate a request to download the entire video file

    • 2. If the agent has established a link with the server, determine if the current Datarequest request is offset greater than the offset of the currently cached file, or cancel the current request to the server if it is greater than and initiate a request from offset to the end of the file (this should be the case when the player is dragged backwards and the cached data is exceeded)

    • 3. If the offset of the current datarequest request is less than the offset of the file that has been cached, and is greater than the offset of the range that the agent requests from the server, a portion of the cached data can be passed to the player. This part of the data is returned to the player (this should be because the player is dragged forward, the requested data has been cached before it appears)

    • 4. If the offset of the current datarequest request is less than the offset of the range requested by the agent to the server, cancel the current request to the server and initiate the request from offset to the end of the file (this should be due to the player dragging forward, And the cached data is exceeded)

    • 5. Whenever the agent re-initiates a request to the server, it causes the cached data to be disjoint, then the cached data is not placed in the local cache after the load is completed

    • 6. If the proxy and server link times out, retry once, and notify the player of the network error if it is still an error

    • 7. If the server returns another error, the agent notifies the player that the network error

The difficulty of Resourceloader treatment
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest{    [self.pendingRequests addObject:loadingRequest]; [self dealWithLoadingRequest:loadingRequest]; return YES;}

The data request from the player starts here, we save all requests sent from here to the array, handle the requests ourselves, and when a request is complete, issue a finishloading message to the request and remove it from the array. Normally, when the player makes the next request, the last request is given to finish.

The following method sends a request stating that the player has shut down the request, that we do not need to process the request, and that each time the system ends an old request, one or more new requests are made, and the request will not be initiated until the player has obtained complete data for the entire video.

- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest{    [self.pendingRequests removeObject:loadingRequest];}

The following approach is to populate the data with requests made by the player

- (BOOL) Respondwithdataforrequest: (Avassetresourceloadingdatarequest *) datarequest{LongLong Startoffset = Datarequest. Requestedoffset;if (datarequest. currentoffset! =0) {Startoffset = Datarequest. Currentoffset; }if ((Self. Task. Offset +Self. Task. Downloadingoffset) < Startoffset) {NSLog (@ "NO DATA for REQUEST");ReturnNO; }if (Startoffset <Self. Task. Offset) {ReturnNO; }NSData *filedata = [NSData datawithcontentsofurl:[Nsurl Fileurlwithpath:_videopath] Options:Nsdatareadingmappedifsafe Error:NIL];This is the total data we have a from startoffset to whatever had been downloaded so farNsuinteger unreadbytes =Self. Task. Downloadingoffset-((Nsinteger) Startoffset-Self. Task. offset);Respond with whatever is available if we can ' t satisfy the request fully yetNsuinteger Numberofbytestorespondwith = MIN ((Nsuinteger) datarequest.requestedlength, unreadbytes); [Datarequest respondwithdata:[filedata subdatawithrange:NSMakeRange (nsuinteger) startoffset-self.task.offset, (nsuinteger) numberofbytestorespondwith)]; long long endoffset = startoffset + DataRequest.REQUESTEDLENGTH; bool didrespondfully = (self.offset + self.task.downloadingoffset) >= Endoffset; return didrespondfully;}           

This is the array that holds all the requests to be processed

- (void) processpendingrequests{Nsmutablearray *requestscompleted = [Nsmutablearray array];Array of request completionEach time a piece of data is downloaded is a request, put these requests into an array, iterate over the arrayfor (Avassetresourceloadingrequest *loadingrequestin self.pendingRequests) {[ Span class= "Hljs-keyword" >self fillincontentinformation:loadingrequest//for each request plus length, file type and other information bool didrespondcompletely = [self respondwithdataforrequest:loadingrequest.dataRequest]; //determine if the data for this request is handled completely if (didrespondcompletely) {[ Requestscompleted Addobject:loadingrequest]; //if complete, put this request into the array of request completion [Loadingrequest finishloading];} } [self.pendingrequests Removeobjectsinarray: Requestscompleted]; //remove completed} In all requested arrays           

Resourceloader The difficulty is basically the above point, when it comes to the player, the following is the avplayer of the difficulties.

Difficulty: Capturing the state of the player

To give a simple example, the total video length of 60 points, now buffered data only 10 minutes, and then drag to 20 minutes to play, at a slower speed, the video from the current position to play, will inevitably appear for a period of time, in order to have a better user experience, in the time of the lag, We need to add a daisy to the state, and now the problem is.

In the drag to the non-buffer area, whether the need to add chrysanthemum, if added, to show how long to disappear, and if the network speed is very slow, if the player waits too long, even if the final data, the player has been "dead", it can not resume playback, this time we need to restore the player, If the replay is unsuccessful, you will need to resume playback again for a while, if the playback is successful, and you need to capture its status. So, if we want to have a good user experience, we need to always know the status of the player.

There are two states to capture, one is buffering, one is playing, the "Playbackbufferempty" property of listening plays can capture the buffering state, the player's time listener can capture the playing state, my demo has a total of 4 states:

typedef NS_ENUM(NSInteger, TBPlayerState) {    TBPlayerStateBuffering = 1, TBPlayerStatePlaying = 2, TBPlayerStateStopped = 3, TBPlayerStatePause = 4};

This can be better for the player to grasp and handle.
Then say in the buffer time processing, and how long after the buffer to play, processing methods:
After entering the buffer state, the buffer after 2 seconds to manually play, if the playback is not successful (the buffered data is too little, not enough to play), then buffer 2 seconds to play again, so loop, see the detailed code:

- (void) bufferingsomesecond{Playbackbufferempty is repeated, so the call Bufferingsomesecond is ignored before the Bufferingonesecond delay play is performedStaticBOOL isbuffering =NO;if (isbuffering) {Return } isbuffering =YES;Need to pause a little before playing, or the network is not good when time is walking, the sound can not be played out [Self .player pause]; Dispatch_after (Dispatch_time (Dispatch_time_now, (int64_t) (2 * nsec_per_sec)), Dispatch_get_main_queue (), ^{// If the user is paused at this time, it is no longer necessary to play the if (self .ispausebyuser) {isbuffering = NO; return;} [self.player play]; //if the play is performed or not, then it is not cached yet, then cached for a period of time isbuffering = NO; if (! Self.currentplayeritem.isplaybacklikelytokeepup) {[ Span class= "Hljs-keyword" >self Bufferingsomesecond]; } });} 

This demo took me a long time to achieve this demo I also met a lot of pits at the end of the completion, and now I dedicate, perhaps to you will be helpful. If you feel good, please also for my star, also is my support and encouragement.



Text/night thousand Seek Ink (Jane book author)
Original link: http://www.jianshu.com/p/990ee3db0563
Copyright belongs to the author, please contact the author to obtain authorization, and Mark "book author".


iOS video edge down--cache play data stream

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.