Hi All,
I have a working C++ code for Jetson TX1 (L4T r24) which does H.264 file compression on a raw gray scale movie and stores frames in an AVI container. The intention is to compress a raw movie file with different compression ratios to control the compressed movie size.
When I use the same code on TX2 (L4T r32) the same pipeline doesn’t work. There are several issues that I see on TX2, which are listed below.
-
I made the control-rate=0 for omxh264enc for TX1 (saw few suggestions on this forum to use control-rate for h264 encoder pipelines), when I use the same setting on TX2, it makes the video too choppy. So, in the code I made a compilation flag for TX1 only to use “control-rate”, and TX2 runs with default flag or control-rate=2.
-
I made “qp-range” = “10,50:10,50:0,1” for best video quality (which gives me ~4X compression) for our purpose, the same parameter for TX2 give me ~300X compression and choppy video.
-
If I use the “h264parse” in TX2 pipeline, it freezes the entire pipeline, I can see that the around 7 frames were read from the file, but none reached to compressed file and the pipeline froze, so I made it available only for TX1.
So, now the pipeline works for TX2, but the video quality is too bad and compression is ~300X regardless
of different qp-range. -
I tune qp-range for TX2 experimentally to produce same compression ratio as TX1, but, now video file is short of few frames, for example, 170 frame raw movie would only generate 140 frames compressed movie (the code in PLATFORM_TX2 compilation flag). I am sending EOS when all frames from the source movie is consumed by the pipeline.
-
I don’t have a good understanding of “qp-range”, but we already have a solution with TX1 qp-range parameters, we now want to tune TX2 to give same compression ratio.
Any help is appreciated, to understand why I see so many differences on TX2 compared to TX1, is there any fundamental change on TX2 that I am missing ?
Please find the pipeline source code function below:
GstDisplayPtr GstApp::buildH264FileDisplay(uint32_t displayId, GstApp *app)
{
GstElement *displayBin = NULL;
GstElement *preQueue = NULL;
GstElement *queue = NULL;
GstElement *converter = NULL;
GstElement *converterFilter = NULL;
//GstElement *videorate = NULL;
//GstElement *videorateFilter = NULL;
GstElement *encoder = NULL;
GstElement *encoderParser = NULL;
GstElement *encoderFilter = NULL;
GstElement *parse = NULL;
GstElement *container = NULL;
GstElement *containerFilter = NULL;
GstElement *sink = NULL;
GstPad *ghostPad = NULL;
GstCaps *converterCaps = NULL;
GstCaps *videorateCaps = NULL;
GstCaps *encoderCaps = NULL;
GstCaps *containerCaps = NULL;
GstDisplayPtr display(new struct GstDisplay);
uint32_t videorateMax = 120;
display->id = displayId;
display->filterCounter = 0;
display->type = DisplayType::H264_FILE_D;
display->bin = NULL;
display->preFilter = NULL;
display->postFilter = NULL;
std::string binName = "H264FileBin_" + std::to_string(displayId);
displayBin = gst_bin_new (binName.c_str());
preQueue = gst_element_factory_make ("queue", NULL);
queue = gst_element_factory_make ("queue", NULL);
converter = gst_element_factory_make ("videoconvert", NULL);
converterFilter = gst_element_factory_make ("capsfilter", NULL);
//videorate = gst_element_factory_make("videorate", NULL);
//videorateFilter = gst_element_factory_make ("capsfilter", NULL);
encoder = gst_element_factory_make ("omxh264enc", NULL);
encoderFilter = gst_element_factory_make ("capsfilter", NULL);
encoderParser = gst_element_factory_make ("h264parse", NULL);
container = gst_element_factory_make ("avimux", NULL);
// container = gst_element_factory_make ("qtmux", NULL);
sink = gst_element_factory_make ("filesink", NULL);
uint32_t width = getDisplayWidth();
uint32_t height = getDisplayHeight();
fill_dr_matrix(width, height);
std::string memTypeString = "video/x-raw";
std::string formatTypeString = "format=NV12";
std::string widthString = "width=" + std::to_string(width);
std::string heightString = "height=" + std::to_string(height);
//std::string framerate = "framerate=" + std::to_string(videorateMax);
std::string converterCapsString = memTypeString + ',' +
formatTypeString + ',' + widthString + ',' +
heightString;
converterCaps = gst_caps_from_string(converterCapsString.c_str());
//videorateCaps = gst_caps_new_simple("video/x-raw",
// "framerate", GST_TYPE_FRACTION, videorateMax, 1,
// NULL);
std::string encoderCapsString = "video/x-h264, stream-format=(string)byte-stream";
encoderCaps = gst_caps_from_string(encoderCapsString.c_str());
g_object_set (G_OBJECT (converterFilter), "caps", converterCaps, NULL);
//g_object_set (G_OBJECT (videorateFilter), "caps", videorateCaps, NULL);
g_object_set (G_OBJECT (encoderFilter), "caps", encoderCaps, NULL);
#if defined(PLATFORM_TX1)
g_object_set (G_OBJECT (encoder), "control-rate", 0, NULL);
switch(app->qfactor) {
case COMP_QUALITY_FACTOR_BEST:
g_object_set (G_OBJECT (encoder), "qp-range", "10,50:10,50:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_MODERATE:
g_object_set (G_OBJECT (encoder), "qp-range", "20,50:20,50:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_GOOD:
g_object_set (G_OBJECT (encoder), "qp-range", "25,50:25,50:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_AVERAGE:
g_object_set (G_OBJECT (encoder), "qp-range", "30,50:30,50:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_FAIR:
g_object_set (G_OBJECT (encoder), "qp-range", "35,50:35,50:0,1", NULL);
break;
default:
LOG_INFO("quality param ", app->qfactor,", fallback to moderate");
g_object_set (G_OBJECT (encoder), "qp-range", "20,50:20,50:0,1", NULL);
break;
}
#elif defined(PLATFORM_TX2)
g_object_set (G_OBJECT (encoder), "control-rate", 2, NULL);
switch(app->qfactor) {
case COMP_QUALITY_FACTOR_BEST:
g_object_set (G_OBJECT (encoder), "qp-range", "5,10:5,10:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_MODERATE:
g_object_set (G_OBJECT (encoder), "qp-range", "15,20:15,20:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_GOOD:
g_object_set (G_OBJECT (encoder), "qp-range", "20,23:20,23:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_AVERAGE:
g_object_set (G_OBJECT (encoder), "qp-range", "23,29:23,29:0,1", NULL);
break;
case COMP_QUALITY_FACTOR_FAIR:
g_object_set (G_OBJECT (encoder), "qp-range", "25,32:25,32:0,1", NULL);
break;
default:
LOG_INFO("quality param ", app->qfactor,", fallback to moderate");
g_object_set (G_OBJECT (encoder), "qp-range", "15,20:15,20:0,1", NULL);
break;
}
#endif
g_object_set (G_OBJECT (encoder), "quant-i-frames", 0, NULL);
g_object_set (G_OBJECT (encoder), "quant-p-frames", 0, NULL);
/* override host field, else need to add new strings in cmd args */
IsxcStorage *isxcStoragePtr = app->getIsxcStorage();
const char *isxcFileName = isxcStoragePtr->isxcFileName.c_str();
if(isxcFileName) {
LOG_WARN("isxc file is : ", isxcFileName);
g_object_set (G_OBJECT (sink), "location", (char *)isxcFileName, NULL);
} else {
LOG_WARN("isxc file is : ", isxcFileName, ", fixing to final.isxc");
g_object_set (G_OBJECT (sink), "location", "final.isxc", NULL);
}
g_object_set (G_OBJECT (sink), "append", true, NULL);
gst_bin_add_many (GST_BIN (displayBin), preQueue, queue, converter,
converterFilter, encoder, encoderFilter,
#if defined(PLATFORM_TX1)
encoderParser,
#endif
container, sink, NULL);
if(gst_element_link_many(preQueue, queue, converter, converterFilter,
encoder, encoderFilter,
#if defined(PLATFORM_TX1)
encoderParser,
#endif
container,
sink, NULL) != TRUE)
{
LOG_ERROR("Elements for H264 file sink could not be linked");
return display;
}
ghostPad = gst_element_get_static_pad (preQueue, "sink");
gst_element_add_pad (displayBin, gst_ghost_pad_new ("sink", ghostPad));
gst_object_unref (GST_OBJECT (ghostPad));
if(m_bitDepth == 16)
{
GstPad *pad = gst_element_get_static_pad (preQueue, "src");
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
(GstPadProbeCallback) GstApp::interceptDataProbeGray16Yc,
(gpointer) app, NULL);
gst_object_unref (pad);
}
LOG_INFO("H264 file sink built");
display->bin = displayBin;
display->preFilter = queue;
display->postFilter = converter;
display->sink = sink;
display->fpsThread = std::thread(GstApp::trackFps, display);
display->enabled = true;
//display->videorateFilter = videorateFilter;
return display;
}