BradLarson/GPUImage

Couldn't write a frame when i swich background to foreground

zj381652512 opened this issue · 1 comments

when i swicth to background and foreground, i find that can not write a video frame...because GPUImageMovieWriter's assetWriter status is AVAssetWriterStatusFailed,

this my code:

#import "ZJCaptureVC.h"
#import "NSTimer+ZJWeakTimer.h"
#import "GPUImage.h"

@interface ZJCaptureVC ()
// GPUImage
@Property (nonatomic, strong) GPUImageVideoCamera *videoCamera;
@Property (nonatomic, strong) GPUImageOutput *filter;
@Property (nonatomic, strong) GPUImageMovieWriter *movieWriter;
@Property (nonatomic, strong) GPUImageView *filterView;
// UI
@Property (weak, nonatomic) IBOutlet UILabel *mLabel;
@Property (nonatomic, weak) NSTimer *mTimer;
@Property (nonatomic, assign) long mLabelTime;
@Property (weak, nonatomic) IBOutlet UIButton *endBtn;
// status
@Property (nonatomic, assign) BOOL recording;
// path
@Property (nonatomic, strong) NSString *pathToMovie;

@EnD

@implementation ZJCaptureVC

  • (NSString *)pathToMovie {
    if (!_pathToMovie) {
    _pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/recordingmovie.mp4"];
    }
    return _pathToMovie;
    }

  • (void)viewDidLoad {
    [super viewDidLoad];

    _videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];
    _videoCamera.outputImageOrientation = [UIApplication sharedApplication].statusBarOrientation;

    _filter = [[GPUImageSepiaFilter alloc] init];
    _filterView = [[GPUImageView alloc] initWithFrame:self.view.bounds];
    [self.view insertSubview:_filterView atIndex:0];

    [_videoCamera addTarget:_filter];
    [_filter addTarget:_filterView];
    [_videoCamera startCameraCapture];
    }

#pragma mark - Actions

  • (IBAction)backClick:(UIButton *)sender {
    [self.navigationController popViewControllerAnimated:YES];
    }

  • (IBAction)endClick:(UIButton *)sender {
    [self endRecording];
    }

  • (IBAction)startClick:(UIButton *)sender {
    sender.selected = !sender.selected;
    if (sender.selected) {
    [self startRecording];
    } else {
    [self pauseRecording];
    }
    }

  • (void)onTimer:(id)sender {
    _mLabel.text = [NSString stringWithFormat:@"录制时间:%lds", _mLabelTime++];
    }

#pragma mark - Private

  • (void)setRecording:(BOOL)recording {
    _recording = recording;
    _endBtn.hidden = !recording;
    }

// 开始录制

  • (void)startRecording {
    if (self.recording) {
    self.movieWriter.paused = NO;
    } else {
    // 如果已经存在文件,AVAssetWriter会有异常,删除旧文件
    NSURL *movieURL = [NSURL fileURLWithPath:self.pathToMovie];
    unlink([self.pathToMovie UTF8String]);

      // 视频设置
      CGFloat width  = 480.f;
      CGFloat height = 640.f;
      NSInteger numPixels     = width * height;
      CGFloat bitsPerPixel    = 6.0;
      NSInteger bitsPerSecond = numPixels * bitsPerPixel;
    
      // 码率和帧率设置
      NSDictionary *compressionProperties =
          @{ AVVideoAverageBitRateKey: @(bitsPerSecond),
             AVVideoExpectedSourceFrameRateKey: @(30),
             AVVideoMaxKeyFrameIntervalKey: @(30),
             AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel };
    
      // 视频属性
      NSDictionary *videoCompressionSettings =
          @{ AVVideoCodecKey: AVVideoCodecH264,
             AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill,
             AVVideoWidthKey: @(width),
             AVVideoHeightKey: @(height),
             AVVideoCompressionPropertiesKey: compressionProperties };
    
      // 创建_movieWriter
      _movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(480.0, 640.0) fileType:AVFileTypeMPEG4 outputSettings:videoCompressionSettings];
      _movieWriter.encodingLiveVideo   = YES;
      _videoCamera.audioEncodingTarget = _movieWriter;
      [_filter addTarget:_movieWriter];
      [_movieWriter startRecording];
    
      self.recording = YES;
    

    }
    // 计时
    _mTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(onTimer:) userInfo:nil repeats:YES];
    [self onTimer:nil];
    }

// 暂停

  • (void)pauseRecording {
    if (!self.recording) {
    NSLog(@"还没开始录制");
    return;
    }
    if (_mTimer) {
    [_mTimer invalidate];
    }
    _movieWriter.paused = YES;
    }

// 完成录制

  • (void)endRecording {
    if (!self.recording) {
    NSLog(@"还没开始录制");
    return;
    }
    if (_mTimer) {
    [_mTimer invalidate];
    }
    [_filter removeTarget:_movieWriter];
    _videoCamera.audioEncodingTarget = nil;

    [_movieWriter finishRecording];
    self.recording = NO;

    if (self.completionHandler) {
    self.completionHandler(self.pathToMovie);
    }
    [self.navigationController popViewControllerAnimated:YES];
    }

@EnD

GPUImageMovieWriter's assetWriter status is AVAssetWriterStatusFailed when app enter background...so we can solve it as below:

  • (void)willEnterBackground:(NSNotification *)notification {
    __weak typeof(self)weakSelf = self;
    UIApplication *app = [UIApplication sharedApplication];
    self.backgroundRenderingID = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:weakSelf.backgroundRenderingID];
    weakSelf.backgroundRenderingID = UIBackgroundTaskInvalid;
    }];
    }