openh264 - bEnableFrameSkip=0, bitrate can't be controlled - c++

there are a lot of questions asked regarding opencv + H.264 but
none of them gave detailed explanation.
i am using openh264(openh264-1.4.0-win32msvc.dll) along with opencv 3.1(custom build with cmake having ffmpeg enabled) in visual studio, i wanted to save video coming from webcam in mp4 format with H.264 compression
VideoWriter write = VideoWriter("D:/movie.mp4", CV_FOURCC('H', '2',
'6', '4'), 10.0, cv::Size(192, 144), true);
before using openh264, in console window i was seeing an warning message
"Failed to load openh264 library : openh264-1.4.0-win32msvc.dll
please check your environment and/or download from here:
https://github.com/cisco/openh264/releases"
(also video was not been saved)
so i downloaded the dll & kept in a folder with my program file(exe)
now when i run the program, i'm seeing different error
"[OpenH264] this = 0x0DE312C0, warning: bEnabledFrameSkip=0, bitrate can't be controlled for RC_QUALITY_MODE and RC_TIMESTAMP_MODE without enabling skip frame"
(now video is saved, but size is very high! bit rate is around 1200 Kbps)
for me, the sole purpose of using h264 is to reduce the file size.. i think i may have to build openh264 myself with some changes to remove this error, can anyone guide me how? or tell me if there is a way to reduce bit rate somehow through code?
P.S: I tried giving -1 instead of CV_FOURCC(), 'installed codecs' window in my system showed up, i couldn't find h264 or x264 or h264vfw even though i have installed variety of codec packs & h264 from here
Thanks & regards

If you want to control bitrate, You have to use both
encoderParemeters.iRCMode = RC_OFF_MODE;
encoderParemeters.bEnableFrameSkip = true;
Here I am showing all the Openh264 Encoding parameters as an Example:
long nReturnedValueFromEncoder = WelsCreateSVCEncoder(&m_pSVCVideoEncoder);
m_nVideoWidth = 352;
m_nVideoHeight = 288;
SEncParamExt encoderParemeters;
memset(&encoderParemeters, 0, sizeof(SEncParamExt));
m_pSVCVideoEncoder->GetDefaultParams(&encoderParemeters);
encoderParemeters.iUsageType = CAMERA_VIDEO_REAL_TIME;
encoderParemeters.iTemporalLayerNum = 0;
encoderParemeters.uiIntraPeriod = 15;
encoderParemeters.eSpsPpsIdStrategy = INCREASING_ID;
encoderParemeters.bEnableSSEI = false;
encoderParemeters.bEnableFrameCroppingFlag = true;
encoderParemeters.iLoopFilterDisableIdc = 0;
encoderParemeters.iLoopFilterAlphaC0Offset = 0;
encoderParemeters.iLoopFilterBetaOffset = 0;
encoderParemeters.iMultipleThreadIdc = 0;
encoderParemeters.iRCMode = RC_BITRATE_MODE;
encoderParemeters.iMinQp = 0;
encoderParemeters.iMaxQp = 52;
encoderParemeters.bEnableDenoise = false;
encoderParemeters.bEnableSceneChangeDetect = false;
encoderParemeters.bEnableBackgroundDetection = true;
encoderParemeters.bEnableAdaptiveQuant = false;
encoderParemeters.bEnableFrameSkip = true;
encoderParemeters.bEnableLongTermReference = true;
encoderParemeters.iLtrMarkPeriod = 20;
encoderParemeters.bPrefixNalAddingCtrl = false;
encoderParemeters.iSpatialLayerNum = 1;
SSpatialLayerConfig *spartialLayerConfiguration = &encoderParemeters.sSpatialLayers[0];
spartialLayerConfiguration->uiProfileIdc = PRO_BASELINE;//;
encoderParemeters.iPicWidth = spartialLayerConfiguration->iVideoWidth = m_nVideoWidth;
encoderParemeters.iPicHeight = spartialLayerConfiguration->iVideoHeight = m_nVideoHeight;
encoderParemeters.fMaxFrameRate = spartialLayerConfiguration->fFrameRate = (float)30;
encoderParemeters.iTargetBitrate = spartialLayerConfiguration->iSpatialBitrate = 500000;
encoderParemeters.iTargetBitrate = spartialLayerConfiguration->iMaxSpatialBitrate = 500000;
spartialLayerConfiguration->iDLayerQp = 24;
//spartialLayerConfiguration->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE;
spartialLayerConfiguration->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
nReturnedValueFromEncoder = m_pSVCVideoEncoder->InitializeExt(&encoderParemeters);
Hope it will help you.

