zhuizhu 7 månader sedan
förälder
incheckning
88f1fa179f
42 ändrade filer med 1666 tillägg och 155 borttagningar
  1. 9 7
      libs/Recorder/Recorder.cpp
  2. 1 1
      libs/Recorder/Recorder.pri
  3. 19 0
      libs/Recorder/WGC/dllmain.cpp
  4. 17 0
      libs/Recorder/WGC/export.cpp
  5. 51 0
      libs/Recorder/WGC/export.h
  6. 1 0
      libs/Recorder/WGC/pch.cpp
  7. 48 0
      libs/Recorder/WGC/pch.h
  8. 425 0
      libs/Recorder/WGC/wgc_session_impl.cpp
  9. 104 0
      libs/Recorder/WGC/wgc_session_impl.h
  10. 174 0
      libs/Recorder/d3d_pixelshader.h
  11. 164 0
      libs/Recorder/d3d_vertexshader.h
  12. 12 6
      libs/Recorder/encoder_aac.cpp
  13. 2 1
      libs/Recorder/encoder_video_nvenc.cpp
  14. 1 1
      libs/Recorder/encoder_video_nvenc.h
  15. 2 1
      libs/Recorder/encoder_video_x264.cpp
  16. 1 1
      libs/Recorder/encoder_video_x264.h
  17. 481 0
      libs/Recorder/ffmpeg_compat.h
  18. 2 1
      libs/Recorder/filter.cpp
  19. 3 2
      libs/Recorder/filter_amix.cpp
  20. 4 3
      libs/Recorder/filter_aresample.cpp
  21. 3 3
      libs/Recorder/hardware_acceleration.cpp
  22. 3 0
      libs/Recorder/headers_ffmpeg.h
  23. 2 1
      libs/Recorder/headers_mmdevice.h
  24. 3 3
      libs/Recorder/log_helper.cpp
  25. 1 0
      libs/Recorder/muxer_define.h
  26. 48 57
      libs/Recorder/muxer_ffmpeg.cpp
  27. 1 1
      libs/Recorder/muxer_ffmpeg.h
  28. 2 1
      libs/Recorder/record_audio.cpp
  29. 7 6
      libs/Recorder/record_audio_dshow.cpp
  30. 1 1
      libs/Recorder/record_audio_dshow.h
  31. 3 2
      libs/Recorder/record_audio_wasapi.cpp
  32. 1 1
      libs/Recorder/record_desktop_duplication.cpp
  33. 11 5
      libs/Recorder/record_desktop_ffmpeg_dshow.cpp
  34. 2 2
      libs/Recorder/record_desktop_ffmpeg_dshow.h
  35. 11 5
      libs/Recorder/record_desktop_ffmpeg_gdi.cpp
  36. 2 2
      libs/Recorder/record_desktop_ffmpeg_gdi.h
  37. 1 1
      libs/Recorder/record_desktop_wgc.cpp
  38. 1 1
      libs/Recorder/record_desktop_wgc.h
  39. 7 7
      libs/Recorder/remuxer_ffmpeg.cpp
  40. 10 9
      libs/Recorder/resample_pcm.cpp
  41. 8 7
      libs/Recorder/test_main.cpp
  42. 17 16
      libs/Recorder/transcode_aac.cpp

+ 9 - 7
libs/Recorder/Recorder.cpp

@@ -8,15 +8,17 @@ extern "C" {
 #include "common.h"
 }
 
+#include "headers_ffmpeg.h"
+
 void capture_screen()
 {
     try {
-        av_register_all();
-        avdevice_register_all();
+        ffmpeg_register_all();
+        ffmpeg_register_devices();
 
         AVFormatContext *pFormatCtx = avformat_alloc_context();
 
-        AVInputFormat *ifmt = av_find_input_format("gdigrab");
+        const AVInputFormat *ifmt = av_find_input_format("gdigrab");
         avformat_open_input(&pFormatCtx, "desktop", ifmt, NULL);
 
         if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
@@ -25,7 +27,7 @@ void capture_screen()
 
         int videoIndex = -1;
         for (int i = 0; i < pFormatCtx->nb_streams; i++) {
-            if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+            if (ffmpeg_get_codec_type(pFormatCtx->streams[i]) == AVMEDIA_TYPE_VIDEO) {
                 videoIndex = i;
                 break;
             }
@@ -34,7 +36,7 @@ void capture_screen()
         if (videoIndex == -1)
             throw std::exception("could not find a video stream");
 
-        AVCodecContext *pDecoderCtx = pFormatCtx->streams[videoIndex]->codec;
+        AVCodecContext *pDecoderCtx = ffmpeg_get_codec_context(pFormatCtx->streams[videoIndex]);
 
         //init decoder
         AVCodec *pDecoder = avcodec_find_decoder(pDecoderCtx->codec_id);
@@ -486,7 +488,7 @@ HRESULT capture_audio()
 
     output_codec_context->channels
         = 2; //av_get_channel_layout_nb_channels(pEncoderCtx->channel_layout);
-    output_codec_context->channel_layout = av_get_default_channel_layout(2); //AV_CH_LAYOUT_STEREO;
+    output_codec_context->channel_layout = ffmpeg_get_default_channel_layout(2); //AV_CH_LAYOUT_STEREO;
     output_codec_context->sample_rate = pwfx->nSamplesPerSec;                //48000
     output_codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
     output_codec_context->bit_rate = 96000;
@@ -530,7 +532,7 @@ HRESULT capture_audio()
 
     AVFrame *sample_frame = av_frame_alloc();
     sample_frame->nb_samples = 1024;
-    sample_frame->channel_layout = av_get_default_channel_layout(pwfx->nChannels);
+    sample_frame->channel_layout = ffmpeg_get_default_channel_layout(pwfx->nChannels);
     sample_frame->format = AV_SAMPLE_FMT_FLT;
     sample_frame->sample_rate = pwfx->nSamplesPerSec;
 

+ 1 - 1
libs/Recorder/Recorder.pri

@@ -55,7 +55,7 @@ HEADERS += \
 
 SOURCES += \
     # $$PWD/AecKsBinder.cpp \
-    $$PWD/Recorder.cpp \
+    # $$PWD/Recorder.cpp \
     $$PWD/d3d_helper.cpp \
     $$PWD/device_audios.cpp \
     $$PWD/device_videos.cpp \

+ 19 - 0
libs/Recorder/WGC/dllmain.cpp

@@ -0,0 +1,19 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved
+                     )
+{
+    switch (ul_reason_for_call)
+    {
+    case DLL_PROCESS_ATTACH:
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+        break;
+    }
+    return TRUE;
+}
+

+ 17 - 0
libs/Recorder/WGC/export.cpp

@@ -0,0 +1,17 @@
+#include "pch.h"
+
+#include <winrt/Windows.Foundation.Metadata.h>
+
+bool wgc_is_supported() {
+  try {
+    /* no contract for IGraphicsCaptureItemInterop, verify 10.0.18362.0 */
+    return winrt::Windows::Foundation::Metadata::ApiInformation::
+        IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 8);
+  } catch (const winrt::hresult_error &) {
+    return false;
+  } catch (...) {
+    return false;
+  }
+}
+
+am::wgc_session *wgc_create_session() { return new am::wgc_session_impl(); }

+ 51 - 0
libs/Recorder/WGC/export.h

@@ -0,0 +1,51 @@
+#pragma once
+
+#include <Windows.h>
+
+#ifdef AMRECORDER_IMPORT
+#define AMRECORDER_API extern "C" __declspec(dllimport)
+#else
+#define AMRECORDER_API extern "C" __declspec(dllexport)
+#endif
+
+namespace am {
+class wgc_session
+{
+public:
+    struct wgc_session_frame
+    {
+        unsigned int width;
+        unsigned int height;
+        unsigned int row_pitch;
+
+        const unsigned char *data;
+    };
+
+    class wgc_session_observer
+    {
+    public:
+        virtual ~wgc_session_observer() {}
+        virtual void on_frame(const wgc_session_frame &frame) = 0;
+    };
+
+public:
+    virtual void release() = 0;
+
+    virtual int initialize(HWND hwnd) = 0;
+    virtual int initialize(HMONITOR hmonitor) = 0;
+
+    virtual void register_observer(wgc_session_observer *observer) = 0;
+
+    virtual int start() = 0;
+    virtual int stop() = 0;
+
+    virtual int pause() = 0;
+    virtual int resume() = 0;
+
+protected:
+    virtual ~wgc_session() {};
+};
+} // namespace am
+
+AMRECORDER_API bool wgc_is_supported();
+AMRECORDER_API am::wgc_session *wgc_create_session();

+ 1 - 0
libs/Recorder/WGC/pch.cpp

@@ -0,0 +1 @@
+#include "pch.h"

+ 48 - 0
libs/Recorder/WGC/pch.h

@@ -0,0 +1,48 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for
+// future builds. This also affects IntelliSense performance, including code
+// completion and many code browsing features. However, files listed here are
+// ALL re-compiled if any one of them is updated between builds. Do not add
+// files here that you will be updating frequently as this negates the
+// performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+
+#include <Unknwn.h>
+#include <inspectable.h>
+
+// WinRT
+#include <winrt/Windows.Foundation.h>
+#include <winrt/Windows.System.h>
+#include <winrt/Windows.Graphics.DirectX.h>
+#include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
+#include <winrt/Windows.Graphics.Capture.h>
+#include <Windows.Graphics.Capture.Interop.h>
+
+#include <DispatcherQueue.h>
+
+
+// STL
+#include <atomic>
+#include <memory>
+
+// D3D
+#include <d3d11_4.h>
+#include <dxgi1_6.h>
+#include <d2d1_3.h>
+#include <wincodec.h>
+
+// windowws
+
+#include <Windows.h>
+
+#include "../Recorder/error_define.h"
+#include "export.h"
+#include "wgc_session_impl.h"
+
+#endif // PCH_H

+ 425 - 0
libs/Recorder/WGC/wgc_session_impl.cpp

@@ -0,0 +1,425 @@
+#include "pch.h"
+
+#include <functional>
+#include <memory>
+
+#define CHECK_INIT                                                             \
+  if (!is_initialized_)                                                        \
+  return AM_ERROR::AE_NEED_INIT
+
+#define CHECK_CLOSED                                                           \
+  if (cleaned_.load() == true) {                                               \
+    throw winrt::hresult_error(RO_E_CLOSED);                                   \
+  }
+
+extern "C" {
+HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
+    ::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
+}
+
+namespace am {
+
+wgc_session_impl::wgc_session_impl() {}
+
+wgc_session_impl::~wgc_session_impl() {
+  stop();
+  cleanup();
+}
+
+void wgc_session_impl::release() { delete this; }
+
+int wgc_session_impl::initialize(HWND hwnd) {
+  std::lock_guard locker(lock_);
+
+  target_.hwnd = hwnd;
+  target_.is_window = true;
+  return initialize();
+}
+
+int wgc_session_impl::initialize(HMONITOR hmonitor) {
+  std::lock_guard locker(lock_);
+
+  target_.hmonitor = hmonitor;
+  target_.is_window = false;
+  return initialize();
+}
+
+void wgc_session_impl::register_observer(wgc_session_observer *observer) {
+  std::lock_guard locker(lock_);
+  observer_ = observer;
+}
+
+int wgc_session_impl::start() {
+  std::lock_guard locker(lock_);
+
+  if (is_running_)
+    return AM_ERROR::AE_NO;
+
+  int error = AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
+
+  CHECK_INIT;
+  try {
+    if (!capture_session_) {
+      auto current_size = capture_item_.Size();
+      capture_framepool_ =
+          winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
+              CreateFreeThreaded(d3d11_direct_device_,
+                                 winrt::Windows::Graphics::DirectX::
+                                     DirectXPixelFormat::B8G8R8A8UIntNormalized,
+                                 2, current_size);
+      capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
+      capture_frame_size_ = current_size;
+      capture_framepool_trigger_ = capture_framepool_.FrameArrived(
+          winrt::auto_revoke, {this, &wgc_session_impl::on_frame});
+      capture_close_trigger_ = capture_item_.Closed(
+          winrt::auto_revoke, {this, &wgc_session_impl::on_closed});
+    }
+
+    if (!capture_framepool_)
+      throw std::exception();
+
+    is_running_ = true;
+
+    // we do not need to crate a thread to enter a message loop coz we use
+    // CreateFreeThreaded instead of Create to create a capture frame pool,
+    // we need to test the performance later
+    // loop_ = std::thread(std::bind(&wgc_session_impl::message_func, this));
+
+    capture_session_.StartCapture();
+
+    error = AM_ERROR::AE_NO;
+  } catch (winrt::hresult_error) {
+    return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
+  } catch (...) {
+    return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
+  }
+
+  return error;
+}
+
+int wgc_session_impl::stop() {
+  std::lock_guard locker(lock_);
+
+  CHECK_INIT;
+
+  is_running_ = false;
+
+  if (loop_.joinable())
+    loop_.join();
+
+  if (capture_framepool_trigger_)
+    capture_framepool_trigger_.revoke();
+
+  if (capture_session_) {
+    capture_session_.Close();
+    capture_session_ = nullptr;
+  }
+
+  return AM_ERROR::AE_NO;
+}
+
+int wgc_session_impl::pause() {
+  std::lock_guard locker(lock_);
+
+  CHECK_INIT;
+  return AM_ERROR::AE_NO;
+}
+
+int wgc_session_impl::resume() {
+  std::lock_guard locker(lock_);
+
+  CHECK_INIT;
+  return AM_ERROR::AE_NO;
+}
+
+auto wgc_session_impl::create_d3d11_device() {
+  auto create_d3d_device = [](D3D_DRIVER_TYPE const type,
+                              winrt::com_ptr<ID3D11Device> &device) {
+    WINRT_ASSERT(!device);
+
+    UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
+
+    //#ifdef _DEBUG
+    //	flags |= D3D11_CREATE_DEVICE_DEBUG;
+    //#endif
+
+    return ::D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
+                               D3D11_SDK_VERSION, device.put(), nullptr,
+                               nullptr);
+  };
+  auto create_d3d_device_wrapper = [&create_d3d_device]() {
+    winrt::com_ptr<ID3D11Device> device;
+    HRESULT hr = create_d3d_device(D3D_DRIVER_TYPE_HARDWARE, device);
+
+    if (DXGI_ERROR_UNSUPPORTED == hr) {
+      hr = create_d3d_device(D3D_DRIVER_TYPE_WARP, device);
+    }
+
+    winrt::check_hresult(hr);
+    return device;
+  };
+
+  auto d3d_device = create_d3d_device_wrapper();
+  auto dxgi_device = d3d_device.as<IDXGIDevice>();
+
+  winrt::com_ptr<::IInspectable> d3d11_device;
+  winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
+      dxgi_device.get(), d3d11_device.put()));
+  return d3d11_device
+      .as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
+}
+
+auto wgc_session_impl::create_capture_item(HWND hwnd) {
+  auto activation_factory = winrt::get_activation_factory<
+      winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
+  auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
+  winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
+  interop_factory->CreateForWindow(
+      hwnd,
+      winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
+      reinterpret_cast<void **>(winrt::put_abi(item)));
+  return item;
+}
+
+auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) {
+  auto activation_factory = winrt::get_activation_factory<
+      winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
+  auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
+  winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
+  interop_factory->CreateForMonitor(
+      hmonitor,
+      winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
+      reinterpret_cast<void **>(winrt::put_abi(item)));
+  return item;
+}
+
+HRESULT wgc_session_impl::create_mapped_texture(
+    winrt::com_ptr<ID3D11Texture2D> src_texture, unsigned int width,
+    unsigned int height) {
+
+  D3D11_TEXTURE2D_DESC src_desc;
+  src_texture->GetDesc(&src_desc);
+  D3D11_TEXTURE2D_DESC map_desc;
+  map_desc.Width = width == 0 ? src_desc.Width : width;
+  map_desc.Height = height == 0 ? src_desc.Height : height;
+  map_desc.MipLevels = src_desc.MipLevels;
+  map_desc.ArraySize = src_desc.ArraySize;
+  map_desc.Format = src_desc.Format;
+  map_desc.SampleDesc = src_desc.SampleDesc;
+  map_desc.Usage = D3D11_USAGE_STAGING;
+  map_desc.BindFlags = 0;
+  map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+  map_desc.MiscFlags = 0;
+
+  auto d3dDevice = get_dxgi_interface<ID3D11Device>(d3d11_direct_device_);
+
+  return d3dDevice->CreateTexture2D(&map_desc, nullptr,
+                                    d3d11_texture_mapped_.put());
+}
+
+void wgc_session_impl::on_frame(
+    winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender,
+    winrt::Windows::Foundation::IInspectable const &args) {
+  std::lock_guard locker(lock_);
+
+  auto is_new_size = false;
+
+  {
+    auto frame = sender.TryGetNextFrame();
+    auto frame_size = frame.ContentSize();
+
+    if (frame_size.Width != capture_frame_size_.Width ||
+        frame_size.Height != capture_frame_size_.Height) {
+      // The thing we have been capturing has changed size.
+      // We need to resize our swap chain first, then blit the pixels.
+      // After we do that, retire the frame and then recreate our frame pool.
+      is_new_size = true;
+      capture_frame_size_ = frame_size;
+    }
+
+    // copy to mapped texture
+    {
+      auto frame_captured =
+          get_dxgi_interface<ID3D11Texture2D>(frame.Surface());
+
+      if (!d3d11_texture_mapped_ || is_new_size)
+        create_mapped_texture(frame_captured);
+
+      d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
+                                          frame_captured.get());
+
+      D3D11_MAPPED_SUBRESOURCE map_result;
+      HRESULT hr = d3d11_device_context_->Map(
+          d3d11_texture_mapped_.get(), 0, D3D11_MAP_READ,
+          0 /*coz we use CreateFreeThreaded, so we cant use flags
+               D3D11_MAP_FLAG_DO_NOT_WAIT*/
+          ,
+          &map_result);
+      if (FAILED(hr)) {
+        OutputDebugStringW(
+            (L"map resource failed: " + std::to_wstring(hr)).c_str());
+      }
+
+      // copy data from map_result.pData
+      if (map_result.pData && observer_) {
+        observer_->on_frame(wgc_session_frame{
+            static_cast<unsigned int>(frame_size.Width),
+            static_cast<unsigned int>(frame_size.Height), map_result.RowPitch,
+            const_cast<const unsigned char *>(
+                (unsigned char *)map_result.pData)});
+      }
+#if 0
+      if (map_result.pData) {
+        static unsigned char *buffer = nullptr;
+        if (buffer && is_new_size)
+          delete[] buffer;
+
+        if (!buffer)
+          buffer = new unsigned char[frame_size.Width * frame_size.Height * 4];
+
+        int dstRowPitch = frame_size.Width * 4;
+        for (int h = 0; h < frame_size.Height; h++) {
+          memcpy_s(buffer + h * dstRowPitch, dstRowPitch,
+                   (BYTE *)map_result.pData + h * map_result.RowPitch,
+                   min(map_result.RowPitch, dstRowPitch));
+        }
+
+        BITMAPINFOHEADER bi;
+
+        bi.biSize = sizeof(BITMAPINFOHEADER);
+        bi.biWidth = frame_size.Width;
+        bi.biHeight = frame_size.Height * (-1);
+        bi.biPlanes = 1;
+        bi.biBitCount = 32; // should get from system color bits
+        bi.biCompression = BI_RGB;
+        bi.biSizeImage = 0;
+        bi.biXPelsPerMeter = 0;
+        bi.biYPelsPerMeter = 0;
+        bi.biClrUsed = 0;
+        bi.biClrImportant = 0;
+
+        BITMAPFILEHEADER bf;
+        bf.bfType = 0x4d42;
+        bf.bfReserved1 = 0;
+        bf.bfReserved2 = 0;
+        bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+        bf.bfSize = bf.bfOffBits + frame_size.Width * frame_size.Height * 4;
+
+        FILE *fp = nullptr;
+
+        fopen_s(&fp, ".\\save.bmp", "wb+");
+
+        fwrite(&bf, 1, sizeof(bf), fp);
+        fwrite(&bi, 1, sizeof(bi), fp);
+        fwrite(buffer, 1, frame_size.Width * frame_size.Height * 4, fp);
+
+        fflush(fp);
+        fclose(fp);
+      }
+#endif
+
+      d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
+    }
+  }
+
+  if (is_new_size) {
+    capture_framepool_.Recreate(d3d11_direct_device_,
+                                winrt::Windows::Graphics::DirectX::
+                                    DirectXPixelFormat::B8G8R8A8UIntNormalized,
+                                2, capture_frame_size_);
+  }
+}
+
+void wgc_session_impl::on_closed(
+    winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
+    winrt::Windows::Foundation::IInspectable const &) {
+  OutputDebugStringW(L"wgc_session_impl::on_closed");
+}
+
+int wgc_session_impl::initialize() {
+  if (is_initialized_)
+    return AM_ERROR::AE_NO;
+
+  if (!(d3d11_direct_device_ = create_d3d11_device()))
+    return AM_ERROR::AE_D3D_CREATE_DEVICE_FAILED;
+
+  try {
+    if (target_.is_window)
+      capture_item_ = create_capture_item(target_.hwnd);
+    else
+      capture_item_ = create_capture_item(target_.hmonitor);
+
+    // Set up
+    auto d3d11_device = get_dxgi_interface<ID3D11Device>(d3d11_direct_device_);
+    d3d11_device->GetImmediateContext(d3d11_device_context_.put());
+
+  } catch (winrt::hresult_error) {
+    return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
+  } catch (...) {
+    return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
+  }
+
+  is_initialized_ = true;
+
+  return AM_ERROR::AE_NO;
+}
+
+void wgc_session_impl::cleanup() {
+  std::lock_guard locker(lock_);
+
+  auto expected = false;
+  if (cleaned_.compare_exchange_strong(expected, true)) {
+    capture_close_trigger_.revoke();
+    capture_framepool_trigger_.revoke();
+
+    if (capture_framepool_)
+      capture_framepool_.Close();
+
+    if (capture_session_)
+      capture_session_.Close();
+
+    capture_framepool_ = nullptr;
+    capture_session_ = nullptr;
+    capture_item_ = nullptr;
+
+    is_initialized_ = false;
+  }
+}
+
+LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
+                            LPARAM l_param) {
+  return DefWindowProc(window, message, w_param, l_param);
+}
+
+void wgc_session_impl::message_func() {
+  const std::wstring kClassName = L"am_fake_window";
+
+  WNDCLASS wc = {};
+
+  wc.style = CS_HREDRAW | CS_VREDRAW;
+  wc.lpfnWndProc = DefWindowProc;
+  wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
+  wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
+  wc.lpszClassName = kClassName.c_str();
+
+  if (!::RegisterClassW(&wc))
+    return;
+
+  hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW, 0,
+                          0, 0, 0, nullptr, nullptr, nullptr, nullptr);
+  MSG msg;
+  while (is_running_) {
+    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+      if (!is_running_)
+        break;
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+    Sleep(10);
+  }
+
+  ::CloseWindow(hwnd_);
+  ::DestroyWindow(hwnd_);
+}
+
+} // namespace am

+ 104 - 0
libs/Recorder/WGC/wgc_session_impl.h

