title: create video from images and save to photo album
body: <p>I was making a video out of an array of images and an audio file</p>
  
  <p>but i can't seem to save it to the camera roll </p>
  
  <p>some times it saves but some times it doesn't and gives me a strange error </p>
  
  <p>outputFile.mp4 cannot be saved to the saved photos album: Error Domain=NSOSStatusErrorDomain Code=-12848 "Movie could not be played." UserInfo=0x7bd7370 {NSLocalizedDescription=Movie could not be played.}</p>
  
  <p>This function creates video from array of images :</p>
  
  <pre><code>-(void) writeImagesToMovieAtPath:(NSString *) path withSize:(CGSize) size
  {
      NSLog(@"Write Started");
  
      NSError *error = nil;
  
      AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                                    [NSURL fileURLWithPath:path] fileType:AVFileTypeMPEG4
                                                                error:&amp;error];
      NSParameterAssert(videoWriter);
  
      NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                     AVVideoCodecH264, AVVideoCodecKey,
                                     [NSNumber numberWithInt:size.width], AVVideoWidthKey,
                                     [NSNumber numberWithInt:size.height], AVVideoHeightKey,
                                     nil];
  
      AVAssetWriterInput* videoWriterInput = [[AVAssetWriterInput
                                               assetWriterInputWithMediaType:AVMediaTypeVideo
                                               outputSettings:videoSettings] retain];
  
  
      AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                       assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
                                                       sourcePixelBufferAttributes:nil];
  
      NSParameterAssert(videoWriterInput);
      NSParameterAssert([videoWriter canAddInput:videoWriterInput]);
      videoWriterInput.expectsMediaDataInRealTime = YES;
      [videoWriter addInput:videoWriterInput];
  
      //Start a session:
      [videoWriter startWriting];
      [videoWriter startSessionAtSourceTime:kCMTimeZero];
  
      CVPixelBufferRef buffer = NULL;
  
      //convert uiimage to CGImage.
  
      int frameCount = 16;
      int kRecordingFPS = 30;
      UIImage * im = [UIImage imageNamed:@"IMG_0103.JPG"];
  
      NSArray * imageArray = [[NSArray alloc]initWithObjects:im,im,im,im,im,im,im,im,im,im,im,im,im,im,im,im, nil];
  
      for(UIImage * img in imageArray)
      {
          buffer = [self pixelBufferFromCGImage:[img CGImage] andSize:size];
  
          BOOL append_ok = NO;
          int j = 0;
          while (!append_ok &amp;&amp; j &lt; 30)
          {
              if (adaptor.assetWriterInput.readyForMoreMediaData)
              {
                  printf("appending %d attemp %d\n", frameCount, j);
  
                  CMTime frameTime = CMTimeMake(frameCount,(int32_t) kRecordingFPS);
                  append_ok = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
  
                  if(buffer)
                      CVBufferRelease(buffer);
                  [NSThread sleepForTimeInterval:0.05];
              }
              else
              {
                  printf("adaptor not ready %d, %d\n", frameCount, j);
                  [NSThread sleepForTimeInterval:0.1];
              }
              j++;
          }
          if (!append_ok) {
              printf("error appending image %d times %d\n", frameCount, j);
          }
          frameCount++;
      }
  
  
      //Finish the session:
      [videoWriterInput markAsFinished];
      [videoWriter finishWriting];
      NSLog(@"Write Ended");
      [videoWriterInput release];
      [videoWriter release];
      [imageArray release];
  }
  </code></pre>
  
  <p>This function adds the audio :</p>
  
  <pre><code>    -(void)CompileFilesToMakeMovie{
          AVMutableComposition* mixComposition = [AVMutableComposition composition];
  
          NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  
          NSString* audio_inputFileName = @"Rihanna-Take a Bow.mp3";
  
          NSString* audio_inputFilePath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,audio_inputFileName];
  
          NSURL*    audio_inputFileUrl = [NSURL fileURLWithPath:audio_inputFilePath];
  
          NSString* video_inputFileName = @"a.mp4";
          NSString* video_inputFilePath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,video_inputFileName];
          NSURL*    video_inputFileUrl = [NSURL fileURLWithPath:video_inputFilePath];
  
          NSString* outputFileName = @"outputFile.mp4";
          NSString* outputFilePath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,outputFileName];
  
          NSURL*    outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
  
          if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
              [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
  
  
  
          CMTime nextClipStartTime = kCMTimeZero;
  
          AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil];
          CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
  
          AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
          [a_compositionVideoTrack insertTimeRange:video_timeRange ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:nextClipStartTime error:nil];
  
          //nextClipStartTime = CMTimeAdd(nextClipStartTime, a_timeRange.duration);
  
          AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
          CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration);
          AVMutableCompositionTrack *b_compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
          [b_compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:nextClipStartTime error:nil];
  
  
  
          AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
          _assetExport.outputFileType = AVFileTypeMPEG4;
          _assetExport.outputURL = outputFileUrl;
          [_assetExport setTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)];
          [_assetExport exportAsynchronouslyWithCompletionHandler:nil];
  
          [audioAsset release];
          [videoAsset release];
  
  
          [_assetExport release];
      }
  </code></pre>
  
  <p>The function calls :</p>
  
  <pre><code>- (void)viewDidLoad
  {
      [super viewDidLoad];
      NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  
      UIImage * i = [UIImage imageNamed:@"IMG_0103.JPG"];
  
      [self writeImagesToMovieAtPath:[NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,@"a.mp4"] withSize:CGSizeMake(i.size.width, i.size.height)];
  
      NSString* exportVideoPath1 = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,@"a.mp4"];
  
  
      NSString* exportVideoPath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,@"outputFile.mp4"];
  
      UISaveVideoAtPathToSavedPhotosAlbum (exportVideoPath,self, @selector(video:didFinishSavingWithError: contextInfo:), nil);
  
  }
  </code></pre>