mirror of
https://github.com/sipeed/MaixCDK.git
synced 2026-09-11 06:09:42 -05:00
* update rtmp & rtmp demo
This commit is contained in:
@@ -129,6 +129,12 @@ namespace maix::sys
|
||||
*/
|
||||
std::vector<std::map<std::string, std::string>> disk_partitions(bool only_disk = true);
|
||||
|
||||
/**
|
||||
* register default signal handle
|
||||
* @maixpy maix.sys.register_default_signal_handle
|
||||
*/
|
||||
void register_default_signal_handle();
|
||||
|
||||
/**
|
||||
* Power off device
|
||||
* @maixpy maix.sys.poweroff
|
||||
|
||||
22
components/basic/port/linux/maix_sys_linux.cpp
Normal file
22
components/basic/port/linux/maix_sys_linux.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "maix_util.hpp"
|
||||
#include "maix_app.hpp"
|
||||
#include "signal.h"
|
||||
|
||||
namespace maix::sys
|
||||
{
|
||||
static void signal_handle(int signal)
|
||||
{
|
||||
const char *signal_msg = NULL;
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
maix::app::set_exit_flag(true);
|
||||
raise(SIGINT);
|
||||
break;
|
||||
default: signal_msg = "UNKNOWN"; break;
|
||||
}
|
||||
}
|
||||
|
||||
void register_default_signal_handle() {
|
||||
signal(SIGILL, signal_handle);
|
||||
}
|
||||
}
|
||||
22
components/basic/port/maixcam/maix_sys_maixcam.cpp
Normal file
22
components/basic/port/maixcam/maix_sys_maixcam.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "maix_sys.hpp"
|
||||
#include "maix_app.hpp"
|
||||
#include "signal.h"
|
||||
|
||||
namespace maix::sys
|
||||
{
|
||||
static void signal_handle(int signal)
|
||||
{
|
||||
const char *signal_msg = NULL;
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
maix::app::set_exit_flag(true);
|
||||
raise(SIGINT);
|
||||
break;
|
||||
default: signal_msg = "UNKNOWN"; break;
|
||||
}
|
||||
}
|
||||
|
||||
void register_default_signal_handle() {
|
||||
signal(SIGILL, signal_handle);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,11 @@ if(CONFIG_MAIXCAM_LIB_COMPILE_FROM_SOURCE)
|
||||
append_srcs_dir(ADD_SRCS "${source_dir}/nn")
|
||||
list(APPEND ADD_REQUIREMENTS cvi_tpu)
|
||||
|
||||
# media_server
|
||||
append_srcs_dir(ADD_SRCS "${source_dir}/media_server")
|
||||
list(APPEND ADD_REQUIREMENTS media_server)
|
||||
|
||||
# middleware
|
||||
set(middleware_include_dir .
|
||||
${middleware_src_path}/v2/component/panel/${CONFIG_SOPHGO_MIDDLEWARE_CHIP}
|
||||
${middleware_src_path}/v2/include
|
||||
|
||||
23
components/maixcam_lib/include/maix_avc2flv.h
Normal file
23
components/maixcam_lib/include/maix_avc2flv.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef __MAIX_AVC2FLV
|
||||
#define __MAIX_AVC2FLV
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "stdint.h"
|
||||
|
||||
int maix_avc2flv_init(int max_buff_size);
|
||||
int maix_avc2flv_deinit();
|
||||
int maix_avc2flv_prepare(uint8_t *data, int data_size);
|
||||
int maix_avc2flv_iterate(void **nalu, int *size);
|
||||
int maix_avc2flv(void *nalu, int nalu_size, uint32_t pts, uint32_t dts, uint8_t **flv, int *flv_size);
|
||||
|
||||
// need free data after used
|
||||
int maix_flv_get_tail(uint8_t **data, int *size);
|
||||
// need free data after used
|
||||
int maix_flv_get_header(int audio, int video, uint8_t **data, int *size);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __MAIX_AVC2FLV
|
||||
@@ -10,12 +10,29 @@
|
||||
|
||||
#include "maix_basic.hpp"
|
||||
#include "maix_camera.hpp"
|
||||
#include "maix_video.hpp"
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* @brief maix.rtmp module
|
||||
* @maixpy maix.rtmp
|
||||
*/
|
||||
namespace maix::rtmp
|
||||
{
|
||||
/**
|
||||
* Video type
|
||||
* @maixpy maix.rtmp.TagType
|
||||
*/
|
||||
enum TagType
|
||||
{
|
||||
TAG_NONE,
|
||||
TAG_VIDEO,
|
||||
TAG_AUDIO,
|
||||
TAG_SCRIPT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Rtmp class
|
||||
* @maixpy maix.rtmp.Rtmp
|
||||
@@ -25,15 +42,20 @@ namespace maix::rtmp
|
||||
std::string _app;
|
||||
std::string _stream;
|
||||
int _port;
|
||||
int _bitrate;
|
||||
|
||||
int _socket;
|
||||
void *_handler;
|
||||
|
||||
camera::Camera *_cam;
|
||||
camera::Camera *_camera;
|
||||
thread::Thread *_thread;
|
||||
thread::Thread *_push_thread;
|
||||
thread::Thread *_app_thread;
|
||||
pthread_mutex_t _lock;
|
||||
bool _start;
|
||||
std::string _path;
|
||||
image::Image *_capture_image;
|
||||
bool _need_capture;
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Video object
|
||||
@@ -45,29 +67,39 @@ namespace maix::rtmp
|
||||
* @param port rtmp port, default is 1935.
|
||||
* @param app rtmp app name
|
||||
* @param stream rtmp stream name
|
||||
* @param bitrate rtmp bitrate, default is 1000 * 1000
|
||||
* @maixpy maix.rtmp.Rtmp.__init__
|
||||
* @maixcdk maix.rtmp.Rtmp.Rtmp
|
||||
*/
|
||||
Rtmp(std::string host, int port = 1935, std::string app = std::string(), std::string stream = std::string());
|
||||
Rtmp(std::string host = "localhost", int port = 1935, std::string app = std::string(), std::string stream = std::string(), int bitrate = 1000 * 1000);
|
||||
~Rtmp();
|
||||
|
||||
/**
|
||||
* @brief Get bitrate
|
||||
* @return bitrate
|
||||
* @maixpy maix.rtmp.Rtmp.push_video
|
||||
*/
|
||||
int bitrate() {
|
||||
return _bitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Push rtmp video data
|
||||
* @return error code, err::ERR_NONE means success, others means failed
|
||||
* @return return 0 ok, other error
|
||||
* @maixcdk maix.rtmp.Rtmp.push_video
|
||||
*/
|
||||
int push_video(void *data, size_t data_size, uint32_t timestamp);
|
||||
|
||||
/**
|
||||
* @brief Push rtmp audio data
|
||||
* @return error code, err::ERR_NONE means success, others means failed
|
||||
* @return return 0 ok, other error
|
||||
* @maixcdk maix.rtmp.Rtmp.push_audio
|
||||
*/
|
||||
int push_audio(void *data, size_t data_size, uint32_t timestamp);
|
||||
|
||||
/**
|
||||
* @brief Push rtmp script data
|
||||
* @return error code, err::ERR_NONE means success, others means failed
|
||||
* @return return 0 ok, other error
|
||||
* @maixcdk maix.rtmp.Rtmp.push_script
|
||||
*/
|
||||
int push_script(void *data, size_t data_size, uint32_t timestamp);
|
||||
@@ -80,10 +112,56 @@ namespace maix::rtmp
|
||||
* @maixpy maix.rtmp.Rtmp.bind_camera
|
||||
*/
|
||||
err::Err bind_camera(camera::Camera *cam) {
|
||||
_cam = cam;
|
||||
_camera = cam;
|
||||
return err::ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If you bind a camera, return the camera object.
|
||||
* @return Camera object
|
||||
* @maixpy maix.rtmp.Rtmp.get_camera
|
||||
*/
|
||||
camera::Camera *get_camera() {
|
||||
return _camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If you bind a camera, capture the image of the camera
|
||||
* @note The return value may be null, you must check whether the return value is null
|
||||
* @return Image object
|
||||
* @maixcdk maix.rtmp.Rtmp.capture
|
||||
*/
|
||||
image::Image *capture() {
|
||||
err::check_raise(err::ERR_NOT_IMPL, "not support now!");
|
||||
// lock(300);
|
||||
// if (!_capture_image || !_capture_image->data()) {
|
||||
// unlock();
|
||||
// return NULL;
|
||||
// }
|
||||
// image::Image *new_image = new image::Image(_capture_image->width(), _capture_image->height(), _capture_image->format(),
|
||||
// (uint8_t *)_capture_image->data(), _capture_image->data_size(), false);
|
||||
// unlock();
|
||||
// return new_image;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get pointer of capture image
|
||||
* @return Image object
|
||||
*/
|
||||
image::Image *get_capture_image() {
|
||||
return _capture_image;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set pointer of capture image
|
||||
* @return Image object
|
||||
*/
|
||||
image::Image *set_capture_image(void *img) {
|
||||
_capture_image = (image::Image *)img;
|
||||
return _capture_image;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start push stream
|
||||
* @note only support flv file now
|
||||
@@ -94,7 +172,7 @@ namespace maix::rtmp
|
||||
err::Err start(std::string path = std::string());
|
||||
|
||||
/**
|
||||
* @brief Stop push
|
||||
* @brief Stop push stream
|
||||
* @return error code, err::ERR_NONE means success, others means failed
|
||||
* @maixpy maix.rtmp.Rtmp.stop
|
||||
*/
|
||||
@@ -132,6 +210,15 @@ namespace maix::rtmp
|
||||
bool is_started() {
|
||||
return _start ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get handler
|
||||
* @note DO NOT ADD TO MAIXPY
|
||||
* @return rtmp handler
|
||||
*/
|
||||
void *get_handler() {
|
||||
return _handler;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace maix::camera
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->buffer_num = buff_num;
|
||||
this->ch = -1;
|
||||
|
||||
if (0 != mmf_init()) {
|
||||
err::check_raise(err::ERR_RUNTIME, "mmf init failed");
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
#include "maix_rtmp.hpp"
|
||||
|
||||
#include "maix_video.hpp"
|
||||
#include "sophgo_middleware.hpp"
|
||||
#include <stdio.h>
|
||||
#include "sockutil.h"
|
||||
#include "sys/system.h"
|
||||
#include "rtmp-client.h"
|
||||
#include "flv-reader.h"
|
||||
#include "flv-writer.h"
|
||||
#include "flv-header.h"
|
||||
#include "flv-proto.h"
|
||||
#include "maix_avc2flv.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#define MMF_VENC_CHN 1
|
||||
#define AAC_ADTS_HEADER_SIZE 7
|
||||
#define FLV_TAG_HEAD_LEN 11
|
||||
#define FLV_PRE_TAG_LEN 4
|
||||
|
||||
static int rtmp_client_send(void* param, const void* header, size_t len, const void* data, size_t bytes)
|
||||
{
|
||||
socket_t* socket = (socket_t*)param;
|
||||
@@ -22,12 +32,74 @@ static int rtmp_client_send(void* param, const void* header, size_t len, const v
|
||||
return socket_send_v_all_by_time(*socket, vec, bytes > 0 ? 2 : 1, 0, 5000);
|
||||
}
|
||||
|
||||
static uint8_t* h264_startcode(uint8_t* data, size_t bytes)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 2; i + 1 < bytes; i++)
|
||||
{
|
||||
if (0x01 == data[i] && 0x00 == data[i - 1] && 0x00 == data[i - 2])
|
||||
return data + i + 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int maix_rtmp_client_push_h264(rtmp_client_t *client, struct flv_vec_t *vec, int num, uint32_t timestamp)
|
||||
{
|
||||
int tmp_offset = 0;
|
||||
int tmp_max_size = 256 * 1024;
|
||||
uint8_t *tmp = (uint8_t *)malloc(tmp_max_size);
|
||||
if (!tmp) return -1;
|
||||
|
||||
for (int i = 0; i < num; i ++) {
|
||||
uint8_t *nalu = h264_startcode((uint8_t *)vec[i].ptr, vec[i].len);
|
||||
uint8_t *raw = (uint8_t *)vec[i].ptr;
|
||||
int raw_size = (uint8_t *)vec[i].ptr + vec[i].len - raw;
|
||||
uint8_t nalutype = nalu[0] & 0x1f;
|
||||
if (nalutype == 0x7 || nalutype == 0x8 || nalutype == 6) {
|
||||
if (tmp_offset + raw_size > tmp_max_size) return -1;
|
||||
memcpy(tmp + tmp_offset, raw, raw_size);
|
||||
tmp_offset += raw_size;
|
||||
|
||||
} else if (nalutype == 0x5 || nalutype == 0x1) {
|
||||
if (tmp_offset + raw_size > tmp_max_size) return -1;
|
||||
memcpy(tmp + tmp_offset, raw, raw_size);
|
||||
tmp_offset += raw_size;
|
||||
|
||||
uint8_t *flv;
|
||||
int flv_size;
|
||||
if (0 != maix_avc2flv(tmp, tmp_offset, timestamp, timestamp, &flv, &flv_size)) {
|
||||
printf("maix_avc2flv failed!\r\n");
|
||||
return -1;
|
||||
}
|
||||
// printf("tmp_offset:%d flv:%p flv_size:%d timestamp:%d\r\n", tmp_offset, flv, flv_size, timestamp);
|
||||
free(tmp);
|
||||
uint8_t *flv_next = flv;
|
||||
while (1) {
|
||||
if (flv_next >= (flv + flv_size)) break;
|
||||
struct flv_tag_header_t tag_header = {0};
|
||||
flv_tag_header_read(&tag_header, flv_next, FLV_TAG_HEAD_LEN);
|
||||
|
||||
// printf("flv:%p flv_next:%p tag len:%d timestamp:%d\r\n", flv, flv_next, tag_header.size, timestamp);
|
||||
|
||||
rtmp_client_push_video(client, flv + FLV_TAG_HEAD_LEN, tag_header.size, timestamp);
|
||||
flv_next += FLV_PRE_TAG_LEN + FLV_TAG_HEAD_LEN + tag_header.size;
|
||||
}
|
||||
|
||||
tmp_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace maix::rtmp {
|
||||
Rtmp::Rtmp(std::string host, int port, std::string app, std::string stream) {
|
||||
Rtmp::Rtmp(std::string host, int port, std::string app, std::string stream, int bitrate) {
|
||||
_host = host;
|
||||
_port = port;
|
||||
_app = app;
|
||||
_stream = stream;
|
||||
_bitrate = bitrate;
|
||||
|
||||
char packet[20 * 1024];
|
||||
snprintf(packet, sizeof(packet), "rtmp://%s/%s", host.c_str(), app.c_str()); // tcurl
|
||||
@@ -49,7 +121,7 @@ namespace maix::rtmp {
|
||||
{
|
||||
int res = rtmp_client_input(rtmp, packet, r);
|
||||
if (res != 0) {
|
||||
throw std::runtime_error("rtmp_client_input failed!");
|
||||
throw std::runtime_error("rtmp client init failed!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,18 +129,33 @@ namespace maix::rtmp {
|
||||
throw std::runtime_error("create lock failed!");
|
||||
}
|
||||
|
||||
if (0 != mmf_init()) {
|
||||
err::check_raise(err::ERR_RUNTIME, "init mmf failed!");
|
||||
}
|
||||
|
||||
_handler = rtmp;
|
||||
_thread = nullptr;
|
||||
_cam = nullptr;
|
||||
_push_thread = nullptr;
|
||||
_app_thread = nullptr;
|
||||
_camera = nullptr;
|
||||
_start = false;
|
||||
_capture_image = nullptr;
|
||||
_need_capture = false;
|
||||
_path = std::string();
|
||||
}
|
||||
|
||||
Rtmp::~Rtmp() {
|
||||
if (_start) {
|
||||
stop();
|
||||
}
|
||||
|
||||
rtmp_client_t* rtmp = (rtmp_client_t *)_handler;
|
||||
rtmp_client_destroy(rtmp);
|
||||
socket_close(_socket);
|
||||
socket_cleanup();
|
||||
|
||||
mmf_deinit();
|
||||
|
||||
pthread_mutex_destroy(&_lock);
|
||||
}
|
||||
|
||||
@@ -196,6 +283,185 @@ namespace maix::rtmp {
|
||||
}
|
||||
}
|
||||
|
||||
static void _push_camera_thread(void *args) {
|
||||
Rtmp *rtmp = (Rtmp *)args;
|
||||
rtmp->lock(-1);
|
||||
camera::Camera *camera = rtmp->get_camera();
|
||||
rtmp_client_t *client = (rtmp_client_t *)rtmp->get_handler();
|
||||
rtmp->unlock();
|
||||
|
||||
uint32_t stream_size = 0;
|
||||
uint32_t timestamp = 0;
|
||||
uint64_t curr_ms = time::time_ms();
|
||||
uint64_t last_ms = curr_ms;
|
||||
|
||||
bool first_frame = 1;
|
||||
|
||||
mmf_venc_cfg_t cfg = {
|
||||
.type = 2, //1, h265, 2, h264
|
||||
.w = camera->width(),
|
||||
.h = camera->height(),
|
||||
.fmt = mmf_invert_format_to_mmf(image::Format::FMT_YVU420SP),
|
||||
.jpg_quality = 0, // unused
|
||||
.gop = 50,
|
||||
.intput_fps = 30,
|
||||
.output_fps = 30,
|
||||
.bitrate = rtmp->bitrate() / 1000,
|
||||
};
|
||||
|
||||
|
||||
if (0 != mmf_add_venc_channel(MMF_VENC_CHN, &cfg)) {
|
||||
err::check_raise(err::ERR_RUNTIME, "mmf venc init failed!");
|
||||
}
|
||||
|
||||
if (0 != maix_avc2flv_init(rtmp->bitrate() / 2)) {
|
||||
err::check_raise(err::ERR_RUNTIME, "maix avc2flv init failed!");
|
||||
}
|
||||
while (1) {
|
||||
rtmp->lock(-1);
|
||||
if (!rtmp->is_started()) {
|
||||
rtmp->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
int vi_ch = camera->get_channel();
|
||||
void *data;
|
||||
int data_size, width, height, format;
|
||||
do {
|
||||
mmf_h265_stream_t stream = {0};
|
||||
if (mmf_venc_pop(MMF_VENC_CHN, &stream)) {
|
||||
log::error("mmf_venc_pop failed\n");
|
||||
mmf_venc_free(MMF_VENC_CHN);
|
||||
mmf_del_venc_channel(MMF_VENC_CHN);
|
||||
rtmp->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
flv_vec_t vec[8];
|
||||
for (int i = 0; i < stream.count; i ++) {
|
||||
vec[i].ptr = stream.data[i];
|
||||
vec[i].len = stream.data_size[i];
|
||||
stream_size += stream.data_size[i];
|
||||
}
|
||||
|
||||
if (first_frame) {
|
||||
last_ms = time::time_ms();
|
||||
timestamp = 0;
|
||||
first_frame = false;
|
||||
}
|
||||
|
||||
if (0 != maix_rtmp_client_push_h264(client, vec, stream.count, timestamp)) {
|
||||
printf("rtmp push failed!\r\n");
|
||||
}
|
||||
|
||||
if (mmf_venc_free(MMF_VENC_CHN)) {
|
||||
printf("mmf_venc_free failed\n");
|
||||
mmf_del_venc_channel(MMF_VENC_CHN);
|
||||
rtmp->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
if (mmf_vi_frame_pop(vi_ch, &data, &data_size, &width, &height, &format)) {
|
||||
log::info("camera read image timeout!\r\n");
|
||||
rtmp->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
curr_ms = time::time_ms();
|
||||
timestamp = curr_ms - last_ms;
|
||||
|
||||
if (data_size > 2560 * 1440 * 3 / 2) {
|
||||
log::error("image is too large!\r\n");
|
||||
rtmp->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
if (rtmp->get_camera()) {
|
||||
image::Image *_capture_image = rtmp->get_capture_image();
|
||||
if (_capture_image && _capture_image->data()) {
|
||||
delete _capture_image;
|
||||
rtmp->set_capture_image(NULL);
|
||||
}
|
||||
|
||||
image::Format capture_format = (image::Format)mmf_invert_format_to_maix(format);
|
||||
bool need_align = (width % mmf_vi_aligned_width(vi_ch) == 0) ? false : true; // Width need align only
|
||||
switch (capture_format) {
|
||||
case image::Format::FMT_BGR888: // fall through
|
||||
case image::Format::FMT_RGB888:
|
||||
{
|
||||
_capture_image = rtmp->set_capture_image(new image::Image(width, height, capture_format));
|
||||
uint8_t * image_data = (uint8_t *)_capture_image->data();
|
||||
if (need_align) {
|
||||
for (int h = 0; h < height; h++) {
|
||||
memcpy((uint8_t *)image_data + h * width * 3, (uint8_t *)data + h * width * 3, width * 3);
|
||||
}
|
||||
} else {
|
||||
memcpy(image_data, data, width * height * 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case image::Format::FMT_YVU420SP:
|
||||
{
|
||||
_capture_image = rtmp->set_capture_image(new image::Image(width, height, capture_format));
|
||||
uint8_t * image_data = (uint8_t *)_capture_image->data();
|
||||
if (need_align) {
|
||||
for (int h = 0; h < height * 3 / 2; h ++) {
|
||||
memcpy((uint8_t *)image_data + h * width, (uint8_t *)data + h * width, width);
|
||||
}
|
||||
} else {
|
||||
memcpy(image_data, data, width * height * 3 / 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
rtmp->set_capture_image(NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mmf_venc_cfg_t cfg = {0};
|
||||
if (0 != mmf_venc_get_cfg(MMF_VENC_CHN, &cfg)) {
|
||||
err::check_raise(err::ERR_RUNTIME, "get venc config failed!\r\n");
|
||||
}
|
||||
|
||||
int img_w = width;
|
||||
int img_h = height;
|
||||
int mmf_fmt = format;
|
||||
if (img_w != cfg.w
|
||||
|| img_h != cfg.h
|
||||
|| mmf_fmt != cfg.fmt) {
|
||||
log::warn("image size or format is incorrect, try to reinit venc!\r\n");
|
||||
mmf_del_venc_channel(MMF_VENC_CHN);
|
||||
cfg.w = img_w;
|
||||
cfg.h = img_h;
|
||||
cfg.fmt = mmf_invert_format_to_mmf(mmf_fmt);
|
||||
if (0 != mmf_add_venc_channel(MMF_VENC_CHN, &cfg)) {
|
||||
err::check_raise(err::ERR_RUNTIME, "mmf venc init failed!\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (mmf_venc_push(MMF_VENC_CHN, (uint8_t *)data, width, height, format)) {
|
||||
mmf_del_venc_channel(MMF_VENC_CHN);
|
||||
rtmp->unlock();
|
||||
err::check_raise(err::ERR_RUNTIME, "mmf venc push failed!\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
mmf_vi_frame_free(vi_ch);
|
||||
} while (stream_size == 0 && rtmp->is_started());
|
||||
rtmp->unlock();
|
||||
}
|
||||
|
||||
maix_avc2flv_deinit();
|
||||
|
||||
if (0 != mmf_del_venc_channel(MMF_VENC_CHN)) {
|
||||
err::check_raise(err::ERR_RUNTIME, "mmf venc init failed!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err::Err Rtmp::lock(uint32_t time) {
|
||||
uint32_t count = 0;
|
||||
while (0 != pthread_mutex_trylock(&_lock)) {
|
||||
@@ -222,12 +488,14 @@ namespace maix::rtmp {
|
||||
err::Err Rtmp::start(std::string path) {
|
||||
lock(-1);
|
||||
if (_start == true) {
|
||||
unlock();
|
||||
return err::ERR_BUSY;
|
||||
}
|
||||
|
||||
if (path.size() > 0) {
|
||||
if (fs::splitext(path) != ".flv") {
|
||||
log::error("check file path failed!\r\n");
|
||||
unlock();
|
||||
return err::ERR_RUNTIME;
|
||||
}
|
||||
|
||||
@@ -236,13 +504,18 @@ namespace maix::rtmp {
|
||||
_thread = new thread::Thread(_push_file_thread, this);
|
||||
if (this->_thread == NULL) {
|
||||
log::error("create camera thread failed!\r\n");
|
||||
unlock();
|
||||
return err::ERR_RUNTIME;
|
||||
}
|
||||
} else {
|
||||
if (_cam == nullptr) {
|
||||
log::error("you need bind camera first!\r\n");
|
||||
_start = true;
|
||||
_app_thread = new thread::Thread(_push_camera_thread, this);
|
||||
if (this->_app_thread == NULL) {
|
||||
log::error("create camera thread failed!\r\n");
|
||||
unlock();
|
||||
return err::ERR_RUNTIME;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unlock();
|
||||
@@ -250,12 +523,23 @@ namespace maix::rtmp {
|
||||
}
|
||||
|
||||
err::Err Rtmp::stop() {
|
||||
lock(-1);
|
||||
_start = false;
|
||||
unlock();
|
||||
|
||||
_thread->join();
|
||||
_thread = nullptr;
|
||||
if (_thread) {
|
||||
_thread->join();
|
||||
_thread = nullptr;
|
||||
}
|
||||
|
||||
if (_push_thread) {
|
||||
_push_thread->join();
|
||||
_push_thread = nullptr;
|
||||
}
|
||||
|
||||
if (_app_thread) {
|
||||
_app_thread->join();
|
||||
_app_thread = nullptr;
|
||||
}
|
||||
|
||||
return err::ERR_NONE;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,12 @@ namespace maix::image
|
||||
if (_format == image::FMT_GRAYSCALE) {
|
||||
convert_to_imlib_image(this, &src_img);
|
||||
} else {
|
||||
gray_img = this->to_format(image::FMT_GRAYSCALE);
|
||||
if (image::FMT_YVU420SP == _format) {
|
||||
gray_img = new image::Image(_width, _height, image::FMT_GRAYSCALE);
|
||||
memcpy(gray_img->data(), _data, _width * _height);
|
||||
} else {
|
||||
gray_img = this->to_format(image::FMT_GRAYSCALE);
|
||||
}
|
||||
convert_to_imlib_image(gray_img, &src_img);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ static int helper(void)
|
||||
printf( "========================\r\n"
|
||||
"Intput param:\r\n"
|
||||
"0 <host> <app> <stream> <file> : rtmp client, push file\r\n"
|
||||
" example: ./test_media_server 0 192.168.0.30 myapp stream ./test.flv"
|
||||
"1 <host> <app> <stream> : rtmp client, push camera image\r\n"
|
||||
" example: ./rtmp_demo 0 192.168.0.30 myapp stream ./test.flv\r\n"
|
||||
"1 <host> <port> <app> <stream> <bitrate>: rtmp client, push camera image\r\n"
|
||||
" example: ./rtmp_demo 1 192.168.0.30 1935 live stream 10000000\r\n"
|
||||
"========================\r\n");
|
||||
fflush(stdin);
|
||||
return 0;
|
||||
@@ -63,6 +64,42 @@ int _main(int argc, char* argv[])
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (argc < 6) {
|
||||
helper();
|
||||
break;
|
||||
}
|
||||
std::string host = argv[2];
|
||||
int port = atoi(argv[3]);
|
||||
std::string app = argv[4];
|
||||
std::string stream = argv[5];
|
||||
int bitrate = 1000 * 1000;
|
||||
if (argc > 6) bitrate = atoi(argv[6]);
|
||||
printf("push rtmp://%s:%d/%s/%s!\r\n", &host[0], port, &app[0], &stream[0]);
|
||||
|
||||
camera::Camera cam = camera::Camera(1280, 720, image::Format::FMT_YVU420SP);
|
||||
display::Display disp = display::Display();
|
||||
rtmp::Rtmp rtmp = rtmp::Rtmp(host, port, app, stream, bitrate);
|
||||
|
||||
rtmp.bind_camera(&cam);
|
||||
|
||||
log::info("start\r\n");
|
||||
rtmp.start();
|
||||
while (!app::need_exit()) {
|
||||
// image::Image *img = rtmp.capture(); // not support now
|
||||
|
||||
// if (img) {
|
||||
// disp.show(*img);
|
||||
// delete img;
|
||||
// }
|
||||
sleep(1);
|
||||
}
|
||||
rtmp.stop();
|
||||
log::info("stop\r\n");
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
helper();
|
||||
|
||||
2
examples/rtsp_yolo_demo/main/include/main.h
Normal file
2
examples/rtsp_yolo_demo/main/include/main.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
||||
Reference in New Issue
Block a user