How to Append two videos in Android Programmatically - android

I am using this code. I need to merge two videos. It saved all videos in temp folder but not in merged condition. Append and DoAppend are my functions which I want for merging the videos.
public String append(ArrayList<String> trimVideos) {
for (int i = 0; i < trimVideos.size() - 1; i++) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
if (i == 0) {
String OutPutFileName = Constants.STORAGE_VIDEO_TEMP_PATH +
File.separator + "APPEND" + "_" + timeStamp + ".mp4";
doAppend(trimVideos.get(0), trimVideos.get(i + 1),OutPutFileName);
Log.e(Constants.TAG, "In First: " + i + " " + OutPutFileName);
} else {
String OutPutFileName = Constants.STORAGE_VIDEO_TEMP_PATH
+ File.separator + "APPEND" + i + "_" + timeStamp + ".mp4";
doAppend(lastAppendOut, trimVideos.get(i + 1), OutPutFileName);
Log.e(Constants.TAG, "In Second: " + i + " " + OutPutFileName);
}
}
Log.e(Constants.TAG, "In End: " + " " + lastAppendOut);
return lastAppendOut;
}
This Method Crashed my application on add track.
private String doAppend(String _firstVideo, String _secondVideo,String _newName) {
try {
Log.e("test", "Stage1");
FileInputStream fis1 = new FileInputStream(_firstVideo);
FileInputStream fis2 = new FileInputStream(_secondVideo);
Movie[] inMovies = new Movie[] {
MovieCreator.build(fis1.getChannel()),MovieCreator.build(fis2.getChannel()) };
List<Track> videoTracks = new LinkedList<Track>();
List<Track> audioTracks = new LinkedList<Track>();
//It returns one item of video and 2 item of video.
for (Movie m : inMovies) {
for (Track t : m.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Log.e("test", "Stage2");
Movie result = new Movie();
if (audioTracks.size() > 0) {
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
IsoFile out = new DefaultMp4Builder().build(result);
Log.e("test", "Stage3");
String filename = _newName;
lastAppendOut = filename;
Log.e(Constants.TAG, "In Append: " + " " + lastAppendOut);
FileOutputStream fos = new FileOutputStream(filename);
FileChannel fco = fos.getChannel();
fco.position(0);
out.getBox(fco);
fco.close();
fos.close();
fis1.close();
fis2.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
Log.e("check", e.getMessage());
}
return _newName;
}

Code For Merging Multiple Video
Gradle Dependency
implementation 'com.googlecode.mp4parser:isoparser:1.1.9'
Code
private String appendTwoVideos(String firstVideoPath, String secondVideoPath)
{
try {
Movie[] inMovies = new Movie[2];
inMovies[0] = MovieCreator.build(firstVideoPath);
inMovies[1] = MovieCreator.build(secondVideoPath);
List<Track> videoTracks = new LinkedList<>();
List<Track> audioTracks = new LinkedList<>();
for (Movie m : inMovies) {
for (Track t : m.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
result.addTrack(new AppendTrack(audioTracks
.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
result.addTrack(new AppendTrack(videoTracks
.toArray(new Track[videoTracks.size()])));
}
BasicContainer out = (BasicContainer) new DefaultMp4Builder().build(result);
#SuppressWarnings("resource")
FileChannel fc = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/wishbyvideo.mp4", "rw").getChannel();
out.writeContainer(fc);
fc.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
mFileName += "/wishbyvideo.mp4";
return mFileName;
}
You might wanna call this function from a background thread.

The above answer is perfectly right but It will only work if your media encoder is H264.....
mediaRecorder.setVideoEncoder(VideoEncoder.H264);
happy Coding :) :D

The above answer will only work when your codec, framerate, and bitrate are the same.
Gradle Dependency(This library will work in nearly every case)
implementation 'com.github.yangjie10930:EpMedia:v0.9.5'
CODE
private void mergeVideos() {
ArrayList<EpVideo> epVideos = new ArrayList<>();
epVideos.add(new EpVideo (file2)); // Video 1
epVideos.add(new EpVideo (file1)); // Video 2
EpEditor. OutputOption outputOption =new EpEditor.OutputOption(fileOutput);
outputOption.setWidth(720);
outputOption.setHeight(1280);
outputOption.frameRate = 25 ;
outputOption.bitRate = 10 ; //Default
EpEditor.merge(epVideos, outputOption, new OnEditorListener() {
#Override
public void onSuccess () {
Log.d("Status","Success");
}
#Override
public void onFailure () {
}
#Override
public void onProgress ( float progress ) {
// Get processing progress here
Log.d("Progress",""+progress);
}
});
}

Gradle Dependency
implementation "com.writingminds:FFmpegAndroid:0.3.2"
Code
Command to concate two videos side by side into one
val cmd : arrayOf("-y", "-i", videoFile!!.path, "-i", videoFileTwo!!.path, "-filter_complex", "hstack", outputFile.path)
Command to append two videos (one after another) into one
val cmd : arrayOf("-y", "-i", videoFile!!.path, "-i", videoFileTwo!!.path, "-strict", "experimental", "-filter_complex",
"[0:v]scale=iw*min(1920/iw\\,1080/ih):ih*min(1920/iw\\,1080/ih), pad=1920:1080:(1920-iw*min(1920/iw\\,1080/ih))/2:(1080-ih*min(1920/iw\\,1080/ih))/2,setsar=1:1[v0];[1:v] scale=iw*min(1920/iw\\,1080/ih):ih*min(1920/iw\\,1080/ih), pad=1920:1080:(1920-iw*min(1920/iw\\,1080/ih))/2:(1080-ih*min(1920/iw\\,1080/ih))/2,setsar=1:1[v1];[v0][0:a][v1][1:a] concat=n=2:v=1:a=1",
"-ab", "48000", "-ac", "2", "-ar", "22050", "-s", "1920x1080", "-vcodec", "libx264", "-crf", "27",
"-q", "4", "-preset", "ultrafast", outputFile.path)
Note :
"videoFile" is your first video path.
"videoFileTwo" is your second video path.
"outputFile" is your combined video path which is our final output path
To create output path of video
fun createVideoPath(context: Context): File {
val timeStamp: String = SimpleDateFormat(Constant.DATE_FORMAT, Locale.getDefault()).format(Date())
val imageFileName: String = "APP_NAME_"+ timeStamp + "_"
val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)
if (storageDir != null) {
if (!storageDir.exists()) storageDir.mkdirs()
}
return File.createTempFile(imageFileName, Constant.VIDEO_FORMAT, storageDir)
}
Code to execute command
try {
FFmpeg.getInstance(context).execute(cmd, object : ExecuteBinaryResponseHandler() {
override fun onStart() {
}
override fun onProgress(message: String?) {
callback!!.onProgress(message!!)
}
override fun onSuccess(message: String?) {
callback!!.onSuccess(outputFile)
}
override fun onFailure(message: String?) {
if (outputFile.exists()) {
outputFile.delete()
}
callback!!.onFailure(IOException(message))
}
override fun onFinish() {
callback!!.onFinish()
}
})
} catch (e: Exception) {
} catch (e2: FFmpegCommandAlreadyRunningException) {
}

Related

Read sound from Assets folder (work with the android nexus 5 emulator but not on my phone)

I succeeded to run my function with the Android Emulator. The Assets folder is well recognised and all sounds files are in my Array allSounds.
But when i try to run my apk on my phone with ADB, my sounds folder in the Assets is empty. This function is on the main Activity.
Do you have any ideas to understand my problem ?
Thank's !!
public void playRandom(View view) throws IOException {
Resources res = getResources(); //if you are in an activity
AssetManager aMan = res.getAssets();
sounds = new ArrayList<>();
String path = "sounds/";
String folderNames[] = aMan.list(path);
// TextView debug = (TextView) findViewById(R.id.debug);
//Evite de reCall la fonction si les sons sont déjà dans l'Array allSounds[]
if (!flagDoNotRepeat) {
for (String folderName : folderNames) {
String[] fileNames = getAssets().list(path + folderName + "/");
for (String file : fileNames) {
allSounds.add(path + folderName + "/" + file);
//debug.append("\n" + path + folderName + "/" + file);
flagDoNotRepeat = true;
}
}
}
m = new MediaPlayer();
try {
if (m.isPlaying()) {
m.stop();
m.release();
m = new MediaPlayer();
}
AssetFileDescriptor descriptor = aMan.openFd(allSounds.get(new Random().nextInt(allSounds.size())));
m.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
descriptor.close();
m.prepare();
m.setVolume(1f, 1f);
m.start();
} catch (Exception e) {
e.printStackTrace();
}
}
Edit : i resolved my problem :
am = getAssets();
String path = "sounds";
String folderNames[] = new String[0];
try {
folderNames = am.list(path);
} catch (IOException e) {
e.printStackTrace();
}
// TextView debug = (TextView) findViewById(R.id.debug);
//Evite de reCall la fonction si les sons sont déjà dans l'Array allSounds[]
if (!flagDoNotRepeat) {
for (String folderName : folderNames) {
String[] fileNames = new String[0];
try {
fileNames = am.list(path + "/" + folderName);
} catch (IOException e) {
e.printStackTrace();
}
for (String file : fileNames) {
allSounds.add(path + "/" + folderName + "/" + file);
//debug.append("\n" + path + folderName + "/" + file);
flagDoNotRepeat = true;
}
}
}

android merging with MP4Parser issue

I have a problem related to the merging of two videos. When I'm trying to merge two videos from different landscape modes (left/right) one of the videos is displaying upside down. I'm using MP4Parser as a library to manage the trimming and merging
protected void combineClips() throws IOException {
MediaMetadataRetriever m = new MediaMetadataRetriever();
for (int i = 0; i < paths.size(); i++) {
m.setDataSource(paths.get(i));
if (Build.VERSION.SDK_INT >= 17) {
String s = m.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
if (Integer.valueOf(s) == 0) {
isLeftLandscape = true;
}
if (Integer.valueOf(s) == 180) {
isRightLandscape = true;
}
}
}
for (int i = 0; i < paths.size(); i++) {
Movie tm = MovieCreator.build(paths.get(i));
Log.d(TAG, files.size() + "files");
files.add(tm);
}
if (isLeftLandscape && isRightLandscape) {
for (int i = 0; i < paths.size(); i++) {
m.setDataSource(paths.get(i));
if (Build.VERSION.SDK_INT >= 17) {
String s = m.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
if (Integer.valueOf(s) == 0)
{
Log.d(TAG, "the rotation is " + s);
rotate(paths.get(i), i);
}}
}
}
List<Track> videoTracks = new ArrayList<Track>();
List<Track> audioTracks = new ArrayList<Track>();
for (Movie movie : files) {
for (Track t : movie.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
Log.d(TAG, String.valueOf(audioTracks.size()) + "audi");
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
Log.d(TAG, String.valueOf(audioTracks.size()) + "vide");
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
Container out = new DefaultMp4Builder().build(result);
String folder_main = "VidApp";
File f = new File(Environment.getExternalStorageDirectory(), folder_main);
if (!f.exists()) {
f.mkdirs();
}
FileChannel fc = new RandomAccessFile(String.format(System.getenv("EXTERNAL_STORAGE") + "/VidApp" + "/output.mp4"), "rw").getChannel();
out.writeContainer(fc);
fc.close();
while (!audioTracks.isEmpty()) {
audioTracks.remove(0);
}
while (!videoTracks.isEmpty()) {
videoTracks.remove(0);
}
while (!files.isEmpty()) {
files.remove(0);
}
}
public void rotate(String path, int position) throws IOException {
IsoFile isoFile = new IsoFile(path);
Movie m = new Movie();
List<TrackBox> trackBoxes = isoFile.getMovieBox().getBoxes(
TrackBox.class);
for (TrackBox trackBox : trackBoxes) {
trackBox.getTrackHeaderBox().setMatrix(Matrix.ROTATE_180);
m.addTrack(new Mp4TrackImpl(trackBox));
}
Log.d(TAG, position + " of " + files.size());
files.set(position, m);
}

NanoHTTPD How to save uploaded file to sdcard folder

How to save uploaded file to sdcard folder , currently it stores to /data/data/cache folder with filename like "NanoHTTPD-some random number".
I am not able to copy it to any folder location in sdcard.
I would like to save the file to a pre-mentioned folder location in sdcard with the same name as the original file name was uploaded from my html page.
I have tried all sort of codes .But file copy fails all the time.
1)Not able to get correct location of temp file.
2)Not getting original filename that the form was posted with
Here is my implementation .
Please help i am stuck.
public class HttpMultimediaServer extends NanoHTTPD {
private static final String TAG = "HttpMultimediaServer";
private FileInputStream fileInputStream;
public HttpMultimediaServer() {
super(12345);
this.setTempFileManagerFactory(new ExampleManagerFactory());
}
#Override
public Response serve(IHTTPSession session) {
Method method = session.getMethod();
String uri = session.getUri();
Log.e("handle", "url>>" + uri);
if (uri.contains(filesOnly)) {
isfilesOnly = true;
uri = "/";
} else
isfilesOnly = false;
uri = uri.replace("%20", " ");
try {
uri=new String (uri.getBytes ("iso-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e2) {
e2.printStackTrace();
}
File filePathServer = new File(uri);
if (method==Method.POST) {
try {
Map<String, String> hdrs=session.getHeaders();
Map<String, String> params=session.getParms();
Map<String, String> files = new HashMap<String, String>();
session.parseBody(files);
Set<String> keys = files.keySet();
for(String key: keys){
String name = key;
String loaction = files.get(key);
File tempfile = new File(loaction);
String tempFileName = files.get(loaction).toString();
File fileToMove = new File(tempFileName);
// temp file path returned by NanoHTTPD
String p =Environment.getExternalStorageDirectory().getPath();
String newFile = p + "/LICENSE.txt";
File nf = new File(newFile); // I want to move file here
if (fileToMove.canWrite()) {
boolean success = fileToMove.renameTo(nf);
if (success == true) {
// LOG to console
Log.i("FILE_MOVED_TO", newFile);
} else {
Log.e("FILE_MOVE_ERROR", tempFileName);
}
} else {
Log.e("PERMISSION_ERROR_TEMP_FILE", tempFileName);
}
}
uploadstatus = UPLOAD_SUCESS;
return new Response("UPLOAD_SUCESS");
} catch (Exception e) {
e.printStackTrace();
uploadstatus = UPLOAD_FAIL;
return new Response("UPLOAD_FAIL");
}
}
}
public static void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
public static void copyFile(File src, File dst) throws IOException
{
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try
{
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
private Response getFullResponse(String mimeType,String filePath) throws FileNotFoundException {
// cleanupStreams();
fileInputStream = new FileInputStream(filePath);
return new Response(Response.Status.OK, mimeType, fileInputStream);
}
private Response getPartialResponse(String mimeType, String rangeHeader,String filePath) throws IOException {
File file = new File(filePath);
String rangeValue = rangeHeader.trim().substring("bytes=".length());
long fileLength = file.length();
long start, end;
if (rangeValue.startsWith("-")) {
end = fileLength - 1;
start = fileLength - 1
- Long.parseLong(rangeValue.substring("-".length()));
} else {
String[] range = rangeValue.split("-");
start = Long.parseLong(range[0]);
end = range.length > 1 ? Long.parseLong(range[1])
: fileLength - 1;
}
if (end > fileLength - 1) {
end = fileLength - 1;
}
if (start <= end) {
long contentLength = end - start + 1;
// cleanupStreams();
fileInputStream = new FileInputStream(file);
//noinspection ResultOfMethodCallIgnored
fileInputStream.skip(start);
Response response = new Response(Response.Status.PARTIAL_CONTENT, mimeType, fileInputStream);
response.addHeader("Content-Length", contentLength + "");
response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
response.addHeader("Content-Type", mimeType);
return response;
} else {
return new Response(Response.Status.RANGE_NOT_SATISFIABLE, "text/html", rangeHeader);
}
}
int UPLOAD_SUCESS = 1;
int UPLOAD_FAIL = -1;
int UPLOAD_NO = 0;
int uploadstatus;
boolean isfilesOnly;
String filesOnly = "?filesOnly=1";
ArrayList<CLocalFile> list;
StringBuilder sb;
public void walkdir(File dir) {
File listFile[] = dir.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
// checking if it is a directory
if (listFile[i].isDirectory()) {
if (isfilesOnly)
walkdir(listFile[i]);
else {
CLocalFile f = new CLocalFile();
f.setName(listFile[i].getName());
f.setData(listFile[i].getAbsolutePath());
f.setSize("Folder");
list.add(f);
continue;
}
}
// checking the file extension if it is a file
String fileName = listFile[i].getName();
String extension = "";
int e = fileName.lastIndexOf('.');
if (e > 0) {
extension = fileName.substring(e + 1);
}
if (!isfilesOnly
|| CollabUtility.video_pattern.contains(extension
.toLowerCase(Locale.ENGLISH))
|| CollabUtility.document_pattern.contains(extension
.toLowerCase(Locale.ENGLISH))
|| CollabUtility.audio_pattern.contains(extension
.toLowerCase(Locale.ENGLISH))) {
CLocalFile f = new CLocalFile();
f.setName(fileName);
String mb = "Bytes";
double size = listFile[i].length();
if (size > 1024) {
size = size / 1024;
mb = "KB";
}
if (size > 1024) {
size = size / 1024;
mb = "MB";
}
if (size > 1024) {
size = size / 1024;
mb = "GB";
}
size = Math.floor(size * 100 + 0.5) / 100;
f.setSize(size + " " + mb);
f.setData(listFile[i].getAbsolutePath());
list.add(f);
}
}
}
}
void listofMedia(File file) {
list = new ArrayList<CLocalFile>();
walkdir(file);
// now create the html page
String style = "<style>" + "html {background-color:#eeeeee;} "
+ "body { background-color:#FFFFFF; "
+ "font-family:Tahoma,Arial,Helvetica,sans-serif; "
+ "font-size:18x; " + "border:3px " + "groove #006600; "
+ "padding:15px; } " + "</style>";
String script = "<script language='javascript'>"
+ "function clickit(state) {"
+ "if(state==true){document.getElementById('filesonly').checked="
+ "! document.getElementById('filesonly').checked}"
+ "if ( document.getElementById('filesonly').checked == false ){"
+ "var l=window.location.href;" + "l=l.replace('" + filesOnly
+ "', '');" + "window.location=l;" + "}"
+ "else{var l=window.location.href;"
+ "window.location=String.concat(l,'" + filesOnly + "')" + "}"
+ "}</script>";
Log.d("check", script);
sb = new StringBuilder();
sb.append("<html>");
sb.append("<head>");
sb.append("<title>Files from device</title>");
sb.append(style);
// sb.append("<script language='javascript'>"
// + "function clickit() {"
// + "if ( document.getElementById('filesonly').checked == false ){"
// + "var l=window.location.href;" + "l=l.replace('" + filesOnly
// + "', '');" + "window.location=l;" + "}"
// + "else{var l=window.location.href;"
// + "window.location=String.concat(l,'" + filesOnly + "')" + "}"
// + "}</script>");
sb.append(script);
sb.append("</head>");
sb.append("<body alink=\"blue\" vlink=\"blue\">");
Log.d("check", sb.toString());
// if(true)
// return;
// form upload
sb.append("<h3>File Upload:</h3>");
sb.append("Select a file to upload: <br/>");
sb.append("<form action=\"\" method=\"post\" enctype=\"multipart/form-data\">");
sb.append("<input type=\"file\" name=\"uploadfile\" size=\"50\" />");
sb.append("<input type=\"submit\" value=\"Upload File\" />");
sb.append("</form>");
if (uploadstatus == UPLOAD_FAIL)
sb.append("<h3><font color='red'>The upload was failed</font></h3>");
else if (uploadstatus == UPLOAD_SUCESS)
sb.append("<h3><font color='red'>The upload was successfull</font></h3>");
// if files are there or not
if (list != null && list.size() != 0) {
sb.append("<h3>The following files are hosted live from ");
if (!isfilesOnly)
sb.append("<font color='blue'>" + file.getName()
+ "</font> folder of ");
sb.append("the device</h3>");
} else {
sb.append("<h3>Couldn't find any file from <font color='blue'>"
+ file.getName() + "</font> folder of the device</h3>");
}
// checkbox
if (isfilesOnly)
sb.append("<input type=\"checkbox\" onchange='clickit(false);' checked='true' id=\"filesonly\" />"
+ "<asd onclick='clickit(true);' style=\"cursor:default;\">"
+ "Show only relevant Files (Audio, Video and Documents)</asd>");
else
sb.append("<input type=\"checkbox\" onchange='clickit(false);' id=\"filesonly\" />"
+ "<asd onclick='clickit(true);' style=\"cursor:default;\">"
+ "Show only relevant Files (Audio, Video and Documents)</asd>");
// table of files
sb.append("<table cellpadding='5px' align=''>");
// showing path URLs if not only files
if (!isfilesOnly) {
ArrayList<File> href = new ArrayList<File>();
File parent = new File(file.getPath());
while (parent != null) {
href.add(parent);
// pointing to the next parent
parent = parent.getParentFile();
}
sb.append("<tr>");
sb.append("<td colspan=2><b>");
sb.append("<a href='" + file.getParent() + "'>");
sb.append("UP");
sb.append("</a>");
// printing the whole structure
String path = "";
for (int i = href.size() - 2; i >= 0; --i) {
path = href.get(i).getPath();
if (isfilesOnly)
path += filesOnly;
sb.append(" => <a href='" + path + "'>");
sb.append(href.get(i).getName());
sb.append("</a>");
}
sb.append("</b></td>");
sb.append("</tr>");
}
sb.append("<tr>");
sb.append("<td>");
sb.append("<b>File Name</b>");
sb.append("</td>");
sb.append("<td>");
sb.append("<b>Size / Type</b>");
sb.append("</td>");
sb.append("<tr>");
// sorting the list
Collections.sort(list);
// showing the list of files
for (CLocalFile f : list) {
String data = f.getData();
if (isfilesOnly)
data += filesOnly;
sb.append("<tr>");
sb.append("<td>");
sb.append("<a href='" + data + "'>");
sb.append(f.getName());
sb.append("</a>");
sb.append("</td>");
sb.append("<td align=\"right\">");
sb.append(f.getSize());
sb.append("</td>");
sb.append("</tr>");
}
sb.append("</table>");
sb.append("</body>");
sb.append("</html>");
}
private static class ExampleManagerFactory implements TempFileManagerFactory {
#Override
public TempFileManager create() {
return new ExampleManager();
}
}
private static class ExampleManager implements TempFileManager {
private final String tmpdir;
private final List<TempFile> tempFiles;
private ExampleManager() {
tmpdir = System.getProperty("java.io.tmpdir");
// tmpdir = System.getProperty("/sdcard");
tempFiles = new ArrayList<TempFile>();
}
#Override
public TempFile createTempFile() throws Exception {
DefaultTempFile tempFile = new DefaultTempFile(tmpdir);
tempFiles.add(tempFile);
System.out.println("Created tempFile: " + tempFile.getName());
return tempFile;
}
#Override
public void clear() {
if (!tempFiles.isEmpty()) {
System.out.println("Cleaning up:");
}
for (TempFile file : tempFiles) {
try {
System.out.println(" "+file.getName());
file.delete();
} catch (Exception ignored) {}
}
tempFiles.clear();
}
}
}
If you are using NanoHTTPD r.2.1.0, please try these codes:
#Override
public Response serve(IHTTPSession session) {
Map<String, String> headers = session.getHeaders();
Map<String, String> parms = session.getParms();
Method method = session.getMethod();
String uri = session.getUri();
Map<String, String> files = new HashMap<>();
if (Method.POST.equals(method) || Method.PUT.equals(method)) {
try {
session.parseBody(files);
} catch (IOException ioe) {
return getResponse("Internal Error IO Exception: " + ioe.getMessage());
} catch (ResponseException re) {
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
}
}
if ("/uploadfile".equalsIgnoreCase(uri)) {
String filename = parms.get("filename");
String tmpFilePath = files.get("filename");
if (null == filename || null == tmpFilePath) {
// Response for invalid parameters
}
File dst = new File(mCurrentDir, filename);
if (dst.exists()) {
// Response for confirm to overwrite
}
File src = new File(tmpFilePath);
try {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
byte[] buf = new byte[65536];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (IOException ioe) {
// Response for failed
}
// Response for success
}
// Others...
}
In order to upload multiple files in a single input file like:
<input type="file" name="filename" multiple>
I modify decodeMultipartData() method in NanoHTTPD.java from:
private void decodeMultipartData(String boundary, ByteBuffer fbuf, BufferedReader in, Map<String, String> parms,
Map<String, String> files) throws ResponseException {
try {
int[] bpositions = getBoundaryPositions(fbuf, boundary.getBytes());
int boundarycount = 1;
String mpline = in.readLine();
while (mpline != null) {
if (!mpline.contains(boundary)) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html");
}
boundarycount++;
Map<String, String> item = new HashMap<String, String>();
mpline = in.readLine();
while (mpline != null && mpline.trim().length() > 0) {
int p = mpline.indexOf(':');
if (p != -1) {
item.put(mpline.substring(0, p).trim().toLowerCase(Locale.US), mpline.substring(p + 1).trim());
}
mpline = in.readLine();
}
if (mpline != null) {
String contentDisposition = item.get("content-disposition");
if (contentDisposition == null) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html");
}
StringTokenizer st = new StringTokenizer(contentDisposition, ";");
Map<String, String> disposition = new HashMap<String, String>();
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
int p = token.indexOf('=');
if (p != -1) {
disposition.put(token.substring(0, p).trim().toLowerCase(Locale.US), token.substring(p + 1).trim());
}
}
String pname = disposition.get("name");
pname = pname.substring(1, pname.length() - 1);
String value = "";
if (item.get("content-type") == null) {
while (mpline != null && !mpline.contains(boundary)) {
mpline = in.readLine();
if (mpline != null) {
int d = mpline.indexOf(boundary);
if (d == -1) {
value += mpline;
} else {
value += mpline.substring(0, d - 2);
}
}
}
} else {
if (boundarycount > bpositions.length) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "Error processing request");
}
int offset = stripMultipartHeaders(fbuf, bpositions[boundarycount - 2]);
String path = saveTmpFile(fbuf, offset, bpositions[boundarycount - 1] - offset - 4);
files.put(pname, path);
value = disposition.get("filename");
value = value.substring(1, value.length() - 1);
do {
mpline = in.readLine();
} while (mpline != null && !mpline.contains(boundary));
}
parms.put(pname, value);
}
}
} catch (IOException ioe) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage(), ioe);
}
}
tobe:
private void decodeMultipartData(String boundary, ByteBuffer fbuf, BufferedReader in, Map<String, String> parms,
Map<String, String> files) throws ResponseException {
try {
String pname_0 = "";
String pname_1 = "";
int pcount = 1;
int[] bpositions = getBoundaryPositions(fbuf, boundary.getBytes());
int boundarycount = 1;
String mpline = in.readLine();
while (mpline != null) {
if (!mpline.contains(boundary)) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html");
}
boundarycount++;
Map<String, String> item = new HashMap<String, String>();
mpline = in.readLine();
while (mpline != null && mpline.trim().length() > 0) {
int p = mpline.indexOf(':');
if (p != -1) {
item.put(mpline.substring(0, p).trim().toLowerCase(Locale.US), mpline.substring(p + 1).trim());
}
mpline = in.readLine();
}
if (mpline != null) {
String contentDisposition = item.get("content-disposition");
if (contentDisposition == null) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html");
}
StringTokenizer st = new StringTokenizer(contentDisposition, ";");
Map<String, String> disposition = new HashMap<String, String>();
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
int p = token.indexOf('=');
if (p != -1) {
disposition.put(token.substring(0, p).trim().toLowerCase(Locale.US), token.substring(p + 1).trim());
}
}
String pname = disposition.get("name");
pname = pname.substring(1, pname.length() - 1);
if (pname.contentEquals(pname_0)) {
pname_1 = pname + String.valueOf(pcount);
pcount++;
} else {
pname_0 = pname;
pname_1 = pname;
}
String value = "";
if (item.get("content-type") == null) {
while (mpline != null && !mpline.contains(boundary)) {
mpline = in.readLine();
if (mpline != null) {
int d = mpline.indexOf(boundary);
if (d == -1) {
value += mpline;
} else {
value += mpline.substring(0, d - 2);
}
}
}
} else {
if (boundarycount > bpositions.length) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "Error processing request");
}
int offset = stripMultipartHeaders(fbuf, bpositions[boundarycount - 2]);
String path = saveTmpFile(fbuf, offset, bpositions[boundarycount - 1] - offset - 4);
files.put(pname_1, path);
value = disposition.get("filename");
value = value.substring(1, value.length() - 1);
do {
mpline = in.readLine();
} while (mpline != null && !mpline.contains(boundary));
}
parms.put(pname_1, value);
}
}
} catch (IOException ioe) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage(), ioe);
}
}
Hope this help and sorry for my bad English..:-)
Here's my working code:
public Response serve(IHTTPSession session) {
Map<String, String> headers = session.getHeaders();
Map<String, String> parms = session.getParms();
Method method = session.getMethod();
String uri = session.getUri();
Map<String, String> files = new HashMap<>();
if (Method.POST.equals(method) || Method.PUT.equals(method)) {
try {
session.parseBody(files);
} catch (IOException ioe) {
return getResponse("Internal Error IO Exception: " + ioe.getMessage());
} catch (ResponseException re) {
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
}
}
uri = uri.trim().replace(File.separatorChar, '/');
if (uri.indexOf('?') >= 0) {
uri = uri.substring(0, uri.indexOf('?'));
}
// Other implementation goes here...
if ("/uploadfiles".equalsIgnoreCase(uri)) {
String filename, tmpFilePath;
File src, dst;
for (Map.Entry entry : parms.entrySet()) {
if (entry.getKey().toString().substring(0, 8).equalsIgnoreCase("filename")) {
filename = entry.getValue().toString();
tmpFilePath = files.get(entry.getKey().toString());
dst = new File(mCurrentDir, filename);
if (dst.exists()) {
return getResponse("Internal Error: File already exist");
}
src = new File(tmpFilePath);
if (! copyFile(src, dst)) {
return getResponse("Internal Error: Uploading failed");
}
}
}
return getResponse("Success");
}
return getResponse("Error 404: File not found");
}
private boolean deleteFile(File target) {
if (target.isDirectory()) {
for (File child : target.listFiles()) {
if (! deleteFile(child)) {
return false;
}
}
}
return target.delete();
}
private boolean copyFile(File source, File target) {
if (source.isDirectory()) {
if (! target.exists()) {
if (! target.mkdir()) {
return false;
}
}
String[] children = source.list();
for (int i = 0; i < source.listFiles().length; i++) {
if (! copyFile(new File(source, children[i]), new File(target, children[i]))) {
return false;
}
}
} else {
try {
InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(target);
byte[] buf = new byte[65536];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (IOException ioe) {
return false;
}
}
return true;
}
private Response getResponse(String message) {
return createResponse(Response.Status.OK, MIME_PLAINTEXT, message);
}
// Announce that the file server accepts partial content requests
private Response createResponse(Response.Status status, String mimeType, String message) {
Response res = new Response(status, mimeType, message);
res.addHeader("Accept-Ranges", "bytes");
return res;
}
To allow multiple file upload:
<input type="file" name="filename" multiple>
The same issue existed in the 2.2.1 branch. Following the same logic, I fixed the same function with a few lines of code change.
Add a counter pcount at the beginning of the function:
private void decodeMultipartFormData(String boundary, String encoding, ByteBuffer fbuf, Map<String, String> parms, Map<String, String> files) throws ResponseException {
int pcount = 1;
try {
Then use the counter to update the keyname if filename is not empty:
while (matcher.find()) {
String key = matcher.group(1);
if ("name".equalsIgnoreCase(key)) {
part_name = matcher.group(2);
} else if ("filename".equalsIgnoreCase(key)) {
file_name = matcher.group(2);
// add these two line to support multiple
// files uploaded using the same field Id
if (!file_name.isEmpty()) {
if (pcount > 0)
part_name = part_name + String.valueOf(pcount++);
else
pcount++;
}
}
}
Maybe late, but just for latecommers just like me.
Explained before, the client use okhttp upload a file just like the follow code:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
//sourceFile is a File as you know
.addFormDataPart("image_file_1", "logo-square1.png", RequestBody.create(MediaType.parse("image/png"), sourceFile))
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
The follow code is what you want
#Override
public Response serve(IHTTPSession session) {
Method method = session.getMethod();
// ▼ 1、parse post body ▼
Map<String, String> files = new HashMap<>();
if (Method.POST.equals(method) || Method.PUT.equals(method)) {
try {
session.parseBody(files);
} catch (IOException ioe) {
return getResponse("Internal Error IO Exception: " + ioe.getMessage());
} catch (ResponseException re) {
return newFixedLengthResponse(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
}
}
//after the body parsed, by default nanoHTTPD will save the file to cache and put it into params( "image_file_1" as key and the value is "logo-square1.png");
//files key is just like "image_file_1", and the value is nanoHTTPD's template file path in cache
// ▲ 1、parse post body ▲
// ▼ 2、copy file to target path xiaoyee ▼
Map<String, String> params = session.getParms();
for (Map.Entry<String, String> entry : params.entrySet()) {
final String paramsKey = entry.getKey();
if (paramsKey.contains("image_file_1")) {
final String tmpFilePath = files.get(paramsKey);
final String fileName = paramsKey;
final File tmpFile = new File(tmpFilePath);
final File targetFile = new File(mCurrentDir + fileName);
LogUtil.log("copy file now, source file path: %s,target file path:%s", tmpFile.getAbsoluteFile(), targetFile.getAbsoluteFile());
//a copy file method just what you like
copyFile(tmpFile, targetFile);
//maybe you should put the follow code out
return getResponse("Success");
}
}
// ▲ 2、copy file to target path xiaoyee ▲
return getResponse("Error 404: File not found");
}

How to concat/merge mp4, with setting correct duration?

I need merge a few mp4 files on android, so I am tried using mp4parser merge a few mp4.
private void mergeMp4(File output, String[] files) throws IOException {
Movie[] inMovies = new Movie[files.length];
for (int i=0, len = files.length; i<len; ++i) {
inMovies[i] = MovieCreator.build("/tmp/tmp/" + files[i]);
}
List<Track> videoTracks = new LinkedList<Track>();
List<Track> audioTracks = new LinkedList<Track>();
for (Movie m : inMovies) {
for (Track t : m.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
Container out = new DefaultMp4Builder().build(result);
FileChannel fc = new RandomAccessFile(output, "rw").getChannel();
out.writeContainer(fc);
fc.close();
}
// work correct for non-merged mp4 file
private long getDuration(String filename) throws IOException {
IsoFile isoFile = new IsoFile(filename);
long lengthInSeconds = isoFile.getMovieBox().getMovieHeaderBox().getDuration() / isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return lengthInSeconds * 1000;
}
somewhere in code
File tmp = new File("/tmp/tmp");
String[] tmpFiles = tmp.list();
File recordedFile = new File("/mnt/sdcard/app/output.mp4")
mergeMp4(recordedFile, tmpFiles);
// both print value near 0 (about 20 millis)
Log.d("TAG", String.valueOf(getDuration(recordedFile)));
System.out.println(getDuration(recordedFile));
If I trying play merged file with android MediaPlayer or any other player:
player = new MediaPlayer();
try {
player.setDataSource(getFilename());
player.prepare();
player.start();
int duration = player.getDuaration();
// both print value near 0 (about 20 millis)
Log.d("TAG", String.valueOf(duration));
System.out.println(duration);
} catch (IOException e) {
Log.e(TAG, "prepare() failed", e);
}
It is merges files but all mediaplayers and even method of mp4parser author of getting duration returns that duration always about 0 (zero) seconds.

downloading files from server using IntentService in android

I am trying to download files using IntentService.My downloading queue is interrupted.
I am using the following code to start a service
Intent intent = new Intent(ViewShowList.this, DownloadService.class);
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(handler);
intent.putExtra("MESSENGER", messenger);
intent.putExtra("url", url);
intent.putExtra("share_id", showID);
intent.putExtra("showname", name);
intent.putExtra("showdatecreated", dateCreated);
intent.putExtra("noofFiles", noofFiles);
startService(intent);
Handler for communication back
#SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
public void handleMessage(Message message) {
Log.d(TAG, "handleMessage.....................");
//Object path = message.obj;
if (message.arg1 == DownloadService.COMPLETED) {
Toast.makeText(mContext, getResources().getString(R.string.Text_MadeOffline), Toast.LENGTH_SHORT).show();
createOfflineShowsList();
syncShowAssets();
if (showListadapter != null) {
showListadapter.notifyDataSetChanged();
}
} else {
Log.e(TAG, "Download Failed...");
}
}
};
DownloadService.java
This is service class which extend IntentService
public class DownloadService
extends IntentService {
private int OFFSET;
private int LIMIT;
String data;
private final String TAG = "DownloadService";
private int result = Activity.RESULT_CANCELED;
public static int COMPLETED = 100;
public static int FAILED = 101;
public static int LOW_SPACE = 102;
public static int NETWORK_PROBLEM = 103;
public static int ASSERT_EXISIT = 104;
public static int PARTIALLY_DOWNLOADED = 105;
public static int NO_FILE = 105;
private NotificationManager notificationManager;
private Notification notification;
ConnectivityManager connMgr;
ArrayList<HashMap<String, String>> showAssetList;
private SharedPreferences sotcPref;
PendingIntent contentIntent;
int i = 1;
String url;
String showname;
String showdatecreated;
String showId;
Messenger messenger;
int noofFiles;
public DownloadService() {
super("DownloadService");
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 5 " + "DownloadService()constructor");
}
if (Constants.DEBUG) {
Log.d(TAG, "DownloadService... Constructor");
}
OFFSET = 0;
LIMIT = 3;
}
#SuppressWarnings("deprecation")
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 6 " + "onHandleIntent");
}
connMgr = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
notificationManager = (NotificationManager) getApplicationContext().getSystemService(getApplicationContext().NOTIFICATION_SERVICE);
sotcPref = getApplicationContext().getSharedPreferences("SOTCPref", MODE_PRIVATE);
if (Constants.DEBUG) {
Log.d(TAG, "onHandleIntent.........");
}
Bundle extras = intent.getExtras();
url = extras.getString("url");
showname = extras.getString("showname");
showdatecreated = extras.getString("showdatecreated");
//sara
if (showdatecreated.contains("/")) {
data = showdatecreated.replaceAll("/", "#");
if (Constants.DEBUG) {
System.out.println("date");
}
if (Constants.DEBUG) {
System.out.println(data);
}
} else {
data = showdatecreated;
if (Constants.DEBUG) {
System.out.println("date in else");
}
if (Constants.DEBUG) {
System.out.println(showdatecreated);
}
if (Constants.DEBUG) {
System.out.println(data);
}
}
showId = extras.getString("share_id");
noofFiles = extras.getInt("noofFiles");
messenger = (Messenger) extras.get("MESSENGER");
Intent notificationIntent = new Intent();
contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
notification = new Notification(R.drawable.sotc_notification_icon, "", System.currentTimeMillis());
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
notification.contentView = new RemoteViews(getApplicationContext()
.getPackageName(), R.layout.upload_progress_bar);
notification.icon = R.drawable.sotc_notification_icon;
notification.contentView.setTextViewText(R.id.textView1, showname);
notification.contentIntent = contentIntent;
notification.contentView.setProgressBar(R.id.progressBar1, 100, 0, false);
notificationManager.notify(1, notification);
if (Constants.DEBUG) {
Log.i("FOO", "Notification started");
}
if (showname.length() > 18) {
showname = showname.substring(0, 17);
}
if (DownloadAssets.TOTAL_ASSET_COUNT == 0) {
downloadSetofAssets(OFFSET, LIMIT, url);
if (DownloadAssets.TOTAL_ASSET_COUNT > LIMIT) {
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 8 " + "if(DownloadAssets.TOTAL_ASSET_COUNT > LIMIT)");
}
for (OFFSET = LIMIT; OFFSET < DownloadAssets.TOTAL_ASSET_COUNT; ) {
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 8.1 " + "if(DownloadAssets.TOTAL_ASSET_COUNT > LIMIT)");
}
downloadSetofAssets(OFFSET, LIMIT, url);
OFFSET = OFFSET + LIMIT;
}
}
}
if (i > 1) {
result = DownloadService.COMPLETED;
notification.setLatestEventInfo(DownloadService.this, "Downloaded Successfully", "", contentIntent);
Message msg = Message.obtain();
msg.arg1 = result;
try {
messenger.send(msg);
} catch (android.os.RemoteException e1) {
if (Constants.DEBUG) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
} else {
result = DownloadService.FAILED;
notification.setLatestEventInfo(DownloadService.this, "Downloaded Failed", "", contentIntent);
if (Constants.DEBUG) {
Log.e(TAG, "Download Failed...");
}
}
notification.contentView.setImageViewResource(R.id.image, R.drawable.icon);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1, notification);
}
private void downloadSetofAssets(int OFFSET, int LIMIT, String url) {
// TODO Auto-generated method stub
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 7 " + "downloadSetofAssets");
}
try {
url = url.replace("value1", URLEncoder.encode("" + OFFSET, "UTF-8"));
url = url.replace("value2", URLEncoder.encode("" + LIMIT, "UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (Constants.DEBUG) {
Log.i(TAG, "Show offline -- Asset URL: " + url);
}
showAssetList = DownloadAssets.hit(getApplicationContext(), url);
for (HashMap<String, String> asset : showAssetList) {
String thumbUrl = asset.get("thumb_url");
String normalUrl = asset.get("normal_url");
String mp4Url = asset.get("mp4_url");
String fileType = asset.get("filetype");
String assetID = asset.get("id");
String assetType = asset.get("asset_type");
if (Constants.DEBUG) {
Log.d(TAG, "Thumb Url :" + thumbUrl);
}
if (Constants.DEBUG) {
Log.d(TAG, "Normal Url :" + normalUrl);
}
if (Constants.DEBUG) {
Log.d(TAG, "Asset ID : " + assetID);
}
if (Constants.DEBUG) {
Log.d(TAG, "Asset Type : " + assetType);
}
if (Constants.DEBUG) {
Log.d(TAG, "MP4 Url : " + mp4Url);
}
if (Constants.DEBUG) {
Log.d(TAG, "FileType : " + fileType);
}
boolean isDownloaded = false;
if (assetType.equals("1")) { // Image
File assetDirectory = createAssetDirectory(showId, showname, data, assetID, assetType);
if (assetDirectory != null) {
File thumb = new File(assetDirectory.getAbsolutePath(), "/Thumb");
thumb.mkdirs();
// Thumbnail
File thumbFile = new File(thumb.getAbsolutePath(), "/Thumb." + getExtention(thumbUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Thumb File ath : " + thumbFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, thumbUrl, thumbFile.getAbsolutePath(), messenger);
File normal = new File(assetDirectory.getAbsolutePath(), "/Normal");
normal.mkdirs();
// Normal
File normalFile = new File(normal.getAbsolutePath(), "/Normal." + getExtention(normalUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Normal File path: " + normalFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, normalUrl, normalFile.getAbsolutePath(), messenger);
}
} else if (assetType.equals("2")) { // Video
File assetDirectory = createAssetDirectory(showId, showname, data, assetID, assetType);
if (assetDirectory != null) {
if (!fileType.equals("Youtube")) { // via AddLink
File thumb = new File(assetDirectory.getAbsolutePath(), "/Thumb");
thumb.mkdirs();
// Thumbnail
File thumbFile = new File(thumb.getAbsolutePath(), "/Thumb." + getExtention(thumbUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Thumb File ath : " + thumbFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, thumbUrl, thumbFile.getAbsolutePath(), messenger);
File mp4url = new File(assetDirectory.getAbsolutePath(), "/Normal");
mp4url.mkdirs();
// mp4_Url
File mp4File = new File(mp4url.getAbsolutePath(), "/Normal." + getExtention(mp4Url));
if (Constants.DEBUG) {
Log.d(TAG, "Normal File path: " + mp4File.getAbsolutePath());
}
isDownloaded = doInBackground(this, mp4Url, mp4File.getAbsolutePath(), messenger);
} else if (Constants.DEBUG) {
Log.d(TAG, "Asset type is video but is Youtube link. So not proceeding for offline");
}
}
} else if (assetType.equals("3")) { // Audio
File assetDirectory = createAssetDirectory(showId, showname, data, assetID, assetType);
if (assetDirectory != null) {
File thumb = new File(assetDirectory.getAbsolutePath(), "/Thumb");
thumb.mkdirs();
// Thumbnail
File thumbFile = new File(thumb.getAbsolutePath(), "/Thumb." + getExtention(thumbUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Thumb File ath : " + thumbFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, thumbUrl, thumbFile.getAbsolutePath(), messenger);
File normal = new File(assetDirectory.getAbsolutePath(), "/Normal");
normal.mkdirs();
// Normal
File normalFile = new File(normal.getAbsolutePath(), "/Normal." + getExtention(normalUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Normal File path: " + normalFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, normalUrl, normalFile.getAbsolutePath(), messenger);
}
} else {
if (!assetType.equals("5")) {
File assetDirectory = createAssetDirectory(showId, showname, data, assetID, assetType);
if (assetDirectory != null) {
File thumb = new File(assetDirectory.getAbsolutePath(), "/Thumb");
thumb.mkdirs();
// Thumbnail
File thumbFile = new File(thumb.getAbsolutePath(), "/Thumb." + getExtention(thumbUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Thumb File ath : " + thumbFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, thumbUrl, thumbFile.getAbsolutePath(), messenger);
File normal = new File(assetDirectory.getAbsolutePath(), "/Normal");
normal.mkdirs();
// Normal
File normalFile = new File(normal.getAbsolutePath(), "/Normal." + getExtention(normalUrl));
if (Constants.DEBUG) {
Log.d(TAG, "Normal File path: " + normalFile.getAbsolutePath());
}
isDownloaded = doInBackground(this, normalUrl, normalFile.getAbsolutePath(), messenger);
} else { //"5" Link
if (Constants.DEBUG) {
Log.d(TAG, "This is Web Link");
}
isDownloaded = true;
}
}
}
}
}
private String getLoginFolders() {
// TODO Auto-generated method stub
File file = null;
int status = Constants.getSDCardStatus();
if (status == Constants.MOUNTED) {
File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"/SOTC_OFF/.nomedia");
f.mkdirs();
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"/SOTC_OFF/" + sotcPref.getString("domain", "") + "/" + sotcPref.getString("user_id", ""));
file.mkdirs();
}
return file.getAbsolutePath();
}
private File createAssetDirectory(String showid, String showname,
String data, String assetID, String assetType) {
// TODO Auto-generated method stub
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 10 " + "createAssetDirectory");
}
File file = null;
int status = Constants.getSDCardStatus();
if (status == Constants.MOUNTED) {
if (DownloadAssets.TOTAL_ASSET_COUNT != 0) {
/**
* From to concept here is to avoid duplication of new
* offline shows when show is updated. So, we are here
* renaming previous offline show's folder name with
* updated asset count.
*/
boolean isRenameSuccess = false;
File f = new File(getLoginFolders());
if (!f.exists()) {
f.mkdirs();
}
File[] fileArray = f.listFiles();
File f2 = new File(getLoginFolders(), "/"
+ showid.trim() + ","
+ showname.trim() + ","
+ data);
for (File from : fileArray) {
String s1 = from.getName().substring(0, from.getName().lastIndexOf(","));
if (Constants.DEBUG) {
Log.i(TAG, "s1: " + s1);
}
if (f2.getName().equalsIgnoreCase(s1)) {
//Rename
File to = new File(getLoginFolders(), "/"
+ showid.trim() + ","
+ showname.trim() + ","
+ data + ","
+ noofFiles);
if (Constants.DEBUG) {
Log.i(TAG, "from existence: " + from.exists());
}
try {
isRenameSuccess = from.renameTo(to);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (Constants.DEBUG) {
Log.i(TAG, "isRenameSuccess: " + isRenameSuccess);
}
break;
}
}
file = new File(getLoginFolders(), "/"
+ showid.trim() + ","
+ showname.trim() + ","
+ data + ","
+ noofFiles +
"/File_"
+ assetID + ","
+ assetType.trim());
}
if (file != null) {
if (!file.exists()) {
file.mkdirs();
}
}
}
return file;
}
public static String getExtention(String url) {
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
return extension;
}
#SuppressWarnings({"deprecation", "deprecation"})
boolean doInBackground(Context context, String urlPath, String destinationPath, Messenger messenger) {
boolean isDownloaded = false;
int lastPercent = 0;
File destination = new File(destinationPath);
if (!destination.exists()) {
if (chkConnectionStatus()) {
InputStream stream = null;
FileOutputStream fos = null;
try {
URL imageUrl = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
stream = conn.getInputStream();
int contentLength = conn.getContentLength();
if (Constants.DEBUG) {
Log.i(TAG, "contentLength : " + contentLength);
}
if (contentLength == 0) {
result = DownloadService.NO_FILE;
destination.delete();
isDownloaded = false;
Toast.makeText(getApplicationContext(), getResources().getString(R.string.Text_NoFile), 1000).show();
} else if (contentLength > availablestorageOnExternalDir()) {
//No Space Available
result = DownloadService.LOW_SPACE;
destination.delete();
isDownloaded = false;
Toast.makeText(getApplicationContext(), getResources().getString(R.string.Text_NoSpaceShow), 1000).show();
} else {
fos = new FileOutputStream(destination.getPath());
long total = 0l;
final int buffer_size = 4 * 1024;
try {
byte[] bytes = new byte[buffer_size];
for (; ; ) {
int count = stream.read(bytes, 0, buffer_size);
if (count == -1) {
break;
}
fos.write(bytes, 0, count);
total += count;
int percent = (int) ((total * 100) / contentLength);
if (percent > lastPercent) {
notification.contentView.setProgressBar(R.id.progressBar1, 100, percent, false);
lastPercent = percent;
}
}
if (destination.length() < contentLength) {
result = DownloadService.PARTIALLY_DOWNLOADED;
destination.delete();
isDownloaded = false;
} else {
if (Constants.DEBUG) {
Log.e(TAG, "Sucessful downloaded-------------------------------------------------" + i++);
}
// Sucessful finished
//i++;
result = Activity.RESULT_OK;
isDownloaded = true;
}
} catch (Exception ex) {
}
}
conn.disconnect();
Message msg = Message.obtain();
msg.arg1 = result;
msg.obj = destination.getAbsolutePath();
try {
messenger.send(msg);
} catch (android.os.RemoteException e1) {
if (Constants.DEBUG) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
if (Constants.DEBUG) {
Log.v(TAG, "Completed.............. ");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
/// no network connection
result = DownloadService.NETWORK_PROBLEM;
notification.setLatestEventInfo(context, "Please check your network connection", "", contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1, notification);
isDownloaded = true;
Message msg = Message.obtain();
msg.arg1 = result;
msg.obj = destination.getAbsolutePath();
try {
messenger.send(msg);
} catch (android.os.RemoteException e1) {
if (Constants.DEBUG) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
}
} else {
result = DownloadService.ASSERT_EXISIT;
Message msg = Message.obtain();
msg.arg1 = result;
msg.obj = destination.getAbsolutePath();
try {
messenger.send(msg);
} catch (android.os.RemoteException e1) {
if (Constants.DEBUG) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
isDownloaded = true;
}
return isDownloaded;
}
public long availablestorageOnExternalDir() //Get Available space(in Bytes)
{
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytesAvailable = (long) stat.getBlockSize() * (long) stat.getAvailableBlocks();
long megAvailable = bytesAvailable / (1024 * 1024);
if (Constants.DEBUG) {
Log.e("", "Available MB : " + megAvailable);
}
if (Constants.DEBUG) {
Log.e("", "Available Bytes : " + bytesAvailable);
}
return bytesAvailable;
}
public boolean chkConnectionStatus() {
final android.net.NetworkInfo wifi =
connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile =
connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifi.isAvailable()) {
if (wifi.isConnected()) {
return true;
}
return false;
} else if (mobile.isAvailable()) {
if (mobile.isConnected()) {
return true;
}
return false;
} else {
return false;
}
}
}
DownloadAssets.java
//To download
//files into
//created folders
public class DownloadAssets {
private static final String TAG = "DownloadAssets";
public static int TOTAL_ASSET_COUNT;
static synchronized ArrayList<HashMap<String, String>> hit(Context context, String url) {
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 9 " + "hit url" + url);
}
ArrayList<HashMap<String, String>> mList = new ArrayList<HashMap<String, String>>();
String message = null;
String result = null;
try {
result = Constants.queryRESTurl(url);
if (result != null) {
if (result.equals("timeout")) {
message = context.getResources().getString(R.string.Text_TimeOut);
} else {
JSONObject json = Constants.convertStringtoJsonObject(result);
try {
JSONObject results = json.getJSONObject(ThumbnailFragment.JSON_RESPONSE_ATTR_RESULTSET);
String totalAssetCount = results.getString(ThumbnailFragment.JSON_RESPONSE_ATTR_ASSET_COUNT);
TOTAL_ASSET_COUNT = Integer.parseInt(totalAssetCount);
if (Constants.DEBUG) {
Log.i("5" + TAG, "totalAssetCount : " + totalAssetCount);
}
if (TOTAL_ASSET_COUNT != 0) {
JSONArray assetData = results.getJSONArray(ThumbnailFragment.JSON_RESPONSE_ATTR_ASSET_ARRAY);
if (Constants.DEBUG) {
Log.i(TAG, "6Madhu " + assetData.toString());
}
int nObjects = assetData.length();
if (Constants.DEBUG) {
Log.i(TAG, "7Madhu " + nObjects);
}
if (nObjects != 0) {
for (int i = 0; i < nObjects; i++) {
HashMap<String, String> map = new HashMap<String, String>();
JSONObject e = assetData.getJSONObject(i);
map.put("id", "" + e.getString("assets_id"));
map.put("asset_name", "" + e.getString("asset_name"));
map.put("thumb_url", "" + e.getString("thumb_url"));
map.put("asset_type", "" + e.getString("asset_type"));
map.put("large_url", "" + e.getString("large_url"));
map.put("mp4_url", "" + e.getString("mp4_url"));
map.put("normal_url", "" + e.getString("normal_url"));
map.put("description", "" + e.getString("description"));
map.put("filetype", "" + e.getString("filetype"));
map.put("filename", "" + e.getString("original_filename"));
map.put("filesize", "" + e.getString("filesize"));
mList.add(map);
if (Constants.DEBUG) {
Log.i(TAG, "Size in Loop " + mList.size());
}
}
} else if (Constants.DEBUG) {
Log.i(TAG, "EXECUTING ELSE nObjects");
}
} else if (Constants.DEBUG) {
Log.i(TAG, "EXECUTING ELSE count");
}
} catch (JSONException e) {
if (Constants.DEBUG) {
Log.e("8log_tag", "Error parsing data " + e.toString());
}
message = context.getResources().getString(R.string.Text_InvalidResponse);
} catch (Exception e) {
if (Constants.DEBUG) {
Log.e("8log_tag", "Error parsing data " + e.toString());
}
message = context.getResources().getString(R.string.Text_InvalidResponse);
e.printStackTrace();
}
}
} else {
if (Constants.DEBUG) {
Log.i(TAG, "EXECUTING ELSE result");
}
message = context.getResources().getString(R.string.Text_InvalidResponse);
}
} catch (Exception e) {
// TODO Auto-generated catch block
message = context.getResources().getString(R.string.Text_ServerProblem);
e.printStackTrace();
}
if (Constants.DEBUG) {
Log.e(TAG, "Message : " + message);
}
if (Constants.DEBUG) {
Log.d(TAG, "Offline step 9 End " + "hit return " + mList);
}
return mList;
}
}
My queries are
Files are downloading but not all files at first time from server.If I download more folders for example Folder1,Folder2 then Folder3, Folder1 and Folder2 interrupted(i.e 1 file is downloaded) but Folder3 downloaded fully...
How can I keep the queue of files/folders to be downloaded? !
For speed up and maintaining the queue of intent follow the below approach
protected void onHandleIntent(Intent intent) {
synchronized (intent) {
final Intent intentCpy=intent;
new Thread(new Runnable() {
#Override
public void run() {
//onHandleIntent code which is in question post
}
}
}
Use ConcurrentHashMap for Thread-Safty in following method
private synchronized void downloadSetofAssets(int OFFSET , int LIMIT , String url)
for more details about ConcurrentHashMap please visit
http://www.cs.umd.edu/class/spring2013/cmsc433/Notes/14-CMSC433-ConcurrentCollections.pdf

Categories

Resources