def roundtrip_audio(self, codec, output_layout, output_sample_rate, drop=[]): """ Round-trip an AudioFrame through encoder then decoder. """ encoder = get_encoder(codec) decoder = get_decoder(codec) input_frames = self.create_audio_frames( layout="mono", sample_rate=8000, count=10 ) output_sample_count = int(output_sample_rate * AUDIO_PTIME) for i, frame in enumerate(input_frames): # encode packages, timestamp = encoder.encode(frame) if i not in drop: # depacketize data = b"" for package in packages: data += depayload(codec, package) # decode frames = decoder.decode(JitterFrame(data=data, timestamp=timestamp)) self.assertEqual(len(frames), 1) self.assertEqual(frames[0].format.name, "s16") self.assertEqual(frames[0].layout.name, output_layout) self.assertEqual(frames[0].samples, output_sample_rate * AUDIO_PTIME) self.assertEqual(frames[0].sample_rate, output_sample_rate) self.assertEqual(frames[0].pts, i * output_sample_count) self.assertEqual( frames[0].time_base, fractions.Fraction(1, output_sample_rate) )
def test_encoder(self): encoder = get_encoder(H264_CODEC) self.assertTrue(isinstance(encoder, H264Encoder)) frame = self.create_video_frame(width=640, height=480, pts=0) packages, timestamp = encoder.encode(frame) self.assertGreaterEqual(len(packages), 1)
def test_encoder(self): encoder = get_encoder(H264_CODEC) self.assertTrue(isinstance(encoder, H264Encoder)) frame = VideoFrame(width=640, height=480) packages = encoder.encode(frame) self.assertGreaterEqual(len(packages), 1)
def test_encoder_large(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, Vp8Encoder)) # first keyframe frame = VideoFrame(width=2560, height=1920) frame.pts = 0 frame.time_base = VIDEO_TIME_BASE payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 7) self.assertEqual(len(payloads[0]), 1300) self.assertEqual(timestamp, 0) # delta frame frame = VideoFrame(width=2560, height=1920) frame.pts = 3000 frame.time_base = VIDEO_TIME_BASE payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) self.assertEqual(timestamp, 3000) # force keyframe frame = VideoFrame(width=2560, height=1920) frame.pts = 6000 frame.time_base = VIDEO_TIME_BASE payloads, timestamp = encoder.encode(frame, force_keyframe=True) self.assertEqual(len(payloads), 7) self.assertEqual(len(payloads[0]), 1300) self.assertEqual(timestamp, 6000)
def roundtrip_audio(self, codec, output_channels, output_sample_rate): """ Round-trip an AudioFrame through encoder then decoder. """ encoder = get_encoder(codec) decoder = get_decoder(codec) # encode frame = AudioFrame(channels=1, data=b'\x00\x00' * 160, sample_rate=8000, timestamp=0) self.assertEqual(len(frame.data), 320) data = encoder.encode(frame) # decode frames = decoder.decode(JitterFrame(data=data, timestamp=0)) self.assertEqual(len(frames), 1) self.assertEqual( len(frames[0].data), output_sample_rate * AUDIO_PTIME * output_channels * 2) self.assertEqual(frames[0].channels, output_channels) self.assertEqual(frames[0].sample_rate, output_sample_rate) self.assertEqual(frames[0].sample_width, 2) self.assertEqual(frames[0].timestamp, 0)
def roundtrip_video(self, codec, width, height): """ Round-trip a VideoFrame through encoder then decoder. """ encoder = get_encoder(codec) decoder = get_decoder(codec) for timestamp in range(0, 90000, 3000): # encode frame = VideoFrame(width=width, height=height) frame.pts = timestamp frame.time_base = VIDEO_TIME_BASE packages, timestamp = encoder.encode(frame) # depacketize data = b'' for package in packages: data += depayload(codec, package) # decode frames = decoder.decode(JitterFrame(data=data, timestamp=timestamp)) self.assertEqual(len(frames), 1) self.assertEqual(frames[0].width, width) self.assertEqual(frames[0].height, height) self.assertEqual(frames[0].pts, timestamp) self.assertEqual(frames[0].time_base, VIDEO_TIME_BASE)
def test_frame_encoder(self): encoder = get_encoder(H264_CODEC) frame = VideoFrame(width=640, height=480) frame.pts = 0 frame.time_base = VIDEO_TIME_BASE packages = list(encoder._encode_frame(frame, False)) self.assertGreaterEqual(len(packages), 3) # first frame must have at least set(p[0] & 0x1f for p in packages).issuperset({ 8, # PPS (picture parameter set) 7, # SPS (session parameter set) 5, # IDR (aka key frame) }) frame = VideoFrame(width=640, height=480) frame.pts = 3000 frame.time_base = VIDEO_TIME_BASE packages = list(encoder._encode_frame(frame, False)) self.assertGreaterEqual(len(packages), 1) # change resolution frame = VideoFrame(width=320, height=240) frame.pts = 6000 frame.time_base = VIDEO_TIME_BASE packages = list(encoder._encode_frame(frame, False)) self.assertGreaterEqual(len(packages), 1)
def roundtrip_video(self, codec, width, height, time_base=VIDEO_TIME_BASE): """ Round-trip a VideoFrame through encoder then decoder. """ encoder = get_encoder(codec) decoder = get_decoder(codec) input_frames = self.create_video_frames( width=width, height=height, count=30, time_base=time_base ) for i, frame in enumerate(input_frames): # encode packages, timestamp = encoder.encode(frame) # depacketize data = b"" for package in packages: data += depayload(codec, package) # decode frames = decoder.decode(JitterFrame(data=data, timestamp=timestamp)) self.assertEqual(len(frames), 1) self.assertEqual(frames[0].width, frame.width) self.assertEqual(frames[0].height, frame.height) self.assertEqual(frames[0].pts, i * 3000) self.assertEqual(frames[0].time_base, VIDEO_TIME_BASE)
def test_encoder_large(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, VpxEncoder)) frame = VideoFrame(width=2560, height=1920) payloads = encoder.encode(frame) self.assertEqual(len(payloads), 7) self.assertEqual(len(payloads[0]), 1300)
def test_encoder(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, VpxEncoder)) frame = VideoFrame(width=320, height=240) payloads = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300)
def test_encoder_mono_8hz(self): encoder = get_encoder(PCMA_CODEC) self.assertTrue(isinstance(encoder, PcmaEncoder)) for frame in self.create_audio_frames(channels=1, sample_rate=8000, count=10): payloads, timestamp = encoder.encode(frame) self.assertEqual(payloads, [b'\xd5' * 160]) self.assertEqual(timestamp, frame.pts)
def test_encoder_stereo_48khz(self): encoder = get_encoder(PCMU_CODEC) self.assertTrue(isinstance(encoder, PcmuEncoder)) for frame in self.create_audio_frames(channels=2, sample_rate=48000, count=10): payloads, timestamp = encoder.encode(frame) self.assertEqual(payloads, [b'\xff' * 160]) self.assertEqual(timestamp, frame.pts // 6)
def test_encoder_mono_8hz(self): encoder = get_encoder(PCMA_CODEC) self.assertTrue(isinstance(encoder, PcmaEncoder)) frame = AudioFrame(channels=1, data=b'\x00\x00' * 160, sample_rate=8000) data = encoder.encode(frame) self.assertEqual(data, b'\xd5' * 160)
def test_encoder(self): encoder = get_encoder(H264_CODEC) self.assertTrue(isinstance(encoder, H264Encoder)) frame = VideoFrame(width=640, height=480) frame.pts = 0 frame.time_base = VIDEO_TIME_BASE packages, timestamp = encoder.encode(frame) self.assertGreaterEqual(len(packages), 1)
def test_encoder_stereo_48khz(self): encoder = get_encoder(OPUS_CODEC) self.assertTrue(isinstance(encoder, OpusEncoder)) frame = AudioFrame(channels=2, data=b'\x00\x00' * 2 * 960, sample_rate=48000) data = encoder.encode(frame) self.assertEqual(data, b'\xfc\xff\xfe')
def test_encoder_stereo_8khz(self): encoder = get_encoder(PCMU_CODEC) self.assertTrue(isinstance(encoder, PcmuEncoder)) frame = AudioFrame(channels=2, data=b'\x00\x00' * 2 * 160, sample_rate=8000) data = encoder.encode(frame) self.assertEqual(data, b'\xff' * 160)
def test_encoder_stereo_8khz(self): encoder = get_encoder(PCMU_CODEC) self.assertTrue(isinstance(encoder, PcmuEncoder)) for frame in self.create_audio_frames(layout="stereo", sample_rate=8000, count=10): payloads, timestamp = encoder.encode(frame) self.assertEqual(payloads, [b"\xff" * 160]) self.assertEqual(timestamp, frame.pts)
def test_encoder_stereo_48khz(self): encoder = get_encoder(PCMA_CODEC) self.assertTrue(isinstance(encoder, PcmaEncoder)) frame = AudioFrame(channels=2, data=b'\x00\x00' * 2 * 960, sample_rate=48000, timestamp=0) data = encoder.encode(frame) self.assertEqual(data, b'\xd5' * 160)
def test_encoder_mono_8khz(self): encoder = get_encoder(OPUS_CODEC) self.assertTrue(isinstance(encoder, OpusEncoder)) frame = AudioFrame(channels=1, data=b'\x00\x00' * 160, sample_rate=8000, timestamp=0) data = encoder.encode(frame) self.assertEqual(data, b'\xfc\xff\xfe')
def test_encoder_rgb(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, Vp8Encoder)) frame = self.create_video_frame(width=640, height=480, pts=0, format='rgb24') payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) self.assertEqual(timestamp, 0)
async def _next_encoded_frame(self, codec: RTCRtpCodecParameters): if isinstance(self.__track, EncodedStreamTrack): force_keyframe = self.__force_keyframe self.__force_keyframe = False return await self.__track.recv_encoded(force_keyframe) else: frame = await self.__track.recv() if self.__encoder is None: self.__encoder = get_encoder(codec) force_keyframe = self.__force_keyframe self.__force_keyframe = False return await self.__loop.run_in_executor(None, self.__encoder.encode, frame, force_keyframe)
def test_encoder_stereo_48khz(self): encoder = get_encoder(OPUS_CODEC) self.assertTrue(isinstance(encoder, OpusEncoder)) frames = self.create_audio_frames(layout='stereo', sample_rate=48000, count=2) # first frame payloads, timestamp = encoder.encode(frames[0]) self.assertEqual(payloads, [b'\xfc\xff\xfe']) self.assertEqual(timestamp, 0) # second frame payloads, timestamp = encoder.encode(frames[1]) self.assertEqual(timestamp, 960)
def test_encoder(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, Vp8Encoder)) frame = VideoFrame(width=640, height=480, timestamp=0) payloads = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) # change resolution frame = VideoFrame(width=320, height=240, timestamp=3000) payloads = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300)
def create_rtp_video_packets(self, codec, frames, seq=0): encoder = get_encoder(codec) packets = [] for frame in self.create_video_frames(width=640, height=480, count=frames): payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) packet = RtpPacket(payload_type=codec.payloadType, sequence_number=seq, ssrc=1234, timestamp=timestamp) packet.payload = payloads[0] packet.marker = 1 packets.append(packet) seq = uint16_add(seq, 1) return packets
def test_encoder_target_bitrate(self): encoder = get_encoder(H264_CODEC) self.assertTrue(isinstance(encoder, H264Encoder)) self.assertEqual(encoder.target_bitrate, 1000000) frame = self.create_video_frame(width=640, height=480, pts=0) packages, timestamp = encoder.encode(frame) self.assertGreaterEqual(len(packages), 1) self.assertTrue(len(packages[0]) < 1300) self.assertEqual(timestamp, 0) # change target bitrate encoder.target_bitrate = 1200000 self.assertEqual(encoder.target_bitrate, 1200000) frame = self.create_video_frame(width=640, height=480, pts=3000) packages, timestamp = encoder.encode(frame) self.assertGreaterEqual(len(packages), 1) self.assertTrue(len(packages[0]) < 1300) self.assertEqual(timestamp, 3000)
def test_encoder(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, Vp8Encoder)) frame = VideoFrame(width=640, height=480) frame.pts = 0 frame.time_base = VIDEO_TIME_BASE payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) self.assertEqual(timestamp, 0) # change resolution frame = VideoFrame(width=320, height=240) frame.pts = 3000 frame.time_base = VIDEO_TIME_BASE payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) self.assertEqual(timestamp, 3000)
def test_encoder_target_bitrate(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, Vp8Encoder)) self.assertEqual(encoder.target_bitrate, 500000) frame = self.create_video_frame(width=640, height=480, pts=0) payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) self.assertEqual(timestamp, 0) # change target bitrate encoder.target_bitrate = 600000 self.assertEqual(encoder.target_bitrate, 600000) frame = self.create_video_frame(width=640, height=480, pts=3000) payloads, timestamp = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) self.assertEqual(timestamp, 3000)
def roundtrip_audio(self, codec, output_channels, output_sample_rate, drop=[]): """ Round-trip an AudioFrame through encoder then decoder. """ encoder = get_encoder(codec) decoder = get_decoder(codec) input_frames = self.create_audio_frames(channels=1, sample_rate=8000, count=10) output_sample_count = int(output_sample_rate * AUDIO_PTIME) for i, frame in enumerate(input_frames): # encode self.assertEqual(len(frame.data), 320) packages, timestamp = encoder.encode(frame) if i not in drop: # depacketize data = b'' for package in packages: data += depayload(codec, package) # decode frames = decoder.decode( JitterFrame(data=data, timestamp=timestamp)) self.assertEqual(len(frames), 1) self.assertEqual( len(frames[0].data), output_sample_rate * AUDIO_PTIME * output_channels * 2) self.assertEqual(frames[0].channels, output_channels) self.assertEqual(frames[0].sample_rate, output_sample_rate) self.assertEqual(frames[0].sample_width, 2) self.assertEqual(frames[0].pts, i * output_sample_count) self.assertEqual(frames[0].time_base, fractions.Fraction(1, output_sample_rate))
def test_encoder_buffering(self): create_encoder_context = h264.create_encoder_context def mock_create_encoder_context(*args, **kwargs): codec, _ = create_encoder_context(*args, **kwargs) return FragmentedCodecContext(codec), True h264.create_encoder_context = mock_create_encoder_context try: encoder = get_encoder(H264_CODEC) self.assertTrue(isinstance(encoder, H264Encoder)) frame = self.create_video_frame(width=640, height=480, pts=0) packages, timestamp = encoder.encode(frame) self.assertEqual(len(packages), 0) frame = self.create_video_frame(width=640, height=480, pts=3000) packages, timestamp = encoder.encode(frame) self.assertGreaterEqual(len(packages), 1) finally: h264.create_encoder_context = create_encoder_context
def test_encoder_large(self): encoder = get_encoder(VP8_CODEC) self.assertTrue(isinstance(encoder, Vp8Encoder)) # first keyframe frame = VideoFrame(width=2560, height=1920, timestamp=0) payloads = encoder.encode(frame) self.assertEqual(len(payloads), 7) self.assertEqual(len(payloads[0]), 1300) # delta frame frame = VideoFrame(width=2560, height=1920, timestamp=3000) payloads = encoder.encode(frame) self.assertEqual(len(payloads), 1) self.assertTrue(len(payloads[0]) < 1300) # force keyframe frame = VideoFrame(width=2560, height=1920, timestamp=6000) payloads = encoder.encode(frame, force_keyframe=True) self.assertEqual(len(payloads), 7) self.assertEqual(len(payloads[0]), 1300)