Efficient and fast way to encode images to Video/GIF in Android - java

I'm trying to make a video out of viewshots in an app.
I have succeeeded to get the images as Bitmaps using this code.
public Bitmap getScreenShot() {
View screenView = findViewById(R.id.button);
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
I have encode images using SequenceEncoder like this :
for(Bitmap bitmap : bitmaps)
sequenceEncoder.encodeImage(bitmap);
I have got it working and got the file but it takes a lot of time.
I have also tried to use MediaMuxer(I used EncodeDecode) but failed to even get a video, I have tried to make a GIF(using AnimatedGifEncoder) but a lot of time too. I want a way to make this video in a very short time.

Related

Android Java - programmatically capture background before app window opens [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to programatically take a screenshot on Android?
How to capture the android device screen content and make an image file using the snapshot data? Which API should I use or where could I find related resources?
BTW:
not camera snapshot, but device screen
Use the following code:
Bitmap bitmap;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
Here MyView is the View through which we need include in the screen. You can also get DrawingCache from of any View this way (without getRootView()).
There is also another way.. If we having ScrollView as root view then its better to use following code,
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout's id)
root.setDrawingCacheEnabled(false);
Here is the getBitmapFromView() method
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
It will display entire screen including content hidden in your ScrollView
UPDATED AS ON 20-04-2016
There is another better way to take screenshot.Here I have taken screenshot of WebView.
WebView w = new WebView(this);
w.setWebViewClient(new WebViewClient()
{
public void onPageFinished(final WebView webView, String url) {
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
webView.measure(View.MeasureSpec.makeMeasureSpec(
View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
webView.layout(0, 0, webView.getMeasuredWidth(),
webView.getMeasuredHeight());
webView.setDrawingCacheEnabled(true);
webView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(),
webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
int height = bitmap.getHeight();
canvas.drawBitmap(bitmap, 0, height, paint);
webView.draw(canvas);
if (bitmap != null) {
try {
String filePath = Environment.getExternalStorageDirectory()
.toString();
OutputStream out = null;
File file = new File(filePath, "/webviewScreenShot.png");
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 50, out);
out.flush();
out.close();
bitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, 1000);
}
});
Hope this helps..!
AFAIK, All of the methods currently to capture a screenshot of android use the /dev/graphics/fb0 framebuffer. This includes ddms. It does require root to read from this stream. ddms uses adbd to request the information, so root is not required as adb has the permissions needed to request the data from /dev/graphics/fb0.
The framebuffer contains 2+ "frames" of RGB565 images. If you are able to read the data, you would have to know the screen resolution to know how many bytes are needed to get the image. each pixel is 2 bytes, so if the screen res was 480x800, you would have to read 768,000 bytes for the image, since a 480x800 RGB565 image has 384,000 pixels.
For newer Android platforms, one can execute a system utility screencap in /system/bin to get the screenshot without root permission.
You can try /system/bin/screencap -h to see how to use it under adb or any shell.
By the way, I think this method is only good for single snapshot.
If we want to capture multiple frames for screen play, it will be too slow.
I don't know if there exists any other approach for a faster screen capture.
[Based on Android source code:]
At the C++ side, the SurfaceFlinger implements the captureScreen API. This is exposed over the binder IPC interface, returning each time a new ashmem area that contains the raw pixels from the screen. The actual screenshot is taken through OpenGL.
For the system C++ clients, the interface is exposed through the ScreenshotClient class, defined in <surfaceflinger_client/SurfaceComposerClient.h> for Android < 4.1; for Android > 4.1 use <gui/SurfaceComposerClient.h>
Before JB, to take a screenshot in a C++ program, this was enough:
ScreenshotClient ssc;
ssc.update();
With JB and multiple displays, it becomes slightly more complicated:
ssc.update(
android::SurfaceComposerClient::getBuiltInDisplay(
android::ISurfaceComposer::eDisplayIdMain));
Then you can access it:
do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);
Using the Android source code, you can compile your own shared library to access that API, and then expose it through JNI to Java. To create a screen shot form your app, the app has to have the READ_FRAME_BUFFER permission.
But even then, apparently you can create screen shots only from system applications, i.e. ones that are signed with the same key as the system. (This part I still don't quite understand, since I'm not familiar enough with the Android Permissions system.)
Here is a piece of code, for JB 4.1 / 4.2:
#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/MemoryHeapBase.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
static void do_save(const char *filename, const void *buf, size_t size) {
int out = open(filename, O_RDWR|O_CREAT, 0666);
int len = write(out, buf, size);
printf("Wrote %d bytes to out.\n", len);
close(out);
}
int main(int ac, char **av) {
android::ScreenshotClient ssc;
const void *pixels;
size_t size;
int buffer_index;
if(ssc.update(
android::SurfaceComposerClient::getBuiltInDisplay(
android::ISurfaceComposer::eDisplayIdMain)) != NO_ERROR ){
printf("Captured: w=%d, h=%d, format=%d\n");
ssc.getWidth(), ssc.getHeight(), ssc.getFormat());
size = ssc.getSize();
do_save(av[1], pixels, size);
}
else
printf(" screen shot client Captured Failed");
return 0;
}
You can try the following library: Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
According to this link, it is possible to use ddms in the tools directory of the android sdk to take screen captures.
To do this within an application (and not during development), there are also applications to do so. But as #zed_0xff points out it certainly requires root.
Framebuffer seems the way to go, it will not always contain 2+ frames like mentioned by Ryan Conrad. In my case it contained only one. I guess it depends on the frame/display size.
I tried to read the framebuffer continuously but it seems to return for a fixed amount of bytes read. In my case that is (3 410 432) bytes, which is enough to store a display frame of 854*480 RGBA (3 279 360 bytes). Yes, the frame in binary outputed from fb0 is RGBA in my device. This will most likely depend from device to device. This will be important for you to decode it =)
In my device /dev/graphics/fb0 permissions are so that only root and users from group graphics can read the fb0. graphics is a restricted group so you will probably only access fb0 with a rooted phone using su command.
Android apps have the user id (uid) app_## and group id (guid) app_## .
adb shell has uid shell and guid shell, which has much more permissions than an app.
You can actually check those permissions at /system/permissions/platform.xml
This means you will be able to read fb0 in the adb shell without root but you will not read it within the app without root.
Also, giving READ_FRAME_BUFFER and/or ACCESS_SURFACE_FLINGER permissions on AndroidManifest.xml will do nothing for a regular app because these will only work for 'signature' apps.
if you want to do screen capture from Java code in Android app AFAIK you must have Root provileges.

How can I get the ID from an image from camera or internal storage to put into Android EasySlider?

I'm programming a new app for my city and I need help with some code. I'm using the EasySliders library for Android, and I need to put images taken from either the camera or internal storage.
I could put them in ImageViews, but I want to put them into a slider. EasySlider needs 2 parameters:
A title for the image
An ID
How can I get the id from those pictures?
Bitmap bitmap;
bitmap = BitmapFactory.decodeFile(dir);
// Here is the problem, the bitmap is not an id and it causes an error
easySliders.add(new SliderItem("temporalname", bitmap));

Loading Database Image in List App is Stuck

I have save image path in database and image save in folder. Displaying image in list view app is stuck and slow. I not understand how to resolve this issue.
I am using following code:
strContactImage = customer.getPhotoPath();
Bitmap decodedImage = BitmapFactory.decodeFile(strContactImage);
customerImage.setImageBitmap(decodedImage);
customer.getPhotoPath() gets folder photo path image, and displays it properly, but when I added more than 20 records app slows down, and gets stuck.
Use uri to set image into image view instead of decoding into bitmap...
strContactImage = customer.getPhotoPath();
Uri uri=Uri.fromFile(new File(strContactImage));
// Set the uri into ImageView
customerImage.setImageURI(uri);
It might help you...
You can use any image caching library, here is the example of Picasso
strContactImage = customer.getPhotoPath();
Picasso.with(context)
.load(new File(strContactImage))
.into(customerImage);
check the size of the images they can effect the memory and make the app stuck and slow if they are take a lot of memory !
to fix that
take a look here
Load a Scaled Down Version into Memory
and check the method calculateInSampleSize() and decodeSampledBitmapFromResource()
it’s not worth loading a 1024x768 pixel image into memory if it will eventually be displayed in a 128x96 pixel thumbnail in an ImageView.
and you can use library that can help you to load image and they will take care about the memory usage and loading the image into Your View
Library :
Picasso
example :
Picasso.with(context).load(file).into(imageview);
Glide
example :
GlideApp.with(context).load(file).into(imageview);
Tools - check this for more about :
TinyPNG - Smart PNG and JPEG compression
Optimizilla

Android Image Masking not rendering as intended

I am using this blog post to generate a the masking effect. I might be missing some thing , I am not able to achieve the intended behavior. I am new to image processing. based on my internet research I am assuming I got to have a JPEG image for the originol image and the PNG format for the mask image with the same dimension . I even tried to create images as below
My Images :
some of the images I created to create masking effect :
But the resulted Image using this logic looks like this ,
.
Why is it ? Am I missing some thing here ? The only Images working so far is the one in the example on that link.
My masking code :
public static Bitmap getMaskedBitmap(Resources res, int sourceResId, int maskResId) {
BitmapFactory.Options options = new BitmapFactory.Options();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
options.inMutable = true;
}
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap source = BitmapFactory.decodeResource(res, sourceResId, options);
Bitmap bitmap;
if (source.isMutable()) {
bitmap = source;
} else {
bitmap = source.copy(Bitmap.Config.ARGB_8888, true);
source.recycle();
}
bitmap.setHasAlpha(true);
Canvas canvas = new Canvas(bitmap);
Bitmap mask = BitmapFactory.decodeResource(res, maskResId);
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(mask, 0, 0, paint);
mask.recycle();
return bitmap;
}
Please let me know where am I going wrong ?
Is there any requirement for the Images ? especially Mask Image
I have tested on Samsung S3 OS 4.2
UPDate :
I tried the mask Image from the blog post with my own JPEG .IT works perfect so the issue is narrowed down to mask Image. It expects some kind of configuration. Please let me know about it if any one know faced this before or am I missing some thing .
Latest UPDate :
I finally figured out. it is the alpha channel inside a mask image that makes the difference . If you are a programmer without a UI designer then you got to take care of this alpha channel
Referring to this SO answer Android: Bitmap recycle() how does it work?
This particular line of code is likely the problem. I can say you probably should not call
mask.recycle();
I haven't tested it but I think its worth a shot.This should work since when you recycle mask the masked image itself is GCed. So if you don't call it it should work.
I finally figured out , the mask image got to have a alpha channel . On Photoshop you have to add a transparency layer to get set the alpha channel enabled.

