I have a URL which, when I enter in browser, opens the image perfectly. But when I try the following code, I get getContentLength() as -1:
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// determine the image size and allocate a buffer
int fileSize = connection.getContentLength();
Please guide me what can be the reason behind this?
If the server is sending down the response using Chunked Transfer Encoding, you will not be able to pre-calculate the size. The response is streamed, and you'll just have to allocate a buffer to store the image until the stream is complete. Note that you should only do this if you can guarantee that the image is small enough to fit into memory. Streaming the response to flash storage is a pretty reasonable option if the image may be large.
In-memory solution:
private static final int READ_SIZE = 16384;
byte[] imageBuf;
if (-1 == contentLength) {
byte[] buf = new byte[READ_SIZE];
int bufferLeft = buf.length;
int offset = 0;
int result = 0;
outer: do {
while (bufferLeft > 0) {
result = is.read(buf, offset, bufferLeft);
if (result < 0) {
// we're done
break outer;
}
offset += result;
bufferLeft -= result;
}
// resize
bufferLeft = READ_SIZE;
int newSize = buf.length + READ_SIZE;
byte[] newBuf = new byte[newSize];
System.arraycopy(buf, 0, newBuf, 0, buf.length);
buf = newBuf;
} while (true);
imageBuf = new byte[offset];
System.arraycopy(buf, 0, imageBuf, 0, offset);
} else { // download using the simple method
In theory, if the Http client presents itself as HTTP 1.0, most servers will switch back to non-streaming mode, but I don't believe this is a possibility for URLConnection.
I am late here but this might help someone. I was facing same issue i was always getting -1 value, when ever i was trying get the content length.
previously i was using below method to get content length.
long totalByte=connection.getContentLength();
Below fixed my problem:-
long totalByte=connection.getHeaderFieldLong("Content-Length",-1);
Related
This is with reference to sipdroid data encrypt failed
I tried using XOR operation instead of reverse byte code for send packets and receive packets in SipdroidSocket.class.
I experienced same issue(too much noise)
Please guide me in encrypting and decrypting packets in SipdroidSocket.class
Sorry for late reply.I am posting the snippets of the code I tried. Please refer the original RtpSocket.java and SipdroidSocket.java classes for complete view. I am just putting the snippets here.
In RtpSocket.java , I took a static value and collected the packet's header length. Then used this header length in SipdroidSocket.java so as to remove the header part prior tweaking with the payload:
In SipdroidSocket.java, following editing were done in Send and Receive functions:
public void receive(DatagramPacket pack) throws IOException {
if (loaded) {
impl.receive(pack);
byte[] b = pack.getData(); // fetch data from receiver
int len = RtpSocket.header;
pack.setData(do_something(b, len)); // do the XORing to retrieve
// original data
} else {
super.receive(pack);
byte[] b = pack.getData();
int len = RtpSocket.header;
pack.setData(do_something(b, len));
}
}
public void send(DatagramPacket pack) throws IOException {
byte[] b = pack.getData(); // fetch original data
int len = RtpSocket.header;
pack.setData(do_something(b, len)); // replace with tweaked data
if (loaded)
impl.send(pack);
else
super.send(pack);
}
private byte[] do_something(byte[] b, int len) {
// TODO Auto-generated method stub
int new_buff_len = b.length - len;
byte[] new_buff = new byte[new_buff_len];
int i = 0;
for (i = len; i < b.length; i++) // separating header values
{
new_buff[i] = (byte) (b[i] ^ 0x43); // XORing original packet
// payload before sending and
// after receiving to get
// original data on both sides
}
return new_buff;
}
Kindly , try it and suggest me please.
Finally it worked ! Had to meddle with the other parts of the code . XOR operation now works fine and have attained the objective.
I'm trying to read content from a Uri on Android, and I need the final Object type passed to the underlying SDK to by a nio.ByteBuffer.
I can get my hands on an InputStream, via ContentResolver but didn't find a way to wrap it with an nio.ByteBuffer.
Is there a way to convert a Uri content to a nio.ByteBuffer on Android?
I've ended up downloading the content of the Uri locally and open it via other method to get the ByteBuffer
Suppose you are working on an Activity,
private ByteBuffer getByteBuffer(Uri uri){
try{
InputStream iStream = getContentResolver().openInputStream(uri);
if(iStream!=null){
//value of MAX_SIZE is up to your requirement
final int MAX_SIZE = 5000000;
byte[] byteArr = new byte[MAX_SIZE];
int arrSize = 0;
while(true){
int value = iStream.read(byteArr);
if(value == -1){
break;
}else{
arrSize += value;
}
}
iStream.close();
return ByteBuffer.wrap(byteArr, 0, arrSize);
}
}catch(IOException e){
//do something
}
return null;
}
Notes:
(i) InputStream.read(byte[] b) will return an Integer which indicate total number of bytes read into the byte array b at each time.
(ii) If InputStream.read(Byte[] b) returns -1, it indicates that it is the end of the inputStream.
(iii) arrSize stores the total number of bytes read, i.e. the length of byte[] b
(iv) ByteBuffer.wrap(byte[] b, int offset, int length) will wrap the byte array to give a ByteBuffer. You may check this reference
(v) ContentResolver.openInputStream(Uri uri) and InputStream.read(byte[] b) will throw IOException so you must handle it.
(vi) Caution: IndexOutOfBoundException might happen if arrSize > MAX_SIZE, you may need to add if-else clause to handle such issue.
Please feel free to comment or change the code if there is any mistake or if there is a faster way to do that. Happy coding
I am trying to post a large video (nearly 1 GB).
I am using FTP to send video to a server, but the upload stops after a while. On the server the video crashes, but I am able to upload a smaller sized video.
I've also used HTTP to send video to the server, sent as a Base64 enoded string, but there is an out of memory exception while encoding.
I've tried to upload the video as a file, but without success. What is the best way to upload a large video to a server?
Use HTTP POST, and post content as Form-based File Upload (mime type: multipart/form-data). This system is standard on web for sending forms and/or uploading files.
Use HTTP chunked post mode, so that size doesn't need to be known beforehand, and you can stream any file in small parts. You still have to make some code on server (e.g. in PHP) to accept the file and do what is needed.
Use HttpURLConnection to initiate connection. Then use my attached class to send the data. It will create proper headers, etc, and you'll use it as OutputStream to write your raw data to it, then call close, and you're done. You can overrite its onHandleResult to handle resulting error code.
public class FormDataWriter extends FilterOutputStream{
private final HttpURLConnection con;
/**
* #param formName name of form in which data are sent
* #param fileName
* #param fileSize size of file, or -1 to use chunked encoding
*/
FormDataWriter(HttpURLConnection con, String formName, String fileName, long fileSize) throws IOException{
super(null);
this.con = con;
con.setDoOutput(true);
String boundary = generateBoundary();
con.setRequestProperty(HTTP.CONTENT_TYPE, "multipart/form-data; charset=UTF-8; boundary="+boundary);
{
StringBuilder sb = new StringBuilder();
writePartHeader(boundary, formName, fileName==null ? null : "filename=\""+fileName+"\"",
"application/octet-stream", sb);
headerBytes = sb.toString().getBytes("UTF-8");
sb = new StringBuilder();
sb.append("\r\n");
sb.append("--"+boundary+"--\r\n");
footerBytes = sb.toString().getBytes();
}
if(fileSize!=-1) {
fileSize += headerBytes.length + footerBytes.length;
con.setFixedLengthStreamingMode((int)fileSize);
}else
con.setChunkedStreamingMode(0x4000);
out = con.getOutputStream();
}
private byte[] headerBytes, footerBytes;
private String generateBoundary() {
StringBuilder sb = new StringBuilder();
Random rand = new Random();
int count = rand.nextInt(11) + 30;
int N = 10+26+26;
for(int i=0; i<count; i++) {
int r = rand.nextInt(N);
sb.append((char)(r<10 ? '0'+r : r<36 ? 'a'+r-10 : 'A'+r-36));
}
return sb.toString();
}
private void writePartHeader(String boundary, String name, String extraContentDispositions, String contentType, StringBuilder sb) {
sb.append("--"+boundary+"\r\n");
sb.append("Content-Disposition: form-data; charset=UTF-8; name=\""+name+"\"");
if(extraContentDispositions!=null)
sb.append("; ").append(extraContentDispositions);
sb.append("\r\n");
if(contentType!=null)
sb.append("Content-Type: "+contentType+"\r\n");
sb.append("\r\n");
}
#Override
public void write(byte[] buffer, int offset, int length) throws IOException{
if(headerBytes!=null) {
out.write(headerBytes);
headerBytes = null;
}
out.write(buffer, offset, length);
}
#Override
public void close() throws IOException{
flush();
if(footerBytes!=null) {
out.write(footerBytes);
footerBytes = null;
}
super.close();
int code = con.getResponseCode();
onHandleResult(code);
}
protected void onHandleResult(int code) throws IOException{
if(code!=200 && code!=201)
throw new IOException("Upload error code: "+code);
}
}
I guess it failed because of a timeout by the big size.
Since
Small size video uploaded successfully
, My suggestion is
Split one big file to several small files.
Upload one by one or several together based on the condition of network.
Join all of parts (after all of those uploaded successfully) at server.
Because of small size, Re-upload failed part will be easy.
Just a theroy.
This site may help .
Added 08.01.2013
It has been a while, don't know if you still need this. Anyway, I wrote some simple codes implement the theory above, because of interest mainly.
Split one big file to several small files. Read the big file into several small parts.
ByteBuffer bb = ByteBuffer.allocate(partSize);
int bytesRead = fc.read(bb);
if (bytesRead == -1) {
break;
}
byte[] bytes = bb.array();
parts.put(new Part(createFileName(fileName, i), bytes));
Upload one by one or several together based on the condition of network.
Part part = parts.take();
if (part == Part.NULL) {
parts.add(Part.NULL);// notify others to stop.
break;
} else {
uploader.upload(part);
}
Join all of parts (after all of those uploaded successfully) at server.
Because it is via HTTP, so it can be in any language, such as Java, PHP, Python, etc. Here is a java example.
...
try (FileOutputStream dest = new FileOutputStream(destFile, true)) {
FileChannel dc = dest.getChannel();// the final big file.
for (long i = 0; i < count; i++) {
File partFile = new File(destFileName + "." + i);// every small parts.
if (!partFile.exists()) {
break;
}
try (FileInputStream part = new FileInputStream(partFile)) {
FileChannel pc = part.getChannel();
pc.transferTo(0, pc.size(), dc);// combine.
}
partFile.delete();
}
statusCode = OK;// set ok at last.
} catch (Exception e) {
log.error("combine failed.", e);
}
I put all codes on GitHub. And made a Android example too.
Please have a look if you still need.
private HttpsURLConnection conn = null;
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setChunkedStreamingMode(1024);
i want to send an audio stream from PC (C++ application, using FMOD-API to decode audio data and send via UDP Socket) to an android device. The communication already works and i can hear "sound" (100ms sound, followed by 900ms silence, alternating) on the android.
I don't know why the sound is stuttering - on the PC the same audio stream is played fine in nice quality. I think the problem is on the android..
Here is the code:
DatagramSocket sock = new DatagramSocket(12345);
byte []bSockBuffer = new byte[1024];
byte []bRecvBufTmp;
int iAudioBufSize, iCurAudioBufPos = 0;
sock.setReceiveBufferSize(bSockBuffer.length);
// Audio Stream initialisieren:
iAudioBufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, iAudioBufSize, AudioTrack.MODE_STREAM);
track.play();
while (true)
{
DatagramPacket pack = new DatagramPacket(bSockBuffer, bSockBuffer.length);
// Paket empfangen:
sock.receive(pack);
track.write(pack.getData(), 0, pack.getLength());
}
I'm sure to set up 'AudioTrack' object correctly, settings compare to my settings in the c++ application.
An other step was pre-buffering the received socket-data in a temporary 'byte[]' variable and writing it to the AudioTrack-object when the size of the buffer 'iAudioBufSize' was reached.
This did not helped.
Any idears?
Thanks
[EDIT]
Code of C++ Application, used sample "manualdecode" of FMOD API examples:
FMOD_RESULT F_CALLBACK pcmreadcallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
{
CCtrlSocket *cClientTmp = /* Obtaining target client sock here */;
FMOD_RESULT result;
unsigned int read, uSentTmp, uSizeTmp;
EnterCriticalSection(&decodecrit);
if (!decodesound)
return (FMOD_ERR_FILE_EOF);
result = decodesound->readData(data, datalen, &read);
if (result == FMOD_ERR_FILE_EOF)
{
// Handle looping:
decodesound->seekData(0);
datalen -= read;
result = decodesound->readData((char*) data + read, datalen, &read);
}
// Split package in multiple parts:
uSentTmp = 0;
do
{
uSizeTmp = (read - uSentTmp);
if (uSizeTmp > 1024)
uSizeTmp = 1024;
uSentTmp += cClientTmp->SendAudioData((char*) data + uSentTmp, uSizeTmp);
} while (uSentTmp < read);
LeaveCriticalSection(&decodecrit);
return (FMOD_OK);
}
I've done this problem.
The mess was an entry in a logfile that has cost lots of time creating a lag :(
Now i can hear the streamed music on my android client. But there are still some lags. I've experimented a LOT of values for socket and AudioTrack buffers.
I have compared the amount of sent and received bytes: In 20 secs sending 9170000 bytes of data results in receiving 8120000 bytes on android device. At first the stream is played fast for 3 secs (that means buffer's full?). After 30 secs the stream lags (which means buffer's empty?).
In general the music quality is very good, but there is a sizzling noise all the time (which indicates lost socket packages?).
My 'PlaybackStart()' function has changed - i'm not using a PCM read callback anymore:
FMOD_RESULT CAudioStream::PlaybackStart()
{
CCtrlSocket *cClientTmp;
unsigned int read, uSentTmp, uSizeTmp;
FMOD_RESULT result;
result = system->createStream("C:\\test.mp3", FMOD_OPENONLY | FMOD_ACCURATETIME, 0, &sound);
if(result != FMOD_OK)
return (result);
int iChannels, iBits;
FMOD_SOUND_FORMAT fFormat;
FMOD_SOUND_TYPE fType;
result = sound->getFormat(&fType, &fFormat, &iChannels, &iBits);
if(result != FMOD_OK)
return (result);
void *data;
unsigned int length = 0;
int iSampleSec = 1; // Playtime
int iSampleSize = (44100 * 2 * sizeof(signed short) * iSampleSec);
int iSleep = 6; // Sleep after sending a package
DWORD dSleepTotal;
result = sound->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
if(result != FMOD_OK)
return (result);
data = malloc(iSampleSize);
if (!data)
return (FMOD_RESULT_FORCEINT);
cClientTmp = (CCtrlSocket*) CCtrlSocket::cServerSock.GetClientSock(CCtrlSocket::cServerSock.GetClientSockCount() - 1);
do
{
result = sound->readData((char*) data, iSampleSize, &read);
if ((result != FMOD_OK) && (result != FMOD_ERR_FILE_EOF))
ASSERT(FALSE);
else if (read > 0)
{
dSleepTotal = 0;
for (int i = 0; i < read; i += NET_SVR_AUDIO_BUFFER)
{
// MIN_VAL_LIMITED ((MIN_VAL(VAL1, VAL2) <= LIMIT) ? LIMIT : MIN_VAL(VAL1, VAL2))
cClientTmp->SendAudioData((char*) data + i, MIN_VAL_LIMITED(NET_SVR_AUDIO_BUFFER, (read - i), 0));
// Sleep after sending every package:
Sleep(iSleep);
dSleepTotal += iSleep;
}
if (dSleepTotal < (iSampleSec * 1000))
{
dSleepTotal = (iSampleSec * 1000) - dSleepTotal;
// Sleep after sending every second playtime:
Sleep(dSleepTotal);
}
}
} while (read > 0);
result = sound->release();
if(result != FMOD_OK)
return (result);
result = system->close();
if(result != FMOD_OK)
return (result);
result = system->release();
if(result != FMOD_OK)
return (result);
return (result);
}
I have experimented with different sleep-timings, too.
I'a using a asynctask to download file. It works normally until i turn off wifi connection (there are no other internet connection) of my android, download dialog still and no changes. When i check by log, i discover that function read() of inputstream is non stop. So how to check this case? here is my code:
URL url = new URL(this.url);
URLConnection connection = url.openConnection();
connection.setReadTimeout(1000);
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
fileName = "temp.zip";
// download the file
InputStream input = new BufferedInputStream(connection.getInputStream());
OutputStream output = new FileOutputStream(path+fileName);
byte buffer[] = new byte[1024000];
long total = 0;
int count;
Log.v("test download:","download in background");
while (((count = input.read(buffer)) != -1)) {
Log.v("test download:","read:"+count);
total += count;
publishProgress((int) (total * 100 / fileLength - 1));
output.write(buffer, 0, count);
}
Since you already set a timeout by calling setReadTimeout(), you should get a SocketTimeoutException shortly after the connection dropped.
Do your code happen to maybe capture this exception silently?
Your file download buffer size is too much byte buffer[] = new byte[1024]; is enough
when i try this Download a file with Android, and showing the progress in a ProgressDialog (top answer) with asynctask ,work fine, didn't get that problem