From 325f626fb5247f4a5892b1e2feac167a2befa6f9 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Mon, 6 Nov 2023 19:02:39 -0800 Subject: [PATCH] Fix openh264 decode error caused by yuv stride --- .../remote_desk/remote_desk_gui/main.cpp | 2 +- .../linux/screen_capture_x11.cpp | 2 +- src/ice/ice_agent.cpp | 2 +- .../decode/openh264/openh264_decoder.cpp | 135 +++++++++++++++--- .../video/decode/openh264/openh264_decoder.h | 6 +- .../encode/ffmpeg/ffmpeg_video_encoder.cpp | 4 +- .../encode/openh264/openh264_encoder.cpp | 49 ++++++- .../video/encode/openh264/openh264_encoder.h | 5 +- xmake.lua | 9 +- 9 files changed, 175 insertions(+), 39 deletions(-) diff --git a/application/remote_desk/remote_desk_gui/main.cpp b/application/remote_desk/remote_desk_gui/main.cpp index 649fb60..273ae61 100644 --- a/application/remote_desk/remote_desk_gui/main.cpp +++ b/application/remote_desk/remote_desk_gui/main.cpp @@ -702,7 +702,7 @@ int main() { SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); } else { if (joined) { - ProcessMouseKeyEven(event); + // ProcessMouseKeyEven(event); } } } diff --git a/application/remote_desk/screen_capture/linux/screen_capture_x11.cpp b/application/remote_desk/screen_capture/linux/screen_capture_x11.cpp index 0ab6619..8699d45 100644 --- a/application/remote_desk/screen_capture/linux/screen_capture_x11.cpp +++ b/application/remote_desk/screen_capture/linux/screen_capture_x11.cpp @@ -26,7 +26,7 @@ int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps, // grabbing frame rate av_dict_set(&options_, "framerate", "30", 0); // Make the grabbed area follow the mouse - // av_dict_set(&options_, "follow_mouse", "centered", 0); + av_dict_set(&options_, "follow_mouse", "centered", 0); // Video frame size. The default is to capture the full screen av_dict_set(&options_, "video_size", "1280x720", 0); ifmt_ = (AVInputFormat *)av_find_input_format("x11grab"); diff --git a/src/ice/ice_agent.cpp b/src/ice/ice_agent.cpp index beea235..b44db99 100644 --- a/src/ice/ice_agent.cpp +++ b/src/ice/ice_agent.cpp @@ -73,7 +73,7 @@ int IceAgent::CreateIceAgent(nice_cb_state_changed_t on_state_changed, turn_port_, turn_username_.c_str(), turn_password_.c_str(), NICE_RELAY_TYPE_TURN_UDP); - g_object_set(agent_, "force-relay", true, NULL); + // g_object_set(agent_, "force-relay", true, NULL); nice_agent_attach_recv(agent_, stream_id_, 1, g_main_loop_get_context(gloop_), on_recv_, diff --git a/src/media/video/decode/openh264/openh264_decoder.cpp b/src/media/video/decode/openh264/openh264_decoder.cpp index cd00918..7c88899 100644 --- a/src/media/video/decode/openh264/openh264_decoder.cpp +++ b/src/media/video/decode/openh264/openh264_decoder.cpp @@ -19,9 +19,40 @@ extern "C" { }; #endif -#define SAVE_DECODER_STREAM 0 +#define SAVE_NV12_STREAM 0 +#define SAVE_H264_STREAM 0 + static const int YUV420P_BUFFER_SIZE = 1280 * 720 * 3 / 2; +void CopyYUVWithStride(uint8_t *srcY, uint8_t *srcU, uint8_t *srcV, int width, + int height, int strideY, int strideU, int strideV, + uint8_t *dst) { + int actualWidth = width; + int actualHeight = height; + + int actualStrideY = actualWidth; + int actualStrideU = actualWidth / 2; + int actualStrideV = actualWidth / 2; + + for (int row = 0; row < actualHeight; row++) { + memcpy(dst, srcY, actualStrideY); + srcY += strideY; + dst += actualStrideY; + } + + for (int row = 0; row < actualHeight / 2; row++) { + memcpy(dst, srcU, actualStrideU); + srcU += strideU; + dst += actualStrideU; + } + + for (int row = 0; row < actualHeight / 2; row++) { + memcpy(dst, srcV, actualStrideV); + srcV += strideV; + dst += actualStrideV; + } +} + int YUV420ToNV12PFFmpeg(unsigned char *src_buffer, int width, int height, unsigned char *dst_buffer) { AVFrame *Input_pFrame = av_frame_alloc(); @@ -48,6 +79,11 @@ int YUV420ToNV12PFFmpeg(unsigned char *src_buffer, int width, int height, OpenH264Decoder::OpenH264Decoder() {} OpenH264Decoder::~OpenH264Decoder() { + if (openh264_decoder_) { + openh264_decoder_->Uninitialize(); + WelsDestroyDecoder(openh264_decoder_); + } + if (nv12_frame_) { delete nv12_frame_; } @@ -63,23 +99,60 @@ OpenH264Decoder::~OpenH264Decoder() { if (pData[2]) { delete pData[2]; } + + if (pData_tmp) { + delete pData_tmp; + pData_tmp = nullptr; + } + + if (SAVE_H264_STREAM && h264_stream_) { + fflush(h264_stream_); + h264_stream_ = nullptr; + } + + if (SAVE_NV12_STREAM && nv12_stream_) { + fflush(nv12_stream_); + nv12_stream_ = nullptr; + } } int OpenH264Decoder::Init() { - SEncParamExt sParam; - sParam.iPicWidth = 1280; - sParam.iPicHeight = 720; - sParam.iTargetBitrate = 1000; - sParam.iTemporalLayerNum = 1; - sParam.fMaxFrameRate = 30; - sParam.iSpatialLayerNum = 1; + if (SAVE_NV12_STREAM) { + nv12_stream_ = fopen("nv12_receive_.yuv", "w+b"); + if (!nv12_stream_) { + LOG_WARN("Fail to open nv12_receive_.yuv"); + } + } + + if (SAVE_NV12_STREAM) { + h264_stream_ = fopen("h264_receive.h264", "w+b"); + if (!h264_stream_) { + LOG_WARN("Fail to open h264_receive.h264"); + } + } + + frame_width_ = 1280; + frame_height_ = 720; + + // SEncParamExt sParam; + // sParam.iPicWidth = frame_width_; + // sParam.iPicHeight = frame_height_; + // sParam.iTargetBitrate = 1000000000; + // sParam.iTemporalLayerNum = 1; + // sParam.fMaxFrameRate = 30; + // sParam.iSpatialLayerNum = 1; decoded_frame_size_ = YUV420P_BUFFER_SIZE; decoded_frame_ = new uint8_t[YUV420P_BUFFER_SIZE]; nv12_frame_ = new uint8_t[YUV420P_BUFFER_SIZE]; - pData[0] = new uint8_t[1280 * 720]; - pData[1] = new uint8_t[1280 * 720]; - pData[2] = new uint8_t[1280 * 720]; + // pData[0] = new uint8_t[1280 * 720]; + // pData[1] = new uint8_t[1280 * 720 / 4]; + // pData[2] = new uint8_t[1280 * 720 / 4]; + + pData_tmp = new uint8_t[frame_width_ * frame_height_ * 3 / 2]; + // *pData = pData_tmp; + // *(pData + 1) = pData_tmp + frame_width_ * frame_height_; + // *(pData + 2) = pData_tmp + (frame_width_ * frame_height_ * 5) / 4; if (WelsCreateDecoder(&openh264_decoder_) != 0) { LOG_ERROR("Failed to create OpenH264 decoder"); @@ -89,12 +162,15 @@ int OpenH264Decoder::Init() { SDecodingParam sDecParam; memset(&sDecParam, 0, sizeof(SDecodingParam)); + sDecParam.uiTargetDqLayer = UCHAR_MAX; + sDecParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; - sDecParam.bParseOnly = false; int32_t iRet = openh264_decoder_->Initialize(&sDecParam); - LOG_ERROR("inited decoded_frame_size_ {}", decoded_frame_size_); + int trace_level = WELS_LOG_WARNING; + openh264_decoder_->SetOption(DECODER_OPTION_TRACE_LEVEL, &trace_level); + LOG_ERROR("inited"); printf("1 this is %p\n", this); return 0; @@ -107,11 +183,17 @@ int OpenH264Decoder::Decode( return -1; } - SBufferInfo sDstBufInfo; + if (SAVE_H264_STREAM) { + fwrite((unsigned char *)data, 1, size, h264_stream_); + } + + SBufferInfo sDstBufInfo = {0}; memset(&sDstBufInfo, 0, sizeof(SBufferInfo)); - int32_t iRet = - openh264_decoder_->DecodeFrameNoDelay(data, size, pData, &sDstBufInfo); + unsigned char *dst[3]; + + int iRet = + openh264_decoder_->DecodeFrameNoDelay(data, size, dst, &sDstBufInfo); if (iRet != 0) { return -1; @@ -119,21 +201,28 @@ int OpenH264Decoder::Decode( if (sDstBufInfo.iBufferStatus == 1) { if (on_receive_decoded_frame) { - memcpy(decoded_frame_, pData[0], frame_width_ * frame_height_); - memcpy(decoded_frame_ + frame_width_ * frame_height_, pData[1], - frame_width_ * frame_height_ / 2); - memcpy(decoded_frame_ + frame_width_ * frame_height_ * 3 / 2, pData[2], - frame_width_ * frame_height_ / 2); + CopyYUVWithStride( + dst[0], dst[1], dst[2], sDstBufInfo.UsrData.sSystemBuffer.iWidth, + sDstBufInfo.UsrData.sSystemBuffer.iHeight, + sDstBufInfo.UsrData.sSystemBuffer.iStride[0], + sDstBufInfo.UsrData.sSystemBuffer.iStride[1], + sDstBufInfo.UsrData.sSystemBuffer.iStride[1], decoded_frame_); + + if (SAVE_NV12_STREAM) { + fwrite((unsigned char *)decoded_frame_, 1, + frame_width_ * frame_height_ * 3 / 2, nv12_stream_); + } YUV420ToNV12PFFmpeg(decoded_frame_, frame_width_, frame_height_, nv12_frame_); VideoFrame decoded_frame(nv12_frame_, frame_width_ * frame_height_ * 3 / 2, frame_width_, frame_height_); + on_receive_decoded_frame(decoded_frame); - if (SAVE_DECODER_STREAM) { + if (SAVE_NV12_STREAM) { fwrite((unsigned char *)decoded_frame.Buffer(), 1, decoded_frame.Size(), - file_); + nv12_stream_); } } } diff --git a/src/media/video/decode/openh264/openh264_decoder.h b/src/media/video/decode/openh264/openh264_decoder.h index c41c92b..b70e9f2 100644 --- a/src/media/video/decode/openh264/openh264_decoder.h +++ b/src/media/video/decode/openh264/openh264_decoder.h @@ -30,13 +30,17 @@ class OpenH264Decoder : public VideoDecoder { ISVCDecoder* openh264_decoder_ = nullptr; bool get_first_keyframe_ = false; bool skip_frame_ = false; - FILE* file_ = nullptr; + FILE* nv12_stream_ = nullptr; + FILE* h264_stream_ = nullptr; uint8_t* decoded_frame_ = nullptr; int decoded_frame_size_ = 0; uint8_t* nv12_frame_ = nullptr; unsigned char* pData[3] = {}; int frame_width_ = 1280; int frame_height_ = 720; + + uint8_t* pData_tmp = nullptr; + uint8_t* pData_tmp_2 = nullptr; }; #endif \ No newline at end of file diff --git a/src/media/video/encode/ffmpeg/ffmpeg_video_encoder.cpp b/src/media/video/encode/ffmpeg/ffmpeg_video_encoder.cpp index f6580a4..5e88f37 100644 --- a/src/media/video/encode/ffmpeg/ffmpeg_video_encoder.cpp +++ b/src/media/video/encode/ffmpeg/ffmpeg_video_encoder.cpp @@ -5,7 +5,7 @@ #include "log.h" #define SAVE_NV12_STREAM 0 -#define SAVE_H264_STREAM 1 +#define SAVE_H264_STREAM 0 #define YUV420P_BUFFER_SIZE 1280 * 720 * 3 / 2 unsigned char yuv420p_buffer[YUV420P_BUFFER_SIZE]; @@ -98,7 +98,7 @@ int FFmpegVideoEncoder::Init() { // 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, "profile", "baseline", 0); av_opt_set(codec_ctx_->priv_data, "preset", "ultrafast", 0); av_opt_set(codec_ctx_->priv_data, "tune", "zerolatency", 0); diff --git a/src/media/video/encode/openh264/openh264_encoder.cpp b/src/media/video/encode/openh264/openh264_encoder.cpp index f2d167e..d4843ac 100644 --- a/src/media/video/encode/openh264/openh264_encoder.cpp +++ b/src/media/video/encode/openh264/openh264_encoder.cpp @@ -19,6 +19,9 @@ extern "C" { }; #endif +#define SAVE_NV12_STREAM 0 +#define SAVE_H264_STREAM 0 + #define YUV420P_BUFFER_SIZE 1280 * 720 * 3 / 2 unsigned char yuv420p_buffer[YUV420P_BUFFER_SIZE]; @@ -46,7 +49,20 @@ int NV12ToYUV420PFFmpeg(unsigned char *src_buffer, int width, int height, return 0; } -OpenH264Encoder::OpenH264Encoder() { delete encoded_frame_; } +OpenH264Encoder::OpenH264Encoder() { + if (SAVE_NV12_STREAM && file_nv12_) { + fflush(file_nv12_); + fclose(file_nv12_); + file_nv12_ = nullptr; + } + + if (SAVE_H264_STREAM && file_h264_) { + fflush(file_h264_); + fclose(file_h264_); + file_h264_ = nullptr; + } + delete encoded_frame_; +} OpenH264Encoder::~OpenH264Encoder() { Release(); } SEncParamExt OpenH264Encoder::CreateEncoderParams() const { @@ -63,8 +79,8 @@ SEncParamExt OpenH264Encoder::CreateEncoderParams() const { encoder_params.iTargetBitrate = target_bitrate_; encoder_params.iMaxBitrate = max_bitrate_; encoder_params.iRCMode = RC_BITRATE_MODE; - encoder_params.fMaxFrameRate = max_frame_rate_; - encoder_params.bEnableFrameSkip = false; + encoder_params.fMaxFrameRate = 0.000030; + encoder_params.bEnableFrameSkip = true; encoder_params.uiIntraPeriod = key_frame_interval_; encoder_params.uiMaxNalSize = 0; // Threading model: use auto. @@ -107,8 +123,8 @@ int OpenH264Encoder::Init() { encoded_frame_ = new uint8_t[YUV420P_BUFFER_SIZE]; - int trace_level = WELS_LOG_WARNING; - openh264_encoder_->SetOption(ENCODER_OPTION_TRACE_LEVEL, &trace_level); + // int trace_level = WELS_LOG_WARNING; + // openh264_encoder_->SetOption(ENCODER_OPTION_TRACE_LEVEL, &trace_level); // Create encoder parameters based on the layer configuration. SEncParamExt encoder_params = CreateEncoderParams(); @@ -122,6 +138,20 @@ int OpenH264Encoder::Init() { int video_format = EVideoFormatType::videoFormatI420; openh264_encoder_->SetOption(ENCODER_OPTION_DATAFORMAT, &video_format); + if (SAVE_H264_STREAM) { + file_h264_ = fopen("encoded_stream.h264", "w+b"); + if (!file_h264_) { + LOG_WARN("Fail to open encoded_stream.h264"); + } + } + + if (SAVE_NV12_STREAM) { + file_nv12_ = fopen("raw_stream.yuv", "w+b"); + if (!file_nv12_) { + LOG_WARN("Fail to open raw_stream.yuv"); + } + } + return 0; } int OpenH264Encoder::Encode( @@ -132,7 +162,11 @@ int OpenH264Encoder::Encode( return -1; } - if (0 == seq_++ % 300) { + if (SAVE_NV12_STREAM) { + fwrite(yuv420p_buffer, 1, nSize, file_nv12_); + } + + if (0 == seq_++ % 3) { ForceIdr(); } @@ -228,6 +262,9 @@ int OpenH264Encoder::Encode( if (on_encoded_image) { on_encoded_image((char *)encoded_frame_, encoded_frame_size_); + if (SAVE_H264_STREAM) { + fwrite(encoded_frame_, 1, encoded_frame_size_, file_h264_); + } } else { OnEncodedImage((char *)encoded_frame_, encoded_frame_size_); } diff --git a/src/media/video/encode/openh264/openh264_encoder.h b/src/media/video/encode/openh264/openh264_encoder.h index 3898215..91d961e 100644 --- a/src/media/video/encode/openh264/openh264_encoder.h +++ b/src/media/video/encode/openh264/openh264_encoder.h @@ -38,14 +38,15 @@ class OpenH264Encoder : public VideoEncoder { private: int frame_width_ = 1280; int frame_height_ = 720; - int key_frame_interval_ = 3000; + int key_frame_interval_ = 5; int target_bitrate_ = 1000; int max_bitrate_ = 1000; int max_payload_size_ = 3000; int max_frame_rate_ = 30; std::vector> encoded_packets_; unsigned char* encoded_image_ = nullptr; - FILE* file_ = nullptr; + FILE* file_h264_ = nullptr; + FILE* file_nv12_ = nullptr; unsigned char* nv12_data_ = nullptr; unsigned int seq_ = 0; diff --git a/xmake.lua b/xmake.lua index 9199c74..36735c8 100644 --- a/xmake.lua +++ b/xmake.lua @@ -29,6 +29,7 @@ if is_os("windows") then add_requires("vcpkg::ffmpeg 5.1.2", {configs = {shared = false}}) add_requires("vcpkg::libnice 0.1.21") add_packages("vcpkg::libnice") + add_requires("openh264") elseif is_os("linux") then add_requireconfs("ffmpeg.x264", {configs = {pic = true}}) add_requires("ffmpeg 5.1.2") @@ -126,19 +127,23 @@ target("media") set_kind("static") add_deps("log", "frame") if is_os("windows") then - add_packages("cuda", "vcpkg::ffmpeg") + add_packages("cuda", "vcpkg::ffmpeg", "openh264") add_files("src/media/video/encode/*.cpp", "src/media/video/decode/*.cpp", "src/media/video/encode/nvcodec/*.cpp", "src/media/video/decode/nvcodec/*.cpp", "src/media/video/encode/ffmpeg/*.cpp", - "src/media/video/decode/ffmpeg/*.cpp") + "src/media/video/decode/ffmpeg/*.cpp", + "src/media/video/encode/openh264/*.cpp", + "src/media/video/decode/openh264/*.cpp") add_includedirs("src/media/video/encode", "src/media/video/decode", "src/media/video/encode/nvcodec", "src/media/video/decode/nvcodec", "src/media/video/encode/ffmpeg", "src/media/video/decode/ffmpeg", + "src/media/video/encode/openh264", + "src/media/video/decode/openh264", "thirdparty/nvcodec/Interface", "thirdparty/nvcodec/Samples", {public = true}) add_linkdirs("thirdparty/nvcodec/Lib/x64")