You can simply controlled bit rate using RC_BITRATE_MODE and enabling bEnableFrameSkip in Openh264.

Related

AVAssetExportSession make black video sometimes

I'm new baby for Video Processing use Swift 3. I try to merge multiple videos with AVAssetExportSession, and using AVVideoCompositionCoreAnimationTool to add overlay for final video.
The problem is sometimes the final video is perfect, but sometimes it just give me a black video with sound only even I didn't change anything :(
Anybody who ran into that problem same me please give an idea, thanks!
let mixComposition: AVMutableComposition = AVMutableComposition()
//Add assets here
let mainComposition: AVMutableVideoComposition = AVMutableVideoComposition(propertiesOf: mixComposition)
mainComposition.frameDuration = CMTimeMake(1, 30)
mainComposition.renderSize = renderSize
mainComposition.renderScale = 1.0
mainComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)
mainComposition.instructions = instructions
let exportSession: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
exportSession.videoComposition = mainComposition
exportSession.audioMix = audioMix
exportSession.outputURL = outputURL
exportSession.outputFileType = AVFileTypeMPEG4
exportSession.shouldOptimizeForNetworkUse = true
exportSession.exportAsynchronously {
// Ended here
}

Changing Mavlink Message Rate ArduPilotMega

I am working on a project that uses Mavlink protocol (in c++) to communicate with the ArduPilotMega (2.6).
I am able to read messages such as ATTITUDE for example. The current message rate (for all messages) is 2Hz and I would like to increase this rate.
I found out that I should probably set MESSAGE_INTERVAL using MAV_CMD_SET_MESSAGE_INTERVAL in order to change it.
So my question is:
How do I send this command message using mavlink in c++?
I tried doing it using the code below but it did not work. I guess I have to use the command I mentioned above, but I don't know how.
mavlink_message_t command;
mavlink_message_interval_t interval;
interval.interval_us = 100000;
interval.message_id = 30;
mavlink_msg_message_interval_encode(255, 200, &command, &interval);
p_sensorsPort->write_message(command);
Update: I also tried this code below, maybe I am not giving it the right system id or component id.
mavlink_message_t command;
mavlink_command_long_t interval;
interval.param1 = MAVLINK_MSG_ID_ATTITUDE;
interval.param2 = 100000;
interval.command = MAV_CMD_SET_MESSAGE_INTERVAL;
interval.target_system = 0;
interval.target_component = 0;
mavlink_msg_command_long_encode(255, 0, &command, &interval);
p_sensorsPort->write_message(command);
Maybe I am missing something about the difference between target_system, target_component and sysid, compid. I tried few values for each but nothing worked.
Is there any ACK that will be able to tell me if it even got the command?
I guess you missed start_stop field. the below sample is working.
final msg_request_data_stream msg = new msg_request_data_stream ();
msg.req_message_rate = rate;
msg.req_stream_id = (short) streamId;
msg.target_component = (short)compID;
msg.target_system = (short)sysID;
/*
GCS_COMMON.cpp contains code that sends when value =1
and stop when value = 0
that is it.
*/
if (rate > 0) {
msg.start_stop = 1;
} else {
msg.start_stop = 0;
}
From Robotis Stack Exchange answer,
In order to change the message rate, the simplest way is to change the SR_* parameters value using Mission Planner. The maximum rate is 10Hz.
For example, in order to change the ATTITUDE message rate to be 10Hz I just had to change the SR_EXTRA1 parameter to be 10.
For more information about which parameter changes each message see GCS_Mavlink.cpp file in ArduCopter firmware.

How to get the screen size with C++ builder (Firemonkey)

I know it is a stupid question, but when changing visual libraries I found a "throuble" with FMX...
My problem is: I need to do my own border, so I set the propriety to Border Style:"None", but the application runs in full screen, also covering the windows toolbar, so I would like a way to resize the application form according to the screen eg.:
mainForm->Height = Screen->Height - 10;
It is possible using VCL, but are there any way to do it using FMX library?
The maximum I conquested with FMX is (I don't know how does it returns values, and the kind of values):
Screen->Size(); // TSize
I've also conquested it now, but I have compiler error:
TSize* Tamanho = new TSize;
Tamanho = Screen->Size();
frmPrincipal->Width = Tamanho->Width;
frmPrincipal->Height = Tamanho->Height - 10;
Error:"E2034 Cannot covert 'TSize' to 'TSize*'"
Finally I've tried to put it on frmPrincipal.h, but the same error:
TSize *Tamanho;
PS.: Other possible solutions to solve the "main problem" are acceptable...
Thanks a LOT!
TScreen::Size() return an actual instance of the TSize struct, not a TSize* pointer. You need to change your code accordingly:
TSize Tamanho = Screen->Size();
frmPrincipal->Width = Tamanho.Width;
frmPrincipal->Height = Tamanho.Height - 10;
Alternatively, you can use FMX's Platform Services framework to access the IFMXScreenService interface directly (this is what TScreen::Size() uses internally):
_di_IInterface Intf;
if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService), Intf))
{
_di_IFMXScreenService Svc = Intf;
TPoint size = Svc->GetScreenSize().Round();
frmPrincipal->Width = size.X;
frmPrincipal->Height = size.Y - 10;
}

How to open AVCodec?

I'm tired of searching the solution about this theme. Can anybody help?Types:
AVOutputFormat* m_outFormat;
AVFormatContext* m_formatContext;
AVCodecContext* m_videoCodecContext;
AVCodec* m_videoCodec;
Code:
avcodec_register_all();
av_register_all();
m_outFormat = av_guess_format(NULL,filePath().toUtf8().constData(),NULL);
//filePath ended like ".mp4"
if (!m_outFormat)
return; //all is fine
avformat_alloc_output_context2(&m_formatContext,NULL,NULL,filePath().toUtf8().constData());
m_formatContext->oformat->video_id = CODEC_ID_H264;
m_outFormat=m_formatContext->oformat;
////////////////////////////////////////////////////////////////////
m_videoCodec=avcodec_find_encoder(CODEC_ID_H264);
m_videoStream = avformat_new_stream(m_formatContext,m_videoCodec);
if (m_videoStream)
return; //all is fine
m_videoCodecContext = avcodec_alloc_context3(m_videoCodec);
m_videoCodecContext->codec_id = CODEC_ID_H264;
m_videoCodecContext->width = 1280;
m_videoCodecContext->height = 720;
m_videoCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
m_videoCodecContext->pix_fmt = PIX_FMT_YUV420P;
av_codec_open2(M_videoCodecContext,m_videoCodec,NULL);
I'm getting an error: [libx264 #.....] Codec type or id mismathes.
av_codec_open2(..) returned (-22 error). Where I did mistake?More info:
last ffmpeg
Mac Os x 10.10
libx264 installed
after av_guess_format(...) I've got audio_codec = CODEC_ID_H264, video_codec = CODEC_ID_NONE, long_name MP4(MPEG-4 Part 14) in m_outFormat.
after avformat_alloc_context3(...) I've got audio_codec_id = video_codec_id = CODEC_ID_NONE in m_formatContext.
after avcodec_find_encoder(CODEC_ID_H264) I've got name = "libx264", id = CODEC_ID_MPEG1VIDEO in m_videoCodec.
I can share more info if You can say, what do You exactly need.
I've found the answer... It's so stupid... I had old headers, from old ffmpeg sources, but with the libs from new sources.. So I replaced new headers and all errors has gone! I don't change code above.

