improve panorama video handling at third party intents

This commit is contained in:
tibbi 2019-01-02 23:56:09 +01:00
parent dd69bbea68
commit af3cfc46bf
3 changed files with 88 additions and 65 deletions

View file

@ -27,6 +27,7 @@ import com.simplemobiletools.gallery.pro.models.Medium
import kotlinx.android.synthetic.main.bottom_actions.* import kotlinx.android.synthetic.main.bottom_actions.*
import kotlinx.android.synthetic.main.fragment_holder.* import kotlinx.android.synthetic.main.fragment_holder.*
import java.io.File import java.io.File
import java.io.FileInputStream
open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentListener { open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentListener {
@ -147,11 +148,31 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
return return
} }
var isPanorama = false
val realPath = intent?.extras?.getString(REAL_FILE_PATH) ?: ""
try {
if (realPath.isNotEmpty()) {
val fis = FileInputStream(File(realPath))
parseFileChannel(realPath, fis.channel, 0, 0, 0) {
isPanorama = true
}
}
} catch (ignored: Exception) {
} catch (ignored: OutOfMemoryError) {
}
if (isPanorama) {
Intent(applicationContext, PanoramaVideoActivity::class.java).apply {
putExtra(PATH, realPath)
startActivity(this)
}
} else {
val mimeType = getUriMimeType(mUri.toString(), newUri) val mimeType = getUriMimeType(mUri.toString(), newUri)
Intent(this, VideoPlayerActivity::class.java).apply { Intent(applicationContext, VideoPlayerActivity::class.java).apply {
setDataAndType(newUri, mimeType) setDataAndType(newUri, mimeType)
startActivity(this) startActivity(this)
} }
}
finish() finish()
} }

View file

@ -35,6 +35,9 @@ import com.simplemobiletools.gallery.pro.svg.SvgSoftwareLayerSetter
import com.simplemobiletools.gallery.pro.views.MySquareImageView import com.simplemobiletools.gallery.pro.views.MySquareImageView
import pl.droidsonroids.gif.GifDrawable import pl.droidsonroids.gif.GifDrawable
import java.io.File import java.io.File
import java.io.FileInputStream
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.util.HashSet import java.util.HashSet
import java.util.LinkedHashSet import java.util.LinkedHashSet
import kotlin.Comparator import kotlin.Comparator
@ -623,3 +626,60 @@ fun Context.updateWidgets() {
} }
} }
} }
// based on https://github.com/sannies/mp4parser/blob/master/examples/src/main/java/com/google/code/mp4parser/example/PrintStructure.java
fun Context.parseFileChannel(path: String, fc: FileChannel, level: Int, start: Long, end: Long, callback: () -> Unit) {
val FILE_CHANNEL_CONTAINERS = arrayListOf("moov", "trak", "mdia", "minf", "udta", "stbl")
try {
var iteration = 0
var currEnd = end
fc.position(start)
if (currEnd <= 0) {
currEnd = start + fc.size()
}
while (currEnd - fc.position() > 8) {
// just a check to avoid deadloop at some videos
if (iteration++ > 50) {
return
}
val begin = fc.position()
val byteBuffer = ByteBuffer.allocate(8)
fc.read(byteBuffer)
byteBuffer.rewind()
val size = IsoTypeReader.readUInt32(byteBuffer)
val type = IsoTypeReader.read4cc(byteBuffer)
val newEnd = begin + size
if (type == "uuid") {
val fis = FileInputStream(File(path))
fis.skip(begin)
val sb = StringBuilder()
val buffer = ByteArray(1024)
while (true) {
val n = fis.read(buffer)
if (n != -1) {
sb.append(String(buffer, 0, n))
} else {
break
}
}
val xmlString = sb.toString().toLowerCase()
if (xmlString.contains("gspherical:projectiontype>equirectangular") || xmlString.contains("gspherical:projectiontype=\"equirectangular\"")) {
callback.invoke()
}
return
}
if (FILE_CHANNEL_CONTAINERS.contains(type)) {
parseFileChannel(path, fc, level + 1, begin + 8, newEnd, callback)
}
fc.position(newEnd)
}
} catch (ignored: Exception) {
}
}

