Specify start absolute timestamp to overlay

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Specify start absolute timestamp to overlay

marc lievens-3

Hi Gstreamer Guys,

 

Is there a way to specify the start absolute timestamp which has to be overlay while playing video from file.

 

I already did take a look  with  ClockOverlay, TimeOverlay and TextOverlay, but this doesn’t allow me start date time to use, or I missed something

 

I presume that this can be done somehow via a probe and add the date time on every frame while recording or playing the video.

 

But I presume that there are more easier ways to establish this.

 

Thanks for any tips.

 


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Specify start absolute timestamp to overlay

jackBuffington
You could do it with custom element if you are up for it.  I'm timestamping
my video using a custom element but am doing it with binary code as small as
possible so that I can do machine vision stuff later.  In short I am working
off of the GstBaseTransform template provide by:
https://gstreamer.mazdermind.de/

I've implemented a transform function rather than a transform_ip function.
I think that it should be possible to use transform_ip but I couldn't get it
to work.    I've attached some code.  It doesn't do exactly what you want
but should be a good starting point.  




// Here is where the input buffer is manipulated and copied to the output
buffer(s)
static GstFlowReturn gst_lfselement_transform (GstBaseTransform *trans,
GstBuffer *inbuf, GstBuffer *outbuf)
{

        GstMapInfo inMap, outMap;
        guint8 *dest;
        guint8 *src;
        static int frameCount = 0;
        static int lastSeconds = 0;

        gsize maxsize;
        gsize inSize = gst_buffer_get_sizes (inbuf, NULL , &maxsize);
        //~ g_print ( " In buf: \n " );
        //~ g_print ( " In size:%lu " G_GSIZE_FORMAT " \n " , inSize);
        //~ g_print ( " In maxsize:%lu " G_GSIZE_FORMAT " \n " , maxsize);
        //~ g_print ( " In number of buffers: %u \n " , gst_buffer_n_memory
(inbuf));


        //~ gsize outSize = gst_buffer_get_sizes (outbuf, NULL , &maxsize);
        //~ g_print ( " Out buf: \n " );
        //~ g_print ( " Out size:%lu " G_GSIZE_FORMAT " \n " , outSize);
        //~ g_print ( " Out maxsize:%lu " G_GSIZE_FORMAT " \n " , maxsize);
        //~ g_print ( " Out number of buffers: %u \n " , gst_buffer_n_memory
(outbuf));



        // map the input buffer
        if (!gst_buffer_map (inbuf, &inMap, GST_MAP_READ))
        {
                GST_WARNING_OBJECT (trans, "Could not map input buffer, skipping");
                return GST_FLOW_OK;
        }

        // map the output buffer
        if (!gst_buffer_map (outbuf, &outMap, GST_MAP_WRITE))
        {
                gst_buffer_unmap (inbuf, &inMap);
                GST_WARNING_OBJECT (trans, "Could not map output buffer, skipping");
                return GST_FLOW_OK;
        }

        dest = outMap.data;
        src = inMap.data;

       
        // Here's the do-nothing part.  It simply copies the buffer.
        copyBuffer(src, dest, inSize);
       
       
       
        // Here is the do-something part.  
        GstLfselement *lfselement = GST_LFSELEMENT (trans);
       
       
        // encode some data onto the bottom of the screen.
        time_t now = time(NULL);
        struct tm currentTime = *localtime(&now);
       
        struct timeval curTime;
        gettimeofday(&curTime, NULL);
        int milli = curTime.tv_usec / 1000;
        uint8_t milliHigh = milli / 256;
        uint8_t milliLow = milli % 256;
       
        uint8_t timeStamp[5] = {currentTime.tm_hour, currentTime.tm_min,
currentTime.tm_sec, milliHigh, milliLow};
        encodeData(dest, 0, 478, lfselement->outInfo.width, timeStamp, 5);
       

        // Tidy up
        gst_buffer_unmap (outbuf, &outMap);
        gst_buffer_unmap (inbuf, &inMap);
        return GST_FLOW_OK;

}



static void copyBuffer(guint8 *inBuffer, guint8 *outBuffer, int bufferSize)
{  
  // Copies each byte from the input buffer into the output buffer
  // TODO:  This could probably be faster by using 64-bit variables.  

  guint8 *inPtr = (guint8*) inBuffer;
  guint8 *inEnd = inPtr + (bufferSize);

  do
  {
    *outBuffer++ = *inPtr++;
  }
  while (inPtr < inEnd - 1);
}




static void inline setPixel(guint8 *buffer, int X, int Y, int value, int
width)
{ /* Sets the pixel at that location to the given value
        X and Y are the location of the pixel that I want to set.
        width and height are the dimensions of the image.
       
        UYVY data is formatted in groups of two pixels per UYVY grouping.
        Think of it like this U (Y1) V (Y2)  where
        Pixel 1 is Y1, U, V
        Pixel 2 is Y2, U, V
        U and V are sampled on every other column but are sampled on every row.
         
        ### IT IS UP TO THE USER TO NOT SPECIFY A PIXEL LOCATION OUTSIDE OF ###
        ### THE BOUNDS OF THE BUFFER! ###
        */
       
        // Calculate the location in the buffer where the pixel should be set
        int rowOffset = Y * width * 2;
        int blockOffset = (X/2) * 2;
        int whichY = X % 2; // this is which Y in the block that this corresponds
to
       
        int offset = rowOffset + blockOffset; // this is the location of the
beginning of the UYVY block
       
        buffer += offset;
        *buffer = 128; // U
        *(buffer + 2) = 128;   // Y
        if(whichY)
                *(buffer + 3) = value;
        else
                *(buffer + 1) = value;
}



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Specify start absolute timestamp to overlay

