实现rtsp服务

master
Matthew 3 months ago
parent 98d5e96650
commit 55ffc1c8dc

@ -139,7 +139,11 @@ void TcpClient::onSockConnect(const SockException &ex) {
std::string TcpClient::getIdentifier() const {
if (_id.empty()) {
static atomic<uint64_t> s_index { 0 };
#ifndef DISABLE_RTTI
_id = toolkit::demangle(typeid(*this).name()) + "-" + to_string(++s_index);
#else
_id = toolkit::demangle("TcpClient") + "-" + to_string(++s_index);
#endif
}
return _id;
}

@ -146,7 +146,9 @@ public:
try {
CLASS_FUNC_INVOKE(C, *ptr, Destory);
} catch (std::exception &ex){
#ifndef DISABLE_RTTI
onDestoryException(typeid(C), ex);
#endif
}
delete ptr;
});
@ -172,7 +174,9 @@ public:
try {
CLASS_FUNC_INVOKE(C, *ptr, Destory);
} catch (std::exception &ex){
#ifndef DISABLE_RTTI
onDestoryException(typeid(C), ex);
#endif
}
delete ptr;
});
@ -455,7 +459,11 @@ public:
throw std::invalid_argument("Any is empty");
}
if (safe && !is<T>()) {
#ifndef DISABLE_RTTI
throw std::invalid_argument("Any::get(): " + demangle(_type->name()) + " unable cast to " + demangle(typeid(T).name()));
#else
throw std::invalid_argument("Any::get(): " + demangle(_type->name()) + " unable cast");
#endif
}
return *((T *)_data.get());
}

