@@ -33,29 +33,50 @@ defmodule Membrane.Transcoder.Video do
3333 ChildrenSpec . builder ( ) ,
3434 video_stream_format ( ) ,
3535 video_stream_format ( ) ,
36+ :always | :if_needed | :never ,
3637 boolean ( )
3738 ) :: ChildrenSpec . builder ( )
38- def plug_video_transcoding ( builder , input_format , output_format , transcoding_policy )
39+ def plug_video_transcoding (
40+ builder ,
41+ input_format ,
42+ output_format ,
43+ transcoding_policy ,
44+ use_vulkan?
45+ )
3946 when is_video_format ( input_format ) and is_video_format ( output_format ) do
40- do_plug_video_transcoding ( builder , input_format , output_format , transcoding_policy )
47+ do_plug_video_transcoding (
48+ builder ,
49+ input_format ,
50+ output_format ,
51+ transcoding_policy ,
52+ use_vulkan?
53+ )
4154 end
4255
4356 defp do_plug_video_transcoding (
4457 builder ,
4558 % RemoteStream { content_format: h26x } ,
4659 output_format ,
47- transcoding_policy
60+ transcoding_policy ,
61+ use_vulkan?
4862 )
4963 when h26x in [ H264 , H265 ] do
5064 do_plug_video_transcoding (
5165 builder ,
5266 struct! ( h26x ) ,
5367 output_format ,
54- transcoding_policy
68+ transcoding_policy ,
69+ use_vulkan?
5570 )
5671 end
5772
58- defp do_plug_video_transcoding ( builder , % H264 { } , % H264 { } = output_format , transcoding_policy )
73+ defp do_plug_video_transcoding (
74+ builder ,
75+ % H264 { } ,
76+ % H264 { } = output_format ,
77+ transcoding_policy ,
78+ _use_vulkan?
79+ )
5980 when transcoding_policy in [ :if_needed , :never ] do
6081 builder
6182 |> child ( :h264_parser , % H264.Parser {
@@ -64,7 +85,13 @@ defmodule Membrane.Transcoder.Video do
6485 } )
6586 end
6687
67- defp do_plug_video_transcoding ( builder , % H265 { } , % H265 { } = output_format , transcoding_policy )
88+ defp do_plug_video_transcoding (
89+ builder ,
90+ % H265 { } ,
91+ % H265 { } = output_format ,
92+ transcoding_policy ,
93+ _use_vulkan?
94+ )
6895 when transcoding_policy in [ :if_needed , :never ] do
6996 builder
7097 |> child ( :h265_parser , % H265.Parser {
@@ -77,7 +104,19 @@ defmodule Membrane.Transcoder.Video do
77104 builder ,
78105 % RawVideo { } = input_format ,
79106 % RawVideo { } = output_format ,
80- _transcoding_policy
107+ _transcoding_policy ,
108+ true
109+ ) do
110+ builder
111+ |> maybe_plug_swscale_converter_vulkan ( input_format , output_format )
112+ end
113+
114+ defp do_plug_video_transcoding (
115+ builder ,
116+ % RawVideo { } = input_format ,
117+ % RawVideo { } = output_format ,
118+ _transcoding_policy ,
119+ false
81120 ) do
82121 builder
83122 |> maybe_plug_swscale_converter ( input_format , output_format )
@@ -87,7 +126,8 @@ defmodule Membrane.Transcoder.Video do
87126 builder ,
88127 % format_module { } ,
89128 % format_module { } ,
90- transcoding_policy
129+ transcoding_policy ,
130+ _use_vulkan?
91131 )
92132 when transcoding_policy in [ :if_needed , :never ] do
93133 Membrane.Logger . debug ( """
@@ -97,20 +137,40 @@ defmodule Membrane.Transcoder.Video do
97137 builder
98138 end
99139
100- defp do_plug_video_transcoding ( _builder , input_format , output_format , :never ) do
101- raise """
102- Cannot convert input format #{ inspect ( input_format ) } to output format #{ inspect ( output_format ) } \
103- with :transcoding_policy option set to :never.
104- """
140+ defp do_plug_video_transcoding ( _builder , input_format , output_format , :never , _use_vulkan? ) ,
141+ do:
142+ raise ( """
143+ Cannot convert input format #{ inspect ( input_format ) } to output format #{ inspect ( output_format ) } \
144+ with :transcoding_policy option set to :never.
145+ """ )
146+
147+ defp do_plug_video_transcoding ( builder , input_format , output_format , _transcoding_policy , true ) do
148+ builder
149+ |> maybe_plug_parser_and_decoder_vulkan ( input_format )
150+ |> maybe_plug_swscale_converter_vulkan ( input_format , output_format )
151+ |> maybe_plug_encoder_and_parser_vulkan ( output_format )
105152 end
106153
107- defp do_plug_video_transcoding ( builder , input_format , output_format , _transcoding_policy ) do
154+ defp do_plug_video_transcoding ( builder , input_format , output_format , _transcoding_policy , false ) do
108155 builder
109156 |> maybe_plug_parser_and_decoder ( input_format )
110157 |> maybe_plug_swscale_converter ( input_format , output_format )
111158 |> maybe_plug_encoder_and_parser ( output_format )
112159 end
113160
161+ # VK-specific decoder: child name :vk_h264_decoder distinguishes it from FFmpeg's :h264_decoder
162+ defp maybe_plug_parser_and_decoder_vulkan ( builder , % H264 { } ) do
163+ builder
164+ |> child ( :h264_input_parser , % H264.Parser {
165+ output_stream_structure: :annexb ,
166+ output_alignment: :au
167+ } )
168+ |> child ( :vk_h264_decoder , Membrane.VKVideo.Decoder )
169+ end
170+
171+ defp maybe_plug_parser_and_decoder_vulkan ( builder , format ) ,
172+ do: maybe_plug_parser_and_decoder ( builder , format )
173+
114174 defp maybe_plug_parser_and_decoder ( builder , % H264 { } ) do
115175 builder
116176 |> child ( :h264_input_parser , % H264.Parser {
@@ -143,10 +203,41 @@ defmodule Membrane.Transcoder.Video do
143203 builder |> child ( :vp8_decoder , decoder_module )
144204 end
145205
146- defp maybe_plug_parser_and_decoder ( builder , % RawVideo { } ) do
147- builder
206+ defp maybe_plug_parser_and_decoder ( builder , % RawVideo { } ) , do: builder
207+
208+ # VK decoder outputs NV12; these clauses handle the NV12 <-> other-format conversion
209+ # when mixing VK decode/encode with different pixel formats.
210+
211+ defp maybe_plug_swscale_converter_vulkan ( builder , % H264 { } , % RawVideo { pixel_format: nil } ) ,
212+ do: builder
213+
214+ defp maybe_plug_swscale_converter_vulkan ( builder , % H264 { } , % RawVideo { pixel_format: :NV12 } ) ,
215+ do: builder
216+
217+ defp maybe_plug_swscale_converter_vulkan ( builder , % H264 { } , % RawVideo { } = output_format ) do
218+ builder |> child ( :raw_video_converter , % SWScale.Converter { format: output_format . pixel_format } )
219+ end
220+
221+ defp maybe_plug_swscale_converter_vulkan ( builder , % RawVideo { pixel_format: :NV12 } , % H264 { } ) ,
222+ do: builder
223+
224+ defp maybe_plug_swscale_converter_vulkan ( builder , % RawVideo { } , % H264 { } ) do
225+ builder |> child ( :raw_video_converter , % SWScale.Converter { format: :NV12 } )
148226 end
149227
228+ defp maybe_plug_swscale_converter_vulkan ( builder , % H264 { } , % H264 { } ) , do: builder
229+
230+ defp maybe_plug_swscale_converter_vulkan ( builder , % H264 { } , _output_format ) do
231+ builder |> child ( :raw_video_converter , % SWScale.Converter { format: :I420 } )
232+ end
233+
234+ defp maybe_plug_swscale_converter_vulkan ( builder , _input_format , % H264 { } ) do
235+ builder |> child ( :raw_video_converter , % SWScale.Converter { format: :NV12 } )
236+ end
237+
238+ defp maybe_plug_swscale_converter_vulkan ( builder , input_format , output_format ) ,
239+ do: maybe_plug_swscale_converter ( builder , input_format , output_format )
240+
150241 defp maybe_plug_swscale_converter ( builder , input_format , % RawVideo { } = output_format ) do
151242 case input_format do
152243 _any when output_format . pixel_format == nil ->
@@ -175,10 +266,20 @@ defmodule Membrane.Transcoder.Video do
175266 end
176267 end
177268
178- defp maybe_plug_swscale_converter ( builder , _input_format , _output_format ) do
269+ defp maybe_plug_swscale_converter ( builder , _input_format , _output_format ) , do: builder
270+
271+ defp maybe_plug_encoder_and_parser_vulkan ( builder , % H264 { } = h264 ) do
179272 builder
273+ |> child ( :vk_h264_encoder , Membrane.VKVideo.Encoder )
274+ |> child ( :h264_output_parser , % H264.Parser {
275+ output_stream_structure: stream_structure_type ( h264 ) ,
276+ output_alignment: h264 . alignment
277+ } )
180278 end
181279
280+ defp maybe_plug_encoder_and_parser_vulkan ( builder , format ) ,
281+ do: maybe_plug_encoder_and_parser ( builder , format )
282+
182283 defp maybe_plug_encoder_and_parser ( builder , % H264 { } = h264 ) do
183284 builder
184285 |> child ( :h264_encoder , % H264.FFmpeg.Encoder { preset: :ultrafast } )
@@ -219,9 +320,7 @@ defmodule Membrane.Transcoder.Video do
219320 builder |> child ( :vp8_encoder , % VP9.Encoder { g_threads: number_of_threads , cpu_used: 15 } )
220321 end
221322
222- defp maybe_plug_encoder_and_parser ( builder , % RawVideo { } ) do
223- builder
224- end
323+ defp maybe_plug_encoder_and_parser ( builder , % RawVideo { } ) , do: builder
225324
226325 defp stream_structure_type ( % h26x { stream_structure: stream_structure } )
227326 when h26x in [ H264 , H265 ] do
0 commit comments