cainmagi / FFmpeg-Encoder-Decoder-for-Python

This is a C++ based FFmpeg Encoder/Decoder for Python 3.6+ & numpy 1.19+. Both Linux & Win versions are provided. Theoretically you do not need to install FFmpeg for using this library.
https://cainmagi.github.io/FFmpeg-Encoder-Decoder-for-Python/
GNU General Public License v3.0
35 stars 7 forks source link

Frame count and metadata access #6

Closed timothyhalim closed 2 years ago

timothyhalim commented 2 years ago

Get started

Problem

Hi, I'm currently testing this library and this looks promising, but I didn't found any way to access the frame count from python (although it seems it is available in the c++ private variable?)

I think it will be good if we can access the metadata of the video.

here is my sample script:

import mpegCoder
from PySide2.QtWidgets import QWidget, QLabel, QVBoxLayout, QApplication
from PySide2.QtGui import QImage, QPixmap

class Player(QWidget):
    def __init__(self, parent=None):
        super(Player, self).__init__(parent)
        self._layout = QVBoxLayout(self)
        self.image = QLabel()
        self._layout.addWidget(self.image)

        decoder = mpegCoder.MpegDecoder()
        decoder.setParameter(nthread=4)
        opened = decoder.FFmpegSetup('30.mp4')

        if opened:
            param = decoder.getParameter()
            fps = float(param['frameRate'][0]) / param['frameRate'][1] # is this correct way to get fps?
            framecount = 0 # How to get framecount of the video?

            frame = 0
            p = decoder.ExtractFrame(frame, 1)

        decoder.clear() #do we need to clear the decoder?

        data = p[0].data
        height = p[0].shape[0]
        width = p[0].shape[1]
        channel = p[0].shape[2]
        self.image.setPixmap(QPixmap.fromImage(QImage(data, width, height, channel*width, QImage.Format_RGB888)))

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    p = Player()
    p.show()
    app.exec_()

Required feature

Frame count or metadata reading

mpegCoder version

3.2.4

Additional context

No response

Also will be waiting for audio support ;)

cainmagi commented 2 years ago

Hello. Thanks for your description. Your question may be related to the following document item:

https://cainmagi.github.io/FFmpeg-Encoder-Decoder-for-Python/docs/apis/MpegDecoder#getparameter

Furthermore, if you want to get the framecount variable, you can use

param = decoder.getParameter('frameCount')

But I need to emphasize that, this frameCount value should be the number of the frames extracted by the last frames = dec.ExtractFrame() or frames = dec.ExtractGOP(). If you have gotten the frames, this value should be the same as len(frames).

If you want to get the total frame number of the whole video, you need to use

param = decoder.getParameter('estFrameNum')

This value is provided by FFmpeg directly. However, I need to point out that this is merely an "estimated value". In other words, it may be not totally accurate. The only way to confirm that all frames are extracted (or get the accurate count) is to call dec.ExtractGOP() or dec.ExtractFrame() repeatedly until it returns a None.


If you still have questions, please let me know. Thank you!

timothyhalim commented 2 years ago

Hi Cain, thanks for clarifying

After reading your documentation and testing with some footage I think this is the correct way to get the correct frameNumber

duration = decoder.getParameter("duration")
fps = decoder.getParameter("avgFrameRate")
frameCount = duration*fps

since using

frameCount = decoder.getParameter('estFrameNum')

will return one or more frame less than the actual frame number

also is it possible to access other metadata such as colorspace ex "sRGB" or colorfromat ex "yuv420p"?

cainmagi commented 2 years ago

Hello, @timothyhalim .

Thank you for testing!

Currently, users do not need to get the colorspace metadata, because mpegCoder will convert all video frames into the RGB data space before returning the extracted frames. The original colorspace is meaningless in this case. I wonder why you need to get those metadata. For example, do you want the decoder to return the original decoded frame in the original colorspace? Currently, I have not provided this feature. If you need it, I can add it to my plan.

timothyhalim commented 2 years ago

Ah i see, so basically all the video frames will be converted to sRGB? if so we won't need to use the colorspace indeed. All is cool then, thanks!

And one more thing, is it possible to disable print to console during frame decoding? it is printed by this line

opened = decoder.FFmpegSetup("30.mp4")
cainmagi commented 2 years ago

@timothyhalim Please check this documentation item: https://cainmagi.github.io/FFmpeg-Encoder-Decoder-for-Python/docs/apis/setGlobal#disable-all-logs-except-errors

To disable all logs, configure mpegCoder globally before running any encoding / decoding programs:

import mpegCoder
mpegCoder.setGlobal(dumpLevel=0)

....

I need to emphasize that some logs can not be disabled, because they are not controlled by FFMpeg or my codes. Some of the codes are provided by third-party programs. For example, if you are using x265 codec, it may show you some logs after saving the video. In this case, I have not found a way to disable those logs.

timothyhalim commented 2 years ago

@cainmagi ok all is clear, closing this issue, thanks!

ps: will wait for audio support ;)