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.

SK-AM62A-LP: H264 Encoder - I-Frames on Demand and Dynamic Bitrate Control

Part Number: SK-AM62A-LP

Hi,

I am trying to test whether the HW encoder can perform two seperate functions but am unable to get either to work, are either of these possible with the AM62A wave5 HW encoder?

1. I-Frames on demand - I want to be able to request an I frame (key frame) on demand while running a live stream through the encoder, to test this I have written the following code:

#include <gst/gst.h>

static GstElement *enc = NULL;  // Declare the enc element globally

// Function to send a key frame request event to the queue 
static gboolean send_key_frame_request(gpointer data) {
    g_print("Sending key frame request event to the queue.\n");

    // Create a custom downstream event with GstForceKeyUnit value
    GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, gst_structure_new("GstForceKeyUnit","all-headers",G_TYPE_BOOLEAN,TRUE,NULL));

    // Send the key frame request event to the queue
    gst_element_send_event(enc, event);
    g_print("Return to main loop.\n");
    return G_SOURCE_REMOVE;
}

int main(int argc, char *argv[]) {
    gst_init(&argc, &argv);

    // Create a GStreamer pipeline
    GstElement *pipeline = gst_parse_launch("videotestsrc pattern=ball is-live=true motion=wavy ! queue ! rawvideoparse width=3840 height=2160 format=i420 framerate=30/1 colorimetry=bt709 ! v4l2h264enc name=enc extra-controls=\"controls,frame_level_rate_control_enable=1,video_bitrate_mode=1,video_bitrate=20000000,h264_profile=0,h264_level=15,h264_entropy_mode=1,h264_i_frame_period=0,video_gop_size=0\" ! queue ! filesink location=/test/insert.h264 sync=false", NULL);
    enc = gst_bin_get_by_name(GST_BIN(pipeline), "enc");  //instantiate the queue object with my_queue
    if (enc != NULL) {
        gst_element_set_state (pipeline, GST_STATE_PLAYING);
        if (gst_element_get_state (pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) {
            g_error ("Failed to go into PLAYING state");
        }
        // Schedule key frame insert event after 10 seconds i.e. 300 frames
        g_timeout_add_seconds(10, send_key_frame_request, NULL);

        // Run the GMainLoop to process the scheduled events
        GMainLoop *loop = g_main_loop_new(NULL, FALSE);
        g_main_loop_run(loop);
        
        // clear the objects
        gst_object_unref(enc);
        gst_object_unref(pipeline);

    } else {
        g_print("Queue element not found in the pipeline.\n"); }

    return 0;
}

I can tell with the Gstreamer logs that the event is successfully sent to the encoder element, but V4L2 doesn't appear to do anything with it, the idea was that the event would trigger the button V4L2_CID_MPEG_FORCE_KEY_FRAME, which would then force the encoder to generate an I/key frame, but this does not happen. Is there a way to do this with the HW encoder?

2. Dynamic Bitrate Control - I would also like to be able to change the bitrate of the encoder on demand while running a live stream through the encoder, I have written the following:

#include <gst/gst.h> 

static GstElement *pipeline = NULL;
static GstElement *enc = NULL;

// Function to send a pause pipeline event, this will work as the src is a live feed
static gboolean set_1M(gpointer data) {
    g_print("Pausing pipeline.\n");
    gst_element_set_state(pipeline, GST_STATE_PAUSED);
    if (gst_element_get_state (pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) {
            // make sure state is PAUSED
            g_error ("Failed to go into PAUSED state");
    }
    g_object_set(enc, "extra-controls", gst_structure_from_string("controls,frame_level_rate_control_enable=1,video_bitrate_mode=1,video_bitrate=10000,h264_profile=1,h264_level=15", NULL), NULL);
    g_print("Changed params!\n");
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (gst_element_get_state (pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) {
            // make sure state is PLAYING
            g_error ("Failed to go into PLAYING state");
    }
    return G_SOURCE_REMOVE;  // Remove the timeout source after this function is called
}

int main(int argc, char *argv[]) {
    gst_init(&argc, &argv);

    // Create a GStreamer pipeline
    pipeline = gst_parse_launch("videotestsrc pattern=ball is-live=true motion=wavy ! queue ! rawvideoparse width=3840 height=2160 format=i420 framerate=30/1 colorimetry=bt709 ! v4l2h264enc name=enc extra-controls=\"controls,frame_level_rate_control_enable=1,video_bitrate_mode=1,video_bitrate=20000000,h264_profile=1,h264_level=15\" ! queue ! filesink location=/test/bwcontrol2.h264 sync=false", NULL);
    enc = gst_bin_get_by_name(GST_BIN(pipeline), "enc");


    if (pipeline != NULL) {
        // Set the pipeline going
        gst_element_set_state (pipeline, GST_STATE_PLAYING);
        if (gst_element_get_state (pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) {
            // Make sure it's running
            g_error ("Failed to go into PLAYING state");
        }
        // trigger pause after 30 seconds with g_timeout_add_seconds 
        g_timeout_add_seconds(10, set_1M, NULL);
        // Wait an hour with encoder paused, then re-start encoder
        //g_timeout_add_seconds(30, send_play, NULL);
        // Run the GMainLoop to process the scheduled events
        GMainLoop *loop = g_main_loop_new(NULL, FALSE);
        g_main_loop_run(loop);
        // clear the objects
        gst_object_unref(pipeline);

    } else {
        g_print("Pipeline element not found.\n"); }

    return 0;
}

But analysing the output video shows no difference in bitrate, is it possible to dynamically change the bitrate of the encoder while in a live pipeline?

  • Hi Matt,

    I am checking internally with the SW team. Will provide you an update by early next week.

    Best Regards,

    Suren

  • Thanks Suren,

    Any update on this so far?

    Kind regards,
    Matt

  • Hi Matt,

    Currently these are not supported on our SDK, But I am seeing if there is a feasibility of this being included in our later SDK releases. Will keep you posted.

    Best Regards,

    Suren

  • Hi Suren,

    Thanks for getting back to me, please do keep me posted if this becomes supported. 

    Am I to assume that dynamically changing the max and min qp values on the fly is also not supported (using a similar method)?

    Kind regards,

    Matt

  • Yes Matt, that's correct. I will keep you posted on when the support would be available.

    Best Regards,

    Suren

  • Thanks for this Suren,

    The project I'm working on is relatively time limited, I have been looking through the kernel source and particularly the wave5 codec driver, it looks like the driver itself doesn't support the features I require. I'm wondering if you have close contact with Chips & Media and can ask them the question as to whether their FW block will support these features if the codec driver was modified. I don't want to start on the path of modifying the wave5 driver if the FW itself cannot support the desired features.

    Kind regards,

    Matt

  • Matt,

    I-frame request, we are working on it. Will share the patch after its validated and verified. 

    Dynamic bitrate also should be supported, will share more updates when I attach the patch for I-frame. 

    Best Regards,

    Suren

  • Suren,

    Thanks very much for your support on this issue, I appreciate you patching this in! I have noted something interesting on dynamic bitstream, the program above does appear to correctly change the s_ctrls in the driver (as shown in kernel debug below), but these updated controls are not used by the VPU instance and therefore the output stream bitrate does not change. 

    When you say that "dynamic bitrate should also be supported", do you mean that the API currently supports it or that the upcoming patch will add this support?

    If the current driver version does support dynamic bitrate changes, do I just need to send some kind of event to the driver to tell it to refresh the VPU instance? Or will this support be added in the upcoming patch?

    Thanks again for your support, if it's possible to give a rough ETA on the patch that would be very much appreciated but if not no worries.

    Kind regards,

    Matt

  • Matt, 

    We are validating the patches still. Once validated, will share the patches for both dynamic bitrate and I-frame request.

    Best Regards,

    Suren

  • Hi Matt,

    The patches will be merged and available in 10.x release planned in the month of July and will be part of 6.6 Kernel.

    Best Regards,

    Suren

  • Hi Suren,

    Just to check, will this patch only be adding in dyanmic bitrate and I-frame insertion? I'm wondering if it was also be possible to do dynamic (frame-by-frame) QP changes as well, but this may not be added in to the latest patch. Will dynamic QP be included with the addition of dynamic bitrate?

    Kind regards,

    Matt

  • Hi Matt,

    Please find the two patches for I-frame request and bitrate.

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/791/v0_2D00_0001_2D00_media_2D00_chips_2D00_media_2D00_wave5_2D00_Support_2D00_a_2D00_force_2D00_key_2D00_frame.patchhttps://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/791/v0_2D00_0001_2D00_media_2D00_chips_2D00_media_2D00_wave5_2D00_Support_2D00_to_2D00_change_2D00_a_2D00_bitrate.patch

    After applying the above patch, if you issue v4l2-ctl -d 1 --list-ctrls-menu on a console, then you can see this "force_key_frame 0x009909e5 (button) : value=0 flags=write-only, execute-on-write" to support the request of I-frame.

    For bitrate testing:

    I assume, you should be able to change the QP value in similar fashion. These would be part of the 10.x SDK release.

    Feel free to try them on your end and see if it helps.

    Best Regards,

    Suren