@@ -0,0 +1,104 @@
+#pragma once
+
+#include <mutex>
+#include <thread>
+
+namespace am {
+class wgc_session_impl : public wgc_session {
+  struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
+      IDirect3DDxgiInterfaceAccess : ::IUnknown {
+    virtual HRESULT __stdcall GetInterface(GUID const &id, void **object) = 0;
+  };
+
+  struct {
+    union {
+      HWND hwnd;
+      HMONITOR hmonitor;
+    };
+    bool is_window;
+  } target_{0};
+
+public:
+  wgc_session_impl();
+  ~wgc_session_impl() override;
+
+public:
+  void release() override;
+
+  int initialize(HWND hwnd) override;
+  int initialize(HMONITOR hmonitor) override;
+
+  void register_observer(wgc_session_observer *observer) override;
+
+  int start() override;
+  int stop() override;
+
+  int pause() override;
+  int resume() override;
+
+private:
+  auto create_d3d11_device();
+  auto create_capture_item(HWND hwnd);
+  auto create_capture_item(HMONITOR hmonitor);
+  template <typename T>
+  auto
+  get_dxgi_interface(winrt::Windows::Foundation::IInspectable const &object);
+  HRESULT create_mapped_texture(winrt::com_ptr<ID3D11Texture2D> src_texture,
+                                unsigned int width = 0,
+                                unsigned int height = 0);
+  void
+  on_frame(winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const
+               &sender,
+           winrt::Windows::Foundation::IInspectable const &args);
+  void on_closed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
+                 winrt::Windows::Foundation::IInspectable const &);
+
+  int initialize();
+  void cleanup();
+
+  void message_func();
+
+private:
+  std::mutex lock_;
+  bool is_initialized_ = false;
+  bool is_running_ = false;
+  bool is_paused_ = false;
+
+  wgc_session_observer *observer_ = nullptr;
+
+  // wgc
+  winrt::Windows::Graphics::Capture::GraphicsCaptureItem capture_item_{nullptr};
+  winrt::Windows::Graphics::Capture::GraphicsCaptureSession capture_session_{
+      nullptr};
+  winrt::Windows::Graphics::SizeInt32 capture_frame_size_;
+
+  winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice
+      d3d11_direct_device_{nullptr};
+  winrt::com_ptr<ID3D11DeviceContext> d3d11_device_context_{nullptr};
+  winrt::com_ptr<ID3D11Texture2D> d3d11_texture_mapped_{nullptr};
+
+  std::atomic<bool> cleaned_ = false;
+  winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool
+      capture_framepool_{nullptr};
+  winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
+      FrameArrived_revoker capture_framepool_trigger_;
+  winrt::Windows::Graphics::Capture::GraphicsCaptureItem::Closed_revoker
+      capture_close_trigger_;
+
+  // message loop
+  std::thread loop_;
+  HWND hwnd_ = nullptr;
+};
+
+template <typename T>
+inline auto wgc_session_impl::get_dxgi_interface(
+    winrt::Windows::Foundation::IInspectable const &object) {
+  auto access = object.as<IDirect3DDxgiInterfaceAccess>();
+  winrt::com_ptr<T> result;
+  winrt::check_hresult(
+      access->GetInterface(winrt::guid_of<T>(), result.put_void()));
+  return result;
+}
+
+
+} // namespace am

+ 174 - 0
libs/Recorder/d3d_pixelshader.h

@@ -0,0 +1,174 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Resource Bindings:
+//
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// samLinear                         sampler      NA          NA             s0      1 
+// tx                                texture  float4          2d             t0      1 
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+//
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler  Source Resource
+// -------------- --------------- ----------------
+// s0             s0              t0               
+//
+//
+// Level9 shader bytecode:
+//
+    ps_2_x
+    dcl t0.xy
+    dcl_2d s0
+    texld r0, t0, s0
+    mov oC0, r0
+
+// approximately 2 instruction slots used (1 texture, 1 arithmetic)
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xy
+dcl_output o0.xyzw
+sample o0.xyzw, v1.xyxx, t0.xyzw, s0
+ret 
+// Approximately 2 instruction slots used
+#endif
+
+const BYTE g_PS[] =
+{
+     68,  88,  66,  67,   2,  67, 
+    173, 250, 254,  69,   0, 177, 
+     12, 180,  52, 221,  45,  84, 
+    178, 127,   1,   0,   0,   0, 
+    180,   2,   0,   0,   6,   0, 
+      0,   0,  56,   0,   0,   0, 
+    164,   0,   0,   0,  16,   1, 
+      0,   0, 140,   1,   0,   0, 
+     40,   2,   0,   0, 128,   2, 
+      0,   0,  65, 111, 110,  57, 
+    100,   0,   0,   0, 100,   0, 
+      0,   0,   0,   2, 255, 255, 
+     60,   0,   0,   0,  40,   0, 
+      0,   0,   0,   0,  40,   0, 
+      0,   0,  40,   0,   0,   0, 
+     40,   0,   1,   0,  36,   0, 
+      0,   0,  40,   0,   0,   0, 
+      0,   0,   1,   2, 255, 255, 
+     31,   0,   0,   2,   0,   0, 
+      0, 128,   0,   0,   3, 176, 
+     31,   0,   0,   2,   0,   0, 
+      0, 144,   0,   8,  15, 160, 
+     66,   0,   0,   3,   0,   0, 
+     15, 128,   0,   0, 228, 176, 
+      0,   8, 228, 160,   1,   0, 
+      0,   2,   0,   8,  15, 128, 
+      0,   0, 228, 128, 255, 255, 
+      0,   0,  83,  72,  68,  82, 
+    100,   0,   0,   0,  64,   0, 
+      0,   0,  25,   0,   0,   0, 
+     90,   0,   0,   3,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     88,  24,   0,   4,   0, 112, 
+     16,   0,   0,   0,   0,   0, 
+     85,  85,   0,   0,  98,  16, 
+      0,   3,  50,  16,  16,   0, 
+      1,   0,   0,   0, 101,   0, 
+      0,   3, 242,  32,  16,   0, 
+      0,   0,   0,   0,  69,   0, 
+      0,   9, 242,  32,  16,   0, 
+      0,   0,   0,   0,  70,  16, 
+     16,   0,   1,   0,   0,   0, 
+     70, 126,  16,   0,   0,   0, 
+      0,   0,   0,  96,  16,   0, 
+      0,   0,   0,   0,  62,   0, 
+      0,   1,  83,  84,  65,  84, 
+    116,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+     82,  68,  69,  70, 148,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   2,   0, 
+      0,   0,  28,   0,   0,   0, 
+      0,   4, 255, 255,   0,   1, 
+      0,   0, 105,   0,   0,   0, 
+     92,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   1,   0, 
+      0,   0, 102,   0,   0,   0, 
+      2,   0,   0,   0,   5,   0, 
+      0,   0,   4,   0,   0,   0, 
+    255, 255, 255, 255,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     13,   0,   0,   0, 115,  97, 
+    109,  76, 105, 110, 101,  97, 
+    114,   0, 116, 120,   0,  77, 
+    105,  99, 114, 111, 115, 111, 
+    102, 116,  32,  40,  82,  41, 
+     32,  72,  76,  83,  76,  32, 
+     83, 104,  97, 100, 101, 114, 
+     32,  67, 111, 109, 112, 105, 
+    108, 101, 114,  32,  49,  48, 
+     46,  49,   0, 171, 171, 171, 
+     73,  83,  71,  78,  80,   0, 
+      0,   0,   2,   0,   0,   0, 
+      8,   0,   0,   0,  56,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0,  68,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   3,   0,   0,  83,  86, 
+     95,  80,  79,  83,  73,  84, 
+     73,  79,  78,   0,  84,  69, 
+     88,  67,  79,  79,  82,  68, 
+      0, 171, 171, 171,  79,  83, 
+     71,  78,  44,   0,   0,   0, 
+      1,   0,   0,   0,   8,   0, 
+      0,   0,  32,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  83,  86,  95,  84, 
+     97, 114, 103, 101, 116,   0, 
+    171, 171
+};

+ 164 - 0
libs/Recorder/d3d_vertexshader.h

@@ -0,0 +1,164 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xyzw        0     NONE   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Runtime generated constant mappings:
+//
+// Target Reg                               Constant Description
+// ---------- --------------------------------------------------
+// c0                              Vertex Shader position offset
+//
+//
+// Level9 shader bytecode:
+//
+    vs_2_x
+    dcl_texcoord v0
+    dcl_texcoord1 v1
+    mad oPos.xy, v0.w, c0, v0
+    mov oPos.zw, v0
+    mov oT0.xy, v1
+
+// approximately 3 instruction slots used
+vs_4_0
+dcl_input v0.xyzw
+dcl_input v1.xy
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xy
+mov o0.xyzw, v0.xyzw
+mov o1.xy, v1.xyxx
+ret 
+// Approximately 3 instruction slots used
+#endif
+
+const BYTE g_VS[] =
+{
+     68,  88,  66,  67,   7, 246, 
+    106, 219, 121, 145,  17, 190, 
+     59, 174,  90, 248, 179, 172, 
+     97,  77,   1,   0,   0,   0, 
+    152,   2,   0,   0,   6,   0, 
+      0,   0,  56,   0,   0,   0, 
+    180,   0,   0,   0,  36,   1, 
+      0,   0, 160,   1,   0,   0, 
+    236,   1,   0,   0,  64,   2, 
+      0,   0,  65, 111, 110,  57, 
+    116,   0,   0,   0, 116,   0, 
+      0,   0,   0,   2, 254, 255, 
+     76,   0,   0,   0,  40,   0, 
+      0,   0,   0,   0,  36,   0, 
+      0,   0,  36,   0,   0,   0, 
+     36,   0,   0,   0,  36,   0, 
+      1,   0,  36,   0,   0,   0, 
+      0,   0,   1,   2, 254, 255, 
+     31,   0,   0,   2,   5,   0, 
+      0, 128,   0,   0,  15, 144, 
+     31,   0,   0,   2,   5,   0, 
+      1, 128,   1,   0,  15, 144, 
+      4,   0,   0,   4,   0,   0, 
+      3, 192,   0,   0, 255, 144, 
+      0,   0, 228, 160,   0,   0, 
+    228, 144,   1,   0,   0,   2, 
+      0,   0,  12, 192,   0,   0, 
+    228, 144,   1,   0,   0,   2, 
+      0,   0,   3, 224,   1,   0, 
+    228, 144, 255, 255,   0,   0, 
+     83,  72,  68,  82, 104,   0, 
+      0,   0,  64,   0,   1,   0, 
+     26,   0,   0,   0,  95,   0, 
+      0,   3, 242,  16,  16,   0, 
+      0,   0,   0,   0,  95,   0, 
+      0,   3,  50,  16,  16,   0, 
+      1,   0,   0,   0, 103,   0, 
+      0,   4, 242,  32,  16,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0, 101,   0,   0,   3, 
+     50,  32,  16,   0,   1,   0, 
+      0,   0,  54,   0,   0,   5, 
+    242,  32,  16,   0,   0,   0, 
+      0,   0,  70,  30,  16,   0, 
+      0,   0,   0,   0,  54,   0, 
+      0,   5,  50,  32,  16,   0, 
+      1,   0,   0,   0,  70,  16, 
+     16,   0,   1,   0,   0,   0, 
+     62,   0,   0,   1,  83,  84, 
+     65,  84, 116,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,  82,  68,  69,  70, 
+     68,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,  28,   0, 
+      0,   0,   0,   4, 254, 255, 
+      0,   1,   0,   0,  28,   0, 
+      0,   0,  77, 105,  99, 114, 
+    111, 115, 111, 102, 116,  32, 
+     40,  82,  41,  32,  72,  76, 
+     83,  76,  32,  83, 104,  97, 
+    100, 101, 114,  32,  67, 111, 
+    109, 112, 105, 108, 101, 114, 
+     32,  49,  48,  46,  49,   0, 
+     73,  83,  71,  78,  76,   0, 
+      0,   0,   2,   0,   0,   0, 
+      8,   0,   0,   0,  56,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     15,  15,   0,   0,  65,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   3,   0,   0,  80,  79, 
+     83,  73,  84,  73,  79,  78, 
+      0,  84,  69,  88,  67,  79, 
+     79,  82,  68,   0, 171, 171, 
+     79,  83,  71,  78,  80,   0, 
+      0,   0,   2,   0,   0,   0, 
+      8,   0,   0,   0,  56,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0,  68,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,  12,   0,   0,  83,  86, 
+     95,  80,  79,  83,  73,  84, 
+     73,  79,  78,   0,  84,  69, 
+     88,  67,  79,  79,  82,  68, 
+      0, 171, 171, 171
+};

