show a preview for video files

This commit is contained in:
Daniel Gultsch 2016-07-11 21:24:33 +02:00
parent 01a4d2ea25
commit be4aa2afc9
8 changed files with 178 additions and 26 deletions

59
art/play_video.svg Normal file
View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
viewBox="0 0 48 48"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="play_video.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1916"
inkscape:window-height="1156"
id="namedview8"
showgrid="false"
inkscape:zoom="4.9166667"
inkscape:cx="0.91525424"
inkscape:cy="24"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<path
d="M0 0h48v48H0z"
fill="none"
id="path4" />
<path
d="M20 33l12-9-12-9v18zm4-29C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm0 36c-8.82 0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16z"
id="path6"
style="fill:#ffffff;fill-opacity:0.7019608;opacity:1;stroke:none;stroke-opacity:0.38039216" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -13,6 +13,7 @@ resolutions = {
images = {
'ic_launcher.svg' => ['ic_launcher', 48],
'main_logo.svg' => ['main_logo', 200],
'play_video.svg' => ['play_video', 96],
'conversations_mono.svg' => ['ic_notification', 24],
'ic_received_indicator.svg' => ['ic_received_indicator', 12],
'ic_send_text_offline.svg' => ['ic_send_text_offline', 36],

View file

@ -10,6 +10,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
@ -380,21 +381,43 @@ public class FileBackend {
if (thumbnail != null) {
return thumbnail;
}
File file = getFile(message);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = calcSampleSize(file, size);
Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
DownloadableFile file = getFile(message);
if (file.getMimeType().startsWith("video/")) {
thumbnail = getVideoPreview(file, size);
} else {
Bitmap fullsize = getFullsizeImagePreview(file, size);
if (fullsize == null) {
throw new FileNotFoundException();
}
thumbnail = resize(fullsize, size);
thumbnail = rotate(thumbnail, getRotation(file));
}
this.mXmppConnectionService.getBitmapCache().put(uuid, thumbnail);
}
}
return thumbnail;
}
private Bitmap getFullsizeImagePreview(File file, int size) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = calcSampleSize(file, size);
return BitmapFactory.decodeFile(file.getAbsolutePath(), options);
}
private Bitmap getVideoPreview(File file, int size) {
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
metadataRetriever.setDataSource(file.getAbsolutePath());
Bitmap frame = metadataRetriever.getFrameAtTime(0);
metadataRetriever.release();
frame = resize(frame, size);
Canvas canvas = new Canvas(frame);
Bitmap play = BitmapFactory.decodeResource(mXmppConnectionService.getResources(), R.drawable.play_video);
float x = (frame.getWidth() - play.getWidth()) / 2.0f;
float y = (frame.getHeight() - play.getHeight()) / 2.0f;
canvas.drawBitmap(play,x,y,null);
return frame;
}
public Uri getTakePhotoUri() {
StringBuilder pathBuilder = new StringBuilder();
pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
@ -656,7 +679,31 @@ public class FileBackend {
public void updateFileParams(Message message, URL url) {
DownloadableFile file = getFile(message);
if (message.getType() == Message.TYPE_IMAGE || file.getMimeType().startsWith("image/")) {
boolean image = message.getType() == Message.TYPE_IMAGE || file.getMimeType().startsWith("image/");
boolean video = message.getMimeType().startsWith("video/");
if (image || video) {
try {
Dimensions dimensions = image ? getImageDimensions(file) : getVideoDimensions(file);
if (url == null) {
message.setBody(Long.toString(file.getSize()) + '|' + dimensions.width + '|' + dimensions.height);
} else {
message.setBody(url.toString() + "|" + Long.toString(file.getSize()) + '|' + dimensions.width + '|' + dimensions.height);
}
return;
} catch (NotAVideoFile notAVideoFile) {
Log.d(Config.LOGTAG,"file with mime type "+file.getMimeType()+" was not a video file");
//fall threw
}
}
if (url != null) {
message.setBody(url.toString()+"|"+Long.toString(file.getSize()));
} else {
message.setBody(Long.toString(file.getSize()));
}
}
private Dimensions getImageDimensions(File file) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
@ -664,19 +711,64 @@ public class FileBackend {
boolean rotated = rotation == 90 || rotation == 270;
int imageHeight = rotated ? options.outWidth : options.outHeight;
int imageWidth = rotated ? options.outHeight : options.outWidth;
if (url == null) {
message.setBody(Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight);
} else {
message.setBody(url.toString()+"|"+Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight);
return new Dimensions(imageHeight, imageWidth);
}
private Dimensions getVideoDimensions(File file) throws NotAVideoFile {
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
metadataRetriever.setDataSource(file.getAbsolutePath());
String hasVideo = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
if (hasVideo == null) {
throw new NotAVideoFile();
}
int rotation = extractRotationFromMediaRetriever(metadataRetriever);
boolean rotated = rotation == 90 || rotation == 270;
int height;
try {
String h = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
height = Integer.parseInt(h);
} catch (Exception e) {
height = -1;
}
int width;
try {
String w = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
width = Integer.parseInt(w);
} catch (Exception e) {
width = -1;
}
metadataRetriever.release();
Log.d(Config.LOGTAG,"extracted video dims "+width+"x"+height);
return rotated ? new Dimensions(width, height) : new Dimensions(height, width);
}
private int extractRotationFromMediaRetriever(MediaMetadataRetriever metadataRetriever) {
int rotation;
if (Build.VERSION.SDK_INT >= 17) {
String r = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
try {
rotation = Integer.parseInt(r);
} catch (Exception e) {
rotation = 0;
}
} else {
if (url != null) {
message.setBody(url.toString()+"|"+Long.toString(file.getSize()));
} else {
message.setBody(Long.toString(file.getSize()));
rotation = 0;
}
return rotation;
}
private class Dimensions {
public final int width;
public final int height;
public Dimensions(int height, int width) {
this.width = width;
this.height = height;
}
}
private class NotAVideoFile extends Exception {
}
public class FileCopyException extends Exception {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB