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