代码如下:
Video.h
#pragma once
#include <functional>
#include "VideoRecoder.h"
#include "ISMSSDK.h"
#include <Windows.h>
#include <future>
#include <queue>
class Video
{
public:
using Handler = std::function<void(const uint8_t*, size_t, const int width, const int height)>;
Video();
~Video();
void Start(const uint16_t width, const uint16_t height, uint16_t fps, void* handle);
void Stop();
void StartServerStream();
void StopServerStream();
static void _stdcall OnDecodeced(long lPlayHandle, const char* pDataArray, int iDataLen, int iWidth, int iHeight,
int iFrameType, int iTimeStamp, void* pUserData);
void OnImageArive(const char* data, size_t size, int iFrameType, const int width, const int height);
private:
using VideoRecoderPtr = std::unique_ptr<VideoRecoder>;
VideoRecoderPtr _recoder;
WindowDrawer _windowDrawer;
long _lPlayHandle;
Handler _recodeHandler;
Handler _decodeHandler;
uint16_t _width;
uint16_t _height;
uint16_t _fps;
void* _form;
};
video.cpp
#include "Video.h"
#include <iostream>
#include <fstream>
const char* g_ip = "xxx";
int port = 80;
const char* userName = "xxx";
const char* password = "xxx";
std::string uuid = "asd";
enStreamType streamType = enStreamType::TYPE_DEFAULT_STREAM;
namespace pl = std::placeholders;
void __stdcall StreamCallBack(long lPlayHnadle, ISMS_STREAM_DATA_TYPE_EN enStreamDataType, const char* pDataArray, int iDataLen, void* pUserData)
{
}
void __stdcall MessageCallBack(long lPlayHandle, int iMsg, void* pUserData)
{
}
Video::Video()
: _lPlayHandle(-1)
{
AllocConsole();
FILE *stream = nullptr;
freopen_s(&stream, "CONOUT$", "w", stdout);
if (ISMS_Init() != 0)
{
std::cout << "ISMS_init error" << std::endl;
return;
}
else
{
std::cout << "ISMS_init success" << std::endl;
}
if (0 != ISMS_Login(g_ip, port, userName, password))
{
std::cout << "ISMS_Login error" << std::endl;
return;
}
else
{
std::cout << "Login success" << std::endl;
}
_recoder = std::make_unique<VideoRecoder>();
}
Video::~Video()
{
}
void Video::Start(const uint16_t width, const uint16_t height, uint16_t fps, void* handle)
{
_windowDrawer.start(handle);
_width = width;
_height = height;
_fps = fps;
_recoder->setSetting(_width, _height, _fps);
StartServerStream();
}
void Video::Stop()
{
_windowDrawer.stop();
StopServerStream();
}
void Video::StartServerStream()
{
if (_lPlayHandle != -1)
{
ISMS_StopPreview(_lPlayHandle);
std::cout << "ISMS_StopPreview" << std::endl;
}
if (!uuid.empty())
{
_lPlayHandle = ISMS_StartPreviewEx(uuid.c_str(), nullptr, streamType, StreamCallBack, MessageCallBack, OnDecodeced, this);
std::cout << "ISMS_StartPreviewEx" << std::endl;
int count = 0;
while (_lPlayHandle < 0 && count < 5)
{
std::cout << "start stream error" << std::endl;
Sleep(1000);
_lPlayHandle = _lPlayHandle = ISMS_StartPreviewEx(uuid.c_str(), nullptr, streamType, StreamCallBack, MessageCallBack, OnDecodeced, this);
count++;
}
}
else
{
std::cout << "uuid is empty!!!!!!!!!!!" << std::endl;
}
}
void Video::StopServerStream()
{
ISMS_StopPreview(_lPlayHandle);
}
void Video::OnDecodeced(long lPlayHandle, const char* pDataArray, int iDataLen, int iWidth, int iHeight, int iFrameType, int iTimeStamp, void* pUserData)
{
Video* _this = reinterpret_cast<Video*>(pUserData);
_this->OnImageArive(
pDataArray,
iDataLen, iFrameType,
static_cast<uint16_t>(iWidth),
static_cast<uint16_t>(iHeight)
);
}
void Video::OnImageArive(const char* data, size_t size, int iFrameType, const int width, const int height)
{
_recoder->recode((uint8_t*)data, size, width, height);
}
videoRecoder.h
#pragma once
#include <cstdint>
#include <vector>
#include <thread>
#include <glib.h>
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
class VideoRecoder {
public:
VideoRecoder();
~VideoRecoder();
void setSetting(const uint16_t width, const uint16_t height, uint16_t fps);
void recode(const uint8_t* data, size_t size, const uint16_t width, const uint16_t height);
private:
GstElement* _pipeline;
GstElement* _source;
GstElement* _queue0;
GstElement* _convert;
GstElement* _scale;
GstElement* _rate;
GstElement* _capsfilter;
GstElement* _queue1;
GstElement* _encode;
GstElement* _parse;
GstElement* _queue2;
GstElement* _flvmu;
GstElement* _queue3;
GstElement* _sink;
};
VideoRecoder.cpp
#include "VideoRecoder.h"
#include <gst/app/gstappsrc.h>
#include <gst/video/video.h>
#include "Check.h"
#include <windows.h>
#include <iostream>
VideoRecoder::VideoRecoder() {
gst_init(nullptr, nullptr);
_pipeline = chk(gst_pipeline_new(nullptr));
_source = chk(gst_element_factory_make("appsrc", nullptr));
_queue0 = chk(gst_element_factory_make("queue", nullptr));
_convert = chk(gst_element_factory_make("videoconvert", nullptr));
_scale = chk(gst_element_factory_make("videoscale", nullptr));
_rate = chk(gst_element_factory_make("videorate", nullptr));
_capsfilter = chk(gst_element_factory_make("capsfilter", nullptr));
_queue1 = chk(gst_element_factory_make("queue", nullptr));
#ifdef USE_X264
_encode = chk(gst_element_factory_make("x264enc", nullptr));
#else
_encode = chk(gst_element_factory_make("openh264enc", nullptr));
#endif
_parse = chk(gst_element_factory_make("h264parse", nullptr));
_queue2 = chk(gst_element_factory_make("queue", nullptr));
_flvmu = chk(gst_element_factory_make("flvmux", nullptr));
_sink = chk(gst_element_factory_make("rtmpsink", nullptr));
g_object_set(_source, "is-live", true, "do-timestamp", true, "format", GST_FORMAT_TIME, NULL);
g_object_set(_queue0, "leaky", 2, NULL);
g_object_set(_queue1, "leaky", 2, NULL);
g_object_set(_queue2, "leaky", 2, NULL);
g_object_set(G_OBJECT(_sink), "location", "rtmp://hn.uniseas.com.cn:1935/hlxlive/stream", NULL);
gst_bin_add_many(GST_BIN(_pipeline), _source, _queue0, _convert, _scale, _rate, _capsfilter, _queue1, _encode, _parse, _queue2, _flvmu, _sink, NULL);
gst_element_link_many(_source, _queue0, _convert, _scale, _rate, _capsfilter, _queue1, _encode, _parse, _queue2, _flvmu, _sink, NULL);
gst_element_set_state(_pipeline, GST_STATE_PLAYING);
}
VideoRecoder::~VideoRecoder() {
gst_element_set_state(_pipeline, GST_STATE_NULL);
gst_object_unref(_pipeline);
}
void VideoRecoder::setSetting(const uint16_t width, const uint16_t height, uint16_t fps) {
GstCaps* caps = gst_caps_new_simple(
"video/x-raw",
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height,
"framerate", GST_TYPE_FRACTION, fps, 1,
NULL);
g_object_set(_capsfilter, "caps", caps, NULL);
gst_caps_unref(caps);
}
void VideoRecoder::recode(const uint8_t* data, size_t size, const uint16_t width, const uint16_t height) {
GstState state = GST_STATE_NULL;
GstState pending = GST_STATE_NULL;
gst_element_get_state(_pipeline, &state, &pending, 0);
if (state == GST_STATE_PLAYING || pending == GST_STATE_PLAYING) {
GstBuffer* buffer = gst_buffer_new_and_alloc(size);
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_WRITE);
memcpy(map.data, data, size);
gst_buffer_unmap(buffer, &map);
GstVideoInfo videoInfo;
gst_video_info_set_format(&videoInfo, GST_VIDEO_FORMAT_YV12, width, height);
GstCaps* caps = gst_video_info_to_caps(&videoInfo);
GstSample* sample = gst_sample_new(buffer, caps, nullptr, nullptr);
gst_caps_unref(caps);
gst_app_src_push_sample(GST_APP_SRC(_source), sample);
gst_buffer_unref(buffer);
gst_sample_unref(sample);
}
}
启动rtmp服务器nginx-rtmp-module(下载地址:https://download.csdn.net/download/qq_23350817/12680515):
nginx.exe -c conf/nginx-win.conf
打开vlc,输入rtmp地址:rtmp://127.0.0.1:1935/live/1播放