From f5842f8c1fcf01f5f1f5ac603721471d44b745dc Mon Sep 17 00:00:00 2001 From: ziyue <1213642868@qq.com> Date: Mon, 2 Aug 2021 15:54:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AF=BB=E5=8F=96h264?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=BD=AC=E6=B5=81=E5=AA=92=E4=BD=93=E8=8C=83?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/include/mk_h264_splitter.h | 56 ++++++++++++++++++++++ api/include/mk_mediakit.h | 1 + api/source/mk_h264_splitter.cpp | 81 ++++++++++++++++++++++++++++++++ api/tests/h264_media_server.c | 83 +++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 api/include/mk_h264_splitter.h create mode 100644 api/source/mk_h264_splitter.cpp create mode 100644 api/tests/h264_media_server.c diff --git a/api/include/mk_h264_splitter.h b/api/include/mk_h264_splitter.h new file mode 100644 index 00000000..514992c9 --- /dev/null +++ b/api/include/mk_h264_splitter.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_MK_H264_SPLITTER_H +#define ZLMEDIAKIT_MK_H264_SPLITTER_H + +#include "mk_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *mk_h264_splitter; + +/** + * h264 分帧器输出回调函数 + * @param user_data 设置回调时的用户数据指针 + * @param splitter 对象 + * @param frame 帧数据 + * @param size 帧数据长度 + */ +typedef void(API_CALL *on_mk_h264_splitter_frame)(void *user_data, mk_h264_splitter splitter, const char *frame, int size); + +/** + * 创建h264分帧器 + * @param cb 分帧回调函数 + * @param user_data 回调用户数据指针 + * @return 分帧器对象 + */ +API_EXPORT mk_h264_splitter API_CALL mk_h264_splitter_create(on_mk_h264_splitter_frame cb, void *user_data); + +/** + * 删除h264分帧器 + * @param ctx 分帧器 + */ +API_EXPORT void API_CALL mk_h264_splitter_release(mk_h264_splitter ctx); + +/** + * 输入数据并分帧 + * @param ctx 分帧器 + * @param data h264/h265数据 + * @param size 数据长度 + */ +API_EXPORT void API_CALL mk_h264_splitter_input_data(mk_h264_splitter ctx, const char *data, int size); + +#ifdef __cplusplus +} +#endif +#endif //ZLMEDIAKIT_MK_H264_SPLITTER_H diff --git a/api/include/mk_mediakit.h b/api/include/mk_mediakit.h index 9f85700d..e42e23c1 100755 --- a/api/include/mk_mediakit.h +++ b/api/include/mk_mediakit.h @@ -23,5 +23,6 @@ #include "mk_util.h" #include "mk_thread.h" #include "mk_rtp_server.h" +#include "mk_h264_splitter.h" #endif /* MK_API_H_ */ diff --git a/api/source/mk_h264_splitter.cpp b/api/source/mk_h264_splitter.cpp new file mode 100644 index 00000000..f764de36 --- /dev/null +++ b/api/source/mk_h264_splitter.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include "mk_h264_splitter.h" +#include "Http/HttpRequestSplitter.h" + +using namespace mediakit; + +class H264Splitter : public HttpRequestSplitter { +public: + using onH264 = function; + H264Splitter() = default; + ~H264Splitter() override; + void setOnSplitted(onH264 cb); + +protected: + ssize_t onRecvHeader(const char *data, size_t len) override; + const char *onSearchPacketTail(const char *data, size_t len) override; + +private: + onH264 _cb; +}; + +void H264Splitter::setOnSplitted(H264Splitter::onH264 cb) { + _cb = std::move(cb); +} + +H264Splitter::~H264Splitter() { + if (remainDataSize()) { + _cb(remainData(), remainDataSize()); + } +} + +ssize_t H264Splitter::onRecvHeader(const char *data, size_t len) { + _cb(data, len); + return 0; +} + +const char *H264Splitter::onSearchPacketTail(const char *data, size_t len) { + for (size_t i = 2; len > 2 && i < len - 2; ++i) { + //判断0x00 00 01 + if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) { + if (i > 0 && data[i - 1] == 0) { + //找到0x00 00 00 01 + return data + i - 1; + } + return data + i; + } + } + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +API_EXPORT mk_h264_splitter API_CALL mk_h264_splitter_create(on_mk_h264_splitter_frame cb, void *user_data) { + assert(cb); + auto ptr = new H264Splitter(); + ptr->setOnSplitted([cb, ptr, user_data](const char *data, size_t len) { + cb(user_data, reinterpret_cast(ptr), data, len); + }); + return reinterpret_cast(ptr); +} + +API_EXPORT void API_CALL mk_h264_splitter_release(mk_h264_splitter ctx){ + assert(ctx); + auto ptr = reinterpret_cast(ctx); + delete ptr; +} + +API_EXPORT void API_CALL mk_h264_splitter_input_data(mk_h264_splitter ctx, const char *data, int size) { + assert(ctx && data && size); + auto ptr = reinterpret_cast(ctx); + ptr->input(data, size); +} diff --git a/api/tests/h264_media_server.c b/api/tests/h264_media_server.c new file mode 100644 index 00000000..d61095ae --- /dev/null +++ b/api/tests/h264_media_server.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifdef _WIN32 +#include "windows.h" +#else +#include "unistd.h" +#endif +#include "mk_mediakit.h" + +static int exit_flag = 0; +static void s_on_exit(int sig) { + exit_flag = 1; +} + +static void on_h264_frame(void *user_data, mk_h264_splitter splitter, const char *frame, int size) { +#ifdef _WIN32 + Sleep(40); +#else + usleep(40 * 1000); +#endif + mk_media media = (mk_media) user_data; + mk_media_input_h264(media, frame, size, 0, 0); +} + +int main(int argc, char *argv[]) { + mk_config config = { + .ini = NULL, + .ini_is_path = 1, + .log_level = 0, + .log_file_path = NULL, + .log_file_days = 0, + .ssl = NULL, + .ssl_is_path = 1, + .ssl_pwd = NULL, + .thread_num = 0 + }; + mk_env_init(&config); + mk_http_server_start(80, 0); + mk_rtsp_server_start(554, 0); + mk_rtmp_server_start(1935, 0); + + signal(SIGINT, s_on_exit);// 设置退出信号 + + FILE *fp = fopen(argv[1], "rb"); + if (!fp) { + log_error("打开文件失败!"); + return -1; + } + + mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0); + //h264的codec + mk_media_init_video(media, 0, 0, 0, 0); + mk_media_init_complete(media); + + //创建h264分帧器 + mk_h264_splitter splitter = mk_h264_splitter_create(on_h264_frame, media); + + char buf[1024]; + while (!exit_flag) { + int size = fread(buf, 1, sizeof(buf) - 1, fp); + if (size > 0) { + mk_h264_splitter_input_data(splitter, buf, size); + } else { + //文件读完了,重新开始 + fseek(fp, 0, SEEK_SET); + } + } + + log_info("文件读取完毕"); + mk_h264_splitter_release(splitter); + mk_media_release(media); + fclose(fp); + mk_stop_all_server(); + return 0; +} \ No newline at end of file