This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM572x encoding application using gstreamer

Hi All,

I am trying to make simple encoding application which takes yuv input and provides ".H264" output, using gstreamer APIs, which runs on AM572x evm. I just want to do a static file operation for now. Meaning, it takes "YUV" inputs from file and dumps "H264" output to another file.

I do not want to use gst-launch binary, and command line interface.

I want to make my own application, which uses gstreamer APIs and ducati plugin, so that we can also use the IVA co-processor capabilities. But, I am facing few issues in creating g-streamer pipeline and setting encoder properties.

Please find attached application code.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>

#include <gst/gst.h>

#define ERR	-1
#define SUCCESS	 0

typedef struct pipeline_ele {
	int status;
	GstElement *pipeline;
}pipeline_ele;

void show_help(void)
{
	printf("Application Usage: \n");
	printf("./gsttestencoder -i <input filename> -o <output filename> \n");
	printf("<input filename> = YUV format raw file \n");
	printf("<output filename> = .H264 filename along with path \n");
}

void src_pad_added_cb(GstElement *element, GstPad *pad, void *data)
{
	GstElement *parse = GST_ELEMENT (data);
	GstPad *srcPad = NULL;
	char *thename = GST_PAD_NAME (pad);
	
	printf("pad added: %s\n", thename);
	srcPad = gst_element_get_static_pad(parse, "source");
	gst_pad_link(pad, srcPad);
	gst_object_unref(srcPad);
}

pipeline_ele* create_pipeline(char *src_filename, char *dst_filename)
{
	GstElement *source = NULL;
	GstElement *encode = NULL;
	GstElement *sink = NULL;
        GstCaps *encodeCaps = NULL;
	pipeline_ele *element = NULL;
	const char *enc_name;

	element = (pipeline_ele *)malloc(sizeof(pipeline_ele));
	if(NULL == element)
	{
		printf("Can not allocate memory..\n");
		return;
	}

	if((NULL == src_filename) || (NULL == dst_filename))
	{
		printf("Invalid argument to create pipeline function\n");
		element->status = ERR;
		return element;
	}
	enc_name = "ducatih264enc";
	
	element->pipeline = gst_pipeline_new("encoding-pipeline");
	source = gst_element_factory_make("filesrc", "source");
	if(!source)
	{
		printf("Error in creating source element\n");
		element->status = ERR;
		return element;
	}
	encode = gst_element_factory_make(enc_name, "encode");
	if(!encode)
	{
                printf("Error in creating encoding element\n");
                element->status = ERR;
                return element;		
	}
	printf("Destination filename: %s\n", dst_filename);
	sink = gst_element_factory_make("filedst", "sink");
	if(!sink)
	{
		printf("Error in creating sink element\n");
		element->status = ERR;
		return element;
	}
  	
	#if 0
	sinkpad = gst_element_get_compatible_pad();
        if(NULL == sinkpad)
        {
                printf("Unable to allocate sink pad\n");
        }
        
	sinkCaps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV12", "width", G_TYPE_INT, "720", "height", G_TYPE_INT, "480", "framerate", GST_TYPE_FRACTION, "30", 1, NULL);
        if(NULL == sinkCaps)
        {
                printf("Set sink capabilities failed\n");
        }
        #endif
	//g_object_set((G_OBJECT)sinkpad, "caps", sinkCaps, NULL);
	
	encodeCaps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "YUV2", "width", G_TYPE_INT, "1024", "height", G_TYPE_INT, "768", "stream-format", G_TYPE_STRING, "byte-stream", "alignment", G_TYPE_STRING, "au", "profile", G_TYPE_STRING, "baseline", NULL);
	if(NULL == encodeCaps)
	{
		printf("Unable to set encoder capabilities\n");
	}
	/* setting parameters to encoder object */
	g_object_set(G_OBJECT (encode), "caps", encodeCaps, NULL);
	g_object_set(G_OBJECT (source), "location", src_filename, NULL);
	g_object_set(G_OBJECT (sink), "location", dst_filename, NULL);
	gst_caps_unref (encodeCaps);
#if 0
	gst_bin_add_many(GST_BIN (element->pipeline), source, encode, sink, NULL);
	gst_element_link_many(source, NULL);
	gst_element_link_many(encode, sink, NULL);
#endif
#if 0
	if(!g_signal_connect(encode, "pad-added", G_CALLBACK(sinkpad), (void *)encode))
	{
		printf("Can not connect sink pad added\n");
	}
#endif
        if(!g_signal_connect(source, "pad-added", G_CALLBACK(src_pad_added_cb), (void *)encode))
        {
                printf("Can not connect source pad added\n");
        }	
	element->status = SUCCESS;
	return element;
}

