2016-04-11 2 views
4

Я пытаюсь отправить видеофайл с моего устройства Android на сервер (который использует PHP для обработки запроса). Я использовал залп для других запросов, которые я сделал на том же сервере, но когда я пытаюсь отправить видеофайл (как Base64 String) на сервер, я получаю OutOfMemoryError. Мне было интересно, есть ли способ отправить файл по-другому (возможно, используя поток).Отправить большой (видео) файл (ы) с Android на PHP Server

Это мой текущий метод, чтобы отправить видео файл:

private void syncFullVideos() { 
    checkPermissions(); 
    if (pDialog == null || !pDialog.isShowing()) { 
     pDialog = new ProgressDialog(this); 
     pDialog.setCanceledOnTouchOutside(false); 
     pDialog.setMessage(getString(R.string.pDialogSync)); 
     pDialog.show(); 
    } 
    syncSucces = new boolean[syncVideos.size()]; 
    Arrays.fill(syncSucces, Boolean.FALSE); 
    for (final Video video: syncVideos) { 
     String picturepath = video.getImage_path(); 
     if (fileExists(picturepath)) { 
      File videoFile = new File(picturepath); 
      FileInputStream fin = null; 
      byte[] byte_arr = null; 
      try { 
       fin = new FileInputStream(videoFile); 
       byte_arr = new byte[(int)videoFile.length()]; 
       fin.read(byte_arr); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      final String image_str = Base64.encodeToString(byte_arr, 0); 
      Log.d("SyncFullVideos", video.toString()); 
      String tag_string_req = "string_req"; 
      final String TAG = AppController.class 
        .getSimpleName(); 
      String url = "http://android.diggin.io/diggin/v1/videos"; 

      StringRequest strReq = new StringRequest(Request.Method.PUT, 
        url, new Response.Listener<String>() { 

       @Override 
       public void onResponse(String response) { 
        Log.d(TAG, response); 
        try { 
         final JSONObject jsonObject = new JSONObject(response); 
         if (!jsonObject.getBoolean("error4")) { 
          int index = jsonObject.getInt("index"); 
          syncSucces[index] = true; 
          Log.e("AddSucces(" + (addCount + 1) + "/" + (syncVideos.size()) + ")", video.toString()); 
          addCount++; 
          if (addCount == syncVideos.size()) { 
           refreshPhotos(); 
          } 
         } else { 
          Log.e("AddFail(" + (addCount + 1) + "/" + (syncVideos.size()) + ")", video.toString()); 
          addCount++; 
          if (addCount == syncVideos.size()) { 
           refreshPhotos(); 
          } 
         } 
        } catch (JSONException e) { 
         e.printStackTrace(); 
        } 
       } 
      }, new Response.ErrorListener() { 

       @Override 
       public void onErrorResponse(VolleyError error) { 
        VolleyLog.d(TAG, "Error: " + error.getMessage()); 
        //Send message when something goes wrong 
        runOnUiThread(new Runnable() { 
         @Override 
         public void run() { 
          pDialog.hide(); 
          AlertDialog.Builder dlgAlert = new AlertDialog.Builder(PictureActivity.this); 
          dlgAlert.setMessage(R.string.errFullSyncVids); 
          dlgAlert.setPositiveButton(R.string.errBtnOK, null); 
          dlgAlert.setCancelable(true); 
          dlgAlert.create().show(); 
         } 
        }); 
       } 
      }) { 

       @Override 
       protected Map<String, String> getParams() { 
        Map<String, String> params = new HashMap<>(); 
        params.put("id", String.valueOf(video.getId())); 
        params.put("im_path", video.getDBImage_path()); 
        params.put("image", image_str); 
        params.put("index", String.valueOf(syncVideos.indexOf(video))); 
        return params; 
       } 
      }; 

      // Adding request to request queue 
      AppController.getInstance().addToRequestQueue(strReq, tag_string_req); 
     } 
    } 
} 

И это PHP я использую, чтобы обработать запрос и отправить ответ (я использую REST API):

$app->put('/videos', function() use ($app) { 
    // check for required params 
    verifyRequiredParams(array('id','im_path','image','index')); 
    $response = array(); 
    $id = $app->request->put('id'); 
    $im_path = $app->request->put('im_path'); 
    $image = $app->request->put('image'); 
    $index = $app->request->put('index'); 
    $db = new DbHandler(); 

    // update photo 
    $result = $db->updateVideo($id, $im_path); 

    if ($result) { 
     $response["error"] = false; 
     $response["message"] = "Video updated successfully"; 
     // Decode Image 
     $binary=base64_decode($image); 
     header('Content-Type: video/mp4'); 
     $im_path2 = explode("_",$im_path); 
     $im_path2[0] .= 's'; 
     $im_path2[2] = $im_path; 
     $im_path3 = implode("/",$im_path2); 
     $filepath = '../images/'.$im_path3; 
     $dirname = dirname($filepath); 
     if (!is_dir($dirname)) 
     { 
      if(mkdir($dirname, 0777, true)) { 
       $response["error2"] = false; 
       $response["message2"] = "Directory Created Succesfully"; 
      } else { 
       $response["error2"] = true; 
       $response["error3"] = true; 
       $response["error4"] = true; 
       $response["message2"] = "Failed to create directory. Please try again"; 
       $response["filepath"] = $filepath; 
      } 
     } 
     // Images will be saved under images folder 
     $file = fopen($filepath, 'wb'); 
     if ($file == false) { 
      $response["error3"] = true; 
      $response["error4"] = true; 
      $response["message3"] = "Failed to open file. Please try again"; 
      $response["filepath"] = $filepath; 
      echoRespnse(200, $response); 
     } else { 
      // Create File 
      $response["error3"] = false; 
      $response["message3"] = "File is open and good to write"; 
      fwrite($file, $binary); 
      fclose($file); 
      if (file_exists($filepath)) { 
       $response["error4"] = false; 
       $response["message4"] = "File exists"; 
       $response["index"] = $index; 
       echoRespnse(201, $response); 
      } else { 
       $response["error4"] = true; 
       $response["message4"] = "File doesn't exist"; 
       echoRespnse(200, $response); 
      } 
     } 
    } else { 
     $response["error"] = true; 
     $response["error2"] = true; 
     $response["error3"] = true; 
     $response["error4"] = true; 
     $response["message"] = "Failed to update video. Please try again"; 
     $response["id"] = $id; 
     $response["im_path"] = $im_path; 
     echoRespnse(200, $response); 
    }    
}); 
+0

Насколько велик видеофайл? Это может быть размер файла, а не тип, который является проблемой. –

+0

@StuartWhitehouse. Для последнего теста я использовал файл размером около 20 МБ, но другие файлы могут быть больше –

ответ

0

После тестирования много разных вещей, которые я нашел способ, используя HttpURLConnection, вот новая версия метода syncFullVideos:

private void syncFullVideos() { 
    new StreamFileTask().execute(); 
} 

private class StreamFileTask extends AsyncTask<Void,Integer,Void> { 

    protected Void doInBackground(Void... params) { 
     syncSucces2 = new boolean[syncVideos.size()]; 
     Arrays.fill(syncSucces2, Boolean.FALSE); 
     for (int i = 0; i < syncVideos.size(); i++) { 
      Video video = syncVideos.get(i); 
      String picturepath = video.getImage_path(); 
      if (fileExists(picturepath)) { 
       File sourceFile = new File(picturepath); 
       String fileName = video.getDBImage_path(); 
       int id = video.getId(); 
       int index = syncVideos.indexOf(video); 
       HttpURLConnection conn; 
       DataOutputStream dos; 
       int bytesRead, bytesAvailable, bufferSize; 
       byte[] buffer; 
       int maxBufferSize = 1024 * 1024; 
       int serverResponseCode; 
       Log.e("VideoUpload", "Uploading: sourcefileURI, " + fileName); 

       if (!sourceFile.isFile()) { 
        Log.e("uploadFile", "Source File not exist"); 
       } else { 
        try { 
         FileInputStream fin = new FileInputStream(sourceFile); 
         URL url = new URL("http://android.diggin.io/diggin/v1/vidUpload.php"); 
         Log.v("VideoUpload", url.toString()); 

         // Open a HTTP connection to the URL 
         conn = (HttpURLConnection) url.openConnection(); 
         conn.setDoInput(true); // Allow Inputs 
         conn.setDoOutput(true); // Allow Outputs 
         conn.setUseCaches(false); // Don't use a Cached Copy 
         conn.setRequestMethod("POST"); 
         conn.setRequestProperty("Connection", "Keep-Alive"); 
         conn.setRequestProperty("ENCTYPE", "multipart/form-data"); 
         conn.setRequestProperty("Content-Type", "multipart/form-data"); 
         conn.setRequestProperty("X_FILE_NAME", fileName); 
         conn.setRequestProperty("VID_ID", String.valueOf(id)); 
         conn.setRequestProperty("VID_INDEX", String.valueOf(index)); 
         conn.setRequestProperty("CONTENT_LENGTH", String.valueOf(sourceFile.length())); 
         publishProgress(2, i); 

         dos = new DataOutputStream(conn.getOutputStream()); 
         bytesAvailable = fin.available(); 
         int thirdOfBytes = bytesAvailable/3; 
         int state = 0; 
         bufferSize = Math.min(bytesAvailable, maxBufferSize); 
         buffer = new byte[bufferSize]; 
         bytesRead = fin.read(buffer, 0, bufferSize); 

         while (bytesRead > 0) { 
          dos.write(buffer, 0, bufferSize); 
          bytesAvailable = fin.available(); 
          bufferSize = Math.min(bytesAvailable, maxBufferSize); 
          bytesRead = fin.read(buffer, 0, bufferSize); 
          Log.i("VideoUpload", "->"); 
          if (bytesAvailable < thirdOfBytes && state == 1) { 
           publishProgress(4, i); 
           state = 2; 
          } else if (bytesAvailable < (2 * thirdOfBytes) && state == 0) { 
           publishProgress(3, i); 
           state = 1; 
          } 
         } 
         publishProgress(5, i); 

         serverResponseCode = conn.getResponseCode(); 
         String serverResponseMessage = conn.getResponseMessage(); 
         Log.i("VideoUpload", "HTTP Response is : " + serverResponseMessage + ": " + serverResponseCode); 
         publishProgress(9, i); 

         DataInputStream inStream; 
         HashMap<String,String> responseMap = new HashMap<>(); 
         try { 
          inStream = new DataInputStream(conn.getInputStream()); 
          String str; 
          while ((str = inStream.readLine()) != null) { 
           Log.e("VideoUpload", "SOF Server Response: " + str); 
           String[] responseItem = str.split(" - "); 
           responseMap.put(responseItem[0], responseItem[1]); 
          } 
          inStream.close(); 
          if (responseMap.get("ERROR").equals("FALSE")) { 
           int index2 = Integer.parseInt(responseMap.get("INDEX")); 
           syncSucces2[index2] = true; 
           Log.e("AddSucces(" + (addCount + 1) + "/" + (syncVideos.size()) + ")", video.toString()); 
          } 
         } catch (IOException e) { 
          Log.e("VideoUpload", "SOF error: " + e.getMessage(), e); 
         } 
         fin.close(); 
         dos.flush(); 
         dos.close(); 
         publishProgress(10, i); 
        } catch (MalformedURLException ex) { 
         ex.printStackTrace(); 
         Log.e("VideoUpload", "UL error: " + ex.getMessage(), ex); 
        } catch (Exception e) { 
         e.printStackTrace(); 
         Log.e("UploadFileException", "Exception : " + e.getMessage(), e); 
        } 
       } 
      } 
     } 
     return null; 
    } 

    @Override 
    protected void onProgressUpdate(Integer... values) { 
     super.onProgressUpdate(values); 
     progressBar.setProgress(values[0] + (values[1] * 10)); 
    } 

    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     progressBar = new ProgressDialog(PictureActivity.this); 
     progressBar.setMax(10 * syncVideos.size()); 
     progressBar.setMessage("Uploading Video File(s)"); 
     progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
     progressBar.setCancelable(false); 
     progressBar.show(); 
    } 

    @Override 
    protected void onPostExecute(Void aVoid) { 
     super.onPostExecute(aVoid); 
     progressBar.hide(); 
     refreshPhotos(); 
    } 
} 

