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