PyAV-Org / PyAV

Pythonic bindings for FFmpeg's libraries.
https://pyav.basswood-io.com/
BSD 3-Clause "New" or "Revised" License
2.44k stars 358 forks source link

got duplicate dts data when encoded a frame from camera #1090

Closed allenling closed 1 year ago

allenling commented 1 year ago

Overview

my program reads frames from a camera, then encodes frames and writes data into a mp4 file.

but when i encoded a frame, i got a error:

last error log: [mp4] Application provided invalid, non monotonically increasing dts to muxer in stream 0

the duplicate packets:

[<av.Packet of #0, dts=33991907, pts=33991907; 31193 bytes at 0x179fd53de08>] [<av.Packet of #0, dts=33991907, pts=33991907; 34806 bytes at 0x179fd53df48>]

how can i handle this error correctly?

def read_and_write():
    codec_name = "h264_nvenc"
    codec_conf = {"bit_rate": 2 * 1024 * 1024,
                  "width": 1920,
                  "height": 1080,
                  "framerate": 30,
                  "pix_fmt": "yuv420p",
                  }
    codec_opts = {"cq": "28",
                  "profile": "high",
                  "preset": "llhq",
                  "rc": "vbr"
                  }
    avopen_options = {"video_size": "1920x1080",
                      "framerate": "30",
                      }
    camera_name = "Live Camera"
    #
    t = int(datetime.datetime.now().timestamp())
    output_video_name = f"{camera_name}_{t}.mp4"
    # print(output_video_name)
    output_container = av.open(output_video_name, 'w')
    out_stream = output_container.add_stream(codec_name, codec_conf["framerate"], options=codec_opts, **codec_conf)
    #
    input_container = av.open(file=f"video={camera_name}", format="dshow", options=avopen_options)
    j = 0
    for packet in input_container.demux(video=0):
        if j == 100:
            break
        j += 1
        for frame in packet.decode():
            wpackets = out_stream.encode(frame)
            output_container.mux(wpackets)
    # flush
    packets = out_stream.encode(None)
    output_container.mux(packets)
    output_container.close()
    input_container.close()
    return

Versions

allenling commented 1 year ago

ok, just reset frame.pts and frame.time_base before you encode the frame

        for frame in packet.decode():
            frame.pts = None
            frame.time_base = None
            wpackets = out_stream.encode(frame)
            output_container.mux(wpackets)