Search code examples
ioscordovaionic-frameworkios13transcoding

Video transcoding problem in IONIC with iOS 13.0


We have an existing IONIC App and since iOS 13.0 has been released we ran into a problem with transcoding videos. When file path is read from camera.getPicture (with sourceType=PHOTOLIBRARY), and passed to videoEditor.transcodeVideo(), it indefinitely keeps calling the progress callback with value 0. It won’t throw any error and it won’t call the Completed callback.

videoEditor.transcodeVideo() does not work on several real iPhone devices with iOS 13.0 +.

I tried the same code on a simulator with iOS 13.0 and surprisingly it worked.

I tried different file URLs passed to the transcodeVideo() - whether normalized or full URL - no chance!

I tried transcoding a video which is taken from the camera (not from the photo library - captureVideo() function) and it works perfectly.

openFromLibrary() { //DOES NOT WORK
  const optionsFiles: CameraOptions = {
    quality: 50,
    destinationType: this.camera.DestinationType.FILE_URI,
    mediaType: this.camera.MediaType.VIDEO,
    targetWidth: 450,
    targetHeight: 450,
    sourceType: this.camera.PictureSourceType.PHOTOLIBRARY
  } 
  this.camera.getPicture(optionsFiles).then((data) => {
    let model = {
      fullPath: data,
      name: data.substring(data.lastIndexOf('/') + 1)
    }
    //model.fullPath is something like:
    //file:///private/var/mobile/Containers/Data/PluginKitPlugin/DE8E75E9-BF8B-4990-8F01-3874169D65E0/tmp/trim.4F8792C3-D9EC-450D-9E05-2D96C1CF5AE5.MOV
    this.TranscodeVideo(model);
  }, (err) => {
    console.log(err) 
  })
}

captureVideo() { //WORKS
    let options: CaptureVideoOptions = { limit: 1, quality: 1 };
    this.mediaCapture.captureVideo(options).then((data: MediaFile[]) => {
      this.TranscodeVideo(data[0]);
    },
       (err: CaptureError) => console.error(err)
    );
  }

TranscodeVideo(data: any) {
  let fileUri = data.fullPath;
  let outputFileName = this.removeExtension(data.name) + new Date().getMilliseconds() + '_transcoded-output';
  console.log("fileUri: " + fileUri);
  console.log("outputFileName: " + outputFileName);
  this.videoEditor.transcodeVideo({
      fileUri: fileUri,
      outputFileName: outputFileName,
      outputFileType: this.videoEditor.OutputFileType.MPEG4,
      progress: (info: number) => {
        //This gets called indefinitely ... with info = 0
        console.log('progress' + info)
      }
    }).then(
        (fileUri: string) => {
          //This never gets called
          console.log('completed')
        }
      ).catch((error: any) =>  {
         //This never gets called
         alert(error)
      });

}

The expected result is what I got from the output of a simulator:

**2019-10-01 13:41:34.518254-0700 MyApp[1120:13425] fileUri: file:///Users/admin/Library/Developer/CoreSimulator/Devices/6E600D79-C397-4B55-B776-DE036DBFCA7C/data/Containers/Data/PluginKitPlugin/5F323D37-2DE5-4440-BCC0-C07D91F7F77E/tmp/trim.2BB1FF35-883B-4CFE-8EC0-2482E4A09321.MOV**
**2019-10-01 13:41:34.518505-0700 MyApp[1120:13425] outputFileName: trim.2BB1FF35-883B-4CFE-8EC0-2482E4A09321501_transcoded-output**
**2019-10-01 13:41:34.642996-0700 MyApp[1120:13425] input videoWidth: 360.000000**
**2019-10-01 13:41:34.643182-0700 MyApp[1120:13425] input videoHeight: 480.000000**
**2019-10-01 13:41:34.643264-0700 MyApp[1120:13425] output newWidth: 360**
**2019-10-01 13:41:34.643323-0700 MyApp[1120:13425] output newHeight: 480**
**2019-10-01 13:41:34.643522-0700 MyApp[1120:13425] THREAD WARNING: ['VideoEditor'] took '124.734131' ms. Plugin should use a background thread.**
**2019-10-01 13:41:34.662540-0700 MyApp[1120:13538] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x6000033c4600> F8BB1C28-BAE8-11D6-9C31-00039315CD46**
**2019-10-01 13:41:34.667810-0700 MyApp[1120:13538] [ddagg]        AggregateDevice.mm:776   couldn't get default input device, ID = 0, err = 0!**
**2019-10-01 13:41:34.701108-0700 MyApp[1120:13425] progress0**
**2019-10-01 13:41:34.889640-0700 MyApp[1120:13530] Video export succeeded**
**2019-10-01 13:41:34.890443-0700 MyApp[1120:13425] progress100**
**2019-10-01 13:41:34.894357-0700 MyApp[1120:13425] completed**

