title: iOS - Read a video file frame-by-frame, image processing, then save as new video file
body: <p>I try to read a video frame-by-frame from iPhone photo album. 
  After image processing, I will save them as a new video.
  I'm running my code without any error, but there is no new video in the album.</p>
  
  <p>Here is my code.</p>
  
  <pre><code>// Video writer init
  - (BOOL)setupAssetWriterForURL:(CMFormatDescriptionRef)formatDescription
  {
      float bitsPerPixel;
      CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
      int numPixels = dimensions.width * dimensions.height;
      int bitsPerSecond;
  
      if ( numPixels &lt; (640 * 480) )
          bitsPerPixel = 4.05; 
      else
          bitsPerPixel = 11.4; 
  
      bitsPerSecond = numPixels * bitsPerPixel;
  
      NSDictionary *videoCompressionSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                                AVVideoCodecH264, AVVideoCodecKey,
                                                [NSNumber numberWithInteger:dimensions.width], AVVideoWidthKey,
                                                [NSNumber numberWithInteger:dimensions.height], AVVideoHeightKey,
                                                [NSDictionary dictionaryWithObjectsAndKeys:
                                                 [NSNumber numberWithInteger:bitsPerSecond], AVVideoAverageBitRateKey,
                                                 [NSNumber numberWithInteger:30], AVVideoMaxKeyFrameIntervalKey,
                                                 nil], AVVideoCompressionPropertiesKey,
                                                nil];
      if ([assetWriter canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo]) {
          assetWriterVideoIn = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoCompressionSettings];
          assetWriterVideoIn.expectsMediaDataInRealTime = YES;
          assetWriterVideoIn.transform = [self transformFromCurrentVideoOrientationToOrientation:self.referenceOrientation];
          if ([assetWriter canAddInput:assetWriterVideoIn])
              [assetWriter addInput:assetWriterVideoIn];
          else {
              NSLog(@"Couldn't add asset writer video input.");
              return NO;
          }
      }
      else {
          NSLog(@"Couldn't apply video output settings.");
          return NO;
      }
  
      return YES;
  }
  </code></pre>
  
  <p>Read video</p>
  
  <pre><code>- (void)readMovie:(NSURL *)url
  {
      AVURLAsset * asset = [AVURLAsset URLAssetWithURL:url options:nil];
      [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler:
       ^{
           dispatch_async(dispatch_get_main_queue(),
                          ^{
                              AVAssetTrack * videoTrack = nil;
                              NSArray * tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
                              if ([tracks count] == 1)
                              {
                                  videoTrack = [tracks objectAtIndex:0];
  
                                  NSError * error = nil;
  
                                  // _movieReader is a member variable
                                  AVAssetReader *movieReader = [[AVAssetReader alloc] initWithAsset:asset error:&amp;error];
                                  if (error)
                                      NSLog(@"_movieReader fail!\n");
  
                                  NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
                                  NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
                                  NSDictionary* videoSettings = 
                                  [NSDictionary dictionaryWithObject:value forKey:key]; 
  
                                  [movieReader addOutput:[AVAssetReaderTrackOutput 
                                                           assetReaderTrackOutputWithTrack:videoTrack 
                                                           outputSettings:videoSettings]];
                                  [movieReader startReading];
  
                                  while ([movieReader status] == AVAssetReaderStatusReading)
                                  {
                                      AVAssetReaderTrackOutput * output = [movieReader.outputs objectAtIndex:0];
                                      CMSampleBufferRef sampleBuffer = [output copyNextSampleBuffer];
                                      if (sampleBuffer)
                                      {
                                          if ( !assetWriter ) {
                                              outputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%llu.mov", NSTemporaryDirectory(), mach_absolute_time()]];
  
                                              NSError *error = nil;
                                              assetWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:(NSString *)kUTTypeQuickTimeMovie error:&amp;error];
                                              if (error)
                                                  [self showError:error];
  
  
                                              if (assetWriter) {
                                                  CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
                                                  [self setupAssetWriterForURL:formatDescription];
                                              }
                                          }
                                          CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
  
  
                                          CVPixelBufferLockBaseAddress(imageBuffer,0);
  
                                          int bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
                                          int bufferWidth = CVPixelBufferGetWidth(imageBuffer);
                                          int bufferHeight = CVPixelBufferGetHeight(imageBuffer);
                                          unsigned char *pixel = (unsigned char *)CVPixelBufferGetBaseAddress(imageBuffer);
  
  
                                          for( int row = 0; row &lt; bufferHeight; row++ ) {
                                              for( int column = 0; column &lt; bufferWidth; column++ ) {
  
                                                  pixel[0] = (pixel[0]+pixel[1]+pixel[2])/3;
                                                  pixel[1] = (pixel[0]+pixel[1]+pixel[2])/3;
                                                  pixel[2] = (pixel[0]+pixel[1]+pixel[2])/3;
  
                                                  pixel += 4;
                                              }
                                          }
  
  
                                          CVPixelBufferUnlockBaseAddress(imageBuffer,0);
  
                                          if ( assetWriter ) {
                                              [self writeSampleBuffer:sampleBuffer ofType:AVMediaTypeVideo];
                                          }
  
  
                                          CFRelease(sampleBuffer);
                                      }
  
                                  }
                                  if (assetWriter) {
                                      [assetWriterVideoIn markAsFinished];
                                      assetWriter = nil;
                                      [assetWriter finishWriting];
                                      assetWriterVideoIn = nil;
                                      assetWriter = nil;
  
                                      [self saveMovieToCameraRoll];
                                  }
                                  else {
                                      [self showError:[assetWriter error]];
                                  }
  
                              }
                          });
       }];
  
  }
  - (void) writeSampleBuffer:(CMSampleBufferRef)sampleBuffer ofType:(NSString *)mediaType
  {
      if ( assetWriter.status == AVAssetWriterStatusUnknown ) {
  
          if ([assetWriter startWriting]) {
              [assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
          }
          else {
              [self showError:[assetWriter error]];
          }
      }
  
      if ( assetWriter.status == AVAssetWriterStatusWriting ) {
  
          if (mediaType == AVMediaTypeVideo) {
              if (assetWriterVideoIn.readyForMoreMediaData) {
                  if (![assetWriterVideoIn appendSampleBuffer:sampleBuffer]) {
                      [self showError:[assetWriter error]];
                  }
              }
          }
  
      }
  }
  - (void)saveMovieToCameraRoll
  {
      ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
      [library writeVideoAtPathToSavedPhotosAlbum:outputURL
                                  completionBlock:^(NSURL *assetURL, NSError *error) {
                                      if (error){
                                          [self showError:error];
                                      NSLog(@"save fail");
                                  }
                                      else
                                      {
                                          [self removeFile:outputURL];
                                          NSLog(@"!!!");
                                      }
                                      });
                                  }];
  }
  - (void)removeFile:(NSURL *)fileURL
  {
      NSFileManager *fileManager = [NSFileManager defaultManager];
      NSString *filePath = [fileURL path];
      if ([fileManager fileExistsAtPath:filePath]) {
          NSError *error;
          BOOL success = [fileManager removeItemAtPath:filePath error:&amp;error];
          if (!success)
              [self showError:error];
      }
  }
  </code></pre>
  
  <p>Any suggestions?</p>