Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sample example for relay command. #355

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -618,3 +618,6 @@ IF(ENABLE_WINDOWS)
file(COPY ${RUNTIME_DLLS} DESTINATION RelWithDebInfo/)
ENDIF(GHA)
ENDIF(ENABLE_WINDOWS)


add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../samples ${CMAKE_CURRENT_BINARY_DIR}/samples)
115 changes: 78 additions & 37 deletions base/src/RTSPClientSrc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

using namespace std;


#include <iostream>
#include <string>

#include <thread>
#include <mutex>
#include <chrono>
#include "H264Utils.h"

extern "C"
{
Expand All @@ -37,24 +37,23 @@ FrameMetadata::FrameType getFrameType_fromFFMPEG(AVMediaType avMediaType, AVCode
case AV_CODEC_ID_BMP:
return FrameMetadata::BMP_IMAGE;
default:
return FrameMetadata::GENERAL;
return FrameMetadata::GENERAL;
}
}
return FrameMetadata::GENERAL; //for everything else we may not have a match
return FrameMetadata::GENERAL; // for everything else we may not have a match
}


class RTSPClientSrc::Detail
{
public:
Detail(RTSPClientSrc* m,std::string path, bool useTCP) :myModule(m), path(path), bConnected(false), bUseTCP(useTCP){}
Detail(RTSPClientSrc* m, std::string path, bool useTCP) : myModule(m), path(path), bConnected(false), bUseTCP(useTCP) {}
~Detail() { destroy(); }
void destroy()
{
if(nullptr!= pFormatCtx)
if (nullptr != pFormatCtx)
avformat_close_input(&pFormatCtx);
}

bool connect()
{
avformat_network_init();
Expand All @@ -64,12 +63,12 @@ class RTSPClientSrc::Detail

AVDictionary* avdic = NULL;

av_dict_set(&avdic, "rtsp_transport", (bUseTCP)?"tcp":"udp", 0);
av_dict_set(&avdic, "rtsp_transport", (bUseTCP) ? "tcp" : "udp", 0);
av_dict_set(&avdic, "max_delay", "100", 0);

if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, &avdic) != 0)
{
LOG_ERROR << "can't open the URL." << path <<std::endl;
LOG_ERROR << "can't open the URL." << path << std::endl;
bConnected = false;
return bConnected;
}
Expand All @@ -81,27 +80,27 @@ class RTSPClientSrc::Detail
return bConnected;
}

//this loop should check that each output pin is satisfied
// this loop should check that each output pin is satisfied
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
{
auto pCodecCtx = pFormatCtx->streams[i]->codec;
LOG_INFO << av_get_media_type_string (pCodecCtx->codec_type)<<" Codec: " << avcodec_get_name(pCodecCtx->codec_id);
auto fType=getFrameType_fromFFMPEG(pCodecCtx->codec_type,pCodecCtx->codec_id);
string outPin=myModule->getOutputPinIdByType(fType);
LOG_INFO << av_get_media_type_string(pCodecCtx->codec_type) << " Codec: " << avcodec_get_name(pCodecCtx->codec_id);
auto fType = getFrameType_fromFFMPEG(pCodecCtx->codec_type, pCodecCtx->codec_id);
string outPin = myModule->getOutputPinIdByType(fType);
if (!outPin.empty())
{
streamsMap[i] = outPin;
if (pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
auto meta= FrameMetadataFactory::downcast<H264Metadata>(myModule->getOutputMetadata(outPin));
auto meta = FrameMetadataFactory::downcast<H264Metadata>(myModule->getOutputMetadata(outPin));
H264Metadata tmp(pCodecCtx->width, pCodecCtx->height, pCodecCtx->gop_size, pCodecCtx->max_b_frames);
meta->setData(tmp);
}
}
}

//by this time all the output pins should be satisfied if not we have a problem
// by this time all the output pins should be satisfied if not we have a problem
if (streamsMap.size() < myModule->getNumberOfOutputPins())
{
LOG_ERROR << "some output pins can not be satsified" << std::endl;
Expand All @@ -110,32 +109,68 @@ class RTSPClientSrc::Detail
bConnected = true;
return bConnected;
}

frame_sp prependSpsPpsToFrame(std::string id)
{
auto spsPpsData = pFormatCtx->streams[0]->codec->extradata;
auto spsPpsSize = pFormatCtx->streams[0]->codec->extradata_size;
size_t totalFrameSize = packet.size + spsPpsSize;

auto frm = myModule->makeFrame(totalFrameSize, id);
uint8_t* frameData = static_cast<uint8_t*>(frm->data());
memcpy(frameData, spsPpsData, spsPpsSize);
frameData += spsPpsSize;
memcpy(frameData, packet.data, packet.size);
return frm;
}