И я изменил PHP много тоже, вместо того, чтобы использовать часть кода в файле index.php (с API REST) ​​Я сделал еще один файл с именем uploadVideo.php:

<?php 

require_once '../include/File_Streamer.php'; 
require_once '../include/DbHandler.php'; 


if (!isset($_SERVER['HTTP_X_FILE_NAME']) || !isset($_SERVER['HTTP_VID_ID']) || !isset($_SERVER['HTTP_VID_INDEX'])) { 
    throw new Exception("Invalid Headers!"); 
} else { 

    $im_path = $_SERVER['HTTP_X_FILE_NAME']; 
    $id = $_SERVER['HTTP_VID_ID']; 
    $index = $_SERVER['HTTP_VID_INDEX']; 
    $db = new DbHandler(); 
    $response = array(); 

    if($db->updateVideo($id, $im_path)) { 
     $im_path2 = explode("_",$im_path); 
     $im_path2[0] .= 's'; 
     $im_path2[2] = $im_path; 
     $im_path3 = implode("/",$im_path2); 
     $filepath = '../images/'.$im_path3; 
     $dirpath = str_replace($im_path,"",$filepath); 
     $ft = new File_Streamer(); 
     $ft->setDestination(__DIR__ . '/' . $dirpath); 
     if ($ft->receive()) { 
      echo "ERROR - FALSE\n"; 
      echo "MESSAGE - UPLOADED VIDEO WITH SUCCES\n"; 
      echo "INDEX - " . $index; 
     } else { 
      echo "ERROR - TRUE\n"; 
      echo "MESSAGE - FAILED TO SAVE VIDEO FILE"; 
     } 
    } else { 
     echo "ERROR - TRUE\n"; 
     echo "MESSAGE - FAILED TO ADD TO DATABASE"; 
    } 
} 

