I have encrypted a video file using base64 encoding format and AES-encryption. I decrypt data stream-by-stream and append/write each stream (as a .mp4 file) to achieve the final video but it takes a lot of time to achieve a final output.
Major Edit:
I have found resources html5-media-and-data-uri which helps to play data in a webview
, but it doesn't play videos with 2,000,000+ base64 characters.
Function to decrypt a file and initialize HTML code within web view with base64 data
decryptfile() {
RNFetchBlob.fs
.readStream(
RNFetchBlob.fs.dirs.DCIMDir + "/encryptfile1.dat",
"base64",
2796256, //character to be read at a time for decryption
2500 // Time taken before each stream enters for decryption
)
.then(stream => {
let data = "";
stream.open();
stream.onData(chunk => {
var decipherText = simpleCrypto.decrypt(chunk.toString()); // Decryption
decryptText = decryptText + decipherText; // appending decrypted data
});
stream.onEnd(() => {
htmlCode =
`<html>
<body>
<video style="width: 50%; height: 50%; margin-top: 10%; margin-left: 22%;"
controls>
<source type="video/mp4" src="data:video/mp4;base64,` +
decryptText.toString() + // final decrypted data
`">
</video>
</body>
</html>`;
this.setState({ playvideo: !this.state.playvideo }); // state set for playing video at end of decryption
console.log("File decrypted");
});
});
}
Web View Code
<WebView
style={{ flex: 1 }}
source={{ html: htmlCode }}
/>
Need help in finding ways/alternatives to play videos from base64 in react-native.
This is an Offline e-learning app where videos are stored on SD-CARD and data is decrypted on the fly and played in a video player.
It's possible to solve it by making your WebView embedded javascript code to read the file content from the device storage, in order to avoid having this large base64 literal inline.
As described here, the recommended workaround is to use a blob URL.
Basically you have to:
RNFetchBlob
and simpleCrypto
inside the WebView. (see here)<video>
src attribute.Your code is going to look something like this:
componentDidMount() {
this.setState({htmlCode: `
<html>
<body>
<video id="myvideo" style="width: 50%; height: 50%; margin-top: 10%; margin-left: 22%;" controls></video>
<script src="${RNFetchBlob.fs.dirs.MainBundleDir}/bundle.js"></script>
<script src="${path/to/simpleCrypto.js}"></script>
<script type="text/javascript">
function b64toBlob(b64Data, contentType, sliceSize) {
//... returns a new Blob using the b64Data.
}
//for simplicity, onDecodeEnd abstracts your decryption code
RNFetchBlob.fs.readStream('encryptfile1.dat').onDecodeEnd((decryptText) => {
var blob = b64toBlob(base64Video, "video/mp4");
var url = URL.createObjectURL(blob);
document.getElementById('myvideo').src = url;
})
</script>
</body>
</html>
`})
render() {
return (
<WebView
style={{ flex: 1 }}
source={{ html: this.state.htmlCode, baseUrl: RNFetchBlob.fs.dirs.DCIMDir }}>
</WebView>
);
}
Disclaimer
Additional Code
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
PS
I myself wouldn't go for this base64 approach. I would rather have some native code, triggered from React Native, that would write and read encrypted videos. The read would generate a temp.mp4 to be loaded from the react-native-video
module. Under the hoods, encryption is done at the bytes level. So we don't need to parse it back and forth to base64. We're dealing with binary files after all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With