Getting snapshot image from IP Camera via URL - android

I am trying to get a picture from a Hikvision IP Camera URL which has a a URL that is more or less formed like this:http://IPaddress:port#/Streaming/channels/1/picture
However as you notice the folder is just named picture with no straight link to an image and its extensions. When I use Picasso library or just normal HttpConnection it fails to get the image / bitmap. How else can I retrieve the image? When I enter the URL in my web browser it loads perfectly and shows me that the picture is .jpeg format.EDIT
Whenever I try to access the snapshot image using InputStream and Bitmap I get a FileNotFoundException error

The problem as pointed out by Dario was the authentication. Status 401 was being returned and that is why the FileNotFoundException was being thrown. The answer he gave me had a lot of deprecated methods my Gradle couldnt even get some of the classes.However I found another way with help from the following forums 1, 2 so I combined with another page for the authentication which I cant find and had the following:
boolean isSaved = false;
try {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI(AppConst.IMAGE_URL));
UsernamePasswordCredentials credentials =
new UsernamePasswordCredentials(AppConst.USERNAME, AppConst.PASSWORD);
BasicScheme scheme = new BasicScheme();
Header authorizationHeader = scheme.authenticate(credentials, request);
request.addHeader(authorizationHeader);
HttpResponse response = client.execute(request);
Log.d("responseType",response!=null? response.getEntity().getContentType().toString():"emptyType");
Log.d("responseCode", response != null ? String.valueOf(response.getStatusLine().getStatusCode()) : "emptyCode");
if((response.getStatusLine().getStatusCode()==200) && (response.getEntity()!=null)){//status OK and not empty
//save stuff
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String path = APP_DIR+System.currentTimeMillis()+".jpg";
FileOutputStream output = new FileOutputStream(path);
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = instream.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
output.close();
Log.d("Snapshot Filename: ", path);
isSaved = true;
}
}else{
isSaved= false;
}
}catch (Exception ex){
Log.e("saveImageError",ex!=null? ex.getMessage():"error");
}
Had to add the following line in the gradle under the android section: useLibrary 'org.apache.http.legacy'

Related

Android:Http get fetches old response

Below is the method which I have used to read a response from server by passing a url which retrieved a json object.
There is a very peculiar issue which is still old values has been fetched , though the data has already been updated.
I tried to find out the solution of it but still no success.
Url is of type: http://www.mywebsite.com/svc/user_auth/user_id
Where a user id is the unique integer id of the user which is being passed as a parameter.
public static String getResponse(String url){
String downloadedData = null;
Log.e("getResponse", url);
try {
URL downloadURL = new URL(url);
InputStream inputStream = (InputStream) downloadURL.getContent();
if (null != inputStream) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[512];
int readCounter = inputStream.read(buffer);
while (readCounter != -1) {
byteArrayOutputStream.write(buffer, 0, readCounter);
readCounter = inputStream.read(buffer);
}
downloadedData = new String(
byteArrayOutputStream.toByteArray());
/*if (null != downloadedData && !"".equals(downloadedData)) {
downloadedJson = new JSONObject(downloadedData);
}*/
}else{
Log.e("getResponse", "Response is null");
}
} catch (Exception e) {
e.printStackTrace();
}
return downloadedData;
}
Any help would be appreciated.
Don't know how is URL.getContent() implemented internally. You can try to use URLConnection, it allows you to control whether to use cache by setUseCaches().
Have you tried opening the url from your browser to see the JSON response? If you see the old value in the browser then the problem is on your server side.
If this is not the case try using the DefaultHttpClient for post and get requests like: (maybe some caching occur with the method you are using, this is not the case for sure with HttpClient)
DefaultHttpClient httpclient = getHttpClient();
HttpPost httpost = new HttpPost(url);
httpost.setEntity(entity); //entity has your params wrapped if you have any...this is just an example for POST request, but for your case you can use GET with URL params..
httpclient.execute(httpost);

How to correctly download a file (zip in my case) through https in Android?

I was first using HttpURLConnection with my first test. Now I would like to also support https, but it doesn't work. I've been at it all day and so far nothing. Most of the past problems have been related to certificate issues. Weird thing is in my case it downloads the file, but its either corrupted (if its a simple file), or the zips contents are missing (empty). I will post my code to see if maybe I am doing something wrong.
try{
URL url = new URL(stuffs[0]);//<-actual url I am searching https://...
String fileName = stuffs[1];
String optionalFilePath = stuffs[2] == null ? null : stuffs[2];
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(20000);
connection.connect();
if(connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
checkErrorCode(connection.getResponseCode());
return false;
}
InputStream in = new BufferedInputStream(connection.getInputStream());
FileOutputStream out = null;
if(optionalFilePath == null)
out = new FileOutputStream(PATH +"/"+fileName);
else {
File newDir = new File(PATH+optionalFilePath);
newDir.mkdirs();
out = new FileOutputStream(PATH + (optionalFilePath==null?"":optionalFilePath) +"/"+fileName);
}
byte[] buffer = new byte[1024];
int count;
while((count = in.read(buffer)) != -1){
out.write(buffer, 0, count);
}
out.flush();
out.close();
in.close();
}
Upon further debugging, I found out the content length is -1. So I guess it makes sense why the zip is empty. Now I am not too sure why it returns -1. I download it on a web browser correctly. So I know it exists.
To Download file via https You should accept https certificate from application Trusting all certificates using HttpClient over HTTPS
And https file download in android causing exception
For Downlod zip or any check this out
Download a file with Android, and showing the progress in a ProgressDialog
I believe the answer is that you are calling connect().
URL url = new URL(stuffs[0]);//<-actual url I am searching https://...
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(20000);
connection.connect();
if(connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
checkErrorCode(connection.getResponseCode());
return false;
}
InputStream in = new BufferedInputStream(connection.getInputStream());
Try not calling connection.connect, and moving the response code check after the line that calls connection.getInputStream().

How to post an image to Twitter using statuses/update_with_media in android

I need to post a image to Twitter. I have integrated Twitter in my app. I need to tweet the image as such not as an URL link. I don't want to use TwitPic.
I used the following code to create the multipart entity. It give 404 error.
Bitmap bm = null;
String encodedImage = "";
try {
URL aURL = new URL("http://50.57.227.117/blacksheep/uploaded/Detailed_images/961314275649aladdins.jpg");
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, 8192);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
imageBytes = baos.toByteArray();
encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
Log.v("encodedImage >>",encodedImage);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"https://api.twitter.com/1.1/statuses/update_with_media.json");
ByteArrayBody bab = new ByteArrayBody(imageBytes, "forest.jpg");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("media", bab);
reqEntity.addPart("status", new StringBody("test image"));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
BufferedReader reader = new BufferedReader(new InputStreamReader(
response.getEntity().getContent(), "UTF-8"));
String sResponse;
StringBuilder s = new StringBuilder();
while ((sResponse = reader.readLine()) != null) {
s = s.append(sResponse);
}
System.out.println("Response: " + s);
// Update status
//twitter4j.Status response = twitter.updateStatus(encodedImage);
// twitter4j.Status response1 = twitter.updateStatus(status);
//Log.d("Status", "> " + response1.getText());
} catch (TwitterException e) {
// Error in updating status
Log.d("Twitter Update Error", e.getMessage());
}
First attempt:
So it seemed like you were using Apache's old http client to make a request external to the library you were using to help integrate with twitter, twitter4j. I assumed you were using a version prior to 3.03 which is latest, and didn't want you to upgrade. You see, update_with_media is quite new, so I didn't think your version had implemented it.
The problem with what you were doing is that twitter uses oauth for authentication. So you'd need to "sign" a request with the access token you'd obtained. Twitter4j, AFAIK, does this for you. You can't use a seperate client to make some calls without reference to your nice helper library without breaking authentication.
The endpoint, ../update_with_media is defined to update a status for the currently authenticating user. I suspect that, since there was no access token and no user in your request, that endpoint doesn't even make sense, so twitter were interpreting it as a 404 (not found) rather than a 401 (unauthorized)- funny.
So the first attempt was not to require you to upgrade to twitter4j. It's a pain to upgrade sometimes! Instead, you can hack with the library as is detailed with this blog. But that wasn't easy as the libraries were different.
So, something else we could try, if you really wanted to make a seperate request to twitter4j, was to actually do the signing, perhaps using scribe to make it easier.... roughly:
final OAuthService myTwitterService = TwitterClient.getTwitterClient().getService();
final OAuthRequest aNiceOAuthRequest = new org.scribe.model.OAuthRequest(
YOURPOST, THATURL);
etc.
Second attempt:
But let's not do all this- turns out you had the latest version of twitter4j anyway. Sorry for going down a cul-de-sac first- I shouldn't have assumed, but I've included the above for help for anybody else should they need it.
It turns out the latest version has implemented this endpoint- documentation here. Except it takes a StatusUpdate object instead. So you want to do something like:
final StatusUpdate statusUpdate = new StatusUpdate("Hallee hallo my status java.lang.String here...");
// now do as you did until:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
imageBytes = baos.toByteArray();
encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
// then flip the stream
byte[] myTwitterUploadBytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(myTwitterUploadBytes);
// doo and double check your encoding etc, similar to in your question..
statusUpdate.setMedia("give me a java.lang.String name", bis);
// then continue just using twitter for j- update status as you would
//... get twitter etc...
//
twitter4j.Status response = twitter.updateStatus(statusUpdate);
Haven't currently got a box on me to test- should be about right. If it still gives 404s, what is the error code in the response? Are you authenticated?
If that doesn't work, we can try some of the above too as a back up.
Hope this helps,
best,
Tom.
Using 4.0.3 (perhaps earlier) it's very simple to embed images in a tweet with twitter4j:
Twitter twtobj;
StatusUpdate stsupd;
Status stsres;
twtobj=twitterFactory.getInstance();
twtobj.setOAuthConsumer(csmkey,csmsec);
twtobj.setOAuthAccessToken(new AccessToken(acstkn,acssec));
stsupd=new StatusUpdate(msgtxt);
if(medurls.length>0) {
long[] medidns=new long[medurls.length];
for(int xa=0; xa<medurls.length; xa++) {
String medurl=Util.resolveRelativeUrl(medurls[xa]);
InputStream imgstm=null;
try {
imgstm=new URL(medurl).openConnection().getInputStream();
medidns[xa]=twtobj.uploadMedia(medurl,imgstm).getMediaId(); // this actually uploads the image to Twitter at this point
}
catch(MalformedURLException thr) { throw new ShfFail(Fail.IMAGE_URL ,"The media URL is not valid: " +medurl+" ("+thr.getMessage()+")"); }
catch(IOException thr) { throw new ShfFail(Fail.IMAGE_READ,"The media could not be read: "+medurl+" ("+thr.getMessage()+")"); }
finally { GenUtil.close(imgstm); }
}
stsupd.setMediaIds(medidns);
}
stsres=twtobj.updateStatus(stsupd);
Note that up to 4 images, or 1 animated GIF, or 1 video are allowed, as of 2015-06-10.
Note also that I am capturlng the image streams to close them explicitly in the outer block (not shown). This may be unnecessary, but I can't find positive confirmation of that.
If anyone cares, resolveRelativeUrls is a convenience to allow a relative path to be resolved as a file URL from the current folder:
static public String resolveRelativeUrl(String url) {
if(!TextUtil.stringCT(url,"://")) {
url=new File(url).getAbsoluteFile().toURI().toString();
}
return url;
}
The utility method stringCT is case-insensitive contains.

