How to change the resolution of a video (React-Native) - react-native

Basically title, i'm trying to change the resolution of the videos because they are too heavy, i'm using react-native-video to display the videos and i saw that it has a selectedVideoTrack which can be used to change it but it is not working for me. could i be using it wrong?
<Video
selectedVideoTrack={{
type: "resolution",
value: 240
}}
resizeMode = "stretch"
source={{ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4' }}
style={{ width: 300, height: 300 }}
controls={true}
ref={(ref) => {
this.player = ref
}} />

Related

How to make expo-av video to take needed inside a flatlist?

I am developing an instagram-like app where I needed to render images/videos. I am using flatlist to prevent memory lost, and using expo-av package to render the video.
Here is a screenshot of what I want to achieve:
So my goal here is to render videos with original ratio.
However, I am struggling to render the flatlist that contains the videos, it just doesn't render the component at all but I can still hear the video playing.
This is my FlatList:
<FlatList
style={{ width: "100%", height: "100%", backgroundColor: "yellow" }}
data={[0, 1, 2, 3, 4]}
keyExtractor={item => item}
renderItem={renderItem}
/>
And my renderItem callback:
const renderItem = ({ item }) => {
return <Post post={item} />;
}
Post item code:
export default ({ post }) => {
const videoRef = useRef(null);
const [status, setStatus] = useState({});
return (
<View style={{ width: "100%", height: "100%", backgroundColor: "blue" }}>
<Video
ref={videoRef}
source={{
uri: 'http://commondatastorage.googleapis.com/gtv-videosbucket/sample/VolkswagenGTIReview.mp4',
}}
style={{ width: "100%", height: "100%", backgroundColor: "blue" }}
resizeMode="contain"
autoplay
isLooping
shouldPlay={true}
onPlaybackStatusUpdate={status => setStatus(() => status)}
/>
</View>
);
}
Result (yellow background: flatlist area, post item should appear blue but not showing up):
The video would display if I give it a static width and height instead of values like 100%, but since I needed the renderItem to look original and take as much space as needed across all kinds of devices, so the only thing I could think of is a percentage.
If there is a way to know the aspect ratio or the width and height of the video, I can do dynamic calculations to achieve my goal, but I don't know if expo-av provide this information~
The renderItem would automatically take the max width inside a FlatList, but the height is default 0.
I figured that we can pass the video's natural aspect ratio to the style property so that it renders itself naturally with max size.
To get the video's natural aspect ratio, we have to define a function for the video's onReadyForDisplay property, it provides information of the video once the first frame is loaded.
To do that, we set the default ratio to the screen ratio:
import { Dimensions } from "react-native";
const defaultScreenRatio = Dimensions.get("window").width / Dimensions.get("window").height;
And then inside the component:
// Use the screenDefaultRatio to render the video before the video is loaded
const [videoRatio, setVideoRatio] = useState(screenDefaultRatio);
// Update the videoRatio right after we know the video natural size
const updateVideoRatioOnDisplay = (videoDetails) => {
const { width, height } = videoDetails.naturalSize;
const newVideoRatio = width / height;
setVideoRatio(newVideoRatio);
}
Code for Video item:
<View>
<Video
ref={videoRef}
source={{
uri: 'http://commondatastorage.googleapis.com/gtv-videosbucket/sample/VolkswagenGTIReview.mp4',
}}
style={{ aspectRatio: videoRatio, backgroundColor: "blue" }}
resizeMode="contain"
autoplay
isLooping
shouldPlay={true}
onPlaybackStatusUpdate={status => setStatus(() => status)}
// Update the video Ratio once done loading the first frame of the video
onReadyForDisplay={updateVideoRatioOnDisplay}
/>
</View>
So, I don't know how to make it dynamic to rach video, but you just can't have percentages for height and width

How to fit video poster to video player height in expo react native video player

I'm using https://github.com/ihmpavel/expo-video-player this library to add video player in react native app and setting poster image to video player. as shown below:
<VideoPlayer
videoProps={{
resizeMode: Video.RESIZE_MODE_CONTAIN,
source: {
uri: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
},
usePoster: true,
posterSource: {
uri: props.thumbnail,
},
posterStyle: {
width: FULL_WIDTH - 35,
height: FULL_WIDTH - 35,
},
}}
style={{
width: FULL_WIDTH - 35,
height: FULL_WIDTH - 35,
}}
defaultControlsVisible
/>
poster is displayed as below:
output
How to fit poster image in video player exactly?
Expo video doesn't support resizeMode for posterSource so you can show an overlay while video is being loaded.
const [status, setStatus] = React.useState({});
const imageHeight = FULL_WIDTH - 35;
const renderPoster = () => {
if(status.isLoaded){
return null;
}
return (
<ImageBackground source={{uri: props.imageUrl}} style={{height:imageHeight, zIndex:99999}} resizeMode="cover"/>
)
}
<Video
ref={video}
source={{
uri: props.videoUrl,
}}
style={{ zIndex: -1, height: imageHeight }}
resizeMode={"cover"}
shouldPlay={true}
isLooping
useNativeControls
onPlaybackStatusUpdate={status => setStatus(() => status)}
>
{renderPoster()}
</Video>

React Native how to fetch data video link from local json file on react native

I prepared an application, I need to get the video links from the data file. What can I do for that.
source={{ ? }} and How do I project 4 videos to the screen using flatlist? Thank you
export const data = [
{
id: 1,
name: "Video1",
video: "http://example.com/video1.mp4" -> ***how do i do this***
},
{
id: 2,
name: "Video2",
video: "http://example.com/video2.mp4" -> ***how do i do this***
},
{
id: 3,
name: "Video3",
video: "http://example.com/video3.mp4" -> ***how do i do this***
},
];
return (
<View style={styles.container}>
<Video
ref={video}
style={{ alignSelf: "center", width: 320, height: 200 }}
source={{ ? }}
useNativeControls
resizeMode="contain"
isLooping
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>
Example Image:
I want to have a video code like the code written here :)
export const data = [
{
id: 1,
name: "image1",
image: "../assets/image/sun.png"
},
];
import data from './data';
function App() {
return (
<View>
<Image source={data.image}/>
</View)
}
You could use the JavaScript FETCH Api. It is like Jquery but better (I think). It is very easy to fetch a video with this. If you're using a functional component you can use useEffect() to fetch the video when the App is loading (loaded)
Here is an example
fetch('http://example.com/yourvideo.mp4')
.then(response => response.json())
.then(data => doSomething());
Now you fetched the video :)
if you put your json file in android's asset and iOS resource, you can use this package to read the file content https://www.npmjs.com/package/react-native-file-asset
return (
<View style={styles.container}>
<Video
ref={video}
style={{ alignSelf: "center", width: 320, height: 200 }}
source={{ uri: data?.video }}
useNativeControls
resizeMode="contain"
isLooping
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>

is there any way to learn uri has no image react-native

I am developing a e-commerce app and some products does not have pictures and because of that sometimes ımage components looks empty. It looks bad. (To get pictures i am using uri.)
My question is how can i know if there isn't a picture on that uri?
<FastImage
source={{
uri: photoUri,
priority: FastImage.priority.high,
}}
style={styles.logo}
/>
You can try react-native-elements, it will show PlaceholderImage when uri error
import { Image as ImageElement } from 'react-native-elements'
import { Image } from 'react-native'
<ImageElement
style={{ width: 100, height: 100 }}
source={{ uri: reduceImageSize(item.image, width) }}
PlaceholderContent={(
<Image source={require('image-placeholder.png')} style={{ width: 100, height: 100 }} />
)}
/>

How to resize react native webview content?

This is my code, I'm trying to load a stream from my IP camera.
<View style={{flex:1,marginTop:70, flexDirection:'column', justifyContent:'space-between'}}>
<Hue/>
<View style={{flex:1}}>
<WebView
source={{uri: 'http://192.168.2.6:81/videostream.cgi?user=admin&pwd=XXXXX'}}
style={{/*marginTop: 20, flex: 1, width:450, height:100*/}}
javaScriptEnabled={false}
domStorageEnabled={false}
startInLoadingState={false}
scalesPageToFit={false}
scrollEnabled={true}
/>
</View>
<Text>Just some text</Text>
</View>
<Hue/> is a component to check if the WebView is still loading (because in a normal case, it won't load if it's not the only component).
The width property have an ambiguous behavior: reducing it increase the height of the webview. Leaving an empty scrolling space.
Moreover, modifying the height of the webview component does nothing at all.
I tried to modify the parent view applying height and width with no luck.
Also, I did not find any props to modify the webview content itself.
Is there any way, or a react-native component that can help me to integrate my IP camera stream in my application ?
Any suggestion is very appreciated.
EDIT
Updated the code according to Ashwin's comment and I still get this :
EDIT 2
I updated my code according to sfratini answer but if I set the scroll enabled and then scroll, I'm able so see that there is always a part of the image not displayed. Seems that react does not understand to resize to 100%.. It's strange...
<WebView
source={{
uri: this.props.url
}}
style={{ height: height, width, resizeMode: 'cover', flex: 1 }}
injectedJavaScript={`const meta = document.createElement('meta'); meta.setAttribute('content', 'width=width, initial-scale=0.5, maximum-scale=0.5, user-scalable=2.0'); meta.setAttribute('name', 'viewport'); document.getElementsByTagName('head')[0].appendChild(meta); `}
scalesPageToFit={false}
onLoadEnd={this._onLoadEnd}
/>
Managed to get the same behavior for ios and Android. Thanks Gowtham Palanisamy.
<WebView
source={{ uri: url }}
style={{ flex: 1 }}
injectedJavaScript={`
const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
if (!iOS) {
const meta = document.createElement('meta');
let initialScale = 1;
if(screen.width <= 800) {
initialScale = ((screen.width / window.innerWidth) + 0.1).toFixed(2);
}
const content = 'width=device-width, initial-scale=' + initialScale ;
meta.setAttribute('name', 'viewport');
meta.setAttribute('content', content);
document.getElementsByTagName('head')[0].appendChild(meta);
}
`}
scalesPageToFit={Platform.OS === 'ios'}
/>
just a note that webview has standard style and also containerStyle see documentation. standard style i believe has background: white, and containerStyle has flex: 1.
To make an image responsive, i made my code like this (iframeWidth is just window width dimension minus some padding):
if (node.name === 'img') {
const imgHeight = Number(node.attribs.height);
const imgAlt = node.attribs.alt;
const imgSource = node.attribs.src;
const imageHtml = `<img src="${imgSource}" height="${
imgHeight * 2.3
}" alt="${imgAlt}" />`;
return (
<WebView
key={index}
source={{ html: imageHtml }}
startInLoadingState
scalesPageToFit
allowsInlineMediaPlayback
domStorageEnabled
style={{ backgroundColor: 'transparent' }}
containerStyle={[{ flex: 0, width: iFrameWidth, height: imgHeight }]}
/>
);
}
Hope this helps to someone!
Using Gowtham Palanisamy's approach, set the source content as an html input and set its viewport to render content inside parent container.
<View>
<WebView
javaScriptEnabled={false}
domStorageEnabled={false}
startInLoadingState={false}
scalesPageToFit={false}
scrollEnabled={true}
source={{
html: `
<head>
<meta content="width=width, initial-scale=1, maximum-scale=1" name="viewport"></meta>
</head>
<body style="background-image: url('${this.props.source}'); background-size:cover;"></body>
`,
}}
/>
</View>
This is is more better and accurate
style={{ height: 350, width: '100%', resizeMode: 'cover', flex: 1 }}
injectedJavaScript={`const meta = document.createElement('meta'); meta.setAttribute('content', 'width=width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); meta.setAttribute('name', 'viewport'); document.getElementsByTagName('head')[0].appendChild(meta); `}
scalesPageToFit={true}
I believe you want this:
<WebView
source={this.props.source}
style={{
width: '100%',
height: 300
}}
scrollEnabled={false}
/>;