菜鸟教程小白 发表于 2022-12-11 20:27:09

ios - UITableViewCell 中的自动播放视频


                                            <p><p>我已经阅读了关于 <code>StackOverflow</code> 自动播放视频的大部分问题,并且我能够在 <code>UITableView</code> 中自动播放它们,但我遇到的问题如下所述</p>

<ol>
<li>视频开始时滚动暂停一秒钟</li>
<li>播放前视频闪烁</li>
<li>如果我向上滚动,视频不会自动播放</li>
</ol>

<p>我想要的是在不使用任何第三方库(如 <code>ASYNCDisplayKit</code>)的情况下自动播放视频(如 Facebook)的流畅体验。
所有视频 <code>urls</code> 均来自 <code>AWSS3</code> 云端 URL。
我还上传了这个问题的视频,以防有人想看。</p>

<p> <a href="https://www.dropbox.com/s/s3llb7wvtc724k4/AutoplayNew.mov?dl=0" rel="noreferrer noopener nofollow">Video Autoplay Hiccups</a> </p>

<p><strong>这是我的完整代码</strong></p>

<pre><code>- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {



            PostViewModel* model = self.posts;
            Post* post = model.post;

            PostItems* item = model.items;
                if(item.itemType == nameAndPicture) {
                  //Removed code as it&#39;s not related to question
                }
                else if(item.itemType == textContent){
                  //Removed code as it&#39;s not related to question
                }
                else if(item.itemType == images){
                  //Removed code as it&#39;s not related to question
                }
                else if(item.itemType == videos){

                  VideoListCell *cell = nil;
                  cell = (VideoListCell*);
                  cell.delegate = self;
                  cell.indexPath = indexPath;
                  cell.selectionStyle = UITableViewCellSelectionStyleNone;
                  cell.backgroundColor = ;

                  cell.videoThumbnail.image = nil;

                  ;

                  if (post.medias.count &gt; 0) {
                        MediaItem* item = post.medias;
                        if ( == VIDEO) {

                           NSString* thumbnailURL = item.thumbnailUrl;
                            ;
                            ;

                            dispatch_async(dispatch_get_main_queue(), ^{
                              ;
                            });
                        }
                  }
                  cell.clipsToBounds = YES;
                  return cell;
                }

}




- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{

    //Check if the cell displayed is video cell then try to autoplay the video
    if(]){
      VideoListCell* videoCell = (VideoListCell*)cell;
      dispatch_async(dispatch_get_main_queue(), ^{
            ;
      });
      PostViewModel* model = self.posts;
      Post* post = model.post;
      PostItems* item = model.items;
      if(item.itemType == videos){
            videoCell.videoThumbnail.image = nil;
            ;

            if (post.medias.count &gt; 0) {
                MediaItem* item = post.medias;
                if ( == VIDEO) {
                  //dispatch_async(dispatch_get_main_queue(), ^{
                  NSString* profilePic = item.thumbnailUrl;
                  ;
                  ;
                  ;
                }
            }
      }
    }
}

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath {

    if(]){

      VideoListCell* videoCell = (VideoListCell*)cell;
      ;
      videoCell.avLayer = nil;
      videoCell.videoPlayer = nil;
      ;
    }
}
</code></pre>

<p>//视频列表单元类</p>

<pre><code>#define kHeight 200

@implementation VideoListCell

- (void)awakeFromNib {
    ;

    UIImage* icon = [ imageTintedWithColor:kSliderDarkYellowColor];
    ;

    UIImage* pauseIcon = [ imageTintedWithColor:kSliderDarkYellowColor];

    ;
    ;


    UITapGestureRecognizer *viewTap = [initWithTarget:self action:@selector(tapOnView)];
    viewTap.numberOfTapsRequired = 1;
    self.viewPlayer.userInteractionEnabled = YES;
    ;

    self.counterView.hidden = YES;
    self.counterView.layer.cornerRadius = 12.0f;
    self.counterView.layer.masksToBounds = YES;

    //Add Gesture to label
    UITapGestureRecognizer *countGesture = [initWithTarget:self action:@selector(tapOnCounterView)];
    countGesture.numberOfTapsRequired = 1;
    self.counterView.userInteractionEnabled = YES;
    ;

    ;

    self.btnFullScreen.hidden = NO;
    UIImage* fullScreenImage = [ imageTintedWithColor:kSliderDarkYellowColor];
    ;

}

- (void)showThumbnail:(BOOL)yesOrNo {
    self.videoThumbnail.hidden = !yesOrNo;
    self.viewForVideo.hidden = yesOrNo;
}

- (void)hideVideoAndShowThumbnail {
    ;
    ;
    self.btnPlay.selected = NO;
    self.isPlaying = NO;
}

- (void)btnFSTapped:(UIButton*)sender {
    if (self.delegate &amp;&amp; ) {
      ;
    }
}

- (void)layoutSubviews
{
    ;
//   if (self.avLayer) {
//         ;
//   }

}