@ -226,7 +226,11 @@ toolkit::EventPoller::Ptr MediaSource::getOwnerPoller() {
if (listener) {
return listener->getOwnerPoller(*this);
}
#ifndef DISABLE_RTTI
throw std::runtime_error(toolkit::demangle(typeid(*this).name()) + "::getOwnerPoller failed: " + getUrl());
#else
throw std::runtime_error(toolkit::demangle("MediaSource") + "::getOwnerPoller failed: " + getUrl());
#endif
}
std::shared_ptr<MultiMediaSourceMuxer> MediaSource::getMuxer() const {

@ -80,7 +80,11 @@ public:
virtual bool close(MediaSource &sender) { return false; }
// 获取观看总人数,此函数一般强制重载 [AUTO-TRANSLATED:1da20a10]
// Get the total number of viewers, this function is generally forced to overload
#ifndef DISABLE_RTTI
virtual int totalReaderCount(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::totalReaderCount not implemented"); }
#else
virtual int totalReaderCount(MediaSource &sender) { throw NotImplemented(toolkit::demangle("MediaSourceEvent") + "::totalReaderCount not implemented"); }
#endif
// 通知观看人数变化 [AUTO-TRANSLATED:bad89528]
// Notify the change in the number of viewers
virtual void onReaderChanged(MediaSource &sender, int size);
@ -92,7 +96,11 @@ public:
virtual float getLossRate(MediaSource &sender, TrackType type) { return -1; }
// 获取所在线程, 此函数一般强制重载 [AUTO-TRANSLATED:71c99afb]
// Get the current thread, this function is generally forced to overload
#ifndef DISABLE_RTTI
virtual toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::getOwnerPoller not implemented"); }
#else
virtual toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::getOwnerPoller not implemented"); }
#endif
// //////////////////////仅供MultiMediaSourceMuxer对象继承//////////////////////// [AUTO-TRANSLATED:6e810d1f]
// //////////////////////Only for MultiMediaSourceMuxer object inheritance////////////////////////

@ -3,7 +3,7 @@ apply plugin: 'com.android.application'
// 10,00,000 major-minor-build
def AppMajorVersion = 1
def AppMinorVersion = 0
def AppBuildNumber = 2
def AppBuildNumber = 3
def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber
def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber
@ -13,8 +13,8 @@ android {
defaultConfig {
applicationId "com.xypower.mplive"
minSdkVersion 21
targetSdkVersion 28
minSdkVersion 28
targetSdkVersion 30
versionCode AppVersionCode
versionName AppVersionName

@ -41,6 +41,8 @@ include_directories(${ZLMediaKit_Root}/3rdpart)
include_directories(${ZLMediaKit_Root}/3rdpart/media-server)
include_directories(${ZLMediaKit_Root}/3rdpart/ZLToolKit/src)
message(WARNING " include path: ${MK_LINK_LIBRARIES}")
#
file(GLOB JNI_src_list ${JNI_Root}/*.cpp ${JNI_Root}/*.h)
add_library(mplive SHARED ${JNI_src_list})

@ -14,6 +14,13 @@
#include "Thread/semaphore.h"
#include "Common/config.h"
#include "Player/MediaPlayer.h"
#include "Network/TcpServer.h"
#include "Network/sockutil.h"
#include "Http/HttpSession.h"
#include "Rtmp/RtmpSession.h"
#include "Rtsp/RtspSession.h"
#include "Rtmp/RtmpPusher.h"
#include "Pusher/MediaPusher.h"
#include "Extension/Frame.h"
using namespace std;
@ -164,6 +171,89 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved){
extern int start_main(int argc,char *argv[]);
std::shared_ptr<TcpServer> startRtmpServer(uint16_t port) {
auto server = std::make_shared<TcpServer>();
server->start<RtmpSession>(port);
InfoL << "RTMP Server listening on port " << port;
return server;
}
std::shared_ptr<TcpServer> startRtspServer(uint16_t port) {
auto server = std::make_shared<TcpServer>();
if (port == 0)
{
port = 554;
}
server->start<RtspSession>(port);
InfoL << "RTSP Server listening on port " << port;
return server;
}
void startRtmpPushers(const std::string& url, const std::string& targetUrl) {
MediaInfo mediaInfo(url);
auto mediaSource = MediaSource::find(mediaInfo);
if (!mediaSource) {
// 文件不存在 [AUTO-TRANSLATED:f97c8ce8]
// File does not exist
WarnL << url << " not existed: ";
return;
}
auto poller = EventPollerPool::Instance().getPoller();
auto pusher = std::make_shared<MediaPusher>(mediaSource, poller);
std::weak_ptr<MediaSource> weak_src = mediaSource;
// src用完了可以直接置空防止main函数持有它(MP4Reader持有它即可) [AUTO-TRANSLATED:52e6393a]
// src is used up, can be set to empty directly, to prevent the main function from holding it (MP4Reader holds it)
mediaSource = nullptr;
std::weak_ptr<MediaPusher> weak_pusher = pusher;
pusher->setOnShutdown([poller, url, weak_pusher, weak_src](const SockException &ex) {
if (!weak_src.lock()) {
// 媒体注销导致的推流中断,不在重试推流 [AUTO-TRANSLATED:625b3e1a]
// Media cancellation causes push interruption, no retry push
WarnL << "MediaSource released:" << ex << ", publish stopped";
return;
}
WarnL << "Server connection is closed:" << ex << ", republish after 2 seconds";
// 重新推流, 2秒后重试 [AUTO-TRANSLATED:f8a261a3]
// Repush, retry after 2 seconds
poller->doDelayTask(2 * 1000, [weak_pusher, url]() {
if (auto strong_push = weak_pusher.lock()) {
strong_push->publish(url);
}
return 0;
});
});
// 设置发布结果处理逻辑 [AUTO-TRANSLATED:ce9de055]
// Set the publish result handling logic
pusher->setOnPublished([poller, weak_pusher, url](const SockException &ex) {
if (!ex) {
InfoL << "Publish success, please play with player:" << url;
return;
}
WarnL << "Publish fail:" << ex << ", republish after 2 seconds";
// 如果发布失败,就重试 [AUTO-TRANSLATED:b37fd4aa]
// If the publish fails, retry
poller->doDelayTask(2 * 1000, [weak_pusher, url]() {
if (auto strong_push = weak_pusher.lock()) {
strong_push->publish(url);
}
return 0;
});
});
pusher->publish(targetUrl);
}
static semaphore sem;
JNI_API(jboolean, startServer, jstring ini_dir){
string sd_path = stringFromJstring(env,ini_dir);
string ini_file = sd_path + "/zlmediakit.ini";
@ -175,38 +265,28 @@ JNI_API(jboolean, startServer, jstring ini_dir){
DebugL << "ini file:" << ini_file;
thread s_th([sd_path,ini_file,pem_file](){
s_tread_id = pthread_self();
try {
//http根目录修改默认路径
mINI::Instance()[Http::kRootPath] = sd_path + "/httpRoot";
//mp4录制点播根目录修改默认路径
mINI::Instance()[Protocol::kMP4SavePath] = sd_path + "/httpRoot";
//hls根目录修改默认路径
mINI::Instance()[Protocol::kHlsSavePath] = sd_path + "/httpRoot";
//替换默认端口号(在配置文件未生成时有效)
mINI::Instance()["http.port"] = 8080;
mINI::Instance()["http.sslport"] = 8443;
mINI::Instance()["rtsp.port"] = 8554;
mINI::Instance()["rtsp.port"] = 0;
mINI::Instance()["rtsp.sslport"] = 8332;
mINI::Instance()["rtsp.sslport"] = 0;
mINI::Instance()["general.enableVhost"] = 0;
for (auto &pr : mINI::Instance()) {
//替换hook默认地址
replace(pr.second, "https://127.0.0.1/", "http://127.0.0.1:8080/");
}
//默认打开hook
mINI::Instance()["hook.enable"] = 0;
//默认打开http api调试
mINI::Instance()["api.apiDebug"] = 1;
int argc = 5;
const char *argv[] = {"", "-c", ini_file.data(), "-s", pem_file.data()};
start_main(argc, (char **) argv);
s_tread_id = 0;
} catch (std::exception &ex) {
WarnL << ex.what();
}
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", LTrace));
// Load the configuration file
// initConfig();
// Initialize the event loop
EventPollerPool::Instance().setPoolSize(4);
// Start the RTMP server
auto rtmpSvr = startRtmpServer(1935);
auto rtspSvr = startRtspServer(554);
// Start the RTMP pushers
// startRtmpPushers("", "");
// Wait for the signal to exit
signal(SIGINT, [](int) { sem.post(); });
signal(SIGTERM, [](int) { sem.post(); });
sem.wait();
});
// static onceToken s_token([]{
@ -216,17 +296,8 @@ JNI_API(jboolean, startServer, jstring ini_dir){
return true;
};
extern semaphore g_zl_sem;
JNI_API(void, stopServer) {
g_zl_sem.post();
s_tread_id = 0;
#if 0
if(s_tread_id){
pthread_kill(s_tread_id, SIGINT);
s_tread_id = 0;
}
#endif
sem.post();
}
JNI_API(jlong, createMediaPlayer, jstring url, jobject callback){

@ -135,6 +135,11 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
Intent intent = getIntent();
final int autoStart = intent.getIntExtra("autoStart", 1);
final int netCamera = intent.getIntExtra("netCamera", 0);
final int vendor = intent.getIntExtra("vendor", 0);
final int disableLocalServer = intent.getIntExtra("disableLocalServer", 0);
final int rotation = intent.getIntExtra("rotation", -1);
int autoClose = intent.getIntExtra("autoClose", 0);
// restore data.
sp = getSharedPreferences("MpLive", MODE_PRIVATE);
@ -143,13 +148,13 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
// initialize url.
final EditText efu = (EditText) findViewById(R.id.url);
btnPublish = (Button) findViewById(R.id.publish);
btnSwitchCamera = (Button) findViewById(R.id.swCam);
btnRecord = (Button) findViewById(R.id.record);
btnSwitchEncoder = (Button) findViewById(R.id.swEnc);
btnPause = (Button) findViewById(R.id.pause);
btnPause.setEnabled(false);
mCameraView = (SrsCameraView) findViewById(R.id.glsurfaceview_camera);
String url = intent.getStringExtra("url");
if (!TextUtils.isEmpty(url)) {
@ -160,70 +165,76 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
rtmpUrl = "rtmp://127.0.0.1/live/0";
}
efu.setText(rtmpUrl);
mCameraView = (SrsCameraView) findViewById(R.id.glsurfaceview_camera);
final int rotation = intent.getIntExtra("rotation", -1);
if (rotation != -1) {
//设置图像显示方向
mCameraView.setPreviewOrientation(rotation);
}
cameraData = mCameraView.getCameraData();
int size = cameraData.size();
if (size == 0) {
Toast.makeText(getApplicationContext(), "没有查询到摄像头", Toast.LENGTH_SHORT).show();
}
mPublisher = new SrsPublisher(mCameraView);
mPublisher.setEncodeHandler(new SrsEncodeHandler(this));
mPublisher.setRtmpHandler(new RtmpHandler(this));
mPublisher.setRecordHandler(new SrsRecordHandler(this));
mPublisher.setPreviewResolution(mWidth, mHeight);//设置预览宽高
mPublisher.setOutputResolution(mHeight, mWidth); // 这里要和preview反过来
mPublisher.setVideoHDMode();
if (autoStart != 0) {
if (disableLocalServer == 0) {
startRTMPServer();
}
}
cameraId = intent.getIntExtra("cameraId", 0);
// mPublisher.startCamera();
if (netCamera != 0) {
mCameraView.setCameraCallbacksHandler(new SrsCameraView.CameraCallbacksHandler() {
@Override
public void onCameraParameters(Camera.Parameters params) {
Log.e("fsfs", "fsdf");
} else {
if (rotation != -1) {
//设置图像显示方向
mCameraView.setPreviewOrientation(rotation);
}
});
cameraData = mCameraView.getCameraData();
int size = cameraData.size();
if (size == 0) {
Toast.makeText(getApplicationContext(), "没有查询到摄像头", Toast.LENGTH_SHORT).show();
}
mPublisher = new SrsPublisher(mCameraView);
mPublisher.setEncodeHandler(new SrsEncodeHandler(this));
mPublisher.setRtmpHandler(new RtmpHandler(this));
mPublisher.setRecordHandler(new SrsRecordHandler(this));
mPublisher.setPreviewResolution(mWidth, mHeight);//设置预览宽高
mPublisher.setOutputResolution(mHeight, mWidth); // 这里要和preview反过来
if (autoStart != 0) {
mPublisher.setVideoHDMode();
startRTMPServer();
cameraId = intent.getIntExtra("cameraId", 0);
// mPublisher.startCamera();
mPublisher.switchCameraFace(cameraId, rotation);
mHandler.postDelayed(new Runnable() {
mCameraView.setCameraCallbacksHandler(new SrsCameraView.CameraCallbacksHandler() {
@Override
public void run() {
public void onCameraParameters(Camera.Parameters params) {
Log.e("fsfs", "fsdf");
}
});
if (autoStart != 0) {
mPublisher.switchCameraFace(cameraId, rotation);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// rtmpUrl = "rtmp://61.169.135.146/live/0";
SharedPreferences.Editor editor = sp.edit();
editor.putString("rtmpUrl", rtmpUrl);
editor.apply();
efu.setText(rtmpUrl + "rotation= " + rotation + " cameraid=" + cameraId + " auto=" + autoStart);
// efu.setText(rtmpUrl + " cameraid=" + cameraId + " auto=" + autoStart);
efu.setText(rtmpUrl);
mPublisher.startPublish(rtmpUrl);
if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
// Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Use soft encoder", Toast.LENGTH_SHORT).show();
SharedPreferences.Editor editor = sp.edit();
editor.putString("rtmpUrl", rtmpUrl);
editor.apply();
efu.setText(rtmpUrl + "rotation= " + rotation + " cameraid=" + cameraId + " auto=" + autoStart);
// efu.setText(rtmpUrl + " cameraid=" + cameraId + " auto=" + autoStart);
efu.setText(rtmpUrl);
mPublisher.startPublish(rtmpUrl);
if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
// Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Use soft encoder", Toast.LENGTH_SHORT).show();
}
btnPublish.setText("stop");
btnSwitchEncoder.setEnabled(false);
btnPause.setEnabled(true);
}
btnPublish.setText("stop");
btnSwitchEncoder.setEnabled(false);
btnPause.setEnabled(true);
}
}, 500);
} else {
mPublisher.switchCameraFace(cameraId, rotation);
}, 500);
} else {
mPublisher.switchCameraFace(cameraId, rotation);
}
}
int autoClose = intent.getIntExtra("autoClose", 0);
if (autoClose != 0) {
mHandler.postDelayed(new Runnable() {
@Override

@ -7,7 +7,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.1'
classpath 'com.android.tools.build:gradle:7.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-6.5-all.zip
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.5-bin.zip

Loading…
Cancel
Save