+ 12 - 6
libs/Recorder/encoder_aac.cpp

@@ -1,4 +1,5 @@
 #include "encoder_aac.h"
+#include "headers_ffmpeg.h"
 
 #include "ring_buffer.h"
 
@@ -8,7 +9,7 @@
 namespace am {
 encoder_aac::encoder_aac()
 {
-    av_register_all();
+    ffmpeg_register_all();
 
     _ring_buffer = new ring_buffer<AVFrame>(1024 * 1024 * 10);
 
@@ -48,7 +49,7 @@ int encoder_aac::init(int nb_channels, int sample_rate, AVSampleFormat fmt, int
         return err;
 
     do {
-        _encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
+        _encoder = (AVCodec*)avcodec_find_encoder(AV_CODEC_ID_AAC);
         if (!_encoder) {
             err = AE_FFMPEG_FIND_ENCODER_FAILED;
             break;
@@ -60,8 +61,8 @@ int encoder_aac::init(int nb_channels, int sample_rate, AVSampleFormat fmt, int
             break;
         }
 
-        _encoder_ctx->channels = nb_channels;
-        _encoder_ctx->channel_layout = av_get_default_channel_layout(nb_channels);
+        ffmpeg_set_channels(_encoder_ctx, nb_channels);
+        ffmpeg_set_channel_layout(_encoder_ctx, ffmpeg_get_default_channel_layout(nb_channels));
         _encoder_ctx->sample_rate = sample_rate;
         _encoder_ctx->sample_fmt = fmt;
         _encoder_ctx->bit_rate = bit_rate;
@@ -86,9 +87,9 @@ int encoder_aac::init(int nb_channels, int sample_rate, AVSampleFormat fmt, int
             break;
         }
 
-        _frame->channels = nb_channels;
+        ffmpeg_set_frame_channels(_frame, nb_channels);
         _frame->nb_samples = _encoder_ctx->frame_size;
-        _frame->channel_layout = av_get_default_channel_layout(nb_channels);
+        ffmpeg_set_frame_channel_layout(_frame, ffmpeg_get_default_channel_layout(nb_channels));
         _frame->format = fmt;
         _frame->sample_rate = sample_rate;
 
@@ -268,7 +269,12 @@ void encoder_aac::encode_loop()
 
         while ((len = _ring_buffer->get(_buff, _buff_size, pcm_frame))) {
             _frame->pts = pcm_frame.pts;
+#if FFMPEG_VERSION_MAJOR >= 7
+            // In FFmpeg 7+, pkt_pts is removed, use pts instead
+            // _frame->pts is already set above
+#else
             _frame->pkt_pts = pcm_frame.pkt_pts;
+#endif
             _frame->pkt_dts = pcm_frame.pkt_dts;
 
             if ((error = encode(_frame, packet)) != AE_NO) {

+ 2 - 1
libs/Recorder/encoder_video_nvenc.cpp

@@ -1,9 +1,10 @@
 #include "encoder_video_nvenc.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 encoder_video_nvenc::encoder_video_nvenc()
 {
-    av_register_all();
+    ffmpeg_register_all();
 
     _encoder = NULL;
     _encoder_ctx = NULL;

+ 1 - 1
libs/Recorder/encoder_video_nvenc.h

@@ -26,7 +26,7 @@ private:
     int encode(AVFrame *frame, AVPacket *packet);
 
 private:
-    AVCodec *_encoder;
+    FFmpegCodec *_encoder;
     AVCodecContext *_encoder_ctx;
     AVFrame *_frame;
     uint8_t *_buff;

+ 2 - 1
libs/Recorder/encoder_video_x264.cpp

@@ -1,4 +1,5 @@
 #include "encoder_video_x264.h"
+#include "headers_ffmpeg.h"
 
 #include "error_define.h"
 #include "log_helper.h"
@@ -6,7 +7,7 @@
 namespace am {
 encoder_video_x264::encoder_video_x264()
 {
-    av_register_all();
+    ffmpeg_register_all();
 
     _encoder = NULL;
     _encoder_ctx = NULL;

+ 1 - 1
libs/Recorder/encoder_video_x264.h

@@ -26,7 +26,7 @@ private:
     int encode(AVFrame *frame, AVPacket *packet);
 
 private:
-    AVCodec *_encoder;
+    FFmpegCodec *_encoder;
     AVCodecContext *_encoder_ctx;
     AVFrame *_frame;
     uint8_t *_buff;

+ 481 - 0
libs/Recorder/ffmpeg_compat.h

@@ -0,0 +1,481 @@
+#pragma once
+
+/**
+ * FFmpeg Version Compatibility Header
+ * This file provides compatibility macros and functions for different FFmpeg versions
+ * Supports FFmpeg 3.x, 4.x, 5.x, 6.x, and 7.x
+ */
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavdevice/avdevice.h>
+#include <libavutil/channel_layout.h>
+#include <libavcodec/bsf.h>
+}
+
+// FFmpeg version detection
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
+    #define FFMPEG_VERSION_MAJOR 3
+#elif LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 0, 100)
+    #define FFMPEG_VERSION_MAJOR 4
+#elif LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(60, 0, 100)
+    #define FFMPEG_VERSION_MAJOR 5
+#elif LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(61, 0, 100)
+    #define FFMPEG_VERSION_MAJOR 6
+#else
+    #define FFMPEG_VERSION_MAJOR 7
+#endif
+
+// Compatibility functions for deprecated functions
+inline void ffmpeg_register_all() {
+#if FFMPEG_VERSION_MAJOR < 4
+    av_register_all();
+#endif
+    // No-op in FFmpeg 4.0+
+}
+
+inline void ffmpeg_register_devices() {
+#if FFMPEG_VERSION_MAJOR < 4
+    avdevice_register_all();
+#endif
+    // No-op in FFmpeg 4.0+
+}
+
+// Compatibility for AVInputFormat/AVOutputFormat
+#if FFMPEG_VERSION_MAJOR >= 4
+    using FFmpegInputFormat = const AVInputFormat;
+    using FFmpegOutputFormat = const AVOutputFormat;
+#else
+    using FFmpegInputFormat = AVInputFormat;
+    using FFmpegOutputFormat = AVOutputFormat;
+#endif
+
+// Compatibility for AVCodec pointer
+#if FFMPEG_VERSION_MAJOR >= 7
+    using FFmpegCodec = const AVCodec;
+#else
+    using FFmpegCodec = AVCodec;
+#endif
+
+// Compatibility for av_err2str macro (C++ safe version)
+#ifdef __cplusplus
+#undef av_err2str
+#ifdef _MSC_VER
+#include <malloc.h>
+#define av_err2str(errnum) av_make_error_string((char*)_alloca(AV_ERROR_MAX_STRING_SIZE), AV_ERROR_MAX_STRING_SIZE, errnum)
+#else
+#define av_err2str(errnum) av_make_error_string((char*)__builtin_alloca(AV_ERROR_MAX_STRING_SIZE), AV_ERROR_MAX_STRING_SIZE, errnum)
+#endif
+#endif
+
+// Compatibility for bitstream filter context
+#if FFMPEG_VERSION_MAJOR >= 6
+    using AVBitStreamFilterContext = AVBSFContext;
+#endif
+
+// Compatibility functions for codec context access
+inline AVMediaType ffmpeg_get_codec_type(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->codec_type;
+#else
+    return stream->codec->codec_type;
+#endif
+}
+
+inline AVCodecID ffmpeg_get_codec_id(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->codec_id;
+#else
+    return stream->codec->codec_id;
+#endif
+}
+
+inline int ffmpeg_get_codec_width(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->width;
+#else
+    return stream->codec->width;
+#endif
+}
+
+inline int ffmpeg_get_codec_height(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->height;
+#else
+    return stream->codec->height;
+#endif
+}
+
+inline AVPixelFormat ffmpeg_get_codec_pix_fmt(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return static_cast<AVPixelFormat>(stream->codecpar->format);
+#else
+    return stream->codec->pix_fmt;
+#endif
+}
+
+inline int ffmpeg_get_codec_sample_rate(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->sample_rate;
+#else
+    return stream->codec->sample_rate;
+#endif
+}
+
+inline int ffmpeg_get_codec_channels(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    return stream->codecpar->ch_layout.nb_channels;
+#elif FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->channels;
+#else
+    return stream->codec->channels;
+#endif
+}
+
+inline uint64_t ffmpeg_get_codec_channel_layout(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    // In FFmpeg 7, use ch_layout.u.mask directly if it's a mask layout
+    if (stream->codecpar->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) {
+        return stream->codecpar->ch_layout.u.mask;
+    } else {
+        // For non-mask layouts, return a default stereo layout
+        return AV_CH_LAYOUT_STEREO;
+    }
+#elif FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->channel_layout;
+#else
+    return stream->codec->channel_layout;
+#endif
+}
+
+inline AVSampleFormat ffmpeg_get_codec_sample_fmt(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return static_cast<AVSampleFormat>(stream->codecpar->format);
+#else
+    return stream->codec->sample_fmt;
+#endif
+}
+
+// Compatibility for channel layout functions
+inline uint64_t ffmpeg_get_default_channel_layout(int channels) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    AVChannelLayout ch_layout;
+    av_channel_layout_default(&ch_layout, channels);
+    if (ch_layout.order == AV_CHANNEL_ORDER_NATIVE) {
+        return ch_layout.u.mask;
+    } else {
+        // Fallback for common channel counts
+        switch (channels) {
+            case 1: return AV_CH_LAYOUT_MONO;
+            case 2: return AV_CH_LAYOUT_STEREO;
+            case 6: return AV_CH_LAYOUT_5POINT1;
+            case 8: return AV_CH_LAYOUT_7POINT1;
+            default: return AV_CH_LAYOUT_STEREO;
+        }
+    }
+#else
+    return av_get_default_channel_layout(channels);
+#endif
+}
+
+// Compatibility for filter registration
+inline void ffmpeg_register_filters() {
+#if FFMPEG_VERSION_MAJOR < 4
+    avfilter_register_all();
+#endif
+    // No-op in FFmpeg 4.0+
+}
+
+// Compatibility for channel layout string functions
+inline int ffmpeg_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    (void)nb_channels; // Suppress unused parameter warning
+    AVChannelLayout ch_layout;
+    av_channel_layout_from_mask(&ch_layout, channel_layout);
+    return av_channel_layout_describe(&ch_layout, buf, buf_size);
+#else
+    av_get_channel_layout_string(buf, buf_size, nb_channels, channel_layout);
+    return strlen(buf);
+#endif
+}
+
+// Compatibility for AVFrame channels access
+inline int ffmpeg_get_frame_channels(AVFrame* frame) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    return frame->ch_layout.nb_channels;
+#else
+    return frame->channels;
+#endif
+}
+
+// Compatibility for av_samples_get_buffer_size
+inline int ffmpeg_get_buffer_size(enum AVSampleFormat sample_fmt, int nb_channels, int nb_samples, int align) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    return av_samples_get_buffer_size(nullptr, nb_channels, nb_samples, sample_fmt, align);
+#else
+    return av_samples_get_buffer_size(nullptr, nb_channels, nb_samples, sample_fmt, align);
+#endif
+}
+
+// Compatibility for codec context creation from stream
+inline AVCodecContext* ffmpeg_get_codec_context(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    const AVCodec* codec = avcodec_find_decoder(stream->codecpar->codec_id);
+    if (!codec) return nullptr;
+    
+    AVCodecContext* ctx = avcodec_alloc_context3(codec);
+    if (!ctx) return nullptr;
+    
+    if (avcodec_parameters_to_context(ctx, stream->codecpar) < 0) {
+        avcodec_free_context(&ctx);
+        return nullptr;
+    }
+    
+    return ctx;
+#else
+    return stream->codec;
+#endif
+}
+
+// Compatibility for setting stream codec parameters
+inline void ffmpeg_set_stream_codec_id(AVStream* stream, enum AVCodecID codec_id) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->codec_id = codec_id;
+#else
+    stream->codec->codec_id = codec_id;
+#endif
+}
+
+inline void ffmpeg_set_stream_codec_type(AVStream* stream, enum AVMediaType codec_type) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->codec_type = codec_type;
+#else
+    stream->codec->codec_type = codec_type;
+#endif
+}
+
+inline void ffmpeg_set_stream_bit_rate(AVStream* stream, int64_t bit_rate) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->bit_rate = bit_rate;
+#else
+    stream->codec->bit_rate = bit_rate;
+#endif
+}
+
+inline void ffmpeg_set_stream_pix_fmt(AVStream* stream, enum AVPixelFormat pix_fmt) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->format = pix_fmt;
+#else
+    stream->codec->pix_fmt = pix_fmt;
+#endif
+}
+
+inline void ffmpeg_set_stream_dimensions(AVStream* stream, int width, int height) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->width = width;
+    stream->codecpar->height = height;
+#else
+    stream->codec->width = width;
+    stream->codec->height = height;
+#endif
+}
+
+// Compatibility for stream codec parameters
+inline int ffmpeg_copy_codec_params_to_stream(AVStream* stream, AVCodecContext* codec_ctx) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return avcodec_parameters_from_context(stream->codecpar, codec_ctx);
+#else
+    return 0;  // No-op for older versions
+#endif
+}
+
+// Compatibility for extradata access
+inline uint8_t* ffmpeg_get_extradata(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->extradata;
+#else
+    return stream->codec->extradata;
+#endif
+}
+
+inline int ffmpeg_get_extradata_size(AVStream* stream) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    return stream->codecpar->extradata_size;
+#else
+    return stream->codec->extradata_size;
+#endif
+}
+
+inline void ffmpeg_set_stream_extradata(AVStream* stream, uint8_t* data, int size) {
+#if FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->extradata = data;
+    stream->codecpar->extradata_size = size;
+#else
+    stream->codec->extradata = data;
+    stream->codec->extradata_size = size;
+#endif
+}
+
+// Compatibility for AVCodecContext channels and channel_layout
+inline void ffmpeg_set_codec_channels(AVCodecContext* ctx, int channels) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_default(&ctx->ch_layout, channels);
+#else
+    ctx->channels = channels;
+#endif
+}
+
+inline void ffmpeg_set_codec_channel_layout(AVCodecContext* ctx, uint64_t channel_layout) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_from_mask(&ctx->ch_layout, channel_layout);
+#else
+    ctx->channel_layout = channel_layout;
+#endif
+}
+
+inline int ffmpeg_get_codec_context_channels(AVCodecContext* ctx) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    return ctx->ch_layout.nb_channels;
+#else
+    return ctx->channels;
+#endif
+}
+
+// Compatibility for swr_alloc_set_opts
+inline SwrContext* ffmpeg_swr_alloc_set_opts(SwrContext *s,
+                                           int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
+                                           int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
+                                           int log_offset, void *log_ctx) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    SwrContext *swr_ctx = swr_alloc();
+    if (!swr_ctx) return NULL;
+    
+    AVChannelLayout out_ch_layout_new, in_ch_layout_new;
+    av_channel_layout_from_mask(&out_ch_layout_new, out_ch_layout);
+    av_channel_layout_from_mask(&in_ch_layout_new, in_ch_layout);
+    
+    av_opt_set_chlayout(swr_ctx, "ochl", &out_ch_layout_new, 0);
+    av_opt_set_int(swr_ctx, "osf", out_sample_fmt, 0);
+    av_opt_set_int(swr_ctx, "osr", out_sample_rate, 0);
+    av_opt_set_chlayout(swr_ctx, "ichl", &in_ch_layout_new, 0);
+    av_opt_set_int(swr_ctx, "isf", in_sample_fmt, 0);
+    av_opt_set_int(swr_ctx, "isr", in_sample_rate, 0);
+    
+    av_channel_layout_uninit(&out_ch_layout_new);
+    av_channel_layout_uninit(&in_ch_layout_new);
+    
+    return swr_ctx;
+#else
+    return swr_alloc_set_opts(s, out_ch_layout, out_sample_fmt, out_sample_rate,
+                             in_ch_layout, in_sample_fmt, in_sample_rate,
+                             log_offset, log_ctx);
+#endif
+}
+
+// Compatibility for codec parameters setting
+inline int ffmpeg_av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
+                                   int nb_samples, enum AVSampleFormat sample_fmt, int align) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    return av_samples_alloc_array_and_samples(&audio_data, linesize, nb_channels, nb_samples, sample_fmt, align);
+#else
+    return av_samples_alloc(audio_data, linesize, nb_channels, nb_samples, sample_fmt, align);
+#endif
+}
+
+inline void ffmpeg_set_frame_channel_layout(AVFrame* frame, AVCodecContext* codec_ctx) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_copy(&frame->ch_layout, &codec_ctx->ch_layout);
+#else
+    frame->channel_layout = codec_ctx->channel_layout;
+#endif
+}
+
+inline void ffmpeg_set_stream_codec_params(AVStream* stream, AVCodecContext* codec_ctx) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    stream->codecpar->codec_id = codec_ctx->codec_id;
+    stream->codecpar->bit_rate = codec_ctx->bit_rate;
+    stream->codecpar->width = codec_ctx->width;
+    stream->codecpar->height = codec_ctx->height;
+    stream->codecpar->format = codec_ctx->pix_fmt;
+    stream->codecpar->sample_rate = codec_ctx->sample_rate;
+    av_channel_layout_copy(&stream->codecpar->ch_layout, &codec_ctx->ch_layout);
+    stream->time_base = codec_ctx->time_base;
+#elif FFMPEG_VERSION_MAJOR >= 4
+    stream->codecpar->codec_id = codec_ctx->codec_id;
+    stream->codecpar->bit_rate = codec_ctx->bit_rate;
+    stream->codecpar->width = codec_ctx->width;
+    stream->codecpar->height = codec_ctx->height;
+    stream->codecpar->format = codec_ctx->pix_fmt;
+    stream->codecpar->sample_rate = codec_ctx->sample_rate;
+    stream->codecpar->channels = codec_ctx->channels;
+    stream->codecpar->channel_layout = codec_ctx->channel_layout;
+    stream->time_base = codec_ctx->time_base;
+#else
+    *(stream->codec) = *codec_ctx;
+#endif
+}
+
+// Additional compatibility functions for missing identifiers
+inline int ffmpeg_get_channels(AVCodecContext* ctx) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    return ctx->ch_layout.nb_channels;
+#else
+    return ctx->channels;
+#endif
+}
+
+inline void ffmpeg_set_channels(AVCodecContext* ctx, int channels) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_default(&ctx->ch_layout, channels);
+#else
+    ctx->channels = channels;
+#endif
+}
+
+inline void ffmpeg_set_channel_layout(AVCodecContext* ctx, uint64_t channel_layout) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_from_mask(&ctx->ch_layout, channel_layout);
+#else
+    ctx->channel_layout = channel_layout;
+#endif
+}
+
+inline void ffmpeg_set_frame_channels(AVFrame* frame, int channels) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_default(&frame->ch_layout, channels);
+#else
+    frame->channels = channels;
+#endif
+}
+
+inline void ffmpeg_set_frame_channel_layout(AVFrame* frame, uint64_t channel_layout) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    av_channel_layout_from_mask(&frame->ch_layout, channel_layout);
+#else
+    frame->channel_layout = channel_layout;
+#endif
+}
+
+inline void ffmpeg_set_frame_pkt_pts(AVFrame* frame, int64_t pts) {
+#if FFMPEG_VERSION_MAJOR >= 7
+    frame->pts = pts;
+#else
+    frame->pkt_pts = pts;
+#endif
+}
+
+// Compatibility for bitstream filter initialization
+inline AVBitStreamFilterContext* ffmpeg_bitstream_filter_init(const char* name) {
+#if FFMPEG_VERSION_MAJOR >= 6
+    const AVBitStreamFilter* bsf = av_bsf_get_by_name(name);
+    if (!bsf) return nullptr;
+    
+    AVBSFContext* ctx = nullptr;
+    if (av_bsf_alloc(bsf, &ctx) < 0) return nullptr;
+    
+    return ctx;
+#else
+    return av_bitstream_filter_init(name);
+#endif
+}

