1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.util; 18 19 import android.content.ContentResolver; 20 import android.content.ContentValues; 21 import android.database.Cursor; 22 import android.media.MediaMetadataRetriever; 23 import android.net.Uri; 24 import android.os.Environment; 25 import android.provider.MediaStore.Video; 26 import android.provider.MediaStore.Video.VideoColumns; 27 28 import com.android.gallery3d.filtershow.tools.SaveImage.ContentResolverQueryCallback; 29 30 import java.io.File; 31 import java.io.IOException; 32 import java.text.SimpleDateFormat; 33 import java.util.Date; 34 35 public class SaveVideoFileUtils { 36 // This function can decide which folder to save the video file, and generate 37 // the needed information for the video file including filename. getDstMp4FileInfo(String fileNameFormat, ContentResolver contentResolver, Uri uri, String defaultFolderName)38 public static SaveVideoFileInfo getDstMp4FileInfo(String fileNameFormat, 39 ContentResolver contentResolver, Uri uri, String defaultFolderName) { 40 SaveVideoFileInfo dstFileInfo = new SaveVideoFileInfo(); 41 // Use the default save directory if the source directory cannot be 42 // saved. 43 dstFileInfo.mDirectory = getSaveDirectory(contentResolver, uri); 44 if ((dstFileInfo.mDirectory == null) || !dstFileInfo.mDirectory.canWrite()) { 45 dstFileInfo.mDirectory = new File(Environment.getExternalStorageDirectory(), 46 BucketNames.DOWNLOAD); 47 dstFileInfo.mFolderName = defaultFolderName; 48 } else { 49 dstFileInfo.mFolderName = dstFileInfo.mDirectory.getName(); 50 } 51 dstFileInfo.mFileName = new SimpleDateFormat(fileNameFormat).format( 52 new Date(System.currentTimeMillis())); 53 54 dstFileInfo.mFile = new File(dstFileInfo.mDirectory, dstFileInfo.mFileName + ".mp4"); 55 return dstFileInfo; 56 } 57 querySource(ContentResolver contentResolver, Uri uri, String[] projection, ContentResolverQueryCallback callback)58 private static void querySource(ContentResolver contentResolver, Uri uri, 59 String[] projection, ContentResolverQueryCallback callback) { 60 Cursor cursor = null; 61 try { 62 cursor = contentResolver.query(uri, projection, null, null, null); 63 if ((cursor != null) && cursor.moveToNext()) { 64 callback.onCursorResult(cursor); 65 } 66 } catch (Exception e) { 67 // Ignore error for lacking the data column from the source. 68 } finally { 69 if (cursor != null) { 70 cursor.close(); 71 } 72 } 73 } 74 getSaveDirectory(ContentResolver contentResolver, Uri uri)75 private static File getSaveDirectory(ContentResolver contentResolver, Uri uri) { 76 final File[] dir = new File[1]; 77 querySource(contentResolver, uri, 78 new String[] { VideoColumns.DATA }, 79 new ContentResolverQueryCallback() { 80 @Override 81 public void onCursorResult(Cursor cursor) { 82 dir[0] = new File(cursor.getString(0)).getParentFile(); 83 } 84 }); 85 return dir[0]; 86 } 87 88 89 /** 90 * Insert the content (saved file) with proper video properties. 91 */ insertContent(SaveVideoFileInfo mDstFileInfo, ContentResolver contentResolver, Uri uri )92 public static Uri insertContent(SaveVideoFileInfo mDstFileInfo, 93 ContentResolver contentResolver, Uri uri ) { 94 long nowInMs = System.currentTimeMillis(); 95 long nowInSec = nowInMs / 1000; 96 final ContentValues values = new ContentValues(13); 97 values.put(Video.Media.TITLE, mDstFileInfo.mFileName); 98 values.put(Video.Media.DISPLAY_NAME, mDstFileInfo.mFile.getName()); 99 values.put(Video.Media.MIME_TYPE, "video/mp4"); 100 values.put(Video.Media.DATE_TAKEN, nowInMs); 101 values.put(Video.Media.DATE_MODIFIED, nowInSec); 102 values.put(Video.Media.DATE_ADDED, nowInSec); 103 values.put(Video.Media.DATA, mDstFileInfo.mFile.getAbsolutePath()); 104 values.put(Video.Media.SIZE, mDstFileInfo.mFile.length()); 105 int durationMs = retrieveVideoDurationMs(mDstFileInfo.mFile.getPath()); 106 values.put(Video.Media.DURATION, durationMs); 107 // Copy the data taken and location info from src. 108 String[] projection = new String[] { 109 VideoColumns.DATE_TAKEN, 110 VideoColumns.LATITUDE, 111 VideoColumns.LONGITUDE, 112 VideoColumns.RESOLUTION, 113 }; 114 115 // Copy some info from the source file. 116 querySource(contentResolver, uri, projection, 117 new ContentResolverQueryCallback() { 118 @Override 119 public void onCursorResult(Cursor cursor) { 120 long timeTaken = cursor.getLong(0); 121 if (timeTaken > 0) { 122 values.put(Video.Media.DATE_TAKEN, timeTaken); 123 } 124 double latitude = cursor.getDouble(1); 125 double longitude = cursor.getDouble(2); 126 // TODO: Change || to && after the default location 127 // issue is 128 // fixed. 129 if ((latitude != 0f) || (longitude != 0f)) { 130 values.put(Video.Media.LATITUDE, latitude); 131 values.put(Video.Media.LONGITUDE, longitude); 132 } 133 values.put(Video.Media.RESOLUTION, cursor.getString(3)); 134 135 } 136 }); 137 138 return contentResolver.insert(Video.Media.EXTERNAL_CONTENT_URI, values); 139 } 140 retrieveVideoDurationMs(String path)141 private static int retrieveVideoDurationMs(String path) { 142 int durationMs = 0; 143 // Calculate the duration of the destination file. 144 MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 145 retriever.setDataSource(path); 146 String duration = retriever.extractMetadata( 147 MediaMetadataRetriever.METADATA_KEY_DURATION); 148 if (duration != null) { 149 durationMs = Integer.parseInt(duration); 150 } 151 try { 152 retriever.release(); 153 } catch (IOException e) { 154 // Ignore errors occurred while releasing the retriever. 155 } 156 return durationMs; 157 } 158 159 } 160