diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/BdfFontFile.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/BdfFontFile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c384b989ddf392e27a156d6b8e87a4f4d57b09d5 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/BdfFontFile.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a8bd5278ab4ed3bcc200bad70ff33159b3848ad Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95c620b168d6cc9cc1fb042407315fe89ff7c738 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ContainerIO.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ContainerIO.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3af2725bf76826e79aea402e8ca7e5786af32b6 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ContainerIO.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/CurImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/CurImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f62628e2cf6055b32350b2a04d2bb73dacc5ab62 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/CurImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4d89300d91f3fe9cba0e7e0572d299ef91cc2ba Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5adbebb64af16d866e542d17cfba6124623e6c62 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ExifTags.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ExifTags.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad2865e2737778eb8d8f93d518919e806f1b08cf Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ExifTags.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06016993ce2cc8cc1e1717846a334414938aee6a Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/FliImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FliImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eae3d991e88078f4eb7ea66361224bc857d84574 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FliImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/FontFile.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FontFile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d8d4573a469c72fa5df63b984d00cb485d2c714 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FontFile.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2d4cbc8318527c22b6d5c3b1621c9c76b89b7e9 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39397dee2002b9e5a985db4d7b241bbcf39a4e33 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..792443cb290ed6547a1aee5ce80282812675c702 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/GdImageFile.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/GdImageFile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..306a3a46e579c2e2e44296c3bb3208e6b6da626b Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/GdImageFile.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/GifImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/GifImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fce42c09906e23909adc6aee0d555e15ca50f79f Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/GifImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c38b150adfe061ef17e78faa78d62cf26e77e280 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3cc145eda9be770bf8895730b8e43ad3961f2e0 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageCms.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageCms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..915d97b85546acfcf4ec2e737e22b066c258c7ab Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageCms.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageColor.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageColor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f677a0ffcf0228de70a145a5ea0e5d45bb06b4b4 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageColor.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageDraw2.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageDraw2.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57cc68deff44de23f546fed1c81e6b2cf493fc7c Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageDraw2.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageEnhance.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageEnhance.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bae7d8d9325f3797d1a6d4bc9be22e8b352b005b Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageEnhance.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFile.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aafdef88d46a062f513a593d44353b3ed0884a10 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFile.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFilter.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFilter.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cf5b74ee8862e182b04f5430419fc00f08ce7c8 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFilter.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFont.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFont.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3eeb42b21d336e2c3244e27ce7904143770e3ca Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageFont.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageGrab.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageGrab.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..617c458cdea08bba4e4cb8349a043b645b8ba81a Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageGrab.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMath.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMath.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1df594ffe576e26cb1bf69522bc5af2911f703e6 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMath.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMode.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMode.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..535ac25eb95b165d28a0ab35e413009f3c2a008d Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMode.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMorph.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMorph.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..820b27ccb0ee682e88dc5fc26f8c2b06fc36c9e8 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageMorph.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageOps.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageOps.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..219cd5ca6d8a07944f1e916b3c830c32cab6f402 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageOps.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImagePalette.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImagePalette.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a217620ef0e76a57ca16fb7e4ceb1196520c3eb Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImagePalette.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImagePath.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImagePath.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..243b8e51eccfda1a105c9ac9252296a6bfd839ed Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImagePath.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageTk.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageTk.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40f84055d8baad20e0bb5f60c22b16fe1a9714a9 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageTk.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageTransform.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageTransform.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9411618a029b161dba66647ebd77b68d16e9a1fe Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageTransform.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageWin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageWin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e02c57cc2559450b2dcbc5766d60207fead73def Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImageWin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f772d38be614c67966d315c17579dd8e5660ad38 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89acbea0f40ae57fe86e9d6d2759686915adf436 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d81f80a5bafe6ce357bbeb0a34aded70afd83f20 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/MicImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/MicImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab88e82c8452c42f796910bcb11cbd554038a293 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/MicImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..734813d12932f86c74077d2f8c8013cb2a58571d Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..563e02fb77612f18dd1983137560be0c45dc5e44 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3975b32ff4f0a922d809384a1cd152d78f35b4e Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dd6fc730d3ba56a2228cf5742cdcd227dc0512e Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dbfd88b607f8cf27bdb6a5379ce8bbbe4f879585 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PdfParser.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PdfParser.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e49ffd4b3c5ded2e45f843bacef66e9a000bb53e Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PdfParser.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8005fbf6f88b25a62128454c0a7e175a3acf4d0 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PngImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PngImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c549755babaea9c1cce9007cc3b9cdd38691364b Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PngImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..111f4fc63db0f2fa50cbc76addf14d9e50e99daa Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c89953e62361fe48810a3280502aeaf668f194d Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/PyAccess.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PyAccess.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9640e79ac51f7a7a0ae61ad0362ca6893ec4882 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/PyAccess.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b450167fb7ad969b91c7a1e717d4adaf1765c33e Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/TiffTags.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/TiffTags.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7fbf8d8e38259b33cbc0fd9dfc20734ecdab4e9 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/TiffTags.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/WalImageFile.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/WalImageFile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a47780f2212b74d04a133002fc69dd28113290d4 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/WalImageFile.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa056b8a71cd343f4a0af8ce48ba7b2cd3b7eac7 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9772087becec72cf3e451412b5645f73f04d8b54 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7c0dadfd025a36e913f5b17fe98823a9ba4bea8 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/__init__.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b756bd9a9652e5b0401f552d8b50df56f77ea7d2 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/__init__.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/_binary.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_binary.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e6f75179dbbd8614455019574dcb75379c4d10d Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_binary.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/_deprecate.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_deprecate.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d9a7ea06a7ad640b6d66e35b84120a6b697a71d Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_deprecate.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/_typing.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_typing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe0d3f3292e25e406a38a5114440a6d4202f9d0c Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_typing.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/_util.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_util.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b907a7a608733bef510150450e3b055fb261fa5 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/_util.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/features.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/features.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..242327b8814f578b0d4e9b39d83a1d030b3e83cc Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/features.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/PIL/__pycache__/report.cpython-311.pyc b/.venv/lib/python3.11/site-packages/PIL/__pycache__/report.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17b8d61c9d2180afd38d9437270bb577a785487c Binary files /dev/null and b/.venv/lib/python3.11/site-packages/PIL/__pycache__/report.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/torio/__init__.py b/.venv/lib/python3.11/site-packages/torio/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..23efa0b2fda2221d721e18a575dd75870e2aece4 --- /dev/null +++ b/.venv/lib/python3.11/site-packages/torio/__init__.py @@ -0,0 +1,8 @@ +from . import _extension # noqa # usort: skip +from . import io, utils + + +__all__ = [ + "io", + "utils", +] diff --git a/.venv/lib/python3.11/site-packages/torio/__pycache__/__init__.cpython-311.pyc b/.venv/lib/python3.11/site-packages/torio/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5874382fc3e8bd49d2a0d7b8f7f0499828e20e02 Binary files /dev/null and b/.venv/lib/python3.11/site-packages/torio/__pycache__/__init__.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/torio/io/__init__.py b/.venv/lib/python3.11/site-packages/torio/io/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7fce6d775278a5e1470d4cf4e2daeeb39f5e5469 --- /dev/null +++ b/.venv/lib/python3.11/site-packages/torio/io/__init__.py @@ -0,0 +1,9 @@ +from ._streaming_media_decoder import StreamingMediaDecoder +from ._streaming_media_encoder import CodecConfig, StreamingMediaEncoder + + +__all__ = [ + "StreamingMediaDecoder", + "CodecConfig", + "StreamingMediaEncoder", +] diff --git a/.venv/lib/python3.11/site-packages/torio/io/__pycache__/__init__.cpython-311.pyc b/.venv/lib/python3.11/site-packages/torio/io/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c85332795da9d758196100688af4c1c0404439ed Binary files /dev/null and b/.venv/lib/python3.11/site-packages/torio/io/__pycache__/__init__.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/torio/io/__pycache__/_streaming_media_decoder.cpython-311.pyc b/.venv/lib/python3.11/site-packages/torio/io/__pycache__/_streaming_media_decoder.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f70fd86e307a420c69523a08882d4264db3ceed Binary files /dev/null and b/.venv/lib/python3.11/site-packages/torio/io/__pycache__/_streaming_media_decoder.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/torio/io/__pycache__/_streaming_media_encoder.cpython-311.pyc b/.venv/lib/python3.11/site-packages/torio/io/__pycache__/_streaming_media_encoder.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9b49b088e27ed3e6c42a266fa4257eb4b957a4b Binary files /dev/null and b/.venv/lib/python3.11/site-packages/torio/io/__pycache__/_streaming_media_encoder.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/torio/io/_streaming_media_decoder.py b/.venv/lib/python3.11/site-packages/torio/io/_streaming_media_decoder.py new file mode 100644 index 0000000000000000000000000000000000000000..8e81b537e7cce56e38da1004e9d3acf01879f9bd --- /dev/null +++ b/.venv/lib/python3.11/site-packages/torio/io/_streaming_media_decoder.py @@ -0,0 +1,978 @@ +from __future__ import annotations + +import os +from dataclasses import dataclass +from pathlib import Path +from typing import BinaryIO, Dict, Iterator, Optional, Tuple, TypeVar, Union + +import torch +import torio +from torch.utils._pytree import tree_map + +ffmpeg_ext = torio._extension.lazy_import_ffmpeg_ext() + +__all__ = [ + "StreamingMediaDecoder", +] + + +@dataclass +class SourceStream: + """The metadata of a source stream, returned by :meth:`~torio.io.StreamingMediaDecoder.get_src_stream_info`. + + This class is used when representing streams of media type other than `audio` or `video`. + + When source stream is `audio` or `video` type, :class:`SourceAudioStream` and + :class:`SourceVideoStream`, which reports additional media-specific attributes, + are used respectively. + """ + + media_type: str + """The type of the stream. + One of ``"audio"``, ``"video"``, ``"data"``, ``"subtitle"``, ``"attachment"`` and empty string. + + .. note:: + Only audio and video streams are supported for output. + .. note:: + Still images, such as PNG and JPEG formats are reported as video. + """ + codec: str + """Short name of the codec. Such as ``"pcm_s16le"`` and ``"h264"``.""" + codec_long_name: str + """Detailed name of the codec. + + Such as "`PCM signed 16-bit little-endian`" and "`H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10`". + """ + format: Optional[str] + """Media format. Such as ``"s16"`` and ``"yuv420p"``. + + Commonly found audio values are; + + - ``"u8"``, ``"u8p"``: Unsigned 8-bit unsigned interger. + - ``"s16"``, ``"s16p"``: 16-bit signed integer. + - ``"s32"``, ``"s32p"``: 32-bit signed integer. + - ``"flt"``, ``"fltp"``: 32-bit floating-point. + + .. note:: + + `p` at the end indicates the format is `planar`. + Channels are grouped together instead of interspersed in memory. + """ + bit_rate: Optional[int] + """Bit rate of the stream in bits-per-second. + This is an estimated values based on the initial few frames of the stream. + For container formats and variable bit rate, it can be 0. + """ + num_frames: Optional[int] + """The number of frames in the stream""" + bits_per_sample: Optional[int] + """This is the number of valid bits in each output sample. + For compressed format, it can be 0. + """ + metadata: Dict[str, str] + """Metadata attached to the source stream.""" + + +@dataclass +class SourceAudioStream(SourceStream): + """The metadata of an audio source stream, returned by :meth:`~torio.io.StreamingMediaDecoder.get_src_stream_info`. + + This class is used when representing audio stream. + + In addition to the attributes reported by :class:`SourceStream`, + the following attributes are reported. + """ + + sample_rate: float + """Sample rate of the audio.""" + num_channels: int + """Number of channels.""" + + +@dataclass +class SourceVideoStream(SourceStream): + """The metadata of a video source stream, returned by :meth:`~torio.io.StreamingMediaDecoder.get_src_stream_info`. + + This class is used when representing video stream. + + In addition to the attributes reported by :class:`SourceStream`, + the following attributes are reported. + """ + + width: int + """Width of the video frame in pixel.""" + height: int + """Height of the video frame in pixel.""" + frame_rate: float + """Frame rate.""" + + +def _parse_si(i): + media_type = i.media_type + if media_type == "audio": + return SourceAudioStream( + media_type=i.media_type, + codec=i.codec_name, + codec_long_name=i.codec_long_name, + format=i.format, + bit_rate=i.bit_rate, + num_frames=i.num_frames, + bits_per_sample=i.bits_per_sample, + metadata=i.metadata, + sample_rate=i.sample_rate, + num_channels=i.num_channels, + ) + if media_type == "video": + return SourceVideoStream( + media_type=i.media_type, + codec=i.codec_name, + codec_long_name=i.codec_long_name, + format=i.format, + bit_rate=i.bit_rate, + num_frames=i.num_frames, + bits_per_sample=i.bits_per_sample, + metadata=i.metadata, + width=i.width, + height=i.height, + frame_rate=i.frame_rate, + ) + return SourceStream( + media_type=i.media_type, + codec=i.codec_name, + codec_long_name=i.codec_long_name, + format=None, + bit_rate=None, + num_frames=None, + bits_per_sample=None, + metadata=i.metadata, + ) + + +@dataclass +class OutputStream: + """Output stream configured on :class:`StreamingMediaDecoder`, + returned by :meth:`~torio.io.StreamingMediaDecoder.get_out_stream_info`. + """ + + source_index: int + """Index of the source stream that this output stream is connected.""" + filter_description: str + """Description of filter graph applied to the source stream.""" + media_type: str + """The type of the stream. ``"audio"`` or ``"video"``.""" + format: str + """Media format. Such as ``"s16"`` and ``"yuv420p"``. + + Commonly found audio values are; + + - ``"u8"``, ``"u8p"``: Unsigned 8-bit unsigned interger. + - ``"s16"``, ``"s16p"``: 16-bit signed integer. + - ``"s32"``, ``"s32p"``: 32-bit signed integer. + - ``"flt"``, ``"fltp"``: 32-bit floating-point. + + .. note:: + + `p` at the end indicates the format is `planar`. + Channels are grouped together instead of interspersed in memory.""" + + +@dataclass +class OutputAudioStream(OutputStream): + """Information about an audio output stream configured with + :meth:`~torio.io.StreamingMediaDecoder.add_audio_stream` or + :meth:`~torio.io.StreamingMediaDecoder.add_basic_audio_stream`. + + In addition to the attributes reported by :class:`OutputStream`, + the following attributes are reported. + """ + + sample_rate: float + """Sample rate of the audio.""" + num_channels: int + """Number of channels.""" + + +@dataclass +class OutputVideoStream(OutputStream): + """Information about a video output stream configured with + :meth:`~torio.io.StreamingMediaDecoder.add_video_stream` or + :meth:`~torio.io.StreamingMediaDecoder.add_basic_video_stream`. + + In addition to the attributes reported by :class:`OutputStream`, + the following attributes are reported. + """ + + width: int + """Width of the video frame in pixel.""" + height: int + """Height of the video frame in pixel.""" + frame_rate: float + """Frame rate.""" + + +def _parse_oi(i): + media_type = i.media_type + if media_type == "audio": + return OutputAudioStream( + source_index=i.source_index, + filter_description=i.filter_description, + media_type=i.media_type, + format=i.format, + sample_rate=i.sample_rate, + num_channels=i.num_channels, + ) + if media_type == "video": + return OutputVideoStream( + source_index=i.source_index, + filter_description=i.filter_description, + media_type=i.media_type, + format=i.format, + width=i.width, + height=i.height, + frame_rate=i.frame_rate, + ) + raise ValueError(f"Unexpected media_type: {i.media_type}({i})") + + +def _get_afilter_desc(sample_rate: Optional[int], fmt: Optional[str], num_channels: Optional[int]): + descs = [] + if sample_rate is not None: + descs.append(f"aresample={sample_rate}") + if fmt is not None or num_channels is not None: + parts = [] + if fmt is not None: + parts.append(f"sample_fmts={fmt}") + if num_channels is not None: + parts.append(f"channel_layouts={num_channels}c") + descs.append(f"aformat={':'.join(parts)}") + return ",".join(descs) if descs else None + + +def _get_vfilter_desc(frame_rate: Optional[float], width: Optional[int], height: Optional[int], fmt: Optional[str]): + descs = [] + if frame_rate is not None: + descs.append(f"fps={frame_rate}") + scales = [] + if width is not None: + scales.append(f"width={width}") + if height is not None: + scales.append(f"height={height}") + if scales: + descs.append(f"scale={':'.join(scales)}") + if fmt is not None: + descs.append(f"format=pix_fmts={fmt}") + return ",".join(descs) if descs else None + + +# Base class for ChunkTensor +# Based off of TrivialTensorViaComposition +# https://github.com/albanD/subclass_zoo/blob/0eeb1d68fb59879029c610bc407f2997ae43ba0a/trivial_tensors.py#L83 +class ChunkTensorBase(torch.Tensor): + __torch_function__ = torch._C._disabled_torch_function_impl + + @staticmethod + def __new__(cls, _elem, *_): + return super().__new__(cls, _elem) + + @classmethod + def __torch_dispatch__(cls, func, _, args=(), kwargs=None): + def unwrap(t): + return t._elem if isinstance(t, cls) else t + + return func(*tree_map(unwrap, args), **tree_map(unwrap, kwargs)) + + +@dataclass +class ChunkTensor(ChunkTensorBase): + """Decoded media frames with metadata. + + The instance of this class represents the decoded video/audio frames with + metadata, and the instance itself behave like :py:class:`~torch.Tensor`. + + Client codes can pass instance of this class as-if it's + :py:class:`~torch.Tensor` class, or call the methods defined on + :py:class:`~torch.Tensor` class. + + Example: + >>> # Define input streams + >>> reader = StreamingMediaDecoder(...) + >>> reader.add_audio_stream(frames_per_chunk=4000, sample_rate=8000) + >>> reader.add_video_stream(frames_per_chunk=7, frame_rate=28) + >>> # Decode the streams and fetch frames + >>> reader.fill_buffer() + >>> audio_chunk, video_chunk = reader.pop_chunks() + + >>> # Access metadata + >>> (audio_chunk.pts, video_chunks.pts) + (0.0, 0.0) + >>> + >>> # The second time the PTS is different + >>> reader.fill_buffer() + >>> audio_chunk, video_chunk = reader.pop_chunks() + >>> (audio_chunk.pts, video_chunks.pts) + (0.5, 0.25) + + >>> # Call PyTorch ops on chunk + >>> audio_chunk.shape + torch.Size([4000, 2] + >>> power = torch.pow(video_chunk, 2) + >>> + >>> # the result is a plain torch.Tensor class + >>> type(power) + + >>> + >>> # Metadata is not available on the result + >>> power.pts + AttributeError: 'Tensor' object has no attribute 'pts' + """ + + # Keep it private for now + _elem: torch.Tensor + + pts: float + """Presentation time stamp of the first frame in the chunk. + + Unit: second. + """ + + +def _format_doc(**kwargs): + def decorator(obj): + obj.__doc__ = obj.__doc__.format(**kwargs) + return obj + + return decorator + + +_frames_per_chunk = """Number of frames returned as one chunk. + If the source stream is exhausted before enough frames are buffered, + then the chunk is returned as-is. + + Providing ``-1`` disables chunking and :py:func:`pop_chunks` method + will concatenate all the buffered frames and return it.""" + +_buffer_chunk_size = """Internal buffer size. + When the number of chunks buffered exceeds this number, old frames are + dropped. For example, if ``frames_per_chunk`` is 5 and ``buffer_chunk_size`` is + 3, then frames older than ``15`` are dropped. + Providing ``-1`` disables this behavior. + + Default: ``3``.""" + +_audio_stream_index = """The source audio stream index. + If omitted, :py:attr:`default_audio_stream` is used.""" + + +_video_stream_index = """The source video stream index. + If omitted, :py:attr:`default_video_stream` is used.""" + +_decoder = """The name of the decoder to be used. + When provided, use the specified decoder instead of the default one. + + To list the available decoders, please use + :py:func:`~torio.utils.ffmpeg_utils.get_audio_decoders` for audio, and + :py:func:`~torio.utils.ffmpeg_utils.get_video_decoders` for video. + + Default: ``None``.""" + +_decoder_option = """Options passed to decoder. + Mapping from str to str. (Default: ``None``) + + To list decoder options for a decoder, you can use + ``ffmpeg -h decoder=`` command. + + | + + In addition to decoder-specific options, you can also pass options related + to multithreading. They are effective only if the decoder support them. + If neither of them are provided, StreamingMediaDecoder defaults to single thread. + + ``"threads"``: The number of threads (in str). + Providing the value ``"0"`` will let FFmpeg decides based on its heuristics. + + ``"thread_type"``: Which multithreading method to use. + The valid values are ``"frame"`` or ``"slice"``. + Note that each decoder supports different set of methods. + If not provided, a default value is used. + + - ``"frame"``: Decode more than one frame at once. + Each thread handles one frame. + This will increase decoding delay by one frame per thread + - ``"slice"``: Decode more than one part of a single frame at once. + + | + """ + + +_hw_accel = """Enable hardware acceleration. + + When video is decoded on CUDA hardware, for example + `decoder="h264_cuvid"`, passing CUDA device indicator to `hw_accel` + (i.e. `hw_accel="cuda:0"`) will make StreamingMediaDecoder place the resulting + frames directly on the specified CUDA device as CUDA tensor. + + If `None`, the frame will be moved to CPU memory. + Default: ``None``.""" + + +_format_audio_args = _format_doc( + frames_per_chunk=_frames_per_chunk, + buffer_chunk_size=_buffer_chunk_size, + stream_index=_audio_stream_index, + decoder=_decoder, + decoder_option=_decoder_option, +) + + +_format_video_args = _format_doc( + frames_per_chunk=_frames_per_chunk, + buffer_chunk_size=_buffer_chunk_size, + stream_index=_video_stream_index, + decoder=_decoder, + decoder_option=_decoder_option, + hw_accel=_hw_accel, +) + + +InputStreamTypes = TypeVar("InputStream", bound=SourceStream) +OutputStreamTypes = TypeVar("OutputStream", bound=OutputStream) + + +class StreamingMediaDecoder: + """Fetch and decode audio/video streams chunk by chunk. + + For the detailed usage of this class, please refer to the tutorial. + + Args: + src (str, path-like, bytes or file-like object): The media source. + If string-type, it must be a resource indicator that FFmpeg can + handle. This includes a file path, URL, device identifier or + filter expression. The supported value depends on the FFmpeg found + in the system. + + If bytes, it must be an encoded media data in contiguous memory. + + If file-like object, it must support `read` method with the signature + `read(size: int) -> bytes`. + Additionally, if the file-like object has `seek` method, it uses + the method when parsing media metadata. This improves the reliability + of codec detection. The signagure of `seek` method must be + `seek(offset: int, whence: int) -> int`. + + Please refer to the following for the expected signature and behavior + of `read` and `seek` method. + + - https://docs.python.org/3/library/io.html#io.BufferedIOBase.read + - https://docs.python.org/3/library/io.html#io.IOBase.seek + + format (str or None, optional): + Override the input format, or specify the source sound device. + Default: ``None`` (no override nor device input). + + This argument serves two different usecases. + + 1) Override the source format. + This is useful when the input data do not contain a header. + + 2) Specify the input source device. + This allows to load media stream from hardware devices, + such as microphone, camera and screen, or a virtual device. + + + .. note:: + + This option roughly corresponds to ``-f`` option of ``ffmpeg`` command. + Please refer to the ffmpeg documentations for the possible values. + + https://ffmpeg.org/ffmpeg-formats.html#Demuxers + + Please use :py:func:`~torio.utils.ffmpeg_utils.get_demuxers` to list the + demultiplexers available in the current environment. + + For device access, the available values vary based on hardware (AV device) and + software configuration (ffmpeg build). + + https://ffmpeg.org/ffmpeg-devices.html#Input-Devices + + Please use :py:func:`~torio.utils.ffmpeg_utils.get_input_devices` to list + the input devices available in the current environment. + + option (dict of str to str, optional): + Custom option passed when initializing format context (opening source). + + You can use this argument to change the input source before it is passed to decoder. + + Default: ``None``. + + buffer_size (int): + The internal buffer size in byte. Used only when `src` is file-like object. + + Default: `4096`. + """ + + def __init__( + self, + src: Union[str, Path, BinaryIO], + format: Optional[str] = None, + option: Optional[Dict[str, str]] = None, + buffer_size: int = 4096, + ): + self.src = src + if isinstance(src, bytes): + self._be = ffmpeg_ext.StreamingMediaDecoderBytes(src, format, option, buffer_size) + elif hasattr(src, "read"): + self._be = ffmpeg_ext.StreamingMediaDecoderFileObj(src, format, option, buffer_size) + else: + self._be = ffmpeg_ext.StreamingMediaDecoder(os.path.normpath(src), format, option) + + i = self._be.find_best_audio_stream() + self._default_audio_stream = None if i < 0 else i + i = self._be.find_best_video_stream() + self._default_video_stream = None if i < 0 else i + + @property + def num_src_streams(self): + """Number of streams found in the provided media source. + + :type: int + """ + return self._be.num_src_streams() + + @property + def num_out_streams(self): + """Number of output streams configured by client code. + + :type: int + """ + return self._be.num_out_streams() + + @property + def default_audio_stream(self): + """The index of default audio stream. ``None`` if there is no audio stream + + :type: Optional[int] + """ + return self._default_audio_stream + + @property + def default_video_stream(self): + """The index of default video stream. ``None`` if there is no video stream + + :type: Optional[int] + """ + return self._default_video_stream + + def get_metadata(self) -> Dict[str, str]: + """Get the metadata of the source media. + + Returns: + dict + """ + return self._be.get_metadata() + + def get_src_stream_info(self, i: int) -> InputStreamTypes: + """Get the metadata of source stream + + Args: + i (int): Stream index. + Returns: + InputStreamTypes: + Information about the source stream. + If the source stream is audio type, then + :class:`~torio.io._stream_reader.SourceAudioStream` is returned. + If it is video type, then + :class:`~torio.io._stream_reader.SourceVideoStream` is returned. + Otherwise :class:`~torio.io._stream_reader.SourceStream` class is returned. + """ + return _parse_si(self._be.get_src_stream_info(i)) + + def get_out_stream_info(self, i: int) -> OutputStreamTypes: + """Get the metadata of output stream + + Args: + i (int): Stream index. + Returns: + OutputStreamTypes + Information about the output stream. + If the output stream is audio type, then + :class:`~torio.io._stream_reader.OutputAudioStream` is returned. + If it is video type, then + :class:`~torio.io._stream_reader.OutputVideoStream` is returned. + """ + info = self._be.get_out_stream_info(i) + return _parse_oi(info) + + def seek(self, timestamp: float, mode: str = "precise"): + """Seek the stream to the given timestamp [second] + + Args: + timestamp (float): Target time in second. + mode (str): Controls how seek is done. + Valid choices are; + + * "key": Seek into the nearest key frame before the given timestamp. + * "any": Seek into any frame (including non-key frames) before the given timestamp. + * "precise": First seek into the nearest key frame before the given timestamp, then + decode frames until it reaches the closes frame to the given timestamp. + + Note: + All the modes invalidate and reset the internal state of decoder. + When using "any" mode and if it ends up seeking into non-key frame, + the image decoded may be invalid due to lack of key frame. + Using "precise" will workaround this issue by decoding frames from previous + key frame, but will be slower. + """ + modes = { + "key": 0, + "any": 1, + "precise": 2, + } + if mode not in modes: + raise ValueError(f"The value of mode must be one of {list(modes.keys())}. Found: {mode}") + self._be.seek(timestamp, modes[mode]) + + @_format_audio_args + def add_basic_audio_stream( + self, + frames_per_chunk: int, + buffer_chunk_size: int = 3, + *, + stream_index: Optional[int] = None, + decoder: Optional[str] = None, + decoder_option: Optional[Dict[str, str]] = None, + format: Optional[str] = "fltp", + sample_rate: Optional[int] = None, + num_channels: Optional[int] = None, + ): + """Add output audio stream + + Args: + frames_per_chunk (int): {frames_per_chunk} + + buffer_chunk_size (int, optional): {buffer_chunk_size} + + stream_index (int or None, optional): {stream_index} + + decoder (str or None, optional): {decoder} + + decoder_option (dict or None, optional): {decoder_option} + + format (str, optional): Output sample format (precision). + + If ``None``, the output chunk has dtype corresponding to + the precision of the source audio. + + Otherwise, the sample is converted and the output dtype is changed + as following. + + - ``"u8p"``: The output is ``torch.uint8`` type. + - ``"s16p"``: The output is ``torch.int16`` type. + - ``"s32p"``: The output is ``torch.int32`` type. + - ``"s64p"``: The output is ``torch.int64`` type. + - ``"fltp"``: The output is ``torch.float32`` type. + - ``"dblp"``: The output is ``torch.float64`` type. + + Default: ``"fltp"``. + + sample_rate (int or None, optional): If provided, resample the audio. + + num_channels (int, or None, optional): If provided, change the number of channels. + """ + self.add_audio_stream( + frames_per_chunk, + buffer_chunk_size, + stream_index=stream_index, + decoder=decoder, + decoder_option=decoder_option, + filter_desc=_get_afilter_desc(sample_rate, format, num_channels), + ) + + @_format_video_args + def add_basic_video_stream( + self, + frames_per_chunk: int, + buffer_chunk_size: int = 3, + *, + stream_index: Optional[int] = None, + decoder: Optional[str] = None, + decoder_option: Optional[Dict[str, str]] = None, + format: Optional[str] = "rgb24", + frame_rate: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + hw_accel: Optional[str] = None, + ): + """Add output video stream + + Args: + frames_per_chunk (int): {frames_per_chunk} + + buffer_chunk_size (int, optional): {buffer_chunk_size} + + stream_index (int or None, optional): {stream_index} + + decoder (str or None, optional): {decoder} + + decoder_option (dict or None, optional): {decoder_option} + + format (str, optional): Change the format of image channels. Valid values are, + + - ``"rgb24"``: 8 bits * 3 channels (R, G, B) + - ``"bgr24"``: 8 bits * 3 channels (B, G, R) + - ``"yuv420p"``: 8 bits * 3 channels (Y, U, V) + - ``"gray"``: 8 bits * 1 channels + + Default: ``"rgb24"``. + + frame_rate (int or None, optional): If provided, change the frame rate. + + width (int or None, optional): If provided, change the image width. Unit: Pixel. + + height (int or None, optional): If provided, change the image height. Unit: Pixel. + + hw_accel (str or None, optional): {hw_accel} + """ + self.add_video_stream( + frames_per_chunk, + buffer_chunk_size, + stream_index=stream_index, + decoder=decoder, + decoder_option=decoder_option, + filter_desc=_get_vfilter_desc(frame_rate, width, height, format), + hw_accel=hw_accel, + ) + + @_format_audio_args + def add_audio_stream( + self, + frames_per_chunk: int, + buffer_chunk_size: int = 3, + *, + stream_index: Optional[int] = None, + decoder: Optional[str] = None, + decoder_option: Optional[Dict[str, str]] = None, + filter_desc: Optional[str] = None, + ): + """Add output audio stream + + Args: + frames_per_chunk (int): {frames_per_chunk} + + buffer_chunk_size (int, optional): {buffer_chunk_size} + + stream_index (int or None, optional): {stream_index} + + decoder (str or None, optional): {decoder} + + decoder_option (dict or None, optional): {decoder_option} + + filter_desc (str or None, optional): Filter description. + The list of available filters can be found at + https://ffmpeg.org/ffmpeg-filters.html + Note that complex filters are not supported. + + """ + i = self.default_audio_stream if stream_index is None else stream_index + if i is None: + raise RuntimeError("There is no audio stream.") + self._be.add_audio_stream( + i, + frames_per_chunk, + buffer_chunk_size, + filter_desc, + decoder, + decoder_option or {}, + ) + + @_format_video_args + def add_video_stream( + self, + frames_per_chunk: int, + buffer_chunk_size: int = 3, + *, + stream_index: Optional[int] = None, + decoder: Optional[str] = None, + decoder_option: Optional[Dict[str, str]] = None, + filter_desc: Optional[str] = None, + hw_accel: Optional[str] = None, + ): + """Add output video stream + + Args: + frames_per_chunk (int): {frames_per_chunk} + + buffer_chunk_size (int, optional): {buffer_chunk_size} + + stream_index (int or None, optional): {stream_index} + + decoder (str or None, optional): {decoder} + + decoder_option (dict or None, optional): {decoder_option} + + hw_accel (str or None, optional): {hw_accel} + + filter_desc (str or None, optional): Filter description. + The list of available filters can be found at + https://ffmpeg.org/ffmpeg-filters.html + Note that complex filters are not supported. + """ + i = self.default_video_stream if stream_index is None else stream_index + if i is None: + raise RuntimeError("There is no video stream.") + self._be.add_video_stream( + i, + frames_per_chunk, + buffer_chunk_size, + filter_desc, + decoder, + decoder_option or {}, + hw_accel, + ) + + def remove_stream(self, i: int): + """Remove an output stream. + + Args: + i (int): Index of the output stream to be removed. + """ + self._be.remove_stream(i) + + def process_packet(self, timeout: Optional[float] = None, backoff: float = 10.0) -> int: + """Read the source media and process one packet. + + If a packet is read successfully, then the data in the packet will + be decoded and passed to corresponding output stream processors. + + If the packet belongs to a source stream that is not connected to + an output stream, then the data are discarded. + + When the source reaches EOF, then it triggers all the output stream + processors to enter drain mode. All the output stream processors + flush the pending frames. + + Args: + timeout (float or None, optional): Timeout in milli seconds. + + This argument changes the retry behavior when it failed to + process a packet due to the underlying media resource being + temporarily unavailable. + + When using a media device such as a microphone, there are cases + where the underlying buffer is not ready. + Calling this function in such case would cause the system to report + `EAGAIN (resource temporarily unavailable)`. + + * ``>=0``: Keep retrying until the given time passes. + + * ``0<``: Keep retrying forever. + + * ``None`` : No retrying and raise an exception immediately. + + Default: ``None``. + + Note: + + The retry behavior is applicable only when the reason is the + unavailable resource. It is not invoked if the reason of failure is + other. + + backoff (float, optional): Time to wait before retrying in milli seconds. + + This option is effective only when `timeout` is effective. (not ``None``) + + When `timeout` is effective, this `backoff` controls how long the function + should wait before retrying. Default: ``10.0``. + + Returns: + int: + ``0`` + A packet was processed properly. The caller can keep + calling this function to buffer more frames. + + ``1`` + The streamer reached EOF. All the output stream processors + flushed the pending frames. The caller should stop calling + this method. + """ + return self._be.process_packet(timeout, backoff) + + def process_all_packets(self): + """Process packets until it reaches EOF.""" + self._be.process_all_packets() + + def is_buffer_ready(self) -> bool: + """Returns true if all the output streams have at least one chunk filled.""" + return self._be.is_buffer_ready() + + def pop_chunks(self) -> Tuple[Optional[ChunkTensor]]: + """Pop one chunk from all the output stream buffers. + + Returns: + Tuple[Optional[ChunkTensor]]: + Buffer contents. + If a buffer does not contain any frame, then `None` is returned instead. + """ + ret = [] + for chunk in self._be.pop_chunks(): + if chunk is None: + ret.append(None) + else: + ret.append(ChunkTensor(chunk.frames, chunk.pts)) + return ret + + def fill_buffer(self, timeout: Optional[float] = None, backoff: float = 10.0) -> int: + """Keep processing packets until all buffers have at least one chunk + + Arguments: + timeout (float or None, optional): See + :py:func:`~StreamingMediaDecoder.process_packet`. (Default: ``None``) + + backoff (float, optional): See + :py:func:`~StreamingMediaDecoder.process_packet`. (Default: ``10.0``) + + Returns: + int: + ``0`` + Packets are processed properly and buffers are + ready to be popped once. + + ``1`` + The streamer reached EOF. All the output stream processors + flushed the pending frames. The caller should stop calling + this method. + """ + return self._be.fill_buffer(timeout, backoff) + + def stream( + self, timeout: Optional[float] = None, backoff: float = 10.0 + ) -> Iterator[Tuple[Optional[ChunkTensor], ...]]: + """Return an iterator that generates output tensors + + Arguments: + timeout (float or None, optional): See + :py:func:`~StreamingMediaDecoder.process_packet`. (Default: ``None``) + + backoff (float, optional): See + :py:func:`~StreamingMediaDecoder.process_packet`. (Default: ``10.0``) + + Returns: + Iterator[Tuple[Optional[ChunkTensor], ...]]: + Iterator that yields a tuple of chunks that correspond to the output + streams defined by client code. + If an output stream is exhausted, then the chunk Tensor is substituted + with ``None``. + The iterator stops if all the output streams are exhausted. + """ + if self.num_out_streams == 0: + raise RuntimeError("No output stream is configured.") + + while True: + if self.fill_buffer(timeout, backoff): + break + yield self.pop_chunks() + + while True: + chunks = self.pop_chunks() + if all(c is None for c in chunks): + return + yield chunks diff --git a/.venv/lib/python3.11/site-packages/torio/io/_streaming_media_encoder.py b/.venv/lib/python3.11/site-packages/torio/io/_streaming_media_encoder.py new file mode 100644 index 0000000000000000000000000000000000000000..bfbfe8791bb5bc56c13daf06dad79f753c1cce0d --- /dev/null +++ b/.venv/lib/python3.11/site-packages/torio/io/_streaming_media_encoder.py @@ -0,0 +1,502 @@ +from dataclasses import dataclass +from pathlib import Path +from typing import BinaryIO, Dict, Optional, Union + +import torch +import torio + +ffmpeg_ext = torio._extension.lazy_import_ffmpeg_ext() + + +@dataclass +class CodecConfig: + """Codec configuration.""" + + bit_rate: int = -1 + """Bit rate""" + + compression_level: int = -1 + """Compression level""" + + qscale: Optional[int] = None + """Global quality factor. Enables variable bit rate. Valid values depend on encoder. + + For example: MP3 takes ``0`` - ``9`` (https://trac.ffmpeg.org/wiki/Encode/MP3) while + libvorbis takes ``-1`` - ``10``. + """ + + gop_size: int = -1 + """The number of pictures in a group of pictures, or 0 for intra_only""" + + max_b_frames: int = -1 + """maximum number of B-frames between non-B-frames.""" + + +def _convert_config(cfg: CodecConfig): + if cfg is None: + return None + # Convert the codecconfig to C++ compatible type. + # omitting the return type annotation so as not to access ffmpeg_ext here. + return ffmpeg_ext.CodecConfig( + cfg.bit_rate, + cfg.compression_level, + cfg.qscale, + cfg.gop_size, + cfg.max_b_frames, + ) + + +def _format_doc(**kwargs): + def decorator(obj): + obj.__doc__ = obj.__doc__.format(**kwargs) + return obj + + return decorator + + +_encoder = """The name of the encoder to be used. + When provided, use the specified encoder instead of the default one. + + To list the available encoders, please use + :py:func:`~torio.utils.ffmpeg_utils.get_audio_encoders` for audio, and + :py:func:`~torio.utils.ffmpeg_utils.get_video_encoders` for video. + + Default: ``None``.""" + + +_encoder_option = """Options passed to encoder. + Mapping from str to str. + + To list encoder options for a encoder, you can use + ``ffmpeg -h encoder=`` command. + + Default: ``None``. + + | + + In addition to encoder-specific options, you can also pass options related + to multithreading. They are effective only if the encoder support them. + If neither of them are provided, StreamReader defaults to single thread. + + ``"threads"``: The number of threads (in str). + Providing the value ``"0"`` will let FFmpeg decides based on its heuristics. + + ``"thread_type"``: Which multithreading method to use. + The valid values are ``"frame"`` or ``"slice"``. + Note that each encoder supports different set of methods. + If not provided, a default value is used. + + - ``"frame"``: Encode more than one frame at once. + Each thread handles one frame. + This will increase decoding delay by one frame per thread + - ``"slice"``: Encode more than one part of a single frame at once. + + | + """ + + +_encoder_format = """Format used to encode media. + When encoder supports multiple formats, passing this argument will override + the format used for encoding. + + To list supported formats for the encoder, you can use + ``ffmpeg -h encoder=`` command. + + Default: ``None``. + + Note: + When ``encoder_format`` option is not provided, encoder uses its default format. + + For example, when encoding audio into wav format, 16-bit signed integer is used, + and when encoding video into mp4 format (h264 encoder), one of YUV format is used. + + This is because typically, 32-bit or 16-bit floating point is used in audio models but + they are not commonly used in audio formats. Similarly, RGB24 is commonly used in vision + models, but video formats usually (and better) support YUV formats. + """ + +_codec_config = """Codec configuration. Please refer to :py:class:`CodecConfig` for + configuration options. + + Default: ``None``.""" + + +_filter_desc = """Additional processing to apply before encoding the input media. + """ + +_format_common_args = _format_doc( + encoder=_encoder, + encoder_option=_encoder_option, + encoder_format=_encoder_format, + codec_config=_codec_config, + filter_desc=_filter_desc, +) + + +class StreamingMediaEncoder: + """Encode and write audio/video streams chunk by chunk + + Args: + dst (str, path-like or file-like object): The destination where the encoded data are written. + If string-type, it must be a resource indicator that FFmpeg can + handle. The supported value depends on the FFmpeg found in the system. + + If file-like object, it must support `write` method with the signature + `write(data: bytes) -> int`. + + Please refer to the following for the expected signature and behavior of + `write` method. + + - https://docs.python.org/3/library/io.html#io.BufferedIOBase.write + + format (str or None, optional): + Override the output format, or specify the output media device. + Default: ``None`` (no override nor device output). + + This argument serves two different use cases. + + 1) Override the output format. + This is useful when writing raw data or in a format different from the extension. + + 2) Specify the output device. + This allows to output media streams to hardware devices, + such as speaker and video screen. + + .. note:: + + This option roughly corresponds to ``-f`` option of ``ffmpeg`` command. + Please refer to the ffmpeg documentations for possible values. + + https://ffmpeg.org/ffmpeg-formats.html#Muxers + + Please use :py:func:`~torio.utils.ffmpeg_utils.get_muxers` to list the + multiplexers available in the current environment. + + For device access, the available values vary based on hardware (AV device) and + software configuration (ffmpeg build). + Please refer to the ffmpeg documentations for possible values. + + https://ffmpeg.org/ffmpeg-devices.html#Output-Devices + + Please use :py:func:`~torio.utils.ffmpeg_utils.get_output_devices` to list + the output devices available in the current environment. + + buffer_size (int): + The internal buffer size in byte. Used only when `dst` is a file-like object. + + Default: `4096`. + """ + + def __init__( + self, + dst: Union[str, Path, BinaryIO], + format: Optional[str] = None, + buffer_size: int = 4096, + ): + if hasattr(dst, "write"): + self._s = ffmpeg_ext.StreamingMediaEncoderFileObj(dst, format, buffer_size) + else: + self._s = ffmpeg_ext.StreamingMediaEncoder(str(dst), format) + self._is_open = False + + @_format_common_args + def add_audio_stream( + self, + sample_rate: int, + num_channels: int, + format: str = "flt", + *, + encoder: Optional[str] = None, + encoder_option: Optional[Dict[str, str]] = None, + encoder_sample_rate: Optional[int] = None, + encoder_num_channels: Optional[int] = None, + encoder_format: Optional[str] = None, + codec_config: Optional[CodecConfig] = None, + filter_desc: Optional[str] = None, + ): + """Add an output audio stream. + + Args: + sample_rate (int): The sample rate. + + num_channels (int): The number of channels. + + format (str, optional): Input sample format, which determines the dtype + of the input tensor. + + - ``"u8"``: The input tensor must be ``torch.uint8`` type. + - ``"s16"``: The input tensor must be ``torch.int16`` type. + - ``"s32"``: The input tensor must be ``torch.int32`` type. + - ``"s64"``: The input tensor must be ``torch.int64`` type. + - ``"flt"``: The input tensor must be ``torch.float32`` type. + - ``"dbl"``: The input tensor must be ``torch.float64`` type. + + Default: ``"flt"``. + + encoder (str or None, optional): {encoder} + + encoder_option (dict or None, optional): {encoder_option} + + encoder_sample_rate (int or None, optional): Override the sample rate used for encoding time. + Some encoders pose restriction on the sample rate used for encoding. + If the source sample rate is not supported by the encoder, the source sample rate is used, + otherwise a default one is picked. + + For example, ``"opus"`` encoder only supports 48k Hz, so, when encoding a + waveform with ``"opus"`` encoder, it is always encoded as 48k Hz. + Meanwhile ``"mp3"`` (``"libmp3lame"``) supports 44.1k, 48k, 32k, 22.05k, + 24k, 16k, 11.025k, 12k and 8k Hz. + If the original sample rate is one of these, then the original sample rate + is used, otherwise it will be resampled to a default one (44.1k). + When encoding into WAV format, there is no restriction on sample rate, + so the original sample rate will be used. + + Providing ``encoder_sample_rate`` will override this behavior and + make encoder attempt to use the provided sample rate. + The provided value must be one support by the encoder. + + encoder_num_channels (int or None, optional): Override the number of channels used for encoding. + + Similar to sample rate, some encoders (such as ``"opus"``, + ``"vorbis"`` and ``"g722"``) pose restriction on + the numbe of channels that can be used for encoding. + + If the original number of channels is supported by encoder, + then it will be used, otherwise, the encoder attempts to + remix the channel to one of the supported ones. + + Providing ``encoder_num_channels`` will override this behavior and + make encoder attempt to use the provided number of channels. + The provided value must be one support by the encoder. + + encoder_format (str or None, optional): {encoder_format} + + codec_config (CodecConfig or None, optional): {codec_config} + + filter_desc (str or None, optional): {filter_desc} + """ + self._s.add_audio_stream( + sample_rate, + num_channels, + format, + encoder, + encoder_option, + encoder_format, + encoder_sample_rate, + encoder_num_channels, + _convert_config(codec_config), + filter_desc, + ) + + @_format_common_args + def add_video_stream( + self, + frame_rate: float, + width: int, + height: int, + format: str = "rgb24", + *, + encoder: Optional[str] = None, + encoder_option: Optional[Dict[str, str]] = None, + encoder_frame_rate: Optional[float] = None, + encoder_width: Optional[int] = None, + encoder_height: Optional[int] = None, + encoder_format: Optional[str] = None, + codec_config: Optional[CodecConfig] = None, + filter_desc: Optional[str] = None, + hw_accel: Optional[str] = None, + ): + """Add an output video stream. + + This method has to be called before `open` is called. + + Args: + frame_rate (float): Frame rate of the video. + + width (int): Width of the video frame. + + height (int): Height of the video frame. + + format (str, optional): Input pixel format, which determines the + color channel order of the input tensor. + + - ``"gray8"``: One channel, grayscale. + - ``"rgb24"``: Three channels in the order of RGB. + - ``"bgr24"``: Three channels in the order of BGR. + - ``"yuv444p"``: Three channels in the order of YUV. + + Default: ``"rgb24"``. + + In either case, the input tensor has to be ``torch.uint8`` type and + the shape must be (frame, channel, height, width). + + encoder (str or None, optional): {encoder} + + encoder_option (dict or None, optional): {encoder_option} + + encoder_frame_rate (float or None, optional): Override the frame rate used for encoding. + + Some encoders, (such as ``"mpeg1"`` and ``"mpeg2"``) pose restriction on the + frame rate that can be used for encoding. + If such case, if the source frame rate (provided as ``frame_rate``) is not + one of the supported frame rate, then a default one is picked, and the frame rate + is changed on-the-fly. Otherwise the source frame rate is used. + + Providing ``encoder_frame_rate`` will override this behavior and + make encoder attempts to use the provided sample rate. + The provided value must be one support by the encoder. + + encoder_width (int or None, optional): Width of the image used for encoding. + This allows to change the image size during encoding. + + encoder_height (int or None, optional): Height of the image used for encoding. + This allows to change the image size during encoding. + + encoder_format (str or None, optional): {encoder_format} + + codec_config (CodecConfig or None, optional): {codec_config} + + filter_desc (str or None, optional): {filter_desc} + + hw_accel (str or None, optional): Enable hardware acceleration. + + When video is encoded on CUDA hardware, for example + `encoder="h264_nvenc"`, passing CUDA device indicator to `hw_accel` + (i.e. `hw_accel="cuda:0"`) will make StreamingMediaEncoder expect video + chunk to be CUDA Tensor. Passing CPU Tensor will result in an error. + + If `None`, the video chunk Tensor has to be CPU Tensor. + Default: ``None``. + """ + self._s.add_video_stream( + frame_rate, + width, + height, + format, + encoder, + encoder_option, + encoder_format, + encoder_frame_rate, + encoder_width, + encoder_height, + hw_accel, + _convert_config(codec_config), + filter_desc, + ) + + def set_metadata(self, metadata: Dict[str, str]): + """Set file-level metadata + + Args: + metadata (dict or None, optional): File-level metadata. + """ + self._s.set_metadata(metadata) + + def _print_output_stream(self, i: int): + """[debug] Print the registered stream information to stdout.""" + self._s.dump_format(i) + + def open(self, option: Optional[Dict[str, str]] = None) -> "StreamingMediaEncoder": + """Open the output file / device and write the header. + + :py:class:`StreamingMediaEncoder` is also a context manager and therefore supports the + ``with`` statement. + This method returns the instance on which the method is called (i.e. `self`), + so that it can be used in `with` statement. + It is recommended to use context manager, as the file is closed automatically + when exiting from ``with`` clause. + + Args: + option (dict or None, optional): Private options for protocol, device and muxer. See example. + + Example - Protocol option + >>> s = StreamingMediaEncoder(dst="rtmp://localhost:1234/live/app", format="flv") + >>> s.add_video_stream(...) + >>> # Passing protocol option `listen=1` makes StreamingMediaEncoder act as RTMP server. + >>> with s.open(option={"listen": "1"}) as f: + >>> f.write_video_chunk(...) + + Example - Device option + >>> s = StreamingMediaEncoder("-", format="sdl") + >>> s.add_video_stream(..., encoder_format="rgb24") + >>> # Open SDL video player with fullscreen + >>> with s.open(option={"window_fullscreen": "1"}): + >>> f.write_video_chunk(...) + + Example - Muxer option + >>> s = StreamingMediaEncoder("foo.flac") + >>> s.add_audio_stream(...) + >>> s.set_metadata({"artist": "torio contributors"}) + >>> # FLAC muxer has a private option to not write the header. + >>> # The resulting file does not contain the above metadata. + >>> with s.open(option={"write_header": "false"}) as f: + >>> f.write_audio_chunk(...) + """ + if not self._is_open: + self._s.open(option) + self._is_open = True + return self + + def close(self): + """Close the output + + :py:class:`StreamingMediaEncoder` is also a context manager and therefore supports the + ``with`` statement. + It is recommended to use context manager, as the file is closed automatically + when exiting from ``with`` clause. + + See :py:meth:`StreamingMediaEncoder.open` for more detail. + """ + if self._is_open: + self._s.close() + self._is_open = False + + def write_audio_chunk(self, i: int, chunk: torch.Tensor, pts: Optional[float] = None): + """Write audio data + + Args: + i (int): Stream index. + chunk (Tensor): Waveform tensor. Shape: `(frame, channel)`. + The ``dtype`` must match what was passed to :py:meth:`add_audio_stream` method. + pts (float, optional, or None): If provided, overwrite the presentation timestamp. + + .. note:: + + The provided value is converted to integer value expressed in basis of + sample rate. Therefore, it is truncated to the nearest value of + ``n / sample_rate``. + """ + self._s.write_audio_chunk(i, chunk, pts) + + def write_video_chunk(self, i: int, chunk: torch.Tensor, pts: Optional[float] = None): + """Write video/image data + + Args: + i (int): Stream index. + chunk (Tensor): Video/image tensor. + Shape: `(time, channel, height, width)`. + The ``dtype`` must be ``torch.uint8``. + The shape (height, width and the number of channels) must match + what was configured when calling :py:meth:`add_video_stream` + pts (float, optional or None): If provided, overwrite the presentation timestamp. + + .. note:: + + The provided value is converted to integer value expressed in basis of + frame rate. Therefore, it is truncated to the nearest value of + ``n / frame_rate``. + """ + self._s.write_video_chunk(i, chunk, pts) + + def flush(self): + """Flush the frames from encoders and write the frames to the destination.""" + self._s.flush() + + def __enter__(self): + """Context manager so that the destination is closed and data are flushed automatically.""" + return self + + def __exit__(self, exception_type, exception_value, traceback): + """Context manager so that the destination is closed and data are flushed automatically.""" + self.flush() + self.close() diff --git a/.venv/lib/python3.11/site-packages/torio/lib/__init__.py b/.venv/lib/python3.11/site-packages/torio/lib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.venv/lib/python3.11/site-packages/torio/lib/__pycache__/__init__.cpython-311.pyc b/.venv/lib/python3.11/site-packages/torio/lib/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eefebc12800e98f550719137676dd4faed89df2a Binary files /dev/null and b/.venv/lib/python3.11/site-packages/torio/lib/__pycache__/__init__.cpython-311.pyc differ diff --git a/.venv/lib/python3.11/site-packages/torio/utils/__init__.py b/.venv/lib/python3.11/site-packages/torio/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a3dbc29a6a840214338e63074703b6f74debdc05 --- /dev/null +++ b/.venv/lib/python3.11/site-packages/torio/utils/__init__.py @@ -0,0 +1,4 @@ +from . import ffmpeg_utils + + +__all__ = ["ffmpeg_utils"] diff --git a/.venv/lib/python3.11/site-packages/torio/utils/ffmpeg_utils.py b/.venv/lib/python3.11/site-packages/torio/utils/ffmpeg_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..06f20bd25112cbe79ed89c7b4c888826bccf8a9f --- /dev/null +++ b/.venv/lib/python3.11/site-packages/torio/utils/ffmpeg_utils.py @@ -0,0 +1,247 @@ +"""Module to change the configuration of FFmpeg libraries (such as libavformat). + +It affects functionalities in :py:mod:`torio.io`. +""" +from typing import Dict, List, Tuple + +import torio + +ffmpeg_ext = torio._extension.lazy_import_ffmpeg_ext() + + +def get_versions() -> Dict[str, Tuple[int]]: + """Get the versions of FFmpeg libraries + + Returns: + dict: mapping from library names to version string, + i.e. `"libavutil": (56, 22, 100)`. + """ + return ffmpeg_ext.get_versions() + + +def get_log_level() -> int: + """Get the log level of FFmpeg. + + See :py:func:`set_log_level` for the detail. + """ + return ffmpeg_ext.get_log_level() + + +def set_log_level(level: int): + """Set the log level of FFmpeg (libavformat etc) + + Arguments: + level (int): Log level. The larger, the more verbose. + + The following values are common values, the corresponding ``ffmpeg``'s + ``-loglevel`` option value and desription. + + * ``-8`` (``quiet``): + Print no output. + * ``0`` (``panic``): + Something went really wrong and we will crash now. + * ``8`` (``fatal``): + Something went wrong and recovery is not possible. + For example, no header was found for a format which depends + on headers or an illegal combination of parameters is used. + * ``16`` (``error``): + Something went wrong and cannot losslessly be recovered. + However, not all future data is affected. + * ``24`` (``warning``): + Something somehow does not look correct. + This may or may not lead to problems. + * ``32`` (``info``): + Standard information. + * ``40`` (``verbose``): + Detailed information. + * ``48`` (``debug``): + Stuff which is only useful for libav* developers. + * ``56`` (``trace``): + Extremely verbose debugging, useful for libav* development. + + """ + ffmpeg_ext.set_log_level(level) + + +def get_demuxers() -> Dict[str, str]: + """Get the available demuxers. + + Returns: + Dict[str, str]: Mapping from demuxer (format) short name to long name. + + Example + >>> for k, v in get_demuxers().items(): + >>> print(f"{k}: {v}") + ... aa: Audible AA format files + ... aac: raw ADTS AAC (Advanced Audio Coding) + ... aax: CRI AAX + ... ac3: raw AC-3 + """ + return ffmpeg_ext.get_demuxers() + + +def get_muxers() -> Dict[str, str]: + """Get the available muxers. + + Returns: + Dict[str, str]: Mapping from muxer (format) short name to long name. + + Example + >>> for k, v in get_muxers().items(): + >>> print(f"{k}: {v}") + ... a64: a64 - video for Commodore 64 + ... ac3: raw AC-3 + ... adts: ADTS AAC (Advanced Audio Coding) + ... adx: CRI ADX + ... aiff: Audio IFF + """ + return ffmpeg_ext.get_muxers() + + +def get_audio_decoders() -> Dict[str, str]: + """Get the available audio decoders. + + Returns: + Dict[str, str]: Mapping from decoder short name to long name. + + Example + >>> for k, v in get_audio_decoders().items(): + >>> print(f"{k}: {v}") + ... a64: a64 - video for Commodore 64 + ... ac3: raw AC-3 + ... adts: ADTS AAC (Advanced Audio Coding) + ... adx: CRI ADX + ... aiff: Audio IFF + """ + return ffmpeg_ext.get_audio_decoders() + + +def get_audio_encoders() -> Dict[str, str]: + """Get the available audio encoders. + + Returns: + Dict[str, str]: Mapping from encoder short name to long name. + + Example + >>> for k, v in get_audio_encoders().items(): + >>> print(f"{k}: {v}") + ... comfortnoise: RFC 3389 comfort noise generator + ... s302m: SMPTE 302M + ... aac: AAC (Advanced Audio Coding) + ... ac3: ATSC A/52A (AC-3) + ... ac3_fixed: ATSC A/52A (AC-3) + ... alac: ALAC (Apple Lossless Audio Codec) + """ + return ffmpeg_ext.get_audio_encoders() + + +def get_video_decoders() -> Dict[str, str]: + """Get the available video decoders. + + Returns: + Dict[str, str]: Mapping from decoder short name to long name. + + Example + >>> for k, v in get_video_decoders().items(): + >>> print(f"{k}: {v}") + ... aasc: Autodesk RLE + ... aic: Apple Intermediate Codec + ... alias_pix: Alias/Wavefront PIX image + ... agm: Amuse Graphics Movie + ... amv: AMV Video + ... anm: Deluxe Paint Animation + """ + return ffmpeg_ext.get_video_decoders() + + +def get_video_encoders() -> Dict[str, str]: + """Get the available video encoders. + + Returns: + Dict[str, str]: Mapping from encoder short name to long name. + + Example + >>> for k, v in get_audio_encoders().items(): + >>> print(f"{k}: {v}") + ... a64multi: Multicolor charset for Commodore 64 + ... a64multi5: Multicolor charset for Commodore 64, extended with 5th color (colram) + ... alias_pix: Alias/Wavefront PIX image + ... amv: AMV Video + ... apng: APNG (Animated Portable Network Graphics) image + ... asv1: ASUS V1 + ... asv2: ASUS V2 + """ + return ffmpeg_ext.get_video_encoders() + + +def get_input_devices() -> Dict[str, str]: + """Get the available input devices. + + Returns: + Dict[str, str]: Mapping from device short name to long name. + + Example + >>> for k, v in get_input_devices().items(): + >>> print(f"{k}: {v}") + ... avfoundation: AVFoundation input device + ... lavfi: Libavfilter virtual input device + """ + return ffmpeg_ext.get_input_devices() + + +def get_output_devices() -> Dict[str, str]: + """Get the available output devices. + + Returns: + Dict[str, str]: Mapping from device short name to long name. + + Example + >>> for k, v in get_output_devices().items(): + >>> print(f"{k}: {v}") + ... audiotoolbox: AudioToolbox output device + """ + return ffmpeg_ext.get_output_devices() + + +def get_input_protocols() -> List[str]: + """Get the supported input protocols. + + Returns: + List[str]: The names of supported input protocols + + Example + >>> print(get_input_protocols()) + ... ['file', 'ftp', 'hls', 'http','https', 'pipe', 'rtmp', 'tcp', 'tls', 'udp', 'unix'] + """ + return ffmpeg_ext.get_input_protocols() + + +def get_output_protocols() -> List[str]: + """Get the supported output protocols. + + Returns: + list of str: The names of supported output protocols + + Example + >>> print(get_output_protocols()) + ... ['file', 'ftp', 'http', 'https', 'md5', 'pipe', 'prompeg', 'rtmp', 'tee', 'tcp', 'tls', 'udp', 'unix'] + """ + return ffmpeg_ext.get_output_protocols() + + +def get_build_config() -> str: + """Get the FFmpeg build configuration + + Returns: + str: Build configuration string. + + Example + >>> print(get_build_config()) + --prefix=/Users/runner/miniforge3 --cc=arm64-apple-darwin20.0.0-clang --enable-gpl --enable-hardcoded-tables --enable-libfreetype --enable-libopenh264 --enable-neon --enable-libx264 --enable-libx265 --enable-libaom --enable-libsvtav1 --enable-libxml2 --enable-libvpx --enable-pic --enable-pthreads --enable-shared --disable-static --enable-version3 --enable-zlib --enable-libmp3lame --pkg-config=/Users/runner/miniforge3/conda-bld/ffmpeg_1646229390493/_build_env/bin/pkg-config --enable-cross-compile --arch=arm64 --target-os=darwin --cross-prefix=arm64-apple-darwin20.0.0- --host-cc=/Users/runner/miniforge3/conda-bld/ffmpeg_1646229390493/_build_env/bin/x86_64-apple-darwin13.4.0-clang # noqa + """ + return ffmpeg_ext.get_build_config() + + +def clear_cuda_context_cache(): + """Clear the CUDA context used by CUDA Hardware accelerated video decoding""" + ffmpeg_ext.clear_cuda_context_cache()