Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * This program is free software: you can redistribute it and/or modify 5 : * it under the terms of the GNU General Public License as published by 6 : * the Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This program is distributed in the hope that it will be useful, 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 : * GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License 15 : * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 : */ 17 : 18 : #include <cppunit/TestAssert.h> 19 : #include <cppunit/TestFixture.h> 20 : #include <cppunit/extensions/HelperMacros.h> 21 : 22 : #include "jami.h" 23 : #include "fileutils.h" 24 : #include "media/libav_deps.h" 25 : #include "media/media_buffer.h" 26 : #include "media/media_decoder.h" 27 : #include "media/media_device.h" 28 : #include "media/media_io_handle.h" 29 : 30 : #include "../../test_runner.h" 31 : 32 : namespace jami { namespace test { 33 : 34 : class MediaDecoderTest : public CppUnit::TestFixture { 35 : public: 36 2 : static std::string name() { return "media_decoder"; } 37 : 38 : void setUp(); 39 : void tearDown(); 40 : 41 : private: 42 : void testAudioFile(); 43 : 44 2 : CPPUNIT_TEST_SUITE(MediaDecoderTest); 45 1 : CPPUNIT_TEST(testAudioFile); 46 4 : CPPUNIT_TEST_SUITE_END(); 47 : 48 : void writeWav(); // writes a minimal wav file to test decoding 49 : 50 : std::unique_ptr<MediaDecoder> decoder_; 51 : std::string filename_ = "test.wav"; 52 : }; 53 : 54 : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MediaDecoderTest, MediaDecoderTest::name()); 55 : 56 : void 57 1 : MediaDecoderTest::setUp() 58 : { 59 1 : libjami::init(libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG)); 60 1 : libav_utils::av_init(); 61 1 : } 62 : 63 : void 64 1 : MediaDecoderTest::tearDown() 65 : { 66 1 : dhtnet::fileutils::remove(filename_); 67 1 : libjami::fini(); 68 1 : } 69 : 70 : void 71 1 : MediaDecoderTest::testAudioFile() 72 : { 73 1 : if (!avcodec_find_decoder(AV_CODEC_ID_PCM_S16LE) 74 1 : || !avcodec_find_decoder(AV_CODEC_ID_PCM_S16BE)) 75 0 : return; // no way to test the wav file, since it is in pcm signed 16 76 : 77 1 : writeWav(); 78 : 79 2 : decoder_.reset(new MediaDecoder([this](const std::shared_ptr<MediaFrame>&& f) mutable { 80 4 : CPPUNIT_ASSERT(f->pointer()->sample_rate == decoder_->getStream().sampleRate); 81 4 : CPPUNIT_ASSERT(f->pointer()->ch_layout.nb_channels == decoder_->getStream().nbChannels); 82 5 : })); 83 1 : DeviceParams dev; 84 1 : dev.input = filename_; 85 1 : CPPUNIT_ASSERT(decoder_->openInput(dev) >= 0); 86 1 : CPPUNIT_ASSERT(decoder_->setupAudio() >= 0); 87 : 88 1 : bool done = false; 89 6 : while (!done) { 90 5 : switch (decoder_->decode()) { 91 0 : case MediaDemuxer::Status::ReadError: 92 0 : CPPUNIT_ASSERT_MESSAGE("Decode error", false); 93 0 : done = true; 94 0 : break; 95 1 : case MediaDemuxer::Status::EndOfFile: 96 1 : done = true; 97 1 : break; 98 4 : case MediaDemuxer::Status::Success: 99 : default: 100 4 : break; 101 : } 102 : } 103 1 : CPPUNIT_ASSERT(done); 104 1 : } 105 : 106 : // write bytes to file using native endianness 107 : template<typename Word> 108 8201 : static std::ostream& write(std::ostream& os, Word value, unsigned size) 109 : { 110 24613 : for (; size; --size, value >>= 8) 111 16412 : os.put(static_cast<char>(value & 0xFF)); 112 8201 : return os; 113 : } 114 : 115 : void 116 1 : MediaDecoderTest::writeWav() 117 : { 118 1 : auto f = std::ofstream(filename_, std::ios::binary); 119 1 : f << "RIFF----WAVEfmt "; 120 1 : write(f, 16, 4); // no extension data 121 1 : write(f, 1, 2); // PCM integer samples 122 1 : write(f, 1, 2); // channels 123 1 : write(f, 8000, 4); // sample rate 124 1 : write(f, 8000 * 1 * 2, 4); // sample rate * channels * bytes per sample 125 1 : write(f, 4, 2); // data block size 126 1 : write(f, 2 * 8, 2); // bits per sample 127 1 : size_t dataChunk = f.tellp(); 128 1 : f << "data----"; 129 : 130 : // fill file with silence 131 : // make sure there is more than 1 AVFrame in the file 132 8193 : for (int i = 0; i < 8192; ++i) 133 8192 : write(f, 0, 2); 134 : 135 1 : size_t length = f.tellp(); 136 1 : f.seekp(dataChunk + 4); 137 1 : write(f, length - dataChunk + 8, 4); 138 1 : f.seekp(4); 139 1 : write(f, length - 8, 4); 140 1 : } 141 : 142 : }} // namespace jami::test 143 : 144 1 : RING_TEST_RUNNER(jami::test::MediaDecoderTest::name());