FFGear can be used for real-time AI/ML video inference with several built-in optimization techniques for improving throughput, reducing latency, and lowering compute usage.
FFGear Keyframes (I-frames) optimization in action!
Here's an example of using FFGear to optimize YOLOv10-Nano model inference by processing only Keyframes (I-frames) while skipping all non-keyframes (P/B-frames), reducing unnecessary compute usage and saving the annotated output as an Optimized GIF with the WriteGear API:
This example requires the latest ultralytics package
Install or upgrade the ultralytics package with pip:
# import required librariesfromvidgear.gearsimportFFGearfromvidgear.gearsimportWriteGearfromultralyticsimportYOLO# Initialize YOLOv10-Nano modelmodel=YOLO("yolov10n.pt")# Configure FFGear with per-frame metadata extraction enableoptions={"-extract_metadata":True}stream=FFGear(source="myvideo.mp4",frame_format="bgr24",logging=True,**options).start()# Add additional required FFmpeg parameters for Optimized GIFoutput_params={"-filter_complex":"[0:v] fps=10,scale=640:-1:flags=lanczos,split [a][b];[a] palettegen [p];[b][p] paletteuse","-vcodec":None,# let FFmpeg auto-select the best video encoder for the output (e.g. GIF)}# Define writer with defined parameterswriter=WriteGear(output="output_foo.gif",**output_params)# loop overwhileTrue:# read data from streamoutput=stream.read()# check if end of streamifoutputisNone:break# Unpack the frame and its associated metadataframe,meta=output# --- OPTIMIZATION STEP ---# We skip all non-keyframes to save processing power.# This ensures the model only runs on the most information-dense frames.ifmetaandnotmeta["is_keyframe"]:continue# <-- Skips Non-key frames (P, B-frames)# Log keyframe detailsprint(f"Keyframe #{meta['frame_num']} at {meta['pts_time']:.3f}s")# Perform AI Inference on keyframes (I-frames) only# Because we skip non-keyframes, this heavy task runs significantly less often.results=model(frame)# Annotate the frame with detection boxes and labelsannotated_frame=results[0].plot()# {Insert your custom logic here, e.g., displaying/saving frames or triggering an alert}# writing Annotated frame to writerwriter.write(annotated_frame)# safely close video streamstream.stop()# safely close writerwriter.close()
Using FFGear with WriteGear for YouTube-Live Streaming¶
You can use FFGear with WriteGear to transcode and publish to YouTube Live:
# import required librariesfromvidgear.gearsimportFFGearfromvidgear.gearsimportWriteGearimportcv2# open any valid video source with FFGearstream=FFGear(source="myvideo.mp4",frame_format="bgr24",logging=True).start()# define required FFmpeg parameters for YouTube Liveoutput_params={"-clones":["-f","lavfi","-i","anullsrc"],# add silent audio (required by YT)"-vcodec":"libx264","-preset":"medium","-b:v":"4500k","-bufsize":"512k","-pix_fmt":"yuv420p","-f":"flv",}# [WARNING] Change your YouTube-Live Stream Key here:YOUTUBE_STREAM_KEY="xxxx-xxxx-xxxx-xxxx-xxxx"# Define WriteGear writer with YouTube RTMP addresswriter=WriteGear(output="rtmp://a.rtmp.youtube.com/live2/{}".format(YOUTUBE_STREAM_KEY),logging=True,**output_params)# loop overwhileTrue:# read frames from streamframe=stream.read()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# write frame to writerwriter.write(frame)# safely close video streamstream.stop()# safely close writerwriter.close()
# import required librariesfromvidgear.gearsimportFFGearfromvidgear.gearsimportNetGearimportcv2# open video source with FFGear (e.g. hardware-decoded video file)stream=FFGear(source="myvideo.mp4",frame_format="bgr24",logging=True).start()# define NetGear Server at default address and port# !!! change address '192.168.x.xxx' with your Client's IP address !!!server=NetGear(address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,logging=True,)# loop over until KeyBoard InterruptedwhileTrue:try:# read frames from FFGear streamframe=stream.read()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# send frame to NetGear clientserver.send(frame)exceptKeyboardInterrupt:break# safely close FFGear streamstream.stop()# safely close NetGear serverserver.close()
# import required librariesfromvidgear.gearsimportNetGearimportcv2# define NetGear Client# !!! change address '192.168.x.xxx' with your Server's IP address !!!client=NetGear(receive_mode=True,address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,logging=True,)# loop overwhileTrue:# receive frames from networkframe=client.recv()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# Show output windowcv2.imshow("Output",frame)# check for 'q' key if pressedkey=cv2.waitKey(1)&0xFFifkey==ord("q"):break# close output windowcv2.destroyAllWindows()# safely close NetGear clientclient.close()
# import necessary libsimportuvicorn,asyncio,cv2fromvidgear.gearsimportNetGearfromvidgear.gears.asyncioimportWebGearfromvidgear.gears.asyncio.helperimportreducer# initialize WebGear app without any sourceweb=WebGear(logging=True)# activate JPEG compression for performanceoptions={"jpeg_compression":True,"jpeg_compression_quality":90,"jpeg_compression_fastdct":True,"jpeg_compression_fastupsample":True,}# create custom frame producerasyncdefmy_frame_producer():# Define NetGear Client# !!! change '192.168.x.xxx' with your Server's IP address !!!client=NetGear(receive_mode=True,address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,logging=True,**options,)# loop over frameswhileTrue:# receive frames from networkframe=client.recv()# if NoneTypeifframeisNone:break# {do something with the frame here}# reduce frame size for better performance (optional)frame=awaitreducer(frame,percentage=30,interpolation=cv2.INTER_AREA)# encode as JPEGencodedImage=cv2.imencode(".jpg",frame)[1].tobytes()yield(b"--frame\r\nContent-Type:image/jpeg\r\n\r\n"+encodedImage+b"\r\n")awaitasyncio.sleep(0)# close streamclient.close()# assign custom frame producer to WebGear configweb.config["generator"]=my_frame_producer# run WebGear app on Uvicorn at http://localhost:8000/uvicorn.run(web(),host="localhost",port=8000)# close app safelyweb.shutdown()
On successfully running this code, the output stream will be displayed at http://localhost:8000/ in your browser.
# import required librariesfromvidgear.gearsimportFFGearfromvidgear.gearsimportNetGearimportcv2# activate JPEG compression for performanceoptions={"jpeg_compression":True,"jpeg_compression_quality":90,"jpeg_compression_fastdct":True,"jpeg_compression_fastupsample":True,}# open video source with FFGearstream=FFGear(source="myvideo.mp4",frame_format="bgr24",logging=True).start()# Define NetGear Server# !!! change '192.168.x.xxx' with your Client's IP address !!!server=NetGear(address="192.168.x.xxx",port="5454",protocol="tcp",pattern=1,logging=True,**options)# loop over until KeyBoard InterruptedwhileTrue:try:# read frames from FFGearframe=stream.read()# check for frame if NonetypeifframeisNone:break# {do something with the frame here}# send frame to clientserver.send(frame)exceptKeyboardInterrupt:break# safely close FFGear streamstream.stop()# safely close NetGear serverserver.close()