Skip to content

Commit ab6feb6

Browse files
committed
Merge upstream/master: resolve snapshot endpoint conflict
Merged latest changes from upstream (mpromonet/v4l2rtspserver). Conflict resolution in src/HTTPServer.cpp: - Kept my SnapshotManager implementation for snapshot endpoint - Upstream had BaseServerMediaSubsession::getLastFrame() approach - My implementation is more flexible and handles both MJPEG and H264 MP4 snapshots Other upstream changes merged: - Updated CI workflows (.github/workflows/*.yml) - CMakeLists.txt updates - BaseServerMediaSubsession improvements - V4L2DeviceSource enhancements - H264/H265 device source updates All tests passing, snapshot functionality preserved.
2 parents 7d902f4 + 10735b5 commit ab6feb6

File tree

11 files changed

+93
-46
lines changed

11 files changed

+93
-46
lines changed

.github/workflows/ccpp.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
cpack
2424
echo "artifactPath=$(ls *.deb)" >> $GITHUB_ENV
2525
26-
- uses: actions/upload-artifact@v3
26+
- uses: actions/upload-artifact@v4
2727
with:
2828
name: ${{ env.artifactPath }}
2929
path: ${{ env.artifactPath }}

.github/workflows/cross.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
cpack
6363
echo "artifactPath=$(ls *.deb)" >> $GITHUB_ENV
6464
65-
- uses: actions/upload-artifact@v3
65+
- uses: actions/upload-artifact@v4
6666
with:
6767
name: ${{ env.artifactPath }}
6868
path: ${{ env.artifactPath }}

.github/workflows/scorecard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
6060
# format to the repository Actions tab.
6161
- name: "Upload artifact"
62-
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
62+
uses: actions/upload-artifact@v4
6363
with:
6464
name: SARIF file
6565
path: results.sarif

CMakeLists.txt

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.5)
1+
cmake_minimum_required(VERSION 3.12)
22

33
project(v4l2rtspserver)
44

@@ -10,24 +10,26 @@ set(STATICSTDCPP ON CACHE BOOL "use gcc static lib if available")
1010
set(LOG4CPP OFF CACHE BOOL "use log4cpp if available")
1111
set(LIVE555URL http://www.live555.com/liveMedia/public/live555-latest.tar.gz CACHE STRING "live555 url")
1212
set(LIVE555CFLAGS -DBSD=1 -DSOCKLEN_T=socklen_t -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -DALLOW_RTSP_SERVER_PORT_REUSE=1 -DNO_STD_LIB=1 CACHE STRING "live555 CFGLAGS")
13-
14-
if(NOT CMAKE_BUILD_TYPE)
15-
set (CMAKE_BUILD_TYPE "Release")
16-
endif()
13+
set(SYSTEMD ON CACHE BOOL "install SystemD service")
1714

1815
set(CMAKE_CXX_STANDARD 20)
1916

2017
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake/")
2118

22-
# set version based on git
2319
find_package(Git)
24-
if(GIT_FOUND)
20+
if(DEFINED ENV{V4L2RTSPSERVER_VERSION})
21+
# set version from V4L2RTSPSERVER_VERSION env variable
22+
add_compile_definitions("VERSION=\"$ENV{V4L2RTSPSERVER_VERSION}\"")
23+
elseif(GIT_FOUND)
24+
# set version based on git
2525
EXECUTE_PROCESS(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --tags --always --dirty OUTPUT_VARIABLE VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
2626
STRING(REGEX REPLACE "^v(.*)" "\\1" VERSION "${VERSION}")
27-
add_definitions("-DVERSION=\"${VERSION}\"")
27+
add_compile_definitions("VERSION=\"${VERSION}\"")
28+
else()
29+
message(WARNING "VERSION is undefined")
30+
add_compile_definitions("VERSION=\"undefined\"")
2831
endif()
2932

30-
3133
# define executable to build
3234
include_directories("inc")
3335
add_executable(${PROJECT_NAME} main.cpp)
@@ -84,7 +86,7 @@ target_compile_definitions(libv4l2rtspserver PUBLIC ${LIVE555CFLAGS})
8486
target_link_libraries (${PROJECT_NAME} libv4l2rtspserver ${LIVE_LIBRARIES})
8587
set (LIBRARIES "")
8688
if (OpenSSL_FOUND)
87-
set(LIBRARIES ${LIBRARIES} ${OPENSSL_LIBRARIES})
89+
set(LIBRARIES ${LIBRARIES} OpenSSL::SSL)
8890
endif ()
8991

9092
#pthread
@@ -108,15 +110,17 @@ if (ALSA)
108110
find_package(ALSA QUIET)
109111
MESSAGE("ALSA_FOUND = ${ALSA_FOUND}")
110112
if (ALSA_LIBRARY)
111-
target_compile_definitions(libv4l2rtspserver PUBLIC HAVE_ALSA)
112-
set(LIBRARIES ${LIBRARIES} ${ALSA_LIBRARY})
113-
113+
target_compile_definitions(libv4l2rtspserver PUBLIC HAVE_ALSA)
114+
set(LIBRARIES ${LIBRARIES} ALSA::ALSA)
115+
114116
SET(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_PACKAGE_DEPENDS}libasound2,)
115117
endif ()
116118
endif()
117119

118120
# libv4l2cpp
119-
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init)
121+
if (GIT_FOUND)
122+
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init)
123+
endif()
120124
add_subdirectory(libv4l2cpp EXCLUDE_FROM_ALL)
121125
target_include_directories(libv4l2rtspserver PUBLIC libv4l2cpp/inc)
122126
target_link_libraries (libv4l2rtspserver PUBLIC libv4l2cpp ${LIBRARIES})
@@ -139,17 +143,19 @@ enable_testing()
139143
add_test(help ./${PROJECT_NAME} -h)
140144

141145
#systemd
142-
find_package(PkgConfig)
143-
pkg_check_modules(SYSTEMD systemd QUIET)
144-
if (SYSTEMD_FOUND)
145-
message(STATUS "SystemD available")
146-
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=systemdsystemunitdir systemd OUTPUT_VARIABLE SYSTEMD_SERVICES_INSTALL_DIR)
147-
string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_SERVICES_INSTALL_DIR "${SYSTEMD_SERVICES_INSTALL_DIR}")
148-
message(STATUS "SystemD directory '${SYSTEMD_SERVICES_INSTALL_DIR}'")
149-
150-
configure_file(v4l2rtspserver.service.in ${CMAKE_CURRENT_BINARY_DIR}/v4l2rtspserver.service @ONLY)
146+
if (SYSTEMD)
147+
find_package(PkgConfig)
148+
pkg_check_modules(SYSTEMD systemd QUIET)
149+
if (SYSTEMD_FOUND)
150+
message(STATUS "SystemD available")
151+
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=systemdsystemunitdir systemd OUTPUT_VARIABLE SYSTEMD_SERVICES_INSTALL_DIR)
152+
string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_SERVICES_INSTALL_DIR "${SYSTEMD_SERVICES_INSTALL_DIR}")
153+
message(STATUS "SystemD directory '${SYSTEMD_SERVICES_INSTALL_DIR}'")
154+
155+
configure_file(v4l2rtspserver.service.in ${CMAKE_CURRENT_BINARY_DIR}/v4l2rtspserver.service @ONLY)
151156
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/v4l2rtspserver.service DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR})
152-
endif (SYSTEMD_FOUND)
157+
endif (SYSTEMD_FOUND)
158+
endif (SYSTEMD)
153159

154160
# package
155161
install (TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)

inc/BaseServerMediaSubsession.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class BaseServerMediaSubsession
6767
case V4L2_PIX_FMT_YUV444: rtpFormat = "video/RAW" ; break;
6868
case V4L2_PIX_FMT_UYVY : rtpFormat = "video/RAW" ; break;
6969
case V4L2_PIX_FMT_NV12 : rtpFormat = "video/RAW" ; break;
70+
case V4L2_PIX_FMT_Y41P : rtpFormat = "video/RAW" ; break;
7071
case V4L2_PIX_FMT_BGR24 : rtpFormat = "video/RAW" ; break;
7172
case V4L2_PIX_FMT_BGR32 : rtpFormat = "video/RAW" ; break;
7273
case V4L2_PIX_FMT_RGB24 : rtpFormat = "video/RAW" ; break;
@@ -116,6 +117,17 @@ class BaseServerMediaSubsession
116117
static RTPSink* createSink(UsageEnvironment& env, Groupsock * rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, const std::string& format, V4L2DeviceSource* source);
117118
char const* getAuxLine(V4L2DeviceSource* source, RTPSink* rtpSink);
118119

120+
std::string getLastFrame() const {
121+
V4L2DeviceSource* deviceSource = dynamic_cast<V4L2DeviceSource*>(m_replicator->inputSource());
122+
if (deviceSource) {
123+
return deviceSource->getLastFrame();
124+
} else {
125+
return "";
126+
}
127+
}
128+
129+
std::string getFormat() const { return m_format; }
130+
119131
protected:
120132
StreamReplicator* m_replicator;
121133
std::string m_format;

inc/V4L2DeviceSource.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
#include <list>
1717
#include <iostream>
1818
#include <iomanip>
19-
20-
#include <pthread.h>
19+
#include <mutex>
20+
#include <thread>
2121

2222
// live555
2323
#include <liveMedia.hh>
@@ -77,6 +77,11 @@ class V4L2DeviceSource: public FramedSource
7777
public:
7878
static V4L2DeviceSource* createNew(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, CaptureMode captureMode) ;
7979
std::string getAuxLine() { return m_auxLine; }
80+
std::string getLastFrame() {
81+
std::lock_guard<std::mutex> lock(m_lastFrameMutex);
82+
std::string frame(m_lastFrame);
83+
return frame;
84+
}
8085
DeviceInterface* getDevice() { return m_device; }
8186
void postFrame(char * frame, int frameSize, const timeval &ref);
8287
virtual std::list< std::string > getInitFrames() { return std::list< std::string >(); }
@@ -87,8 +92,7 @@ class V4L2DeviceSource: public FramedSource
8792
V4L2DeviceSource(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, CaptureMode captureMode);
8893
virtual ~V4L2DeviceSource();
8994

90-
protected:
91-
static void* threadStub(void* clientData) { return ((V4L2DeviceSource*) clientData)->thread();};
95+
protected:
9296
virtual void* thread();
9397
static void deliverFrameStub(void* clientData) {((V4L2DeviceSource*) clientData)->deliverFrame();};
9498
void deliverFrame();
@@ -112,8 +116,10 @@ class V4L2DeviceSource: public FramedSource
112116
int m_outfd;
113117
DeviceInterface * m_device;
114118
unsigned int m_queueSize;
115-
pthread_t m_thid;
116-
pthread_mutex_t m_mutex;
119+
std::thread m_thread;
120+
std::mutex m_mutex;
117121
std::string m_auxLine;
122+
std::mutex m_lastFrameMutex;
123+
std::string m_lastFrame;
118124
};
119125

src/H264_V4l2DeviceSource.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames
8989
{
9090
switch (frameType&0x1F)
9191
{
92-
case 7: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); break;
92+
case 7: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); m_pps.clear(); break;
9393
case 8: LOG(INFO) << "PPS size:" << size << " bufSize:" << bufSize; m_pps.assign((char*)buffer,size); break;
9494
case 5:
9595
LOG(INFO) << "IDR size:" << size << " bufSize:" << bufSize;
@@ -123,6 +123,15 @@ std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames
123123
outputBuffer.insert(outputBuffer.end(), m_pps.begin(), m_pps.end());
124124
}
125125
}
126+
if (!m_sps.empty() && !m_pps.empty()) {
127+
std::lock_guard<std::mutex> lock(m_lastFrameMutex);
128+
m_lastFrame.assign(H264marker, sizeof(H264marker));
129+
m_lastFrame.append(m_sps.c_str(), m_sps.size());
130+
m_lastFrame.append(H264marker, sizeof(H264marker));
131+
m_lastFrame.append(m_pps.c_str(), m_pps.size());
132+
m_lastFrame.append(H264marker, sizeof(H264marker));
133+
m_lastFrame.append((char*)buffer, size);
134+
}
126135
break;
127136
default:
128137
break;

src/H265_V4l2DeviceSource.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ std::list< std::pair<unsigned char*,size_t> > H265_V4L2DeviceSource::splitFrames
3131
{
3232
switch ((frameType&0x7E)>>1)
3333
{
34-
case 32: LOG(INFO) << "VPS size:" << size << " bufSize:" << bufSize; m_vps.assign((char*)buffer,size); break;
34+
case 32: LOG(INFO) << "VPS size:" << size << " bufSize:" << bufSize; m_vps.assign((char*)buffer,size); m_sps.clear(); m_pps.clear(); break;
3535
case 33: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); break;
3636
case 34: LOG(INFO) << "PPS size:" << size << " bufSize:" << bufSize; m_pps.assign((char*)buffer,size); break;
3737
case 19:
@@ -42,6 +42,17 @@ std::list< std::pair<unsigned char*,size_t> > H265_V4L2DeviceSource::splitFrames
4242
frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_sps.c_str(), m_sps.size()));
4343
frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_pps.c_str(), m_pps.size()));
4444
}
45+
if (!m_vps.empty() && !m_sps.empty() && !m_pps.empty()) {
46+
std::lock_guard<std::mutex> lock(m_lastFrameMutex);
47+
m_lastFrame.assign(H264marker, sizeof(H264marker));
48+
m_lastFrame.append(m_vps.c_str(), m_vps.size());
49+
m_lastFrame.append(H264marker, sizeof(H264marker));
50+
m_lastFrame.append(m_sps.c_str(), m_sps.size());
51+
m_lastFrame.append(H264marker, sizeof(H264marker));
52+
m_lastFrame.append(m_pps.c_str(), m_pps.size());
53+
m_lastFrame.append(H264marker, sizeof(H264marker));
54+
m_lastFrame.append((char*)buffer, size);
55+
}
4556
break;
4657
default: break;
4758
}

src/HTTPServer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
#include <cstring>
1919
#include <time.h>
2020
#include "ByteStreamMemoryBufferSource.hh"
21-
2221
#include "HTTPServer.h"
2322
#include "SnapshotManager.h"
2423

24+
#include "BaseServerMediaSubsession.h"
25+
2526
u_int32_t HTTPServer::HTTPClientConnection::m_ClientSessionId = 0;
2627

2728
void HTTPServer::HTTPClientConnection::sendHeader(const char* contentType, unsigned int contentLength)

src/ServerMediaSubsession.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ RTPSink* BaseServerMediaSubsession::createSink(UsageEnvironment& env, Groupsock
8686
case V4L2_PIX_FMT_YUV444: sampling = "YCbCr-4:4:4"; break;
8787
case V4L2_PIX_FMT_UYVY : sampling = "YCbCr-4:2:2"; break;
8888
case V4L2_PIX_FMT_NV12 : sampling = "YCbCr-4:2:0"; break;
89+
case V4L2_PIX_FMT_Y41P : sampling = "YCbCr-4:1:1"; break;
8990
case V4L2_PIX_FMT_RGB24 : sampling = "RGB" ; break;
9091
case V4L2_PIX_FMT_RGB32 : sampling = "RGBA" ; break;
9192
case V4L2_PIX_FMT_BGR24 : sampling = "BGR" ; break;

0 commit comments

Comments
 (0)