From 44f787b3603f68c01c3bb3715fdbab8bb1bb049a Mon Sep 17 00:00:00 2001 From: dijunkun Date: Fri, 15 Sep 2023 16:51:40 +0800 Subject: [PATCH] Support ffmpeg soft decode for Winodws --- src/frame/frame.cpp | 7 + src/frame/frame.h | 3 + .../video/decode/ffmpeg/ffmpeg_decoder.cpp | 433 ++++-------------- .../video/decode/ffmpeg/ffmpeg_decoder.h | 66 ++- src/media/video/decode/nvcodec/nv_decoder.cpp | 42 +- src/media/video/decode/nvcodec/nv_decoder.h | 4 +- src/pc/peer_connection.h | 2 +- thirdparty/ffmpeg/xmake.lua | 2 +- xmake.lua | 16 +- 9 files changed, 163 insertions(+), 412 deletions(-) diff --git a/src/frame/frame.cpp b/src/frame/frame.cpp index 767a9f9..a0cd09f 100644 --- a/src/frame/frame.cpp +++ b/src/frame/frame.cpp @@ -4,6 +4,13 @@ VideoFrame::VideoFrame() {} +VideoFrame::VideoFrame(size_t size) { + buffer_ = new uint8_t[size]; + size_ = size; + width_ = 0; + height_ = 0; +} + VideoFrame::VideoFrame(const uint8_t *buffer, size_t size) { buffer_ = new uint8_t[size]; memcpy(buffer_, buffer, size); diff --git a/src/frame/frame.h b/src/frame/frame.h index 265a85c..25cfded 100644 --- a/src/frame/frame.h +++ b/src/frame/frame.h @@ -6,6 +6,7 @@ class VideoFrame { public: VideoFrame(); + VideoFrame(size_t size); VideoFrame(const uint8_t *buffer, size_t size); VideoFrame(const uint8_t *buffer, size_t size, size_t width, size_t height); VideoFrame(const VideoFrame &video_frame); @@ -19,6 +20,8 @@ class VideoFrame { const uint8_t *Buffer() { return buffer_; } const size_t Size() { return size_; } + uint8_t *GetBuffer() { return buffer_; } + private: size_t width_ = 0; size_t height_ = 0; diff --git a/src/media/video/decode/ffmpeg/ffmpeg_decoder.cpp b/src/media/video/decode/ffmpeg/ffmpeg_decoder.cpp index 89659f5..28d7c32 100644 --- a/src/media/video/decode/ffmpeg/ffmpeg_decoder.cpp +++ b/src/media/video/decode/ffmpeg/ffmpeg_decoder.cpp @@ -2,357 +2,124 @@ #include "log.h" -const char H264_NAL_START[] = {0x00, 0x00, 0x00, 0x01}; +#define SAVE_ENCODER_STREAM 1 -VideoDecoder::VideoDecoder(PacketQueue *packetQueue) { - pPacketQueue = packetQueue; - pFrameDataCallbackMutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); +extern "C" { +#include +#include +#include +}; - int ret = pthread_mutex_init(pFrameDataCallbackMutex, nullptr); - if (ret != 0) { - LOG_ERROR("video FrameDataCallbackMutex init failed.\n"); +VideoDecoder::VideoDecoder() { + if (SAVE_ENCODER_STREAM) { + file_ = fopen("decode_stream.yuv", "w+b"); + if (!file_) { + LOG_WARN("Fail to open stream.yuv"); + } } - - gSPSLen = 0; - pSPS = nullptr; - - gPPSLen = 0; - pPPS = nullptr; - - isFirstIDR = false; - - gFrameRate = 25; - - pFrameDataCallback = nullptr; } VideoDecoder::~VideoDecoder() { - pthread_mutex_destroy(pFrameDataCallbackMutex); - - if (nullptr != pFrameDataCallbackMutex) { - free(pFrameDataCallbackMutex); - pFrameDataCallbackMutex = nullptr; + if (SAVE_ENCODER_STREAM && file_) { + fflush(file_); + fclose(file_); + file_ = nullptr; } + + if (decoded_frame_) { + delete decoded_frame_; + decoded_frame_ = nullptr; + } + + av_frame_free(&frame_); + av_frame_free(&frame_nv12_); + sws_freeContext(img_convert_ctx); + avcodec_close(codec_ctx_); + av_free(codec_ctx_); } -void VideoDecoder::setFrameDataCallback(FrameDataCallback *frameDataCallback) { - pthread_mutex_lock(pFrameDataCallbackMutex); - pFrameDataCallback = frameDataCallback; - pthread_mutex_unlock(pFrameDataCallbackMutex); +int VideoDecoder::Init() { + // av_log_set_level(AV_LOG_DEBUG); + + codec_id_ = AV_CODEC_ID_H264; + codec_ = avcodec_find_decoder(codec_id_); + if (!codec_) { + printf("Codec not found\n"); + return -1; + } + codec_ctx_ = avcodec_alloc_context3(codec_); + if (!codec_ctx_) { + printf("Could not allocate video codec context\n"); + return -1; + } + + codec_ctx_->time_base.num = 1; + codec_ctx_->frame_number = 1; + codec_ctx_->codec_type = AVMEDIA_TYPE_VIDEO; + codec_ctx_->bit_rate = 0; + codec_ctx_->time_base.den = 29; + codec_ctx_->width = 1280; + codec_ctx_->height = 720; + codec_ctx_->pix_fmt = AV_PIX_FMT_NV12; + codec_ctx_->color_range = AVCOL_RANGE_MPEG; + + if (avcodec_open2(codec_ctx_, codec_, NULL) < 0) { + printf("Could not open codec\n"); + return -1; + } + + frame_ = av_frame_alloc(); + frame_nv12_ = av_frame_alloc(); + + img_convert_ctx = + sws_getContext(1280, 720, AV_PIX_FMT_YUV420P, 1280, 720, AV_PIX_FMT_NV12, + SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); + + decoded_frame_ = new VideoFrame(1280 * 720 * 3 / 2); + + return 0; } -void VideoDecoder::close() { - isDecoding = false; - pthread_join(decodeThread, nullptr); - - if (pSPS != nullptr) { - free(pSPS); - pSPS = nullptr; - } - - if (pPPS != nullptr) { - free(pPPS); - pPPS = nullptr; - } - - if (pFrame != nullptr) { - av_frame_free(&pFrame); - LOG_INFO("%s video Frame free", __FUNCTION__); - } - - if (pVideoAVCodecCtx != nullptr) { - avcodec_free_context(&pVideoAVCodecCtx); - LOG_INFO("%s video avcodec_free_context", __FUNCTION__); - } -} - -bool VideoDecoder::open(unsigned int frameRate, unsigned int profile, - unsigned int level, char *sps, unsigned int spsLen, - char *pps, unsigned int ppsLen) { - gSPSLen = 0; - pSPS = nullptr; - - gPPSLen = 0; - pPPS = nullptr; - - LOG_INFO("%s spsLen=%d ppsLen=%d", __FUNCTION__, spsLen, ppsLen); - - if (spsLen > 0) { - pSPS = (char *)malloc(spsLen); - if (nullptr == pSPS) { - return false; - } - - memcpy(pSPS, sps, spsLen); - gSPSLen = spsLen; - } - - if (ppsLen > 0) { - pPPS = (char *)malloc(ppsLen); - if (nullptr == pPPS) { - free(pSPS); - return false; - } - - memcpy(pPPS, pps, ppsLen); - gPPSLen = ppsLen; - } - - isFirstIDR = false; - - if (frameRate > 0) { - gFrameRate = frameRate; - } - - int ret; - AVCodec *dec = avcodec_find_decoder(AV_CODEC_ID_H264); - LOG_INFO("%s video decoder name: %s", __FUNCTION__, dec->name); - pVideoAVCodecCtx = avcodec_alloc_context3(dec); - - if (pVideoAVCodecCtx == nullptr) { - LOG_ERROR("%s VideoAVCodecCtx alloc failed", __FUNCTION__); - return false; - } - - AVCodecParameters *par = avcodec_parameters_alloc(); - if (par == nullptr) { - LOG_ERROR("%s video AVCodecParameters alloc failed", __FUNCTION__); - free(pSPS); - free(pPPS); - avcodec_free_context(&pVideoAVCodecCtx); - return false; - } - - par->codec_type = AVMEDIA_TYPE_VIDEO; - par->codec_id = AV_CODEC_ID_H264; - par->format = AV_PIX_FMT_YUV420P; // AV_PIX_FMT_NV12 - par->color_range = AVCOL_RANGE_JPEG; - - if (profile != 0) { - par->profile = (int)profile; - } - - if (level != 0) { - par->level = (int)level; - } - - avcodec_parameters_to_context(pVideoAVCodecCtx, par); - avcodec_parameters_free(&par); - - LOG_INFO("%s profile=%d level=%d", __FUNCTION__, profile, level); - ret = avcodec_open2(pVideoAVCodecCtx, dec, nullptr); - if (ret < 0) { - LOG_ERROR("%s Can not open video encoder", __FUNCTION__); - free(pSPS); - free(pPPS); - avcodec_free_context(&pVideoAVCodecCtx); - return false; - } - LOG_INFO("%s avcodec_open2 video SUCC", __FUNCTION__); - pFrame = av_frame_alloc(); - if (pFrame == nullptr) { - LOG_ERROR("%s video av_frame_alloc failed", __FUNCTION__); - free(pSPS); - free(pPPS); - avcodec_free_context(&pVideoAVCodecCtx); - return false; - } - - isDecoding = true; - ret = pthread_create(&decodeThread, nullptr, &VideoDecoder::_decode, - (void *)this); - if (ret != 0) { - LOG_ERROR("video decode-thread create failed.\n"); - isDecoding = false; - free(pSPS); - free(pPPS); - avcodec_free_context(&pVideoAVCodecCtx); - av_frame_free(&pFrame); - return false; - } - - return true; -} - -void VideoDecoder::decode() { - int ret; - unsigned sleepDelta = 1000000 / gFrameRate / 4; // 一帧视频的 1/4 - int NAL_START_LEN = 4; - - while (isDecoding) { - AVPacket *pkt = av_packet_alloc(); - - if (pkt == nullptr) { - usleep(sleepDelta); - continue; - } - - if (pPacketQueue == nullptr) { - av_packet_free(&pkt); - usleep(sleepDelta); - continue; - } - - PACKET_STRUCT *packetStruct; - bool isDone = pPacketQueue->Take(packetStruct); - if (isDone && packetStruct != nullptr && packetStruct->data != nullptr && - packetStruct->data_size > 0) { - // 0x67:sps - if (packetStruct->data[0] == 0x67) { - if (gSPSLen <= 0) { - gSPSLen = packetStruct->data_size; - pSPS = (char *)malloc(gSPSLen); - if (nullptr == pSPS) { - av_packet_free(&pkt); - free(packetStruct->data); - free(packetStruct); - - usleep(sleepDelta); - continue; - } - memcpy(pSPS, packetStruct->data, gSPSLen); - LOG_INFO("%s get sps spsLen=%d", __FUNCTION__, gSPSLen); - } - - av_packet_free(&pkt); - free(packetStruct->data); - free(packetStruct); - - continue; - } - // 0x68:pps - if (packetStruct->data[0] == 0x68) { - if (gPPSLen <= 0) { - gPPSLen = packetStruct->data_size; - pPPS = (char *)malloc(gPPSLen); - if (nullptr == pPPS) { - av_packet_free(&pkt); - free(packetStruct->data); - free(packetStruct); - - usleep(sleepDelta); - continue; - } - memcpy(pPPS, packetStruct->data, gPPSLen); - LOG_INFO("%s get pps ppsLen=%d", __FUNCTION__, gPPSLen); - } - - av_packet_free(&pkt); - free(packetStruct->data); - free(packetStruct); - - continue; - } - - if (!isFirstIDR) { - // 0x65:IDR - if (packetStruct->data[0] == 0x65) { - isFirstIDR = true; - LOG_INFO("%s get first idr.", __FUNCTION__); - } else { - av_packet_free(&pkt); - free(packetStruct->data); - free(packetStruct); - - continue; - } - } - - if (packetStruct->data[0] == 0x65 && gSPSLen > 0 && gPPSLen > 0) { - ret = av_new_packet( - pkt, (int)(NAL_START_LEN + gSPSLen + NAL_START_LEN + gPPSLen + - packetStruct->data_size + NAL_START_LEN)); - } else { - ret = av_new_packet(pkt, packetStruct->data_size + NAL_START_LEN); - } - - if (ret < 0) { - av_packet_free(&pkt); - free(packetStruct->data); - free(packetStruct); - - usleep(sleepDelta); - continue; - } +int VideoDecoder::Decode( + const uint8_t *data, int size, + std::function on_receive_decoded_frame) { + if (!first_) { + if ((*(data + 4) & 0x1f) != 0x07) { + return -1; } else { - av_packet_free(&pkt); - usleep(sleepDelta); + first_ = true; + } + } + + packet_.data = (uint8_t *)data; + packet_.size = size; + + int ret = avcodec_send_packet(codec_ctx_, &packet_); + + while (ret >= 0) { + ret = avcodec_receive_frame(codec_ctx_, frame_); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + continue; + } else if (ret < 0) { + LOG_ERROR("Error receive decoding video frame ret=%d", ret); continue; } - if (packetStruct->data[0] == 0x65 && gSPSLen > 0 && gPPSLen > 0) { - int pos = 0; - // 复制 0x 00 00 00 01 - memcpy(pkt->data + pos, H264_NAL_START, NAL_START_LEN); - pos += NAL_START_LEN; - memcpy(pkt->data + pos, pSPS, gSPSLen); - pos += (int)gSPSLen; + if (on_receive_decoded_frame) { + av_image_fill_arrays(frame_nv12_->data, frame_nv12_->linesize, + decoded_frame_->GetBuffer(), AV_PIX_FMT_NV12, + frame_->width, frame_->height, 1); - memcpy(pkt->data + pos, H264_NAL_START, NAL_START_LEN); - pos += NAL_START_LEN; - memcpy(pkt->data + pos, pPPS, gPPSLen); - pos += (int)gPPSLen; + sws_scale(img_convert_ctx, frame_->data, frame_->linesize, 0, + frame_->height, frame_nv12_->data, frame_nv12_->linesize); - memcpy(pkt->data + pos, H264_NAL_START, NAL_START_LEN); - pos += NAL_START_LEN; - memcpy(pkt->data + pos, packetStruct->data, packetStruct->data_size); - } else { - memcpy(pkt->data, H264_NAL_START, NAL_START_LEN); - memcpy(pkt->data + NAL_START_LEN, packetStruct->data, - packetStruct->data_size); - } - - pkt->pts = packetStruct->timestamp; - pkt->dts = packetStruct->timestamp; - - free(packetStruct->data); - free(packetStruct); - /* send the packet for decoding */ - ret = avcodec_send_packet(pVideoAVCodecCtx, pkt); - // LOGD("%s send the video packet for decoding pkt size=%d", __FUNCTION__, - // pkt->size); - - av_packet_unref(pkt); - av_packet_free(&pkt); - - if (ret < 0) { - LOG_ERROR("%s Error sending the video pkt to the decoder ret=%d", - __FUNCTION__, ret); - usleep(sleepDelta); - continue; - } else { - // 编码和解码都是一样的,都是send 1次,然后receive多次, - // 直到AVERROR(EAGAIN)或者AVERROR_EOF - while (ret >= 0) { - ret = avcodec_receive_frame(pVideoAVCodecCtx, pFrame); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { - usleep(sleepDelta); - continue; - } else if (ret < 0) { - LOG_ERROR("%s Error receive decoding video frame ret=%d", - __FUNCTION__, ret); - usleep(sleepDelta); - continue; - } - - pthread_mutex_lock(pFrameDataCallbackMutex); - if (pFrameDataCallback != nullptr) { - // 解码固定为 AV_PIX_FMT_YUV420P - int planeNum = 3; - int yuvLens[planeNum]; - yuvLens[0] = pFrame->linesize[0] * pFrame->height; - yuvLens[1] = pFrame->linesize[1] * pFrame->height / 2; - yuvLens[2] = pFrame->linesize[2] * pFrame->height / 2; - // LOG_INFO("%s video onDataArrived", __FUNCTION__); - pFrameDataCallback->onDataArrived( - StreamType::VIDEO, (long long)pFrame->pts, (char **)pFrame->data, - yuvLens, planeNum, -1, -1, pFrame->width, pFrame->height); - } - - pthread_mutex_unlock(pFrameDataCallbackMutex); - - av_frame_unref(pFrame); + on_receive_decoded_frame(*decoded_frame_); + if (SAVE_ENCODER_STREAM) { + fwrite((unsigned char *)frame_->data, 1, + frame_->width * frame_->height * 3 / 2, file_); } } } + + return 0; } \ No newline at end of file diff --git a/src/media/video/decode/ffmpeg/ffmpeg_decoder.h b/src/media/video/decode/ffmpeg/ffmpeg_decoder.h index bace9a6..4760de5 100644 --- a/src/media/video/decode/ffmpeg/ffmpeg_decoder.h +++ b/src/media/video/decode/ffmpeg/ffmpeg_decoder.h @@ -1,57 +1,49 @@ #ifndef _FFMPEG_DECODER_H_ #define _FFMPEG_DECODER_H_ +#ifdef _WIN32 +// Windows extern "C" { -// 编解码 #include "libavcodec/avcodec.h" -} +}; +#else +// Linux... +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +}; +#endif +#endif -#include "PacketQueue.h" -#include "cb/FrameDataCallback.h" +#include + +#include "frame.h" class VideoDecoder { public: - VideoDecoder(PacketQueue *packetQueue); + VideoDecoder(); ~VideoDecoder(); public: int Init(); - int Decode(const uint8_t *pData, int nSize); - int GetFrame(uint8_t *yuv_data, uint32_t &width, uint32_t &height, - uint32_t &size); - - bool open(unsigned int frameRate, unsigned int profile, unsigned int level, - char *sps, unsigned int spsLen, char *pps, unsigned int ppsLen); - - void close(); - - void decode(); - - static void *_decode(void *self) { - static_cast(self)->decode(); - return nullptr; - } - - void setFrameDataCallback(FrameDataCallback *frameDataCallback); + int Decode(const uint8_t *data, int size, + std::function on_receive_decoded_frame); private: - PacketQueue *pPacketQueue; - AVCodecContext *pVideoAVCodecCtx; - AVFrame *pFrame; + AVCodecID codec_id_; + const AVCodec *codec_; + AVCodecContext *codec_ctx_ = nullptr; + AVPacket packet_; + AVFrame *frame_ = nullptr; + AVFrame *frame_nv12_ = nullptr; + struct SwsContext *img_convert_ctx = nullptr; - bool volatile isDecoding; - pthread_t decodeThread; - pthread_mutex_t *pFrameDataCallbackMutex; - FrameDataCallback *pFrameDataCallback; + VideoFrame *decoded_frame_ = nullptr; - char *pSPS; - unsigned int volatile gSPSLen; - char *pPPS; - unsigned int volatile gPPSLen; - - bool volatile isFirstIDR; - - unsigned int gFrameRate; + FILE *file_ = nullptr; + bool first_ = false; }; #endif \ No newline at end of file diff --git a/src/media/video/decode/nvcodec/nv_decoder.cpp b/src/media/video/decode/nvcodec/nv_decoder.cpp index 57dd506..f9e6b89 100644 --- a/src/media/video/decode/nvcodec/nv_decoder.cpp +++ b/src/media/video/decode/nvcodec/nv_decoder.cpp @@ -44,21 +44,21 @@ int VideoDecoder::Init() { } int VideoDecoder::Decode( - const uint8_t *pData, int nSize, + const uint8_t *data, int size, std::function on_receive_decoded_frame) { if (!decoder) { return -1; } - if ((*(pData + 4) & 0x1f) == 0x07) { + if ((*(data + 4) & 0x1f) == 0x07) { // LOG_WARN("Receive key frame"); } if (SAVE_ENCODER_STREAM) { - fwrite((unsigned char *)pData, 1, nSize, file_); + fwrite((unsigned char *)data, 1, size, file_); } - int num_frame_returned = decoder->Decode(pData, nSize); + int num_frame_returned = decoder->Decode(data, size); for (size_t i = 0; i < num_frame_returned; ++i) { cudaVideoSurfaceFormat format = decoder->GetOutputFormat(); @@ -66,11 +66,10 @@ int VideoDecoder::Decode( uint8_t *data = nullptr; data = decoder->GetFrame(); if (data) { - VideoFrame decoded_frame( - data, decoder->GetWidth() * decoder->GetHeight() * 3 / 2, - decoder->GetWidth(), decoder->GetHeight()); - if (on_receive_decoded_frame) { + VideoFrame decoded_frame( + data, decoder->GetWidth() * decoder->GetHeight() * 3 / 2, + decoder->GetWidth(), decoder->GetHeight()); on_receive_decoded_frame(decoded_frame); } } @@ -78,29 +77,4 @@ int VideoDecoder::Decode( } return -1; -} - -int VideoDecoder::GetFrame(uint8_t *yuv_data, uint32_t &width, uint32_t &height, - uint32_t &size) { - if (nullptr == decoder) { - return -1; - } - cudaVideoSurfaceFormat format = decoder->GetOutputFormat(); - if (format == cudaVideoSurfaceFormat_NV12) { - uint8_t *data = nullptr; - data = decoder->GetFrame(); - if (data) { - // yuv_data = data; - - width = decoder->GetWidth(); - height = decoder->GetHeight(); - size = width * height * 3 / 2; - memcpy(yuv_data, data, size); - return 0; - - return -1; - } - return -1; - } - return -1; -} +} \ No newline at end of file diff --git a/src/media/video/decode/nvcodec/nv_decoder.h b/src/media/video/decode/nvcodec/nv_decoder.h index be7c8e7..c089dde 100644 --- a/src/media/video/decode/nvcodec/nv_decoder.h +++ b/src/media/video/decode/nvcodec/nv_decoder.h @@ -13,10 +13,8 @@ class VideoDecoder { public: int Init(); - int Decode(const uint8_t* pData, int nSize, + int Decode(const uint8_t* data, int size, std::function on_receive_decoded_frame); - int GetFrame(uint8_t* yuv_data, uint32_t& width, uint32_t& height, - uint32_t& size); private: NvDecoder* decoder = nullptr; diff --git a/src/pc/peer_connection.h b/src/pc/peer_connection.h index 2d6a728..fd6a4be 100644 --- a/src/pc/peer_connection.h +++ b/src/pc/peer_connection.h @@ -4,8 +4,8 @@ #include #include +#include "ffmpeg_decoder.h" #include "ice_transmission.h" -#include "nv_decoder.h" #include "nv_encoder.h" #include "ws_transmission.h" diff --git a/thirdparty/ffmpeg/xmake.lua b/thirdparty/ffmpeg/xmake.lua index 6cb947f..f5d6bbf 100644 --- a/thirdparty/ffmpeg/xmake.lua +++ b/thirdparty/ffmpeg/xmake.lua @@ -1,4 +1,4 @@ -package("ffmpeg") +package("ffmpegxx") set_homepage("https://www.ffmpeg.org") set_description("A collection of libraries to process multimedia content such as audio, video, subtitles and related metadata.") set_license("GPL-3.0") diff --git a/xmake.lua b/xmake.lua index 4c5c226..2c22413 100644 --- a/xmake.lua +++ b/xmake.lua @@ -9,6 +9,14 @@ add_rules("mode.release", "mode.debug") add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.11.0") add_requires("libjuice", {system = false}) +if is_os("windows") then + add_requires("vcpkg::ffmpeg 5.1.2", {configs = {shared = false}}) + add_packages("vcpkg::ffmpeg") +elseif is_os("linux") then + add_requires("ffmpeg 5.1.2", {system = false}) + add_packages("ffmpeg") +end + add_defines("JUICE_STATIC") add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_PTR", "ASIO_HAS_STD_ADDRESSOF", "ASIO_HAS_STD_ATOMIC", "ASIO_HAS_STD_CHRONO", "ASIO_HAS_CSTDINT", "ASIO_HAS_STD_ARRAY", @@ -17,6 +25,7 @@ add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_ if is_os("windows") then add_defines("_WEBSOCKETPP_CPP11_INTERNAL_") add_links("ws2_32", "Bcrypt") + add_links("windowsapp", "User32", "Strmiids", "Mfuuid") add_requires("cuda") elseif is_os("linux") then add_links("pthread") @@ -90,14 +99,14 @@ target("media") set_kind("static") add_deps("log", "frame") add_packages("cuda") - add_links("cuda", "nvencodeapi", "nvcuvid") add_files("src/media/video/encode/nvcodec/*.cpp", - "src/media/video/decode/nvcodec/*.cpp") + "src/media/video/decode/nvcodec/*.cpp", "src/media/video/decode/ffmpeg/*.cpp") add_includedirs("src/media/video/encode/nvcodec", - "src/media/video/decode/nvcodec", + "src/media/video/decode/nvcodec", "src/media/video/decode/ffmpeg", "thirdparty/nvcodec/Interface", "thirdparty/nvcodec/Samples", {public = true}) add_linkdirs("thirdparty/nvcodec/Lib/x64") + add_links("cuda", "nvencodeapi", "nvcuvid") target("qos") set_kind("static") @@ -120,6 +129,7 @@ target("pc") add_packages("asio", "nlohmann_json", "cuda") add_includedirs("src/transmission", {public = true}) + target("projectx") set_kind("shared") add_deps("log")