2012-04-11 44 views
6

द्वारा एक वीडियो फ़ाइल अपलोड करें हां, यह बहुत विस्तार से एक लंबा प्रश्न है ... तो, मेरा सवाल है: मैं सेगमेंट में वीमियो को अपलोड कैसे कर सकता हूं?चंक्स

अपने स्वयं मशीन पर कॉपी और डिबग के लिए इच्छुक किसी के लिए:

  • मेरे कोड here: यहाँ चीजें आप की जरूरत है।
  • शामिल स्क्राइब पुस्तकालय पाया here
  • कोई मान्य वीडियो फ़ाइल (MP4) जो 10 MB से कम से कम अधिक है है और बात करने के लिए जहाँ कहीं भी तुम्हारा है निर्देशिका C:\test.mp4 में रख या कि कोड बदल जाते हैं।
  • यही वह है! मेरी मदद करने के लिए धन्यवाद!

बिग अद्यतन: मैं कोड here में Vimeo के लिए एक काम कर API कुंजी और गुप्त छोड़ दिया है। इसलिए जब तक आपके पास Vimeo खाता है, तब तक जब आप एप्लिकेशन को अनुमति देते हैं और अपना टोकन दर्ज करते हैं तो सभी कोड आपके लिए ठीक काम करना चाहिए। बस उस लिंक से कोड को अपने पसंदीदा आईडीई पर एक प्रोजेक्ट में कॉपी करें और देखें कि क्या आप इसे मेरे साथ ठीक कर सकते हैं। मैं जो भी मुझे कामकाजी कोड देता हूं उसे बक्षीस दूंगा। धन्यवाद! ओह, और लंबे समय तक इस कुंजी और गुप्त का उपयोग करने की उम्मीद नहीं है। एक बार यह समस्या हल हो जाने के बाद मैं इसे हटा दूंगा। समस्या का :)

अवलोकन: समस्या है जब मैं Vimeo बाइट्स के अंतिम हिस्सा भेजने और अपलोड करने की पुष्टि, प्रतिक्रिया लौटाता है कि सभी सामग्री की लंबाई केवल पिछले हिस्सा की लंबाई है , सभी हिस्सों को संयुक्त नहीं होना चाहिए।

एसएससीसीई नोट: मेरे पास मेरा पूरा एसएससीसीई here है। मैंने इसे कहीं और रखा है, इसलिए यह सी अयोग्य हो सकता है। यह बहुत एस हॉर्ट (लगभग 300 लाइनें) नहीं है, लेकिन उम्मीद है कि आपको एस एल्फ-निहित होना चाहिए, और यह निश्चित रूप से xample!) है। हालांकि, मैं इस पोस्ट में अपने कोड के प्रासंगिक भाग पोस्ट कर रहा हूं। , सामग्री- समाप्ति बिंदु:

यह है कि यह कैसे काम करता है: आप स्ट्रीमिंग विधि के माध्यम से Vimeo करने के लिए एक वीडियो अपलोड करते हैं (अपलोड API दस्तावेज़ here देख सेटअप इस बिंदु को पाने के लिए के लिए), तो आपको कुछ हेडर देना है लंबाई, और सामग्री प्रकार। दस्तावेज कहता है कि यह किसी भी अन्य शीर्षकों को अनदेखा करता है। आप इसे अपलोड करने वाली फ़ाइल के लिए बाइट जानकारी का एक पेलोड भी देते हैं। और उसके बाद हस्ताक्षर करें और भेजें (मेरे पास एक तरीका है जो scribe का उपयोग करके ऐसा करेगा)।

मेरी समस्या: जब मैं सिर्फ एक अनुरोध में वीडियो भेजता हूं तो सबकुछ बढ़िया काम करता है। मेरी समस्या उन मामलों में है जब मैं कई बड़ी फाइलें अपलोड कर रहा हूं, कंप्यूटर जो मैं उपयोग कर रहा हूं उसमें सभी बाइट जानकारी लोड करने के लिए पर्याप्त स्मृति नहीं है और इसे HTTP PUT अनुरोध में डाल दिया गया है, इसलिए मुझे इसे विभाजित करना है 1 एमबी सेगमेंट यह वह जगह है जहां चीजें मुश्किल हो जाती हैं। प्रलेखन का उल्लेख है कि अपलोड को "फिर से शुरू करना" संभव है, इसलिए मैं इसे अपने कोड के साथ करने की कोशिश कर रहा हूं, लेकिन यह बिल्कुल सही काम नहीं कर रहा है। नीचे, आप वीडियो भेजने के लिए कोड देखेंगे। याद रखें मेरी SSCCE here है।

