def test_pts_simple(self): fifo = av.AudioFifo() iframe = av.AudioFrame(samples=1024) iframe.pts = 0 iframe.sample_rate = 48000 iframe.time_base = "1/48000" fifo.write(iframe) oframe = fifo.read(512) self.assertTrue(oframe is not None) self.assertEqual(oframe.pts, 0) self.assertEqual(oframe.time_base, iframe.time_base) self.assertEqual(fifo.samples_written, 1024) self.assertEqual(fifo.samples_read, 512) self.assertEqual(fifo.pts_per_sample, 1.0) iframe.pts = 1024 fifo.write(iframe) oframe = fifo.read(512) self.assertTrue(oframe is not None) self.assertEqual(oframe.pts, 512) self.assertEqual(oframe.time_base, iframe.time_base) iframe.pts = 9999 # Wrong! self.assertRaises(ValueError, fifo.write, iframe)
def test_data(self): container = av.open( fate_suite("audio-reference/chorusnoise_2ch_44kHz_s16.wav")) stream = container.streams.audio[0] fifo = av.AudioFifo() input_ = [] output = [] for i, packet in enumerate(container.demux(stream)): for frame in packet.decode(): input_.append(bytes(frame.planes[0])) fifo.write(frame) for frame in fifo.read_many(512, partial=i == 10): output.append(bytes(frame.planes[0])) if i == 10: break input_ = b"".join(input_) output = b"".join(output) min_len = min(len(input_), len(output)) self.assertTrue(min_len > 10 * 512 * 2 * 2) self.assertTrue(input_[:min_len] == output[:min_len])
def player_worker(loop, container, audio_track, video_track, quit_event, throttle_playback): audio_fifo = av.AudioFifo() audio_format = av.AudioFormat('s16') audio_sample_rate = 48000 audio_samples = 0 audio_samples_per_frame = int(audio_sample_rate * AUDIO_PTIME) audio_resampler = av.AudioResampler( format=audio_format, rate=audio_sample_rate) video_first_pts = None frame_time = None start_time = time.time() while not quit_event.is_set(): try: frame = next(container.decode()) except (av.AVError, StopIteration): if audio_track: asyncio.run_coroutine_threadsafe(audio_track._queue.put(None), loop) if video_track: asyncio.run_coroutine_threadsafe(video_track._queue.put(None), loop) break # read up to 1 second ahead if throttle_playback: elapsed_time = (time.time() - start_time) if frame_time and frame_time > elapsed_time + 1: time.sleep(0.1) if isinstance(frame, AudioFrame) and audio_track: if frame.format != audio_format or frame.sample_rate != audio_sample_rate: frame.pts = None frame = audio_resampler.resample(frame) # fix timestamps frame.pts = audio_samples frame.time_base = fractions.Fraction(1, audio_sample_rate) audio_samples += frame.samples audio_fifo.write(frame) while True: frame = audio_fifo.read(audio_samples_per_frame) if frame: frame_time = frame.time asyncio.run_coroutine_threadsafe(audio_track._queue.put(frame), loop) else: break elif isinstance(frame, VideoFrame) and video_track: # video from a webcam doesn't start at pts 0, cancel out offset if frame.pts is not None: if video_first_pts is None: video_first_pts = frame.pts frame.pts -= video_first_pts frame_time = frame.time asyncio.run_coroutine_threadsafe(video_track._queue.put(frame), loop)
def test_missing_time_base(self): fifo = av.AudioFifo() iframe = av.AudioFrame(samples=1024) iframe.pts = 0 iframe.sample_rate = 48000 fifo.write(iframe) oframe = fifo.read(512) self.assertTrue(oframe is not None) self.assertIsNone(oframe.pts) self.assertIsNone(oframe.time_base) self.assertEqual(oframe.sample_rate, iframe.sample_rate)
def test_pts_complex(self): fifo = av.AudioFifo() iframe = av.AudioFrame(samples=1024) iframe.pts = 0 iframe.sample_rate = 48000 iframe.time_base = "1/96000" fifo.write(iframe) iframe.pts = 2048 fifo.write(iframe) oframe = fifo.read_many(1024)[-1] self.assertEqual(oframe.pts, 2048) self.assertEqual(fifo.pts_per_sample, 2.0)
def player_worker(loop, container, streams, audio_track, video_track, quit_event, throttle_playback): audio_fifo = av.AudioFifo() audio_format_name = "s16" audio_layout_name = "stereo" audio_sample_rate = 48000 audio_samples = 0 audio_samples_per_frame = int(audio_sample_rate * AUDIO_PTIME) audio_resampler = av.AudioResampler(format=audio_format_name, layout=audio_layout_name, rate=audio_sample_rate) video_first_pts = None frame_time = None start_time = time.time() while not quit_event.is_set(): try: frame = next(container.decode(*streams)) except (av.AVError, StopIteration) as exc: if isinstance(exc, av.FFmpegError) and exc.errno == errno.EAGAIN: time.sleep(0.01) continue if audio_track: asyncio.run_coroutine_threadsafe(audio_track._queue.put(None), loop) if video_track: asyncio.run_coroutine_threadsafe(video_track._queue.put(None), loop) break # read up to 1 second ahead if throttle_playback: elapsed_time = time.time() - start_time if frame_time and frame_time > elapsed_time + 1: time.sleep(0.1) if isinstance(frame, AudioFrame) and audio_track: if (frame.format.name != audio_format_name or frame.layout.name != audio_layout_name or frame.sample_rate != audio_sample_rate): frame.pts = None frame = audio_resampler.resample(frame) # fix timestamps frame.pts = audio_samples frame.time_base = fractions.Fraction(1, audio_sample_rate) audio_samples += frame.samples audio_fifo.write(frame) while True: frame = audio_fifo.read(audio_samples_per_frame) if frame: frame_time = frame.time asyncio.run_coroutine_threadsafe( audio_track._queue.put(frame), loop) else: break elif isinstance(frame, VideoFrame) and video_track: if frame.pts is None: # pragma: no cover logger.warning( "MediaPlayer(%s) Skipping video frame with no pts", container.name) continue # video from a webcam doesn't start at pts 0, cancel out offset if video_first_pts is None: video_first_pts = frame.pts frame.pts -= video_first_pts frame_time = frame.time asyncio.run_coroutine_threadsafe(video_track._queue.put(frame), loop)
def worker(player, loop, container, streams, tracks, lock_tracks, quit_event, throttle_playback, audio_effect, video_effect): import fractions import time audio_fifo = av.AudioFifo() audio_format_name = "s16" audio_layout_name = "stereo" audio_sample_rate = 48000 audio_samples = 0 audio_samples_per_frame = int(audio_sample_rate * AUDIO_PTIME) audio_resampler = av.AudioResampler(format=audio_format_name, layout=audio_layout_name, rate=audio_sample_rate) video_first_pts = None audio_frame_time = None start_time = time.time() audio_print_warning = True video_print_warning = True def iter_tracks(kind=None): with lock_tracks: for track in tracks: track = track() if track is not None: if kind is None or kind == track.kind: yield track def cleanup_tracks(): with lock_tracks: to_remove = {track for track in tracks if track() is None} for track in to_remove: tracks.discard(track) def run_threadsafe(coro): asyncio.run_coroutine_threadsafe(coro, loop) def append_frame(frame, kind=None, force=True): for track in iter_tracks(kind=kind): if track._queue.full(): # remove one frame and append the new frame if force: run_threadsafe(track._queue.get()) run_threadsafe(track._queue.put(frame)) else: run_threadsafe(track._queue.put(frame)) while not quit_event.is_set(): # clean invalid ref cleanup_tracks() # decode frame try: frame = next(container.decode(*streams)) except (av.AVError, StopIteration): for track in iter_tracks(): append_frame(None, force=True) break # read up to 1 second ahead if throttle_playback: elapsed_time = time.time() - start_time if audio_frame_time and audio_frame_time > elapsed_time + 1: time.sleep(0.1) # audio if isinstance(frame, av.AudioFrame) and (set(iter_tracks('audio')) or player.always_running): if (frame.format.name != audio_format_name or frame.layout.name != audio_layout_name or frame.sample_rate != audio_sample_rate): frame.pts = None frame = audio_resampler.resample(frame) # fix timestamps frame.pts = audio_samples frame.time_base = fractions.Fraction(1, audio_sample_rate) audio_samples += frame.samples # apply audio effect if audio_effect is not None: try: frame = audio_effect(loop, frame) audio_print_warning = True except BaseException: if audio_print_warning: logger.exception('Failed to apply audio effect') audio_print_warning = False audio_fifo.write(frame) while True: frame = audio_fifo.read(audio_samples_per_frame) if frame: audio_frame_time = frame.time append_frame(frame, 'audio') else: break # video if isinstance(frame, av.VideoFrame) and (set(iter_tracks('video')) or player.always_running): if frame.pts is None: # pragma: no cover logger.warning("Skipping video frame with no pts") continue # video from a webcam doesn't start at pts 0, cancel out offset if video_first_pts is None: video_first_pts = frame.pts frame.pts -= video_first_pts # drop frame if too late if throttle_playback: elapsed_time = time.time() - start_time if elapsed_time - frame.time > 0.1: continue # apply video effect if video_effect is not None: try: frame = video_effect(loop, frame) video_print_warning = True except BaseException: if video_print_warning: logger.exception('Failed to apply video effect') video_print_warning = False append_frame(frame, 'video')
import subprocess import time from qtproxy import Q import av parser = argparse.ArgumentParser() parser.add_argument('path') args = parser.parse_args() container = av.open(args.path) stream = next(s for s in container.streams if s.type == 'audio') fifo = av.AudioFifo() resampler = av.AudioResampler( format=av.AudioFormat('s16').packed, layout='stereo', rate=48000, ) qformat = Q.AudioFormat() qformat.setByteOrder(Q.AudioFormat.LittleEndian) qformat.setChannelCount(2) qformat.setCodec('audio/pcm') qformat.setSampleRate(48000) qformat.setSampleSize(16) qformat.setSampleType(Q.AudioFormat.SignedInt)
arg_parser.add_argument('path') arg_parser.add_argument('-p', '--play', action='store_true') arg_parser.add_argument('-d', '--data', action='store_true') arg_parser.add_argument('-f', '--format') arg_parser.add_argument('-l', '--layout') arg_parser.add_argument('-r', '--rate', type=int) arg_parser.add_argument('-s', '--size', type=int, default=1024) arg_parser.add_argument('-c', '--count', type=int, default=5) args = arg_parser.parse_args() ffplay = None container = av.open(args.path) stream = next(s for s in container.streams if s.type == 'audio') fifo = av.AudioFifo() if args.size else None resampler = av.AudioResampler( format=av.AudioFormat(args.format or stream.format.name).packed if args.format else None, layout=int(args.layout) if args.layout and args.layout.isdigit() else args.layout, rate=args.rate, ) if (args.format or args.layout or args.rate) else None read_count = 0 fifo_count = 0 sample_count = 0 for i, packet in enumerate(container.demux(stream)): for frame in packet.decode():
import os from pytgcalls import GroupCallFactory import pyrogram import telethon import av API_HASH = None API_ID = None CHAT_PEER = '@tgcallschat' # chat or channel where you want to play audio SOURCE = 'input.mp3' # Audio file path or stream url: eg. https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3 CLIENT_TYPE = GroupCallFactory.MTPROTO_CLIENT_TYPE.PYROGRAM # for Telethon uncomment line below #CLIENT_TYPE = GroupCallFactory.MTPROTO_CLIENT_TYPE.TELETHON fifo = av.AudioFifo(format='s16le') resampler = av.AudioResampler(format='s16', layout='stereo', rate=48000) def on_played_data(gc, length): data = fifo.read(length / 4) if data: data = data.to_ndarray().tobytes() return data async def main(client): await client.start() while not client.is_connected: await asyncio.sleep(1)