2

I'm working on moving our application from some proprietary codec to iOS native h264 encoder (VideoToolbox.framework) and have question:

Is there exists way to set bitrate or datarate for compressed data ?

Here is how I creating encoder session:

CFMutableDictionaryRef sessionAttributes = CFDictionaryCreateMutable(
                                                                     NULL, 
                                                                     0,    
                                                                     &kCFTypeDictionaryKeyCallBacks,
                                                                     &kCFTypeDictionaryValueCallBacks);

//** bitrate
int fixedBitrate = bitrate; // 2000 * 1024 -> assume 2 Mbits/s

CFNumberRef bitrateNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &fixedBitrate);
CFDictionarySetValue(sessionAttributes, kVTCompressionPropertyKey_AverageBitRate, bitrateNum);
CFRelease(bitrateNum);

CFDictionarySetValue(sessionAttributes, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_High_AutoLevel);

CFDictionarySetValue(sessionAttributes, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);

OSStatus error = VTCompressionSessionCreate(kCFAllocatorDefault,
                                            width,
                                            height,
                                            kCMVideoCodecType_H264,
                                            sessionAttributes, 
                                            NULL, 
                                            kCFAllocatorDefault,  
                                            &EncoderCallback,
                                            this, *outputCallbackRefCon,
                                            &m_EncoderSession);

I'm played a lot with different values of kVTCompressionPropertyKey_AverageBitRate but this does nothing for me, I also tried kVTCompressionPropertyKey_DataRateLimits with different values but also without any luck.

Any ideas, suggestions are welcome

sage444
  • 5,661
  • 4
  • 33
  • 60
  • Have your question been solved? I have the same problem. I use the VTCompressoinSession encode H264 format, and I found its quality is very bad when I play it. – tutu_magi Jan 06 '16 at 09:46
  • 1
    Yes, everything fine, accepted answer helped me. – sage444 Jan 06 '16 at 11:06
  • Yes, I set `VTSessionSetProperty(session, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)@[800 * 1024 / 8, 1]);`, and it works well. – tutu_magi Jan 06 '16 at 12:22
  • have achieved quality using hardware acceleration option,but some time it is generating bigger frame,is there any way to set perticular quality with normal frames – PR Singh Oct 05 '17 at 11:10
  • @PRSingh As far as I can recall there is no way to limit frame size, there is only way to set average bitrate value – sage444 Oct 05 '17 at 11:13
  • @sage444 have tried everything but quality of image is still constant,there is no difference after changing these values: kVTCompressionPropertyKey_AverageBitRate and kVTCompressionPropertyKey_DataRateLimits – PR Singh Oct 06 '17 at 05:47
  • @PRSingh maybe it will be better to you to start new question? – sage444 Oct 06 '17 at 12:04

1 Answers1

9

The short story is that you need to use VTSessionSetProperty after you've created the session.

The dictionary you're passing in as the fifth parameter is actually used for specifying the encoder to use rather than the encoder settings. It's a bit confusing but Apple documentation states:

To specify a particular video encoder when creating a compression session, pass an encoderSpecification CFDictionary containing this key and the EncoderID as its value. The EncoderID CFString may be obtained from the kVTVideoEncoderList_EncoderID entry in the array returned by VTCopyVideoEncoderList.

You need to set the kVTCompressionPropertyKey_AverageBitRate and kVTCompressionPropertyKey_DataRateLimits properties after you have created the session using the VTSessionSetProperty function.

For example:

 status = VTSessionSetProperty(session, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(600 * 1024));
 status = VTSessionSetProperty(session, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)@[800 * 1024 / 8, 1]);

Just remember that kVTCompressionPropertyKey_AverageBitRate takes bits and kVTCompressionPropertyKey_DataRateLimits takes bytes and seconds.

viz
  • 1,247
  • 16
  • 27
tumtumtum
  • 1,052
  • 9
  • 11
  • Thank you! I'm already found solution but your answer help me understand why I should do this way. – sage444 Jul 20 '15 at 08:51
  • So for my understanding sake you are setting the AverageBitRate to 600kbps and you are setting the DataRateLimits to 800kbps. This means that you bitrate should hover at around 600kbps and not go above 800kbps. What is stopping the bitrate from dropping lower thank 600kbps? Personally I have run in to a lot of trouble with bitrate trying to get it to stay at a constants rate with out massive spike or drops but cant seem to get it to do so. I use the same way to set it that you do. – Charlie Nov 15 '16 at 21:51