marc lievens-2
Hi,

Thanks for the info. 
Seems not easy at first glance, but I'm certain going to try this.





Op di 4 feb. 2020 om 00:43 schreef jackBuffington <[hidden email]>:
You could do it with custom element if you are up for it.  I'm timestamping
my video using a custom element but am doing it with binary code as small as
possible so that I can do machine vision stuff later.  In short I am working
off of the GstBaseTransform template provide by:
https://gstreamer.mazdermind.de/

I've implemented a transform function rather than a transform_ip function.
I think that it should be possible to use transform_ip but I couldn't get it
to work.    I've attached some code.  It doesn't do exactly what you want
but should be a good starting point. 




// Here is where the input buffer is manipulated and copied to the output
buffer(s)
static GstFlowReturn gst_lfselement_transform (GstBaseTransform *trans,
GstBuffer *inbuf, GstBuffer *outbuf)
{

        GstMapInfo inMap, outMap;
        guint8 *dest;
        guint8 *src;
        static int frameCount = 0;
        static int lastSeconds = 0;

        gsize maxsize;
        gsize inSize = gst_buffer_get_sizes (inbuf, NULL , &maxsize);
        //~ g_print ( " In buf: \n " );
        //~ g_print ( " In size:%lu " G_GSIZE_FORMAT " \n " , inSize);
        //~ g_print ( " In maxsize:%lu " G_GSIZE_FORMAT " \n " , maxsize);
        //~ g_print ( " In number of buffers: %u \n " , gst_buffer_n_memory
(inbuf));


        //~ gsize outSize = gst_buffer_get_sizes (outbuf, NULL , &maxsize);
        //~ g_print ( " Out buf: \n " );
        //~ g_print ( " Out size:%lu " G_GSIZE_FORMAT " \n " , outSize);
        //~ g_print ( " Out maxsize:%lu " G_GSIZE_FORMAT " \n " , maxsize);
        //~ g_print ( " Out number of buffers: %u \n " , gst_buffer_n_memory
(outbuf));



        // map the input buffer
        if (!gst_buffer_map (inbuf, &inMap, GST_MAP_READ))
        {
                GST_WARNING_OBJECT (trans, "Could not map input buffer, skipping");
                return GST_FLOW_OK;
        }

        // map the output buffer
        if (!gst_buffer_map (outbuf, &outMap, GST_MAP_WRITE))
        {
                gst_buffer_unmap (inbuf, &inMap);
                GST_WARNING_OBJECT (trans, "Could not map output buffer, skipping");
                return GST_FLOW_OK;
        }

        dest = outMap.data;
        src = inMap.data;


        // Here's the do-nothing part.  It simply copies the buffer.
        copyBuffer(src, dest, inSize);



        // Here is the do-something part. 
        GstLfselement *lfselement = GST_LFSELEMENT (trans);


        // encode some data onto the bottom of the screen.
        time_t now = time(NULL);
        struct tm currentTime = *localtime(&now);

        struct timeval curTime;
        gettimeofday(&curTime, NULL);
        int milli = curTime.tv_usec / 1000;
        uint8_t milliHigh = milli / 256;
        uint8_t milliLow = milli % 256;

        uint8_t timeStamp[5] = {currentTime.tm_hour, currentTime.tm_min,
currentTime.tm_sec, milliHigh, milliLow};
        encodeData(dest, 0, 478, lfselement->outInfo.width, timeStamp, 5);


        // Tidy up
        gst_buffer_unmap (outbuf, &outMap);
        gst_buffer_unmap (inbuf, &inMap);
        return GST_FLOW_OK;

}



static void copyBuffer(guint8 *inBuffer, guint8 *outBuffer, int bufferSize)
{   
  // Copies each byte from the input buffer into the output buffer
  // TODO:  This could probably be faster by using 64-bit variables. 

  guint8 *inPtr = (guint8*) inBuffer;
  guint8 *inEnd = inPtr + (bufferSize);

  do
  {
    *outBuffer++ = *inPtr++;
  }
  while (inPtr < inEnd - 1);
}




static void inline setPixel(guint8 *buffer, int X, int Y, int value, int
width)
{       /* Sets the pixel at that location to the given value
        X and Y are the location of the pixel that I want to set.
        width and height are the dimensions of the image.

        UYVY data is formatted in groups of two pixels per UYVY grouping.
        Think of it like this U (Y1) V (Y2)  where
        Pixel 1 is Y1, U, V
        Pixel 2 is Y2, U, V
        U and V are sampled on every other column but are sampled on every row.

        ### IT IS UP TO THE USER TO NOT SPECIFY A PIXEL LOCATION OUTSIDE OF     ###
        ### THE BOUNDS OF THE BUFFER!                                                                                                   ###
        */

        // Calculate the location in the buffer where the pixel should be set
        int rowOffset = Y * width * 2;
        int blockOffset = (X/2) * 2;
        int whichY = X % 2; // this is which Y in the block that this corresponds
to

        int offset = rowOffset + blockOffset; // this is the location of the
beginning of the UYVY block

        buffer += offset;
        *buffer = 128;                  // U
        *(buffer + 2) = 128;   // Y
        if(whichY)
                *(buffer + 3) = value;
        else
                *(buffer + 1) = value;
}



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel