2017-09-07 7 views
0

J'ai eu quelques problèmes téléchargés images de mon drone directement à mon application. Je reçois toujours un "Le système est occupé, veuillez réessayer plus tard." (Code: -1004) "Message d'erreur lorsque vous essayez de télécharger l'image, j'ai vérifié le forum DJI et d'autres questions ici sur stackoverflow toute solution à ce problème.Comment télécharger par programme des images à partir du drone à l'aide de l'IOS DJI-SDK

J'ai déjà jeté un oeil à this question, mais j'utilise déjà la technique suggérée par cette réponse.

Voici la fonction que j'ai écrit pour télécharger les images:

func downloadFilesFromDrone(){ 

    // get current product 
    guard let drone = DJISDKManager.product() else { 
     Logger.logError("Product is connected but DJISDKManager.product is nil when attempting to download media") 
     return 
    } 


    // Get camera on drone 
    guard let camera: DJICamera = drone.camera else { 
     Logger.logError("Unable to detect Camera in downloadFilesFromDrone()") 
     // make recursive call until we are able to detect the camera 
     DispatchQueue.main.asyncAfter(deadline: .now() + 1) { 
      Logger.logH1("Trying to detect Camera again") 
      self.downloadFilesFromDrone() 
     } 
     return 
    } 

    Logger.logH1("Successfully detected the camera") 

    // check if we can download images with the product 
    if !camera.isMediaDownloadModeSupported() { 
     Logger.logError("Product does not support media download mode") 
     return 
    } 


    // switch camera mode to allow for media downloads 
    camera.setMode(.mediaDownload, withCompletion: {(error) in 
     if error != nil { 
      print("\(error!.localizedDescription)") 
     } 
     else { 

      // get the media manager from the drone to gain access to the files 
      let manager = camera.mediaManager! 
      manager.refreshFileList(completion: { (error) in 

       if error != nil { 
        print("State: \(manager.fileListState.rawValue)") 
        print("Error refreshing list: \(error!.localizedDescription)") 
       } 
       else { 
        Logger.logH1("Refreshed file list") 
        print("State: \(manager.fileListState.rawValue)") 


        guard let files = manager.fileListSnapshot() else { 
         Logger.logError("No files to download") 
         return 
        } 

        Logger.logH1("There are files to download") 

        var images: [UIImage] = [] 

        for file in files { 

         if file.mediaType == .JPEG { 

          print("Time created: \(file.timeCreated)") 

          DispatchQueue.main.asyncAfter(deadline: .now() + 1) { 

           file.fetchData(withOffset: 0, update: DispatchQueue.main, update: {(_ data: Data?, _ isComplete: Bool, _ error: Error?) -> Void in 

            if error != nil { 
             print("State: \(manager.fileListState.rawValue)") 
             print("Error downloading photo: \(error!)") 
            } 
            else { 
             // unwrap downloaded data and create image 
             if let data = data, let downloadedImage = UIImage(data: data) { 
              print("Image was downloaded!") 
              images.append(downloadedImage) 
             } 
            } 

           }) // end of filedata fetch 

          } 

         } 

        } // end of loop 


       } 
      }) // end of file-refresh block 

     } 

    })// end of camera setMode block 

} 

Et voici la sortie de cette fonction lors du test avec mon drone:

*** Product Connected *** 
*** Unable to detect Camera in downloadFilesFromDrone() *** 
*** Firmware package version is: Unknown *** 
--> Trying to detect Camera again 
--> Successfully detected the camera 
--> Refreshed file list 
State: 0 
--> There are files to download 
Time created: 2017-09-01 15:17:04 
Time created: 2017-09-01 15:17:16 
Time created: 2017-09-01 15:17:26 
Time created: 2017-09-01 15:17:36 
Time created: 2017-09-01 15:19:06 
State: 0 
Error downloading photo: System is busy, please retry later.(code:-1004) 
State: 0 
Error downloading photo: System is busy, please retry later.(code:-1004) 
State: 0 
Error downloading photo: System is busy, please retry later.(code:-1004) 
State: 0 
Error downloading photo: System is busy, please retry later.(code:-1004) 

Edit:

Voici le code que j'ai utilisé pour télécharger des images du drone.

