Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Nitan Alexandru Marcel
    @nitanmarcel
    Is this possible without revolving around subprocesses?
    NewUserHa
    @NewUserHa
    ffmpeg cli is good in your case
    quantotto
    @quantotto
    @nitanmarcel pyav allows re-encoding / transcoding the stream in memory (if io.BytesIO) is used for output buffer. It will not create any subprocesses and will use libav libraries. If you already use ffmpeg, you can definitely translate command line into a program that uses pyav. It allows supplying options by passing options dictionary to av.open method
    Nitan Alexandru Marcel
    @nitanmarcel
    @quantotto thanks, I'll take a look into it
    NewUserHa
    @NewUserHa
    container_out = av.open('udp://224.0.0.1:999?overrun_nonfatal=1', format='mpegts', mode='w')
    video_stream = container_out.add_stream('libx264', 30)
    video_stream.low_delay = True
    video_stream.width = 1280
    video_stream.height = 720
    video_stream.options = {'preset': 'veryfast', 'tune': 'film,zerolatency'}
    
    graph = av.filter.Graph()
    
    src0 = graph.add('testsrc', 's=1280x720:r=30')
    f01 = graph.add('drawtext', "text='%{n}@%{localtime}@%{pts}':y=190:fontsize=20")
    f02 = graph.add('format','pix_fmts=yuv420p')
    f03 = graph.add('scale', '640:360:flags=lanczos')
    
    src1 = graph.add('testsrc', 's=1280x720:r=30')
    f11 = graph.add('drawtext', "text='%{n}@%{localtime}@%{pts}':y=190:fontsize=20")
    f12 = graph.add('format','pix_fmts=yuv420p')
    f13 = graph.add('scale', '640:360:flags=lanczos')
    
    xstack = graph.add('xstack', 'inputs=2:layout=0_0|w0_0')
    
    src0.link_to(f01)
    f01.link_to(f02)
    f02.link_to(f03)
    f03.link_to(xstack, 0, 0)
    
    src1.link_to(f11)
    f11.link_to(f12)
    f12.link_to(f13)
    f13.link_to(xstack, 0, 1)
    
    xstack.link_to(graph.add('buffersink'))
    graph.configure()
    
    subprocess.Popen(
        """ffplay -f lavfi -i testsrc=r=30 -vf "drawtext=text='%{n}@%{localtime}@%{pts}':y=190:fontsize=20""", 
        shell=True)
    subprocess.Popen(
        """ffplay -fflags nobuffer udp://224.0.0.1:999?overrun_nonfatal=1""",
        shell=True)
    while 1:
        for packet in video_stream.encode(xstack.pull()):
            container_out.mux(packet)
    Why does streaming latency of this code keep increasing forever? any ideas?
    the latency = the %{localtime} in ffplay -i testsrc and ffplay udp://
    is it because that the PYTHON is slow?
    arsserpentarium
    @arsserpentarium
    Hello. Do anybody have example, how to record video with sound?
    quantotto
    @quantotto
    @NewUserHa it is probably less about Python, but more about encoding speed. If your encoding pipeline is slow indeed, most of the chances it is CPU bound. Check if you have one of the cores maxed out at 100% while running your code. I saw similar issues on weaker machines, like Raspberry Pi.
    NewUserHa
    @NewUserHa
    @quantotto But no, overall cpu usage ~40%, and all logical core usage <70%.
    @quantotto would you like to try that code?
    quantotto
    @quantotto
    @NewUserHa do I just replace 224.0.0.1 with localhost?
    quantotto
    @quantotto
    @NewUserHa I am not sure how graphs work exactly in AV, but it is probably some logic issue rather than performance. If you change rate to 2 from 30 everything becomes even slower. So, it seems that rate affects how often new frames are pushed and the localtime remains the same even longer than with rate 30. I'd check this rate logic.
    Zeyu Dong
    @dong-zeyu

    Hello everyone, I have problem trying to remux a raw h264 stream to mp4. That is what I'm currently dong.

    avin = av.open("test.h264", "r", "h264")
    avout = av.open("test.mp4", "w", "mp4")
    s = avout.add_stream(template=avin.streams[0], rate=30)
    for pkt in avin.demux():
        pkt.stream = s
        avout.mux(pkt)
    avin.close()
    avout.close()

    However, when I read the output file using ffprobe test.mp4, the stream info shows

    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 720x480, 278198 kb/s, 10868.85 fps, 12800 tbr, 12800 tbn, 25600 tbc (default)

    The fps is too large to play.
    It seems that raw h264 stream dose not contain the information of the fps and pts data, but I know the actual fps is 30. How to tell the demuxer this information?

    Nitan Alexandru Marcel
    @nitanmarcel
    I've got a small problem with av.open. I'm passing to it an audio stream from fmstream.org and the container reaches eof early and the stream stops. Am I doing something wrong or?
    quantotto
    @quantotto
    @dong-zeyu yes, you have to calculate pts / dts yourself. Something like below worked for me:
    import av
    avin = av.open("test.264", "r", "h264")
    avout = av.open("test.mp4", "w", format="mp4")
    avout.add_stream(template=avin.streams[0])
    time_base = int(1 / avin.streams[0].time_base)
    rate = avin.streams[0].base_rate
    ts_inc = int(time_base / rate)
    ts = 0
    for pkt in avin.demux():
        pkt.pts = ts
        pkt.dts = ts
        avout.mux(pkt)
        ts += ts_inc
    avin.close()
    avout.close()
    @nitanmarcel could you share what exactly are you trying to open? which URL etc. Basically, code snippet that doesn't work
    Nitan Alexandru Marcel
    @nitanmarcel
    And about the snippet I removed it but I haven't set an out file instead I've tried to read it frame by frame
    The library I want to use pyav is called tgcalls and here's an example on how it should be used https://github.com/MarshalX/tgcalls/blob/main/examples/restream_using_raw_data.py
    NewUserHa
    @NewUserHa
    @quantotto maybe the pts problem may also solve by filter fps or encoder fps=
    @nitanmarcel the ffmpeg cli may work in that case
    Nitan Alexandru Marcel
    @nitanmarcel
    NewUserHa
    @NewUserHa
    @quantotto no need to replace 224.0.0.1 which is a multicast address and should work fine on most situations for udp
    if slow down the testsrc rate, then the while loop is also be slowed down. so it can also help solve this issue if it's really because the Python is slow.
    should consider other languages maybe I guess?
    Nitan Alexandru Marcel
    @nitanmarcel
    @NewUserHa i know as I'm already using the cli, I'm just looking for alternatives ^^
    NewUserHa
    @NewUserHa
    pyav has issues like the issue I encounter..
    but PYAV transferring audio shouldn't have any issue
    but if you want to read frame by frame, I guess you should caution overflow of ffmpeg libs(PYAV depends) internal's buffer
    Nitan Alexandru Marcel
    @nitanmarcel
    Oh, actually I haven't though of exploring projects that uses pyav, but most probably most of them are about converting files rather than reading from live streams
    NewUserHa
    @NewUserHa
    no. pyav has many streaming use cases as you can see on github issue tracker
    quantotto
    @quantotto
    Whatever works from ffmpeg cli will work through pyav as well. Just need to make sure correct options are supplied and, in some cases, things like pts / dts need to be set manually.
    NewUserHa
    @NewUserHa
    maybe pull from testsrc is using python's main thread??
    quantotto
    @quantotto
    @NewUserHa I don't think that this is the case of slow Python (thought I might be wrong). Most of the processing is happening in libav libraries (in C/C++). It is something related to logic of the graph.
    NewUserHa
    @NewUserHa
    the videoframe pulled from libav is in python's object form which is slow
    and change src rate from 30 to 2 solving the issue may also indicate the reason?
    quantotto
    @quantotto
    @NewUserHa did rate change solve the issue? I saw that localtime lagging even more, but it could be that I didn't run it properly. I didn't have too much time to invest in it
    NewUserHa
    @NewUserHa
    heard you said change src rate from 30 to 2 solving the issue..
    will try to change it to 60 fps later.
    quantotto
    @quantotto
    @NewUserHa what i said: "If you change rate to 2 from 30 everything becomes even slower."
    NewUserHa
    @NewUserHa
    the localtime difference is different with pts difference, also different with frame.
    but from the frame number, the video does delay, but not that much as localtime showed. and pts slower than other's changes is also weired
    quantotto
    @quantotto
    @nitanmarcel the following works fine for me and not reaching end of file. It continuously reads packets from the stream. I had to stop it with CTRL-C; otherwise, it runs endlessly.
    >>> import av
    >>> a = av.open("https://stream.live.vc.bbcmedia.co.uk/bbc_radio_one")
    >>> s = a.streams.audio[0]
    >>> s
    <av.AudioStream #0 mp3float at 48000Hz, stereo, fltp at 0x1c4ce7a9940>
    >>> for pkt in a.demux(s):
    ...     print(pkt.pts)
    ...
    0
    338688
    677376
    1016064
    1354752
    1693440
    2032128
    2370816
    2709504
    ...
    Nitan Alexandru Marcel
    @nitanmarcel
    Thanks I'll try to experiment with that. One last question tho: Calling a.close() will stop the outgoing process?
    quantotto
    @quantotto
    @nitanmarcel a.close() closes file object that you read / write or network connection of streaming. Not sure what you mean by "outgoing process"
    Nitan Alexandru Marcel
    @nitanmarcel
    Ah thanks. I just want to stop the stream without having to ctrl+c
    quantotto
    @quantotto
    You can also break the loop when needed and stop reading packets from demux generator and then call close.
    Nitan Alexandru Marcel
    @nitanmarcel
    @quantotto so I started with something like this:
    async def _start_av(self): input_ = await run_in_executor(av.open, self.url, options={"format": "s16le", "acodec": "pcm_s16le", "ac": "2", "ar": "48k"}) for frame in input_.decode(): if frame: self._fifo.write(frame)
    wait

    So I've started with something like this:

    self._fifo = av.AudioFifo(format="s16le")
    
    def _start_av(self):
    input_ = av.open(self.url, options={"format": "s16le", "acodec": "pcm_s16le", "ac": "2", "ar": "48k"})
    for frame in input_decode():
        if frame:
            self._fifo.write(frame)
    
    def read(self, length):
        data = self._fifo.read(length)
        if data:
            data = data.to_ndarray().tobytes()
        return data # returns the data to the library

    But I have a small problem, the data received from the AudioFifo is bigger than the one requested

    or wait, maybe I'm getting the AudioFifo wrong
    Nitan Alexandru Marcel
    @nitanmarcel
    Wait, can in this example self._fifo be any object that has a write method similar to bytesio?