But what I getis an indefinite number of progress = 0, here is what I logged from an iPhone device with iOS 13.0:

**2019-10-01 13:46:40.599042-0700 MyApp[458:25050] fileUri: file:///private/var/mobile/Containers/Data/PluginKitPlugin/DE8E75E9-BF8B-4990-8F01-3874169D65E0/tmp/trim.521777DB-3325-4E83-98F6-BEDF14EBDC9C.MOV**
**2019-10-01 13:46:40.599279-0700 MyApp[458:25050] outputFileName: trim.521777DB-3325-4E83-98F6-BEDF14EBDC9C594_transcoded-output**
**2019-10-01 13:46:40.617653-0700 MyApp[458:25050] input videoWidth: 360.000000**
**2019-10-01 13:46:40.617717-0700 MyApp[458:25050] input videoHeight: 480.000000**
**2019-10-01 13:46:40.617747-0700 MyApp[458:25050] output newWidth: 360**
**2019-10-01 13:46:40.617780-0700 MyApp[458:25050] output newHeight: 480**
**2019-10-01 13:46:40.617903-0700 MyApp[458:25050] THREAD WARNING: ['VideoEditor'] took '17.159912' ms. Plugin should use a background thread.**
**2019-10-01 13:46:40.624098-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:40.624256-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:41.633175-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:42.639211-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:43.642919-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:44.649573-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:45.653984-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:46.661094-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:47.665412-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:48.669655-0700 MyApp[458:25050] progress0**
**2019-10-01 13:46:49.674255-0700 MyApp[458:25050] progress0**
...

Plugins used are: VideoEditor,Camera


Solution

  • I found the answer and it may helps those who are running into a similar problem. The problem is not the Transcode function in VideoEditor plugin, but, it is because of the incorrect file path that the Camera plugin returns when calling camera.getPicture().

    The path is something like this: file:///private/var/mobile/Containers/Data/PluginKitPlugin/DE8E75E9-BF8B-4990-8F01-3874169D65E0/tmp/trim.521777DB-3325-4E83-98F6-BEDF14EBDC9C.MOV

    So for those who cannot wait for an update for this plugin to come for iOS 13.0, here is the solution: In XCode find the camera plugin source file - CDVCamera.m and

    Change:

    (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
      NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
      return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }
    

    To:

    (CDVPluginResult*)resultForVideo:(NSDictionary*)info
    {
      NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
    
      NSArray* spliteArray = [moviePath componentsSeparatedByString: @"/"];
      NSString* lastString = [spliteArray lastObject];
      NSError *error;
      NSFileManager *fileManager = [NSFileManager defaultManager];
      NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"];
      NSString *filePath = [documentsDirectory stringByAppendingPathComponent:lastString];
      [fileManager copyItemAtPath:moviePath toPath:filePath error:&error];
    
      return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:filePath];
    }
    
    

    This change copies the movie to the App document directory so we can use it afterwards.

    Thanks to litiobat on GitHub: Source