├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── cmake ├── FindFFMPEG.cmake ├── FindPORTAUDIO.cmake ├── fix_sdl2_release.cmake ├── get-portaudio.cmake └── get-sdl2.cmake ├── libs └── CMakeLists.txt └── src ├── AudioProdusser.cpp ├── AudioProdusser.h ├── BitWidthConverter.cpp ├── BitWidthConverter.h ├── CMakeLists.txt ├── FFmpegVideoCoderConsumer.cpp ├── FFmpegVideoCoderConsumer.h ├── FrameProxy.cpp ├── FrameProxy.h ├── IConsumer.h ├── LineGeneratorStage.cpp ├── LineGeneratorStage.h ├── PCMFrmageStage.cpp ├── PCMFrmageStage.h ├── PixelDuplicatorStage.cpp ├── PixelDuplicatorStage.h ├── PlayerConsumer.cpp ├── PlayerConsumer.h ├── RPIFbDisplayConsumer.cpp ├── RPIFbDisplayConsumer.h ├── SDL2DisplayConsumer.cpp ├── SDL2DisplayConsumer.h ├── SDL2DisplayConsumerBase.cpp ├── SDL2DisplayConsumerBase.h ├── Splitter.h ├── abstractprocessingstage.h ├── argparser.cpp ├── argparser.h ├── audioreader.cpp ├── audioreader.h ├── audiosample.h ├── constants.h ├── ctrlc_listener.cpp ├── ctrlc_listener.h ├── ffmpegvideocoder.cpp ├── ffmpegvideocoder.h ├── frame.cpp ├── frame.h ├── iframe.h ├── ipcmframeprocessingpolicy.h ├── main-st.cpp ├── pcmdatabuffer.cpp ├── pcmdatabuffer.h ├── pcmframe.cpp ├── pcmframe.h ├── pcmline.cpp ├── pcmline.h ├── print_duration.cpp ├── print_duration.h ├── result.h ├── rpi_fb_shifter.cpp ├── samplegenerator.cpp ├── samplegenerator.h ├── samplespack.h ├── samplestairsitherator.cpp └── samplestairsitherator.h /.gitignore: -------------------------------------------------------------------------------- 1 | 7# Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | *build*/ 55 | creator-*/ 56 | CMakeLists.txt.user* 57 | 58 | __pycache__ 59 | .idea/ 60 | *.autosave 61 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libs/CLI11"] 2 | path = libs/CLI11 3 | url = https://github.com/CLIUtils/CLI11.git 4 | [submodule "libs/pcm_utils"] 5 | path = libs/pcm_utils 6 | url = https://github.com/ololoshka2871/pcm_utils.git 7 | [submodule "libs/progress-cpp"] 8 | path = libs/progress-cpp 9 | url = https://github.com/prakhar1989/progress-cpp.git 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | set(CPP_STD 17) 4 | 5 | project(pcm_coder) 6 | 7 | set(MODULES_DIR ${CMAKE_SOURCE_DIR}/cmake) 8 | 9 | SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULES_DIR}) 10 | 11 | add_subdirectory(libs) 12 | add_subdirectory(src) 13 | 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PCM Encoder 2 | 3 | Генератор PCM видео из звуковых файлов. 4 | 5 | 6 | ## Features 7 | 8 | * Открывает любые поддерживаемые FFmpeg звуковые файлы (также видео со звуковой дорожкой) 9 | * Кодирование в PCM видеопоток формата PAL и NTSC 10 | * Режим просмотра: дисплей + звук 11 | * Кодирование видео средствами FFmpeg: Возможность указать видеокодек и битрейт 12 | 13 | 14 | ## Сборка 15 | 16 | * Клонировать репозиторий 17 | 18 | ``` 19 | git clone https://github.com/ololoshka2871/pcm_coder.git && cd pcm_coder 20 | ``` 21 | 22 | * Клонировать субмодули 23 | 24 | ``` 25 | git submodule update --init --recursive 26 | ``` 27 | 28 | * Создать каталог для сборки и перейти в него 29 | 30 | ``` 31 | mkdir build && cd build 32 | ``` 33 | 34 | 35 | ### Linux 36 | 37 | Необходимые зависимости: 38 | 39 | * [SDL2](https://www.libsdl.org/download-2.0.php) 40 | * [portaudio](http://www.portaudio.com/) 41 | * [ffmpeg](http://ffmpeg.org/) 42 | * [cmake](https://cmake.org/) 43 | * Компилятор gcc/clang с поддержкой С++17 44 | 45 | 46 | * Конфигурирование 47 | 48 | ``` 49 | cmake .. -DCMAKE_BUILD_TYPE=Release 50 | ``` 51 | 52 | * Сборка 53 | 54 | ``` 55 | make 56 | ``` 57 | 58 | * Исполняемый файл находится в подкаталоге src 59 | 60 | 61 | ### Windows 62 | 63 | Необходимые зависимости: 64 | 65 | * [ffmpeg](http://ffmpeg.org/) 66 | * [cmake](https://cmake.org/) 67 | * [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) или 68 | Visual Studio 2019 69 | * [Visual C Runtime 2019](https://aka.ms/vs/16/release/vc_redist.x64.exe) Только для клиентов 70 | 71 | 72 | * Распаковать [библиотеки](https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.2.3-win64-shared.zip) и 73 | [хедеры](https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.2.3-win64-dev.zip) FFmpeg'а куда угодно, например в каталог ffmpeg 74 | 75 | ``` 76 | ffmpeg 77 | ├───bin 78 | ├───doc 79 | ├───include 80 | │ ├───libavcodec 81 | │ ├───libavdevice 82 | │ ├───libavfilter 83 | │ ├───libavformat 84 | │ ├───libavutil 85 | │ ├───libpostproc 86 | │ ├───libswresample 87 | │ └───libswscale 88 | ├───lib 89 | └───presets 90 | ``` 91 | 92 | * Конфигурирование 93 | 94 | **-A платформа** 95 | - x64 - 64 битный вариант 96 | - Win32 - 32 битный 97 | 98 | ``` 99 | cmake .. -DCMAKE_BUILD_TYPE=Release -A x64 -DLIBAVCODEC_INCLUDE_DIR=<путь к ffmpeg>/include -DLIBAVDEVICE_INCLUDE_DIR=<путь к ffmpeg>/include -DLIBAVFORMAT_INCLUDE_DIR=<путь к ffmpeg>/include -DLIBAVUTIL_INCLUDE_DIR=<путь к ffmpeg>/include -DLIBSWRESAMPLE_INCLUDE_DIR=<путь к ffmpeg>/include -DLIBSWSCALE_INCLUDE_DIR=<путь к ffmpeg>/include 100 | ``` 101 | 102 | Или то же самое через cmake-gui 103 | 104 | * Сборка 105 | 106 | ``` 107 | cmake --build . --config Release 108 | ``` 109 | 110 | Исполняемый файл находится в подкаталоге src/Release 111 | 112 | Для запуска потребуется **скопировать библотеки** 113 | 114 | ffmpeg: 115 | - avcodec-58.dll 116 | - avdevice-58.dll 117 | - avfilter-7.dll 118 | - avformat-58.dll 119 | - avutil-56.dll 120 | - postproc-55.dll 121 | - swresample-3.dll 122 | - swscale-5.dll 123 | 124 | SDL2: 125 | - SDL2.dll (появится при сборке в каталоге `libs\dependencies\install\bin`) 126 | 127 | В один каталог с исполняемым файлом 128 | 129 | 130 | # Использование 131 | 132 | ## Воспроизведение 133 | 134 | ``` 135 | $ pcm_coder <входной файл> 136 | ``` 137 | 138 | ## Вопроизведение на Raspberry PI 139 | 1. Используйте [инструкцию](https://www.raspberrypi.org/documentation/configuration/config-txt/video.md) Чтобы включить 140 | композитный выход 141 | 2. Убедитесь, что композит рботает 142 | 143 | ``` 144 | $ tvservice -s 145 | state 0x80000 [PAL 4:3], 720x576 @ 50.00Hz, interlaced 146 | ``` 147 | 148 | 3. Зпустите воспроизведение командой 149 | ``` 150 | $ pcm_coder -R --crop-top X <входной файл> 151 | ``` 152 | 153 | Где: 154 | `-R` - Активирует режим воспроизведения на Raspberry PI 155 | `--crop-top X` - Сдвигает изображение "вверх" на указанное количество строк. Экспериментируёте с этим значением 156 | начиная с 0, чтобы дабиться устойчивого воспроизведения на аппаратном декодере PCM 157 | 158 | ### EXPERT: 159 | В состеве пакета также собирается утилита rpi-fb-shifter позволяющая аналогично утилете tvct из пакета [raspi-teletext](https://github.com/ali1234/raspi-teletext) 160 | Сдвигать фреймбуфер относительно строк видеосигнала. (запус должен требует прав root) 161 | 162 | ``` 163 | # rpi-fb-shifter -s <сдвиг> 164 | ``` 165 | 166 | `сдвиг` - задает смещеине фреймбуфера **+** - вверх, **-** - вниз. 167 | Чтобы отключить режим сдвига используйте off, однако следует указать ранее установленное значение `-s`, иначе отменить 168 | сдвиг невозможно без перезагрузки. 169 | 170 | ## Кодирование 171 | 172 | ``` 173 | pcm_coder -c <название кодека ffmpeg> -b <битрейт видео> {--pal|--ntsc} <входной файл> <выходной файл.avi> 174 | ``` 175 | 176 | Остальные опции кодирования смотри в справке `--help` 177 | 178 | ## TODO 179 | 180 | * [v] Поддержка 16 бит (--16) 181 | * [v] Поддержка обрезки (--Cut) - Заменено на произвольную обрезку сверху и снизу --crop-* 182 | * [v] Поддержка вывода на Raspberry PI 1+ 183 | -------------------------------------------------------------------------------- /cmake/FindFFMPEG.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find FFMPEG 2 | # Once done this will define 3 | # FFMPEG_FOUND - System has FFMPEG 4 | # FFMPEG_INCLUDE_DIRS - The FFMPEG include directories 5 | # FFMPEG_LIBRARIES - The libraries needed to use FFMPEG 6 | # FFMPEG_LIBRARY_DIRS - The directory to find FFMPEG libraries 7 | # 8 | # written by Roy Shilkrot 2013 http://www.morethantechnical.com/ 9 | # 10 | 11 | find_package(PkgConfig) 12 | 13 | 14 | MACRO(FFMPEG_FIND varname shortname headername) 15 | 16 | IF(NOT WIN32) 17 | PKG_CHECK_MODULES(PC_${varname} ${shortname}) 18 | 19 | FIND_PATH(${varname}_INCLUDE_DIR "${shortname}/${headername}" 20 | HINTS ${PC_${varname}_INCLUDEDIR} ${PC_${varname}_INCLUDE_DIRS} 21 | NO_DEFAULT_PATH 22 | ) 23 | ELSE() 24 | FIND_PATH(${varname}_INCLUDE_DIR "${shortname}/${headername}") 25 | ENDIF() 26 | 27 | IF(${varname}_INCLUDE_DIR STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND") 28 | message(STATUS "look for newer strcture") 29 | IF(NOT WIN32) 30 | PKG_CHECK_MODULES(PC_${varname} "lib${shortname}") 31 | 32 | FIND_PATH(${varname}_INCLUDE_DIR "lib${shortname}/${headername}" 33 | HINTS ${PC_${varname}_INCLUDEDIR} ${PC_${varname}_INCLUDE_DIRS} 34 | NO_DEFAULT_PATH 35 | ) 36 | ELSE() 37 | FIND_PATH(${varname}_INCLUDE_DIR "lib${shortname}/${headername}") 38 | IF(${${varname}_INCLUDE_DIR} STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND") 39 | #Desperate times call for desperate measures 40 | MESSAGE(STATUS "globbing...") 41 | FILE(GLOB_RECURSE ${varname}_INCLUDE_DIR "/ffmpeg*/${headername}") 42 | MESSAGE(STATUS "found: ${${varname}_INCLUDE_DIR}") 43 | IF(${varname}_INCLUDE_DIR) 44 | GET_FILENAME_COMPONENT(${varname}_INCLUDE_DIR "${${varname}_INCLUDE_DIR}" PATH) 45 | GET_FILENAME_COMPONENT(${varname}_INCLUDE_DIR "${${varname}_INCLUDE_DIR}" PATH) 46 | ELSE() 47 | SET(${varname}_INCLUDE_DIR "${varname}_INCLUDE_DIR-NOTFOUND") 48 | ENDIF() 49 | ENDIF() 50 | ENDIF() 51 | ENDIF() 52 | 53 | 54 | IF(${${varname}_INCLUDE_DIR} STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND") 55 | MESSAGE(STATUS "Can't find includes for ${shortname}...") 56 | ELSE() 57 | MESSAGE(STATUS "Found ${shortname} include dirs: ${${varname}_INCLUDE_DIR}") 58 | 59 | # GET_DIRECTORY_PROPERTY(FFMPEG_PARENT DIRECTORY ${${varname}_INCLUDE_DIR} PARENT_DIRECTORY) 60 | GET_FILENAME_COMPONENT(FFMPEG_PARENT ${${varname}_INCLUDE_DIR} PATH) 61 | MESSAGE(STATUS "Using FFMpeg dir parent as hint: ${FFMPEG_PARENT}") 62 | 63 | IF(NOT WIN32) 64 | FIND_LIBRARY(${varname}_LIBRARIES NAMES ${shortname} 65 | HINTS ${PC_${varname}_LIBDIR} ${PC_${varname}_LIBRARY_DIR} ${FFMPEG_PARENT}) 66 | ELSE() 67 | # FIND_PATH(${varname}_LIBRARIES "${shortname}.dll.a" HINTS ${FFMPEG_PARENT}) 68 | FILE(GLOB_RECURSE ${varname}_LIBRARIES "${FFMPEG_PARENT}/*${shortname}.lib") 69 | # GLOBing is very bad... but windows sux, this is the only thing that works 70 | ENDIF() 71 | 72 | IF(${varname}_LIBRARIES STREQUAL "${varname}_LIBRARIES-NOTFOUND") 73 | MESSAGE(STATUS "look for newer structure for library") 74 | FIND_LIBRARY(${varname}_LIBRARIES NAMES lib${shortname} 75 | HINTS ${PC_${varname}_LIBDIR} ${PC_${varname}_LIBRARY_DIR} ${FFMPEG_PARENT}) 76 | ENDIF() 77 | 78 | 79 | IF(${varname}_LIBRARIES STREQUAL "${varname}_LIBRARIES-NOTFOUND") 80 | MESSAGE(STATUS "Can't find lib for ${shortname}...") 81 | ELSE() 82 | MESSAGE(STATUS "Found ${shortname} libs: ${${varname}_LIBRARIES}") 83 | ENDIF() 84 | 85 | 86 | IF(NOT ${varname}_INCLUDE_DIR STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND" 87 | AND NOT ${varname}_LIBRARIES STREQUAL ${varname}_LIBRARIES-NOTFOUND) 88 | 89 | MESSAGE(STATUS "found ${shortname}: include ${${varname}_INCLUDE_DIR} lib ${${varname}_LIBRARIES}") 90 | SET(FFMPEG_${varname}_FOUND 1) 91 | SET(FFMPEG_${varname}_INCLUDE_DIRS ${${varname}_INCLUDE_DIR}) 92 | SET(FFMPEG_${varname}_LIBS ${${varname}_LIBRARIES}) 93 | ELSE() 94 | MESSAGE(STATUS "Can't find ${shortname}") 95 | ENDIF() 96 | 97 | ENDIF() 98 | 99 | ENDMACRO(FFMPEG_FIND) 100 | 101 | FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) 102 | FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) 103 | FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) 104 | FFMPEG_FIND(LIBAVUTIL avutil avutil.h) 105 | FFMPEG_FIND(LIBSWSCALE swscale swscale.h) 106 | FFMPEG_FIND(LIBSWRESAMPLE swresample swresample.h) 107 | 108 | SET(FFMPEG_FOUND "NO") 109 | IF (FFMPEG_LIBAVFORMAT_FOUND AND 110 | FFMPEG_LIBAVDEVICE_FOUND AND 111 | FFMPEG_LIBAVCODEC_FOUND AND 112 | FFMPEG_LIBAVUTIL_FOUND AND 113 | FFMPEG_LIBSWSCALE_FOUND 114 | ) 115 | 116 | 117 | SET(FFMPEG_FOUND "YES") 118 | 119 | SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) 120 | 121 | SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) 122 | 123 | SET(FFMPEG_LIBRARIES 124 | ${FFMPEG_LIBAVFORMAT_LIBS} 125 | ${FFMPEG_LIBAVDEVICE_LIBS} 126 | ${FFMPEG_LIBAVCODEC_LIBS} 127 | ${FFMPEG_LIBAVUTIL_LIBS} 128 | ${FFMPEG_LIBSWSCALE_LIBS} 129 | ${FFMPEG_LIBSWRESAMPLE_LIBS} 130 | ) 131 | 132 | ELSE () 133 | 134 | MESSAGE(STATUS "Could not find FFMPEG") 135 | 136 | ENDIF() 137 | 138 | include(FindPackageHandleStandardArgs) 139 | # handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE 140 | # if all listed variables are TRUE 141 | find_package_handle_standard_args(FFMPEG DEFAULT_MSG 142 | FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) 143 | 144 | mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARY_DIRS FFMPEG_LIBRARIES) 145 | -------------------------------------------------------------------------------- /cmake/FindPORTAUDIO.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Portaudio 2 | # Once done this will define 3 | # 4 | # PORTAUDIO_FOUND - system has Portaudio 5 | # PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory 6 | # PORTAUDIO_LIBRARIES - Link these to use Portaudio 7 | # PORTAUDIO_DEFINITIONS - Compiler switches required for using Portaudio 8 | # PORTAUDIO_VERSION - Portaudio version 9 | # 10 | # Copyright (c) 2006 Andreas Schneider 11 | # 12 | # Redistribution and use is allowed according to the terms of the New BSD license. 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 14 | # 15 | 16 | 17 | if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) 18 | # in cache already 19 | set(PORTAUDIO_FOUND TRUE) 20 | else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) 21 | if (NOT WIN32) 22 | include(FindPkgConfig) 23 | pkg_check_modules(PORTAUDIO2 portaudio-2.0) 24 | endif (NOT WIN32) 25 | 26 | if (PORTAUDIO2_FOUND) 27 | set(PORTAUDIO_INCLUDE_DIRS 28 | ${PORTAUDIO2_INCLUDE_DIRS} 29 | ) 30 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 31 | set(PORTAUDIO_LIBRARIES "${PORTAUDIO2_LIBRARY_DIRS}/lib${PORTAUDIO2_LIBRARIES}.dylib") 32 | else (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 33 | set(PORTAUDIO_LIBRARIES 34 | ${PORTAUDIO2_LIBRARIES} 35 | ) 36 | endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 37 | set(PORTAUDIO_VERSION 38 | 19 39 | ) 40 | set(PORTAUDIO_FOUND TRUE) 41 | else (PORTAUDIO2_FOUND) 42 | find_path(PORTAUDIO_INCLUDE_DIR 43 | NAMES 44 | portaudio.h 45 | PATHS 46 | /usr/include 47 | /usr/local/include 48 | /opt/local/include 49 | /sw/include 50 | ) 51 | 52 | find_library(PORTAUDIO_LIBRARY 53 | NAMES 54 | portaudio 55 | PATHS 56 | /usr/lib 57 | /usr/local/lib 58 | /opt/local/lib 59 | /sw/lib 60 | ) 61 | 62 | find_path(PORTAUDIO_LIBRARY_DIR 63 | NAMES 64 | portaudio 65 | PATHS 66 | /usr/lib 67 | /usr/local/lib 68 | /opt/local/lib 69 | /sw/lib 70 | ) 71 | 72 | set(PORTAUDIO_INCLUDE_DIRS 73 | ${PORTAUDIO_INCLUDE_DIR} 74 | ) 75 | set(PORTAUDIO_LIBRARIES 76 | ${PORTAUDIO_LIBRARY} 77 | ) 78 | 79 | set(PORTAUDIO_LIBRARY_DIRS 80 | ${PORTAUDIO_LIBRARY_DIR} 81 | ) 82 | 83 | set(PORTAUDIO_VERSION 84 | 18 85 | ) 86 | 87 | if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) 88 | set(PORTAUDIO_FOUND TRUE) 89 | endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) 90 | 91 | if (PORTAUDIO_FOUND) 92 | if (NOT Portaudio_FIND_QUIETLY) 93 | message(STATUS "Found Portaudio: ${PORTAUDIO_LIBRARIES}") 94 | endif (NOT Portaudio_FIND_QUIETLY) 95 | else (PORTAUDIO_FOUND) 96 | if (Portaudio_FIND_REQUIRED) 97 | message(FATAL_ERROR "Could not find Portaudio") 98 | endif (PORTAUDIO_FIND_REQUIRED) 99 | endif (PORTAUDIO_FOUND) 100 | endif (PORTAUDIO2_FOUND) 101 | 102 | 103 | # show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view 104 | mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES) 105 | 106 | endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) 107 | -------------------------------------------------------------------------------- /cmake/fix_sdl2_release.cmake: -------------------------------------------------------------------------------- 1 | 2 | message(STATUS "Fixing SDL2 MSVS compability") 3 | 4 | set(target_file ${__TARGET}/CmakeLists.txt) 5 | 6 | file(READ ${target_file} content) 7 | string(REPLACE 8 | "list(APPEND EXTRA_LIBS user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)" 9 | "list(APPEND EXTRA_LIBS vcruntime user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)" 10 | content ${content}) 11 | file(WRITE ${target_file} ${content}) -------------------------------------------------------------------------------- /cmake/get-portaudio.cmake: -------------------------------------------------------------------------------- 1 | set(DEPENDENCY_EXTRACT_DIR ${DEPENDENCY_DIR}/extract) 2 | set(DEPENDENCY_INSTALL_DIR ${DEPENDENCY_DIR}/install) 3 | 4 | ExternalProject_Add(project_portaudio 5 | UPDATE_COMMAND "" 6 | GIT_REPOSITORY https://git.assembla.com/portaudio.git 7 | GIT_TAG 799a6834a5 8 | PREFIX ${DEPENDENCY_EXTRACT_DIR} 9 | INSTALL_DIR ${DEPENDENCY_INSTALL_DIR} 10 | CMAKE_ARGS 11 | -DCMAKE_INSTALL_PREFIX=${DEPENDENCY_INSTALL_DIR} 12 | #-DPA_USE_DS=OFF 13 | #-DPA_USE_WASAPI=OFF 14 | #-DPA_USE_WDMKS=OFF 15 | #-DPA_USE_WDMKS_DEVICE_INFO=OFF 16 | ) -------------------------------------------------------------------------------- /cmake/get-sdl2.cmake: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # External Project: SDL2 3 | # Downloads: https://libsdl.org/release/ 4 | #------------------------------------------------------------------------------ 5 | 6 | include(ExternalProject) 7 | 8 | set(SDL2_VERSION "2.0.12") 9 | 10 | set(ARCHIVE https://www.libsdl.org/release/SDL2-${SDL2_VERSION}.tar.gz) 11 | 12 | set(DEPENDENCY_DOWNLOAD_DIR ${DEPENDENCY_DIR}/download) 13 | set(DEPENDENCY_EXTRACT_DIR ${DEPENDENCY_DIR}/extract) 14 | set(DEPENDENCY_INSTALL_DIR ${DEPENDENCY_DIR}/install) 15 | 16 | if(MINGW) # download pre-compiled SDL2 dev package for MinGW 32/64-bit 17 | 18 | ExternalProject_Add(sdl2 19 | PATCH_COMMAND ${CMAKE_COMMAND} -D__TARGET=${DEPENDENCY_EXTRACT_DIR}/src/sdl2 -P ${MODULES_DIR}/fix_sdl2_release.cmake 20 | PREFIX ${DEPENDENCY_EXTRACT_DIR} 21 | DOWNLOAD_DIR ${DEPENDENCY_DOWNLOAD_DIR} 22 | URL ${ARCHIVE} 23 | INSTALL_DIR ${DEPENDENCY_INSTALL_DIR} 24 | CMAKE_ARGS 25 | -DCMAKE_INSTALL_PREFIX=${DEPENDENCY_INSTALL_DIR} 26 | #CONFIGURE_COMMAND "" 27 | #BUILD_COMMAND "" 28 | #INSTALL_COMMAND 29 | # COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDENCY_EXTRACT_DIR}/src/sdl2/lib ${DEPENDENCY_INSTALL_DIR}/lib 30 | # COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDENCY_EXTRACT_DIR}/src/sdl2/include ${DEPENDENCY_INSTALL_DIR}/include/SDL2 31 | ) 32 | 33 | endif(MINGW) 34 | 35 | if(MSVC) # download pre-compiled SDL2 dev package for Visual C++ 32/64-bit 36 | 37 | ExternalProject_Add(sdl2 38 | PATCH_COMMAND ${CMAKE_COMMAND} -D__TARGET=${DEPENDENCY_EXTRACT_DIR}/src/sdl2 -P ${MODULES_DIR}/fix_sdl2_release.cmake 39 | PREFIX ${DEPENDENCY_EXTRACT_DIR} 40 | DOWNLOAD_DIR ${DEPENDENCY_DOWNLOAD_DIR} 41 | URL ${ARCHIVE} 42 | INSTALL_DIR ${DEPENDENCY_INSTALL_DIR} 43 | CMAKE_ARGS 44 | -DCMAKE_INSTALL_PREFIX=${DEPENDENCY_INSTALL_DIR} 45 | #CONFIGURE_COMMAND "" 46 | #BUILD_COMMAND "" 47 | #INSTALL_COMMAND 48 | # COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDENCY_EXTRACT_DIR}/src/sdl2/lib ${DEPENDENCY_INSTALL_DIR}/lib 49 | # COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDENCY_EXTRACT_DIR}/src/sdl2/include ${DEPENDENCY_INSTALL_DIR}/include/SDL2 50 | ) 51 | 52 | endif(MSVC) 53 | 54 | set(DEPENDENCY_INSTALL_DIR ${DEPENDENCY_INSTALL_DIR} PARENT_SCOPE) 55 | 56 | -------------------------------------------------------------------------------- /libs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | find_package(FFMPEG REQUIRED) 3 | 4 | ############## 5 | # CLI11 6 | ############## 7 | 8 | set(CLI11_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CLI11/include) 9 | 10 | add_library(CLI11 INTERFACE) 11 | 12 | target_include_directories(CLI11 INTERFACE ${CLI11_DIR}) 13 | 14 | ############## 15 | # FFmpegVideoReader 16 | ############## 17 | 18 | set(FFmpegVideoReader_DIR ${CMAKE_CURRENT_SOURCE_DIR}/pcm_utils/FFmpegVideoReader) 19 | 20 | set(FFmpegVideoReader_SRC 21 | ${FFmpegVideoReader_DIR}/Context.cpp 22 | ${FFmpegVideoReader_DIR}/FFmpegVideoReader.cpp 23 | ${FFmpegVideoReader_DIR}/FFmpegVideoWriter.cpp 24 | ) 25 | 26 | add_library(FFmpegVideoReader STATIC ${FFmpegVideoReader_SRC}) 27 | 28 | target_include_directories(FFmpegVideoReader 29 | PUBLIC 30 | ${FFMPEG_INCLUDE_DIRS} 31 | ${FFmpegVideoReader_DIR} 32 | ) 33 | 34 | # message(STATUS ${FFMPEG_INCLUDE_DIRS}) 35 | 36 | target_link_libraries(FFmpegVideoReader 37 | PUBLIC 38 | ${FFMPEG_LIBRARIES} 39 | ) 40 | 41 | ############## 42 | # PlayerWriter 43 | ############## 44 | 45 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 46 | 47 | set(CMAKE_DEBUG_POSTFIX d) 48 | 49 | set(DEPENDENCY_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies) 50 | 51 | include(get-sdl2) 52 | include(get-portaudio) 53 | 54 | ExternalProject_Get_Property(sdl2 install_dir) 55 | 56 | set(sdl2_install_dir ${install_dir}) 57 | 58 | add_library(SDL2 STATIC IMPORTED) 59 | set_target_properties(SDL2 PROPERTIES IMPORTED_LOCATION_RELEASE ${sdl2_install_dir}/lib/SDL2${CMAKE_STATIC_LIBRARY_SUFFIX}) 60 | set_target_properties(SDL2 PROPERTIES IMPORTED_LOCATION_DEBUG ${sdl2_install_dir}/lib/SDL2d${CMAKE_STATIC_LIBRARY_SUFFIX}) 61 | add_dependencies(SDL2 sdl2) 62 | 63 | add_library(SDL2main STATIC IMPORTED) 64 | set_target_properties(SDL2main PROPERTIES IMPORTED_LOCATION_RELEASE ${sdl2_install_dir}/lib/SDL2main${CMAKE_STATIC_LIBRARY_SUFFIX}) 65 | set_target_properties(SDL2main PROPERTIES IMPORTED_LOCATION_DEBUG ${sdl2_install_dir}/lib/SDL2main${CMAKE_STATIC_LIBRARY_SUFFIX}) 66 | add_dependencies(SDL2main sdl2) 67 | 68 | ExternalProject_Get_Property(project_portaudio install_dir) 69 | 70 | set(portaudio_install_dir ${install_dir}) 71 | 72 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 73 | set(portaudio_libName portaudio_static_x86${CMAKE_STATIC_LIBRARY_SUFFIX}) 74 | else() 75 | set(portaudio_libName portaudio_static_x64${CMAKE_STATIC_LIBRARY_SUFFIX}) 76 | endif() 77 | 78 | add_library(Portaudio STATIC IMPORTED) 79 | set_target_properties(Portaudio PROPERTIES IMPORTED_LOCATION ${portaudio_install_dir}/lib/${portaudio_libName}) 80 | add_dependencies(Portaudio project_portaudio) 81 | 82 | #set(ADD_LIBS SDL2 Portaudio) 83 | #set(ADD_INCLUDES_PATHS 84 | # ${sdl2_install_dir}/include 85 | # ${portaudio_install_dir}/include 86 | #) 87 | 88 | set(PORTAUDIO_INCLUDE_DIRS ${portaudio_install_dir}/include) 89 | set(PORTAUDIO_LIBRARIES Portaudio) 90 | 91 | set(SDL2_FOUND TRUE) 92 | set(PORTAUDIO_FOUND TRUE) 93 | set(PORTAUDIO_VERSION 19) 94 | 95 | add_library(SDL2::SDL2main ALIAS SDL2main) 96 | add_library(SDL2::SDL2 ALIAS SDL2) 97 | 98 | else() 99 | 100 | find_package(SDL2) 101 | find_package(PORTAUDIO) 102 | 103 | endif() 104 | 105 | set(PlayerWriter_DIR ${CMAKE_CURRENT_SOURCE_DIR}/pcm_utils/PlayerWriter) 106 | 107 | 108 | if ((SDL2_FOUND) AND (PORTAUDIO_FOUND) AND (PORTAUDIO_VERSION EQUAL 19)) 109 | set(ADD_LIBS ${PORTAUDIO_LIBRARIES}) 110 | set(ADD_INCLUDES_PATHS ${PORTAUDIO_INCLUDE_DIRS}) 111 | if (SDL2_LIBRARIES) 112 | list(APPEND ADD_LIBS ${SDL2_LIBRARIES}) 113 | list(APPEND ADD_INCLUDES_PATHS ${SDL2_INCLUDE_DIRS}) 114 | else() 115 | list(APPEND ADD_LIBS SDL2::SDL2main SDL2::SDL2) 116 | endif() 117 | 118 | set(PlayerWriter_SRC 119 | ${PlayerWriter_DIR}/player.cpp 120 | ) 121 | 122 | add_library(PlayerWriter STATIC ${PlayerWriter_SRC}) 123 | 124 | target_include_directories(PlayerWriter 125 | PUBLIC 126 | ${ADD_INCLUDES_PATHS} 127 | ${PlayerWriter_DIR} 128 | ) 129 | 130 | target_link_libraries(PlayerWriter 131 | PUBLIC 132 | ${FFMPEG_LIBRARIES} 133 | ${ADD_LIBS} 134 | ) 135 | target_compile_definitions(PlayerWriter PUBLIC -DPLAYER) 136 | set(USE_PLAYER TRUE PARENT_SCOPE) 137 | else() 138 | message(STATUS "SDL2 or Portaudio not found. Display pcm not supported!") 139 | add_library(PlayerWriter INTERFACE) 140 | target_include_directories(PlayerWriter INTERFACE ${PlayerWriter_DIR}) 141 | set(USE_PLAYER FALSE PARENT_SCOPE) 142 | endif() 143 | 144 | ############## 145 | # pcm_utils 146 | ############## 147 | 148 | set(pcm_utils_DIR ${CMAKE_CURRENT_SOURCE_DIR}/pcm_utils/pcm_utils) 149 | 150 | set(pcm_utils_SRC 151 | ${pcm_utils_DIR}/PQ.cpp 152 | ${pcm_utils_DIR}/matrix_constants.cpp 153 | ${pcm_utils_DIR}/matrix_equations.cpp 154 | ${pcm_utils_DIR}/DataBlock.cpp 155 | ${pcm_utils_DIR}/Sample.cpp 156 | ${pcm_utils_DIR}/testlib.cpp 157 | ) 158 | 159 | add_library(pcm_utils STATIC ${pcm_utils_SRC}) 160 | 161 | target_include_directories(pcm_utils PUBLIC ${pcm_utils_DIR}) 162 | 163 | ############## 164 | # progress-cpp 165 | ############## 166 | 167 | add_subdirectory(progress-cpp) 168 | -------------------------------------------------------------------------------- /src/AudioProdusser.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "AudioProdusser.h" 4 | 5 | AudioProdusser::AudioProdusser(const std::string &filename) 6 | : audioreader(filename) {} 7 | 8 | Result AudioProdusser::exec() { 9 | AudioPacket packet; 10 | std::chrono::nanoseconds timestamp; 11 | 12 | if (!audioreader.getNextAudioData(packet.audio_data, packet.frames_read, 13 | timestamp)) { 14 | audioDataconsumer->Ressive(AudioPacketEof()); 15 | return Err(false); 16 | } 17 | 18 | audioDataconsumer->Ressive(packet); 19 | return Ok(timestamp); 20 | } 21 | -------------------------------------------------------------------------------- /src/AudioProdusser.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOPRODUSSER_H 2 | #define AUDIOPRODUSSER_H 3 | 4 | #include 5 | 6 | #include "result.h" 7 | 8 | #include "IConsumer.h" 9 | 10 | #include "audioreader.h" 11 | 12 | #include "abstractprocessingstage.h" 13 | 14 | struct AudioProdusser { 15 | struct AudioPacket { 16 | const AudioSample *audio_data; 17 | uint32_t frames_read; 18 | 19 | virtual bool eof() const { return false; } 20 | }; 21 | 22 | struct AudioPacketEof : public AudioPacket { 23 | bool eof() const override { return true; } 24 | }; 25 | 26 | const AudioReader &reader() const { return audioreader; } 27 | 28 | AudioProdusser(const std::string &filename); 29 | 30 | IConsumer &NextConsumer(IConsumer *newconsumer) { 31 | audioDataconsumer.reset(newconsumer); 32 | return *newconsumer; 33 | } 34 | 35 | template 36 | AbstractprocessingStage & 37 | NextStage(AbstractprocessingStage *newconsumer) { 38 | audioDataconsumer.reset(newconsumer); 39 | return *newconsumer; 40 | } 41 | 42 | Result exec(); 43 | 44 | std::chrono::nanoseconds duration() const { return audioreader.duration(); } 45 | 46 | private: 47 | std::unique_ptr> audioDataconsumer; 48 | AudioReader audioreader; 49 | }; 50 | 51 | #endif // AUDIOPRODUSSER_H 52 | -------------------------------------------------------------------------------- /src/BitWidthConverter.cpp: -------------------------------------------------------------------------------- 1 | #include "samplegenerator.h" 2 | 3 | #include "BitWidthConverter.h" 4 | 5 | struct BitWidthConverter::Context { 6 | Context(bool is_14_bit, bool use_dither) : generator{is_14_bit, use_dither} {} 7 | 8 | SampleGenerator generator; 9 | }; 10 | 11 | BitWidthConverter::BitWidthConverter(bool is_14_bit, bool use_dither) 12 | : ctx{std::make_unique(is_14_bit, use_dither)} {} 13 | 14 | void BitWidthConverter::Ressive( 15 | const AudioProdusser::AudioPacket &audiopacket) { 16 | if (audiopacket.eof()) { 17 | Send(SamplesPackEof{}); 18 | return; 19 | } 20 | Send(SamplesPack{ 21 | ctx->generator.convert(audiopacket.audio_data, audiopacket.frames_read)}); 22 | } 23 | -------------------------------------------------------------------------------- /src/BitWidthConverter.h: -------------------------------------------------------------------------------- 1 | #ifndef BITWIDTHCONVERTER_H 2 | #define BITWIDTHCONVERTER_H 3 | 4 | #include "abstractprocessingstage.h" 5 | 6 | #include "AudioProdusser.h" 7 | 8 | #include "samplespack.h" 9 | 10 | struct BitWidthConverter 11 | : public AbstractprocessingStage { 12 | 13 | BitWidthConverter(bool is_14_bit = false, bool use_dither = false); 14 | 15 | void Ressive(const AudioProdusser::AudioPacket &audiopacket) override; 16 | 17 | private: 18 | struct Context; 19 | std::unique_ptr ctx; 20 | }; 21 | 22 | #endif // BITWIDTHCONVERTER_H 23 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | ipcmframeprocessingpolicy.h 3 | iframe.h 4 | Splitter.h 5 | IConsumer.h 6 | result.h 7 | abstractprocessingstage.h 8 | samplespack.h 9 | audiosample.h 10 | 11 | audioreader.h 12 | audioreader.cpp 13 | 14 | print_duration.h 15 | print_duration.cpp 16 | 17 | samplegenerator.h 18 | samplegenerator.cpp 19 | 20 | pcmline.h 21 | pcmline.cpp 22 | 23 | pcmframe.h 24 | pcmframe.cpp 25 | 26 | frame.h 27 | frame.cpp 28 | 29 | samplestairsitherator.h 30 | samplestairsitherator.cpp 31 | 32 | ffmpegvideocoder.h 33 | ffmpegvideocoder.cpp 34 | 35 | argparser.h 36 | argparser.cpp 37 | 38 | AudioProdusser.h 39 | AudioProdusser.cpp 40 | 41 | BitWidthConverter.h 42 | BitWidthConverter.cpp 43 | 44 | ctrlc_listener.h 45 | ctrlc_listener.cpp 46 | 47 | LineGeneratorStage.h 48 | LineGeneratorStage.cpp 49 | 50 | PCMFrmageStage.h 51 | PCMFrmageStage.cpp 52 | 53 | PixelDuplicatorStage.h 54 | PixelDuplicatorStage.cpp 55 | 56 | FrameProxy.h 57 | FrameProxy.cpp 58 | 59 | FFmpegVideoCoderConsumer.h 60 | FFmpegVideoCoderConsumer.cpp 61 | ) 62 | 63 | add_library(common STATIC ${SRC}) 64 | set_property(TARGET common PROPERTY CXX_STANDARD ${CPP_STD}) 65 | target_link_libraries(common 66 | PUBLIC 67 | CLI11 68 | FFmpegVideoReader 69 | PlayerWriter 70 | pcm_utils 71 | progresscpp 72 | ) 73 | 74 | if (USE_PLAYER) 75 | # https://github.com/zanac/OpenPB4/blob/master/RetroPie/EmulationStation/CMakeLists.txt 76 | if(EXISTS "/opt/vc/include/bcm_host.h") 77 | # ref: https://github.com/ali1234/raspi-teletext 78 | add_executable(rpi-fb-shifter rpi_fb_shifter.cpp) 79 | 80 | set_property(TARGET rpi-fb-shifter PROPERTY CXX_STANDARD ${CPP_STD}) 81 | target_link_libraries(rpi-fb-shifter 82 | PUBLIC 83 | CLI11 84 | ) 85 | install(TARGETS rpi-fb-shifter) 86 | 87 | SET(RPI ON) 88 | endif() 89 | 90 | set(PLAY_LIN_SRC 91 | PlayerConsumer.h 92 | PlayerConsumer.cpp 93 | 94 | SDL2DisplayConsumerBase.h 95 | SDL2DisplayConsumerBase.cpp 96 | 97 | SDL2DisplayConsumer.h 98 | SDL2DisplayConsumer.cpp 99 | ) 100 | 101 | if (RPI) 102 | list(APPEND PLAY_LIN_SRC 103 | RPIFbDisplayConsumer.h 104 | RPIFbDisplayConsumer.cpp 105 | ) 106 | endif() 107 | 108 | add_library(playlib STATIC ${PLAY_LIN_SRC}) 109 | 110 | target_link_libraries(playlib 111 | PUBLIC 112 | PlayerWriter 113 | pcm_utils 114 | ) 115 | 116 | if (RPI) 117 | target_compile_definitions(playlib 118 | PUBLIC 119 | -DRPI 120 | ) 121 | target_compile_definitions(common 122 | PUBLIC 123 | -DRPI 124 | ) 125 | target_include_directories(playlib 126 | PRIVATE 127 | "/opt/vc/include" 128 | ) 129 | target_link_libraries(playlib 130 | PUBLIC 131 | -L/opt/vc/lib/ -lbcm_host 132 | ) 133 | endif() 134 | 135 | set_property(TARGET playlib PROPERTY CXX_STANDARD ${CPP_STD}) 136 | 137 | endif() 138 | 139 | add_executable(${PROJECT_NAME} main-st.cpp) 140 | 141 | target_link_libraries(${PROJECT_NAME} PUBLIC common) 142 | 143 | if (USE_PLAYER) 144 | target_link_libraries(${PROJECT_NAME} PUBLIC playlib) 145 | endif() 146 | 147 | if (NOT WIN32) 148 | target_link_libraries(${PROJECT_NAME} 149 | PUBLIC 150 | stdc++ 151 | pthread 152 | ) 153 | endif() 154 | 155 | 156 | #if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 157 | #set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:playlib /NODEFAULTLIB:common") 158 | #endif() 159 | 160 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_SIZEOF_VOID_P EQUAL 4) 161 | set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/SAFESEH:NO") 162 | endif() 163 | 164 | set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD ${CPP_STD}) 165 | 166 | install(TARGETS ${PROJECT_NAME}) 167 | 168 | add_custom_target(run ${CMAKE_CURENT_BINARY_DIR}/${PROJECT_NAME}) 169 | -------------------------------------------------------------------------------- /src/FFmpegVideoCoderConsumer.cpp: -------------------------------------------------------------------------------- 1 | #include "ffmpegvideocoder.h" 2 | 3 | #include "FFmpegVideoCoderConsumer.h" 4 | 5 | struct FFmpegVideoCoderConsumer::Context { 6 | Context(const std::string &filename, const std::string &codec, 7 | const uint32_t bitrate, bool PAL) 8 | : encoder{filename, codec, bitrate, PAL}, started{false} {} 9 | 10 | FFmpegVideoCoder encoder; 11 | bool started; 12 | }; 13 | 14 | FFmpegVideoCoderConsumer::FFmpegVideoCoderConsumer(const std::string &filename, 15 | const std::string &codec, 16 | const uint32_t bitrate, 17 | bool PAL) 18 | : ctx{std::make_unique(filename, codec, bitrate, PAL)} {} 19 | 20 | FFmpegVideoCoderConsumer::~FFmpegVideoCoderConsumer() {} 21 | 22 | void FFmpegVideoCoderConsumer::Ressive(const IFrame &frame) { 23 | if (!ctx->started) { 24 | ctx->encoder.Init(frame.width(), frame.heigth()); 25 | ctx->started = true; 26 | } 27 | 28 | if (ctx->started && frame.Eof()) { 29 | ctx->encoder.finish(); 30 | } else { 31 | ctx->encoder(frame); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/FFmpegVideoCoderConsumer.h: -------------------------------------------------------------------------------- 1 | #ifndef FFMPEGVIDEOCODERCONSUMER_H 2 | #define FFMPEGVIDEOCODERCONSUMER_H 3 | 4 | #include 5 | 6 | #include "IConsumer.h" 7 | #include "iframe.h" 8 | 9 | struct FFmpegVideoCoderConsumer : public IConsumer