View file

@ -11,7 +11,6 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
import com.simplemobiletools.gallery.pro.activities.PanoramaVideoActivity import com.simplemobiletools.gallery.pro.activities.PanoramaVideoActivity
import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.extensions.*
import com.simplemobiletools.gallery.pro.helpers.IsoTypeReader
import com.simplemobiletools.gallery.pro.helpers.MEDIUM import com.simplemobiletools.gallery.pro.helpers.MEDIUM
import com.simplemobiletools.gallery.pro.helpers.PATH import com.simplemobiletools.gallery.pro.helpers.PATH
import com.simplemobiletools.gallery.pro.models.Medium import com.simplemobiletools.gallery.pro.models.Medium
@ -19,12 +18,8 @@ import com.simplemobiletools.gallery.pro.views.MediaSideScroll
import kotlinx.android.synthetic.main.pager_video_item.view.* import kotlinx.android.synthetic.main.pager_video_item.view.*
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
class VideoFragment : ViewPagerFragment() { class VideoFragment : ViewPagerFragment() {
private val FILE_CHANNEL_CONTAINERS = arrayListOf("moov", "trak", "mdia", "minf", "udta", "stbl")
private var mIsFullscreen = false private var mIsFullscreen = false
private var mWasFragmentInit = false private var mWasFragmentInit = false
private var mIsPanorama = false private var mIsPanorama = false
@ -168,67 +163,14 @@ class VideoFragment : ViewPagerFragment() {
private fun checkIfPanorama() { private fun checkIfPanorama() {
try { try {
val fis = FileInputStream(File(medium.path)) val fis = FileInputStream(File(medium.path))
parseFileChannel(fis.channel, 0, 0, 0) context!!.parseFileChannel(medium.path, fis.channel, 0, 0, 0) {
mIsPanorama = true
}
} catch (ignored: Exception) { } catch (ignored: Exception) {
} catch (ignored: OutOfMemoryError) { } catch (ignored: OutOfMemoryError) {
} }
} }
// based on https://github.com/sannies/mp4parser/blob/master/examples/src/main/java/com/google/code/mp4parser/example/PrintStructure.java
private fun parseFileChannel(fc: FileChannel, level: Int, start: Long, end: Long) {
try {
var iteration = 0
var currEnd = end
fc.position(start)
if (currEnd <= 0) {
currEnd = start + fc.size()
}
while (currEnd - fc.position() > 8) {
// just a check to avoid deadloop at some videos
if (iteration++ > 50) {
return
}
val begin = fc.position()
val byteBuffer = ByteBuffer.allocate(8)
fc.read(byteBuffer)
byteBuffer.rewind()
val size = IsoTypeReader.readUInt32(byteBuffer)
val type = IsoTypeReader.read4cc(byteBuffer)
val newEnd = begin + size
if (type == "uuid") {
val fis = FileInputStream(File(medium.path))
fis.skip(begin)
val sb = StringBuilder()
val buffer = ByteArray(1024)
while (true) {
val n = fis.read(buffer)
if (n != -1) {
sb.append(String(buffer, 0, n))
} else {
break
}
}
val xmlString = sb.toString().toLowerCase()
mIsPanorama = xmlString.contains("gspherical:projectiontype>equirectangular") ||
xmlString.contains("gspherical:projectiontype=\"equirectangular\"")
return
}
if (FILE_CHANNEL_CONTAINERS.contains(type)) {
parseFileChannel(fc, level + 1, begin + 8, newEnd)
}
fc.position(newEnd)
}
} catch (ignored: Exception) {
}
}
private fun openPanorama() { private fun openPanorama() {
Intent(context, PanoramaVideoActivity::class.java).apply { Intent(context, PanoramaVideoActivity::class.java).apply {
putExtra(PATH, medium.path) putExtra(PATH, medium.path)