improve panorama video handling at third party intents
This commit is contained in:
parent
dd69bbea68
commit
af3cfc46bf
3 changed files with 88 additions and 65 deletions
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue