React-Native录制视频并通过Nginx RTMP模块上传至后端存储的方案问询
I’ve worked on similar setups before, so let’s walk through the step-by-step solution tailored to your tech stack:
1. Configure Nginx with the RTMP Module
First, make sure your Nginx instance has the RTMP module compiled (most pre-built packages include it; if not, compile Nginx with --with-rtmp-module). Add this configuration to your nginx.conf:
rtmp { server { listen 1935; # Default RTMP port chunk_size 4096; application live { live on; record all; # Auto-record all incoming streams record_path /var/www/recorded-videos; # Local storage path for recordings record_format flv; # Use mp4 if you prefer that format record_unique on; # Generate unique filenames to avoid overwrites # Trigger your Express backend when a recording finishes on_record_done http://your-express-server/api/video/record-complete; } } } # Add an HTTP block to serve recorded videos publicly (optional but useful) http { # ... your existing HTTP config ... server { listen 80; location /videos { alias /var/www/recorded-videos; autoindex on; # Optional, for browsing stored files } } }
This setup accepts RTMP streams at rtmp://your-nginx-server/live/<your-stream-key> and saves recordings automatically. The on_record_done hook lets your backend know when a recording is ready to be tracked in MongoDB.
2. React Native Video Recording & RTMP Streaming
For the React Native side, use a library that handles video capture and RTMP streaming. react-native-rtmp-stream is a reliable choice. Here’s a simplified implementation with Redux integration:
First, install the library and set up permissions:
npm install react-native-rtmp-stream --save
- For iOS: Add
NSCameraUsageDescriptionandNSMicrophoneUsageDescriptionto yourInfo.plist. - For Android: Add
<uses-permission android:name="android.permission.CAMERA" />and<uses-permission android:name="android.permission.RECORD_AUDIO" />toAndroidManifest.xml.
Then build your recorder component:
import React, { useRef } from 'react'; import { View, Button, Text } from 'react-native'; import { RtmpStream } from 'react-native-rtmp-stream'; import { useDispatch, useSelector } from 'react-redux'; import { startRecording, stopRecording, setRecordingError } from '../redux/actions/recordingActions'; const VideoRecorder = () => { const streamRef = useRef(null); const dispatch = useDispatch(); const { isRecording, error } = useSelector(state => state.recording); const startStream = async () => { try { // Use a unique stream key (generate one per user/recording session) await streamRef.current.startStream('rtmp://your-nginx-server/live/user-123-session-456'); dispatch(startRecording()); } catch (err) { dispatch(setRecordingError(err.message)); } }; const stopStream = async () => { try { await streamRef.current.stopStream(); dispatch(stopRecording()); } catch (err) { dispatch(setRecordingError(err.message)); } }; return ( <View> <RtmpStream ref={streamRef} style={{ width: '100%', height: 400 }} camera={1} // 1 for front camera, 0 for back audio={true} video={true} /> {error && <Text style={{ color: 'red' }}>{error}</Text>} <Button title={isRecording ? 'Stop Recording' : 'Start Recording'} onPress={isRecording ? stopStream : startStream} /> </View> ); }; export default VideoRecorder;
3. Integrate with Node.js/Express & MongoDB
When Nginx finishes a recording, it sends a POST request to your Express endpoint. Use this to store recording metadata in MongoDB:
First, create a Mongoose model:
// models/VideoRecord.js const mongoose = require('mongoose'); const videoRecordSchema = new mongoose.Schema({ streamKey: { type: String, required: true }, filePath: { type: String, required: true }, fileName: { type: String, required: true }, duration: { type: Number }, // Parsed from Nginx's payload createdAt: { type: Date, default: Date.now } }); module.exports = mongoose.model('VideoRecord', videoRecordSchema);
Then create the Express endpoint:
// routes/videoRoutes.js const express = require('express'); const router = express.Router(); const VideoRecord = require('../models/VideoRecord'); router.post('/api/video/record-complete', async (req, res) => { try { // Nginx sends data like: name, path, duration, etc. const { name, path, duration } = req.body; const streamKey = name.split('/')[1]; // Extract stream key from filename const newRecord = new VideoRecord({ streamKey, filePath: path, fileName: name, duration: parseInt(duration) }); await newRecord.save(); res.status(200).send('Record saved successfully'); } catch (err) { console.error('Error saving video record:', err); res.status(500).send('Internal server error'); } }); module.exports = router;
Don’t forget to mount this route in your Express app and connect to MongoDB as usual.
4. Redux State Management
Set up Redux to track recording state across your app:
// redux/actions/recordingActions.js export const START_RECORDING = 'START_RECORDING'; export const STOP_RECORDING = 'STOP_RECORDING'; export const SET_RECORDING_ERROR = 'SET_RECORDING_ERROR'; export const startRecording = () => ({ type: START_RECORDING }); export const stopRecording = () => ({ type: STOP_RECORDING }); export const setRecordingError = (error) => ({ type: SET_RECORDING_ERROR, payload: error }); // redux/reducers/recordingReducer.js import { START_RECORDING, STOP_RECORDING, SET_RECORDING_ERROR } from '../actions/recordingActions'; const initialState = { isRecording: false, error: null }; const recordingReducer = (state = initialState, action) => { switch (action.type) { case START_RECORDING: return { ...state, isRecording: true, error: null }; case STOP_RECORDING: return { ...state, isRecording: false }; case SET_RECORDING_ERROR: return { ...state, error: action.payload }; default: return state; } }; export default recordingReducer;
Combine this reducer with your existing store setup, and you’re ready to go.
Key Tips for Production
- Network Stability: Add logic to handle disconnections (auto-retry, user notifications) since RTMP relies on stable internet.
- Security: Use Nginx’s
on_publishhook to validate stream keys against your backend before allowing streams to start. - Scalability: If local storage isn’t enough, modify the Express endpoint to upload recordings to cloud storage (like S3) and update MongoDB with the cloud URL.
- Format Conversion: Use
ffmpegto convert FLV to MP4 (trigger this via your Express backend after recording finishes).
内容的提问来源于stack exchange,提问作者Jor Khachatryan