И я используя следующий класс:

<?php 
class File_Streamer 
{ 
    private $_fileName; 
    private $_contentLength; 
    private $_destination; 
    public function __construct() 
    { 
     if (!isset($_SERVER['HTTP_X_FILE_NAME']) 
       || !isset($_SERVER['CONTENT_LENGTH'])) { 
       throw new Exception("Invalid Headers!"); 
     } 

     $this->_fileName = $_SERVER['HTTP_X_FILE_NAME']; 
     $this->_contentLength = $_SERVER['CONTENT_LENGTH']; 
    } 
    public function isValid() 
    { 
     if (($this->_contentLength > 0)) { 
      return true; 
     } 
     return false; 
    } 
    public function setDestination($destination) 
    { 
     $this->_destination = $destination; 
    } 
    public function receive() 
    { 
     try { 
     if (!$this->isValid()) { 
      throw new Exception('No file uploaded!'); 
     } 
     $fileReader = fopen('php://input', "r"); 
     $fileWriter = fopen($this->_destination . $this->_fileName, "w+"); 
     while(true) { 
      $buffer = fgets($fileReader, 4096); 
      if (strlen($buffer) == 0) { 
       fclose($fileReader); 
       fclose($fileWriter); 
       return true; 
      } 
      fwrite($fileWriter, $buffer); 
     } 
     return false; 
     } 
     catch(Exception $ex) { 
      echo "error: " . $ex->getMessage(); 
     } 
    } 
} 
Смежные вопросы