- (void)initNewPlayerItem {
    // Pause the existing video (if there is one)
    //;

    if(self.asset){
      ;
    }


    // First we need to make sure we have a valid URL
    if (!self.videoURL) {
      return;
    }

    // Create a new AVAsset from the URL
    self.asset = ;

    // Now we need an AVPlayerItem to pass to the AVPlayer
    AVPlayerItem* item= [ initWithAsset:self.asset];

    if(item){
      [ addObserver:self

                                                 selector:@selector(playerItemDidReachEnd:)

                                                   name:AVPlayerItemDidPlayToEndTimeNotification

                                                   object:item];
    }
    //;

    // Finally, we set this as the current AVPlayer item

    completionHandler:^{

      NSError* error = nil;
      AVKeyValueStatus status = ;
      if (status == AVKeyValueStatusFailed) {
            ;
            self.btnPlay.hidden = NO;
            self.btnPlay.selected = NO;
            return;
      }
      dispatch_async(dispatch_get_main_queue(), ^{
            ;
            ;
            self.btnPlay.selected = YES;
            self.btnPlay.hidden = YES;
            ;
            ;
            self.isPlaying = YES;
      });
    }];
}

- (void)playerItemDidReachEnd:(NSNotification*)notif {

    id object = ;
    if (object &amp;&amp; ]) {
      AVPlayerItem* item = (AVPlayerItem*);
      ;
    }
    //;
    ;
    self.btnPlay.selected = NO;
    self.btnPlay.hidden = NO;

}

-(void)prepareForReuse {

//    self.videoURL = nil;
//    self.videoThumbnail.image = nil;
    //;
    self.videoThumbnail.image = nil;
    if (self.avLayer.superlayer) {
      ;
    }

    if (self.viewForVideo.subviews.count &gt; 0) {
      for (UIView* v in self.viewForVideo.subviews) {
            ;
      }
    }

    self.videoURL = nil;
    self.player = nil;
    self.userID = nil;
    self.videoItem = nil;
    self.videoPlayer = nil;
    self.btnPlay.selected = NO;

    ;
}

- (void)tapOnView {

    //if(self.counterView.hidden){
      if (self.delegate &amp;&amp; ) {
            ;
      }
    //}
//    else
//    {
//            if (self.delegate &amp;&amp; ) {
//                ;
//            }
//    }
}

-(void)tapOnCounterView {
    if (self.delegate &amp;&amp; ) {
          ;
    }
}

- (void)setCounter:(NSUInteger)count {

    if (count &gt; 1) {
      self.counterView.hidden = NO;
      self.lblCounter.text = ;
    }
    else{
      self.counterView.hidden = YES;
    }
}

- (IBAction)btnPlayTapped:(id)sender {

    //;

   //if(self.counterView.hidden){
      if(self.btnPlay.selected){
            ;
            self.btnPlay.selected = NO;
      }else{
            ;
            self.btnPlay.selected = YES;
      }
}

- (void)touchesBegan:(NSSet&lt;UITouch *&gt; *)touches withEvent:(UIEvent *)event {
    if(self.player.player.timeControlStatus == AVPlayerTimeControlStatusPlaying){
      if(self.btnPlay.hidden){
            self.btnPlay.hidden = NO;
      }
    }
}


- (void)playVideo {

    //if (!self.player) {
      if () {

            //Call API here and update media item object URL
            dispatch_async(dispatch_get_main_queue(), ^{
                //Call API here
                //URL is expired then give a call to our server to generate a new URL
                ;
            });
      }
      else{
            if (!self.videoURL) {

                dispatch_async(dispatch_get_main_queue(), ^{
                  ;
                });
            }else{
                dispatch_async(dispatch_get_main_queue(), ^{
                  ;

                });
            }
      }
}

- (void)stopVideo {
    if (self.player) {
      self.isPlaying = NO;
      self.btnPlay.hidden = NO;
      ;
    }
}

- (void)setMediaItem:(MediaItem*)item withUserID:(NSNumber*)userId {
    self.videoObject = item;
    self.userID = userId;
    ;
}

