1 /*
2  * This file is part of Wireless Display Software for Linux OS
3  *
4  * Copyright (C) 2014 Intel Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  */
21 
22 #include "libwds/rtsp/videoformats.h"
23 
24 #include <cassert>
25 
26 #include "libwds/rtsp/macros.h"
27 
28 namespace wds {
29 namespace rtsp {
30 
31 namespace {
32 template <typename EnumType>
EnumListToMask(const std::vector<EnumType> & from)33 unsigned int EnumListToMask(const std::vector<EnumType>& from) {
34   unsigned int result = 0;
35 
36   for (auto item : from) {
37     result = result | (1 << item);
38   }
39 
40   return result;
41 }
42 } //namespace
43 
44 using wds::H264VideoFormat;
45 using wds::H264VideoCodec;
46 
H264Codec(unsigned char profile,unsigned char level,unsigned int cea_support,unsigned int vesa_support,unsigned int hh_support,unsigned char latency,unsigned short min_slice_size,unsigned short slice_enc_params,unsigned char frame_rate_control_support,unsigned short max_hres,unsigned short max_vres)47 H264Codec::H264Codec(unsigned char profile, unsigned char level,
48     unsigned int cea_support, unsigned int vesa_support,
49     unsigned int hh_support, unsigned char latency,
50     unsigned short min_slice_size, unsigned short slice_enc_params,
51     unsigned char frame_rate_control_support,
52     unsigned short max_hres, unsigned short max_vres)
53   : profile(profile),
54     level(level),
55     cea_support(cea_support),
56     vesa_support(vesa_support),
57     hh_support(hh_support),
58     latency(latency),
59     min_slice_size(min_slice_size),
60     slice_enc_params(slice_enc_params),
61     frame_rate_control_support(frame_rate_control_support),
62     max_hres(max_hres),
63     max_vres(max_vres) {}
64 
H264Codec(const H264VideoFormat & format)65 H264Codec::H264Codec(const H264VideoFormat& format)
66   : profile(1 << format.profile),
67     level(1 << format.level),
68     cea_support((format.type == CEA) ? 1 << format.rate_resolution : 0),
69     vesa_support((format.type == VESA) ? 1 << format.rate_resolution : 0),
70     hh_support((format.type == HH) ? 1 << format.rate_resolution : 0),
71     latency(0),
72     min_slice_size(0),
73     slice_enc_params(0),
74     frame_rate_control_support(0),
75     max_hres(0),
76     max_vres(0) {
77 
78 }
79 
H264Codec(const H264VideoCodec & format)80 H264Codec::H264Codec(const H264VideoCodec& format)
81   : profile(1 << format.profile),
82     level(1 << format.level),
83     cea_support(format.cea_rr.to_ulong()),
84     vesa_support(format.vesa_rr.to_ulong()),
85     hh_support(format.hh_rr.to_ulong()),
86     latency(0),
87     min_slice_size(0),
88     slice_enc_params(0),
89     frame_rate_control_support(0),
90     max_hres(0),
91     max_vres(0) {
92 
93 }
94 
95 
ToString() const96 std::string H264Codec::ToString() const {
97   std::string ret;
98   MAKE_HEX_STRING_2(profile_str, profile);
99   MAKE_HEX_STRING_2(level_str, level);
100   MAKE_HEX_STRING_8(cea_support_str, cea_support);
101   MAKE_HEX_STRING_8(vesa_support_str, vesa_support);
102   MAKE_HEX_STRING_8(hh_support_str, hh_support);
103   MAKE_HEX_STRING_2(latency_str, latency);
104   MAKE_HEX_STRING_4(min_slice_size_str, min_slice_size);
105   MAKE_HEX_STRING_4(slice_enc_params_str, slice_enc_params);
106   MAKE_HEX_STRING_2(frame_rate_control_support_str, frame_rate_control_support);
107 
108   ret = profile_str + std::string(SPACE)
109       + level_str + std::string(SPACE)
110       + cea_support_str + std::string(SPACE)
111       + vesa_support_str + std::string(SPACE)
112       + hh_support_str + std::string(SPACE)
113       + latency_str + std::string(SPACE)
114       + min_slice_size_str + std::string(SPACE)
115       + slice_enc_params_str + std::string(SPACE)
116       + frame_rate_control_support_str + std::string(SPACE);
117 
118   if (max_hres > 0) {
119     MAKE_HEX_STRING_4(max_hres_str, max_hres);
120     ret += max_hres_str;
121   } else {
122     ret += NONE;
123   }
124   ret += std::string(SPACE);
125 
126   if (max_vres > 0) {
127     MAKE_HEX_STRING_4(max_vres_str, max_vres);
128     ret += max_vres_str;
129   } else {
130     ret += NONE;
131   }
132 
133   return ret;
134 }
135 
136 namespace {
137 
138 template <typename EnumType, typename ArgType>
139 EnumType MaskToEnum(ArgType from, EnumType biggest_value) {
140   assert(from != 0);
141   ArgType copy = from;
142   unsigned result = 0;
143   while ((copy & 1) == 0 && copy != 0) {
144     copy = copy >> 1;
145     ++result;
146   }
147   if (result > static_cast<unsigned>(biggest_value)) {
148     assert(false);
149     return biggest_value;
150   }
151   return static_cast<EnumType>(result);
152 }
153 
154 template <typename EnumType, typename ArgType>
MaskToEnumList(ArgType from,EnumType biggest_value)155 std::vector<EnumType> MaskToEnumList(ArgType from, EnumType biggest_value) {
156   assert(from != 0);
157   ArgType copy = from;
158   unsigned enum_value = 0;
159   std::vector<EnumType> result;
160 
161   while (copy != 0) {
162     if ((copy & 1) != 0) {
163       if (enum_value > static_cast<unsigned>(biggest_value))
164         break;
165 
166       result.push_back(static_cast<EnumType>(enum_value));
167     }
168     copy = copy >> 1;
169     ++enum_value;
170   }
171 
172   return result;
173 }
174 
ToH264Profile(unsigned char profile)175 inline H264Profile ToH264Profile(unsigned char profile) {
176   return MaskToEnum<H264Profile>(profile, CHP);
177 }
178 
ToH264Level(unsigned char level)179 inline H264Level ToH264Level(unsigned char level) {
180   return MaskToEnum<H264Level>(level, k4_2);
181 }
182 
183 }  // namespace
184 
ToH264VideoCodec() const185 H264VideoCodec H264Codec::ToH264VideoCodec() const {
186   H264VideoCodec result;
187   result.profile = ToH264Profile(profile);
188   result.level = ToH264Level(level);
189   result.cea_rr = RateAndResolutionsBitmap(cea_support);
190   result.vesa_rr = RateAndResolutionsBitmap(vesa_support);
191   result.hh_rr = RateAndResolutionsBitmap(hh_support);
192   return result;
193 }
194 
VideoFormats()195 VideoFormats::VideoFormats() : Property(VideoFormatsPropertyType, true) {
196 }
197 
VideoFormats(NativeVideoFormat format,bool preferred_display_mode,const std::vector<H264VideoFormat> & h264_formats)198 VideoFormats::VideoFormats(NativeVideoFormat format,
199     bool preferred_display_mode,
200     const std::vector<H264VideoFormat>& h264_formats)
201   : Property(VideoFormatsPropertyType),
202     preferred_display_mode_(preferred_display_mode ? 1 : 0) {
203   native_ = (format.rate_resolution << 3) | format.type;
204   for(auto h264_format : h264_formats)
205     h264_codecs_.push_back(H264Codec(h264_format));
206 }
207 
VideoFormats(NativeVideoFormat format,bool preferred_display_mode,const std::vector<H264VideoCodec> & h264_formats)208 VideoFormats::VideoFormats(NativeVideoFormat format,
209     bool preferred_display_mode,
210     const std::vector<H264VideoCodec>& h264_formats)
211   : Property(VideoFormatsPropertyType),
212     preferred_display_mode_(preferred_display_mode ? 1 : 0) {
213   native_ = (format.rate_resolution << 3) | format.type;
214   for(auto h264_format : h264_formats)
215     h264_codecs_.push_back(H264Codec(h264_format));
216 }
217 
VideoFormats(unsigned char native,unsigned char preferred_display_mode,const H264Codecs & h264_codecs)218 VideoFormats::VideoFormats(unsigned char native,
219     unsigned char preferred_display_mode,
220     const H264Codecs& h264_codecs)
221   : Property(VideoFormatsPropertyType),
222     native_(native),
223     preferred_display_mode_(preferred_display_mode),
224     h264_codecs_(h264_codecs) {
225 }
226 
~VideoFormats()227 VideoFormats::~VideoFormats() {
228 }
229 
230 namespace {
231 
232 template <typename EnumType>
GetFormatFromIndex(unsigned index,EnumType biggest_value)233 NativeVideoFormat GetFormatFromIndex(unsigned index, EnumType biggest_value) {
234   if (index <= static_cast<unsigned>(biggest_value))
235     return NativeVideoFormat(static_cast<EnumType>(index));
236   assert(false);
237   return NativeVideoFormat(biggest_value);
238 }
239 
240 }
241 
GetNativeFormat() const242 NativeVideoFormat VideoFormats::GetNativeFormat() const {
243   unsigned index  = native_ >> 3;
244   unsigned selection_bits = native_ & 7;
245   switch (selection_bits) {
246   case 0: // 0b000 CEA
247     return GetFormatFromIndex<CEARatesAndResolutions>(index, CEA1920x1080p24);
248   case 1: // 0b001 VESA
249     return GetFormatFromIndex<VESARatesAndResolutions>(index, VESA1920x1200p30);
250   case 2: // 0b010 HH
251     return GetFormatFromIndex<HHRatesAndResolutions>(index, HH848x480p60);
252   default:
253     assert(false);
254     break;
255   }
256   return NativeVideoFormat(CEA640x480p60);
257 }
258 
GetH264Formats() const259 std::vector<H264VideoFormat> VideoFormats::GetH264Formats() const {
260   std::vector<H264VideoFormat> result;
261   for (const auto& codec : h264_codecs_)
262     PopulateVideoFormatList(codec.ToH264VideoCodec(), result);
263   return result;
264 }
265 
GetH264VideoCodecs() const266 std::vector<H264VideoCodec> VideoFormats::GetH264VideoCodecs() const {
267   std::vector<H264VideoCodec> result;
268   for (const auto& codec : h264_codecs_)
269     result.push_back(codec.ToH264VideoCodec());
270   return result;
271 }
272 
ToString() const273 std::string VideoFormats::ToString() const {
274   std::string ret;
275 
276   ret = PropertyName::wfd_video_formats
277       + std::string(SEMICOLON)+ std::string(SPACE);
278 
279   if (is_none())
280     return ret + NONE;
281 
282   MAKE_HEX_STRING_2(native, native_);
283   MAKE_HEX_STRING_2(preferred_display_mode, preferred_display_mode_);
284 
285   ret += native + std::string(SPACE)
286       + preferred_display_mode + std::string(SPACE);
287 
288   auto it = h264_codecs_.begin();
289   auto end = h264_codecs_.end();
290   while(it != end) {
291     ret += (*it).ToString();
292     ++it;
293     if (it != end)
294       ret += ", ";
295   }
296 
297   return ret;
298 }
299 
300 }  // namespace rtsp
301 }  // namespace wds
302