For a project I am working on I have a few MP4 video files sitting on a Server.
A Java based web app I am writing needs to play these files in the browser. Due to a security restriction, only the server hosting the web app has access to this server, the browsers using the web app do not have access, making it impossible to use HTML 5 for play back.
The solution I am working on, is having a servlet (sitting on the web app server), access the video file. Write the video as it's output, and have the servlet be the source for the HTML player.
However I seem to be unable to successfully output the video file as servlet output in a streaming fashion.
I've done a large amount of research. The closest thing I came to a solution is this:
private static final int BUFFER_LENGTH = 1024 * 16;
private static final long EXPIRE_TIME = 1000 * 60 * 60 * 24;
private static final Pattern RANGE_PATTERN = Pattern.compile("bytes=(?<start>\\d*)-(?<end>\\d*)");
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
URL video = new URL("http://localhost/App/Videos/FileSD.mp4");
URLConnection yc = video.openConnection();
yc.setDoOutput(true);
int length = yc.getContentLength();
int start = 0;
int end = length - 1;
int contentLength = end - start + 1;
response.reset();
response.setBufferSize(BUFFER_LENGTH);
response.setHeader("Accept-Ranges", "bytes");
response.setDateHeader("Last-Modified", yc.getLastModified());
response.setDateHeader("Expires", System.currentTimeMillis()
+ EXPIRE_TIME);
response.setContentType(yc.getContentType());
response.setHeader("Content-Range",
String.format("bytes %s-%s/%s", start, end, length));
response.setHeader("Content-Length", String.format("%s", contentLength));
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
ReadableByteChannel input = Channels.newChannel(yc.getInputStream());
int bytesRead;
int bytesLeft = contentLength;
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_LENGTH);
try (OutputStream output = response.getOutputStream()) {
while ((bytesRead = input.read(buffer)) != -1 && bytesLeft > 0) {
buffer.clear();
output.write(buffer.array(), 0,
bytesLeft < bytesRead ? bytesLeft : bytesRead);
bytesLeft -= bytesRead;
output.flush();
}
output.close();
input.close();
}
}
For the most part, this code works fine, it takes a URL as input, and streams it as Output. The problem is, it only works for HD video files. SD video files simply don't play. Was hoping anyone has any idea why that is, and how it can be fixed.
Related
How to receive an image file through Rest APIs. There is an option of MULTIPART_FORM_DATA which looks like it will send files in parts as in more than one request.
I want to receive images very fast on server. around 2 images per second.
Simply read image in a File and use Response class to build the response.
Response.ok(new File("myimage.jpg"), "image/jpeg").build();
There are other variations of the same.
Read the image using following.
URL url = new URL("http://localhost:8080/myimage/1");
URLConnection connection = url.openConnection();
input = connection.getInputStream();
byte[] buffer = new byte[1024];
int n = - 1;
OutputStream fos = new FileOutputStream("Output.jpg" );
while ( (n = input.read(buffer)) != -1)
{
fos.write(buffer, 0, n);
}
fos.close();
You can use Apache HTTP client to make it prettier.
I try to download a file using services in android... I was able to write the program and I can download what ever I want. but the problem is with the progress bar!!!
I'm not able to define the total file length (or size) and the current downloaded size.
I used this code to get the file lenght
URL url = new URL(urlToDownload);
URLConnection connection = url.openConnection();
connection.connect();
int fileLength = connection.getContentLength();
and I used this part of code to define the current downloaded size
InputStream input = new BufferedInputStream(connection.getInputStream());
OutputStream output = new FileOutputStream("/sdcard/BarcodeScanner-debug.apk");
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
int currentValue=(total * 100 / fileLength);
output.write(data, 0, count);
}
the problem is that at the end of download I got something like 241% instead of 100% (because the fileLength for ex was around 12226 and the total was 29349)
Do you have any idea about this topic.
checkout this links for your reference
Download a file with Android, and showing the progress in a ProgressDialog
http://www.java-samples.com/showtutorial.php?tutorialid=1521
http://www.androidhive.info/2012/04/android-downloading-file-by-showing-progress-bar/
http://www.androidbegin.com/tutorial/android-download-progress-bar/
I'm trying to Gzip a file for output in Play Framework 2.2.1, with Java.
This is not an asset, it is not a static file. For instance, it can be a user avatar which the user uploads. For example, a PNG image.
I've searched a for this and found only how to GZIP strings and that the Play Framework does automatic Gzipping for public assets, which this is not.
Some code I've tried:
public static Result userAvatar(long userId) throws IOException {
UserAvatar avatar = UserAvatar.get(userId);
InputStream avatarStream;
Long version;
// Use the default avatar.
if (avatar == null) {
avatarStream = Play.current().resourceAsStream("public/images/noavatar.png").get();
version = 0L;
} else {
avatarStream = new ByteArrayInputStream(avatar.avatar);
version = avatar.version;
}
byte[] byteArray = IOUtils.toByteArray(avatarStream);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(byteArray.length);
OutputStream gzip = new GZIPOutputStream(outputStream);
int len;
while ((len = avatarStream.read(byteArray)) > 0) {
gzip.write(byteArray, 0, len);
}
avatarStream.close();
gzip.close();
// The client has the correct image cached if the ETag matches
String eTag = request().getHeader("If-None-Match");
if (eTag != null && eTag.equals(version.toString())) {
return status(NOT_MODIFIED, "Not modified");
}
response().setContentType("image/png");
response().setHeader(ETAG, version.toString());
return Results.ok(outputStream.toByteArray());
}
This did not work and google is only returning answers for gzipping strings. Can anyone help?
EDIT: Does not work in this case means the result was 0 bytes.
len is bound to always be 0.
In this line:
byte[] byteArray = IOUtils.toByteArray(avatarStream);
you read all of avatarStream - it is now empty, 0 bytes left.
And in this line:
while ((len = avatarStream.read(byteArray)) > 0) {
you check how much you can still read of it - which is 0 bytes.
Replace
int len;
while ((len = avatarStream.read(byteArray)) > 0) {
gzip.write(byteArray, 0, len);
}
by just
gzip.write(byteArray);
I'm quite new to using Java I/O as I haven't ever before and have written this to download a .mp4 file from www.kissanime.com.
The download is very, very slow at the moment (approximately 70-100kb/s) and was wondering how I could speed it up. I don't really understand the byte buffering so any help with that would be appreciated. That may be my problem, I'm not sure.
Here's my code:
protected static boolean downloadFile(URL source, File dest) {
try {
URLConnection urlConn = source.openConnection();
urlConn.setConnectTimeout(1000);
urlConn.setReadTimeout(5000);
InputStream in = urlConn.getInputStream();
FileOutputStream out = new FileOutputStream(dest);
BufferedOutputStream bout = new BufferedOutputStream(out);
int fileSize = urlConn.getContentLength();
byte[] b = new byte[65536];
int bytesDownloaded = 0, len;
while ((len = in.read(b)) != -1 && bytesDownloaded < fileSize) {
bout.write(b, 0, len);
bytesDownloaded += len;
// System.out.println((double) bytesDownloaded / 1000000.0 + "mb/" + (double) fileSize / 1000000.0 + "mb");
}
bout.close();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
Thanks. Any further information will be provided upon request.
I can't find any questions on here related to downloading media files, and I'm sorry if this is deemed to be a duplicate.
Try using IOUtils.toByteArray, It takes an inputstream and returns an array with all bytes, in my opinion it's generally a good idea to check the common utility packages like apache-commons and guava and see if what you're trying to do hasn't already been done
If you want to save the file from InputStream then use this bellow method of apache-commons
FileUtils.copyInputStreamToFile ()
public static void copyInputStreamToFile(InputStream source,
File destination)
throws IOException
Copies bytes from an InputStream source to a file destination. The directories up to destination will be created if they don't already exist. destination will be overwritten if it already exists. The source stream is closed.
Always use file and IO related stuff by using library if available.There are also some other utility methods available & you can explore .
IOUtils
FileUtils
Turns out that it was the vast number of redirects from the link that caused the download speed to be throttled. Thanks everyone who answered.
I'm really despairing on calculating the moving average of an upload (binary/jpg) with http-post in my android app.
I am using DataOutputStream as ouputStream:
while (true) {
while(bufferSize > 0) {
int transferedBytes = Math.min(bufferSize, packetSize);
outputStream.write(buffer, offset, transferedBytes);
outputStream.flush();
// save transferedBytes as throughput
offset += transferedBytes;
bufferSize -= transferedBytes;
}
if ((available = inputStream.available()) <= 0) {
break;
}
int nBytes = Math.min(avail, bufferSize);
bufferSize = inputStream.read(buffer, 0, nBytes);
offset = 0;
}
The upload is working fine with this implemention, but the mentioned lines are executed in less than 500ms (file is 1MB). The real upload seems to be executed in the following line (takes about 11000ms):
int responseCode = connection.getResponseCode();
It seems, that I can't solve my issue with the code above. Is there any approach which could do what I want? I've heard Apaches HttpCore has abilities to do stuff like that, but I couldn't find any method or documentation which seems to help.
Does anyone has an idea how to do this?
Please make sure you use setChunkedStreamingMode(int) otherwise the response body will be buffered in memory until you try to close the connection and get the response code back which seems like what you are experiencing.
Android doc on setChunkedStreamingMode