Android MediaMetadataRetriever wrong video height and width - android

I want to retrieve height and width of video, I am using MediaMetadataRetriever class for this. It is working correct for most of the case, but for few case height and width are interchanged.
I think this might be happening because of orientation change.
My current code:
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(videoPath);
videoHeight = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
videoWidth = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
How can i get correct values? Thank you

I've been trying to figure this out myself for the last day or so, I eventually had to solve it experimentally.
File file = new File(path);
if (file.exists()) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(file.getAbsolutePath());
String metaRotation = retriever.extractMetadata(METADATA_KEY_VIDEO_ROTATION);
int rotation = metaRotation == null ? 0 : Integer.parseInt(metaRotation);
Log.i("Test", "Rotation = " + rotation);
}
If the rotation is 90 or 270 the width and height will be transposed.

Related

Rotate screen depending on video width and height

I'm currently detecting the width and height of a selected video by doing the following:
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(this, mVideoUri);
String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
The activity in manifest:
<activity android:name=".TrimVideoActivity"
android:theme="#style/Theme.AppCompat.Light.NoActionBar.FullScreen"
/>
If I toast the the width and height it always returns w : 1920 h : 1080 no matter what the dimensions of the video are. I think it is returning the width and height of the device instead.
Is there something that I'm missing or doing wrong?
EDIT
By following the link that #VladMatvienko suggested I was able to get the correct width and height of the video file, this is how I implemented it:
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
Bitmap bmp = null;
retriever.setDataSource(this, mVideoUri);
bmp = retriever.getFrameAtTime();
String videoWidth = String.valueOf(bmp.getWidth());
String videoHeight = String.valueOf(bmp.getHeight());
Now I want to rotate the screen depending on the result (width/height), I tried it by doing the following:
int w = Integer.parseInt(videoWidth);
int h = Integer.parseInt(videoHeight);
if (w > h) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} if(w < h) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
But, the screen always gets rotated to landscape, instead of being set to portrait when the width is smaller than the height?
I decided to add a answer explaining how I fixed this issue.
The issue with my initial approach:
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(this, mVideoUri);
String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
The problem with this is that the video might not have the metadata that I'm looking for, which will result a nullpointerexception.
To avoid this issue I can get one frame from the video (as a bitmap) and get the width and height from that bitmap by doing the following:
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
Bitmap bmp;
retriever.setDataSource(this, mVideoUri);
bmp = retriever.getFrameAtTime();
But, this brings up another issue, that you might not have. In my case I would like to get the first/nearest frame to the start, because if the screen was rotated during the capturing of the video, then the width/height of the frame will change, so I just added 1 to getFrameAtTime(1).
Now I can rotate the screen depending of the width and height of my video file by doing:
try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
Bitmap bmp;
retriever.setDataSource(this, mVideoUri);
bmp = retriever.getFrameAtTime(1);
int videoWidth = bmp.getWidth();
int videoHeight = bmp.getHeight();
if (videoWidth > videoHeight) {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
if (videoWidth < videoHeight) {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}catch (RuntimeException ex){
Log.e("MediaMetadataRetriever", "- Failed to rotate the video");
}
Of course the above will be called from within onCreate.
Hope this helps someone out there.

Video width is different in different devices

I have a special video when i want to get this video's width code returns different value for Samsung galaxy s6 and Samsung note 3. I tested many different codes and libraries, but result is the same.
in Samsung galaxy s6: 640x480
in Samsung note 3: 853x480
when I open this video with Gspot program it shows:
Recommended Display Size: 853x480
and this is the same value is returned by our IOS app tested in Iphone 7. aspect radio is not the same and this is big problem.
here is some of codes I tested:
(1)
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(path);
Bitmap bmp = metaRetriever.getFrameAtTime(-1);
int height = bmp.getHeight();
int width = bmp.getWidth();
(2)
MediaPlayer myMediaPlayer= MediaPlayer.create(ApplicationLoader.applicationContext,
Uri.fromFile(new File(path)));
width = myMediaPlayer.getVideoWidth();
height = myMediaPlayer.getVideoHeight();
(3)
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(path);
String heights = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String widths = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
int height = Integer.valueOf(heights);
int width = Integer.valueOf(widths);
(4)
MediaPlayer myMediaPlayer= MediaPlayer.create(ApplicationLoader.applicationContext, Uri.fromFile(new File(path)));
myMediaPlayer.setOnVideoSizeChangedListener((mp, width, height) -> {
int videoWidth = width;
int videoHeight = height;
);
myMediaPlayer.setDataSource(path);
myMediaPlayer.prepare();
FFmpegMediaMetadataRetriever, FFmpeg Java, ExoPlayer and some other libraries returns the same result.
try to scale images with DPI scale of device, i had same problem with premade bitmaps original pixel width was scaled like that.

Detecting if video was taken in portrait/landscape

I would like to confirm that what I am doing is indeed the correct way as some elements behave unexpected.
First, I have a landscape and portrait layout, as I understand, doing this will automatically detect if the phone is in portrait/landscape mode:
- layout
- activity_video_player.xml
- layout-land
- activity_video_player.xml
Then when the user selects a video from the gallery, I check if the video was taking in landscape or portrait, by doing this (inside OnCreate):
int w;
int h;
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(this, videoURI);
String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
w = Integer.parseInt(width);
h = Integer.parseInt(height);
if (w > h) {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
I have tested this and it works fine, but I noticed some of my xml elements (play button) is placed incorrectly.
So my app flow is:
MainActivity --> SelectvidButton --> Gallery Intent --> VideoPlayActivity
My Question
Is this the correct way of doing this and if it is, is there any reason why some of the xml elements get placed incorrectly?
EDIT 1:
I noticed that this only happens when the activity is launched for the first time, if I press the back button and select the same video again, the layout is perfectly like I want it to be.
EDIT 2:
I have also noticed that this only happens if the previous activity (MainActivity) was in the same orientation than what the selected video is.
Here is what I ended up doing.
Instead of using MediaMetadataRetriever to get the width and height, I first retrieve a Bitmap from the video file and then setting the orientation according to the width and hight of the Bitmap, as shown below:
private void rotateScreen() {
try {
//Create a new instance of MediaMetadataRetriever
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
//Declare the Bitmap
Bitmap bmp;
//Set the video Uri as data source for MediaMetadataRetriever
retriever.setDataSource(this, mVideoUri);
//Get one "frame"/bitmap - * NOTE - no time was set, so the first available frame will be used
bmp = retriever.getFrameAtTime();
//Get the bitmap width and height
videoWidth = bmp.getWidth();
videoHeight = bmp.getHeight();
//If the width is bigger then the height then it means that the video was taken in landscape mode and we should set the orientation to landscape
if (videoWidth > videoHeight) {
//Set orientation to landscape
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
//If the width is smaller then the height then it means that the video was taken in portrait mode and we should set the orientation to portrait
if (videoWidth < videoHeight) {
//Set orientation to portrait
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
} catch (RuntimeException ex) {
//error occurred
Log.e("MediaMetadataRetriever", "- Failed to rotate the video");
}
}

"return 0 faces because error exists btk_facefinder_putdcr" Error in Android face detector

fd = new FaceDetector(mFaceWidth, mFaceHeight, MAX_FACES);
count = fd.findFaces(mFaceBitmap, faces);
Using the above code I'm getting this error on some images.
return 0 faces because error exists btk_facefinder_putdcr
Can someone help me? How to get rid of this?
The same code works fine for some other images.
http://blog.csdn.net/devilkin64/article/details/8509767
传入的图片的宽度必须是偶数的
Bitmap srcImg = BitmapFactory.decodeFile(imgUrl);
Bitmap srcFace = srcImg.copy(Bitmap.Config.RGB_565, true);
srcImg = null;
int w = srcFace.getWidth();
int h = srcFace.getHeight();
if (w % 2 == 1) {
w++;
srcFace = Bitmap.createScaledBitmap(srcFace,
srcFace.getWidth()+1, srcFace.getHeight(), false);
}
if (h % 2 == 1) {
h++;
srcFace = Bitmap.createScaledBitmap(srcFace,
srcFace.getWidth(), srcFace.getHeight()+1, false);
}
As mentioned on this page, the image width needs to be even. I faced the same problem so I scaled the image width by one if the width was odd. And it started working :)
BitmapFactory.Options bitmap_options = new BitmapFactory.Options();
bitmap_options.inPreferredConfig = Bitmap.Config.RGB_565;
background_image = BitmapFactory.decodeFile(image_fn, bitmap_options);
if((1==(background_image.getWidth()%2))){
background_image = Bitmap.createScaledBitmap(background_image,
background_image.getWidth()+1, background_image.getHeight(), false);
}
FaceDetector face_detector = new FaceDetector(
background_image.getWidth(), background_image.getHeight(),
MAX_FACES);
faces = new FaceDetector.Face[MAX_FACES];
face_count = face_detector.findFaces(background_image, faces);
Log.d("Face_Detection", "Face Count: " + String.valueOf(face_count));
I had the same issue and when I created a new "drawable" folder to hold the image, without the "-hdpi" at the end of "drawable" it worked. Only problem I have now is scaling the image to fit the screen but this should be relatively straight forward.
Hope this helps.
If you are getting images from gallery and camera and this error come then check the width of bitmap
where you apply facedetection it must be 1.
As per the documentation of developers.android.com if the image width is not even then this exception occur.
for further detail check this link.
Or if u are not getting image from gallery and taken from camera then place the image in the folder name drawable.

How to create a Drawable from a stream without resizing it?

If I have the minimum target SDK for my app set to 4 then all calls to Drawable.createFromStream resize images.
e.g. if the source image is 480px wide and the Android device my app is running on has a density of 1.5 then the following code returns a BitmapDrawable with a width of 320
URL url = new URL("http://www.examples.com/something.png");
Drawable d = Drawable.createFromStream(url.openStream(), "something.png");
Is there a method to force it to be unchanged or specify the scale (ldpi/mdpi/hdpi etC) to return an image from an InputStream?
Edit: Solution from below.
Bitmap b = BitmapFactory.decodeStream(inputStream);
b.setDensity(Bitmap.DENSITY_NONE);
Drawable d = new BitmapDrawable(b);
You can load image as Bitmap. This way its size will be unchanged.
BitmapFactory.decodeStream(...)
Or you can try BitmapDrawable(InputStream is) constructor. It is deprecated but I guess it should do the job.
Loading images from local resource in ImageView Adapter
I was stuck with OOM error in ion by Koushik Dutta, for as low as 2 images, loading from the resource folder. Even he mentioned it may happen since they are not streams of data. and suggested to load them as InputStream.
I chucked ion Library since i wanted just 4 images from the local.
here is the solution with simple ImageView.
inside the RecyclerViewAdapter/ or any where
InputStream inputStream = mContext.getResources().openRawResource(R.drawable.your_id);
Bitmap b = BitmapFactory.decodeStream(inputStream);
b.setDensity(Bitmap.DENSITY_NONE);
Drawable d = new BitmapDrawable(b);
holder.mImageView.setImageDrawable(d);
Although Drawable d = new BitmapDrawable(b); is deprecated but, does the job quite well.
so instead we can directly get drawable from InputStream just by this line..
Drawable d = Drawable.createFromStream(inputStream,"src");
Hope it helps.
After a long time, I came across the following solution. It works. It retrieves creates bitmap from file at locallink.
private Drawable getDrawableForStore(String localLink) {
Bitmap thumbnail = null;
try {
File filePath = this.getFileStreamPath(localLink);
FileInputStream fi = new FileInputStream(filePath);
thumbnail = BitmapFactory.decodeStream(fi);
} catch (Exception ex) {
Log.e("getThumbnail() on internal storage", ex.getMessage());
return null;
}
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float scaledDensity = metrics.density;
int width = thumbnail.getWidth();
int height = thumbnail.getHeight();
if(scaledDensity<1){
width = (int) (width *scaledDensity);
height = (int) (height *scaledDensity);
}else{
width = (int) (width +width *(scaledDensity-1));
height = (int) (height +height *(scaledDensity-1));
}
thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
Drawable d = new BitmapDrawable(getResources(),thumbnail);
return d;
}

Categories

Resources