ColdFusion - Reading in lots of images

What is the most efficient way of reading in lots of images in CF / Railo and checking their width and height?
In my app, I need to typically read in about 20 images + and at the moment this takes up to 14 seconds to complete. A bit too long really.
theImageRead = ImageNew(theImageSrc);
if ( imageGetWidth(theImageRead) > 100 ) {
writeOutput('<img src="' & theImageSrc & '" />');
}
Images are read from a list of absolute URL's. I need to get images specified over a certain dimension.
If there's a quicker solution to this then I'd love to get your insight. Perhaps underlying java methods?
I am also using jSoup if there's anything in that which could help.
Thanks,
Michael.
I don't believe there's any way to determine the pixel dimensions of an image without reading the bytes and creating an image object. The main bottleneck here will be the http request overhead.
that said there are a few ways to speed up what you're trying to do.
use threads to concurrently request images, then when all threads have finished processing output the images.
If you display the same image or set of images more than once cache it. If you don't want to cache the actually image you can cache the metadata to avoid having to perform a http request for every image.
decide if you need to output all the images to the page immediately, or could some or all of these be deferred and loaded via and ajax request
I have written this utility function quite a while ago (it runs on older ColdFusion versions, too). Maybe it helps.
Note that this requires the Java Advanced Imaging Image I/O Tools (Jai-imageio). Download the .jar and put it in your class path (restarting CF is necessary).
/**
* Reads basic properties of many types of images. Values are
* returned as a struct consisting of the following elements:
*
* Property names, their types and default values:
* ImgInfo.width = 0 (pixels)
* ImgInfo.height = 0 (pixels)
* ImgInfo.size = 0 (bytes)
* ImgInfo.isGrayscale = false (boolean)
* ImgInfo.isFile = false (boolean)
* ImgInfo.success = false (boolean)
* ImgInfo.error = "" (string)
*
* #param FilePath Physical path to image file.
* #return A struct, as described.
*/
function GetImageProperties(FilePath) {
var ImgInfo = StructNew();
var jImageIO = CreateObject("java", "javax.imageio.ImageIO");
var jFile = CreateObject("java", "java.io.File").init(FilePath);
var jBufferedImage = 0;
var jColorSpace = 0;
ImgInfo.width = "";
ImgInfo.height = "";
ImgInfo.fileSize = 0;
ImgInfo.isGrayscale = false;
ImgInfo.isFile = jFile.isFile();
ImgInfo.success = false;
ImgInfo.error = "";
try {
jBufferedImage = jImageIO.read(jFile);
ImgInfo.fileSize = jFile.length();
ImgInfo.width = jBufferedImage.getWidth();
ImgInfo.height = jBufferedImage.getHeight();
jColorSpace = jBufferedImage.getColorModel().getColorSpace();
ImgInfo.isGrayscale = (jColorSpace.getType() eq jColorSpace.TYPE_GRAY);
ImgInfo.success = true;
}
catch (any ex) {
ImgInfo.error = ToString(ex);
}
jImageIO = JavaCast("null", "");
jFile = JavaCast("null", "");
jBufferedImage = JavaCast("null", "");
jColorSpace = JavaCast("null", "");
return ImgInfo;
}
Use like:
imageInfo = GetImageProperties(theImageSrc);
if (imageInfo.success and imageInfo.width > 100)
writeOutput('<img src="#HTMLEditFormat(theImageSrc)#" />');
}