通过上传大块的视频文件 [英] Upload a video file by chunks

查看:204
本文介绍了通过上传大块的视频文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是,它与很多细节的长的问题... 所以,我的问题是:我如何能在段流上传到Vimeo

Yes, it's a long question with a lot of detail... So, my question is: How can I stream an upload to Vimeo in segments?

对于任何人想要复制并调试自己的机器上:这里有你需要的东西:

For anyone wanting to copy and debug on their own machine: Here are the things you need:


  • 我的code 这里

  • 包括抄写员库中找到这里

  • 有一个有效的视频文件(MP4),这是至少大于10 MB,并把它放在目录 C:\\ test.mp4 或更改code到地方点你的是。

  • 这就是它!谢谢你帮我出去!

  • My code here.
  • Include the Scribe library found here
  • Have a valid video file (mp4) which is at least greater than 10 MB and put it in the directory C:\test.mp4 or change that code to point wherever yours is.
  • That's it! Thanks for helping me out!

大更新:我已经离开了Vimeo的工作API密钥和秘密在code的此处。所以只要你有一个Vimeo账户,一旦你允许的应用程序并输入令牌的所有code应该只是罚款你。刚刚从该链接复制code到您喜欢的IDE的项目,并看看你能不能和我一起解决这个问题。我就给赏金给​​谁就给我的工作code。谢谢!哦,不要指望用这个Key和Secret长。一旦这个问题得到解决的,我会删除它。 :)

Big update: I've left a working API Key and Secret for Vimeo in the code here. So as long as you have a Vimeo account, all the code should work just fine for you once you've allowed the application and entered your token. Just copy the code from that link into a project on your favorite IDE and see if you can fix this with me. I'll give the bounty to whoever gives me the working code. Thanks! Oh, and don't expect to use this Key and Secret for long. Once this problem's resolved I'll delete it. :)

问题的概述:问题是,当我字节的最后一个块发送到Vimeo然后验证上传,响应返回的所有内容的长度是只有长度最后一个块,并不是所有的块组合成所应当的。

Overview of the problem: The problem is when I send the last chunk of bytes to Vimeo and then verify the upload, the response returns that the length of all the content is the length of only the last chunk, not all the chunks combined as it should be.

SSCCE注意:我有我的整个SSCCE 这里。我把它放在别的地方,因此它可以是 C ompilable。是不是很取值园艺(大约300线),但希望你觉得这是<强>取值精灵包含的,它肯定是一个电子 xample!)。我,但是,我张贴code的相关部分在这个岗位。

SSCCE Note: I have my entire SSCCE here. I put it somewhere else so it can be C ompilable. It is NOT very S hort (about 300 lines), but hopefully you find it to be S elf-contained, and it's certainly an E xample!). I am, however, posting the relevant portions of my code in this post.

这是如何工作的:如果您通过流媒体方式上传到Vimeo的视频(见上传API文档的这里设置才能到了这一点),你必须给几个标题:终端,内容长度和内容类型。文档说,它忽略了其他任何头。您也给它的你要上传的文件字节的信息的有效载荷。然后签署并发送(我有这将做到这一点使用的方法)。

This is how it works: When you upload a video to Vimeo via the streaming method (see Upload API documentation here for setup to get to this point), you have to give a few headers: endpoint, content-length, and content-type. The documentation says it ignores any other headers. You also give it a payload of the byte information for the file you're uploading. And then sign and send it (I have a method which will do this using scribe).

我的问题:一切都很正常,当我刚刚发送视频的一个请求。我的问题是,当我上载几个大文件的情况下,我使用的是没有足够的内存来加载所有这些字节的信息,并把它放在HTTP PUT请求的计算机,所以我必须把它分割成1 MB段。这就是事情变得棘手。文档提到,这是可能的简历上载,所以我尝试这样做,我的code,但它不工作很正确。下面,你会看到code发送的视频。 记住我SSCCE是这里

My problem: Everything works great when I just send the video in one request. My problem is in cases when I'm uploading several bigger files, the computer I'm using doesn't have enough memory to load all of that byte information and put it in the HTTP PUT request, so I have to split it up into 1 MB segments. This is where things get tricky. The documentation mentions that it's possible to "resume" uploads, so I'm trying to do that with my code, but it's not working quite right. Below, you'll see the code for sending the video. Remember my SSCCE is here.

事情我已经试过:我想它有什么做的内容Range头......因此,这里有我在改变什么内容范围尝试的事情头说...

Things I've tried: I'm thinking it has something to do with the Content-Range header... So here are the things I've tried in changing what the Content-Range header says...


  • 不添加内容范围标头第一块

  • 添加preFIX到内容范围标题(每个与previous头的组合):

  • Not adding content range header to the first chunk
  • Adding a prefix to the content range header (each with a combination of the previous header):


  • 字节

  • 字节(抛出连接错误,请参见错误的最底部) - >它出现在的文档,这是他们在找什么,但我pretty肯定有文档中的拼写错误,因为他们有自己的简历例如内容范围头为: 1001-339108 / 339108 当它应该是 1001-339107 / 339108 。所以...是啊...

  • 字节%20

  • 字节:

  • 字节:

  • 字节=

  • 字节=

  • "bytes"
  • "bytes " (throws connection error, see the very bottom for the error) --> It appears in the documentation that this is what they're looking for, but I'm pretty sure there are typos in the documentation because they have the content-range header on their "resume" example as: 1001-339108/339108 when it should be 1001-339107/339108. So... Yeah...
  • "bytes%20"
  • "bytes:"
  • "bytes: "
  • "bytes="
  • "bytes= "

不添加任何东西作为preFIX的含量范围标头

Not adding anything as a prefix to the content range header

这里的code:

/**
* 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方式:

Here's the signAndSendToVimeo method:

/**
* 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;
}

和这里的部分(一个例子...所有的输出,可以发现这里)从printRequest和printResponse方法的输出:注意:此输出取决于改变什么 contentRangeHeader preFIX 设置为和在第一布尔值设置为(指定是否要包括第一个块中的Content-Range头)。

And here's some (an example... All of the output can be found here) of the output from the printRequest and printResponse methods: NOTE This output changes depending on what the contentRangeHeaderPrefix is set to and the first boolean is set to (which specifies whether or not to include the Content-Range header on the first chunk).

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: 

然后code接着完成上传并设置视频信息(你可以看到,在我的全code )。

编辑2:试图消除从内容范围%20,并获得该错误使得连接。我必须使用字节%20或不加字节在所有...

Edit 2: Tried removing the "%20" from the content-range and received this error making connection. I must use either "bytes%20" or not add "bytes" at all...

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:更新了code和输出。仍然需要帮助!

Edit 1: Updated the code and output. Still need help!

推荐答案

我觉得你的问题可能仅仅是此行的结果是:

I think your problem could simply be the result of this line:

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

尝试更换字节%20通过简单的字节

在您的输出可以看到相应的标题中有不正确的内容:

In your output you see the corresponding header has incorrect content:

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

内容范围的话题 ...

On the topic of Content-Range...

您说得对,内容的一个例子最终块应该有一个范围,比如 14680064-15125119 / 15125120 。这就是HTTP 1.1规范的一部分。

You're right that an example final block of content should have a range like 14680064-15125119/15125120. That's part of the HTTP 1.1 spec.

这篇关于通过上传大块的视频文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