bool readBuffer()
{
frame_container outFrames;
bool got_something = false;
while(!got_something)
while (!got_something)
{
if (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (videoStream >= 0) //source has video
if (videoStream >= 0) // source has video
{
if (packet.stream_index == videoStream) //got video
if (packet.stream_index == videoStream) // got video
{
got_something = true;
}
}
else
{
got_something = true; //does not need video and got something
got_something = true; // does not need video and got something
}
auto it = streamsMap.find(packet.stream_index);
if (it != streamsMap.end()) { // so we have an interest in sending this
auto frm=myModule->makeFrame(packet.size, it->second);
if (it != streamsMap.end())
{ // so we have an interest in sending this
frame_sp frm;
auto naluType = H264Utils::getNALUType((const char*)packet.data);
if (naluType == H264Utils::H264_NAL_TYPE_SEI)
{
size_t offset = 0;
packet.data += 4;
packet.size -= 4;
H264Utils::getNALUnit((const char*)packet.data, packet.size, offset);
packet.data += offset - 4;
packet.size -= offset - 4;
frm = prependSpsPpsToFrame(it->second);
}
else if (naluType == H264Utils::H264_NAL_TYPE_IDR_SLICE)
{
frm = prependSpsPpsToFrame(it->second);
}
else
{
frm = myModule->makeFrame(packet.size, it->second);
memcpy(frm->data(), packet.data, packet.size);
}

//dreaded memory copy should be avoided
memcpy(frm->data(), packet.data, packet.size);
frm->timestamp = packet.pts;
std::chrono::time_point<std::chrono::system_clock> t = std::chrono::system_clock::now();
auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(t.time_since_epoch());
frm->timestamp = dur.count();
if (!outFrames.insert(make_pair(it->second, frm)).second)
{
LOG_WARNING << "oops! there is already another packet for pin " << it->second;
Expand All @@ -144,8 +179,8 @@ class RTSPClientSrc::Detail
av_packet_unref(&packet);
}
}
if(outFrames.size()>0)
myModule->send(outFrames);
if (outFrames.size() > 0)
myModule->send(outFrames);
return true;
}

Expand All @@ -156,45 +191,51 @@ class RTSPClientSrc::Detail
AVFormatContext* pFormatCtx = nullptr;
std::string path;
bool bConnected;
int videoStream=-1;
int videoStream = -1;
bool bUseTCP;
std::map<unsigned int, std::string> streamsMap;
RTSPClientSrc* myModule;
};

RTSPClientSrc::RTSPClientSrc(RTSPClientSrcProps _props) : Module(SOURCE, "RTSPClientSrc", _props), mProps(_props)
{
mDetail.reset(new Detail(this,mProps.rtspURL, mProps.useTCP));
mDetail.reset(new Detail(this, mProps.rtspURL, mProps.useTCP));
}
RTSPClientSrc::~RTSPClientSrc() {
RTSPClientSrc::~RTSPClientSrc()
{
}
bool RTSPClientSrc::init() {
bool RTSPClientSrc::init()
{
if (mDetail->connect())
{
return Module::init();
}
return false;
}
bool RTSPClientSrc::term() {
bool RTSPClientSrc::term()
{
mDetail.reset();
return true;
}
void RTSPClientSrc::setProps(RTSPClientSrcProps& props)
{
mProps = props;
//TBD need to also reset the whole connection
// TBD need to also reset the whole connection
}
RTSPClientSrcProps RTSPClientSrc::getProps() {
RTSPClientSrcProps RTSPClientSrc::getProps()
{
return mProps;
}

bool RTSPClientSrc::produce() {
bool RTSPClientSrc::produce()
{
return mDetail->readBuffer();
}
bool RTSPClientSrc::validateOutputPins() {
//smallest check at least one output pin should be there
bool RTSPClientSrc::validateOutputPins()
{
// smallest check at least one output pin should be there
return this->getNumberOfOutputPins() > 0;
}
void RTSPClientSrc::notifyPlay(bool play) {}
bool RTSPClientSrc::handleCommand(Command::CommandType type, frame_sp& frame) { return true; }
bool RTSPClientSrc::handlePropsChange(frame_sp& frame) { return true; }
bool RTSPClientSrc::handlePropsChange(frame_sp& frame) { return true; }
Binary file added data/1714992199120.mp4
Binary file not shown.
10 changes: 10 additions & 0 deletions samples/cMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#dependencies

find_package(Threads REQUIRED)

include_directories(
../base
${CMAKE_CURRENT_SOURCE_DIR}
)

add_subdirectory(relay-sample)
53 changes: 53 additions & 0 deletions samples/relay-sample/cMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
set(TARGET relay-sample)
SET(CORE_FILES
relay_sample.cpp
)
SET(CORE_FILES_H
relay_sample.h
)
SET(SOURCE
${CORE_FILES}
${CORE_FILES_H}
)
set(UT_FILE
relay_sample_test.cpp
)
find_library(APRA_PIPES_LIB NAMES aprapipes)
add_library(example_aprapipes STATIC ${SOURCE})
add_executable(runner_test ${UT_FILE})
target_include_directories ( example_aprapipes PRIVATE
${JETSON_MULTIMEDIA_LIB_INCLUDE}
${FFMPEG_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${LIBMP4_INC_DIR}
${BARESIP_INC_DIR}
${LIBRE_INC_DIR}
${NVCODEC_INCLUDE_DIR}
)
target_include_directories ( runner_test PUBLIC
${JETSON_MULTIMEDIA_LIB_INCLUDE}
${FFMPEG_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${LIBMP4_INC_DIR}
${BARESIP_INC_DIR}
${LIBRE_INC_DIR}
${NVCODEC_INCLUDE_DIR}
)
target_link_libraries(
runner_test
aprapipes
${JPEG_LIBRARIES}
${LIBMP4_LIB}
${OPENH264_LIB}
${Boost_LIBRARIES}
${FFMPEG_LIBRARIES}
${OpenCV_LIBRARIES}
${JETSON_LIBS}
${NVCUDAToolkit_LIBS}
${NVCODEC_LIB}
${NVJPEGLIB_L4T}
${CURSES_LIBRARIES}
example_aprapipes
)
Loading