int main(int argc, char *argv [])
{
	GstElement *p;
	pipeline_ele *pipe_element = NULL;

	pipe_element = (pipeline_ele *)malloc(sizeof(pipeline_ele));
	if(NULL == pipe_element)
	{
		printf("Failed to allocate memory for pipeline structure\n");
		return 1;
	}
	memset(pipe_element, 0x00, sizeof(pipeline_ele));

	gst_init(&argc, &argv); //initialize g-streamer engine

	if((argc < 2) || (0 == strcmp(argv[1],"--help")) || (0 == strcmp(argv[1], "-h")))
	{
		show_help();
		return 1;
	}

	pipe_element = create_pipeline(argv[1], argv[2]);
	if(ERR == pipe_element->status)
	{
		printf("Gstreamer pipeline creation failed\n");
		return 1;
	}

	gst_object_unref(pipe_element->pipeline);
	if(NULL != pipe_element)
	{
		free(pipe_element);
		pipe_element = NULL;
	}
	sleep(1);

	return 0;	
}

This code shows me error, while creating "sink" element. 

It shows me error that "object class 'GstDucatiH264Enc' has no property named 'caps'".  Please guide me on how I can set encoder properties with ducati plugin. Also guide me if, I have made any mistakes in pipeline creation.

Please help me on this.

Thanks,