- (void)generatePreSignedURLWithVideoThumbnail {

    if (self.videoObject.mediaUrl &amp;&amp; ) {
      //Already have pre signed url check if URL is expired
      //If URL expired then call our own server to generate a new presigned URL
      dispatch_async(dispatch_get_main_queue(), ^{
            self.videoURL = ;
            ;
      });
    }
    else if(self.videoObject.mediaUrl &amp;&amp; ){
      AppDelegate* delegate = ;
      AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = ;
      getPreSignedURLRequest.bucket = S3BucketName;
      getPreSignedURLRequest.key = kS3OutputVideoFileInternalPath(delegate.loggedInUser.userId,,self.videoObject.mediaUrl);

      getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
      getPreSignedURLRequest.expires = ;

      [[ getPreSignedURL:getPreSignedURLRequest]
         continueWithBlock:^id(AWSTask *task) {
             if (task.error) {
               NSLog(@&#34;Error: %@&#34;,task.error);
             } else {
               dispatch_async(dispatch_get_main_queue(), ^{
                     self.videoURL = task.result;
                     ;
               });
             }
             return nil;
         }];
    }
    else{
      //Generate Pre signed URL
      AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = ;
      getPreSignedURLRequest.bucket = S3BucketName;
      getPreSignedURLRequest.key = ;

      getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
      getPreSignedURLRequest.expires = ;

      [[ getPreSignedURL:getPreSignedURLRequest]
         continueWithBlock:^id(AWSTask *task) {
             if (task.error) {
               NSLog(@&#34;Error: %@&#34;,task.error);
             } else {
               dispatch_async(dispatch_get_main_queue(), ^{
                     self.videoURL = task.result;
                     ;

               });
             }
             return nil;
         }];
    }
}

- (void)setupPlayer {
    self.btnPlay.hidden = YES;

    self.videoItem = nil;
    self.videoPlayer = nil;

    self.videoItem = [ initWithURL:self.videoURL];

    if (self.avLayer.superlayer) {
      ;
    }

    if (self.viewForVideo.subviews.count &gt; 0) {
      for (UIView* v in self.viewForVideo.subviews) {
            ;
      }
    }

    self.videoPlayer = [ initWithPlayerItem:self.videoItem];

    self.avLayer = ;
    self.avLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

    self.player = [ init];
    self.player.player = self.videoPlayer;
    self.player.videoGravity = AVLayerVideoGravityResizeAspectFill;

    self.player.showsPlaybackControls = NO;

    // Insert the player into the cell view hierarchy and setup autolayout
    self.player.view.translatesAutoresizingMaskIntoConstraints = false;
    ;

    //Trailing
    NSLayoutConstraint *trailing =[NSLayoutConstraint
                                 constraintWithItem:self.player.view
                                 attribute:NSLayoutAttributeTrailing
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:self.viewForVideo
                                 attribute:NSLayoutAttributeTrailing
                                 multiplier:1.0f
                                 constant:0.f];

    //Leading

    NSLayoutConstraint *leading = [NSLayoutConstraint
                                 constraintWithItem:self.player.view
                                 attribute:NSLayoutAttributeLeading
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:self.viewForVideo
                                 attribute:NSLayoutAttributeLeading
                                 multiplier:1.0f
                                 constant:0.f];

    //Bottom
    NSLayoutConstraint *bottom =[NSLayoutConstraint
                                 constraintWithItem:self.player.view
                                 attribute:NSLayoutAttributeBottom
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:self.viewForVideo
                                 attribute:NSLayoutAttributeBottom
                                 multiplier:1.0f
                                 constant:0.f];

    //Height to be fixed for SubView same as AdHeight
    NSLayoutConstraint *height = [NSLayoutConstraint
                                  constraintWithItem:self.player.view
                                  attribute:NSLayoutAttributeHeight
                                  relatedBy:NSLayoutRelationEqual
                                  toItem:nil
                                  attribute:NSLayoutAttributeNotAnAttribute
                                  multiplier:0
                                  constant:kHeight];

    //Add constraints to the Parent
    ;
    ;
    ;

    //Add height constraint to the subview, as subview owns it.
    ;

    ;
}

- (void)generateNewPreSignedURL {

    if (self.videoObject) {
      NSDictionary* postParams = @{kMediaId:self.videoObject.mediaId};


      dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            TBWebAPIConsumer *web = ;
            [web generatePreSignedURL:postParams andCompletionBlock:^(NSError *error, id serverResponse) {

                // Do something...
                dispatch_async(dispatch_get_main_queue(), ^{
                  if (error == nil){
                        //Parse user data here
                        NSDictionary* data = (NSDictionary*)serverResponse;

                        if (!) {
                            self.videoObject.mediaUrl = ;
                        }
                        if (!) {
                            self.videoObject.videoSignedUrlExpiry = ;
                        }
                        ;

                  }
                });

            }];

      });
    }


}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    ;

    // Configure the view for the selected state
}
</code></pre>

<p>有人可以帮我解决这个问题吗?</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>我有一些建议给你:</p>

<ol>
<li><p>在滚动过程中不要尝试调用播放/暂停。只需在滚动停止后立即执行此操作:<a href="https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e" rel="noreferrer noopener nofollow">https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e</a> </p></li>
<li><p>你可以尝试使用这个肮脏的技巧:<a href="https://gist.github.com/k06a/66f7815b0325f239411e26f498c75755" rel="noreferrer noopener nofollow">https://gist.github.com/k06a/66f7815b0325f239411e26f498c75755</a>要对 Apple Review Team 隐藏它,只需使用 <code>UAObfuscateString</code> 库混淆 keypath <code>@"_player.stateDispatchQueue"</code>。</p></li>
<li><p>我听说没有肮脏的黑客可以实现平稳的返回。我会请我的一个 friend 来回答你的问题。</p></li>
</ol></p>
                                   
                                                <p style="font-size: 20px;">关于ios - UITableViewCell 中的自动播放视频,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/51787983/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/51787983/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - UITableViewCell 中的自动播放视频