1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "WebrtcVideoCodecFactory.h"
7 
8 #include "GmpVideoCodec.h"
9 #include "MediaDataCodec.h"
10 #include "VideoConduit.h"
11 #include "mozilla/StaticPrefs_media.h"
12 
13 // libwebrtc includes
14 #include "api/rtp_headers.h"
15 #include "api/video_codecs/video_codec.h"
16 #include "api/video_codecs/video_encoder_software_fallback_wrapper.h"
17 #include "media/engine/encoder_simulcast_proxy.h"
18 #include "modules/video_coding/codecs/vp8/include/vp8.h"
19 #include "modules/video_coding/codecs/vp9/include/vp9.h"
20 
21 namespace mozilla {
22 
23 std::unique_ptr<webrtc::VideoDecoder>
CreateVideoDecoder(const webrtc::SdpVideoFormat & aFormat)24 WebrtcVideoDecoderFactory::CreateVideoDecoder(
25     const webrtc::SdpVideoFormat& aFormat) {
26   std::unique_ptr<webrtc::VideoDecoder> decoder;
27   auto type = webrtc::PayloadStringToCodecType(aFormat.name);
28 
29   // Attempt to create a decoder using MediaDataDecoder.
30   decoder.reset(MediaDataCodec::CreateDecoder(type));
31   if (decoder) {
32     return decoder;
33   }
34 
35   switch (type) {
36     case webrtc::VideoCodecType::kVideoCodecH264: {
37       // Get an external decoder
38       auto gmpDecoder = WrapUnique(GmpVideoCodec::CreateDecoder(mPCHandle));
39       mCreatedGmpPluginEvent.Forward(*gmpDecoder->InitPluginEvent());
40       mReleasedGmpPluginEvent.Forward(*gmpDecoder->ReleasePluginEvent());
41       decoder.reset(gmpDecoder.release());
42       break;
43     }
44 
45     // Use libvpx decoders as fallbacks.
46     case webrtc::VideoCodecType::kVideoCodecVP8:
47       if (!decoder) {
48         decoder = webrtc::VP8Decoder::Create();
49       }
50       break;
51     case webrtc::VideoCodecType::kVideoCodecVP9:
52       decoder = webrtc::VP9Decoder::Create();
53       break;
54 
55     default:
56       break;
57   }
58 
59   return decoder;
60 }
61 
62 std::unique_ptr<webrtc::VideoEncoder>
CreateVideoEncoder(const webrtc::SdpVideoFormat & aFormat)63 WebrtcVideoEncoderFactory::CreateVideoEncoder(
64     const webrtc::SdpVideoFormat& aFormat) {
65   if (!mInternalFactory->Supports(aFormat)) {
66     return nullptr;
67   }
68   auto type = webrtc::PayloadStringToCodecType(aFormat.name);
69   switch (type) {
70     case webrtc::VideoCodecType::kVideoCodecVP8:
71       // XXX We might be able to use the simulcast proxy for more codecs, but
72       // that requires testing.
73       return std::make_unique<webrtc::EncoderSimulcastProxy>(
74           mInternalFactory.get(), aFormat);
75     default:
76       return mInternalFactory->CreateVideoEncoder(aFormat);
77   }
78 }
79 
Supports(const webrtc::SdpVideoFormat & aFormat)80 bool WebrtcVideoEncoderFactory::InternalFactory::Supports(
81     const webrtc::SdpVideoFormat& aFormat) {
82   switch (webrtc::PayloadStringToCodecType(aFormat.name)) {
83     case webrtc::VideoCodecType::kVideoCodecVP8:
84     case webrtc::VideoCodecType::kVideoCodecVP9:
85     case webrtc::VideoCodecType::kVideoCodecH264:
86       return true;
87     default:
88       return false;
89   }
90 }
91 
92 std::unique_ptr<webrtc::VideoEncoder>
CreateVideoEncoder(const webrtc::SdpVideoFormat & aFormat)93 WebrtcVideoEncoderFactory::InternalFactory::CreateVideoEncoder(
94     const webrtc::SdpVideoFormat& aFormat) {
95   MOZ_ASSERT(Supports(aFormat));
96 
97   std::unique_ptr<webrtc::VideoEncoder> platformEncoder;
98   platformEncoder.reset(MediaDataCodec::CreateEncoder(aFormat));
99   const bool fallback = StaticPrefs::media_webrtc_software_encoder_fallback();
100   if (!fallback && platformEncoder) {
101     return platformEncoder;
102   }
103 
104   std::unique_ptr<webrtc::VideoEncoder> encoder;
105   switch (webrtc::PayloadStringToCodecType(aFormat.name)) {
106     case webrtc::VideoCodecType::kVideoCodecH264: {
107       // get an external encoder
108       auto gmpEncoder = WrapUnique(GmpVideoCodec::CreateEncoder(mPCHandle));
109       mCreatedGmpPluginEvent.Forward(*gmpEncoder->InitPluginEvent());
110       mReleasedGmpPluginEvent.Forward(*gmpEncoder->ReleasePluginEvent());
111       encoder.reset(gmpEncoder.release());
112       break;
113     }
114     // libvpx fallbacks.
115     case webrtc::VideoCodecType::kVideoCodecVP8:
116       if (!encoder) {
117         encoder = webrtc::VP8Encoder::Create();
118       }
119       break;
120     case webrtc::VideoCodecType::kVideoCodecVP9:
121       encoder = webrtc::VP9Encoder::Create();
122       break;
123 
124     default:
125       break;
126   }
127   if (fallback && encoder && platformEncoder) {
128     return webrtc::CreateVideoEncoderSoftwareFallbackWrapper(
129         std::move(encoder), std::move(platformEncoder), false);
130   }
131   if (platformEncoder) {
132     return platformEncoder;
133   }
134   return encoder;
135 }
136 
137 }  // namespace mozilla
138