modify universal-image-loader

I am using this project universal-image-loader in order to display in a gridview several images. But I would like to modify these images with some html (for example add ads at the bottom of each images).
I saw the image are displayed by calling imageLoader.displayImage(..), in the method getView of the ImageAdapter.
I don't know what approach is better:
add a step in displayImage(...) in order to create a webview with my image and html and transform this webview in bitmap?
modify the getView of ImageAdapter which will create the webview and add an argument webview in displayeImage()?
...
...
I guess I don't have the choice, I have to use a webview.
Moreover in the method displayImage() of ImageLoader.java, i don't understand where the images are loaded, I guess this is somewhere in this line, but when I am looking in these methods I can't find/understand
ImageSize targetSize = getImageSizeScaleTo(imageView);
String memoryCacheKey = MemoryCacheUtil.generateKey(uri, targetSize);
cacheKeysForImageViews.put(imageView.hashCode(), memoryCacheKey);
Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
(How from a string built by an uri and ImageSize we can have a bitmap? where is the image?)
Images are loaded asynchronously. So your code piece is just a top of complex logic. Main work is done in LoadAndDisplayTask class but you don't need to touch it.
For your case you can create own BitmapDisplayer:
create BitmapDisplayer implementation
implement Bitmap display(Bitmap bitmap, ImageView imageView) method
in this method you can process incoming Bitmap as you want
set result Bitmap in ImageView and return result
Set your BitmapDisplayer into configuration.

Categories

Resources