जो चीजें मैंने कोशिश की हैं: मुझे लगता है कि यह सामग्री-श्रेणी शीर्षलेख के साथ कुछ करने के लिए है ...तो यहाँ बातें मैं बदल रहा है क्या सामग्री रेंज हैडर का कहना है में की कोशिश की है ...

  • पहले हिस्सा
  • सामग्री रेंज शीर्षक के एक उपसर्ग जोड़ने के लिए सामग्री सीमा हेडर को जोड़े नहीं (प्रत्येक रहे हैं पिछले हैडर का एक संयोजन) के साथ:

    • "बाइट"
    • "बाइट" (कनेक्शन त्रुटि फेंकता है, त्रुटि के लिए बहुत नीचे देखें) -> यह documentation में प्रतीत होता है कि यह क्या है वे की तलाश में है, लेकिन मुझे यकीन है कि टी हैं दस्तावेज में ypos क्योंकि उनके पास "resume" उदाहरण पर सामग्री-श्रेणी शीर्षलेख है: 1001-339108/339108 जब यह 1001-339107/339108 होना चाहिए। तो ... हाँ ...
    • "बाइट्स% 20"
    • "बाइट:"
    • "बाइट:"
    • "बाइट्स ="
    • "बाइट्स ="
  • सामग्री रेंज हैडर

यहाँ करने के लिए एक उपसर्ग के रूप में कुछ भी जोड़ने नहीं कोड है:

01,235,
/** 
* Send the video data 
* 
* @return whether the video successfully sent 
*/ 
private static boolean sendVideo(String endpoint, File file) throws FileNotFoundException, IOException { 
    // Setup File 
    long contentLength = file.length(); 
    String contentLengthString = Long.toString(contentLength); 
    FileInputStream is = new FileInputStream(file); 
    int bufferSize = 10485760; // 10 MB = 10485760 bytes 
    byte[] bytesPortion = new byte[bufferSize]; 
    int byteNumber = 0; 
    int maxAttempts = 1; 
    while (is.read(bytesPortion, 0, bufferSize) != -1) { 
    String contentRange = Integer.toString(byteNumber); 
    long bytesLeft = contentLength - byteNumber; 
    System.out.println(newline + newline + "Bytes Left: " + bytesLeft); 
    if (bytesLeft < bufferSize) { 
     //copy the bytesPortion array into a smaller array containing only the remaining bytes 
     bytesPortion = Arrays.copyOf(bytesPortion, (int) bytesLeft); 
     //This just makes it so it doesn't throw an IndexOutOfBounds exception on the next while iteration. It shouldn't get past another iteration 
     bufferSize = (int) bytesLeft; 
    } 
    byteNumber += bytesPortion.length; 
    contentRange += "-" + (byteNumber - 1) + "/" + contentLengthString; 
    int attempts = 0; 
    boolean success = false; 
    while (attempts < maxAttempts && !success) { 
     int bytesOnServer = sendVideoBytes("Test video", endpoint, contentLengthString, "video/mp4", contentRange, bytesPortion, first); 
     if (bytesOnServer == byteNumber) { 
     success = true; 
     } else { 
     System.out.println(bytesOnServer + " != " + byteNumber); 
     System.out.println("Success is not true!"); 
     } 
     attempts++; 
    } 
    first = true; 
    if (!success) { 
     return false; 
    } 
    } 
    return true; 
} 

/** 
* Sends the given bytes to the given endpoint 
* 
* @return the last byte on the server (from verifyUpload(endpoint)) 
*/ 
private static int sendVideoBytes(String videoTitle, String endpoint, String contentLength, String fileType, String contentRange, byte[] fileBytes, boolean addContentRange) throws FileNotFoundException, IOException { 
    OAuthRequest request = new OAuthRequest(Verb.PUT, endpoint); 
    request.addHeader("Content-Length", contentLength); 
    request.addHeader("Content-Type", fileType); 
    if (addContentRange) { 
    request.addHeader("Content-Range", contentRangeHeaderPrefix + contentRange); 
    } 
    request.addPayload(fileBytes); 
    Response response = signAndSendToVimeo(request, "sendVideo on " + videoTitle, false); 
    if (response.getCode() != 200 && !response.isSuccessful()) { 
    return -1; 
    } 
    return verifyUpload(endpoint); 
} 

