blob: abed497a3344f4c151281cd7959c1978bf28a454 [file] [log] [blame]
// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#define HAVE_CONFIG_H "vpx_codecs_config.h"
#include "vpx/vpx_encoder.h"
#include "vpx/vpx_codec_impl_top.h"
#include "vpx/vpx_codec_impl_bottom.h"
#include "vpx/vp8cx.h"
#if __APPLE_CC__
#include <QuickTime/QuickTime.h>
#else
#include <ConditionalMacros.h>
#include <Endian.h>
#include <ImageCodec.h>
#endif
#include "log.h"
#include "Raw_debug.h"
#include "VP8CodecVersion.h"
#include "VP8Encoder.h"
#include "VP8EncoderEncode.h"
#include "VP8EncoderGui.h"
static void setCustom(VP8EncoderGlobals glob);
static ComponentResult setMaxKeyDist(VP8EncoderGlobals glob);
static ComponentResult setFrameRate(VP8EncoderGlobals glob);
static ComponentResult setBitrate(VP8EncoderGlobals glob,
ICMCompressorSourceFrameRef sourceFrame);
static void setUInt(unsigned int * i, UInt32 val);
static void setCustom(VP8EncoderGlobals glob);
static void initializeCodec(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame);
static ComponentResult convertColorSpace(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame);
//these are for the source frame queue
static void addSourceFrame(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame);
static ICMCompressorSourceFrameRef popSourceFrame(VP8EncoderGlobals glob);
static Boolean isInQueue(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame);
static void dbg_printEncoderSettings(vpx_codec_enc_cfg_t *cfg)
{
dbg_printf("[vp8e] ------- dbg_printEncoderSettings\n");
dbg_printf("g_usage %d\n", cfg->g_usage);
dbg_printf("g_threads %d\n", cfg->g_threads);
dbg_printf("g_profile %d\n", cfg->g_profile);
dbg_printf("g_w %d\n", cfg->g_w);
dbg_printf("g_h %d\n", cfg->g_h);
dbg_printf("g_timebase %d/%d\n", cfg->g_timebase.num, cfg->g_timebase.den);
dbg_printf("g_error_resilient %d\n", cfg->g_error_resilient);
dbg_printf("g_pass %d\n", cfg->g_pass);
dbg_printf("g_lag_in_frames %d\n", cfg->g_lag_in_frames);
dbg_printf("rc_dropframe_thresh %d\n", cfg->rc_dropframe_thresh);
dbg_printf("rc_resize_allowed %d\n", cfg->rc_resize_allowed);
dbg_printf("rc_resize_up_thresh %d\n", cfg->rc_resize_up_thresh);
dbg_printf("rc_resize_down_thresh %d\n", cfg->rc_resize_down_thresh);
dbg_printf("rc_resize_down_thresh %d\n", cfg->rc_resize_down_thresh);
dbg_printf("rc_end_usage %d\n", cfg->rc_end_usage);
dbg_printf("rc_twopass_stats_in %d\n", cfg->rc_twopass_stats_in);
dbg_printf("rc_target_bitrate %d\n", cfg->rc_target_bitrate);
dbg_printf("rc_min_quantizer %d\n", cfg->rc_min_quantizer);
dbg_printf("rc_max_quantizer %d\n", cfg->rc_max_quantizer);
dbg_printf("rc_undershoot_pct %d\n", cfg->rc_undershoot_pct);
dbg_printf("rc_overshoot_pct %d\n", cfg->rc_overshoot_pct);
dbg_printf("rc_buf_sz %d\n", cfg->rc_buf_sz);
dbg_printf("rc_buf_initial_sz %d\n", cfg->rc_buf_initial_sz);
dbg_printf("rc_buf_optimal_sz %d\n", cfg->rc_buf_optimal_sz);
dbg_printf("rc_2pass_vbr_bias_pct %d\n", cfg->rc_2pass_vbr_bias_pct);
dbg_printf("rc_2pass_vbr_minsection_pct %d\n", cfg->rc_2pass_vbr_minsection_pct);
dbg_printf("rc_2pass_vbr_maxsection_pct %d\n", cfg->rc_2pass_vbr_maxsection_pct);
dbg_printf("kf_mode %d\n", cfg->kf_mode);
dbg_printf("kf_min_dist %d\n", cfg->kf_min_dist);
dbg_printf("kf_max_dist %d\n", cfg->kf_max_dist);
}
static ComponentResult emitEncodedFrame(VP8EncoderGlobals glob, const vpx_codec_cx_pkt_t *pkt)
{
ICMMutableEncodedFrameRef encodedFrame = NULL;
unsigned char *dataPtr;
size_t dataSize = 0;
ComponentResult err= noErr;
MediaSampleFlags mediaSampleFlags;
Boolean keyFrame = false;
Boolean droppableFrame = false;
Boolean invisibleFrame = false;
//get the source frame off the queue
//for an alt-ref frame this won't work.
ICMCompressorSourceFrameRef sourceFrame = NULL;
dbg_printf("[VP8E] emitEncodedFrame frames out %ld, pts %ld, frames in queue %d\n",
glob->sourceQueue.frames_out, pkt->data.frame.pts, glob->sourceQueue.size);
if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
{
dbg_printf("[VP8E] Keeping Altref Frame data %ld\n", pkt->data.frame.sz);
//This indicates an alt -ref frame, instead of popping the frame I'm just going to hold on to data and append.
if (glob->altRefFrame.buf != NULL)
{
//this shouldn't happen
dbg_printf("[VP8E] Errror: possible memory leak in alt ref frame data\n");
}
glob->altRefFrame.buf = malloc(pkt->data.frame.sz);
memcpy(glob->altRefFrame.buf, pkt->data.frame.buf, pkt->data.frame.sz);
glob->altRefFrame.size = pkt->data.frame.sz;
return noErr;
}
while (glob->sourceQueue.size > 0)
{
//time is in timeBase *2
UInt32 expectedTime = glob->sourceQueue.frames_out * 2 ;
dbg_printf("Expected time = %lu\n", expectedTime);
sourceFrame = popSourceFrame(glob);
if (expectedTime >= pkt->data.frame.pts)
{
break;
}
else //frames_out < pts
{
dbg_printf("[VP8E] Dropping frame %ld, Queue size %ld\n",
glob->sourceQueue.frames_out, glob->sourceQueue.size);
ICMCompressorSessionDropFrame(glob->session, sourceFrame);
}
sourceFrame = NULL;
}
if (sourceFrame == NULL && (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) == 0)
{
dbg_printf("[VP8e] Error: asked to output a frame at time %ld but last frame in was %ld\n",
pkt->data.frame.pts, glob->sourceQueue.frames_in);
return qErr;
}
TimeValue64 frameDisplayDuration = 0;
TimeScale timescale = 0;
ICMValidTimeFlags validTimeFlags = 0;
unsigned int bitrate = 0;
TimeValue64 timeStamp=0,decodeTimeStamp=0;
TimeScale timeScale =0;
//use the time stamp of the input frame for the output frame
err = ICMCompressorSourceFrameGetDisplayTimeStampAndDuration(sourceFrame, &timeStamp,NULL, &timeScale, NULL);
decodeTimeStamp = timeStamp;
dbg_printf("[VP8e] ICMCompressorSourceFrameGetDisplayTimeStampAndDuration(%lld,%lld)\n" ,timeStamp, timeScale );
err = ICMEncodedFrameCreateMutable(glob->session, sourceFrame,
glob->maxEncodedDataSize, &encodedFrame);
if (err) goto bail;
dataPtr = ICMEncodedFrameGetDataPtr(encodedFrame);
dbg_printf("[vp8e - %08lx] getDataPtr %x\n", (UInt32)glob, dataPtr);
//paranoid check to make sure I don't write past my buffer
if (pkt->data.frame.sz + dataSize >= glob->maxEncodedDataSize)
{
dbg_printf("[vp8e - %08lx] Error: buffer overload. Encoded frame larger than raw frame\n", (UInt32)glob);
goto bail;
}
//if we have an altref frame, prepend that data.
if (glob->altRefFrame.buf != NULL)
{
//This method prepends the altref size and altref data to the following interframe.
// I've also tried sending in bogus source frames, and sending back altref via those (has major implementation issues)
// Also I've tried reading altref size from the data... Seems as though I can't though in the future that may be better.
//Quicktime and altref frames are difficult because of paramErr failures that occur when trying to use sourceframes 2x
memcpy(&(dataPtr[dataSize]), &glob->altRefFrame.size, sizeof(glob->altRefFrame.size));
dataSize += sizeof(glob->altRefFrame.size);
dbg_printf("[VP8e] Appended altrefsize %ld bytes %lu\n", glob->altRefFrame.size, dataSize);
memcpy(&(dataPtr[dataSize]), glob->altRefFrame.buf, glob->altRefFrame.size);
dataSize += glob->altRefFrame.size;
dbg_printf("[VP8e] Appended altref frame bytes %lu\n", dataSize);
}
dbg_printf("[vp8e - %08lx] copying %d bytes of data to output dataBuffer\n", (UInt32)glob, pkt->data.frame.sz);
memcpy(&(dataPtr[dataSize]), pkt->data.frame.buf, pkt->data.frame.sz);
dataSize += pkt->data.frame.sz;
dbg_printf("[vp8e - %08lx] Encoded frame %d with %d bytes of data\n", (UInt32)glob, glob->frameCount, dataSize);
keyFrame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
dbg_printf(keyFrame ? "Key Packet\n" : "Non Key Packet\n");
droppableFrame = pkt->data.frame.flags & VPX_FRAME_IS_DROPPABLE;
dbg_printf(droppableFrame ? "Droppable frame\n" : "Not droppable frame\n");
invisibleFrame = pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE;
// Update the encoded frame to reflect the actual frame size, sample flags and frame type.
err = ICMEncodedFrameSetDataSize(encodedFrame, dataSize);
if (err) goto bail;
mediaSampleFlags = 0;
if (! keyFrame)
{
mediaSampleFlags |= mediaSampleNotSync;
if (droppableFrame)
mediaSampleFlags |= mediaSampleDroppable;
}
ICMFrameType frameType = keyFrame ? kICMFrameType_I : kICMFrameType_P;
if (glob->altRefFrame.buf != NULL)
{
frameType = kICMFrameType_Unknown;
free(glob->altRefFrame.buf);
glob->altRefFrame.buf =NULL;
glob->altRefFrame.size =0;
dbg_printf("[vp8e - %08lx] frame type set to Unknown\n", (UInt32)glob);
}
else
dbg_printf("[vp8e - %08lx] frame type set to %c\n", (UInt32)glob, keyFrame ? 'I' : 'P');
if (kICMFrameType_I == frameType)
mediaSampleFlags |= mediaSampleDoesNotDependOnOthers;
err = ICMEncodedFrameSetMediaSampleFlags(encodedFrame, mediaSampleFlags);
if (err)
goto bail;
err = ICMEncodedFrameSetFrameType(encodedFrame, frameType);
if (err)
goto bail;
if (timeStamp == 0)
{
timeStamp = pkt->data.frame.pts * glob->cfg.g_timebase.num * timeScale / 2 /glob->cfg.g_timebase.den ; //pts is timebase *2 2
}
dbg_printf("[vp8e]setting ICMEncodedFrameSetDisplayTimeStamp %lld\n", timeStamp);
err= ICMEncodedFrameSetDisplayTimeStamp(encodedFrame, timeStamp);
// Output the encoded frame.
dbg_printf("[vp8e - %08lx] Emit Encoded Frames\n", (UInt32)glob);
err = ICMCompressorSessionEmitEncodedFrame(glob->session, encodedFrame, 1, &sourceFrame);
if (err)
goto bail;
bail:
// Since we created this, we must also release it.
if (encodedFrame)
{
ICMEncodedFrameRelease(encodedFrame);
}
if (err)
dbg_printf("[VP8e] EmitEncodedFrame Error = %d\n", err);
return err;
}
ComponentResult completeThisSourceFrame(VP8EncoderGlobals glob,
ICMCompressorSourceFrameRef sourceFrame)
{
ComponentResult err = noErr;
if (!isInQueue(glob, sourceFrame))
{
err = encodeThisSourceFrame(glob, sourceFrame);
}
if (err) return err;
while (isInQueue(glob, sourceFrame))
{
UInt32 framesInQueue = glob->sourceQueue.size;
err = encodeThisSourceFrame(glob, NULL);
if (err) break;
//handles the case where terminating source frames are dropped
if (glob->sourceQueue.size == framesInQueue)
{
dbg_printf("[VP8E] Dropping frame %ld\n", glob->sourceQueue.frames_out);
sourceFrame = popSourceFrame(glob);
err = ICMCompressorSessionDropFrame(glob->session, sourceFrame);
if (err)
return err;
}
}
return err;
}
ComponentResult encodeThisSourceFrame(VP8EncoderGlobals glob,
ICMCompressorSourceFrameRef sourceFrame)
{
vpx_codec_err_t codecError;
ComponentResult err = noErr;
const UInt8 *decoderDataPtr;
int storageIndex = 0;
//time is multiplied by 2 to allow space for altref frames
UInt32 time2 = glob->frameCount * 2;
dbg_printf("[vp8e - %08lx] encode this frame %08lx %ld time2 %lu\n",
(UInt32)glob, (UInt32)sourceFrame, glob->frameCount, time2);
//long dispNumber = ICMCompressorSourceFrameGetDisplayNumber(sourceFrame);
// Initialize codec if needed
initializeCodec(glob, sourceFrame);
/////// Transfer the current frame to glob->raw
if (sourceFrame != NULL)
{
if (glob->currentPass != VPX_RC_FIRST_PASS)
addSourceFrame(glob,sourceFrame);
err = convertColorSpace(glob, sourceFrame);
if (err) goto bail;
int flags = 0 ; //TODO - find out what I may need in these flags
dbg_printf("[vp8e - %08lx] vpx_codec_encode codec %x raw %x framecount %d flags %x\n", (UInt32)glob, glob->codec, glob->raw, glob->frameCount, flags);
//TODO seems like quality should be an option. Right now hardcoded to GOOD_QUALITY
codecError = vpx_codec_encode(glob->codec, glob->raw, time2,
1, flags, VPX_DL_GOOD_QUALITY);
dbg_printf("[vp8e - %08lx] vpx_codec_encode codec exit\n", (UInt32)glob);
}
else //sourceFrame is Null. this could be termination of a pass
{
int flags = 0 ; //TODO - find out what I may need in these flags
dbg_printf("[vp8e - %08lx] vpx_codec_encode codec %x raw %x framecount %d ----NULL TERMINATION\n", (UInt32)glob, glob->codec, NULL, glob->frameCount, flags);
codecError = vpx_codec_encode(glob->codec, NULL, time2,
1, flags, VPX_DL_GOOD_QUALITY);
}
glob->frameCount++ ; //framecount gets reset on a new pass
if (codecError)
{
const char *detail = vpx_codec_error_detail(glob->codec);
dbg_printf("[vp8e - %08lx] error vpx encode is %s\n", (UInt32)glob, vpx_codec_error(glob->codec));
if (detail)
dbg_printf(" %s\n", detail);
goto bail;
}
vpx_codec_iter_t iter = NULL;
int got_data = 0;
while (1)
{
const vpx_codec_cx_pkt_t *pkt = vpx_codec_get_cx_data(glob->codec, &iter);
if (pkt == NULL)
break;
got_data ++;
switch (pkt->kind)
{
case VPX_CODEC_CX_FRAME_PKT:
err = emitEncodedFrame(glob, pkt);
if (err)
goto bail;
break;
case VPX_CODEC_STATS_PKT:
if (1)
{
unsigned long newSize = glob->stats.sz + pkt->data.twopass_stats.sz;
glob->stats.buf = realloc(glob->stats.buf, newSize);
if (!glob->stats.buf)
return mFulErr;
dbg_printf("[vp8e - %08lx] Reallocation buffer size to %ld\n", (UInt32)glob, newSize);
memcpy((char*)glob->stats.buf + glob->stats.sz, pkt->data.twopass_stats.buf,
pkt->data.twopass_stats.sz);
glob->stats.sz = newSize;
}
break;
default:
break;
}
}
if (glob->currentPass == VPX_RC_FIRST_PASS)
{
//in the first pass no need to export any frames
return err;
}
bail:
if (err)
dbg_printf("[vp8e - %08lx] bailed with err %d\n", (UInt32)glob, err);
return err;
}
//initialize the codec if needed
static void initializeCodec(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame)
{
if (glob->codec != NULL)
return;
dbg_printf("[vp8e - %08lx] initializeCodec\n", (UInt32)glob);
glob->codec = calloc(1, sizeof(vpx_codec_ctx_t));
setBitrate(glob, sourceFrame); //because we don't know framerate untile we have a source image.. this is done here
setMaxKeyDist(glob);
setFrameRate(glob);
setCustom(glob);
glob->cfg.g_pass = glob->currentPass;
dbg_printEncoderSettings(&glob->cfg);
if (vpx_codec_enc_init(glob->codec, &vpx_codec_vp8_cx_algo, &glob->cfg, 0))
{
const char *detail = vpx_codec_error_detail(glob->codec);
dbg_printf("[vp8e - %08lx] Failed to initialize encoder pass = %d %s\n", (UInt32)glob, glob->currentPass, detail);
}
setCustomPostInit(glob);
}
//creates raw yv12 from sourceframe
static ComponentResult convertColorSpace(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame)
{
CVPixelBufferRef sourcePixelBuffer = NULL;
sourcePixelBuffer = ICMCompressorSourceFrameGetPixelBuffer(sourceFrame);
CVPixelBufferLockBaseAddress(sourcePixelBuffer, 0);
//copy our frame to the raw image. TODO: I'm not checking for any padding here.
unsigned char *srcBytes = CVPixelBufferGetBaseAddress(sourcePixelBuffer);
dbg_printf("[vp8e - %08lx] CVPixelBufferGetBaseAddress %x\n", (UInt32)glob, sourcePixelBuffer);
dbg_printf("[vp8e - %08lx] CopyChunkyYUV422ToPlanarYV12 %dx%d, %x, %d, %x, %d, %x, %d, %x, %d \n", (UInt32)glob,
glob->width, glob->height,
CVPixelBufferGetBaseAddress(sourcePixelBuffer),
CVPixelBufferGetBytesPerRow(sourcePixelBuffer),
glob->raw->planes[PLANE_Y],
glob->raw->stride[PLANE_Y],
glob->raw->planes[PLANE_U],
glob->raw->stride[PLANE_U],
glob->raw->planes[PLANE_V],
glob->raw->stride[PLANE_V]);
ComponentResult err = CopyChunkyYUV422ToPlanarYV12(glob->width, glob->height,
CVPixelBufferGetBaseAddress(sourcePixelBuffer),
CVPixelBufferGetBytesPerRow(sourcePixelBuffer),
glob->raw->planes[PLANE_Y],
glob->raw->stride[PLANE_Y],
glob->raw->planes[PLANE_U],
glob->raw->stride[PLANE_U],
glob->raw->planes[PLANE_V],
glob->raw->stride[PLANE_V]);
CVPixelBufferUnlockBaseAddress(sourcePixelBuffer, 0);
dbg_printf("[vp8e - %08lx] CVPixelBufferUnlockBaseAddress %x\n", sourcePixelBuffer);
return err;
}
///////////Functions for configuring the encoder
static ComponentResult setMaxKeyDist(VP8EncoderGlobals glob)
{
SInt32 maxInterval = 0;
ComponentResult err = ICMCompressionSessionOptionsGetProperty(glob->sessionOptions,
kQTPropertyClass_ICMCompressionSessionOptions,
kICMCompressionSessionOptionsPropertyID_MaxKeyFrameInterval,
sizeof(SInt32),
&maxInterval, NULL);
if (err) return err;
if (maxInterval == 0)
glob->cfg.kf_max_dist = 300; //default : don't pass in 0 as vp8 sdk reserves that for key every frame
else
glob->cfg.kf_max_dist = maxInterval;
dbg_printf("[vp8e - %08lx] setMaxKeyDist %ld\n", (UInt32)glob, glob->cfg.kf_max_dist);
return noErr;
}
static ComponentResult setFrameRate(VP8EncoderGlobals glob)
{
dbg_printf("[vp8e - %08lx] setFrameRate \n", (UInt32) glob);
ComponentResult err = noErr;
Fixed frameRate;
err= ICMCompressionSessionOptionsGetProperty(glob->sessionOptions,
kQTPropertyClass_ICMCompressionSessionOptions,
kICMCompressionSessionOptionsPropertyID_ExpectedFrameRate,
sizeof(Fixed), &frameRate, NULL);
if (err) goto bail;
double fps = FixedToFloat(frameRate);
dbg_printf("[vp8e - %08lx] Got FrameRate %f \n", (UInt32) glob,fps);
if (fps == 0)
return err; //use the defaults
if (fps > 29.965 && fps < 29.975) // I am putting everything in this threshold as 29.97
{
glob->cfg.g_timebase.num = 1001;
glob->cfg.g_timebase.den = 30000;
}
else
{
//I'm using a default of a millisecond timebase, this may not be 100% accurate
// however, container uses this timebase so this estimate is best.
glob->cfg.g_timebase.num = 1000;
glob->cfg.g_timebase.den = fps * 1000;
}
dbg_printf("[vp8e - %08lx] Setting g_timebase to %d/%d \n", (UInt32) glob,
glob->cfg.g_timebase.num, glob->cfg.g_timebase.den);
bail:
return err;
}
static ComponentResult setBitrate(VP8EncoderGlobals glob,
ICMCompressorSourceFrameRef sourceFrame)
{
ComponentResult err = noErr;
TimeValue64 frameDisplayDuration = 0;
TimeScale timescale = 0;
ICMValidTimeFlags validTimeFlags = 0;
unsigned int bitrate = 0;
// If we have a known frame duration and an average data rate, use them to guide the byte budget.
err = ICMCompressorSourceFrameGetDisplayTimeStampAndDuration(sourceFrame, NULL, &frameDisplayDuration,
&timescale, &validTimeFlags);
/* Update the default configuration with our settings */
SInt32 avgDataRate = 0;
err = ICMCompressionSessionOptionsGetProperty(glob->sessionOptions,
kQTPropertyClass_ICMCompressionSessionOptions,
kICMCompressionSessionOptionsPropertyID_AverageDataRate,
sizeof(avgDataRate), &avgDataRate, NULL);
if (avgDataRate != 0 )
{
//convert from bytes/sec to kilobits/second
bitrate = avgDataRate * 8 /1000;
dbg_printf("[vp8e - %08lx] setting bitrate to %d (from averageDataRate)\n", (UInt32)glob, bitrate);
}
else
{
CodecQ sliderVal = codecNormalQuality; //min = 0 max = 1024
err = ICMCompressionSessionOptionsGetProperty(glob->sessionOptions,
kQTPropertyClass_ICMCompressionSessionOptions,
kICMCompressionSessionOptionsPropertyID_Quality,
sizeof(CodecQ), &sliderVal, NULL);
if (err) return err;
if (sliderVal > codecMaxQuality)
sliderVal = codecMaxQuality;
//TODO Look over this formula
//slider val is between 0 and 1024. This formula ranges from, 10 - 1034 kbps on a 640x480 video
double totalPixels = glob->width * glob->height;
double tmp = totalPixels * sliderVal / (640.0 * 480.0);
bitrate = tmp+ 10;
dbg_printf("[vp8e - %08lx] setting bitrate to %d (calculated from Quality Slider)\n", (UInt32)glob, bitrate);
}
glob->cfg.rc_target_bitrate = bitrate;
}
static void setUInt(unsigned int * i, UInt32 val)
{
if (val == UINT_MAX)
return;
dbg_printf("[VP8e] setting custom setting to %lu\n", val);
*i= val;
}
static void setCustom(VP8EncoderGlobals glob)
{
setUInt(&glob->cfg.g_threads, glob->settings[2]);
setUInt(&glob->cfg.g_error_resilient, glob->settings[3]);
setUInt(&glob->cfg.rc_dropframe_thresh, glob->settings[4]);
if(glob->settings[5] == 1)
glob->cfg.rc_end_usage = VPX_CBR;
else if (glob->settings[5] ==2)
glob->cfg.rc_end_usage = VPX_VBR;
setUInt(&glob->cfg.g_lag_in_frames, glob->settings[6]);
if (glob->settings[6] != UINT_MAX)
{
dbg_printf("[WebM] setting g_lag_in_frames to %d\n", glob->settings[6]);
}
setUInt(&glob->cfg.rc_min_quantizer, glob->settings[8]);
setUInt(&glob->cfg.rc_max_quantizer, glob->settings[9]);
setUInt(&glob->cfg.rc_undershoot_pct, glob->settings[10]);
setUInt(&glob->cfg.rc_overshoot_pct, glob->settings[11]);
setUInt(&glob->cfg.rc_resize_allowed, glob->settings[16]);
setUInt(&glob->cfg.rc_resize_up_thresh, glob->settings[17]);
setUInt(&glob->cfg.rc_resize_down_thresh, glob->settings[18]);
setUInt(&glob->cfg.rc_buf_sz, glob->settings[19]);
setUInt(&glob->cfg.rc_buf_initial_sz, glob->settings[20]);
setUInt(&glob->cfg.rc_buf_optimal_sz, glob->settings[21]);
if(glob->settings[22] == 1)
glob->cfg.kf_mode = VPX_KF_DISABLED;
if(glob->settings[22] == 2)
glob->cfg.kf_mode = VPX_KF_AUTO;
setUInt(&glob->cfg.kf_min_dist, glob->settings[23]);
setUInt(&glob->cfg.kf_max_dist, glob->settings[24]);
setUInt(&glob->cfg.rc_2pass_vbr_bias_pct, glob->settings[30]);
setUInt(&glob->cfg.rc_2pass_vbr_minsection_pct, glob->settings[31]);
setUInt(&glob->cfg.rc_2pass_vbr_maxsection_pct, glob->settings[32]);
}
void setCustomPostInit(VP8EncoderGlobals glob)
{
if (glob->settings[12] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_CPUUSED, glob->settings[12]);
if (glob->settings[13] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_NOISE_SENSITIVITY, glob->settings[13]);
if (glob->settings[14] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_SHARPNESS, glob->settings[14]);
if (glob->settings[15] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_STATIC_THRESHOLD, glob->settings[15]);
//setUIntPostInit(glob, VP8E_SET_TOKEN_PARTITIONS, 25); // TODO not sure how to set this.
//TODO verify this when enabling alt - ref
if (glob->settings[25] != UINT_MAX)
{
vpx_codec_control(glob->codec, VP8E_SET_ENABLEAUTOALTREF, glob->settings[25]);
dbg_printf("[VP8e] Setting enable Altref %d\n", glob->settings[25]);
}
if (glob->settings[26] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_ARNR_MAXFRAMES, glob->settings[26]);
if (glob->settings[27] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_ARNR_STRENGTH, glob->settings[27]);
if (glob->settings[28] != UINT_MAX)
vpx_codec_control(glob->codec, VP8E_SET_ARNR_TYPE, glob->settings[28]);
}
#define SFQ_INC_SIZE 10
//The source frame queue is maintained so we can match output packets to source frames in the queue
static void addSourceFrame(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame)
{
if (glob->sourceQueue.size +1 > glob->sourceQueue.max)
{
glob->sourceQueue.max += SFQ_INC_SIZE;
glob->sourceQueue.queue = realloc(glob->sourceQueue.queue, glob->sourceQueue.max * sizeof(ICMCompressorSourceFrameRef));
}
glob->sourceQueue.queue[glob->sourceQueue.size] = sourceFrame;
glob->sourceQueue.size += 1;
glob->sourceQueue.frames_in += 1;
}
static ICMCompressorSourceFrameRef popSourceFrame(VP8EncoderGlobals glob)
{
if (glob->sourceQueue.size <=0)
{
dbg_printf("[VP8E] **ERROR in source frame queue! Popping a frame that doesn't exist!\n");
return NULL;
}
ICMCompressorSourceFrameRef rval = glob->sourceQueue.queue[0];
int i;
for (i=1;i < glob->sourceQueue.size; i ++)
{
glob->sourceQueue.queue[i-1] = glob->sourceQueue.queue[i];
}
glob->sourceQueue.size -=1;
glob->sourceQueue.frames_out += 1;
return rval;
}
static Boolean isInQueue(VP8EncoderGlobals glob, ICMCompressorSourceFrameRef sourceFrame)
{
int i;
for (i=0;i < glob->sourceQueue.size; i ++)
{
if (glob->sourceQueue.queue[i] == sourceFrame)
return true;
}
return false;
}