调整网络短视频实现

PtzNew
Matthew 3 months ago
parent d1298663f3
commit 6f56bf0fe3

@ -154,7 +154,7 @@ add_definitions(-DDISABLE_RTTI)
# include_directories( ${HDRPLUS_ROOT}/${ANDROID_ABI}/include/ZLToolKit/src/ ) # include_directories( ${HDRPLUS_ROOT}/${ANDROID_ABI}/include/ZLToolKit/src/ )
# SET(ZLMEDIAKIT_LIBS ${ZLMEDIAKIT_LIBS} zlmediakit zltoolkit) # SET(ZLMEDIAKIT_LIBS ${ZLMEDIAKIT_LIBS} zlmediakit zltoolkit)
SET(STREAMING_SRCS media/RTSPToMP4.cpp media/RTSPRecorder.cpp ) SET(STREAMING_SRCS media/RTSPToMP4.cpp media/RTSPRecorder.cpp media/Streaming.cpp )
SET(HDRPLUS_LIBS raw exiv2 exiv2-xmp expat lcms2 OpenMP::OpenMP_CXX) SET(HDRPLUS_LIBS raw exiv2 exiv2-xmp expat lcms2 OpenMP::OpenMP_CXX)

@ -9,6 +9,7 @@
#include "CvText.h" #include "CvText.h"
#include "PositionHelper.h" #include "PositionHelper.h"
#include "DngCreator.h" #include "DngCreator.h"
#include "media/Streaming.h"
#include "netcamera/VendorCtrl.h" #include "netcamera/VendorCtrl.h"
#include "netcamera/YuShiCtrl.h" #include "netcamera/YuShiCtrl.h"
@ -1775,7 +1776,7 @@ bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
std::string tmpFile = m_appPath + (APP_PATH_TMP DIR_SEP_STR) + std::to_string(localPhotoInfo.photoId) + ".mp4"; std::string tmpFile = m_appPath + (APP_PATH_TMP DIR_SEP_STR) + std::to_string(localPhotoInfo.photoId) + ".mp4";
// RTSPToMP4 dumper(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000); // RTSPToMP4 dumper(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000);
// dumper.start(); // dumper.start();
dumpRtspToMp4(streamingUrl.c_str(), tmpFile.c_str(), localPhotoInfo.duration * 1000); dumpRtspToMp4(streamingUrl.c_str(), tmpFile.c_str(), localPhotoInfo.duration * 1000, GetEthnetHandle());
ethernetPowerCtrl.reset(); ethernetPowerCtrl.reset();
XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power OFF"); XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power OFF");
@ -1803,8 +1804,92 @@ bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
return true; return true;
} }
bool CPhoneDevice::StartPushStreaming(IDevice::PHOTO_INFO& localPhotoInfo, const std::string& url, std::vector<IDevice::OSD_INFO>& osds, std::shared_ptr<PowerControl> powerCtrlPtr) bool CPhoneDevice::StartPushStreaming(IDevice::PHOTO_INFO& photoInfo, const std::string& url, std::vector<IDevice::OSD_INFO>& osds, std::shared_ptr<PowerControl> powerCtrlPtr)
{ {
#if 0
if (photoInfo.mediaType == XY_MEDIA_TYPE_STREAM)
{
std::map<uint8_t, std::shared_ptr<Streaming> >::iterator it = m_streamings.find(photoInfo.channel);
if (it != m_streamings.end())
{
it->second->stop();
it->second.reset();
m_streamings.erase(it);
}
NET_PHOTO_INFO netPhotoInfo = { 0, 0 };
if (photoInfo.vendor == 1)
{
// Hai Kang
netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST;
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/ISAPI/Streaming/channels/1/picture?");
}
else if (photoInfo.vendor == 2)
{
// Hang Yu
strcpy(netPhotoInfo.url, "/cgi-bin/snapshot.cgi");
}
else if (photoInfo.vendor == 3)
{
// Yu Shi
netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST;
int streamSid = 0; // should put into config
// rtsp://192.168.0.13:554/media/video1
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/media/video%u", (uint32_t)photoInfo.cameraId);
// strcpy(netPhotoInfo.url, "rtsp://192.168.50.224/live/0");
}
else if (photoInfo.vendor == 5)
{
// Hang Yu - New
netPhotoInfo.authType = HTTP_AUTH_TYPE_BASIC;
// http://192.168.1.46/Snapshot/%u/RemoteImageCapture?ImageFormat=2&HorizontalPixel=1920&VerticalPixel=1080
// http://192.168.1.101/Snapshot/1/2/RemoteImageCaptureV2?ImageFormat=jpg
// http://192.168.1.101/Snapshot/1/1/RemoteImageCaptureV2?ImageFormat=jpg
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/Snapshot/%u/1/RemoteImageCaptureV2?ImageFormat=jpg", (uint32_t)photoInfo.cameraId);
}
else
{
XYLOG(XYLOG_SEVERITY_ERROR, "Vendor(%u) not Supported CH=%u PR=%X PHOTOID=%u", (uint32_t)photoInfo.vendor, (uint32_t)photoInfo.channel, (unsigned int)photoInfo.preset, photoInfo.photoId);
TakePhotoCb(0, photoInfo, "", 0);
return false;
}
StreamForwarder* forwarder = new StreamForwarder();
m_streamings[photoInfo.channel] = std::shared_ptr<Streaming>((Streaming*)forwarder);
// Initialize with RTSP input and RTMP output
if (!forwarder->initialize(std::string(netPhotoInfo.url), url)) {
std::cerr << "Failed to initialize stream forwarder" << std::endl;
return -1;
}
// Optional: Set callback to process video frames
#if 0
forwarder->setFrameCallback([](uint8_t* data, int linesize, int width, int height) {
// Process frame data here
// Example: Add OSD overlay
});
#endif
// Start forwarding
forwarder->start();
// Wait for user input to stop
// std::cout << "Press Enter to stop streaming..." << std::endl;
// std::cin.get();
// forwarder.stop();
}
else if (photoInfo.mediaType == XY_MEDIA_TYPE_STREAM_OFF)
{
auto it = m_streamings.find(photoInfo.channel);
if (it != m_streamings.end())
{
it->second->stop();
it->second.reset();
m_streamings.erase(it);
}
}
#endif
return true; return true;
} }
@ -4949,4 +5034,4 @@ VendorCtrl* CPhoneDevice::MakeVendorCtrl(int vendor, uint8_t channel, const std:
vendorCtrl = new HangYuCtrl(ip, userName, password, channel, netHandle); vendorCtrl = new HangYuCtrl(ip, userName, password, channel, netHandle);
} }
return vendorCtrl; return vendorCtrl;
} }

@ -155,6 +155,7 @@ void MatToBitmap(JNIEnv *env, cv::Mat& mat, jobject& bitmap) {
class PowerControl; class PowerControl;
class VendorCtrl; class VendorCtrl;
class Streaming;
class CPhoneDevice : public IDevice class CPhoneDevice : public IDevice
{ {
@ -425,6 +426,8 @@ protected:
std::atomic<bool> m_collecting; std::atomic<bool> m_collecting;
unsigned long long localDelayTime; unsigned long long localDelayTime;
std::map<uint8_t, std::shared_ptr<Streaming> > m_streamings;
}; };

@ -6,6 +6,7 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <android/log.h> #include <android/log.h>
#include <errno.h>
extern "C" { extern "C" {
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
@ -21,15 +22,17 @@ extern "C" {
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration) void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle)
{ {
AVFormatContext* inputFormatContext = nullptr; AVFormatContext* inputFormatContext = nullptr;
AVFormatContext* outputFormatContext = nullptr; AVFormatContext* outputFormatContext = nullptr;
AVPacket packet; AVPacket packet;
AVDictionary *options = NULL;
av_register_all(); av_register_all();
avformat_network_init(); avformat_network_init();
// Open input RTMP stream // Open input RTMP stream
if (avformat_open_input(&inputFormatContext, rtmpUrl, nullptr, nullptr) != 0) { if (avformat_open_input(&inputFormatContext, rtmpUrl, nullptr, nullptr) != 0) {
fprintf(stderr, "Could not open input file '%s'\n", rtmpUrl); fprintf(stderr, "Could not open input file '%s'\n", rtmpUrl);
@ -126,28 +129,61 @@ void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duratio
} }
void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration) void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle)
{ {
AVFormatContext* inputFormatContext = nullptr; AVFormatContext* inputFormatContext = nullptr;
AVFormatContext* outputFormatContext = nullptr; AVFormatContext* outputFormatContext = nullptr;
AVPacket packet; AVPacket packet;
AVDictionary *options = NULL;
int res = 0;
av_register_all(); av_register_all();
avformat_network_init(); avformat_network_init();
// Set RTSP transport protocol option before opening
av_dict_set(&options, "rtsp_transport", "tcp", 0);
// Set custom socket options via protocol whitelist and options
inputFormatContext->protocol_whitelist = av_strdup("file,udp,rtp,tcp,rtsp");
// Open input RTSP stream // Open input RTSP stream
if (avformat_open_input(&inputFormatContext, rtspUrl, nullptr, nullptr) != 0) { if (avformat_open_input(&inputFormatContext, rtspUrl, nullptr, nullptr) != 0) {
fprintf(stderr, "Could not open input file '%s'\n", rtspUrl); // fprintf(stderr, "Could not open input file '%s'\n", rtspUrl);
return; return;
} }
// Retrieve input stream information // Retrieve input stream information
if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) { if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
fprintf(stderr, "Could not find stream information\n"); // fprintf(stderr, "Could not find stream information\n");
avformat_close_input(&inputFormatContext); avformat_close_input(&inputFormatContext);
return; return;
} }
// Get socket file descriptor
if (NETWORK_UNSPECIFIED != netHandle)
{
int fd = -1;
if (inputFormatContext->pb) {
AVIOContext *io_ctx = inputFormatContext->pb;
// const char *url = io_ctx->filename;
// You can access socket options using av_opt API
res = av_opt_get_int(io_ctx, "fd", AV_OPT_SEARCH_CHILDREN, (int64_t*)&fd);
if (res >= 0 && fd >= 0) {
// printf("Socket file descriptor: %d\n", fd);
int res = android_setsocknetwork(netHandle, fd);
if (res == -1)
{
int errcode = errno;
// printf("android_setsocknetwork errno=%d", errcode);
// XYLOG(XYLOG_SEVERITY_ERROR,"setsocknetwork -1, errcode=%d",errcode);
}
}
}
}
// Open output MP4 file // Open output MP4 file
if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) { if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) {
fprintf(stderr, "Could not create output context\n"); fprintf(stderr, "Could not create output context\n");

@ -6,10 +6,11 @@
#define MICROPHOTO_RTSPRECORDER_H #define MICROPHOTO_RTSPRECORDER_H
#include <string> #include <string>
#include <android/multinetwork.h>
// void dumpRtspToMp4(const std::string &rtspUrl, const std::string &outputPath, uint32_t durationInMs); // void dumpRtspToMp4(const std::string &rtspUrl, const std::string &outputPath, uint32_t durationInMs);
void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration); void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle);
void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration); void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle);
class RTSPRecorder { class RTSPRecorder {

@ -0,0 +1,159 @@
//
// Created by Matthew on 2025/3/11.
//
#include "Streaming.h"
#include <android/api-level.h>
#include <android/log.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#if 0
StreamForwarder::~StreamForwarder() {
stop();
if (inputCtx) {
avformat_close_input(&inputCtx);
}
if (outputCtx) {
if (outputCtx->pb) {
avio_closep(&outputCtx->pb);
}
avformat_free_context(outputCtx);
}
}
bool StreamForwarder::initialize(const std::string& inputUrl, const std::string& outputUrl) {
if (!openInput(inputUrl)) {
return false;
}
if (!openOutput(outputUrl)) {
return false;
}
return true;
}
bool StreamForwarder::openInput(const std::string& inputUrl) {
inputCtx = avformat_alloc_context();
if (!inputCtx) {
return false;
}
if (avformat_open_input(&inputCtx, inputUrl.c_str(), nullptr, nullptr) < 0) {
return false;
}
if (avformat_find_stream_info(inputCtx, nullptr) < 0) {
return false;
}
return true;
}
bool StreamForwarder::openOutput(const std::string& outputUrl) {
int ret = avformat_alloc_output_context2(&outputCtx, nullptr, "flv", outputUrl.c_str());
if (ret < 0) {
return false;
}
// Copy streams from input to output
for (unsigned int i = 0; i < inputCtx->nb_streams; i++) {
AVStream* inStream = inputCtx->streams[i];
AVStream* outStream = avformat_new_stream(outputCtx, inStream->codec->codec);
if (!outStream) {
return false;
}
ret = avcodec_copy_context(outStream->codec, inStream->codec);
if (ret < 0) {
return false;
}
}
// Open output file
if (!(outputCtx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&outputCtx->pb, outputUrl.c_str(), AVIO_FLAG_WRITE);
if (ret < 0) {
return false;
}
}
// Write header
ret = avformat_write_header(outputCtx, nullptr);
if (ret < 0) {
return false;
}
return true;
}
void StreamForwarder::setFrameCallback(std::function<void(uint8_t*, int, int, int)> callback) {
frameCallback = callback;
}
void StreamForwarder::start() {
isRunning = true;
forwardPackets();
}
void StreamForwarder::stop() {
isRunning = false;
}
void StreamForwarder::forwardPackets() {
AVPacket packet;
AVFrame* frame = av_frame_alloc();
while (isRunning) {
if (av_read_frame(inputCtx, &packet) < 0) {
break;
}
// Process video frames if callback is set
if (frameCallback && packet.stream_index == 0) { // Assuming video is stream 0
AVCodecContext* codecCtx = inputCtx->streams[packet.stream_index]->codec;
int ret = avcodec_send_packet(codecCtx, &packet);
if (ret < 0) {
continue;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codecCtx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
goto end;
}
processFrame(frame);
}
}
// Forward packet
av_packet_rescale_ts(&packet,
inputCtx->streams[packet.stream_index]->time_base,
outputCtx->streams[packet.stream_index]->time_base);
int ret = av_interleaved_write_frame(outputCtx, &packet);
if (ret < 0) {
break;
}
av_packet_unref(&packet);
}
end:
av_frame_free(&frame);
av_write_trailer(outputCtx);
}
void StreamForwarder::processFrame(AVFrame* frame) {
if (frameCallback) {
frameCallback(frame->data[0], frame->linesize[0],
frame->width, frame->height);
}
}
#endif

@ -0,0 +1,50 @@
//
// Created by Matthew on 2025/3/11.
//
#ifndef MICROPHOTO_STREAMING_H
#define MICROPHOTO_STREAMING_H
#include <string>
#include <memory>
#include <android/multinetwork.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
}
class Streaming
{
public:
virtual ~Streaming() {}
virtual void start() {}
virtual void stop() {}
};
#if 0
class StreamForwarder : public Streaming
{
private:
AVFormatContext* inputCtx = nullptr;
AVFormatContext* outputCtx = nullptr;
bool isRunning = false;
public:
StreamForwarder() = default;
virtual ~StreamForwarder();
bool initialize(const std::string& inputUrl, const std::string& outputUrl);
virtual void start();
virtual void stop();
private:
bool openInput(const std::string& inputUrl);
bool openOutput(const std::string& outputUrl);
void forwardPackets();
};
#endif
#endif //MICROPHOTO_STREAMING_H
Loading…
Cancel
Save