/** 
* Verifies the upload and returns whether it's successful 
* 
* @param endpoint to verify upload to 
* @return the last byte on the server 
*/ 
public static int verifyUpload(String endpoint) { 
    // Verify the upload 
    OAuthRequest request = new OAuthRequest(Verb.PUT, endpoint); 
    request.addHeader("Content-Length", "0"); 
    request.addHeader("Content-Range", "bytes */*"); 
    Response response = signAndSendToVimeo(request, "verifyUpload to " + endpoint, true); 
    if (response.getCode() != 308 || !response.isSuccessful()) { 
    return -1; 
    } 
    String range = response.getHeader("Range"); 
    //range = "bytes=0-10485759" 
    return Integer.parseInt(range.substring(range.lastIndexOf("-") + 1)) + 1; 
    //The + 1 at the end is because Vimeo gives you 0-whatever byte where 0 = the first byte 
} 

यहाँ signAndSendToVimeo विधि है:

/** 
* Signs the request and sends it. Returns the response. 
* 
* @param service 
* @param accessToken 
* @param request 
* @return response 
*/ 
public static Response signAndSendToVimeo(OAuthRequest request, String description, boolean printBody) throws org.scribe.exceptions.OAuthException { 
    System.out.println(newline + newline 
      + "Signing " + description + " request:" 
      + ((printBody && !request.getBodyContents().isEmpty()) ? newline + "\tBody Contents:" + request.getBodyContents() : "") 
      + ((!request.getHeaders().isEmpty()) ? newline + "\tHeaders: " + request.getHeaders() : "")); 
    service.signRequest(accessToken, request); 
    printRequest(request, description); 
    Response response = request.send(); 
    printResponse(response, description, printBody); 
    return response; 
} 

और यहाँ कुछ (एक उदाहरण ... उत्पादन के सभी here पाया जा सकता है) printRequest और printResponse तरीकों से उत्पादन की है: नोट यह आउटपुट contentRangeHeaderPrefix पर सेट किया गया है और first बूलियन पर सेट किया गया है (जो निर्दिष्ट करता है कि पहले खंड पर सामग्री-श्रेणी शीर्षलेख शामिल करना है या नहीं)।

We're sending the video for upload! 


Bytes Left: 15125120 


Signing sendVideo on Test video request: 
    Headers: {Content-Length=15125120, Content-Type=video/mp4, Content-Range=bytes%200-10485759/15125120} 

sendVideo on Test video >>> Request 
Headers: {Authorization=OAuth oauth_signature="zUdkaaoJyvz%2Bt6zoMvAFvX0DRkc%3D", oauth_version="1.0", oauth_nonce="340477132", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="5cb447d1fc4c3308e2c6531e45bcadf1", oauth_token="460633205c55d3f1806bcab04174ae09", oauth_timestamp="1334336004", Content-Length=15125120, Content-Type=video/mp4, Content-Range=bytes: 0-10485759/15125120} 
Verb: PUT 
Complete URL: http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d 

sendVideo on Test video >>> Response 
Code: 200 
Headers: {null=HTTP/1.1 200 OK, Content-Length=0, Connection=close, Content-Type=text/plain, Server=Vimeo/1.0} 


Signing verifyUpload to http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d request: 
    Headers: {Content-Length=0, Content-Range=bytes */*} 

verifyUpload to http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d >>> Request 
Headers: {Authorization=OAuth oauth_signature="FQg8HJe84nrUTdyvMJGM37dpNpI%3D", oauth_version="1.0", oauth_nonce="298157825", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="5cb447d1fc4c3308e2c6531e45bcadf1", oauth_token="460633205c55d3f1806bcab04174ae09", oauth_timestamp="1334336015", Content-Length=0, Content-Range=bytes */*} 
Verb: PUT 
Complete URL: http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d 

verifyUpload to http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d >>> Response 
Code: 308 
Headers: {null=HTTP/1.1 308 Resume Incomplete, Range=bytes=0-10485759, Content-Length=0, Connection=close, Content-Type=text/plain, Server=Vimeo/1.0} 
Body: 


Bytes Left: 4639360 


Signing sendVideo on Test video request: 
    Headers: {Content-Length=15125120, Content-Type=video/mp4, Content-Range=bytes: 10485760-15125119/15125120} 

sendVideo on Test video >>> Request 
Headers: {Authorization=OAuth oauth_signature="qspQBu42HVhQ7sDpzKGeu3%2Bn8tM%3D", oauth_version="1.0", oauth_nonce="183131870", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="5cb447d1fc4c3308e2c6531e45bcadf1", oauth_token="460633205c55d3f1806bcab04174ae09", oauth_timestamp="1334336015", Content-Length=15125120, Content-Type=video/mp4, Content-Range=bytes%2010485760-15125119/15125120} 
Verb: PUT 
Complete URL: http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d 

