diff --git a/.github/workflows/BuildAndTest.yml b/.github/workflows/BuildAndTest.yml index 87b299d..973aeb1 100644 --- a/.github/workflows/BuildAndTest.yml +++ b/.github/workflows/BuildAndTest.yml @@ -10,10 +10,12 @@ jobs: build: strategy: matrix: - config: [ {os: windows-latest, copyCommand: copy, artifactName: integrationTestWindows, buildPath: Release/, dummyLib: dummyLib.dll, integrationTest: integrationTest.exe}, - {os: ubuntu-latest, copyCommand: cp, artifactName: integrationTestUbuntu, buildPath: , dummyLib: libdummyLib.so, integrationTest: integrationTest}, - {os: macos-13, copyCommand: cp, artifactName: integrationTestMacIntel, buildPath: , dummyLib: libdummyLib.dylib, integrationTest: integrationTest}, - {os: macos-14, copyCommand: cp, artifactName: integrationTestMacM1, buildPath: , dummyLib: libdummyLib.dylib, integrationTest: integrationTest} ] + config: [ {os: windows-2025, copyCommand: copy, artifactName: integrationTestWindows, buildPath: Release/, dummyLib: dummyLib.dll, integrationTest: integrationTest.exe}, + {os: windows-11-arm, copyCommand: copy, artifactName: integrationTestWindowsArm, buildPath: Release/, dummyLib: dummyLib.dll, integrationTest: integrationTest.exe}, + {os: ubuntu-24.04, copyCommand: cp, artifactName: integrationTestUbuntu, buildPath: , dummyLib: libdummyLib.so, integrationTest: integrationTest}, + {os: ubuntu-24.04-arm, copyCommand: cp, artifactName: integrationTestUbuntuArm, buildPath: , dummyLib: libdummyLib.so, integrationTest: integrationTest}, + {os: macos-15, copyCommand: cp, artifactName: integrationTestMacArm, buildPath: , dummyLib: libdummyLib.dylib, integrationTest: integrationTest}, + {os: macos-15-intel, copyCommand: cp, artifactName: integrationTestMacIntel, buildPath: , dummyLib: libdummyLib.dylib, integrationTest: integrationTest} ] runs-on: ${{ matrix.config.os }} steps: @@ -40,12 +42,22 @@ jobs: needs: build strategy: matrix: - config: [ {os: windows-latest, artifactName: integrationTestWindows, azureFolder: windows, unzipCommand: 7z x }, - {os: ubuntu-latest, artifactName: integrationTestUbuntu, azureFolder: ubuntu-22.04, unzipCommand: unzip }, - {os: macos-13, artifactName: integrationTestMacIntel, azureFolder: macos-intel, unzipCommand: unzip }, - {os: macos-14, artifactName: integrationTestMacM1, azureFolder: macos-m1, unzipCommand: unzip } ] - ffmpegVersions: ["2.8.22", "3.4.13", "4.4.4", "5.1.4", "6.1.1", "7.0"] + config: [ {os: windows-2025, artifactName: integrationTestWindows, unzipCommand: 7z x }, + {os: windows-11-arm, artifactName: integrationTestWindowsArm, unzipCommand: 7z x }, + {os: ubuntu-24.04, artifactName: integrationTestUbuntu, unzipCommand: unzip }, + {os: ubuntu-24.04-arm, artifactName: integrationTestUbuntuArm, unzipCommand: unzip }, + {os: macos-15, artifactName: integrationTestMacArm, unzipCommand: unzip }, + {os: macos-15-intel, artifactName: integrationTestMacIntel, unzipCommand: unzip } ] + ffmpegVersions: ["2.8.22", "3.4.14", "4.4.6", "5.1.8", "6.1.4", "7.0.3", "8.0.1"] + exclude: + # I did not manage to compile the older ffmpeg versions an windows ARM + # Let me know if you manage to do so. + - ffmpegVersions: "2.8.22" + config: {os: windows-11-arm, artifactName: integrationTestWindowsArm, unzipCommand: 7z x } + - ffmpegVersions: "3.4.14" + config: {os: windows-11-arm, artifactName: integrationTestWindowsArm, unzipCommand: 7z x } runs-on: ${{ matrix.config.os }} + continue-on-error: true steps: - uses: actions/download-artifact@master with: @@ -53,12 +65,12 @@ jobs: - name: Make integrationTest executable run: chmod a+x integrationTest - if: ${{ matrix.config.os }} != windows-latest + if: runner.os == 'Linux' || runner.os == 'macOS' - name: Download FFmpeg run: | - curl -L "${{ secrets.AZURE_BLOB_ROOT_PATH }}ffmpeg/${{ matrix.config.azureFolder }}/ffmpeg-${{ matrix.ffmpegVersions }}.zip${{ secrets.AZURE_BLOB_TOKEN }}" -o ffmpeg.zip - curl -L "${{ secrets.AZURE_BLOB_ROOT_PATH }}bitstream-testfiles/TestFile_h264_aac_1s_320x240.mp4${{ secrets.AZURE_BLOB_TOKEN }}" -o TestFile_h264_aac_1s_320x240.mp4 + curl -L "${{ secrets.AZURE_BLOB_ROOT_PATH }}ffmpeg/github/ffmpeg-${{ matrix.ffmpegVersions }}-${{ matrix.config.os }}.zip?${{ secrets.AZURE_BLOB_TOKEN }}" -o ffmpeg.zip + curl -L "${{ secrets.AZURE_BLOB_ROOT_PATH }}bitstream-testfiles/TestFile_h264_aac_1s_320x240.mp4?${{ secrets.AZURE_BLOB_TOKEN }}" -o TestFile_h264_aac_1s_320x240.mp4 ${{ matrix.config.unzipCommand }} ffmpeg.zip rm ffmpeg.zip @@ -69,11 +81,13 @@ jobs: needs: build strategy: matrix: - config: [ {os: windows-latest, artifactName: integrationTestWindows}, - {os: ubuntu-latest, artifactName: integrationTestUbuntu}, - {os: macos-13, artifactName: integrationTestMacIntel}, - {os: macos-14, artifactName: integrationTestMacM1} ] + config: [ {os: windows-2025, artifactName: integrationTestWindows}, + {os: ubuntu-24.04, artifactName: integrationTestUbuntu}, + {os: ubuntu-24.04-arm, artifactName: integrationTestUbuntuArm}, + {os: macos-15, artifactName: integrationTestMacArm}, + {os: macos-15-intel, artifactName: integrationTestMacIntel} ] runs-on: ${{ matrix.config.os }} + continue-on-error: true steps: - uses: actions/download-artifact@master with: @@ -87,14 +101,14 @@ jobs: - name: Make integrationTest executable run: chmod a+x integrationTest - if: matrix.config.os != 'windows-latest' + if: runner.os == 'Linux' || runner.os == 'macOS' - name: Add ffmpeg to path - run: echo "C:\ProgramData\chocolatey\lib\ffmpeg-shared\tools\ffmpeg-7.0.2-full_build-shared\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - if: matrix.config.os == 'windows-latest' + run: echo "C:\ProgramData\chocolatey\lib\ffmpeg-shared\tools\ffmpeg-8.0.1-full_build-shared\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + if: runner.os == 'Windows' - name: Download Test files - run: curl -L "${{ secrets.AZURE_BLOB_ROOT_PATH }}bitstream-testfiles/TestFile_h264_aac_1s_320x240.mp4${{ secrets.AZURE_BLOB_TOKEN }}" -o TestFile_h264_aac_1s_320x240.mp4 + run: curl -L "${{ secrets.AZURE_BLOB_ROOT_PATH }}bitstream-testfiles/TestFile_h264_aac_1s_320x240.mp4?${{ secrets.AZURE_BLOB_TOKEN }}" -o TestFile_h264_aac_1s_320x240.mp4 - name: Run integration tests run: ./integrationTest diff --git a/.gitignore b/.gitignore index d0b6b4b..7417a0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vscode +.cache build buildFFmpeg *.mp4 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1090359..9a1a798 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if(NOT CMAKE_BUILD_TYPE) endif() message(STATUS "Build type " ${CMAKE_BUILD_TYPE}) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) project(LibFFmpeg++) diff --git a/src/lib/AVCodec/Channel.h b/src/lib/AVCodec/Channel.h new file mode 100644 index 0000000..6a9773a --- /dev/null +++ b/src/lib/AVCodec/Channel.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2023 Christian Feldmann [christian.feldmann@gmx.de]. + * All rights reserved. + * This work is licensed under the terms of the MIT license. + * For a copy, see . + */ + +#pragma once + +#include "common/EnumMapper.h" + +#include + +namespace libffmpeg::avcodec +{ + +enum class Channel +{ + Unused, + FrontLeft, + FrontRight, + FrontCenter, + LowFrequency, + BackLeft, + BackRight, + FrontLeftOfCenter, + FrontRightOfCenter, + BackCenter, + SideLeft, + SideRight, + TopCenter, + TopFrontLeft, + TopFrontCenter, + TopFrontRight, + TopBackLeft, + TopBackCenter, + TopBackRight, + StereoLeft, + StereoRight, + WideLeft, + WideRight, + SurroundDirectLeft, + SurroundDirectRight, + LowFrequency2, + TopSideLeft, + TopSideRight, + BottomFrontCenter, + BottomFrontLeft, + BottomFrontRight, + SideSurroundLeft, + SideSurroundRight, + TopSurroundLeft, + TopSurroundRight, + BinauralLeft, + BinauralRight, + Ambisonic +}; + +const EnumMapper + channelMapper({{Channel::FrontLeft, "FL", "Front Left"}, + {Channel::FrontRight, "FR", "Front Right"}, + {Channel::FrontCenter, "FC", "Front Center"}, + {Channel::LowFrequency, "LFE", "Low Frequency"}, + {Channel::BackLeft, "BL", "Back Left"}, + {Channel::BackRight, "BR", "Back Right"}, + {Channel::FrontLeftOfCenter, "FLC", "Front Left of Center"}, + {Channel::FrontRightOfCenter, "FRC", "Front Right of Center"}, + {Channel::BackCenter, "BC", "Back Center"}, + {Channel::SideLeft, "SL", "Side Left"}, + {Channel::SideRight, "SR", "Side Right"}, + {Channel::TopCenter, "TC", "Top Center"}, + {Channel::TopFrontLeft, "TFL", "Top Front Left"}, + {Channel::TopFrontCenter, "TFC", "Top Front Center"}, + {Channel::TopFrontRight, "TFR", "Top Front Right"}, + {Channel::TopBackLeft, "TBL", "Top Back Left"}, + {Channel::TopBackCenter, "TBC", "Top Back Center"}, + {Channel::TopBackRight, "TBR", "Top Back Right"}, + {Channel::StereoLeft, "SLT", "Stereo Left"}, + {Channel::StereoRight, "SRT", "Stereo Right"}, + {Channel::WideLeft, "WL", "Wide Left"}, + {Channel::WideRight, "WR", "Wide Right"}, + {Channel::SurroundDirectLeft, "SDL", "Surround Direct Left"}, + {Channel::SurroundDirectRight, "SDR", "Surround Direct Right"}, + {Channel::LowFrequency2, "LFE2", "Low Frequency 2"}, + {Channel::TopSideLeft, "TSL", "Top Side Left"}, + {Channel::TopSideRight, "TSR", "Top Side Right"}, + {Channel::BottomFrontCenter, "BFC", "Bottom Front Center"}, + {Channel::BottomFrontLeft, "BFL", "Bottom Front Left"}, + {Channel::BottomFrontRight, "BFR", "Bottom Front Right"}, + {Channel::SideSurroundLeft, "SSL", "Side Surround Left"}, + {Channel::SideSurroundRight, "SSR", "Side Surround Right"}, + {Channel::TopSurroundLeft, "TSL", "Top Surround Left"}, + {Channel::TopSurroundRight, "TSR", "Top Surround Right"}, + {Channel::BinauralLeft, "BL", "Binaural Left"}, + {Channel::BinauralRight, "BR", "Binaural Right"}, + {Channel::Ambisonic, "AMB", "Ambisonic"}}); + +struct ChannelInfo +{ + std::optional channel; + std::optional ambisonicIndex; + std::string name; + + bool operator==(const ChannelInfo &other) const + { + return this->channel == other.channel && this->ambisonicIndex == other.ambisonicIndex && + this->name == other.name; + } + + friend std::ostream &operator<<(std::ostream &stream, const ChannelInfo &channelInfo) + { + stream << "{ Channel " + << (channelInfo.channel ? channelMapper.getName(*channelInfo.channel) : "nullopt") + << ", ambisonicIndex: " + << (channelInfo.ambisonicIndex ? std::to_string(*channelInfo.ambisonicIndex) : "nullopt") + << ", name: \"" << channelInfo.name << "\"}"; + return stream; + } +}; + +using ChannelLayout = std::vector; + +} // namespace libffmpeg::avcodec \ No newline at end of file diff --git a/src/lib/AVCodec/wrappers/AVChannelInternal.cpp b/src/lib/AVCodec/wrappers/AVChannelInternal.cpp new file mode 100644 index 0000000..550b784 --- /dev/null +++ b/src/lib/AVCodec/wrappers/AVChannelInternal.cpp @@ -0,0 +1,215 @@ +/* Copyright (c) 2023 Christian Feldmann [christian.feldmann@gmx.de]. + * All rights reserved. + * This work is licensed under the terms of the MIT license. + * For a copy, see . + */ + +#include "AVChannelInternal.h" + +#include "../Channel.h" + +#include + +namespace libffmpeg::internal::avcodec +{ + +using libffmpeg::avcodec::Channel; +using libffmpeg::avcodec::ChannelInfo; + +namespace +{ + +ChannelLayout createUndefinedChannelLayout(const int numberChannels) +{ + ChannelLayout channelLayout; + for (int ch = 0; ch < numberChannels; ++ch) + { + ChannelInfo channelInfo; + channelInfo.name = "Unspecified"; + channelLayout.push_back(channelInfo); + } + return channelLayout; +} + +std::optional avChannelToChannel(const AVChannel avChannel) +{ + switch (avChannel) + { + case AVChannel::AV_CHAN_UNUSED: + return Channel::Unused; + case AVChannel::AV_CHAN_FRONT_LEFT: + return Channel::FrontLeft; + case AVChannel::AV_CHAN_FRONT_RIGHT: + return Channel::FrontRight; + case AVChannel::AV_CHAN_FRONT_CENTER: + return Channel::FrontCenter; + case AVChannel::AV_CHAN_LOW_FREQUENCY: + return Channel::LowFrequency; + case AVChannel::AV_CHAN_BACK_LEFT: + return Channel::BackLeft; + case AVChannel::AV_CHAN_BACK_RIGHT: + return Channel::BackRight; + case AVChannel::AV_CHAN_FRONT_LEFT_OF_CENTER: + return Channel::FrontLeftOfCenter; + case AVChannel::AV_CHAN_FRONT_RIGHT_OF_CENTER: + return Channel::FrontRightOfCenter; + case AVChannel::AV_CHAN_BACK_CENTER: + return Channel::BackCenter; + case AVChannel::AV_CHAN_SIDE_LEFT: + return Channel::SideLeft; + case AVChannel::AV_CHAN_SIDE_RIGHT: + return Channel::SideRight; + case AVChannel::AV_CHAN_TOP_CENTER: + return Channel::TopCenter; + case AVChannel::AV_CHAN_TOP_FRONT_LEFT: + return Channel::TopFrontLeft; + case AVChannel::AV_CHAN_TOP_FRONT_CENTER: + return Channel::TopFrontCenter; + case AVChannel::AV_CHAN_TOP_FRONT_RIGHT: + return Channel::TopFrontRight; + case AVChannel::AV_CHAN_TOP_BACK_LEFT: + return Channel::TopBackLeft; + case AVChannel::AV_CHAN_TOP_BACK_CENTER: + return Channel::TopBackCenter; + case AVChannel::AV_CHAN_TOP_BACK_RIGHT: + return Channel::TopBackRight; + case AVChannel::AV_CHAN_STEREO_LEFT: + return Channel::StereoLeft; + case AVChannel::AV_CHAN_STEREO_RIGHT: + return Channel::StereoRight; + case AVChannel::AV_CHAN_WIDE_LEFT: + return Channel::WideLeft; + case AVChannel::AV_CHAN_WIDE_RIGHT: + return Channel::WideRight; + case AVChannel::AV_CHAN_SURROUND_DIRECT_LEFT: + return Channel::SurroundDirectLeft; + case AVChannel::AV_CHAN_SURROUND_DIRECT_RIGHT: + return Channel::SurroundDirectRight; + case AVChannel::AV_CHAN_LOW_FREQUENCY_2: + return Channel::LowFrequency2; + case AVChannel::AV_CHAN_TOP_SIDE_LEFT: + return Channel::TopSideLeft; + case AVChannel::AV_CHAN_TOP_SIDE_RIGHT: + return Channel::TopSideRight; + case AVChannel::AV_CHAN_BOTTOM_FRONT_CENTER: + return Channel::BottomFrontCenter; + case AVChannel::AV_CHAN_BOTTOM_FRONT_LEFT: + return Channel::BottomFrontLeft; + case AVChannel::AV_CHAN_BOTTOM_FRONT_RIGHT: + return Channel::BottomFrontRight; + case AVChannel::AV_CHAN_SIDE_SURROUND_LEFT: + return Channel::SideSurroundLeft; + case AVChannel::AV_CHAN_SIDE_SURROUND_RIGHT: + return Channel::SideSurroundRight; + case AVChannel::AV_CHAN_TOP_SURROUND_LEFT: + return Channel::TopSurroundLeft; + case AVChannel::AV_CHAN_TOP_SURROUND_RIGHT: + return Channel::TopSurroundRight; + case AVChannel::AV_CHAN_BINAURAL_LEFT: + return Channel::BinauralLeft; + case AVChannel::AV_CHAN_BINAURAL_RIGHT: + return Channel::BinauralRight; + default: + return {}; + } +} + +ChannelLayout customChannelMapToLayout(const AVChannelCustom *map, int numberChannels) +{ + ChannelLayout layout; + + auto iterator = map; + for (int i = 0; i < numberChannels; ++i) + { + ChannelInfo channelInfo; + channelInfo.name = std::string(iterator->name); + + if (iterator->id == AVChannel::AV_CHAN_AMBISONIC_BASE) + { + channelInfo.ambisonicIndex = + static_cast(iterator->id) - static_cast(AVChannel::AV_CHAN_AMBISONIC_BASE); + channelInfo.channel = Channel::Ambisonic; + } + else + channelInfo.channel = avChannelToChannel(iterator->id); + + layout.push_back(channelInfo); + iterator++; + } + + return layout; +} + +} // namespace + +ChannelLayout bitMaskToChannelLayout(const uint64_t mask, const bool isAmbisonic) +{ + ChannelLayout layout; + + std::bitset<64> bits(mask); + for (int bitPosition = 0; bitPosition < 64; ++bitPosition) + { + if (bits.test(bitPosition)) + { + const auto avChannel = static_cast(bitPosition); + if (const auto channel = avChannelToChannel(avChannel)) + { + ChannelInfo channelInfo; + channelInfo.channel = *channel; + channelInfo.name = libffmpeg::avcodec::channelMapper.getName(*channel); + if (isAmbisonic) + channelInfo.ambisonicIndex = bitPosition; + layout.push_back(channelInfo); + } + } + } + + return layout; +} + +std::vector maskArrayToChannelLayouts(const uint64_t *masks) +{ + std::vector layouts; + int i = 0; + auto mask = masks[i]; + while (mask != 0) + { + layouts.push_back(bitMaskToChannelLayout(mask)); + + i++; + mask = masks[i]; + } + return layouts; +} + +ChannelLayout avChannelLayoutToChannelLayout(const AVChannelLayout &avLayout) +{ + if (avLayout.order == AVChannelOrder::AV_CHANNEL_ORDER_UNSPEC) + return createUndefinedChannelLayout(avLayout.nb_channels); + else if (avLayout.order == AVChannelOrder::AV_CHANNEL_ORDER_NATIVE) + return bitMaskToChannelLayout(avLayout.u.mask); + else if (avLayout.order == AVChannelOrder::AV_CHANNEL_ORDER_CUSTOM) + return customChannelMapToLayout(avLayout.u.map, avLayout.nb_channels); + else if (avLayout.order == AVChannelOrder::AV_CHANNEL_ORDER_AMBISONIC) + return bitMaskToChannelLayout(avLayout.u.mask, true); + + throw std::runtime_error("Invalid channel layout order"); +} + +std::vector avChannelLayoutListToChannelLayouts(const AVChannelLayout *layoutList) +{ + std::vector layouts; + + int i = 0; + auto layout = layoutList[i]; + while (layout.nb_channels != 0) + { + layouts.push_back(avChannelLayoutToChannelLayout(layout)); + i++; + layout = layoutList[i]; + } + + return layouts; +} + +} // namespace libffmpeg::internal::avcodec diff --git a/src/lib/AVCodec/wrappers/AVChannelInternal.h b/src/lib/AVCodec/wrappers/AVChannelInternal.h new file mode 100644 index 0000000..51a3ec6 --- /dev/null +++ b/src/lib/AVCodec/wrappers/AVChannelInternal.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2023 Christian Feldmann [christian.feldmann@gmx.de]. + * All rights reserved. + * This work is licensed under the terms of the MIT license. + * For a copy, see . + */ + +#pragma once + +#include + +#include "../Channel.h" + +namespace libffmpeg::internal::avcodec +{ + +enum AVChannelOrder +{ + AV_CHANNEL_ORDER_UNSPEC, + AV_CHANNEL_ORDER_NATIVE, + AV_CHANNEL_ORDER_CUSTOM, + AV_CHANNEL_ORDER_AMBISONIC +}; + +enum AVChannel +{ + AV_CHAN_NONE = -1, + AV_CHAN_FRONT_LEFT, + AV_CHAN_FRONT_RIGHT, + AV_CHAN_FRONT_CENTER, + AV_CHAN_LOW_FREQUENCY, + AV_CHAN_BACK_LEFT, + AV_CHAN_BACK_RIGHT, + AV_CHAN_FRONT_LEFT_OF_CENTER, + AV_CHAN_FRONT_RIGHT_OF_CENTER, + AV_CHAN_BACK_CENTER, + AV_CHAN_SIDE_LEFT, + AV_CHAN_SIDE_RIGHT, + AV_CHAN_TOP_CENTER, + AV_CHAN_TOP_FRONT_LEFT, + AV_CHAN_TOP_FRONT_CENTER, + AV_CHAN_TOP_FRONT_RIGHT, + AV_CHAN_TOP_BACK_LEFT, + AV_CHAN_TOP_BACK_CENTER, + AV_CHAN_TOP_BACK_RIGHT, + AV_CHAN_STEREO_LEFT = 29, + AV_CHAN_STEREO_RIGHT, + AV_CHAN_WIDE_LEFT, + AV_CHAN_WIDE_RIGHT, + AV_CHAN_SURROUND_DIRECT_LEFT, + AV_CHAN_SURROUND_DIRECT_RIGHT, + AV_CHAN_LOW_FREQUENCY_2, + AV_CHAN_TOP_SIDE_LEFT, + AV_CHAN_TOP_SIDE_RIGHT, + AV_CHAN_BOTTOM_FRONT_CENTER, + AV_CHAN_BOTTOM_FRONT_LEFT, + AV_CHAN_BOTTOM_FRONT_RIGHT, + AV_CHAN_SIDE_SURROUND_LEFT, ///< +90 degrees, Lss, SiL + AV_CHAN_SIDE_SURROUND_RIGHT, ///< -90 degrees, Rss, SiR + AV_CHAN_TOP_SURROUND_LEFT, ///< +110 degrees, Lvs, TpLS + AV_CHAN_TOP_SURROUND_RIGHT, ///< -110 degrees, Rvs, TpRS + AV_CHAN_BINAURAL_LEFT = 61, + AV_CHAN_BINAURAL_RIGHT, + AV_CHAN_UNUSED = 0x200, + AV_CHAN_UNKNOWN = 0x300, + AV_CHAN_AMBISONIC_BASE = 0x400, + AV_CHAN_AMBISONIC_END = 0x7ff +}; + +struct AVChannelCustom +{ + AVChannel id{}; + char name[16]{}; + void *opaque{}; +}; + +struct AVChannelLayout +{ + AVChannelOrder order{}; + int nb_channels{}; + union + { + uint64_t mask; + AVChannelCustom *map; + } u{}; + void *opaque{}; +}; + +using libffmpeg::avcodec::ChannelLayout; +ChannelLayout bitMaskToChannelLayout(const uint64_t mask, const bool isAmbisonic = false); +std::vector maskArrayToChannelLayouts(const uint64_t *masks); + +ChannelLayout avChannelLayoutToChannelLayout(const AVChannelLayout &avLayout); +std::vector avChannelLayoutListToChannelLayouts(const AVChannelLayout *layoutList); + +} // namespace libffmpeg::internal::avcodec \ No newline at end of file diff --git a/src/lib/AVCodec/wrappers/AVCodecContextWrapper.cpp b/src/lib/AVCodec/wrappers/AVCodecContextWrapper.cpp index ffdb44b..8646b29 100644 --- a/src/lib/AVCodec/wrappers/AVCodecContextWrapper.cpp +++ b/src/lib/AVCodec/wrappers/AVCodecContextWrapper.cpp @@ -29,6 +29,7 @@ using libffmpeg::internal::avcodec::AVCodecContext_58; using libffmpeg::internal::avcodec::AVCodecContext_59; using libffmpeg::internal::avcodec::AVCodecContext_60; using libffmpeg::internal::avcodec::AVCodecContext_61; +using libffmpeg::internal::avcodec::AVCodecContext_62; namespace internal { diff --git a/src/lib/AVCodec/wrappers/AVCodecContextWrapperInternal.h b/src/lib/AVCodec/wrappers/AVCodecContextWrapperInternal.h index efb61eb..c147733 100644 --- a/src/lib/AVCodec/wrappers/AVCodecContextWrapperInternal.h +++ b/src/lib/AVCodec/wrappers/AVCodecContextWrapperInternal.h @@ -432,4 +432,49 @@ struct AVCodecContext_61 // Actually, there is more here, but the variables above are the only we need. }; +struct AVCodecContext_62 +{ + const AVClass * av_class{}; + int log_level_offset{}; + AVMediaType codec_type{}; + const AVCodec * codec{}; + AVCodecID codec_id{}; + unsigned int codec_tag{}; + void * priv_data{}; + AVCodecInternal * internal{}; + void * opaque{}; + int64_t bit_rate; + int flags; + int flags2; + uint8_t * extradata; + int extradata_size; + AVRational time_base; + AVRational pkt_timebase; + AVRational framerate; + int delay; + int width, height; + int coded_width, coded_height; + AVRational sample_aspect_ratio; + enum AVPixelFormat pix_fmt; + enum AVPixelFormat sw_pix_fmt; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + enum AVColorRange color_range; + enum AVChromaLocation chroma_sample_location; + enum AVFieldOrder field_order; + int refs; + int has_b_frames; + int slice_flags; + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame * src, + int offset[AV_NUM_DATA_POINTERS], + int y, + int type, + int height); + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat *fmt); + + // Actually, there is more here, but the variables above are the only we need. +}; + } // namespace libffmpeg::internal::avcodec diff --git a/src/lib/AVCodec/wrappers/AVCodecDescriptorConversion.h b/src/lib/AVCodec/wrappers/AVCodecDescriptorConversion.h index aa85ab3..c1a0236 100644 --- a/src/lib/AVCodec/wrappers/AVCodecDescriptorConversion.h +++ b/src/lib/AVCodec/wrappers/AVCodecDescriptorConversion.h @@ -9,8 +9,6 @@ #include #include -#include - namespace libffmpeg::avcodec { @@ -37,6 +35,6 @@ struct CodecDescriptor bool operator==(const CodecDescriptorProperties &lhs, const CodecDescriptorProperties &rhs); CodecDescriptor convertAVCodecDescriptor(const internal::AVCodecDescriptor *avCodecDescriptor, - const Version & avCodecVersion); + const Version &avCodecVersion); } // namespace libffmpeg::avcodec diff --git a/src/lib/AVCodec/wrappers/AVCodecDescriptorConversionInternal.h b/src/lib/AVCodec/wrappers/AVCodecDescriptorConversionInternal.h index cd75e99..8593d50 100644 --- a/src/lib/AVCodec/wrappers/AVCodecDescriptorConversionInternal.h +++ b/src/lib/AVCodec/wrappers/AVCodecDescriptorConversionInternal.h @@ -46,5 +46,6 @@ typedef AVCodecDescriptor_57 AVCodecDescriptor_58; typedef AVCodecDescriptor_57 AVCodecDescriptor_59; typedef AVCodecDescriptor_57 AVCodecDescriptor_60; typedef AVCodecDescriptor_57 AVCodecDescriptor_61; +typedef AVCodecDescriptor_57 AVCodecDescriptor_62; } // namespace libffmpeg::internal::avcodec diff --git a/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.cpp b/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.cpp index f8ff4d3..38aed9a 100644 --- a/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.cpp +++ b/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.cpp @@ -9,6 +9,7 @@ #include #include +#include "AVCodec/wrappers/AVChannelInternal.h" #include "AVCodecParametersWrapperInternal.h" #include "CastCodecClasses.h" @@ -30,6 +31,7 @@ using libffmpeg::internal::avcodec::AVCodecParameters_58; using libffmpeg::internal::avcodec::AVCodecParameters_59; using libffmpeg::internal::avcodec::AVCodecParameters_60; using libffmpeg::internal::avcodec::AVCodecParameters_61; +using libffmpeg::internal::avcodec::AVCodecParameters_62; constexpr std::size_t AV_INPUT_BUFFER_PADDING_SIZE = 32; @@ -125,11 +127,43 @@ Rational AVCodecParametersWrapper::getSampleAspectRatio() const return {sampleAspectRatio.num, sampleAspectRatio.den}; } +ChannelLayout AVCodecParametersWrapper::getChannelLayout() const +{ + const auto version = this->ffmpegLibraries->getLibrariesVersion().avformat.major; + + if (version == 56) + { + return {}; + } + else if (version == 57 || version == 58) + { + const auto p = reinterpret_cast(this->codecParameters); + return internal::avcodec::bitMaskToChannelLayout(p->channel_layout); + } + else if (version == 59) + { + const auto p = reinterpret_cast(this->codecParameters); + return internal::avcodec::avChannelLayoutToChannelLayout(p->ch_layout); + } + else if (version == 60) + { + const auto p = reinterpret_cast(this->codecParameters); + return internal::avcodec::avChannelLayoutToChannelLayout(p->ch_layout); + } + else if (version == 61 || version == 62) + { + const auto p = reinterpret_cast(this->codecParameters); + return internal::avcodec::avChannelLayoutToChannelLayout(p->ch_layout); + } + + throw std::runtime_error("Invalid library version"); +} + void AVCodecParametersWrapper::setClearValues() { const auto version = this->ffmpegLibraries->getLibrariesVersion().avformat.major; - if (version == 57 || version == 58 || version == 59 || version == 60 || version == 61) + if (version == 57 || version == 58 || version == 59 || version == 60) { auto p = reinterpret_cast(this->codecParameters); p->codec_type = libffmpeg::internal::AVMEDIA_TYPE_UNKNOWN; @@ -159,6 +193,39 @@ void AVCodecParametersWrapper::setClearValues() p->chroma_location = internal::AVCHROMA_LOC_UNSPECIFIED; p->video_delay = 0; } + else if (version == 61 || version == 62) + { + auto p = reinterpret_cast(this->codecParameters); + p->codec_type = libffmpeg::internal::AVMEDIA_TYPE_UNKNOWN; + p->codec_id = libffmpeg::internal::AV_CODEC_ID_NONE; + p->codec_tag = 0; + p->extradata = nullptr; + p->extradata_size = 0; + p->coded_side_data = nullptr; + p->nb_coded_side_data = 0; + p->format = 0; + p->bit_rate = 0; + p->bits_per_coded_sample = 0; + p->bits_per_raw_sample = 0; + p->profile = 0; + p->level = 0; + p->width = 0; + p->height = 0; + { + AVRational ratio; + ratio.num = 1; + ratio.den = 1; + p->sample_aspect_ratio = ratio; + p->framerate = ratio; + } + p->field_order = internal::AV_FIELD_UNKNOWN; + p->color_range = internal::AVCOL_RANGE_UNSPECIFIED; + p->color_primaries = internal::AVCOL_PRI_UNSPECIFIED; + p->color_trc = internal::AVCOL_TRC_UNSPECIFIED; + p->color_space = internal::AVCOL_SPC_UNSPECIFIED; + p->chroma_location = internal::AVCHROMA_LOC_UNSPECIFIED; + p->video_delay = 0; + } else throw std::runtime_error("Invalid library version"); } @@ -176,7 +243,7 @@ void AVCodecParametersWrapper::setAVCodecID(AVCodecID id) void AVCodecParametersWrapper::setExtradata(const ByteVector &data) { - uint8_t * extradata{}; + uint8_t *extradata{}; const auto versions = this->ffmpegLibraries->getLibrariesVersion(); CAST_AVCODEC_GET_MEMBER(AVCodecParameters, this->codecParameters, extradata, extradata); diff --git a/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.h b/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.h index 859b57a..c3a2108 100644 --- a/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.h +++ b/src/lib/AVCodec/wrappers/AVCodecParametersWrapper.h @@ -13,6 +13,8 @@ #include #include +#include "../Channel.h" + namespace libffmpeg::avcodec { class AVCodecParametersWrapper @@ -29,6 +31,7 @@ class AVCodecParametersWrapper avutil::ColorSpace getColorspace() const; avutil::PixelFormatDescriptor getPixelFormat() const; Rational getSampleAspectRatio() const; + ChannelLayout getChannelLayout() const; // Set a default set of (unknown) values void setClearValues(); diff --git a/src/lib/AVCodec/wrappers/AVCodecParametersWrapperInternal.h b/src/lib/AVCodec/wrappers/AVCodecParametersWrapperInternal.h index 43f5616..4935fd6 100644 --- a/src/lib/AVCodec/wrappers/AVCodecParametersWrapperInternal.h +++ b/src/lib/AVCodec/wrappers/AVCodecParametersWrapperInternal.h @@ -6,6 +6,10 @@ #pragma once +#include + +#include "AVChannelInternal.h" + namespace libffmpeg::internal::avcodec { @@ -18,7 +22,7 @@ struct AVCodecParameters_56 { AVMediaType codec_type; AVCodecID codec_id; - uint8_t * extradata; + uint8_t *extradata; int extradata_size; int format; int profile; @@ -34,7 +38,7 @@ struct AVCodecParameters_57 AVMediaType codec_type; AVCodecID codec_id; uint32_t codec_tag; - uint8_t * extradata; + uint8_t *extradata; int extradata_size; int format; int64_t bit_rate; @@ -52,22 +56,97 @@ struct AVCodecParameters_57 AVColorSpace color_space; AVChromaLocation chroma_location; int video_delay; - - // Actually, there is more here, but the variables above are the only we need. + uint64_t channel_layout; + int channels; + int sample_rate; + int block_align; + int frame_size; + int initial_padding; + int trailing_padding; + int seek_preroll; }; typedef AVCodecParameters_57 AVCodecParameters_58; -typedef AVCodecParameters_57 AVCodecParameters_59; -typedef AVCodecParameters_57 AVCodecParameters_60; + +struct AVCodecParameters_59 +{ + AVMediaType codec_type; + AVCodecID codec_id; + uint32_t codec_tag; + uint8_t *extradata; + int extradata_size; + int format; + int64_t bit_rate; + int bits_per_coded_sample; + int bits_per_raw_sample; + int profile; + int level; + int width; + int height; + AVRational sample_aspect_ratio; + AVFieldOrder field_order; + AVColorRange color_range; + AVColorPrimaries color_primaries; + AVColorTransferCharacteristic color_trc; + AVColorSpace color_space; + AVChromaLocation chroma_location; + int video_delay; + uint64_t channel_layout; + int channels; + int sample_rate; + int block_align; + int frame_size; + int initial_padding; + int trailing_padding; + int seek_preroll; + AVChannelLayout ch_layout; +}; + +struct AVCodecParameters_60 +{ + AVMediaType codec_type; + AVCodecID codec_id; + uint32_t codec_tag; + uint8_t *extradata; + int extradata_size; + int format; + int64_t bit_rate; + int bits_per_coded_sample; + int bits_per_raw_sample; + int profile; + int level; + int width; + int height; + AVRational sample_aspect_ratio; + AVFieldOrder field_order; + AVColorRange color_range; + AVColorPrimaries color_primaries; + AVColorTransferCharacteristic color_trc; + AVColorSpace color_space; + AVChromaLocation chroma_location; + int video_delay; + uint64_t channel_layout; + int channels; + int sample_rate; + int block_align; + int frame_size; + int initial_padding; + int trailing_padding; + int seek_preroll; + AVChannelLayout ch_layout; + AVRational framerate; + AVPacketSideData *coded_side_data; + int nb_coded_side_data; +}; struct AVCodecParameters_61 { AVMediaType codec_type; AVCodecID codec_id; uint32_t codec_tag; - uint8_t * extradata; + uint8_t *extradata; int extradata_size; - AVPacketSideData * coded_side_data; + AVPacketSideData *coded_side_data; int nb_coded_side_data; int format; int64_t bit_rate; @@ -86,8 +165,15 @@ struct AVCodecParameters_61 AVColorSpace color_space; AVChromaLocation chroma_location; int video_delay; - - // Actually, there is more here, but the variables above are the only we need. + AVChannelLayout ch_layout; + int sample_rate; + int block_align; + int frame_size; + int initial_padding; + int trailing_padding; + int seek_preroll; }; +typedef AVCodecParameters_61 AVCodecParameters_62; + } // namespace libffmpeg::internal::avcodec diff --git a/src/lib/AVCodec/wrappers/AVCodecWrapper.cpp b/src/lib/AVCodec/wrappers/AVCodecWrapper.cpp index d0b3ce6..4d0a74a 100644 --- a/src/lib/AVCodec/wrappers/AVCodecWrapper.cpp +++ b/src/lib/AVCodec/wrappers/AVCodecWrapper.cpp @@ -8,8 +8,10 @@ #include +#include #include +#include "AVChannelInternal.h" #include "AVCodecWrapperInternal.h" #include "CastCodecClasses.h" @@ -22,12 +24,17 @@ using libffmpeg::internal::AVMediaType; using libffmpeg::internal::AVPixelFormat; using libffmpeg::internal::AVRational; using libffmpeg::internal::AVSampleFormat; +using libffmpeg::internal::avcodec::AVChannel; +using libffmpeg::internal::avcodec::AVChannelCustom; +using libffmpeg::internal::avcodec::AVChannelLayout; +using libffmpeg::internal::avcodec::AVChannelOrder; using libffmpeg::internal::avcodec::AVCodec_56; using libffmpeg::internal::avcodec::AVCodec_57; using libffmpeg::internal::avcodec::AVCodec_58; using libffmpeg::internal::avcodec::AVCodec_59; using libffmpeg::internal::avcodec::AVCodec_60; using libffmpeg::internal::avcodec::AVCodec_61; +using libffmpeg::internal::avcodec::AVCodec_62; namespace { @@ -140,11 +147,46 @@ std::vector AVCodecWrapper::getSampleFormats() const return convertRawListToVec(formats, AVSampleFormat(-1)); } -std::vector AVCodecWrapper::getChannelLayouts() const +std::vector AVCodecWrapper::getSupportedChannelLayouts() const { - const uint64_t *layouts; - CAST_AVCODEC_GET_MEMBER(AVCodec, this->codec, layouts, channel_layouts); - return convertRawListToVec(layouts, uint64_t(0)); + using internal::avcodec::maskArrayToChannelLayouts; + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 56) + { + const auto p = reinterpret_cast(this->codec); + return maskArrayToChannelLayouts(p->channel_layouts); + } + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 57) + { + const auto p = reinterpret_cast(this->codec); + return maskArrayToChannelLayouts(p->channel_layouts); + } + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 58) + { + const auto p = reinterpret_cast(this->codec); + return maskArrayToChannelLayouts(p->channel_layouts); + } + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 59) + { + const auto p = reinterpret_cast(this->codec); + return maskArrayToChannelLayouts(p->channel_layouts); + } + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 60) + { + const auto p = reinterpret_cast(this->codec); + return avChannelLayoutListToChannelLayouts(p->channel_layouts); + } + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 61) + { + const auto p = reinterpret_cast(this->codec); + return avChannelLayoutListToChannelLayouts(p->channel_layouts); + } + if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 62) + { + const auto p = reinterpret_cast(this->codec); + return avChannelLayoutListToChannelLayouts(p->channel_layouts); + } + + throw std::runtime_error("Invalid library version"); } uint8_t AVCodecWrapper::getMaxLowres() const diff --git a/src/lib/AVCodec/wrappers/AVCodecWrapper.h b/src/lib/AVCodec/wrappers/AVCodecWrapper.h index 05eb341..adeab19 100644 --- a/src/lib/AVCodec/wrappers/AVCodecWrapper.h +++ b/src/lib/AVCodec/wrappers/AVCodecWrapper.h @@ -10,6 +10,8 @@ #include #include +#include "../Channel.h" + #include #include @@ -20,7 +22,7 @@ class AVCodecWrapper { public: AVCodecWrapper() = delete; - AVCodecWrapper(libffmpeg::internal::AVCodec * codec, + AVCodecWrapper(libffmpeg::internal::AVCodec *codec, std::shared_ptr ffmpegLibraries); explicit operator bool() const { return this->codec != nullptr; } @@ -35,11 +37,11 @@ class AVCodecWrapper std::vector getPixelFormats() const; std::vector getSupportedSamplerates() const; std::vector getSampleFormats() const; - std::vector getChannelLayouts() const; + std::vector getSupportedChannelLayouts() const; uint8_t getMaxLowres() const; private: - libffmpeg::internal::AVCodec * codec{}; + libffmpeg::internal::AVCodec *codec{}; std::shared_ptr ffmpegLibraries{}; }; diff --git a/src/lib/AVCodec/wrappers/AVCodecWrapperInternal.h b/src/lib/AVCodec/wrappers/AVCodecWrapperInternal.h index 52503b4..1d581e2 100644 --- a/src/lib/AVCodec/wrappers/AVCodecWrapperInternal.h +++ b/src/lib/AVCodec/wrappers/AVCodecWrapperInternal.h @@ -8,23 +8,25 @@ #include +#include "AVChannelInternal.h" + namespace libffmpeg::internal::avcodec { struct AVCodec_56 { - const char * name; - const char * long_name; + const char *name; + const char *long_name; AVMediaType type; AVCodecID id; int capabilities; - const AVRational * supported_framerates; - const AVPixelFormat * pix_fmts; - const int * supported_samplerates; + const AVRational *supported_framerates; + const AVPixelFormat *pix_fmts; + const int *supported_samplerates; const AVSampleFormat *sample_fmts; - const uint64_t * channel_layouts; + const uint64_t *channel_layouts; uint8_t max_lowres; - const AVClass * priv_class; + const AVClass *priv_class; // Actually, there is more here, but nothing more of the public API }; @@ -34,40 +36,59 @@ typedef AVCodec_56 AVCodec_58; struct AVCodec_59 { - const char * name; - const char * long_name; + const char *name; + const char *long_name; AVMediaType type; AVCodecID id; int capabilities; uint8_t max_lowres; - const AVRational * supported_framerates; - const AVPixelFormat * pix_fmts; - const int * supported_samplerates; + const AVRational *supported_framerates; + const AVPixelFormat *pix_fmts; + const int *supported_samplerates; const AVSampleFormat *sample_fmts; - const uint64_t * channel_layouts; - const AVClass * priv_class; + const uint64_t *channel_layouts; + const AVClass *priv_class; // Actually, there is more here, but nothing more of the public API }; -typedef AVCodec_59 AVCodec_60; +struct AVCodec_60 +{ + const char *name; + const char *long_name; + AVMediaType type; + AVCodecID id; + int capabilities; + uint8_t max_lowres; + const AVRational *supported_framerates; + const AVPixelFormat *pix_fmts; + const int *supported_samplerates; + const AVSampleFormat *sample_fmts; + const uint64_t *deprecated_channel_layouts; // Actually named channel_layouts + const AVClass *priv_class; + const AVProfile *profiles; + const char *wrapper_name; + const AVChannelLayout *channel_layouts; // Actual name ch_layouts +}; struct AVCodec_61 { - const char * name; - const char * long_name; - AVMediaType type; - AVCodecID id; - int capabilities; - uint8_t max_lowres; - const AVRational * supported_framerates; - const AVPixelFormat * pix_fmts; - const int * supported_samplerates; - const AVSampleFormat *sample_fmts; - const AVClass * priv_class; - const AVProfile * profiles; - const char * wrapper_name; - const uint64_t * channel_layouts; + const char *name; + const char *long_name; + AVMediaType type; + AVCodecID id; + int capabilities; + uint8_t max_lowres; + const AVRational *supported_framerates; + const AVPixelFormat *pix_fmts; + const int *supported_samplerates; + const AVSampleFormat *sample_fmts; + const AVClass *priv_class; + const AVProfile *profiles; + const char *wrapper_name; + const AVChannelLayout *channel_layouts; }; +typedef AVCodec_61 AVCodec_62; + } // namespace libffmpeg::internal::avcodec diff --git a/src/lib/AVCodec/wrappers/AVPacketWrapper.cpp b/src/lib/AVCodec/wrappers/AVPacketWrapper.cpp index b578ac6..c3abc37 100644 --- a/src/lib/AVCodec/wrappers/AVPacketWrapper.cpp +++ b/src/lib/AVCodec/wrappers/AVPacketWrapper.cpp @@ -26,6 +26,7 @@ using libffmpeg::internal::avcodec::AVPacket_58; using libffmpeg::internal::avcodec::AVPacket_59; using libffmpeg::internal::avcodec::AVPacket_60; using libffmpeg::internal::avcodec::AVPacket_61; +using libffmpeg::internal::avcodec::AVPacket_62; constexpr auto AV_PKT_FLAG_KEY = 0x0001; ///< The packet contains a keyframe constexpr auto AV_PKT_FLAG_CORRUPT = 0x0002; ///< The packet content is corrupted diff --git a/src/lib/AVCodec/wrappers/AVPacketWrapperInternal.h b/src/lib/AVCodec/wrappers/AVPacketWrapperInternal.h index 21e97e2..55525c0 100644 --- a/src/lib/AVCodec/wrappers/AVPacketWrapperInternal.h +++ b/src/lib/AVCodec/wrappers/AVPacketWrapperInternal.h @@ -71,5 +71,6 @@ struct AVPacket_59 typedef AVPacket_59 AVPacket_60; typedef AVPacket_59 AVPacket_61; +typedef AVPacket_59 AVPacket_62; } // namespace libffmpeg::internal::avcodec diff --git a/src/lib/AVCodec/wrappers/CastCodecClasses.h b/src/lib/AVCodec/wrappers/CastCodecClasses.h index e9ba179..44e726f 100644 --- a/src/lib/AVCodec/wrappers/CastCodecClasses.h +++ b/src/lib/AVCodec/wrappers/CastCodecClasses.h @@ -38,6 +38,11 @@ const auto p = reinterpret_cast(castFrom); \ variableToAssign = p->member; \ } \ + else if (this->ffmpegLibraries->getLibrariesVersion().avcodec.major == 62) \ + { \ + const auto p = reinterpret_cast(castFrom); \ + variableToAssign = p->member; \ + } \ else \ throw std::runtime_error("Invalid library version"); \ } @@ -76,6 +81,11 @@ const auto p = reinterpret_cast(castFrom); \ p->member = variableToSet; \ } \ + else if (this->ffmpegLibraries->getLibrariesVersion().avformat.major == 62) \ + { \ + const auto p = reinterpret_cast(castFrom); \ + p->member = variableToSet; \ + } \ else \ throw std::runtime_error("Invalid library version"); \ } diff --git a/src/lib/AVFormat/wrappers/AVFormatContextWrapper.cpp b/src/lib/AVFormat/wrappers/AVFormatContextWrapper.cpp index 988d583..ba7469b 100644 --- a/src/lib/AVFormat/wrappers/AVFormatContextWrapper.cpp +++ b/src/lib/AVFormat/wrappers/AVFormatContextWrapper.cpp @@ -22,6 +22,7 @@ using libffmpeg::internal::avformat::AVFormatContext_58; using libffmpeg::internal::avformat::AVFormatContext_59; using libffmpeg::internal::avformat::AVFormatContext_60; using libffmpeg::internal::avformat::AVFormatContext_61; +using libffmpeg::internal::avformat::AVFormatContext_62; AVFormatContextWrapper::AVFormatContextWrapper(std::shared_ptr ffmpegLibraries) { diff --git a/src/lib/AVFormat/wrappers/AVFormatContextWrapperInternal.h b/src/lib/AVFormat/wrappers/AVFormatContextWrapperInternal.h index 8aa0d63..3f53a83 100644 --- a/src/lib/AVFormat/wrappers/AVFormatContextWrapperInternal.h +++ b/src/lib/AVFormat/wrappers/AVFormatContextWrapperInternal.h @@ -192,4 +192,6 @@ struct AVFormatContext_61 // Actually, there is more here, but the variables above are the only we need. }; +typedef AVFormatContext_61 AVFormatContext_62; + } // namespace libffmpeg::internal::avformat diff --git a/src/lib/AVFormat/wrappers/AVInputFormatWrapper.cpp b/src/lib/AVFormat/wrappers/AVInputFormatWrapper.cpp index 3b047b6..7eb71ca 100644 --- a/src/lib/AVFormat/wrappers/AVInputFormatWrapper.cpp +++ b/src/lib/AVFormat/wrappers/AVInputFormatWrapper.cpp @@ -26,6 +26,7 @@ using libffmpeg::internal::avformat::AVInputFormat_58; using libffmpeg::internal::avformat::AVInputFormat_59; using libffmpeg::internal::avformat::AVInputFormat_60; using libffmpeg::internal::avformat::AVInputFormat_61; +using libffmpeg::internal::avformat::AVInputFormat_62; } // namespace diff --git a/src/lib/AVFormat/wrappers/AVInputFormatWrapperInternal.h b/src/lib/AVFormat/wrappers/AVInputFormatWrapperInternal.h index 0628053..aa960e7 100644 --- a/src/lib/AVFormat/wrappers/AVInputFormatWrapperInternal.h +++ b/src/lib/AVFormat/wrappers/AVInputFormatWrapperInternal.h @@ -46,5 +46,6 @@ typedef AVInputFormat_56 AVInputFormat_58; typedef AVInputFormat_56 AVInputFormat_59; typedef AVInputFormat_56 AVInputFormat_60; typedef AVInputFormat_56 AVInputFormat_61; +typedef AVInputFormat_56 AVInputFormat_62; } // namespace libffmpeg::internal::avformat diff --git a/src/lib/AVFormat/wrappers/AVStreamWrapper.cpp b/src/lib/AVFormat/wrappers/AVStreamWrapper.cpp index 6d51a12..b83a829 100644 --- a/src/lib/AVFormat/wrappers/AVStreamWrapper.cpp +++ b/src/lib/AVFormat/wrappers/AVStreamWrapper.cpp @@ -29,10 +29,11 @@ using libffmpeg::internal::avformat::AVStream_58; using libffmpeg::internal::avformat::AVStream_59; using libffmpeg::internal::avformat::AVStream_60; using libffmpeg::internal::avformat::AVStream_61; +using libffmpeg::internal::avformat::AVStream_62; } // namespace -AVStreamWrapper::AVStreamWrapper(AVStream * stream, +AVStreamWrapper::AVStreamWrapper(AVStream *stream, std::shared_ptr ffmpegLibraries) : stream(stream), ffmpegLibraries(ffmpegLibraries) { @@ -177,6 +178,10 @@ std::optional AVStreamWrapper::getCodecContext() std::optional AVStreamWrapper::getCodecParameters() const { const auto version = this->ffmpegLibraries->getLibrariesVersion().avformat.major; + if (version == 56) + { + return {}; + } if (version == 57) { const auto p = reinterpret_cast(this->stream); @@ -207,6 +212,12 @@ std::optional AVStreamWrapper::getCodecParame if (p->codecpar != nullptr) return avcodec::AVCodecParametersWrapper(p->codecpar, this->ffmpegLibraries); } + if (version == 62) + { + const auto p = reinterpret_cast(this->stream); + if (p->codecpar != nullptr) + return avcodec::AVCodecParametersWrapper(p->codecpar, this->ffmpegLibraries); + } return {}; } diff --git a/src/lib/AVFormat/wrappers/AVStreamWrapperInternal.h b/src/lib/AVFormat/wrappers/AVStreamWrapperInternal.h index 86fc2eb..bf7fe52 100644 --- a/src/lib/AVFormat/wrappers/AVStreamWrapperInternal.h +++ b/src/lib/AVFormat/wrappers/AVStreamWrapperInternal.h @@ -207,4 +207,26 @@ struct AVStream_60 typedef AVStream_60 AVStream_61; +struct AVStream_62 +{ + const AVClass * av_class{}; + int index{}; + int id{}; + AVCodecParameters * codecpar{}; + void * priv_data{}; + AVRational time_base{}; + int64_t start_time{}; + int64_t duration{}; + int64_t nb_frames{}; + int disposition{}; + AVDiscard discard{}; + AVRational sample_aspect_ratio{}; + AVDictionary * metadata{}; + AVRational avg_frame_rate{}; + avcodec::AVPacket_62 attached_pic{}; + int event_flags{}; + AVRational r_frame_rate{}; + int pts_wrap_bits{}; +}; + } // namespace libffmpeg::internal::avformat diff --git a/src/lib/AVFormat/wrappers/CastFormatClasses.h b/src/lib/AVFormat/wrappers/CastFormatClasses.h index 38dbfbd..e306bdb 100644 --- a/src/lib/AVFormat/wrappers/CastFormatClasses.h +++ b/src/lib/AVFormat/wrappers/CastFormatClasses.h @@ -40,6 +40,11 @@ const auto p = reinterpret_cast(castFrom); \ variableToGetInto = p->member; \ } \ + else if (this->ffmpegLibraries->getLibrariesVersion().avformat.major == 62) \ + { \ + const auto p = reinterpret_cast(castFrom); \ + variableToGetInto = p->member; \ + } \ else \ throw std::runtime_error("Invalid library version"); \ } @@ -78,6 +83,11 @@ const auto p = reinterpret_cast(castFrom); \ p->member = variableToSet; \ } \ + else if (this->ffmpegLibraries->getLibrariesVersion().avformat.major == 62) \ + { \ + const auto p = reinterpret_cast(castFrom); \ + p->member = variableToSet; \ + } \ else \ throw std::runtime_error("Invalid library version"); \ } diff --git a/src/lib/AVUtil/wrappers/AVFrameSideDataWrapperInternal.h b/src/lib/AVUtil/wrappers/AVFrameSideDataWrapperInternal.h index 5387322..fb99ecd 100644 --- a/src/lib/AVUtil/wrappers/AVFrameSideDataWrapperInternal.h +++ b/src/lib/AVUtil/wrappers/AVFrameSideDataWrapperInternal.h @@ -34,5 +34,6 @@ struct AVFrameSideData_57 typedef AVFrameSideData_57 AVFrameSideData_58; typedef AVFrameSideData_57 AVFrameSideData_59; +typedef AVFrameSideData_57 AVFrameSideData_60; } // namespace libffmpeg::internal::avutil diff --git a/src/lib/AVUtil/wrappers/AVFrameWrapper.cpp b/src/lib/AVUtil/wrappers/AVFrameWrapper.cpp index 3c33e7d..720dab1 100644 --- a/src/lib/AVUtil/wrappers/AVFrameWrapper.cpp +++ b/src/lib/AVUtil/wrappers/AVFrameWrapper.cpp @@ -130,9 +130,44 @@ avutil::PictureType AVFrameWrapper::getPictType() const bool AVFrameWrapper::isKeyFrame() const { - int keyframe; - CAST_AVUTIL_GET_MEMBER(AVFrame, this->frame.get(), keyframe, key_frame); - return keyframe == 1; + constexpr auto AV_FRAME_FLAG_KEY = (1 << 1); + + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 60) + { + const auto p = reinterpret_cast(this->frame.get()); + return (p->flags & AV_FRAME_FLAG_KEY) != 0; + } + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 59) + { + const auto p = reinterpret_cast(this->frame.get()); + return p->key_frame == 1 || (p->flags & AV_FRAME_FLAG_KEY) != 0; + } + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 58) + { + const auto p = reinterpret_cast(this->frame.get()); + return p->key_frame == 1 || (p->flags & AV_FRAME_FLAG_KEY) != 0; + } + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 57) + { + const auto p = reinterpret_cast(this->frame.get()); + return p->key_frame == 1; + } + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 56) + { + const auto p = reinterpret_cast(this->frame.get()); + return p->key_frame == 1; + } + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 55) + { + const auto p = reinterpret_cast(this->frame.get()); + return p->key_frame == 1; + } + if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 54) + { + const auto p = reinterpret_cast(this->frame.get()); + return p->key_frame == 1; + } + throw std::runtime_error("Invalid library version"); } std::optional AVFrameWrapper::getMetadata() const diff --git a/src/lib/AVUtil/wrappers/AVFrameWrapperInternal.h b/src/lib/AVUtil/wrappers/AVFrameWrapperInternal.h index ea8a154..a63a8c2 100644 --- a/src/lib/AVUtil/wrappers/AVFrameWrapperInternal.h +++ b/src/lib/AVUtil/wrappers/AVFrameWrapperInternal.h @@ -140,4 +140,38 @@ struct AVFrame_59 // Actually, there is more here, but the variables above are the only we need. }; +struct AVFrame_60 +{ + uint8_t * data[AV_NUM_DATA_POINTERS]; + int linesize[AV_NUM_DATA_POINTERS]; + uint8_t ** extended_data; + int width, height; + int nb_samples; + int format; + AVPictureType pict_type; + AVRational sample_aspect_ratio; + int64_t pts; + int64_t pkt_dts; + AVRational time_base; + int quality; + void * opaque; + int repeat_pict; + int sample_rate; + AVBufferRef * buf[AV_NUM_DATA_POINTERS]; + AVBufferRef ** extended_buf; + int nb_extended_buf; + AVFrameSideData ** side_data; + int nb_side_data; + int flags; + AVColorRange color_range; + AVColorPrimaries color_primaries; + AVColorTransferCharacteristic color_trc; + AVColorSpace colorspace; + AVChromaLocation chroma_location; + int64_t best_effort_timestamp; + AVDictionary * metadata; + + // Actually, there is more here, but the variables above are the only we need. +}; + } // namespace libffmpeg::internal::avutil diff --git a/src/lib/AVUtil/wrappers/AVMotionVectorConversion.cpp b/src/lib/AVUtil/wrappers/AVMotionVectorConversion.cpp index 034c0af..038f350 100644 --- a/src/lib/AVUtil/wrappers/AVMotionVectorConversion.cpp +++ b/src/lib/AVUtil/wrappers/AVMotionVectorConversion.cpp @@ -14,7 +14,7 @@ namespace libffmpeg::avutil { using internal::avutil::AVMotionVector_54; -using internal::avutil::AVMotionVector_55_56_57_58_59; +using internal::avutil::AVMotionVector_55_56_57_58_59_60; std::vector parseMotionData(const LibraryVersions &libraryVersions, const uint8_t *data, const size_t dataSize) @@ -45,13 +45,14 @@ parseMotionData(const LibraryVersions &libraryVersions, const uint8_t *data, con libraryVersions.avutil.major == 56 || // libraryVersions.avutil.major == 57 || // libraryVersions.avutil.major == 58 || // - libraryVersions.avutil.major == 59) + libraryVersions.avutil.major == 59 || // + libraryVersions.avutil.major == 60) { - const auto nrMotionVectors = dataSize / sizeof(AVMotionVector_55_56_57_58_59); + const auto nrMotionVectors = dataSize / sizeof(AVMotionVector_55_56_57_58_59_60); for (size_t index = 0; index < nrMotionVectors; ++index) { - const auto byteOffset = sizeof(AVMotionVector_55_56_57_58_59) * index; - const auto p = reinterpret_cast(data + byteOffset); + const auto byteOffset = sizeof(AVMotionVector_55_56_57_58_59_60) * index; + const auto p = reinterpret_cast(data + byteOffset); MotionVector motionVector; motionVector.source = p->source; diff --git a/src/lib/AVUtil/wrappers/AVMotionVectorConversionInternal.h b/src/lib/AVUtil/wrappers/AVMotionVectorConversionInternal.h index bfdce63..04a9ba4 100644 --- a/src/lib/AVUtil/wrappers/AVMotionVectorConversionInternal.h +++ b/src/lib/AVUtil/wrappers/AVMotionVectorConversionInternal.h @@ -25,7 +25,7 @@ struct AVMotionVector_54 uint64_t flags; }; -struct AVMotionVector_55_56_57_58_59 +struct AVMotionVector_55_56_57_58_59_60 { int32_t source; uint8_t w, h; diff --git a/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversion.cpp b/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversion.cpp index 98aa205..035f224 100644 --- a/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversion.cpp +++ b/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversion.cpp @@ -120,7 +120,7 @@ convertAVPixFmtDescriptor(const internal::AVPixelFormat avPixelFormat format.componentDescriptors.push_back(descriptor); } } - else if (version == 57 || version == 58 || version == 59) + else if (version == 57 || version == 58 || version == 59 || version == 60) { auto p = reinterpret_cast(descriptor); format.name = std::string(p->name); diff --git a/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversionInternal.h b/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversionInternal.h index deae6a1..2e44d5a 100644 --- a/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversionInternal.h +++ b/src/lib/AVUtil/wrappers/AVPixFmtDescriptorConversionInternal.h @@ -82,5 +82,6 @@ struct AVPixFmtDescriptor_57 typedef AVPixFmtDescriptor_57 AVPixFmtDescriptor_58; typedef AVPixFmtDescriptor_57 AVPixFmtDescriptor_59; +typedef AVPixFmtDescriptor_57 AVPixFmtDescriptor_60; } // namespace libffmpeg::internal::avutil diff --git a/src/lib/AVUtil/wrappers/CastUtilClasses.h b/src/lib/AVUtil/wrappers/CastUtilClasses.h index 861d50e..57380a9 100644 --- a/src/lib/AVUtil/wrappers/CastUtilClasses.h +++ b/src/lib/AVUtil/wrappers/CastUtilClasses.h @@ -38,6 +38,11 @@ const auto p = reinterpret_cast(castFrom); \ variableToAssign = p->member; \ } \ + else if (this->ffmpegLibraries->getLibrariesVersion().avutil.major == 60) \ + { \ + const auto p = reinterpret_cast(castFrom); \ + variableToAssign = p->member; \ + } \ else \ throw std::runtime_error("Invalid library version"); \ } diff --git a/src/lib/common/Version.h b/src/lib/common/Version.h index e0dfd2f..8c40b99 100644 --- a/src/lib/common/Version.h +++ b/src/lib/common/Version.h @@ -39,7 +39,8 @@ enum class FFmpegVersion FFmpeg_4x, FFmpeg_5x, FFmpeg_6x, - FFmpeg_7x + FFmpeg_7x, + FFmpeg_8x }; const EnumMapper @@ -48,7 +49,8 @@ const EnumMapper {FFmpegVersion::FFmpeg_4x, "4.x", "FFmpeg 4.x"}, {FFmpegVersion::FFmpeg_5x, "5.x", "FFmpeg 5.x"}, {FFmpegVersion::FFmpeg_6x, "6.x", "FFmpeg 6.x"}, - {FFmpegVersion::FFmpeg_7x, "7.x", "FFmpeg 7.x"}}); + {FFmpegVersion::FFmpeg_7x, "7.x", "FFmpeg 7.x"}, + {FFmpegVersion::FFmpeg_8x, "8.x", "FFmpeg 8.x"}}); struct LibraryVersions { @@ -66,7 +68,12 @@ using VersionSwresample = Version; // These FFmpeg versions are supported. The numbers indicate the major versions. // The versions are sorted from newest to oldest, so that we try to open the newest ones first. -constexpr auto SupportedFFmpegVersions = {LibraryVersions({FFmpegVersion::FFmpeg_7x, +constexpr auto SupportedFFmpegVersions = {LibraryVersions({FFmpegVersion::FFmpeg_8x, + VersionAVFormat(62), + VersionAVCodec(62), + VersionAVUtil(60), + VersionSwresample(6)}), + LibraryVersions({FFmpegVersion::FFmpeg_7x, VersionAVFormat(61), VersionAVCodec(61), VersionAVUtil(59), diff --git a/test/integration/DemuxingTest.cpp b/test/integration/DemuxingTest.cpp index 9f6cb1f..27120da 100644 --- a/test/integration/DemuxingTest.cpp +++ b/test/integration/DemuxingTest.cpp @@ -19,7 +19,9 @@ namespace libffmpeg::test::integration using libffmpeg::avutil::ColorSpace; using libffmpeg::avutil::MediaType; +using ::testing::AnyOf; using ::testing::Contains; +using ::testing::ElementsAre; TEST(Demuxing, OpenTestFileAndCheckFormat_ShouldHaveCorrectFormat) { @@ -77,13 +79,29 @@ TEST(Demuxing, OpenTestFileAndCheckFormat_ShouldHaveCorrectFormat) EXPECT_EQ(audioCodecDescriptor->codecName, "aac"); EXPECT_EQ(audioCodecDescriptor->longName, "AAC (Advanced Audio Coding)"); avcodec::CodecDescriptorProperties expectedAudioProperties{}; - if (majorVersion >= 58) - // Older (< ffmpeg 4) versions will report this flag as false + if (majorVersion >= 58 && majorVersion < 62) + // Older (< ffmpeg 4) versions and newer versions (>= 8) will report this flag as false expectedAudioProperties.intraOnly = true; expectedAudioProperties.lossy = true; EXPECT_EQ(audioCodecDescriptor->properties, expectedAudioProperties); EXPECT_EQ(audioCodecDescriptor->mimeTypes.size(), 0); + const auto audioCodecParameters = audioStream.getCodecParameters(); + if (majorVersion <= 56) + EXPECT_FALSE(audioCodecParameters); + else + { + EXPECT_EQ(audioCodecParameters->getCodecType(), MediaType::Audio); + EXPECT_EQ(audioCodecParameters->getExtradata().size(), 5); + EXPECT_EQ(audioCodecParameters->getSize(), Size({0, 0})); + EXPECT_EQ(audioCodecParameters->getColorspace(), ColorSpace::UNSPECIFIED); + EXPECT_THAT(audioCodecParameters->getPixelFormat().name, testing::AnyOf("None", "gray")); + EXPECT_EQ(audioCodecParameters->getSampleAspectRatio(), Rational({0, 1})); + EXPECT_THAT(audioCodecParameters->getChannelLayout(), + ElementsAre(avcodec::ChannelInfo({avcodec::Channel::FrontLeft, {}, "FL"}), + avcodec::ChannelInfo({avcodec::Channel::FrontRight, {}, "FR"}))); + } + if (majorVersion == 56) // FFmpeg versions 2 does not parse profiles in the descriptor EXPECT_EQ(audioCodecDescriptor->profiles.size(), 0); @@ -91,9 +109,13 @@ TEST(Demuxing, OpenTestFileAndCheckFormat_ShouldHaveCorrectFormat) // For some reason, the "LC" profile is reported twice for FFmpeg 3 EXPECT_TRUE(areEqual(audioCodecDescriptor->profiles, {"LC", "HE-AAC", "HE-AACv2", "LD", "ELD", "Main", "LC", "SSR", "LTP"})); - else + else if (majorVersion < 62) EXPECT_TRUE(areEqual(audioCodecDescriptor->profiles, {"LC", "HE-AAC", "HE-AACv2", "LD", "ELD", "Main", "SSR", "LTP"})); + else + EXPECT_TRUE( + areEqual(audioCodecDescriptor->profiles, + {"LC", "HE-AAC", "HE-AACv2", "LD", "ELD", "Main", "SSR", "LTP", "xHE-AAC"})); EXPECT_EQ(audioStream.getAverageFrameRate(), Rational({24, 1})); EXPECT_EQ(audioStream.getTimeBase(), Rational({1, 44100})); diff --git a/test/unit/wrappers/AVCodec/AVCodecParametersWrapperTest.cpp b/test/unit/wrappers/AVCodec/AVCodecParametersWrapperTest.cpp index c953966..a76c41c 100644 --- a/test/unit/wrappers/AVCodec/AVCodecParametersWrapperTest.cpp +++ b/test/unit/wrappers/AVCodec/AVCodecParametersWrapperTest.cpp @@ -11,7 +11,9 @@ #include +#include "TestDefinitions.h" #include "VersionToAVCodecTypes.h" +#include "common/Version.h" #include @@ -28,8 +30,8 @@ using libffmpeg::internal::AVCodecParameters; using libffmpeg::internal::AVCOL_SPC_SMPTE240M; using libffmpeg::internal::AVMEDIA_TYPE_AUDIO; using libffmpeg::internal::AVPixelFormat; -using libffmpeg::internal::AVPixFmtDescriptor; using libffmpeg::internal::AVRational; +using ::testing::ElementsAreArray; using ::testing::Return; void runAVCodecParametersWrapperTestAVFormat56(const LibraryVersions &version) @@ -77,6 +79,10 @@ template void runAVCodecParametersWrapperTest() codecParameters.color_space = AVCOL_SPC_SMPTE240M; codecParameters.format = TEST_PIXEL_FORMAT; codecParameters.sample_aspect_ratio = AVRational({23, 88}); + if constexpr (V == FFmpegVersion::FFmpeg_3x || V == FFmpegVersion::FFmpeg_4x) + codecParameters.channel_layout = TEST_CHANNEL_LAYOUT_5POINT1; + if constexpr (V >= FFmpegVersion::FFmpeg_5x) + codecParameters.ch_layout = TEST_AVCHANNEL_LAYOUT_5POINT1; AVCodecParametersWrapper parameters(reinterpret_cast(&codecParameters), ffmpegLibraries); @@ -88,6 +94,7 @@ template void runAVCodecParametersWrapperTest() EXPECT_EQ(parameters.getColorspace(), avutil::ColorSpace::SMPTE240M); EXPECT_EQ(parameters.getPixelFormat().name, "None"); EXPECT_EQ(parameters.getSampleAspectRatio(), Rational({23, 88})); + EXPECT_THAT(parameters.getChannelLayout(), ElementsAreArray(TEST_CHANNELINFO_5POINT1)); EXPECT_EQ(ffmpegLibraries->functionCounters.avPixFmtDescGet, 1); } diff --git a/test/unit/wrappers/AVCodec/AVCodecWrapperTest.cpp b/test/unit/wrappers/AVCodec/AVCodecWrapperTest.cpp index fed0912..ae05d41 100644 --- a/test/unit/wrappers/AVCodec/AVCodecWrapperTest.cpp +++ b/test/unit/wrappers/AVCodec/AVCodecWrapperTest.cpp @@ -12,6 +12,8 @@ #include #include +#include "TestDefinitions.h" + #include #include @@ -25,6 +27,7 @@ namespace using libffmpeg::internal::AVCodec; using libffmpeg::internal::AVPixelFormat; using libffmpeg::internal::AVRational; +using ::testing::ElementsAre; using ::testing::Return; template void runAVCodecWrapperTest() @@ -43,6 +46,10 @@ template void runAVCodecWrapperTest() rawCodec.type = libffmpeg::internal::AVMEDIA_TYPE_SUBTITLE; rawCodec.id = TEST_CODEC_ID; rawCodec.capabilities = TEST_CAPABILITIES; + if constexpr (V <= FFmpegVersion::FFmpeg_5x) + rawCodec.channel_layouts = TEST_CHANNEL_FORMATS; + else + rawCodec.channel_layouts = TEST_AVCHANNEL_LAYOUTS; std::array rawFrameRates = { AVRational({30, 1}), AVRational({30, 1001}), AVRational({77, 999}), AVRational({0, 0})}; @@ -71,6 +78,10 @@ template void runAVCodecWrapperTest() std::vector(rawPixelFormats.begin(), rawPixelFormats.end() - 1)); EXPECT_EQ(codec.getSupportedSamplerates(), std::vector(rawSupportedSampleRates.begin(), rawSupportedSampleRates.end() - 1)); + + EXPECT_THAT( + codec.getSupportedChannelLayouts(), + ElementsAre(TEST_CHANNELINFO_STEREO, TEST_CHANNELINFO_5POINT1, TEST_CHANNELINFO_7POINT1)); } } // namespace diff --git a/test/unit/wrappers/AVCodec/TestDefinitions.h b/test/unit/wrappers/AVCodec/TestDefinitions.h new file mode 100644 index 0000000..34ea763 --- /dev/null +++ b/test/unit/wrappers/AVCodec/TestDefinitions.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2023 Christian Feldmann [christian.feldmann@gmx.de]. + * All rights reserved. + * This work is licensed under the terms of the MIT license. + * For a copy, see . + */ + +#pragma once + +#include + +namespace libffmpeg::avcodec +{ + +constexpr uint64_t TEST_CHANNEL_LAYOUT_STEREO = 0b11; +constexpr uint64_t TEST_CHANNEL_LAYOUT_5POINT1 = 0b11000001111; +constexpr uint64_t TEST_CHANNEL_LAYOUT_7POINT1 = 0b11000111111; +constexpr uint64_t TEST_CHANNEL_LAYOUT_TERMINATION = 0; +constexpr uint64_t TEST_CHANNEL_FORMATS[4] = {TEST_CHANNEL_LAYOUT_STEREO, + TEST_CHANNEL_LAYOUT_5POINT1, + TEST_CHANNEL_LAYOUT_7POINT1, + TEST_CHANNEL_LAYOUT_TERMINATION}; + +using internal::avcodec::AVChannelLayout; +using internal::avcodec::AVChannelOrder; +constexpr AVChannelLayout TEST_AVCHANNEL_LAYOUT_STEREO(AVChannelOrder::AV_CHANNEL_ORDER_NATIVE, + 2, + {TEST_CHANNEL_LAYOUT_STEREO}); +constexpr AVChannelLayout TEST_AVCHANNEL_LAYOUT_5POINT1(AVChannelOrder::AV_CHANNEL_ORDER_NATIVE, + 2, + {TEST_CHANNEL_LAYOUT_5POINT1}); +constexpr AVChannelLayout TEST_AVCHANNEL_LAYOUT_7POINT1(AVChannelOrder::AV_CHANNEL_ORDER_NATIVE, + 2, + {TEST_CHANNEL_LAYOUT_7POINT1}); +constexpr AVChannelLayout + TEST_AVCHANNEL_LAYOUT_TERMINATION(AVChannelOrder::AV_CHANNEL_ORDER_UNSPEC, 0, {0}); +constexpr AVChannelLayout TEST_AVCHANNEL_LAYOUTS[4] = {TEST_AVCHANNEL_LAYOUT_STEREO, + TEST_AVCHANNEL_LAYOUT_5POINT1, + TEST_AVCHANNEL_LAYOUT_7POINT1, + TEST_AVCHANNEL_LAYOUT_TERMINATION}; + +const std::initializer_list TEST_CHANNELINFO_STEREO = { + {Channel::FrontLeft, {}, "FL"}, {Channel::FrontRight, {}, "FR"}}; + +const std::initializer_list TEST_CHANNELINFO_5POINT1 = { + {Channel::FrontLeft, {}, "FL"}, + {Channel::FrontRight, {}, "FR"}, + {Channel::FrontCenter, {}, "FC"}, + {Channel::LowFrequency, {}, "LFE"}, + {Channel::SideLeft, {}, "SL"}, + {Channel::SideRight, {}, "SR"}}; + +const std::initializer_list TEST_CHANNELINFO_7POINT1 = { + {Channel::FrontLeft, {}, "FL"}, + {Channel::FrontRight, {}, "FR"}, + {Channel::FrontCenter, {}, "FC"}, + {Channel::LowFrequency, {}, "LFE"}, + {Channel::BackLeft, {}, "BL"}, + {Channel::BackRight, {}, "BR"}, + {Channel::SideLeft, {}, "SL"}, + {Channel::SideRight, {}, "SR"}}; + +} // namespace libffmpeg::avcodec diff --git a/test/unit/wrappers/AVCodec/VersionToAVCodecTypes.h b/test/unit/wrappers/AVCodec/VersionToAVCodecTypes.h index 66a39f8..521db9b 100644 --- a/test/unit/wrappers/AVCodec/VersionToAVCodecTypes.h +++ b/test/unit/wrappers/AVCodec/VersionToAVCodecTypes.h @@ -33,6 +33,10 @@ namespace return TypeWrapper{}; \ if constexpr (V == FFmpegVersion::FFmpeg_7x) \ return TypeWrapper{}; \ + if constexpr (V == FFmpegVersion::FFmpeg_8x) \ + return TypeWrapper{}; \ + else \ + throw std::runtime_error("Invalid FFmpeg version"); \ } } // namespace diff --git a/test/unit/wrappers/AVFormat/VersionToAVFormatTypes.h b/test/unit/wrappers/AVFormat/VersionToAVFormatTypes.h index 07782d1..7fd6d34 100644 --- a/test/unit/wrappers/AVFormat/VersionToAVFormatTypes.h +++ b/test/unit/wrappers/AVFormat/VersionToAVFormatTypes.h @@ -29,6 +29,12 @@ namespace return TypeWrapper{}; \ if constexpr (V == FFmpegVersion::FFmpeg_6x) \ return TypeWrapper{}; \ + if constexpr (V == FFmpegVersion::FFmpeg_7x) \ + return TypeWrapper{}; \ + if constexpr (V == FFmpegVersion::FFmpeg_8x) \ + return TypeWrapper{}; \ + else \ + throw std::runtime_error("Invalid FFmpeg version"); \ } } // namespace diff --git a/test/unit/wrappers/AVUtil/AVFrameSideDataWrapperTest.cpp b/test/unit/wrappers/AVUtil/AVFrameSideDataWrapperTest.cpp index 035f9ff..ecf032a 100644 --- a/test/unit/wrappers/AVUtil/AVFrameSideDataWrapperTest.cpp +++ b/test/unit/wrappers/AVUtil/AVFrameSideDataWrapperTest.cpp @@ -24,14 +24,14 @@ using libffmpeg::internal::AV_FRAME_DATA_DOWNMIX_INFO; using libffmpeg::internal::AV_FRAME_DATA_MOTION_VECTORS; using libffmpeg::internal::AVFrameSideData; using internal::avutil::AVMotionVector_54; -using internal::avutil::AVMotionVector_55_56_57_58_59; +using internal::avutil::AVMotionVector_55_56_57_58_59_60; using ::testing::Return; template std::array createDummyMotionData() { static_assert(std::is_same_v || - std::is_same_v); + std::is_same_v); std::array array; for (int i = 0; i < 5; ++i) @@ -44,7 +44,7 @@ template std::array createDummy array[i].dst_x = i * 6; array[i].dst_y = i * 7; array[i].flags = i * 8; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { array[i].motion_x = i * 9; array[i].motion_y = i * 10; diff --git a/test/unit/wrappers/AVUtil/AVFrameWrapperTest.cpp b/test/unit/wrappers/AVUtil/AVFrameWrapperTest.cpp index 23bd63e..e63e4cf 100644 --- a/test/unit/wrappers/AVUtil/AVFrameWrapperTest.cpp +++ b/test/unit/wrappers/AVUtil/AVFrameWrapperTest.cpp @@ -33,14 +33,16 @@ template void runAVFrameWrapperTest() ffmpegLibraries->functionChecks.avutilPixFmtDescGetExpectedFormat = TEST_PIXEL_FORMAT; int frameAllocCounter = 0; - ffmpegLibraries->avutil.av_frame_alloc = [&frameAllocCounter]() { + ffmpegLibraries->avutil.av_frame_alloc = [&frameAllocCounter]() + { auto frame = new AVFrameType; frameAllocCounter++; return reinterpret_cast(frame); }; int frameFreeCounter = 0; - ffmpegLibraries->avutil.av_frame_free = [&frameFreeCounter](AVFrame **frame) { + ffmpegLibraries->avutil.av_frame_free = [&frameFreeCounter](AVFrame **frame) + { if (frame != nullptr && *frame != nullptr) { auto castFrame = reinterpret_cast *>(*frame); @@ -56,15 +58,18 @@ template void runAVFrameWrapperTest() EXPECT_EQ(frameFreeCounter, 0); { - auto castFrame = reinterpret_cast *>(frame.getFrame()); - castFrame->width = 320; - castFrame->height = 160; - castFrame->linesize[0] = 123; - castFrame->linesize[1] = 223; - castFrame->linesize[2] = 323; - castFrame->pts = 1000; - castFrame->pict_type = internal::AV_PICTURE_TYPE_P; - castFrame->key_frame = 1; + auto castFrame = reinterpret_cast *>(frame.getFrame()); + castFrame->width = 320; + castFrame->height = 160; + castFrame->linesize[0] = 123; + castFrame->linesize[1] = 223; + castFrame->linesize[2] = 323; + castFrame->pts = 1000; + castFrame->pict_type = internal::AV_PICTURE_TYPE_P; + if constexpr (V < FFmpegVersion::FFmpeg_8x) + castFrame->key_frame = 1; + if constexpr (V >= FFmpegVersion::FFmpeg_6x) + castFrame->flags = (1 << 1); // AV_FRAME_FLAG_KEY castFrame->sample_aspect_ratio = {16, 9}; castFrame->format = TEST_PIXEL_FORMAT; } diff --git a/test/unit/wrappers/AVUtil/VersionToAVUtilTypes.h b/test/unit/wrappers/AVUtil/VersionToAVUtilTypes.h index f3d5291..9f55ddc 100644 --- a/test/unit/wrappers/AVUtil/VersionToAVUtilTypes.h +++ b/test/unit/wrappers/AVUtil/VersionToAVUtilTypes.h @@ -31,6 +31,12 @@ namespace return TypeWrapper{}; \ if constexpr (V == FFmpegVersion::FFmpeg_6x) \ return TypeWrapper{}; \ + if constexpr (V == FFmpegVersion::FFmpeg_7x) \ + return TypeWrapper{}; \ + if constexpr (V == FFmpegVersion::FFmpeg_8x) \ + return TypeWrapper{}; \ + else \ + throw std::runtime_error("Invalid FFmpeg version"); \ } } // namespace @@ -48,8 +54,10 @@ template constexpr auto avMotionVectorTypeFromVersionFunc() if constexpr (V == FFmpegVersion::FFmpeg_2x) return TypeWrapper{}; if constexpr (V == FFmpegVersion::FFmpeg_3x || V == FFmpegVersion::FFmpeg_4x || - V == FFmpegVersion::FFmpeg_5x || V == FFmpegVersion::FFmpeg_6x) - return TypeWrapper{}; + V == FFmpegVersion::FFmpeg_5x || V == FFmpegVersion::FFmpeg_6x || + V == FFmpegVersion::FFmpeg_7x || V == FFmpegVersion::FFmpeg_8x) + return TypeWrapper{}; + throw std::runtime_error("Invalid FFmpeg version"); } template diff --git a/test/unit/wrappers/RunTestForAllVersions.h b/test/unit/wrappers/RunTestForAllVersions.h index 9d98eb5..5549fb4 100644 --- a/test/unit/wrappers/RunTestForAllVersions.h +++ b/test/unit/wrappers/RunTestForAllVersions.h @@ -13,16 +13,22 @@ namespace libffmpeg #define RUN_TEST_FOR_VERSION(version, testFunctionName) \ { \ - if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_2x) \ - testFunctionName(); \ - else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_3x) \ - testFunctionName(); \ - else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_4x) \ - testFunctionName(); \ - else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_5x) \ - testFunctionName(); \ - else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_6x) \ - testFunctionName(); \ + if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_2x) \ + testFunctionName(); \ + else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_3x) \ + testFunctionName(); \ + else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_4x) \ + testFunctionName(); \ + else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_5x) \ + testFunctionName(); \ + else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_6x) \ + testFunctionName(); \ + else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_7x) \ + testFunctionName(); \ + else if (version.ffmpegVersion == libffmpeg::FFmpegVersion::FFmpeg_8x) \ + testFunctionName(); \ + else \ + throw std::runtime_error("Invalid FFmpeg version"); \ } template struct TypeWrapper