Crymes
Posts: 5
Joined: Thu Apr 07, 2016 10:05 am

How to set the bitrate in v4l2 ?

Tue Jul 19, 2016 10:44 am

Hi,
I want to record a video with v4l2 and have to change the bitrate for a smaller size.
This command in the terminal works :
v4l2-ctl --set-ctrl video_bitrate=10000000

But I need the command in the c v4l2 api.
I already took a look at the source code of v4l2-ctl but it seems to me as if the program reads the constants for the ioctls on the fly and has got no hard coded ones.
The strace output showed a ioctl with the extended_controls constant but the other parameters are unreadable to me.

That's the code which is supposed to work due to the v4l2 reference spec but it doesn't work :| :

Code: Select all

  struct v4l2_ext_controls ecs1;
   struct v4l2_ext_control ec1;
   memset(&ecs1, 0, sizeof(ecs1));
   memset(&ec1, 0, sizeof(ec1));
   ec1.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
   ec1.value = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
   ec1.size = 0;
   ecs1.controls = &ec1;
   ecs1.count = 1;
   ecs1.ctrl_class = V4L2_CTRL_CLASS_MPEG;
   if(ioctl(fd, VIDIOC_S_EXT_CTRLS, &ecs1) < 0)
   {
      cout << "error in extended controls bitrate mode";
      cout.flush();
   }

struct v4l2_ext_controls ecs;
   struct v4l2_ext_control ec;
   memset(&ecs, 0, sizeof(ecs));
   memset(&ec, 0, sizeof(ec));
   ec.id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK;
   ec.value = 50000;
   ec.size = 0;
   ecs.controls = &ec;
   ecs.count = 1;
   ecs.ctrl_class = V4L2_CTRL_CLASS_MPEG;
   if(ioctl(fd, VIDIOC_S_EXT_CTRLS, &ecs) < 0)
   {
      cout << "error in extended controls bitrate";
      cout.flush();
   }
Does anyone know what's going wrong or at least how I can figure out what's going on in v4l2-ctl ?

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7422
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: How to set the bitrate in v4l2 ?

Tue Jul 19, 2016 12:44 pm

I always use http://hverkuil.home.xs4all.nl/spec/media.html for referencing the spec as it puts the whole thing on one page and makes it easy to search.

Code: Select all

V4L2_CID_MPEG_VIDEO_BITRATE_MODE 	enum v4l2_mpeg_video_bitrate_mode	 
 	Video bitrate mode. Possible values are:
 	
 	 	V4L2_MPEG_VIDEO_BITRATE_MODE_VBR 	Variable bitrate
 	 	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR 	Constant bitrate
 	 	 	 
V4L2_CID_MPEG_VIDEO_BITRATE 	integer	 
 	Video bitrate in bits per second.
 	 	 	 
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK 	integer	 
 	Peak video bitrate in bits per second. Must be larger or equal to the average video bitrate. It is ignored if the  video bitrate mode is set to constant bitrate.
So you're using the wrong CID and need to use V4L2_CID_MPEG_VIDEO_BITRATE instead.

Code: Select all

v4l2-ctl --list-ctrls
will list all the controls that are supported. The names are all provided by the V4L2 driver, generally via the list in http://lxr.free-electrons.com/source/dr ... rls.c#L611
The code actually setting values is the loop at https://git.linuxtv.org/v4l-utils.git/t ... n.cpp#n819. Now that is a generic implementation making use of all the data provided by the driver to make the relevant call. Seeing as you've got the data from the spec, you can skip that bit and just make the call.

Having just done a Google for V4L2_CID_MPEG_VIDEO_BITRATE I see http://stackoverflow.com/questions/3800 ... -correctly where it appears you've asked this same question. That code looks correct in using V4L2_CID_MPEG_VIDEO_BITRATE. Your error is that you've done:

Code: Select all

write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);
so are writing the length of the allocated buffer, not the filled contents as indicated by bufferinfo.bytesused. With H264 being a compressed format, each buffer can be a different length. Try

Code: Select all

write(file, pb[bufferinfo.index].startadress, bufferinfo.bytesused);
and you might get better results.

BTW CBR on Pi can only be used with base or main profile H264 due to the way the pipeline works with CABAC enabled.
Also you can always read back the value set from a V4L2 device using "v4l2-ctl --get-ctrl=video_bitrate" or similar. Values should persist over opening and closing the device quite happily.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

Return to “Camera board”