sendVideo on Test video >>> Response 
Code: 200 
Headers: {null=HTTP/1.1 200 OK, Content-Length=0, Connection=close, Content-Type=text/plain, Server=Vimeo/1.0} 


Signing verifyUpload to http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d request: 
    Headers: {Content-Length=0, Content-Range=bytes */*} 

verifyUpload to http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d >>> Request 
Headers: {Authorization=OAuth oauth_signature="IdhhhBryzCa5eYqSPKAQfnVFpIg%3D", oauth_version="1.0", oauth_nonce="442087608", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="5cb447d1fc4c3308e2c6531e45bcadf1", oauth_token="460633205c55d3f1806bcab04174ae09", oauth_timestamp="1334336020", Content-Length=0, Content-Range=bytes */*} 
Verb: PUT 
Complete URL: http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d 

4639359 != 15125120 
verifyUpload to http://174.129.125.96:8080/upload?ticket_id=5ea64d64547e38e5e3c121852b2d306d >>> Response 
Success is not true! 
Code: 308 
Headers: {null=HTTP/1.1 308 Resume Incomplete, Range=bytes=0-4639359, Content-Length=0, Connection=close, Content-Type=text/plain, Server=Vimeo/1.0} 
Body: 

तो कोड अपलोड और सेट वीडियो जानकारी पूरा करने के लिए पर चला जाता है (आपको लगता है कि my full code में देख सकते हैं)।

संपादित करें 2: सामग्री-सीमा से "% 20" को निकालने का प्रयास किया और यह त्रुटि कनेक्शन बना। मैं या तो "बाइट्स% 20" का उपयोग करना चाहिए या नहीं जोड़ "बाइट" बिल्कुल ...

Exception in thread "main" org.scribe.exceptions.OAuthException: Problems while creating connection. 
    at org.scribe.model.Request.send(Request.java:70) 
    at org.scribe.model.OAuthRequest.send(OAuthRequest.java:12) 
    at autouploadermodel.VimeoTest.signAndSendToVimeo(VimeoTest.java:282) 
    at autouploadermodel.VimeoTest.sendVideoBytes(VimeoTest.java:130) 
    at autouploadermodel.VimeoTest.sendVideo(VimeoTest.java:105) 
    at autouploadermodel.VimeoTest.main(VimeoTest.java:62) 
Caused by: java.io.IOException: Error writing to server 
    at sun.net.www.protocol.http.HttpURLConnection.writeRequests(HttpURLConnection.java:622) 
    at sun.net.www.protocol.http.HttpURLConnection.writeRequests(HttpURLConnection.java:634) 
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1317) 
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468) 
    at org.scribe.model.Response.<init>(Response.java:28) 
    at org.scribe.model.Request.doSend(Request.java:110) 
    at org.scribe.model.Request.send(Request.java:62) 
    ... 5 more 
Java Result: 1 

संपादित करें 1: कोड और आउटपुट अपडेट किया गया। अभी भी सहायता चाहिए!

+0

तुम्हारा के अलावा अन्य खातों की तरह लग रहा अपनी API कुंजी + गुप्त उपयोग करने में सक्षम नहीं हैं। हालांकि, मुझे पुनः अपलोड करने योग्य अपलोड पर कुछ और दस्तावेज मिल गए हैं और पता चला है कि 1. हेडर वास्तव में "सामग्री-श्रेणी: बाइट 0-49 9/1000" और 2 जैसा दिखना चाहिए। 2. आपके अंतिम PUT के लिए शीर्षलेख इस तरह दिखना चाहिए " सामग्री-रेंज: 500-999/1000 बाइट्स "। http://code.google.com/apis/gdata/docs/resumable_upload.html#Resuming – TomTasche

+0

अजीब Vimeo API चीज काम नहीं कर रही है। @anyone else: क्या यह आपके लिए भी वही है? मैं अपने हेडर को ऐसा संकेत नहीं दे रहा हूं जैसा आपने संकेत दिया है क्योंकि जब मैं बाइट्स को उपसर्ग के रूप में "बाइट्स" का उपयोग करता हूं तो यह एक कनेक्शन अपवाद फेंकता है (ऊपर त्रुटि देखें)। – kentcdodds

+0

आपके द्वारा छोड़े गए 'काम कर रहे एपीआई' का लिंक टूटा हुआ है! –

उत्तर

6

मुझे लगता है कि आपकी समस्या को बस इस लाइन का परिणाम हो सकता है:

:

request.addHeader("Content-Range", "bytes%20" + contentRange); 

प्रयास करें और केवल "bytes "

अपने उत्पादन जैसा कि आप देख में से "bytes%20" की जगह इसी हेडर गलत सामग्री है

Headers: { 
    Content-Length=15125120, 
    Content-Type=video/mp4, 
    Content-Range=bytes%200-10485759/15125120  <-- INCORRECT 
} 

Content-Range के विषय पर ...

आप सही हैं कि सामग्री का एक अंतिम अंतिम ब्लॉक 14680064-15125119/15125120 जैसा होना चाहिए। वह HTTP 1.1 spec का हिस्सा है।

+0

कोशिश की। नीचे 2 संपादित करें देखें। – kentcdodds

+0

मुझे विश्वास है कि '% 20' गलत है और नतीजतन, सर्वर 'सामग्री-श्रेणी' शीर्षलेख को हटा रहा है और फ़ाइल की शुरुआत के रूप में आपके डेटा को इंटरैपेट कर रहा है। इमो अगला कदम है जिसे आप हटाए गए त्रुटि को '% 20' से रोकते हैं। हां, मुझे पता है कि यह कुछ भी हल नहीं करता है, क्षमा करें :) – Torious

+0

आप अभी भी पहले कंक अपलोड अनुरोध से 'सामग्री-श्रेणी' शीर्षलेख को छोड़ने का प्रयास कर सकते हैं, जिसमें केवल बाद के अनुरोधों ('% 20' के बिना) शामिल हैं। – Torious

2

यहाँ

String contentRange = Integer.toString(byteNumber + 1); 

आप 1 और नहीं से 0 से पहले यात्रा पर शुरू करते हैं।

यहाँ

request.addHeader("Content-Length", contentLength); 

आप पूरी फ़ाइल सामग्री की लंबाई और नहीं वर्तमान हिस्सा की लंबाई डाल दिया।

+0

उत्तर के लिए धन्यवाद। प्रारंभ में मेरे पास थोड़ी देर से पहले 'byteNumber = 0' था, अब यह' byteNumber = -1' है, इसलिए यह पहली सामग्री रेंज स्ट्रिंग पर 0 से शुरू होता है। अभी भी काम नहीं किया। मुझे यकीन नहीं है कि क्यों, लेकिन सत्यापन प्रतिक्रिया अभी भी इंगित करती है कि सर्वर पर केवल बाइट्स हाल ही में अपलोड किए गए हैं। अगर मैं प्रत्येक पुनरावृत्ति में सत्यापन करता हूं, तो परिणाम वही होता है (केवल सर्वर पर बाइट हाल ही में अपलोड किए गए हैं)। यदि आप कृपया इस के माध्यम से मेरी मदद कर सकते हैं तो मैं वास्तव में इसकी सराहना करता हूं! धन्यवाद। – kentcdodds

+1

एक त्रुटि तय की गई है, अब हम दूसरे की खोज करेंगे: डी – dash1e

+0

वैसे, आप इस टिप्पणी में देखेंगे (http://vimeo.com/forums/topic:49393#comment_6729467) Vimeo API फोरम पर (जो किसी कारण से मैं पोस्ट नहीं कर सकता) कि आखिरी बिट के बारे में कुछ अजीब बात है। मेरा अनुमान है कि इसका मतलब है कि मेरे आखिरी पुनरावृत्ति पर, मुझे सामग्री श्रेणी को '14680064-15125119/15125120' के बजाय' 14680064-15125120/15125120' के बजाय सेट करने की आवश्यकता है। सही? – kentcdodds

0

vimeo API पृष्ठ कहता है: "अंतिम चरण vimeo.videos.upload.complete को ट्रांसकोडिंग के लिए वीडियो कतार में कॉल करना है। यह कॉल वीडियो_आईडी वापस कर देगी, जिसे आप अन्य कॉलों में उपयोग कर सकते हैं शीर्षक, वर्णन, गोपनीयता, आदि सेट करें)। यदि आप इस विधि को नहीं कहते हैं, तो वीडियो संसाधित नहीं किया जाएगा। "

मैं अंत करने के लिए कोड के इस बिट जोड़ा गया है और यह काम करने के लिए मिल गया:

request = new OAuthRequest(Verb.PUT, "http://vimeo.com/api/rest/v2"); 
    request.addQuerystringParameter("method", "vimeo.videos.upload.complete"); 
    request.addQuerystringParameter("filename", video.getName()); 
    request.addQuerystringParameter("ticket_id", ticket); 
    service.signRequest(token, request);   

    response = request.send();