This commit is contained in:
cxh 2025-10-15 10:30:36 +08:00
parent cb37ca9eb3
commit 4de32c3487
2 changed files with 99 additions and 132 deletions

View File

@ -7,79 +7,79 @@
"client_id": "20004_vehmedia",
"username": "20004_4A:69:BE:32:59:AE",
"password": "31d6bb29f177d5bf8560756c0f0e63c63fd412e52c5b9ea59476024eab893884a5f34f0637e0fe3ad42b802c16edb6feb37cde613957c3540c060c07b230cb0aa6b4547bb86fcae43d484179d3a11a1969a2f367ec0ceede4c10510757a89927af4c2d0c0484476be3241a9ff9242e7401f3fbcd824b5cfb19674663b7045e32dd2f97b4",
"mqtt_heart_threshold": 2000
"mqtt_heart_threshold": 1000
},
"cameras": [
{
"device": "/dev/video11",
"device": "/dev/video0",
"name": "AHD1",
"enabled": true,
"resolution": "720p",
"resolution": "960p",
"width": 1280,
"height": 720,
"fps": 30
},
{
"device": "/dev/video12",
"name": "AHD2",
"enabled": false,
"resolution": "720p",
"width": 1280,
"height": 720,
"fps": 30
},
{
"device": "/dev/video13",
"name": "AHD3",
"enabled": false,
"resolution": "720p",
"width": 1280,
"height": 720,
"fps": 30
},
{
"device": "/dev/video14",
"name": "AHD4",
"enabled": false,
"resolution": "720p",
"width": 1280,
"height": 720,
"fps": 30
},
{
"device": "/dev/video3",
"name": "AHD5",
"enabled": false,
"resolution": "1080p",
"width": 1920,
"height": 1080,
"fps": 30
},
{
"device": "/dev/video2",
"name": "AHD6",
"enabled": false,
"resolution": "1080p",
"width": 1920,
"height": 1080,
"height": 960,
"fps": 30
},
{
"device": "/dev/video1",
"name": "AHD7",
"enabled": false,
"resolution": "1080p",
"width": 1920,
"height": 1080,
"name": "AHD2",
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
},
{
"device": "/dev/video0",
"device": "/dev/video2",
"name": "AHD3",
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
},
{
"device": "/dev/video3",
"name": "AHD4",
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
},
{
"device": "/dev/video11",
"name": "AHD5",
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
},
{
"device": "/dev/video12",
"name": "AHD6",
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
},
{
"device": "/dev/video13",
"name": "AHD7",
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
},
{
"device": "/dev/video14",
"name": "AHD8",
"enabled": false,
"resolution": "1080p",
"width": 1920,
"height": 1080,
"enabled": true,
"resolution": "960p",
"width": 1280,
"height": 960,
"fps": 30
}
]

View File

@ -82,11 +82,24 @@ void RTMPManager::stream_loop(Camera cam, StreamType type)
std::string key = make_stream_key(cam.name, type);
LOG_INFO("[RTMP] Stream loop started for " + key);
const int MAX_RETRIES = 5;
int retry_count = 0;
GstElement *pipeline = create_pipeline(cam, type);
if (!pipeline)
{
update_status(key, {false, StreamResult::PIPELINE_ERROR, "Failed to create pipeline"});
LOG_ERROR("[RTMP] " + key + " pipeline creation failed. Exiting stream loop.");
return;
}
GstBus *bus = gst_element_get_bus(pipeline);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
update_status(key, {true, StreamResult::OK, ""});
LOG_INFO("[RTMP] " + key + " is streaming.");
while (true)
{
GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
static_cast<GstMessageType>(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
{
std::lock_guard<std::mutex> lock(streams_mutex);
auto it = streams.find(key);
@ -94,88 +107,42 @@ void RTMPManager::stream_loop(Camera cam, StreamType type)
break;
}
GstElement *pipeline = create_pipeline(cam, type);
if (!pipeline)
{
update_status(key, {false, StreamResult::PIPELINE_ERROR, "Failed to create pipeline"});
std::this_thread::sleep_for(std::chrono::seconds(3));
if (++retry_count > MAX_RETRIES)
break;
if (!msg)
continue;
}
GstBus *bus = gst_element_get_bus(pipeline);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
update_status(key, {true, StreamResult::OK, ""});
LOG_INFO("[RTMP] " + key + " is streaming.");
bool stop_flag = false;
GstMessage *msg = nullptr;
while (true)
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
{
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
static_cast<GstMessageType>(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
{
std::lock_guard<std::mutex> lock(streams_mutex);
auto it = streams.find(key);
if (it == streams.end() || !it->second->running.load())
{
stop_flag = true;
break;
}
}
if (!msg)
continue;
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
{
GError *err = nullptr;
gchar *debug = nullptr;
gst_message_parse_error(msg, &err, &debug);
std::string err_msg = err ? err->message : "Unknown GStreamer error";
LOG_ERROR("[RTMP] Error in " + key + ": " + err_msg);
update_status(key, {false, StreamResult::CONNECTION_FAIL, err_msg});
if (err)
g_error_free(err);
if (debug)
g_free(debug);
stop_flag = true;
}
else if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS)
{
LOG_WARN("[RTMP] EOS on " + key);
update_status(key, {false, StreamResult::EOS_RECEIVED, "EOS"});
stop_flag = true;
}
GError *err = nullptr;
gchar *debug = nullptr;
gst_message_parse_error(msg, &err, &debug);
std::string err_msg = err ? err->message : "Unknown GStreamer error";
LOG_ERROR("[RTMP] Error in " + key + ": " + err_msg);
update_status(key, {false, StreamResult::CONNECTION_FAIL, err_msg});
if (err)
g_error_free(err);
if (debug)
g_free(debug);
gst_message_unref(msg);
if (stop_flag)
break;
break; // 出错立即退出
}
gst_element_set_state(pipeline, GST_STATE_NULL);
if (bus)
gst_object_unref(bus);
gst_object_unref(pipeline);
if (!stop_flag)
break;
if (++retry_count > MAX_RETRIES)
else if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS)
{
LOG_ERROR("[RTMP] " + key + " reached max retries. Giving up.");
break;
LOG_WARN("[RTMP] EOS on " + key);
update_status(key, {false, StreamResult::EOS_RECEIVED, "EOS"});
gst_message_unref(msg);
break; // EOS 退出
}
LOG_WARN("[RTMP] Reconnecting " + key + " in 3s...");
std::this_thread::sleep_for(std::chrono::seconds(3));
gst_message_unref(msg);
}
update_status(key, {false, StreamResult::UNKNOWN, "Stream loop exited"});
gst_element_set_state(pipeline, GST_STATE_NULL);
if (bus)
gst_object_unref(bus);
gst_object_unref(pipeline);
LOG_INFO("[RTMP] Stream loop ended for " + key);
update_status(key, {false, StreamResult::UNKNOWN, "Stream loop exited"});
}
void RTMPManager::start_camera(const Camera &cam, StreamType type)