Krinali Shah

  • Hi,

    I will ask the software team to comment.
  • Hello,

    I would recommend you first to create the pipeline and test it on the board before to implement it in the app.

    You could check here for examples:
    processors.wiki.ti.com/.../Processor_Training:_Multimedia

    You could check with gst-inspect command the ducatih264enc's supported properties.
    This error (GstDucatiH264Enc' has no property named 'caps' ) it seems that you have encoder properties named: "caps". Please check with gst-inspect command for available encoder's properties.

    Let me know the pipeline, which is working for you.


    BR
    Margarita
  • Hello,

    I checked your source code.

    It seems that you are creating a caps filter(gst_caps_new_simple) not an encoder properties:

    encodeCaps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "YUV2", "width", G_TYPE_INT, "1024", "height", G_TYPE_INT, "768", "stream-format", G_TYPE_STRING, "byte-stream", "alignment", G_TYPE_STRING, "au", "profile", G_TYPE_STRING, "baseline", NULL);

    A caps filter in the pipeline is ! '...' !

    Here is an example :

     ! 'video/x-raw, format=(string)NV12, framerate=(fraction)24/1, width=(int)1280, height=(int)720'  !

    The encoder properties should be set like:


    g_object_set (G_OBJECT (encoder), "profile", "baseline", NULL);
    g_object_set (G_OBJECT (encoder), "xxxx", "xxxx", NULL);

    etc.


    Here is example for caps filter :

    static gboolean link_element_with_filter (GstElement *element1,
    GstElement *element2)

    {
        /* CAPS to be linked:
         * audio/x-raw-int, width=(int)1920, depth=(int)1080
         * */
        
        gboolean link_ok;
        GstCaps *caps;

        caps = gst_caps_new_simple ("video/x-raw",
        "width", G_TYPE_INT, 1920,
        "depth", G_TYPE_INT, 1080,
        NULL);
        
        link_ok = gst_element_link_filtered (element1, element2, caps);
        gst_caps_unref (caps);
        
        if (!link_ok) {
            g_warning ("Failed to link element1 and element2!(filesource->encoder)");
        }
        return link_ok;
        
        }

    ....


      gst_element_link_pads (filesource, "src", encoder, "sink");
      link_element_with_filter(filesource, encoder);




    BR
    Margarita



  • Thanks Margarita.
    I will set the encoder properties like you have suggested above.
    But here are few queries,
    1. How can i differentiate between sink and source pad properties for my encoder element?
    eg, sink pad input format would be NV12/YUV2 and source pad format will be x-h264
    2. I believe I need to create two pads, setting properties of each pad and link them with encoder.
    3. Please suggest me some way to do it.
    4. My input and output both are static file, as I have mentioed in my requirement,
    So, what should be the pipeline state that I need to set?
    If I set "GST_STATE_PLAYING", on created pipeline, it gives me segmentation fault.

    Thanks,
    Krinali Shah
  • Hello,

    In the wiki page which I linked there is an example:

    target #  gst-launch-1.0 filesrc location=xxx.yuv ! videoparse width=352 height=288 format=nv12 ! ducatih264enc ! filesink location=xxx.h264

    The encoder support YUV NV12 format.

    krinali shah said:
    1. How can i differentiate between sink and source pad properties for my encoder element?
    eg, sink pad input format would be NV12/YUV2 and source pad format will be x-h264

    I am not sure that I completely understand the question.

    You have NV12 on the input of the encoder element and on the output you have an elementary stream (h264).

    If you need something like :

    .... ! ....format=nv12 ... ! encoder ! ...x-h264 ..! ...

    Check the caps filter example in my previous post.

    It would be better if you link me the pipeline which you are implementing the in app.

    krinali shah said:
    4. My input and output both are static file, as I have mentioed in my requirement,
    So, what should be the pipeline state that I need to set?

    For filesrc element:

    filesrc = gst_element_factory_make("filesrc", "filesource");
    //  g_return_val_if_fail (filesrc, -1);
      g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);

    or


      g_object_set (G_OBJECT (filesrc), "location", "full_path_and_file_name.yuv", NULL);

    For filesink element:

      filesink = gst_element_factory_make("filesink", "videofilesink");
    //  g_return_val_if_fail (filesink, -1);
      g_object_set (G_OBJECT (filesink), "location", "elementary_video.264", NULL);

    Add elements to the bin before linking them. Link the element's (src, sinks) pads after that, and then you could move to playing state.


    BR
    Margarita

  • Hello,

    I would recommend you to check this element as well:
    processors.wiki.ti.com/.../Linux_Core_VPE_User's_Guide

    BR
    Margarita
  • Thanks Margarita.. :)

    Yes. Input format is fixed. ie. NV12..
    But we need to set properties like "height" ,"width", "input framerate" etc. to the input side of encoder, and at output side, we need to set "profile_type", "profile_level", "bitrate" etc.
    I do not understand how i can set this parameters.
    Without setting these parameters and creating a link as you suggested, I could now play the pipeline. And output file gets generated, but still am not able to play the ".H264" file. It is not encoded properly.

    my code snippet is as below,

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <unistd.h>

    #include <gst/gst.h>

    #define ERR -1
    #define SUCCESS 0

    typedef struct pipeline_ele {
    int status;
    GstElement *pipeline;
    }pipeline_ele;

    void show_help(void)
    {
    printf("Application Usage: \n");
    printf("./gsttestencoder -i <input filename> -o <output filename> \n");
    printf("<input filename> = YUV format raw file \n");
    printf("<output filename> = .H264 filename along with path \n");
    }
    pipeline_ele* create_pipeline(char *src_filename, char *dst_filename)
    {
    GstElement *source = NULL;
    GstElement *encode = NULL;
    GstElement *sink = NULL;
    GstElementFactory *factory = NULL;
    pipeline_ele *element = NULL;
    const char *enc_name;

    element = (pipeline_ele *)malloc(sizeof(pipeline_ele));
    if(NULL == element)
    {
    printf("Can not allocate memory..\n");
    return;
    }

    if((NULL == src_filename) || (NULL == dst_filename))
    {
    printf("Invalid argument to create pipeline function\n");
    element->status = ERR;
    return element;
    }
    enc_name = "ducatih264enc";

    element->pipeline = gst_pipeline_new("encoding-pipeline");
    source = gst_element_factory_make("filesrc", "filesource");
    if(!source)
    {
    printf("Error in creating source element\n");
    element->status = ERR;
    return element;
    }
    encode = gst_element_factory_make(enc_name, "encode");
    if(!encode)
    {
    printf("Error in creating encoding element\n");
    element->status = ERR;
    return element;
    }
    factory = gst_element_factory_find("filesink");
    if(NULL == factory)
    {
    printf("failed to find factory of type fakesink\n");
    }
    sink = gst_element_factory_make("filesink", "sink");
    if(!sink)
    {
    printf("Error in creating sink element\n");
    element->status = ERR;
    return element;
    }
    g_object_set(G_OBJECT (source), "location", src_filename, NULL);
    g_object_set(G_OBJECT (sink), "location", dst_filename, NULL);
    gst_bin_add_many(GST_BIN (element->pipeline), source, encode, sink, NULL);
    gst_element_link_many(source, sink, NULL);
    element->status = SUCCESS;
    gst_element_set_state(element->pipeline, GST_STATE_PLAYING);
    return element;
    }

    int main(int argc, char *argv [])
    {
    GstElement *p;
    pipeline_ele *pipe_element = NULL;

    pipe_element = (pipeline_ele *)malloc(sizeof(pipeline_ele));
    if(NULL == pipe_element)
    {
    printf("Failed to allocate memory for pipeline structure\n");
    return 1;
    }
    memset(pipe_element, 0x00, sizeof(pipeline_ele));

    gst_init(&argc, &argv); //initialize g-streamer engine

    if((argc < 2) || (0 == strcmp(argv[1],"--help")) || (0 == strcmp(argv[1], "-h")))
    {
    show_help();
    return 1;
    }

    pipe_element = create_pipeline(argv[2], argv[4]);
    if(ERR == pipe_element->status)
    {
    printf("Gstreamer pipeline creation failed\n");
    return 1;
    }
    gst_object_unref(pipe_element->pipeline);
    if(NULL != pipe_element)
    {
    free(pipe_element);
    pipe_element = NULL;
    }
    sleep(1);

    return 0;
    }

    Thanks,
    Krinali Shah
  • Hello,

    Could you post how the  pipeline is look like?

    Could you verify the pipeline in the console and the h264 elementary stream?

    Did you check with gst-inspect command what are the supported gst encoder properties?

    The properties in gstreamer are set with g_object_set ().

    BR
    Margarita

  • Hi Margarita,

    Yes, I have tested the pipeline below, for encoding using ducati-h264 encoder,

    gst-launch-1.0 filesrc location=input_nv12.yuv ! videoparse width=1024 height=768 format=nv12 ! ducatih264enc ! filesink location=output1.h264

    This command line pipeline works absolutely fine, and generates proper output. But, when I try to create same gstreamer pipeline using my own application it does not work. It generates some garbage output and output ".H264" file can not get played.

    filesrc -> encoder(ducatiH264) -> filesink.

    The output generated is not proper.

    I have also checked the supported properties of ducati h64 encoder using gst-inspect command,
    Element Properties:
    name : The name of the object
    parent : The parent of the object
    bitrate : Bitrate in kbit/sec
    rate-preset : H.264 Rate Control
    intra-interval : Interval between intra frames (keyframes)
    profile : H.264 Profile
    (66): baseline - Base Profile
    (77): main - Main Profile
    (88): extended - Extended Profile
    (100): high - High Profile
    (110): high-10 - High 10 Profile
    (122): high-422 - High 4:2:2 Profile
    level : H.264 Level
    (10): level-1 - Level 1
    (9): level-1b - Level 1b
    (11): level-11 - Level 11
    (12): level-12 - Level 12
    (13): level-13 - Level 13
    (20): level-2 - Level 2
    (21): level-21 - Level 21
    (22): level-22 - Level 22
    (30): level-3 - Level 3
    (31): level-31 - Level 31
    (32): level-32 - Level 32
    (40): level-4 - Level 4
    (41): level-41 - Level 41
    (42): level-42 - Level 42
    (50): level-5 - Level 5
    (51): level-51 - Level 51
    rate-control-params-preset: This preset controls the USER_DEFINED versus DEFAULT mode. If you are not aware about the fields, it should be set as 'rate-control-params-preset-default'

    rate-control-algo : This defines the rate control algorithm to be used. Only useful if 'rate-control-params-preset' is set as 'rate-control-params-preset-user-defined'

    qpi : Initial quantization parameter for I/IDR frames.

    qp-max-i : Maximum quantization parameter for I/IDR frames.

    qp-min-i : Minimum quantization parameter for I/IDR frames.

    hrd-buffer-size : Hypothetical reference decoder buffer size. This size controls the frame skip logic of the encoder. For low delay applications this size should be small. This size is in bits. Maximum Value is level dependant and min value is 4096

    entropy-coding-mode : Controls the entropy coding type.

    inter-interval : Max inter frame interval (B frames are allowed between them if > 1)

    slice-mode : This defines the control mechanism to split a picture in slices. It can be either MB based or bytes based

    Thanks,
    Krinali Shah

  • Hello,

    krinali shah said:
    gst-launch-1.0 filesrc location=input_nv12.yuv ! videoparse width=1024 height=768 format=nv12 ! ducatih264enc ! filesink location=output1.h264

    I do not see videoparse element in your app gsttestencoder.c.

    Could you create it?

      parser = gst_element_factory_make("videoparse","parser");
      g_return_val_if_fail (parser, -1);

    Could you set these properties:

    g_object_set( G_OBJECT(parser), "width", .... , NULL );

    g_object_set( G_OBJECT(parser), "height", .... , NULL );

    g_object_set( G_OBJECT(parser), "format", ...  , NULL );

    BR
    Margarita

  • Hi Margarita,

    Yes. after adding video parsing link, it worked.
    Thanks a lot for your prompt support.
    Really appreciated..!! :)

    Thanks,
    Krinali Shah
  • Hello,

    I am glad that this issue is resolved.
    Please, verify this thread.

    BR
    Margarita