LCOV - code coverage report
Current view: top level - test/unitTest/media - test_media_encoder.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 89 98 90.8 %
Date: 2024-12-21 08:56:24 Functions: 10 10 100.0 %

          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_encoder.h"
      26             : #include "media/media_io_handle.h"
      27             : #include "media/system_codec_container.h"
      28             : 
      29             : #include "../../test_runner.h"
      30             : 
      31             : namespace jami { namespace test {
      32             : 
      33             : class MediaEncoderTest : public CppUnit::TestFixture {
      34             : public:
      35           2 :     static std::string name() { return "media_encoder"; }
      36             : 
      37             :     void setUp();
      38             :     void tearDown();
      39             : 
      40             : private:
      41             :     void testMultiStream();
      42             : 
      43           2 :     CPPUNIT_TEST_SUITE(MediaEncoderTest);
      44           1 :     CPPUNIT_TEST(testMultiStream);
      45           4 :     CPPUNIT_TEST_SUITE_END();
      46             : 
      47             :     std::unique_ptr<MediaEncoder> encoder_;
      48             :     std::vector<std::string> files_;
      49             : };
      50             : 
      51             : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MediaEncoderTest, MediaEncoderTest::name());
      52             : 
      53             : void
      54           1 : MediaEncoderTest::setUp()
      55             : {
      56           1 :     libjami::init(libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
      57           1 :     libav_utils::av_init();
      58           1 :     encoder_.reset(new MediaEncoder);
      59           1 :     files_.push_back("test.mkv");
      60           1 : }
      61             : 
      62             : void
      63           1 : MediaEncoderTest::tearDown()
      64             : {
      65             :     // clean up behind ourselves
      66           2 :     for (const auto& file : files_)
      67           1 :         dhtnet::fileutils::remove(file);
      68           1 :     libjami::fini();
      69           1 : }
      70             : 
      71             : static AVFrame*
      72          25 : getVideoFrame(int width, int height, int frame_index)
      73             : {
      74             :     int x, y;
      75          25 :     AVFrame* frame = av_frame_alloc();
      76          25 :     if (!frame)
      77           0 :         return nullptr;
      78             : 
      79          25 :     frame->format = AV_PIX_FMT_YUV420P;
      80          25 :     frame->width = width;
      81          25 :     frame->height = height;
      82             : 
      83          25 :     if (av_frame_get_buffer(frame, 32) < 0) {
      84           0 :         av_frame_free(&frame);
      85           0 :         return nullptr;
      86             :     }
      87             : 
      88             :     /* Y */
      89        6025 :     for (y = 0; y < height; y++)
      90     1926000 :         for (x = 0; x < width; x++)
      91     1920000 :             frame->data[0][y * frame->linesize[0] + x] = x + y + frame_index * 3;
      92             : 
      93             :     /* Cb and Cr */
      94        3025 :     for (y = 0; y < height / 2; y++) {
      95      483000 :         for (x = 0; x < width / 2; x++) {
      96      480000 :             frame->data[1][y * frame->linesize[1] + x] = 128 + y + frame_index * 2;
      97      480000 :             frame->data[2][y * frame->linesize[2] + x] = 64 + x + frame_index * 5;
      98             :         }
      99             :     }
     100             : 
     101          25 :     return frame;
     102             : }
     103             : 
     104             : static AVFrame*
     105          25 : getAudioFrame(int sampleRate, int nbSamples, int nbChannels)
     106             : {
     107          25 :     const constexpr float pi = 3.14159265358979323846264338327950288; // M_PI
     108          25 :     const float tincr = 2 * pi * 440.0 / sampleRate;
     109          25 :     float t = 0;
     110          25 :     AVFrame* frame = av_frame_alloc();
     111          25 :     if (!frame)
     112           0 :         return nullptr;
     113             : 
     114          25 :     frame->format = AV_SAMPLE_FMT_S16;
     115          25 :     av_channel_layout_default(&frame->ch_layout, nbChannels);
     116          25 :     frame->nb_samples = nbSamples;
     117          25 :     frame->sample_rate = sampleRate;
     118             : 
     119          25 :     if (av_frame_get_buffer(frame, 0) < 0) {
     120           0 :         av_frame_free(&frame);
     121           0 :         return nullptr;
     122             :     }
     123             : 
     124          25 :     auto samples = reinterpret_cast<uint16_t*>(frame->data[0]);
     125        5025 :     for (int i = 0; i < 200; ++i) {
     126     4805000 :         for (int j = 0; j < nbSamples; ++j) {
     127     4800000 :             samples[2 * j] = static_cast<int>(sin(t) * 10000);
     128     9600000 :             for (int k = 1; k < nbChannels; ++k) {
     129     4800000 :                 samples[2 * j + k] = samples[2 * j];
     130             :             }
     131     4800000 :             t += tincr;
     132             :         }
     133             :     }
     134             : 
     135          25 :     return frame;
     136             : }
     137             : 
     138             : void
     139           1 : MediaEncoderTest::testMultiStream()
     140             : {
     141           1 :     const constexpr int sampleRate = 48000;
     142           1 :     const constexpr int nbChannels = 2;
     143           1 :     const constexpr int width = 320;
     144           1 :     const constexpr int height = 240;
     145             :     auto vp8Codec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(
     146           2 :         getSystemCodecContainer()->searchCodecByName("VP8", jami::MEDIA_VIDEO)
     147           1 :     );
     148             :     auto opusCodec = std::static_pointer_cast<SystemAudioCodecInfo>(
     149           2 :         getSystemCodecContainer()->searchCodecByName("opus", jami::MEDIA_AUDIO)
     150           1 :     );
     151           2 :     auto v = MediaStream("v", AV_PIX_FMT_YUV420P, rational<int>(1, 30), width, height, 1, 30);
     152           2 :     auto a = MediaStream("a", AV_SAMPLE_FMT_S16, rational<int>(1, sampleRate), sampleRate, nbChannels, 960);
     153             : 
     154             :     try {
     155           1 :         encoder_->openOutput("test.mkv");
     156           1 :         encoder_->setOptions(a);
     157           1 :         CPPUNIT_ASSERT(encoder_->getStreamCount() == 1);
     158           1 :         int audioIdx = encoder_->addStream(*opusCodec.get());
     159           1 :         CPPUNIT_ASSERT(audioIdx >= 0);
     160           1 :         encoder_->setOptions(v);
     161           1 :         CPPUNIT_ASSERT(encoder_->getStreamCount() == 2);
     162           1 :         int videoIdx = encoder_->addStream(*vp8Codec.get());
     163           1 :         CPPUNIT_ASSERT(videoIdx >= 0);
     164           1 :         CPPUNIT_ASSERT(videoIdx != audioIdx);
     165           1 :         encoder_->setIOContext(nullptr);
     166           1 :         int sentSamples = 0;
     167           1 :         AVFrame* audio = nullptr;
     168           1 :         AVFrame* video = nullptr;
     169          26 :         for (int i = 0; i < 25; ++i) {
     170          25 :             audio = getAudioFrame(sampleRate, 0.02*sampleRate, nbChannels);
     171          25 :             CPPUNIT_ASSERT(audio);
     172          25 :             audio->pts = sentSamples;
     173          25 :             video = getVideoFrame(width, height, i);
     174          25 :             CPPUNIT_ASSERT(video);
     175          25 :             video->pts = i;
     176             : 
     177          25 :             CPPUNIT_ASSERT(encoder_->encode(audio, audioIdx) >= 0);
     178          25 :             sentSamples += audio->nb_samples;
     179          25 :             CPPUNIT_ASSERT(encoder_->encode(video, videoIdx) >= 0);
     180             : 
     181          25 :             av_frame_free(&audio);
     182          25 :             av_frame_free(&video);
     183             :         }
     184           1 :         CPPUNIT_ASSERT(encoder_->flush() >= 0);
     185           0 :     } catch (const MediaEncoderException& e) {
     186           0 :         CPPUNIT_FAIL(e.what());
     187           0 :     }
     188           1 : }
     189             : 
     190             : }} // namespace jami::test
     191             : 
     192           1 : RING_TEST_RUNNER(jami::test::MediaEncoderTest::name());

Generated by: LCOV version 1.14