In this tutorial, we’ll look at how to retrieve a video stream from Motion with a React Native application.
Project configuration
We’ve set up a video stream with Motion on a Linux machine with address 192.168.1.92:8554 on the Wifi network.
The Motion program serves the video streams as an HTML page using the HTTP protocol. To retrieve this page, we use the react-native-webview library, which can display complete web pages in an application.
To install the library, enter the following command
npm install --save react-native-webview
Using WebView
To use the WebView component, simply import the
import {WebView} from 'react-native-webview'
and call the component in the App functional component renderer, specifying the video source
<View style={{flex: 1 }}> <WebView source={{uri: "http://192.168.1.92:8554/"}} style={styles.webVideo} /> </View>
With the following style sheet
var styles = StyleSheet.create({ webVideo: { position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, }, });
To take this a step further, we’ve created a textInput insert that allows us to update the stream url (or web page) with ipAddress and ipServer states.
Details can be found in the full code.
The video is displayed with a delay of less than 3 seconds and a quality that is not very fluid.
Full code for the React Native application to play a Motion video stream
In the following code we define textInput, which will enable us to update the value of ipAddress (stored ip value) and, when the button is pressed, update the url read by the WebView component (ipServer)
We’ve also added a real-time date and time display (currentDate) to evaluate the delay in receiving the video stream. We’ve commented on this function because it refreshes the application every second.
/** * https://github.com/react-native-webview/react-native-webview */ import React, { useEffect, useState } from 'react' import { Text, View, StyleSheet, TextInput, TouchableOpacity } from 'react-native' import {WebView} from 'react-native-webview' const App = () => { const videoRef = React.createRef(); const [ipAddress, setIpAddress] = useState("http://192.168.1.92:8554/"); const [ipServer, setIpServer] = useState("http://192.168.1.92:8554/"); //const [currentDate, setCurrentDate] = useState(''); useEffect(() => { /*setInterval(() => { var date = new Date().getDate(); //Current Date var month = new Date().getMonth() + 1; //Current Month var year = new Date().getFullYear(); //Current Year var hours = new Date().getHours(); //Current Hours var min = new Date().getMinutes(); //Current Minutes var sec = new Date().getSeconds(); //Current Seconds setCurrentDate( date + '/' + month + '/' + year + ' ' + hours + ':' + min + ':' + sec ); }, 1000)*/ }, []); console.log("rendering..."); return ( <View style={{ flexGrow: 1, flex: 1 }}> <Text style={styles.mainTitle}>AC Video Player</Text> <View style={styles.inputBar}> <TextInput style={styles.textInput} placeholder="Enter a message" value={ipAddress} onChangeText={(text) => setIpAddress(text) } /> <TouchableOpacity onPress={() => { setIpServer(""); //force state change thus rendering setIpServer(ipAddress);} } style={[styles.sendButton]}> <Text style={styles.buttonText}> SEND </Text> </TouchableOpacity> </View> <View style={{flex: 1 }}> <WebView source={{uri: ipServer}} style={styles.webVideo} /> </View> {/*<Text style={{textAlign: 'right'}}>{currentDate}</Text>*/} </View> ) } export default App; let BACKGROUND_COLOR = "#161616"; //191A19 let BUTTON_COLOR = "#346751"; //1E5128 let ERROR_COLOR = "#C84B31"; //4E9F3D let TEXT_COLOR = "#ECDBBA"; //D8E9A8 var styles = StyleSheet.create({ mainTitle:{ color: TEXT_COLOR, fontSize: 30, textAlign: 'center', borderBottomWidth: 2, borderBottomColor: ERROR_COLOR, }, webVideo: { position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, }, buttonText: { color: TEXT_COLOR, fontWeight: 'bold', fontSize: 12, textAlign: 'center', textAlignVertical: 'center', }, sendButton: { backgroundColor: BUTTON_COLOR, padding: 15, borderRadius: 15, margin: 2, paddingHorizontal: 20, }, inputBar:{ flexDirection: 'row', justifyContent: 'space-between', margin: 5, }, textInput:{ backgroundColor: '#888888', margin: 2, borderRadius: 15, flex:3, }, });