Exemple #1
0
 def _free(self):
     """Free any resources that have been allocated by the object.
     
     This must be called by the stream after all frames have been processed.
     """
     if self._numpySwsCtx is not None:
         swscale.sws_freeContext(self._numpySwsCtx)
         self._numpySwsCtx = None
         
     if self._pilSwsCtx is not None:
         swscale.sws_freeContext(self._pilSwsCtx)
         self._pilSwsCtx = None
     
     if self._picture is not None:
         avcodec.avpicture_free(self._picture)
         self._picture = None
Exemple #2
0
    def _initNumpyProcessing(self, pixelFormat, pixelAccess, colorAccess):
        """Initialize decoding into a numpy array.
        
        This has to be called at least once before a frame is converted into
        a numpy array.
        If the layout of the numpy array changes, the method has to be called
        again.
        
        The method creates the numpy array, the swscale context to convert
        the image data and the _lineSizes and _dataPtrs arrays for the sws_scale()
        call.
        """
        # Check the pixelAccess value...
        if pixelAccess not in [WIDTH_HEIGHT, HEIGHT_WIDTH]:
            raise ValueError("Invalid pixelAcess value")
        
        # Check the colorAccess value...
        if colorAccess not in [SEPARATE_CHANNELS, COMBINED_CHANNELS]:
            raise ValueError("Invalid colorAccess value")
        
        # Check the pixel format...
        numChannels = None
        dstPixFmt = None
        if pixelFormat==RGB:
            numChannels = 3
            dstPixFmt = decls.PIX_FMT_RGB24
        elif pixelFormat==BGR:
            numChannels = 3
            dstPixFmt = decls.PIX_FMT_BGR24
        elif pixelFormat==RGBA:
            numChannels = 4
            dstPixFmt = decls.PIX_FMT_RGBA
        elif pixelFormat==ARGB:
            numChannels = 4
            dstPixFmt = decls.PIX_FMT_ARGB
        elif pixelFormat==ABGR:
            numChannels = 4
            dstPixFmt = decls.PIX_FMT_ABGR
        elif pixelFormat==BGRA:
            numChannels = 4
            dstPixFmt = decls.PIX_FMT_BGRA
        elif pixelFormat==GRAY:
            numChannels = 1
            dstPixFmt = decls.PIX_FMT_GRAY8
        else:
            raise ValueError("Invalid pixelFormat value")

        width,height = self.size
        # Allocate the numpy array that will hold the converted image.
        # The memory layout of the buffer is always so that the image is stored
        # in rows and all the channels are stored together with a pixel.
        # Example: Row 0: RGB-RGB-RGB-RGB...
        #          Row 1: RGB-RGB-RGB-RGB...
        #          ...
        # To get from one channel to the next channel, you always have to add 1 byte
        # (for int8 channels). To get to the next x position, you have to add
        # numChannels bytes and to get to the next y position you have to add
        # width*numChannels bytes.
        # The pixelAccess and colorAccess parameters don't affect this memory
        # layout, they only affect how a pixel is accessed via numpy.
        if colorAccess==SEPARATE_CHANNELS:
            # Allocate a RGB buffer...
            if pixelAccess==WIDTH_HEIGHT:
                self._numpyArray = numpy.empty((width,height,numChannels), dtype=numpy.uint8)
                # Adjust the strides so that image rows are consecutive
                self._numpyArray.strides = (numChannels, numChannels*width, 1)
            else:
                self._numpyArray = numpy.empty((height,width,numChannels), dtype=numpy.uint8)
        else:
            if numChannels not in [1,4]:
                raise ValueError("COMBINED_CHANNELS pixel access can only be used with 1-channel or 4-channel pixel formats")
            
            if numChannels==1:
                dtype = numpy.uint8
            else:
                dtype = numpy.uint32
            
            # Allocate a RGBA buffer (where a RGBA value is stored as a uint32)
            if pixelAccess==WIDTH_HEIGHT:
                self._numpyArray = numpy.empty((width,height), dtype=dtype, order="F")
            else:
                self._numpyArray = numpy.empty((height,width), dtype=dtype)

        # Free any previously allocated context 
        if self._numpySwsCtx is not None:
            swscale.sws_freeContext(self._numpySwsCtx)
            self._numpySwsCtx = None

        # Allocate the swscale context
        self._numpySwsCtx = swscale.sws_getContext(width, height, self._srcPixFmt, 
                                                   width, height, dstPixFmt, 1)

        # Initialize the lineSizes and dataPtrs array that are passed into sws_scale().
        # The first data pointer points to the beginning of the numpy buffer.
        DataPtrType = ctypes.POINTER(ctypes.c_uint8)
        self._lineSizes = (4*ctypes.c_int)(numChannels*width,0,0,0)
        self._dataPtrs = (4*DataPtrType)(self._numpyArray.ctypes.data_as(DataPtrType), None, None, None)
        
        # Store the parameters so that we can detect parameter changes
        self._numpyBufferParams = (pixelFormat, pixelAccess, colorAccess)