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-04-26 09:41:19 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.14