+ 2 - 1
libs/Recorder/filter.cpp

@@ -1,4 +1,5 @@
 #include "filter.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 void format_pad_arg(char *arg, int size, const FILTER_CTX &ctx)
@@ -10,6 +11,6 @@ void format_pad_arg(char *arg, int size, const FILTER_CTX &ctx)
               ctx.time_base.den,
               ctx.sample_rate,
               av_get_sample_fmt_name(ctx.sample_fmt),
-              av_get_default_channel_layout(ctx.nb_channel));
+              ffmpeg_get_default_channel_layout(ctx.nb_channel));
 }
 } // namespace am

+ 3 - 2
libs/Recorder/filter_amix.cpp

@@ -1,4 +1,5 @@
 #include "filter_amix.h"
+#include "headers_ffmpeg.h"
 
 #include <chrono>
 
@@ -13,8 +14,8 @@ static void print_frame(const AVFrame *frame, int index)
 
 filter_amix::filter_amix()
 {
-    av_register_all();
-    avfilter_register_all();
+    ffmpeg_register_all();
+    ffmpeg_register_filters();
 
     memset(&_ctx_in_0, 0, sizeof(FILTER_CTX));
     memset(&_ctx_in_1, 0, sizeof(FILTER_CTX));

+ 4 - 3
libs/Recorder/filter_aresample.cpp

@@ -1,4 +1,5 @@
 #include "filter_aresample.h"
+#include "headers_ffmpeg.h"
 
 #include <chrono>
 #include <sstream>
@@ -9,8 +10,8 @@
 namespace am {
 filter_aresample::filter_aresample()
 {
-    av_register_all();
-    avfilter_register_all();
+    ffmpeg_register_all();
+    ffmpeg_register_filters();
 
     memset(&_ctx_in, 0, sizeof(FILTER_CTX));
     memset(&_ctx_out, 0, sizeof(FILTER_CTX));
@@ -52,7 +53,7 @@ int filter_aresample::init(const FILTER_CTX &ctx_in, const FILTER_CTX &ctx_out,
         }
 
         char layout_name[256] = {0};
-        av_get_channel_layout_string(layout_name, 256, ctx_out.nb_channel, ctx_out.channel_layout);
+        ffmpeg_get_channel_layout_string(layout_name, 256, ctx_out.nb_channel, ctx_out.channel_layout);
 
         std::stringstream filter_desrcss;
         filter_desrcss << "aresample=";

+ 3 - 3
libs/Recorder/hardware_acceleration.cpp

@@ -84,7 +84,7 @@ bool is_nvenc_support()
     bool is_support = false;
 
 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
-    av_register_all();
+    ffmpeg_register_all();
 #endif
     do {
         if (avcodec_find_encoder_by_name("nvenc_h264") == nullptr
@@ -166,14 +166,14 @@ std::vector<std::string> hardware_acceleration::get_video_hardware_devices()
         al_debug("%s", av_hwdevice_get_type_name(type));
     }
 
-    AVCodec *nvenc = avcodec_find_encoder_by_name("nvenc_h264");
+    FFmpegCodec *nvenc = avcodec_find_encoder_by_name("nvenc_h264");
     if (nvenc == nullptr)
         nvenc = avcodec_find_encoder_by_name("h264_nvenc");
 
     if (nvenc)
         al_debug("nvenc support");
 
-    AVCodec *vaapi = avcodec_find_encoder_by_name("h264_qsv");
+    FFmpegCodec *vaapi = avcodec_find_encoder_by_name("h264_qsv");
     if (vaapi)
         al_debug("qsv support");
 

+ 3 - 0
libs/Recorder/headers_ffmpeg.h

@@ -21,3 +21,6 @@ extern "C" {
 #include <libswresample\swresample.h>
 #include <libswscale\swscale.h>
 }
+
+// Include FFmpeg compatibility layer
+#include "ffmpeg_compat.h"

+ 2 - 1
libs/Recorder/headers_mmdevice.h

@@ -4,10 +4,11 @@
 
 #include <windows.h>
 
-#include <functiondiscoverykeys_devpkey.h>
 #include <mmdeviceapi.h>
 #include <propkeydef.h> //must include before functiondiscoverykeys_devpkey
 
+#include <functiondiscoverykeys_devpkey.h>
+
 #include <devicetopology.h>
 #include <wrl/client.h>
 

+ 3 - 3
libs/Recorder/log_helper.cpp

@@ -33,16 +33,16 @@ AMLog* AMLog::get(const char* path)
         return _log;
     }
     DWORD size = 0;
-    HANDLE file = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    HANDLE file = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (file != INVALID_HANDLE_VALUE) {
         size = GetFileSize(file, NULL);
         CloseHandle(file);
     }
     if (size != INVALID_FILE_SIZE && size > LOG_ROLL_SIZE) {
         if (DeleteFileA(path) == FALSE) {
-            TCHAR roll_path[MAX_PATH];
+            char roll_path[MAX_PATH];
             sprintf_s(roll_path, MAX_PATH, "%s.1", path);
-            if (!MoveFileEx(path, roll_path, MOVEFILE_REPLACE_EXISTING)) {
+            if (!MoveFileExA(path, roll_path, MOVEFILE_REPLACE_EXISTING)) {
                 return NULL;
             }
         }

+ 1 - 0
libs/Recorder/muxer_define.h

@@ -2,6 +2,7 @@
 #define MUXER_DEFINE
 
 #include "encoder_video_define.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 typedef struct

+ 48 - 57
libs/Recorder/muxer_ffmpeg.cpp

@@ -1,5 +1,6 @@
 #include "muxer_ffmpeg.h"
 #include "muxer_define.h"
+#include "headers_ffmpeg.h"
 
 #include "encoder_video.h"
 #include "encoder_video_factory.h"
@@ -19,7 +20,7 @@
 namespace am {
 muxer_ffmpeg::muxer_ffmpeg()
 {
-    av_register_all();
+    ffmpeg_register_all();
 
     _v_stream = NULL;
     _a_stream = NULL;
@@ -289,16 +290,14 @@ void muxer_ffmpeg::on_filter_amix_data(AVFrame *frame, int)
     AUDIO_SAMPLE *resamples = _a_stream->a_resamples[0];
 
     int copied_len = 0;
-    int sample_len = av_samples_get_buffer_size(frame->linesize,
-                                                frame->channels,
-                                                frame->nb_samples,
-                                                (AVSampleFormat) frame->format,
-                                                1);
-    sample_len = av_samples_get_buffer_size(NULL,
-                                            frame->channels,
+    int sample_len = ffmpeg_get_buffer_size((AVSampleFormat) frame->format,
+                                            ffmpeg_get_frame_channels(frame),
                                             frame->nb_samples,
-                                            (AVSampleFormat) frame->format,
                                             1);
+    sample_len = ffmpeg_get_buffer_size((AVSampleFormat) frame->format,
+                                        ffmpeg_get_frame_channels(frame),
+                                        frame->nb_samples,
+                                        1);
 
 #ifdef _DEBUG
     //al_debug("dg:%d", pcm_fltp_db_count(frame, frame->channels));
@@ -362,16 +361,14 @@ void muxer_ffmpeg::on_filter_aresample_data(AVFrame *frame, int index)
     AUDIO_SAMPLE *resamples = _a_stream->a_resamples[0];
 
     int copied_len = 0;
-    int sample_len = av_samples_get_buffer_size(frame->linesize,
-                                                frame->channels,
-                                                frame->nb_samples,
-                                                (AVSampleFormat) frame->format,
-                                                1);
-    sample_len = av_samples_get_buffer_size(NULL,
-                                            frame->channels,
+    int sample_len = ffmpeg_get_buffer_size((AVSampleFormat) frame->format,
+                                            ffmpeg_get_frame_channels(frame),
                                             frame->nb_samples,
-                                            (AVSampleFormat) frame->format,
                                             1);
+    sample_len = ffmpeg_get_buffer_size((AVSampleFormat) frame->format,
+                                        ffmpeg_get_frame_channels(frame),
+                                        frame->nb_samples,
+                                        1);
 
     int remain_len = sample_len;
 
@@ -519,13 +516,13 @@ int muxer_ffmpeg::add_video_stream(const MUX_SETTING_T &setting, record_desktop
         if (error != AE_NO)
             break;
 
-        AVCodec *codec = avcodec_find_encoder(_v_stream->v_enc->get_codec_id());
+        const AVCodec *codec = avcodec_find_encoder(_v_stream->v_enc->get_codec_id());
         if (!codec) {
             error = AE_FFMPEG_FIND_ENCODER_FAILED;
             break;
         }
 
-        _fmt->video_codec = codec->id;
+        const_cast<AVOutputFormat*>(_fmt)->video_codec = codec->id;
 
         AVStream *st = avformat_new_stream(_fmt_ctx, codec);
         if (!st) {
@@ -533,29 +530,21 @@ int muxer_ffmpeg::add_video_stream(const MUX_SETTING_T &setting, record_desktop
             break;
         }
 
-        st->codec->codec_id = AV_CODEC_ID_H264;
-        st->codec->bit_rate_tolerance = setting.v_bit_rate;
-        st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
-        st->codec->time_base.den = setting.v_frame_rate;
-        st->codec->time_base.num = 1;
-        st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
-
-        st->codec->coded_width = setting.v_out_width;
-        st->codec->coded_height = setting.v_out_height;
-        st->codec->width = setting.v_out_width;
-        st->codec->height = setting.v_out_height;
-        st->codec->max_b_frames = 0; //NO B Frame
-        st->time_base = {1, 90000};  //fixed?
-        st->avg_frame_rate = av_inv_q(st->codec->time_base);
+        ffmpeg_set_stream_codec_id(st, AV_CODEC_ID_H264);
+        ffmpeg_set_stream_bit_rate(st, setting.v_bit_rate);
+        ffmpeg_set_stream_codec_type(st, AVMEDIA_TYPE_VIDEO);
+        st->time_base.den = setting.v_frame_rate;
+        st->time_base.num = 1;
+        ffmpeg_set_stream_pix_fmt(st, AV_PIX_FMT_YUV420P);
 
-        if (_fmt_ctx->oformat->flags
-            & AVFMT_GLOBALHEADER) { //without this,normal player can not play,extradata will write with avformat_write_header
-            st->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+        ffmpeg_set_stream_dimensions(st, setting.v_out_width, setting.v_out_height);
+        st->time_base = {1, 90000};  //fixed?
+        st->avg_frame_rate = av_inv_q(st->time_base);
 
-            st->codec->extradata_size
-                = _v_stream->v_enc->get_extradata_size(); // +AV_INPUT_BUFFER_PADDING_SIZE;
-            st->codec->extradata = (uint8_t *) av_memdup(_v_stream->v_enc->get_extradata(),
-                                                         _v_stream->v_enc->get_extradata_size());
+        if (_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
+            uint8_t* extradata = (uint8_t*)av_memdup(_v_stream->v_enc->get_extradata(),
+                                                     _v_stream->v_enc->get_extradata_size());
+            ffmpeg_set_stream_extradata(st, extradata, _v_stream->v_enc->get_extradata_size());
         }
 
         _v_stream->st = st;
@@ -617,14 +606,14 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
 
             FILTER_CTX ctx_in = {0}, ctx_out = {0};
             ctx_in.time_base = _a_stream->a_src[i]->get_time_base();
-            ctx_in.channel_layout = av_get_default_channel_layout(
+            ctx_in.channel_layout = ffmpeg_get_default_channel_layout(
                 _a_stream->a_src[i]->get_channel_num());
             ctx_in.nb_channel = _a_stream->a_src[i]->get_channel_num();
             ctx_in.sample_fmt = _a_stream->a_src[i]->get_fmt();
             ctx_in.sample_rate = _a_stream->a_src[i]->get_sample_rate();
 
             ctx_out.time_base = {1, AV_TIME_BASE};
-            ctx_out.channel_layout = av_get_default_channel_layout(setting.a_nb_channel);
+            ctx_out.channel_layout = ffmpeg_get_default_channel_layout(setting.a_nb_channel);
             ctx_out.nb_channel = setting.a_nb_channel;
             ctx_out.sample_fmt = setting.a_sample_fmt;
             ctx_out.sample_rate = setting.a_sample_rate;
@@ -666,7 +655,7 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
                                                     _a_stream->a_src[0]->get_sample_rate(),
                                                     _a_stream->a_src[0]->get_fmt(),
                                                     _a_stream->a_src[0]->get_channel_num(),
-                                                    av_get_default_channel_layout(
+                                                    (int64_t)ffmpeg_get_default_channel_layout(
                                                         _a_stream->a_src[0]->get_channel_num())},
                                                    {NULL,
                                                     NULL,
@@ -674,7 +663,7 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
                                                     _a_stream->a_src[1]->get_sample_rate(),
                                                     _a_stream->a_src[1]->get_fmt(),
                                                     _a_stream->a_src[1]->get_channel_num(),
-                                                    av_get_default_channel_layout(
+                                                    (int64_t)ffmpeg_get_default_channel_layout(
                                                         _a_stream->a_src[1]->get_channel_num())},
                                                    {NULL,
                                                     NULL,
@@ -682,7 +671,7 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
                                                     setting.a_sample_rate,
                                                     setting.a_sample_fmt,
                                                     setting.a_nb_channel,
-                                                    av_get_default_channel_layout(
+                                                    (int64_t)ffmpeg_get_default_channel_layout(
                                                         setting.a_nb_channel)});
 
             if (error != AE_NO) {
@@ -699,13 +688,14 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
                                                            std::placeholders::_2));
         }
 
-        AVCodec *codec = avcodec_find_encoder(_a_stream->a_enc->get_codec_id());
+        const AVCodec *codec = avcodec_find_encoder(_a_stream->a_enc->get_codec_id());
         if (!codec) {
             error = AE_FFMPEG_FIND_ENCODER_FAILED;
             break;
         }
 
-        _fmt->audio_codec = _a_stream->a_enc->get_codec_id();
+        AVCodecID audio_codec_id = _a_stream->a_enc->get_codec_id();
+        const_cast<AVOutputFormat*>(_fmt)->audio_codec = audio_codec_id;
 
         AVStream *st = avformat_new_stream(_fmt_ctx, codec);
         if (!st) {
@@ -717,27 +707,28 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
 
         st->time_base = {1, setting.a_sample_rate};
 
-        st->codec->bit_rate = setting.a_bit_rate;
-        st->codec->channels = setting.a_nb_channel;
-        st->codec->sample_rate = setting.a_sample_rate;
-        st->codec->sample_fmt = setting.a_sample_fmt;
-        st->codec->time_base = {1, setting.a_sample_rate};
-        st->codec->channel_layout = av_get_default_channel_layout(setting.a_nb_channel);
+        AVCodecContext *codec_ctx = ffmpeg_get_codec_context(st);
+        codec_ctx->bit_rate = setting.a_bit_rate;
+        ffmpeg_set_codec_channels(codec_ctx, setting.a_nb_channel);
+        codec_ctx->sample_rate = setting.a_sample_rate;
+        codec_ctx->sample_fmt = setting.a_sample_fmt;
+        codec_ctx->time_base = {1, setting.a_sample_rate};
+        ffmpeg_set_codec_channel_layout(codec_ctx, ffmpeg_get_default_channel_layout(setting.a_nb_channel));
 
         if (_fmt_ctx->oformat->flags
             & AVFMT_GLOBALHEADER) { //without this,normal player can not play
-            st->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+            codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 
-            st->codec->extradata_size
+            codec_ctx->extradata_size
                 = _a_stream->a_enc->get_extradata_size(); // +AV_INPUT_BUFFER_PADDING_SIZE;
-            st->codec->extradata = (uint8_t *) av_memdup(_a_stream->a_enc->get_extradata(),
+            codec_ctx->extradata = (uint8_t *) av_memdup(_a_stream->a_enc->get_extradata(),
                                                          _a_stream->a_enc->get_extradata_size());
         }
 
         _a_stream->st = st;
 
         _a_stream->setting = setting;
-        _a_stream->filter = av_bitstream_filter_init("aac_adtstoasc");
+        _a_stream->filter = ffmpeg_bitstream_filter_init("aac_adtstoasc");
 
     } while (0);
 

+ 1 - 1
libs/Recorder/muxer_ffmpeg.h

@@ -78,7 +78,7 @@ private:
 private:
     struct MUX_STREAM_T *_v_stream, *_a_stream;
 
-    AVOutputFormat *_fmt;
+    const AVOutputFormat *_fmt;
     AVFormatContext *_fmt_ctx;
 
     int64_t _base_time;

+ 2 - 1
libs/Recorder/record_audio.cpp

@@ -1,4 +1,5 @@
 #include "record_audio.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 record_audio::record_audio()
@@ -10,7 +11,7 @@ record_audio::record_audio()
     _sample_rate = 48000;
     _bit_rate = 3072000;
     _channel_num = 2;
-    _channel_layout = av_get_default_channel_layout(_channel_num);
+    _channel_layout = ffmpeg_get_default_channel_layout(_channel_num);
     _bit_per_sample = _bit_rate / _sample_rate / _channel_num;
     _fmt = AV_SAMPLE_FMT_FLT;
     _on_data = nullptr;

+ 7 - 6
libs/Recorder/record_audio_dshow.cpp

@@ -1,4 +1,5 @@
 #include "record_audio_dshow.h"
+#include "headers_ffmpeg.h"
 
 #include "error_define.h"
 #include "log_helper.h"
@@ -6,8 +7,8 @@
 namespace am {
 record_audio_dshow::record_audio_dshow()
 {
-    av_register_all();
-    avdevice_register_all();
+    ffmpeg_register_all();
+    ffmpeg_register_devices();
 
     _fmt_ctx = NULL;
     _input_fmt = NULL;
@@ -59,7 +60,7 @@ int record_audio_dshow::init(const std::string &device_name,
 
         int stream_index = -1;
         for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
-            if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+            if (ffmpeg_get_codec_type(_fmt_ctx->streams[i]) == AVMEDIA_TYPE_AUDIO) {
                 stream_index = i;
                 break;
             }
@@ -71,8 +72,8 @@ int record_audio_dshow::init(const std::string &device_name,
         }
 
         _stream_index = stream_index;
-        _codec_ctx = _fmt_ctx->streams[stream_index]->codec;
-        _codec = avcodec_find_decoder(_codec_ctx->codec_id);
+        _codec_ctx = ffmpeg_get_codec_context(_fmt_ctx->streams[stream_index]);
+        _codec = (AVCodec*)avcodec_find_decoder(_codec_ctx->codec_id);
         if (_codec == NULL) {
             error = AE_FFMPEG_FIND_DECODER_FAILED;
             break;
@@ -89,7 +90,7 @@ int record_audio_dshow::init(const std::string &device_name,
         _sample_rate = _codec_ctx->sample_rate;
         _bit_rate = _codec_ctx->bit_rate;
         _bit_per_sample = _codec_ctx->bits_per_coded_sample;
-        _channel_num = _codec_ctx->channels;
+        _channel_num = ffmpeg_get_channels(_codec_ctx);
         _fmt = _codec_ctx->sample_fmt;
 
         _inited = true;

+ 1 - 1
libs/Recorder/record_audio_dshow.h

@@ -31,7 +31,7 @@ private:
 
 private:
     AVFormatContext *_fmt_ctx;
-    AVInputFormat *_input_fmt;
+    FFmpegInputFormat *_input_fmt;
     AVCodecContext *_codec_ctx;
     AVCodec *_codec;
 

+ 3 - 2
libs/Recorder/record_audio_wasapi.cpp

@@ -1,4 +1,5 @@
 #include "record_audio_wasapi.h"
+#include "headers_ffmpeg.h"
 
 #include <string>
 
@@ -94,7 +95,7 @@ int64_t record_audio_wasapi::convert_layout(DWORD layout, WORD channels)
         return AV_CH_LAYOUT_7POINT1;
     }
 
-    return av_get_default_channel_layout(channels);
+    return ffmpeg_get_default_channel_layout(channels);
 }
 
 void record_audio_wasapi::init_format(WAVEFORMATEX *wfex)
@@ -439,7 +440,7 @@ void record_audio_wasapi::process_data(AVFrame *frame,
     frame->nb_samples = sample_count;
     frame->format = _fmt;
     frame->sample_rate = _sample_rate;
-    frame->channels = _channel_num;
+    ffmpeg_set_frame_channels(frame, _channel_num);
     frame->pkt_size = sample_count * sample_size;
 
     av_samples_fill_arrays(frame->data, frame->linesize, data, _channel_num, sample_count, _fmt, 1);

+ 1 - 1
libs/Recorder/record_desktop_duplication.cpp

@@ -849,7 +849,7 @@ void record_desktop_duplication::record_func()
 
         frame->pts = av_gettime_relative();
         frame->pkt_dts = frame->pts;
-        frame->pkt_pts = frame->pts;
+        // frame->pkt_pts = frame->pts;
 
         frame->width = _width;
         frame->height = _height;

+ 11 - 5
libs/Recorder/record_desktop_ffmpeg_dshow.cpp

@@ -2,12 +2,13 @@
 
 #include "error_define.h"
 #include "log_helper.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 record_desktop_ffmpeg_dshow::record_desktop_ffmpeg_dshow()
 {
-    av_register_all();
-    avdevice_register_all();
+    ffmpeg_register_all();
+    ffmpeg_register_devices();
 
     _fmt_ctx = NULL;
     _input_fmt = NULL;
@@ -64,7 +65,7 @@ int record_desktop_ffmpeg_dshow::init(const RECORD_DESKTOP_RECT &rect, const int
 
         int stream_index = -1;
         for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
-            if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+            if (ffmpeg_get_codec_type(_fmt_ctx->streams[i]) == AVMEDIA_TYPE_VIDEO) {
                 stream_index = i;
                 break;
             }
@@ -76,8 +77,13 @@ int record_desktop_ffmpeg_dshow::init(const RECORD_DESKTOP_RECT &rect, const int
         }
 
         _stream_index = stream_index;
-        _codec_ctx = _fmt_ctx->streams[stream_index]->codec;
+#if FFMPEG_VERSION_MAJOR >= 4
+        _codec_ctx = ffmpeg_get_codec_context(_fmt_ctx->streams[stream_index]);
+        _codec = avcodec_find_decoder(ffmpeg_get_codec_id(_fmt_ctx->streams[stream_index]));
+#else
+        _codec_ctx = ffmpeg_get_codec_context(_fmt_ctx->streams[stream_index]);
         _codec = avcodec_find_decoder(_codec_ctx->codec_id);
+#endif
         if (_codec == NULL) {
             error = AE_FFMPEG_FIND_DECODER_FAILED;
             break;
@@ -91,7 +97,7 @@ int record_desktop_ffmpeg_dshow::init(const RECORD_DESKTOP_RECT &rect, const int
 
         _start_time = _fmt_ctx->streams[_stream_index]->start_time;
         _time_base = _fmt_ctx->streams[_stream_index]->time_base;
-        _pixel_fmt = _fmt_ctx->streams[_stream_index]->codec->pix_fmt;
+        _pixel_fmt = ffmpeg_get_codec_pix_fmt(_fmt_ctx->streams[_stream_index]);
 
         _inited = true;
     } while (0);

+ 2 - 2
libs/Recorder/record_desktop_ffmpeg_dshow.h

@@ -26,8 +26,8 @@ private:
 
     int _stream_index;
     AVFormatContext *_fmt_ctx;
-    AVInputFormat *_input_fmt;
+    FFmpegInputFormat *_input_fmt;
     AVCodecContext *_codec_ctx;
-    AVCodec *_codec;
+    FFmpegCodec *_codec;
 };
 } // namespace am

+ 11 - 5
libs/Recorder/record_desktop_ffmpeg_gdi.cpp

@@ -2,12 +2,13 @@
 
 #include "error_define.h"
 #include "log_helper.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 record_desktop_ffmpeg_gdi::record_desktop_ffmpeg_gdi()
 {
-    av_register_all();
-    avdevice_register_all();
+    ffmpeg_register_all();
+    ffmpeg_register_devices();
 
     _fmt_ctx = NULL;
     _input_fmt = NULL;
@@ -64,7 +65,7 @@ int record_desktop_ffmpeg_gdi::init(const RECORD_DESKTOP_RECT &rect, const int f
 
         int stream_index = -1;
         for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
-            if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+            if (ffmpeg_get_codec_type(_fmt_ctx->streams[i]) == AVMEDIA_TYPE_VIDEO) {
                 stream_index = i;
                 break;
             }
@@ -76,8 +77,13 @@ int record_desktop_ffmpeg_gdi::init(const RECORD_DESKTOP_RECT &rect, const int f
         }
 
         _stream_index = stream_index;
-        _codec_ctx = _fmt_ctx->streams[stream_index]->codec;
+#if FFMPEG_VERSION_MAJOR >= 4
+        _codec_ctx = ffmpeg_get_codec_context(_fmt_ctx->streams[stream_index]);
+        _codec = avcodec_find_decoder(ffmpeg_get_codec_id(_fmt_ctx->streams[stream_index]));
+#else
+        _codec_ctx = ffmpeg_get_codec_context(_fmt_ctx->streams[stream_index]);
         _codec = avcodec_find_decoder(_codec_ctx->codec_id);
+#endif
         if (_codec == NULL) {
             error = AE_FFMPEG_FIND_DECODER_FAILED;
             break;
@@ -91,7 +97,7 @@ int record_desktop_ffmpeg_gdi::init(const RECORD_DESKTOP_RECT &rect, const int f
 
         _start_time = _fmt_ctx->streams[_stream_index]->start_time;
         _time_base = _fmt_ctx->streams[_stream_index]->time_base;
-        _pixel_fmt = _fmt_ctx->streams[_stream_index]->codec->pix_fmt;
+        _pixel_fmt = ffmpeg_get_codec_pix_fmt(_fmt_ctx->streams[_stream_index]);
 
         _inited = true;
     } while (0);

+ 2 - 2
libs/Recorder/record_desktop_ffmpeg_gdi.h

@@ -27,9 +27,9 @@ private:
 
     int _stream_index;
     AVFormatContext *_fmt_ctx;
-    AVInputFormat *_input_fmt;
+    FFmpegInputFormat *_input_fmt;
     AVCodecContext *_codec_ctx;
-    AVCodec *_codec;
+    const AVCodec *_codec;
 };
 } // namespace am
 #endif

+ 1 - 1
libs/Recorder/record_desktop_wgc.cpp

@@ -131,7 +131,7 @@ void record_desktop_wgc::on_frame(const wgc_session::wgc_session_frame &frame)
 
     av_frame->pts = av_gettime_relative();
     av_frame->pkt_dts = av_frame->pts;
-    av_frame->pkt_pts = av_frame->pts;
+    // av_frame->pkt_pts = av_frame->pts;
 
     av_frame->width = frame.width;
     av_frame->height = frame.height;

+ 1 - 1
libs/Recorder/record_desktop_wgc.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "../WGC/export.h"
+#include "WGC/export.h"
 #include "record_desktop.h"
 
 #include <Windows.h>

+ 7 - 7
libs/Recorder/remuxer_ffmpeg.cpp

@@ -92,31 +92,31 @@ int open_dst(AVFormatContext **ctx_dst, const char *path, AVFormatContext *ctx_s
 
     for (unsigned i = 0; i < ctx_src->nb_streams; i++) {
         AVStream *in_stream = ctx_src->streams[i];
-        AVStream *out_stream = avformat_new_stream(*ctx_dst, in_stream->codec->codec);
+        AVStream *out_stream = avformat_new_stream(*ctx_dst, NULL);
         if (!out_stream) {
             return AE_FFMPEG_NEW_STREAM_FAILED;
         }
 
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
         AVCodecParameters *par = avcodec_parameters_alloc();
-        ret = avcodec_parameters_from_context(par, in_stream->codec);
+        ret = avcodec_parameters_from_context(par, ffmpeg_get_codec_context(in_stream));
         if (ret == 0)
-            ret = avcodec_parameters_to_context(out_stream->codec, par);
+            ret = avcodec_parameters_to_context(ffmpeg_get_codec_context(out_stream), par);
         avcodec_parameters_free(&par);
 #else
-        ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
+        ret = avcodec_copy_context(ffmpeg_get_codec_context(out_stream), ffmpeg_get_codec_context(in_stream));
 #endif
 
         if (ret < 0) {
             return AE_FFMPEG_COPY_PARAMS_FAILED;
         }
-        out_stream->time_base = out_stream->codec->time_base;
+        out_stream->time_base = ffmpeg_get_codec_context(out_stream)->time_base;
 
         av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
 
-        out_stream->codec->codec_tag = 0;
+        ffmpeg_get_codec_context(out_stream)->codec_tag = 0;
         if ((*ctx_dst)->oformat->flags & AVFMT_GLOBALHEADER)
-            out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+            ffmpeg_get_codec_context(out_stream)->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
     }
 
 #ifndef _NDEBUG

+ 10 - 9
libs/Recorder/resample_pcm.cpp

@@ -2,6 +2,7 @@
 
 #include "error_define.h"
 #include "log_helper.h"
+#include "headers_ffmpeg.h"
 
 namespace am {
 resample_pcm::resample_pcm()
@@ -29,15 +30,15 @@ int resample_pcm::init(const SAMPLE_SETTING *sample_src,
         memcpy(_sample_src, sample_src, sizeof(SAMPLE_SETTING));
         memcpy(_sample_dst, sample_dst, sizeof(SAMPLE_SETTING));
 
-        _ctx = swr_alloc_set_opts(NULL,
-                                  _sample_dst->channel_layout,
-                                  _sample_dst->fmt,
-                                  _sample_dst->sample_rate,
-                                  _sample_src->channel_layout,
-                                  _sample_src->fmt,
-                                  _sample_src->sample_rate,
-                                  0,
-                                  NULL);
+        _ctx = ffmpeg_swr_alloc_set_opts(NULL,
+                                         _sample_dst->channel_layout,
+                                         _sample_dst->fmt,
+                                         _sample_dst->sample_rate,
+                                         _sample_src->channel_layout,
+                                         _sample_src->fmt,
+                                         _sample_src->sample_rate,
+                                         0,
+                                         NULL);
 
         if (_ctx == NULL) {
             err = AE_RESAMPLE_INIT_FAILED;

+ 8 - 7
libs/Recorder/test_main.cpp

@@ -18,6 +18,7 @@
 #include "hardware_acceleration.h"
 
 #include "remuxer_ffmpeg.h"
+#include "headers_ffmpeg.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -192,7 +193,7 @@ void on_pcm_error(int, int) {
 void on_pcm_data1(AVFrame *frame, int index) {
 
 	int copied_len = 0;
-	int sample_len = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, (AVSampleFormat)frame->format, 1);
+	int sample_len = av_samples_get_buffer_size(NULL, ffmpeg_get_frame_channels(frame), frame->nb_samples, (AVSampleFormat)frame->format, 1);
 	int remain_len = sample_len;
 
 	int is_planner = av_sample_fmt_is_planar((AVSampleFormat)frame->format);
@@ -227,8 +228,8 @@ void on_pcm_data(AVFrame *frame, int index) {
 
 void on_aresample_data(AVFrame * frame,int index) {
 	int copied_len = 0;
-	int sample_len = av_samples_get_buffer_size(frame->linesize, frame->channels, frame->nb_samples, (AVSampleFormat)frame->format, 1);
-	sample_len = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, (AVSampleFormat)frame->format, 1);
+	int sample_len = av_samples_get_buffer_size(frame->linesize, ffmpeg_get_frame_channels(frame), frame->nb_samples, (AVSampleFormat)frame->format, 1);
+	sample_len = av_samples_get_buffer_size(NULL, ffmpeg_get_frame_channels(frame), frame->nb_samples, (AVSampleFormat)frame->format, 1);
 
 	int remain_len = sample_len;
 
@@ -303,14 +304,14 @@ void save_aac() {
 	am::SAMPLE_SETTING src, dst = { 0 };
 	src = {
 		_encoder_aac->get_nb_samples(),
-		av_get_default_channel_layout(_recorder_audio->get_channel_num()),
+		(int64_t)ffmpeg_get_default_channel_layout(_recorder_audio->get_channel_num()),
 		_recorder_audio->get_channel_num(),
 		_recorder_audio->get_fmt(),
 		_recorder_audio->get_sample_rate()
 	};
 	dst = {
 		_encoder_aac->get_nb_samples(),
-		av_get_default_channel_layout(A_SAMPLE_CHANNEL),
+		(int64_t)ffmpeg_get_default_channel_layout(A_SAMPLE_CHANNEL),
 		A_SAMPLE_CHANNEL,
 		AV_SAMPLE_FMT_FLTP,
 		A_SAMPLE_RATE
@@ -330,14 +331,14 @@ void save_aac() {
 		_recorder_audio->get_sample_rate(),
 		_recorder_audio->get_fmt(),
 		_recorder_audio->get_channel_num(),
-		av_get_default_channel_layout(_recorder_audio->get_channel_num())
+		(int64_t)ffmpeg_get_default_channel_layout(_recorder_audio->get_channel_num())
 	}, {
 		NULL,NULL,
 		{ 1,AV_TIME_BASE },
 		A_SAMPLE_RATE,
 		AV_SAMPLE_FMT_FLTP,
 		A_SAMPLE_CHANNEL,
-		av_get_default_channel_layout(A_SAMPLE_CHANNEL)
+		(int64_t)ffmpeg_get_default_channel_layout(A_SAMPLE_CHANNEL)
 	},0);
 	_filter_aresample->registe_cb(on_aresample_data, on_aresample_error);
 

+ 17 - 16
libs/Recorder/transcode_aac.cpp

@@ -44,6 +44,7 @@
 #include "libswresample/swresample.h"
 
 #include "common.h"
+#include "headers_ffmpeg.h"
 
 /* The output bit rate in bit/s */
 #define OUTPUT_BIT_RATE 96000
@@ -62,7 +63,7 @@ static int open_input_file(const char *filename,
                            AVCodecContext **input_codec_context)
 {
     AVCodecContext *avctx;
-    AVCodec *input_codec;
+    FFmpegCodec *input_codec;
     int error;
 
     /* Open the input file to read from it. */
@@ -147,7 +148,7 @@ static int open_output_file(const char *filename,
     AVCodecContext *avctx = NULL;
     AVIOContext *output_io_context = NULL;
     AVStream *stream = NULL;
-    AVCodec *output_codec = NULL;
+    FFmpegCodec *output_codec = NULL;
     int error;
 
     /* Open the output file to write to it. */
@@ -202,8 +203,8 @@ static int open_output_file(const char *filename,
 
     /* Set the basic encoder parameters.
 	* The input file's sample rate is used to avoid a sample rate conversion. */
-    avctx->channels = OUTPUT_CHANNELS;
-    avctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS);
+    ffmpeg_set_codec_channels(avctx, OUTPUT_CHANNELS);
+    ffmpeg_set_codec_channel_layout(avctx, ffmpeg_get_default_channel_layout(OUTPUT_CHANNELS));
     avctx->sample_rate = input_codec_context->sample_rate;
     avctx->sample_fmt = output_codec->sample_fmts[0];
     avctx->bit_rate = OUTPUT_BIT_RATE;
@@ -294,11 +295,11 @@ static int init_resampler(AVCodecContext *input_codec_context,
 	* properly by the demuxer and/or decoder).
 	*/
     *resample_context
-        = swr_alloc_set_opts(NULL,
-                             av_get_default_channel_layout(output_codec_context->channels),
+        = ffmpeg_swr_alloc_set_opts(NULL,
+                             ffmpeg_get_default_channel_layout(ffmpeg_get_codec_context_channels(output_codec_context)),
                              output_codec_context->sample_fmt,
                              output_codec_context->sample_rate,
-                             av_get_default_channel_layout(input_codec_context->channels),
+                             ffmpeg_get_default_channel_layout(ffmpeg_get_codec_context_channels(input_codec_context)),
                              input_codec_context->sample_fmt,
                              input_codec_context->sample_rate,
                              0,
@@ -333,7 +334,7 @@ static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context)
 {
     /* Create the FIFO buffer based on the specified output sample format. */
     if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt,
-                                      output_codec_context->channels,
+                                      ffmpeg_get_codec_context_channels(output_codec_context),
                                       1))) {
         fprintf(stderr, "Could not allocate FIFO\n");
         return AVERROR(ENOMEM);
@@ -446,7 +447,7 @@ static int init_converted_samples(uint8_t ***converted_input_samples,
 	* Each pointer will later point to the audio samples of the corresponding
 	* channels (although it may be NULL for interleaved formats).
 	*/
-    if (!(*converted_input_samples = (uint8_t **) calloc(output_codec_context->channels,
+    if (!(*converted_input_samples = (uint8_t **) calloc(ffmpeg_get_codec_context_channels(output_codec_context),
                                                          sizeof(**converted_input_samples)))) {
         fprintf(stderr, "Could not allocate converted input sample pointers\n");
         return AVERROR(ENOMEM);
@@ -454,12 +455,12 @@ static int init_converted_samples(uint8_t ***converted_input_samples,
 
     /* Allocate memory for the samples of all channels in one consecutive
 	* block for convenience. */
-    if ((error = av_samples_alloc(*converted_input_samples,
-                                  NULL,
-                                  output_codec_context->channels,
-                                  frame_size,
-                                  output_codec_context->sample_fmt,
-                                  0))
+    if ((error = ffmpeg_av_samples_alloc(*converted_input_samples,
+                                         NULL,
+                                         ffmpeg_get_codec_context_channels(output_codec_context),
+                                         frame_size,
+                                         output_codec_context->sample_fmt,
+                                         0))
         < 0) {
         fprintf(stderr,
                 "Could not allocate converted input samples (error '%s')\n",
@@ -633,7 +634,7 @@ static int init_output_frame(AVFrame **frame, AVCodecContext *output_codec_conte
 	* Default channel layouts based on the number of channels
 	* are assumed for simplicity. */
     (*frame)->nb_samples = frame_size;
-    (*frame)->channel_layout = output_codec_context->channel_layout;
+    ffmpeg_set_frame_channel_layout(*frame, output_codec_context);
     (*frame)->format = output_codec_context->sample_fmt;
     (*frame)->sample_rate = output_codec_context->sample_rate;