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?