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