android httpclient to trigger a download from server

I have created a HTTP file server with the objective of transferring media files (mp3, ogg etc) to an Android device. When the server is accessed from the android browser like
10.0.2.2:portNumber/path/to/file
The server initiates the file download process. Of course the customer would not do such a thing, Its fine for testing the file server.
I m new to Android development and have learned that httpclient package can manage get/post requests. Here is the sample code I have been using for reading the response
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
return response;
The above code works fine when the server sends a list of file in JSON. Since the server part of sending file has been coded, the point where I m stuck is in retrieving the media file on android.
I m confused about how to receive the mp3 files send by the server. Should they be read in a stream ? Thanks
Yes, you want to read the file onto disk via an inputstream.
Here's an example. If you don't want a file download progress bar then remove the progress related code.
try {
File f = new File("yourfilename.mp3");
if (f.exists()) {
publishProgress(100,100);
} else {
int count;
URL url = new URL("http://site:port/your/mp3file/here.mp3");
URLConnection connection = url.openConnection();
connection.connect();
int lengthOfFile = connection.getContentLength();
long total = 0;
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(f);
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
total += count;
publishProgress((int)(total/1024),lengthOfFile/1024);
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
} catch (Exception e) {
Log.e("Download Error: ", e.toString());
}

Is there a faster way to download a page from the net to a string?

I have tried other methods to download info from a URL, but needed a faster one. I need to download and parse about 250 separate pages, and would like the app to not appear ridiculously slow. This is the code I am currently using to retrieve a single page, any insight would be great.
try
{
URL myURL = new URL("http://www.google.com");
URLConnection ucon = myURL.openConnection();
InputStream inputStream = ucon.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);
int current = 0;
while ((current = bufferedInputStream.read()) != -1) {
byteArrayBuffer.append((byte) current);
}
tempString = new String(byteArrayBuffer.toByteArray());
}
catch (Exception e)
{
Log.i("Error",e.toString());
}
Try to keep the connection open if the requests are to the same server. Also, try to avoid reallocations in the buffer, and read as much as possible in one go.
const int APPROX_MAX_PAGE_SIZE = 300;
try
{
URL myURL = new URL("http://www.google.com");
URLConnection ucon = myURL.openConnection();
ucon.setRequestHeader("Connection", "keep-alive") // (1)
InputStream inputStream = ucon.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(APPROX_MAX_PAGE_SIZE); // (2)
int current = 0;
byte[] buf = new byte[APPROX_MAX_PAGE_SIZE];
int read;
do {
read = bufferedInputStream.read(buf, 0, buf.length); // (3)
if(read > 0) byteArrayBuffer.append(buf, 0, read);
} while (read >= 0);
tempString = new String(byteArrayBuffer.toByteArray());
}
catch (Exception e)
{
Log.i("Error",e.toString());
}
Set Keep-alive header (not sure if you need this, on J2SE it is a configurable property as well)
Allocate what is "usually enough" in the buffer to avoid reallocation.
Read more than one byte at once
Disclaimer: This was written "in the blind" without access to a Java compiler. It may be that setRequestHeader is only available on a HttpURLConnection (cast needed), or that some parameters are wrong, but please feel free to edit if so.
Why don't you use the built in apache http components?
HttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(uri);
HttpResponse response = httpClient.execute(request);
int status = response.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK) {
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
response.getEntity().writeTo(ostream);
}
Use a pooled HTTPClient and try to make 2 or 3 requests at once. And try to create a memory pool to avoid allocations and the GC stalls.

Categories

Resources