video_sender.cpp 4.83 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004-2019 Savoir-faire Linux Inc.
3
 *
4
 *  Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
5
 *  Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
6
 *  Author: Eloi Bail <eloi.bail@savoirfairelinux.com>
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
20
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
21 22
 */

23
#include "video_sender.h"
24
#include "video_mixer.h"
25
#include "socket_pair.h"
26
#include "client/videomanager.h"
Tristan Matthews's avatar
Tristan Matthews committed
27
#include "logger.h"
28
#include "manager.h"
29
#include "media_device.h"
Gasuleg's avatar
Gasuleg committed
30
#include "smartools.h"
31 32 33 34
#include "sip/sipcall.h"
#ifdef RING_ACCEL
#include "accel.h"
#endif
35

36
#include <map>
37
#include <unistd.h>
Adrien Béraud's avatar
Adrien Béraud committed
38 39 40
extern "C" {
#include <libavutil/display.h>
}
41

Adrien Béraud's avatar
Adrien Béraud committed
42
namespace jami { namespace video {
43

44 45
using std::string;

Guillaume Roguez's avatar
Guillaume Roguez committed
46
VideoSender::VideoSender(const std::string& dest, const DeviceParams& dev,
47
                         const MediaDescription& args, SocketPair& socketPair,
48 49 50
                         const uint16_t seqVal,
                         uint16_t mtu)
    : muxContext_(socketPair.createIOContext(mtu))
Guillaume Roguez's avatar
Guillaume Roguez committed
51
    , videoEncoder_(new MediaEncoder)
52
{
53
    keyFrameFreq_ = dev.framerate.numerator() * KEY_FRAME_PERIOD;
54
    videoEncoder_->openOutput(dest, "rtp");
55 56
    auto opts = MediaStream("video sender", AV_PIX_FMT_YUV420P, 1 / (rational<int>)dev.framerate, dev.width, dev.height, 1, (rational<int>)dev.framerate);
    videoEncoder_->setOptions(opts);
57 58
    videoEncoder_->setOptions(args);
    videoEncoder_->addStream(args.codec->systemCodecInfo);
59
    videoEncoder_->setInitSeqVal(seqVal);
60
    videoEncoder_->setIOContext(muxContext_->getContext());
61 62

    // Send local video codec in SmartInfo
63
    Smartools::getInstance().setLocalVideoCodec(videoEncoder_->getVideoCodec());
64 65 66

    // Send the resolution in smartInfo
    Smartools::getInstance().setResolution("local", dev.width, dev.height);
67 68
}

69 70 71 72 73
VideoSender::~VideoSender()
{
    videoEncoder_->flush();
}

74 75
void
VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
76
{
77
    if (auto packet = input_frame.packet()) {
78 79 80 81 82 83
#if __ANDROID__
        if (forceKeyFrame_) {
            emitSignal<DRing::VideoSignal::RequestKeyFrame>();
            forceKeyFrame_ = 0;
        }
#endif
84 85 86 87 88 89 90 91 92
        int size {0};
        uint8_t* side_data = av_packet_get_side_data(packet, AV_PKT_DATA_DISPLAYMATRIX, &size);
        auto angle = (side_data == nullptr || size == 0) ? 0 : av_display_rotation_get(reinterpret_cast<int32_t*>(side_data));
        if (rotation_ != angle) {
            rotation_ = angle;
            if (changeOrientationCallback_)
                changeOrientationCallback_(rotation_);
        }

93 94 95 96 97 98 99 100
        videoEncoder_->send(*packet);
    } else {
        bool is_keyframe = forceKeyFrame_ > 0
            or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);

        if (is_keyframe)
            --forceKeyFrame_;

Adrien Béraud's avatar
Adrien Béraud committed
101
        AVFrameSideData* side_data = av_frame_get_side_data(input_frame.pointer(), AV_FRAME_DATA_DISPLAYMATRIX);
102 103 104 105 106
        auto angle = side_data == nullptr ? 0 : av_display_rotation_get(reinterpret_cast<int32_t*>(side_data->data));
        if (rotation_ != angle) {
            rotation_ = angle;
            if (changeOrientationCallback_)
                changeOrientationCallback_(rotation_);
Adrien Béraud's avatar
Adrien Béraud committed
107 108
        }

109
        if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
Adrien Béraud's avatar
Adrien Béraud committed
110
            JAMI_ERR("encoding failed");
111
    }
112 113 114 115
#ifdef DEBUG_SDP
    if (frameNumber_ == 1) // video stream is lazy initialized, wait for first frame
        videoEncoder_->print_sdp();
#endif
116 117
}

118
void
119 120
VideoSender::update(Observable<std::shared_ptr<MediaFrame>>* /*obs*/,
                    const std::shared_ptr<MediaFrame>& frame_p)
121
{
122
    encodeAndSendVideo(*std::static_pointer_cast<VideoFrame>(frame_p));
123
}
124

125 126
void
VideoSender::forceKeyFrame()
127
{
Adrien Béraud's avatar
Adrien Béraud committed
128
    JAMI_DBG("Key frame requested");
129 130
    ++forceKeyFrame_;
}
131

132 133 134 135 136 137
uint16_t
VideoSender::getLastSeqValue()
{
    return videoEncoder_->getLastSeqValue();
}

Adrien Béraud's avatar
Adrien Béraud committed
138 139 140
void
VideoSender::setChangeOrientationCallback(std::function<void(int)> cb)
{
Adrien Béraud's avatar
Adrien Béraud committed
141
    changeOrientationCallback_ = std::move(cb);
Adrien Béraud's avatar
Adrien Béraud committed
142 143
}

144 145 146 147 148 149 150 151 152 153 154 155 156
int
VideoSender::setBitrate(uint64_t br)
{
    // The encoder may be destroy during a bitrate change
    // when a codec parameter like auto quality change
    if(!videoEncoder_)
        return -1;

    videoEncoder_->setBitrate(br);
    return 0;

}

Adrien Béraud's avatar
Adrien Béraud committed
157
}} // namespace jami::video