gstreamer-0.11.0: Media/Streaming/GStreamer/Core/Buffer.chs
{-# LANGUAGE CPP #-}
-- GIMP Toolkit (GTK) Binding for Haskell: binding to gstreamer -*-haskell-*-
--
-- Author : Peter Gavin
-- Created: 1-Apr-2007
--
-- Copyright (c) 2007 Peter Gavin
--
-- This library is free software: you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public License
-- as published by the Free Software Foundation, either version 3 of
-- the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this program. If not, see
-- <http://www.gnu.org/licenses/>.
--
-- GStreamer, the C library which this Haskell library depends on, is
-- available under LGPL Version 2. The documentation included with
-- this library is based on the original GStreamer documentation.
--
-- |
-- Maintainer : gtk2hs-devel@lists.sourceforge.net
-- Stability : alpha
-- Portability : portable (depends on GHC)
--
-- Data-passing buffer type, supporting sub-buffers.
module Media.Streaming.GStreamer.Core.Buffer (
-- * Types
-- | 'Buffer's are the basic unit of data transfer in GStreamer. The
-- 'Buffer' type provides all the state necessary to define a
-- region of memory as part of a stream. Sub-buffers are also
-- supported, allowing a smaller region of a 'Buffer' to become its
-- own 'Buffer', with mechansims in place to ensure that neither
-- memory space goes away prematurely.
Buffer,
BufferClass,
castToBuffer,
gTypeBuffer,
BufferFlags(..),
-- * Buffer Operations
bufferOffsetNone,
bufferGetFlags,
bufferGetFlagsM,
bufferSetFlagsM,
bufferUnsetFlagsM,
bufferGetSize,
bufferGetSizeM,
#if __GLASGOW_HASKELL__ >= 606
bufferGetData,
bufferGetDataM,
bufferSetDataM,
#endif
unsafeBufferGetPtrM,
bufferGetTimestamp,
bufferGetTimestampM,
bufferSetTimestampM,
bufferGetDuration,
bufferGetDurationM,
bufferSetDurationM,
bufferGetCaps,
bufferGetCapsM,
bufferSetCapsM,
bufferGetOffset,
bufferGetOffsetM,
bufferSetOffsetM,
bufferGetOffsetEnd,
bufferGetOffsetEndM,
bufferSetOffsetEndM,
bufferIsDiscont,
bufferIsDiscontM,
bufferCreateEmpty,
bufferCreate,
bufferCreateSub,
bufferIsSpanFast,
bufferSpan,
bufferMerge
) where
import Control.Monad ( liftM
, when )
import Control.Monad.Trans
#if __GLASGOW_HASKELL__ >= 606
import qualified Data.ByteString as BS
#if __GLASGOW_HASKELL__ < 608
#define OLD_BYTESTRING
#endif
#endif
{#import Media.Streaming.GStreamer.Core.Types#}
import System.Glib.FFI
{# context lib = "gstreamer" prefix = "gst" #}
-- | Get the flags set on @buffer@.
bufferGetFlags :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a 'Buffer'
-> [BufferFlags] -- ^ the flags set on @buffer@
bufferGetFlags = mkMiniObjectGetFlags
-- | Get the flags set on the current 'Buffer'.
bufferGetFlagsM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m [BufferFlags] -- ^ the flags set on the current 'Buffer'
bufferGetFlagsM = mkMiniObjectGetFlagsM
-- | Set flags on the current 'Buffer'.
bufferSetFlagsM :: (BufferClass bufferT, MonadIO m)
=> [BufferFlags] -- ^ @flags@ - the flags to set on the current 'Buffer'
-> MiniObjectT bufferT m ()
bufferSetFlagsM = mkMiniObjectSetFlagsM
-- | Unset flags on the current 'Buffer'.
bufferUnsetFlagsM :: (BufferClass bufferT, MonadIO m)
=> [BufferFlags] -- ^ @flags@ - the flags to unset on the current 'Buffer'
-> MiniObjectT bufferT m ()
bufferUnsetFlagsM = mkMiniObjectUnsetFlagsM
-- | Get @buffer@'s size in bytes.
bufferGetSize :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a 'Buffer'
-> Word -- ^ the size of @buffer@ in bytes
bufferGetSize buffer =
fromIntegral $ unsafePerformIO $
withMiniObject buffer {# get GstBuffer->size #}
marshalBufferM :: (BufferClass bufferT, MonadIO m)
=> (Ptr Buffer -> IO a)
-> MiniObjectT bufferT m a
marshalBufferM action = do
ptr <- askMiniObjectPtr
liftIO $ action $ castPtr ptr
-- | Get the size of the current 'Buffer' in bytes.
bufferGetSizeM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m Word -- ^ the size of the current 'Buffer' in bytes
bufferGetSizeM =
liftM fromIntegral $
marshalBufferM {# get GstBuffer->size #}
#if __GLASGOW_HASKELL__ >= 606
-- | Make an O(n) copy of the data stored in @buffer@.
bufferGetData :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a 'Buffer'
-> BS.ByteString -- ^ the data stored in @buffer@
bufferGetData buffer =
unsafePerformIO $ withMiniObject buffer $ \bufferPtr ->
do ptr <- {# get GstBuffer->data #} bufferPtr
size <- {# get GstBuffer->size #} bufferPtr
#ifdef OLD_BYTESTRING
BS.copyCStringLen (castPtr ptr, fromIntegral size)
#else
BS.packCStringLen (castPtr ptr, fromIntegral size)
#endif
-- | Make an O(n) copy of the current 'Buffer'.
bufferGetDataM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m BS.ByteString -- ^ the data stored in the current 'Buffer'
bufferGetDataM =
marshalBufferM $ \bufferPtr ->
do ptr <- {# get GstBuffer->data #} bufferPtr
size <- {# get GstBuffer->size #} bufferPtr
#ifdef OLD_BYTESTRING
BS.copyCStringLen (castPtr ptr, fromIntegral size)
#else
BS.packCStringLen (castPtr ptr, fromIntegral size)
#endif
-- | Store an O(n) copy of the provided data in the current 'Buffer'.
bufferSetDataM :: (BufferClass bufferT, MonadIO m)
=> BS.ByteString -- ^ @bs@ - the data to store in the current 'Buffer'
-> MiniObjectT bufferT m ()
bufferSetDataM bs =
marshalBufferM $ \bufferPtr ->
BS.useAsCStringLen bs $ \(origData, size) ->
do mallocData <- {# get GstBuffer->malloc_data #} bufferPtr
when (mallocData /= nullPtr) $
{# call g_free #} $ castPtr mallocData
newData <- liftM castPtr $ {# call g_malloc #} $ fromIntegral size
copyBytes (castPtr newData) origData size
{# set GstBuffer->data #} bufferPtr newData
{# set GstBuffer->malloc_data #} bufferPtr newData
{# set GstBuffer->size #} bufferPtr $ fromIntegral size
#endif
-- | Get a raw pointer to the internal data area for the current
-- buffer. The pointer may be used to write into the data area if
-- desired. This function is unsafe in that the pointer should not
-- be used once the 'Buffer' is returned.
unsafeBufferGetPtrM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m (Ptr Word8) -- ^ a pointer to the data stored in the current 'Buffer'
unsafeBufferGetPtrM = do
ptr <- askMiniObjectPtr
liftIO $ liftM castPtr $
{# get GstBuffer->data #} ptr
marshalGetNum :: (BufferClass bufferT, Integral intT, Num numT)
=> (Ptr Buffer -> IO intT)
-> numT
-> bufferT
-> Maybe numT
marshalGetNum getAction invalid buffer =
let n = fromIntegral $ unsafePerformIO $
withMiniObject (toBuffer buffer) getAction
in if n /= invalid
then Just n
else Nothing
marshalGetNumM :: (BufferClass bufferT, Integral intT, Num numT, MonadIO m)
=> (Ptr Buffer -> IO intT)
-> numT
-> MiniObjectT bufferT m (Maybe numT)
marshalGetNumM getAction invalid =
marshalBufferM $ \bufferPtr -> do
n <- liftM fromIntegral $ getAction bufferPtr
return $ if n /= invalid
then Just n
else Nothing
marshalSetNumM :: (BufferClass bufferT, Integral intT, Num numT, MonadIO m)
=> (Ptr Buffer -> numT -> IO ())
-> intT
-> Maybe intT
-> MiniObjectT bufferT m ()
marshalSetNumM setAction invalid nM =
let n = case nM of
Just n' -> n'
Nothing -> invalid
in marshalBufferM $ flip setAction $ fromIntegral n
-- | Get the timestamp on @buffer@.
bufferGetTimestamp :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a 'Buffer'
-> Maybe ClockTime -- ^ the timestamp on @buffer@
bufferGetTimestamp =
marshalGetNum {# get GstBuffer->timestamp #} clockTimeNone
-- | Get the timestamp on the current 'Buffer'.
bufferGetTimestampM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m (Maybe ClockTime) -- ^ the timestamp on the current 'Buffer'
bufferGetTimestampM =
marshalGetNumM {# get GstBuffer->timestamp #} clockTimeNone
-- | Set the timestamp on the current 'Buffer'.
bufferSetTimestampM :: (BufferClass bufferT, MonadIO m)
=> Maybe ClockTime -- ^ @timestamp@ - the timestamp to set on the current 'Buffer'
-> MiniObjectT bufferT m ()
bufferSetTimestampM =
marshalSetNumM {# set GstBuffer->timestamp #} clockTimeNone
-- | Get the duration of @buffer@.
bufferGetDuration :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a 'Buffer'
-> Maybe ClockTime -- ^ the duration of @buffer@
bufferGetDuration =
marshalGetNum {# get GstBuffer->duration #} clockTimeNone
-- | Get the duration of the current 'Buffer'.
bufferGetDurationM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m (Maybe ClockTime) -- ^ the duration of the current 'Buffer'
bufferGetDurationM =
marshalGetNumM {# get GstBuffer->duration #} clockTimeNone
-- | Set the duration of the current 'Buffer'.
bufferSetDurationM :: (BufferClass bufferT, MonadIO m)
=> Maybe ClockTime -- ^ @duration@ - the duration to set on the current 'Buffer'
-> MiniObjectT bufferT m ()
bufferSetDurationM =
marshalSetNumM {# set GstBuffer->duration #} clockTimeNone
-- | Get the 'Caps' of @buffer@.
bufferGetCaps :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a buffer
-> Maybe Caps -- ^ the 'Caps' of @buffer@ if set, otherwise 'Nothing'
bufferGetCaps buffer =
unsafePerformIO $
{# call buffer_get_caps #} (toBuffer buffer) >>=
maybePeek takeCaps
-- | Get the caps of the current 'Buffer'.
bufferGetCapsM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m (Maybe Caps) -- ^ the 'Caps' of the current 'Buffer'
-- if set, otherwise 'Nothing'
bufferGetCapsM = do
ptr <- askMiniObjectPtr
liftIO $ gst_buffer_get_caps (castPtr ptr) >>=
maybePeek takeCaps
where _ = {# call buffer_get_caps #}
-- | Set the caps of the current 'Buffer'.
bufferSetCapsM :: (BufferClass bufferT, MonadIO m)
=> Maybe Caps -- ^ @caps@ - the 'Caps' to set on the current
-- 'Buffer', or 'Nothing' to unset them
-> MiniObjectT bufferT m ()
bufferSetCapsM capsM = do
ptr <- askMiniObjectPtr
liftIO $ withForeignPtr (case capsM of
Just caps -> unCaps caps
Nothing -> nullForeignPtr)
(gst_buffer_set_caps $ castPtr ptr)
where _ = {# call buffer_set_caps #}
-- | Get the start offset of the 'Buffer'.
bufferGetOffset :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a buffer
-> Maybe Word64 -- ^ the start offset of @buffer@ if set, otherwise 'Nothing'
bufferGetOffset =
marshalGetNum {# get GstBuffer->offset #} bufferOffsetNone
-- | Get the start offset of the current 'Buffer'.
bufferGetOffsetM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m (Maybe Word64) -- ^ the start offset of the current
-- 'Buffer' if set, otherwise 'Nothing'
bufferGetOffsetM =
marshalGetNumM {# get GstBuffer->offset #} bufferOffsetNone
-- | Set the start offset of the current 'Buffer'.
bufferSetOffsetM :: (BufferClass bufferT, MonadIO m)
=> Maybe Word64 -- ^ @offset@ - the start offset to set on the current buffer
-> MiniObjectT bufferT m ()
bufferSetOffsetM =
marshalSetNumM {# set GstBuffer->offset #} bufferOffsetNone
-- | Get the end offset of the 'Buffer'.
bufferGetOffsetEnd :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a buffer
-> Maybe Word64 -- ^ the end offset of @buffer@ if set, otherwise 'Nothing'
bufferGetOffsetEnd =
marshalGetNum {# get GstBuffer->offset_end #} bufferOffsetNone
-- | Get the end offset of the current 'Buffer'.
bufferGetOffsetEndM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m (Maybe Word64) -- ^ the start offset of the current
-- 'Buffer' if set, otherwise 'Nothing'
bufferGetOffsetEndM =
marshalGetNumM {# get GstBuffer->offset_end #} bufferOffsetNone
-- | Set the end offset of the current 'Buffer'.
bufferSetOffsetEndM :: (BufferClass bufferT, MonadIO m)
=> Maybe Word64 -- ^ @offset@ - the end offset to set on the current buffer
-> MiniObjectT bufferT m ()
bufferSetOffsetEndM =
marshalSetNumM {# set GstBuffer->offset_end #} bufferOffsetNone
-- | Return 'True' if the 'Buffer' marks a discontinuity in a stream, or
-- 'False' otherwise. This typically occurs after a seek or a
-- dropped buffer from a live or network source.
bufferIsDiscont :: BufferClass bufferT
=> bufferT -- ^ @buffer@ - a buffer
-> Bool -- ^ 'True' if @buffer@ marks a discontinuity in a stream
bufferIsDiscont =
(elem BufferDiscont) . bufferGetFlags
-- | Return 'True' if the current 'Buffer' marks a discontinuity in a
-- stream, or 'False' otherwise.
bufferIsDiscontM :: (BufferClass bufferT, MonadIO m)
=> MiniObjectT bufferT m Bool -- ^ 'True' if the current buffer marks a
-- discontinuity in a stream
bufferIsDiscontM =
liftM (elem BufferDiscont) $ bufferGetFlagsM
-- | Create an empty 'Buffer' and mutate it according to the given
-- action. Once this function returns, the 'Buffer' is immutable.
bufferCreateEmpty :: MonadIO m
=> MiniObjectT Buffer m a -- ^ @mutate@ - the mutating action
-> m (Buffer, a) -- ^ the new buffer and the action's result
bufferCreateEmpty =
marshalMiniObjectModify $ liftIO {# call buffer_new #}
-- | Create and mutate a 'Buffer' of the given size.
bufferCreate :: MonadIO m
=> Word -- ^ @size@ - the size of the 'Buffer' to be created
-> MiniObjectT Buffer m a -- ^ @mutate@ - the mutating action
-> m (Buffer, a) -- ^ the new 'Buffer' and the action's result
bufferCreate size =
marshalMiniObjectModify $
liftIO $ {# call buffer_new_and_alloc #} $ fromIntegral size
-- | Create a sub-buffer from an existing 'Buffer' with the given offset
-- and size. This sub-buffer uses the actual memory space of the
-- parent buffer. Thus function will copy the offset and timestamp
-- fields when the offset is 0. Otherwise, they will both be set to
-- 'Nothing'. If the offset is 0 and the size is the total size of
-- the parent, the duration and offset end fields are also
-- copied. Otherwise they will be set to 'Nothing'.
bufferCreateSub :: BufferClass bufferT
=> bufferT -- ^ @parent@ - the parent buffer
-> Word -- ^ @offset@ - the offset
-> Word -- ^ @size@ - the size
-> Maybe Buffer -- ^ the new sub-buffer
bufferCreateSub parent offset size =
unsafePerformIO $
{# call buffer_create_sub #} (toBuffer parent)
(fromIntegral offset)
(fromIntegral size) >>=
maybePeek takeMiniObject
-- | Return 'True' if 'bufferSpan' can be done without copying the
-- data, or 'False' otherwise.
bufferIsSpanFast :: (BufferClass bufferT1, BufferClass bufferT2)
=> bufferT1 -- ^ @buffer1@ - the first buffer
-> bufferT2 -- ^ @buffer2@ - the second buffer
-> Bool -- ^ 'True' if the buffers are contiguous,
-- or 'False' if copying would be
-- required
bufferIsSpanFast buffer1 buffer2 =
toBool $ unsafePerformIO $
{# call buffer_is_span_fast #} (toBuffer buffer1)
(toBuffer buffer2)
-- | Create a new 'Buffer' that consists of a span across the given
-- buffers. Logically, the buffers are concatenated to make a larger
-- buffer, and a new buffer is created at the given offset and with
-- the given size.
--
-- If the two buffers are children of the same larger buffer, and
-- are contiguous, no copying is necessary. You can use
-- 'bufferIsSpanFast' to determine if copying is needed.
bufferSpan :: (BufferClass bufferT1, BufferClass bufferT2)
=> bufferT1 -- ^ @buffer1@ - the first buffer
-> Word32 -- ^ @offset@ - the offset into the concatenated buffer
-> bufferT2 -- ^ @buffer2@ - the second buffer
-> Word32 -- ^ @len@ - the length of the final buffer
-> Maybe Buffer -- ^ the spanning buffer, or 'Nothing' if
-- the arguments are invalid
bufferSpan buffer1 offset buffer2 len =
unsafePerformIO $
{# call buffer_span #} (toBuffer buffer1)
(fromIntegral offset)
(toBuffer buffer2)
(fromIntegral len) >>=
maybePeek takeMiniObject
-- | Concatenate two buffers. If the buffers point to contiguous memory
-- areas, no copying will occur.
bufferMerge :: (BufferClass bufferT1, BufferClass bufferT2)
=> bufferT1 -- ^ @buffer1@ - a buffer
-> bufferT2 -- ^ @buffer2@ - a buffer
-> Buffer -- ^ the concatenation of the buffers
bufferMerge buffer1 buffer2 =
unsafePerformIO $
{# call buffer_merge #} (toBuffer buffer1)
(toBuffer buffer2) >>=
takeMiniObject