mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Support ffmpeg soft encode
This commit is contained in:
@@ -24,6 +24,7 @@ int IceAgent::CreateIceAgent(juice_cb_state_changed_t on_state_changed,
|
|||||||
juice_cb_recv_t on_recv, void *user_ptr) {
|
juice_cb_recv_t on_recv, void *user_ptr) {
|
||||||
// juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
// juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||||
|
|
||||||
|
LOG_ERROR("{} {} {} {}", stun_ip_, stun_port_, turn_ip_, turn_port_);
|
||||||
juice_config_t config;
|
juice_config_t config;
|
||||||
memset(&config, 0, sizeof(config));
|
memset(&config, 0, sizeof(config));
|
||||||
|
|
||||||
|
|||||||
@@ -85,8 +85,10 @@ int VideoDecoder::Decode(
|
|||||||
std::function<void(VideoFrame)> on_receive_decoded_frame) {
|
std::function<void(VideoFrame)> on_receive_decoded_frame) {
|
||||||
if (!first_) {
|
if (!first_) {
|
||||||
if ((*(data + 4) & 0x1f) != 0x07) {
|
if ((*(data + 4) & 0x1f) != 0x07) {
|
||||||
|
LOG_ERROR("1");
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
LOG_ERROR("2");
|
||||||
first_ = true;
|
first_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,23 +21,119 @@ VideoEncoder::~VideoEncoder() {
|
|||||||
file_ = nullptr;
|
file_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
av_packet_free(&packet_);
|
||||||
|
|
||||||
if (nv12_data_) {
|
if (nv12_data_) {
|
||||||
free(nv12_data_);
|
free(nv12_data_);
|
||||||
nv12_data_ = nullptr;
|
nv12_data_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int VideoEncoder::Init() { return 0; }
|
int VideoEncoder::Init() {
|
||||||
|
av_log_set_level(AV_LOG_ERROR);
|
||||||
|
|
||||||
|
codec_ = avcodec_find_encoder(AV_CODEC_ID_H264);
|
||||||
|
|
||||||
|
if (!codec_) {
|
||||||
|
LOG_ERROR("Failed to find H.264 encoder");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
codec_ctx_ = avcodec_alloc_context3(codec_);
|
||||||
|
if (!codec_ctx_) {
|
||||||
|
LOG_ERROR("Failed to allocate codec context");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
codec_ctx_->codec_id = AV_CODEC_ID_H264;
|
||||||
|
codec_ctx_->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||||
|
codec_ctx_->width = frame_width_;
|
||||||
|
codec_ctx_->height = frame_height;
|
||||||
|
codec_ctx_->time_base.num = 1;
|
||||||
|
codec_ctx_->time_base.den = fps_;
|
||||||
|
codec_ctx_->pix_fmt = AV_PIX_FMT_NV12;
|
||||||
|
codec_ctx_->gop_size = keyFrameInterval_;
|
||||||
|
codec_ctx_->keyint_min = keyFrameInterval_;
|
||||||
|
codec_ctx_->max_b_frames = 0;
|
||||||
|
codec_ctx_->bit_rate = maxBitrate_ * 500;
|
||||||
|
|
||||||
|
// av_opt_set_int(codec_ctx_->priv_data, "qp", 51, 0);
|
||||||
|
// av_opt_set_int(codec_ctx_->priv_data, "crf", 23, 0);
|
||||||
|
|
||||||
|
av_opt_set(codec_ctx_->priv_data, "profile", "baseline", 0);
|
||||||
|
av_opt_set(codec_ctx_->priv_data, "preset", "ultrafast", 0);
|
||||||
|
av_opt_set(codec_ctx_->priv_data, "tune", "zerolatency", 0);
|
||||||
|
|
||||||
|
if (avcodec_open2(codec_ctx_, codec_, nullptr) < 0) {
|
||||||
|
LOG_ERROR("Failed to open codec");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_ = av_frame_alloc();
|
||||||
|
frame_->format = codec_ctx_->pix_fmt;
|
||||||
|
frame_->width = codec_ctx_->width;
|
||||||
|
frame_->height = codec_ctx_->height;
|
||||||
|
|
||||||
|
int ret = av_frame_get_buffer(frame_, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("Could not allocate the raw frame");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_ = av_packet_alloc();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int VideoEncoder::Encode(
|
int VideoEncoder::Encode(
|
||||||
const uint8_t *pData, int nSize,
|
const uint8_t *pData, int nSize,
|
||||||
std::function<int(char *encoded_packets, size_t size)> on_encoded_image) {
|
std::function<int(char *encoded_packets, size_t size)> on_encoded_image) {
|
||||||
|
if (!codec_ctx_) {
|
||||||
|
LOG_ERROR("Invalid codec context");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(frame_->data[0], pData, frame_->width * frame_->height);
|
||||||
|
memcpy(frame_->data[1], pData + frame_->width * frame_->height,
|
||||||
|
frame_->width * frame_->height / 2);
|
||||||
|
|
||||||
|
frame_->pts = pts_++;
|
||||||
|
|
||||||
|
int ret = avcodec_send_frame(codec_ctx_, frame_);
|
||||||
|
|
||||||
|
// frame_->pict_type = AV_PICTURE_TYPE_I;
|
||||||
|
while (ret >= 0) {
|
||||||
|
ret = avcodec_receive_packet(codec_ctx_, packet_);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
return 0;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove first 6 bytes in I frame, SEI ?
|
||||||
|
if (0x00 == packet_->data[0] && 0x00 == packet_->data[1] &&
|
||||||
|
0x00 == packet_->data[2] && 0x01 == packet_->data[3] &&
|
||||||
|
0x09 == packet_->data[4] && 0x10 == packet_->data[5]) {
|
||||||
|
packet_->data += 6;
|
||||||
|
packet_->size -= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on_encoded_image) {
|
||||||
|
on_encoded_image((char *)packet_->data, packet_->size);
|
||||||
|
if (SAVE_ENCODER_STREAM) {
|
||||||
|
fwrite(packet_->data, 1, packet_->size, file_);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OnEncodedImage((char *)packet_->data, packet_->size);
|
||||||
|
}
|
||||||
|
av_packet_unref(packet_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VideoEncoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
int VideoEncoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
||||||
LOG_INFO("output encoded image");
|
LOG_INFO("OnEncodedImage not implemented");
|
||||||
fwrite(encoded_packets, 1, size, file_);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,20 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "libavcodec/avcodec.h"
|
#include "libavcodec/avcodec.h"
|
||||||
};
|
#include "libavformat/avformat.h"
|
||||||
|
#include "libavutil/imgutils.h"
|
||||||
|
#include "libavutil/opt.h"
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
extern "C" {
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -31,10 +39,11 @@ class VideoEncoder {
|
|||||||
void ForceIdr();
|
void ForceIdr();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int frame_width = 1280;
|
int frame_width_ = 1280;
|
||||||
int frame_height = 720;
|
int frame_height = 720;
|
||||||
int keyFrameInterval_ = 3000;
|
int keyFrameInterval_ = 3000;
|
||||||
int maxBitrate_ = 2000;
|
int maxBitrate_ = 1000;
|
||||||
|
int fps_ = 30;
|
||||||
int max_payload_size_ = 3000;
|
int max_payload_size_ = 3000;
|
||||||
|
|
||||||
std::vector<std::vector<uint8_t>> encoded_packets_;
|
std::vector<std::vector<uint8_t>> encoded_packets_;
|
||||||
@@ -42,6 +51,13 @@ class VideoEncoder {
|
|||||||
FILE* file_ = nullptr;
|
FILE* file_ = nullptr;
|
||||||
unsigned char* nv12_data_ = nullptr;
|
unsigned char* nv12_data_ = nullptr;
|
||||||
unsigned int seq_ = 0;
|
unsigned int seq_ = 0;
|
||||||
|
|
||||||
|
const AVCodec* codec_ = nullptr;
|
||||||
|
AVCodecContext* codec_ctx_ = nullptr;
|
||||||
|
AVFrame* frame_ = nullptr;
|
||||||
|
AVPacket* packet_;
|
||||||
|
bool got_output_ = false;
|
||||||
|
uint32_t pts_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -40,7 +40,7 @@ int VideoEncoder::Init() {
|
|||||||
if (!cuda_ctx_succeed) {
|
if (!cuda_ctx_succeed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder_ = new NvEncoderCuda(cuda_context_, frame_width, frame_height,
|
encoder_ = new NvEncoderCuda(cuda_context_, frame_width_, frame_height_,
|
||||||
NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_NV12);
|
NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_NV12);
|
||||||
|
|
||||||
// Init encoder_ session
|
// Init encoder_ session
|
||||||
@@ -52,8 +52,8 @@ int VideoEncoder::Init() {
|
|||||||
encoder_->CreateDefaultEncoderParams(&init_params, codec_guid, preset_guid,
|
encoder_->CreateDefaultEncoderParams(&init_params, codec_guid, preset_guid,
|
||||||
tuning_info);
|
tuning_info);
|
||||||
|
|
||||||
init_params.encodeWidth = frame_width;
|
init_params.encodeWidth = frame_width_;
|
||||||
init_params.encodeHeight = frame_height;
|
init_params.encodeHeight = frame_height_;
|
||||||
init_params.encodeConfig->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
|
init_params.encodeConfig->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
|
||||||
init_params.encodeConfig->encodeCodecConfig.h264Config.level =
|
init_params.encodeConfig->encodeCodecConfig.h264Config.level =
|
||||||
NV_ENC_LEVEL::NV_ENC_LEVEL_H264_31;
|
NV_ENC_LEVEL::NV_ENC_LEVEL_H264_31;
|
||||||
@@ -108,6 +108,9 @@ int VideoEncoder::Encode(
|
|||||||
for (const auto &packet : encoded_packets_) {
|
for (const auto &packet : encoded_packets_) {
|
||||||
if (on_encoded_image) {
|
if (on_encoded_image) {
|
||||||
on_encoded_image((char *)packet.data(), packet.size());
|
on_encoded_image((char *)packet.data(), packet.size());
|
||||||
|
if (SAVE_ENCODER_STREAM) {
|
||||||
|
fwrite(packet.data(), 1, packet.size(), file_);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
OnEncodedImage((char *)packet.data(), packet.size());
|
OnEncodedImage((char *)packet.data(), packet.size());
|
||||||
}
|
}
|
||||||
@@ -128,8 +131,7 @@ int VideoEncoder::Encode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int VideoEncoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
int VideoEncoder::OnEncodedImage(char *encoded_packets, size_t size) {
|
||||||
LOG_INFO("output encoded image");
|
LOG_INFO("OnEncodedImage not implemented");
|
||||||
fwrite(encoded_packets, 1, size, file_);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class VideoEncoder {
|
|||||||
GUID preset_guid = NV_ENC_PRESET_P2_GUID;
|
GUID preset_guid = NV_ENC_PRESET_P2_GUID;
|
||||||
NV_ENC_TUNING_INFO tuning_info =
|
NV_ENC_TUNING_INFO tuning_info =
|
||||||
NV_ENC_TUNING_INFO::NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY;
|
NV_ENC_TUNING_INFO::NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY;
|
||||||
int frame_width = 1280;
|
int frame_width_ = 1280;
|
||||||
int frame_height = 720;
|
int frame_height_ = 720;
|
||||||
int keyFrameInterval_ = 3000;
|
int keyFrameInterval_ = 3000;
|
||||||
int maxBitrate_ = 1000;
|
int maxBitrate_ = 1000;
|
||||||
int max_payload_size_ = 3000;
|
int max_payload_size_ = 3000;
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
#include "ice_transmission.h"
|
#include "ice_transmission.h"
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "nv_decoder.h"
|
|
||||||
#include "nv_encoder.h"
|
|
||||||
#else
|
|
||||||
#include "ffmpeg_decoder.h"
|
#include "ffmpeg_decoder.h"
|
||||||
#include "ffmpeg_encoder.h"
|
#include "ffmpeg_encoder.h"
|
||||||
|
// #include "nv_decoder.h"
|
||||||
|
// #include "nv_encoder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ws_transmission.h"
|
#include "ws_transmission.h"
|
||||||
|
|||||||
17
xmake.lua
17
xmake.lua
@@ -29,7 +29,7 @@ add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_
|
|||||||
if is_os("windows") then
|
if is_os("windows") then
|
||||||
add_defines("_WEBSOCKETPP_CPP11_INTERNAL_")
|
add_defines("_WEBSOCKETPP_CPP11_INTERNAL_")
|
||||||
add_links("ws2_32", "Bcrypt")
|
add_links("ws2_32", "Bcrypt")
|
||||||
add_links("windowsapp", "User32", "Strmiids", "Mfuuid")
|
add_links("windowsapp", "User32", "Strmiids", "Mfuuid", "Secur32", "Bcrypt")
|
||||||
add_requires("cuda")
|
add_requires("cuda")
|
||||||
elseif is_os("linux") then
|
elseif is_os("linux") then
|
||||||
add_links("pthread")
|
add_links("pthread")
|
||||||
@@ -105,16 +105,23 @@ target("media")
|
|||||||
if is_os("windows") or is_os(("linux")) then
|
if is_os("windows") or is_os(("linux")) then
|
||||||
add_packages("cuda")
|
add_packages("cuda")
|
||||||
add_files("src/media/video/encode/nvcodec/*.cpp",
|
add_files("src/media/video/encode/nvcodec/*.cpp",
|
||||||
"src/media/video/decode/nvcodec/*.cpp")
|
"src/media/video/decode/nvcodec/*.cpp",
|
||||||
|
"src/media/video/encode/ffmpeg/*.cpp",
|
||||||
|
"src/media/video/decode/ffmpeg/*.cpp"
|
||||||
|
)
|
||||||
add_includedirs("src/media/video/encode/nvcodec",
|
add_includedirs("src/media/video/encode/nvcodec",
|
||||||
"src/media/video/decode/nvcodec", "src/media/video/decode/ffmpeg",
|
"src/media/video/decode/nvcodec",
|
||||||
|
"src/media/video/encode/ffmpeg",
|
||||||
|
"src/media/video/decode/ffmpeg",
|
||||||
"thirdparty/nvcodec/Interface",
|
"thirdparty/nvcodec/Interface",
|
||||||
"thirdparty/nvcodec/Samples", {public = true})
|
"thirdparty/nvcodec/Samples", {public = true})
|
||||||
add_linkdirs("thirdparty/nvcodec/Lib/x64")
|
add_linkdirs("thirdparty/nvcodec/Lib/x64")
|
||||||
add_links("cuda", "nvencodeapi", "nvcuvid")
|
add_links("cuda", "nvencodeapi", "nvcuvid")
|
||||||
elseif is_os("macosx") then
|
elseif is_os("macosx") then
|
||||||
add_files("src/media/video/encode/ffmpeg/*.cpp", "src/media/video/decode/ffmpeg/*.cpp")
|
add_files("src/media/video/encode/ffmpeg/*.cpp",
|
||||||
add_includedirs("src/media/video/encode/ffmpeg", "src/media/video/decode/ffmpeg", {public = true})
|
"src/media/video/decode/ffmpeg/*.cpp")
|
||||||
|
add_includedirs("src/media/video/encode/ffmpeg",
|
||||||
|
"src/media/video/decode/ffmpeg", {public = true})
|
||||||
end
|
end
|
||||||
|
|
||||||
target("qos")
|
target("qos")
|
||||||
|
|||||||
Reference in New Issue
Block a user