Line data Source code
1 : /*
2 : * Copyright (C) 2004-2025 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 : #pragma once
18 :
19 : #include "libav_deps.h"
20 : #include "logger.h"
21 : #include "rational.h"
22 : #include "audio/audio_format.h"
23 :
24 : #include <string>
25 :
26 : namespace jami {
27 :
28 : struct MediaStream
29 : {
30 : std::string name {};
31 : int format {-1};
32 : bool isVideo {false};
33 : rational<int> timeBase;
34 : int64_t firstTimestamp {0};
35 : int width {0};
36 : int height {0};
37 : int bitrate {0};
38 : rational<int> frameRate;
39 : int sampleRate {0};
40 : int nbChannels {0};
41 : int frameSize {0};
42 :
43 1081 : MediaStream() {}
44 :
45 106 : MediaStream(const std::string& streamName, int fmt, rational<int> tb, int w, int h, int br, rational<int> fr)
46 106 : : name(streamName)
47 106 : , format(fmt)
48 106 : , isVideo(true)
49 106 : , timeBase(tb)
50 106 : , width(w)
51 106 : , height(h)
52 106 : , bitrate(br)
53 106 : , frameRate(fr)
54 106 : {}
55 :
56 6 : MediaStream(const std::string& streamName, int fmt, rational<int> tb, int sr, int channels, int size)
57 6 : : name(streamName)
58 6 : , format(fmt)
59 6 : , isVideo(false)
60 6 : , timeBase(tb)
61 6 : , sampleRate(sr)
62 6 : , nbChannels(channels)
63 6 : , frameSize(size)
64 6 : {}
65 :
66 180 : MediaStream(const std::string& streamName, AudioFormat fmt)
67 180 : : MediaStream(streamName, fmt, 0)
68 180 : {}
69 :
70 182 : MediaStream(const std::string& streamName, AudioFormat fmt, int64_t startTimestamp)
71 182 : : name(streamName)
72 182 : , format(fmt.sampleFormat)
73 182 : , isVideo(false)
74 182 : , timeBase(1, fmt.sample_rate)
75 182 : , firstTimestamp(startTimestamp)
76 182 : , sampleRate(fmt.sample_rate)
77 182 : , nbChannels(fmt.nb_channels)
78 182 : , frameSize(fmt.sample_rate / 50) // standard frame size for our encoder is 20 ms
79 182 : {}
80 :
81 0 : MediaStream(const std::string& streamName, AVCodecContext* c)
82 0 : : MediaStream(streamName, c, 0)
83 0 : {}
84 :
85 98 : MediaStream(const std::string& streamName, AVCodecContext* c, int64_t startTimestamp)
86 98 : : name(streamName)
87 98 : , firstTimestamp(startTimestamp)
88 : {
89 98 : if (c) {
90 98 : timeBase = c->time_base;
91 98 : switch (c->codec_type) {
92 90 : case AVMEDIA_TYPE_VIDEO:
93 90 : format = c->pix_fmt;
94 90 : isVideo = true;
95 90 : width = c->width;
96 90 : height = c->height;
97 90 : bitrate = c->bit_rate;
98 90 : frameRate = c->framerate;
99 90 : break;
100 8 : case AVMEDIA_TYPE_AUDIO:
101 8 : format = c->sample_fmt;
102 8 : isVideo = false;
103 8 : sampleRate = c->sample_rate;
104 8 : nbChannels = c->ch_layout.nb_channels;
105 8 : frameSize = c->frame_size;
106 8 : break;
107 0 : default:
108 0 : break;
109 : }
110 : } else {
111 0 : JAMI_WARN() << "Attempting to get stream info from null codec context";
112 : }
113 98 : }
114 :
115 404 : MediaStream(const MediaStream& other) = default;
116 :
117 500 : bool isValid() const
118 : {
119 500 : if (format < 0)
120 154 : return false;
121 346 : if (isVideo)
122 157 : return width > 0 && height > 0;
123 : else
124 189 : return sampleRate > 0 && nbChannels > 0;
125 : }
126 :
127 1 : void update(AVFrame* f)
128 : {
129 : // update all info possible (AVFrame has no fps or bitrate data)
130 1 : format = f->format;
131 1 : if (isVideo) {
132 0 : width = f->width;
133 0 : height = f->height;
134 : } else {
135 1 : sampleRate = f->sample_rate;
136 1 : nbChannels = f->ch_layout.nb_channels;
137 1 : timeBase = rational<int>(1, f->sample_rate);
138 1 : if (!frameSize)
139 0 : frameSize = f->nb_samples;
140 : }
141 1 : }
142 :
143 1 : friend bool operator==(const MediaStream& ms1, const MediaStream& ms2)
144 : {
145 1 : return ms1.bitrate == ms2.bitrate and ms1.firstTimestamp == ms2.firstTimestamp and ms1.format == ms2.format
146 0 : and ms1.frameRate == ms2.frameRate and ms1.frameSize == ms2.frameSize and ms1.height == ms2.height
147 0 : and ms1.isVideo == ms2.isVideo and ms1.name == ms2.name and ms1.nbChannels == ms2.nbChannels
148 2 : and ms1.sampleRate == ms2.sampleRate and ms1.timeBase == ms2.timeBase and ms1.width == ms2.width;
149 : }
150 : };
151 :
152 : inline std::ostream&
153 0 : operator<<(std::ostream& os, const MediaStream& ms)
154 : {
155 0 : if (ms.isVideo) {
156 0 : auto formatName = av_get_pix_fmt_name(static_cast<AVPixelFormat>(ms.format));
157 0 : os << (ms.name.empty() ? "(null)" : ms.name) << ": " << (formatName ? formatName : "(unknown format)")
158 0 : << " video, " << ms.width << "x" << ms.height << ", " << ms.frameRate << " fps (" << ms.timeBase << ")";
159 0 : if (ms.bitrate > 0)
160 0 : os << ", " << ms.bitrate << " kb/s";
161 : } else {
162 0 : os << (ms.name.empty() ? "(null)" : ms.name) << ": "
163 0 : << av_get_sample_fmt_name(static_cast<AVSampleFormat>(ms.format)) << " audio, " << ms.nbChannels
164 0 : << " channel(s), " << ms.sampleRate << " Hz (" << ms.timeBase << "), " << ms.frameSize
165 0 : << " samples per frame";
166 : }
167 0 : if (ms.firstTimestamp > 0)
168 0 : os << ", start: " << ms.firstTimestamp;
169 0 : return os;
170 : }
171 :
172 : }; // namespace jami
|