/** 
* This function downloads the N latest images from the drone and passes them to the completionhandler once all images have completed downloading 
*/ 
func downloadImages(files: [DJIMediaFile], howMany: Int, maxErrors: Int, completion: @escaping ([UIImage]) -> Void){ 

    Logger.logH1("Queueing \(howMany) image(s) to be downloaded") 

    func downloadNextImage(files: [DJIMediaFile], fileCount: Int, index: Int = 0, downloadedFiles: [UIImage] = [], errorCount: Int = 0) { 

     // stop when we reach the end of the list 
     if index == fileCount { 
      completion(downloadedFiles) 
      return 
     } 
     else { 
      var imageData: Data? 
      let file = files[index] 

      file.fetchData(withOffset: 0, update: DispatchQueue.main, update: {(_ data: Data?, _ isComplete: Bool, _ error: Error?) -> Void in 

       if let error = error { 
        Logger.logError("\(error)") 

        if errorCount < maxErrors { 
         DispatchQueue.main.asyncAfter(deadline: .now() + 1) { 
          Logger.logH1("Attempting to download: \(file.fileName) again") 
          downloadNextImage(files: files, fileCount: fileCount, index: index, downloadedFiles: downloadedFiles, errorCount: errorCount + 1) 
         } 

        } 
        else { 
         Logger.logError("Too many errors downloading the images, try downloading again") 
        } 


       } 
       else { 
        // if image is done downloading 
        if isComplete { 

         // get full image data 
         if let imageData = imageData, let image = UIImage(data: imageData) { 
          Logger.logH1("Downloaded: \(file.fileName)") 

          // now that the image is done downloading, move onto the next image 
          downloadNextImage(files: files, fileCount: fileCount, index: (index + 1), downloadedFiles: downloadedFiles + [image], errorCount: 0) 
         } 
        } 
         // else, download the file 
        else { 

         // If image exists, append the data 
         if let _ = imageData, let data = data { 
          imageData?.append(data) 
         } 
          // initialize the image data 
         else { 
          imageData = data 
         } 

        } 
       } 


      }) // end of filedata fetch 


     } // end of else statement 
    } 

    // bounds checking 
    let available = files.count 
    let n = howMany > available ? available : howMany 

    // grab the N latest images taken by the drone 
    let filesToDownload : [DJIMediaFile] = Array (files.suffix(n)) 


    // start the recursive function 
    downloadNextImage(files: filesToDownload, fileCount: filesToDownload.count) 
} 

Et voici comment l'appeler:

// get current product 
    guard let drone = DJISDKManager.product() else { 
     Logger.logError("Product is connected but DJISDKManager.product is nil when attempting to download media") 
     return 
    } 


    // Get camera on drone 
    guard let camera: DJICamera = drone.camera else { 
     Logger.logError("Unable to detect Camera in initDownload()") 
     return 
    } 

    Logger.logH1("Successfully detected the camera") 

    // check if we can download images with the product 
    if !camera.isMediaDownloadModeSupported() { 
     Logger.logError("Product does not support media download mode") 
     return 
    } 

    // switch camera mode to allow for media downloads 
    camera.setMode(.mediaDownload, withCompletion: {(error) in 
     if error != nil { 
      print("\(error!.localizedDescription)") 
     } 
     else { 

      // get the media manager from the drone to gain access to the files 
      let manager = camera.mediaManager! 
      manager.refreshFileList(completion: { (error) in 

       if error != nil { 
        print("State: \(manager.fileListState.rawValue)") 
        print("Error refreshing list: \(error!.localizedDescription)") 
       } 
       else { 
        Logger.logH1("Refreshed file list") 
        print("State: \(manager.fileListState.rawValue)") 

        // get list of files 
        guard let files = manager.fileListSnapshot() else { 
         Logger.logError("No files to download") 
         return 
        } 

        Logger.logH1("There are files to download.. Beginning Download") 
        self.downloadImages(files: files, howMany: waypoints, maxErrors: 4, completion: { images in 
         Logger.logH1("Finished downloading: \(images.count) image(s)") 
         // do something with the images here 
        }) 



       } 
      }) // end of file-refresh block 

     } 

    })// end of camera setMode block 
+0

Avez-vous téléchargé la version de travail de la fonction pour l'exhaustivité? – IanTimmis

+0

@IanTimmis J'ai mis à jour ma question avec la solution que j'ai utilisée. En passant, la fonction peut ne pas détecter la caméra sur le premier appel, vous devez essayer plusieurs appels avant que la caméra est détectée. –

Répondre

1

Vous avez deux problèmes ici. Tout d'abord, votre updateBlock est inadéquat car il suppose que toutes les données viendront en un seul appel. Regardez plus attentivement la documentation pour fetchData()

Notez la définition de updateBlock: "Bloquer pour recevoir des données de fichier, il sera appelé plusieurs fois et chaque fois retournera les données reçues depuis le dernier appel."

Ainsi, votre updateBlock a besoin de faire quelque chose comme ceci:

imageData.append(data) 
if isComplete { 
    image = UIImage(data: imageData) 
    // handle image as desired 
} 

Le deuxième problème est que vous demandez le téléchargement asynchrone de tous les fichiers simultanément. Vous devez télécharger un seul fichier à la fois et ne lancer le suivant que lorsque le précédent est terminé. Par exemple:

imageData.append(data) 
if isComplete { 
    image = UIImage(data: imageData) 
    // handle image as desired 

    // then, initiate next download 
    downloadFilesFromDrone() 
} 
+0

Merci de clarifier les choses! En ce qui concerne mon deuxième problème, comment puis-je m'assurer de ne télécharger qu'une seule image à la fois? Je comprends que je dois d'abord prendre la fonction fetchData() en dehors du bloc DispatchQueue, mais je ne sais pas où aller à partir de là (comme la fonction fetchData() ressemble à une fonction asynchrone) –

+0

@NathanOrtega J'ai mis à jour l'exemple , le plus simple serait probablement de lancer le prochain téléchargement à partir de updateBlock une fois le téléchargement terminé. – biomiker

+0

@NathanOrtega vous l'avez probablement compris, mais vous ne devriez pas appeler votre fichier downloadFilesFromDrone() plusieurs fois. Vous devriez déplacer la plus grande partie de ce code vers une autre méthode appelée initDownload() qui est appelée une seule fois pour effectuer toute la configuration. Ensuite, downloadFilesFromDrone doit être appelé plusieurs fois, en appelant fetchData() sur le fichier suivant de votre liste. – biomiker