/// <summary> /// validates a source against a given AVC level taking into account the source properties and the x264 settings /// <param name="bytesPerFrame">bytesize of a single frame</param> /// <param name="FS">frame area in pixels</param> /// <param name="MBPS">macroblocks per second</param> /// <param name="settings">the codec config to test</param> /// <param name="compliantLevel">the first avc level that can be used to encode this source</param> /// <returns>whether or not the current level is okay, if false and compliantLevel is -1, /// the source could not be read</returns> public bool validateAVCLevel(int hRes, int vRes, double framerate, x264Settings settings, out int compliantLevel) { settings = (x264Settings)settings.Clone(); //Otherwise this sets it to the lowest compliant level anyway. const int unrestricted = 15; // maybe this should be set as a global constant compliantLevel = unrestricted; if (settings.Level == unrestricted) // 15 = unrestricted { return(true); } int FrameSize = (int)maxFS(hRes, vRes); int MBPS = maxBPS(hRes, vRes, framerate); int hBlocks = macroblocks(hRes); int vBlocks = macroblocks(vRes); double bufferSize = pictureBufferSize(settings, bytesPerFrame(hRes, vRes)); int allowableBPS = this.getMaxMBPS(settings.Level); int allowableFS = this.getMaxFS(settings.Level); double dimensionRestriction = Math.Ceiling(Math.Sqrt((double)(allowableFS) * 8)); double allowableDPB = this.getMaxDPB(settings.Level); if (allowableBPS >= MBPS && allowableFS >= FrameSize && allowableDPB >= bufferSize && dimensionRestriction >= hBlocks && dimensionRestriction >= vBlocks) { return(true); } else { while (settings.Level < unrestricted && (allowableBPS < MBPS || allowableFS < FrameSize || allowableDPB < bufferSize || dimensionRestriction < hBlocks || dimensionRestriction < vBlocks)) { settings.Level = settings.Level + 1; allowableBPS = this.getMaxMBPS(settings.Level); allowableFS = this.getMaxFS(settings.Level); dimensionRestriction = Math.Ceiling(Math.Sqrt((double)(allowableFS) * 8)); allowableDPB = this.getMaxDPB(settings.Level); } compliantLevel = settings.Level; return(false); } }
/// <summary> /// validates a source against a given AVC level taking into account the source properties and the x264 settings /// </summary> /// <param name="bytesPerFrame">bytesize of a single frame</param> /// <param name="FS">frame area in pixels</param> /// <param name="MBPS">macroblocks per second</param> /// <param name="settings">the codec config to test</param> /// <param name="compliantLevel">the first avc level that can be used to encode this source</param> /// <returns>whether or not the current level is okay, if false and compliantLevel is -1, /// the source could not be read</returns> public bool validateAVCLevel(int hRes, int vRes, double framerate, x264Settings settings, out AVCLevels.Levels?compliantLevel) { settings = (x264Settings)settings.Clone(); // otherwise this sets it to the lowest compliant level anyway. compliantLevel = Levels.L_UNRESTRICTED; if (settings.AVCLevel == Levels.L_UNRESTRICTED) { return(true); } int FrameSize = (int)maxFS(hRes, vRes); int MBPS = maxBPS(hRes, vRes, framerate); int hBlocks = macroblocks(hRes); int vBlocks = macroblocks(vRes); double bufferSize = pictureBufferSize(settings, bytesPerFrame(hRes, vRes)); int allowableBPS = this.getMaxMBPS(settings.AVCLevel); int allowableFS = this.getMaxFS(settings.AVCLevel); double dimensionRestriction = Math.Ceiling(Math.Sqrt((double)(allowableFS) * 8)); double allowableDPB = this.getMaxDPB(settings.AVCLevel) * 3 / 8 * 1024; if (allowableBPS >= MBPS && allowableFS >= FrameSize && allowableDPB >= bufferSize && dimensionRestriction >= hBlocks && dimensionRestriction >= vBlocks) { return(true); } else { while (settings.AVCLevel != Levels.L_UNRESTRICTED && (allowableBPS < MBPS || allowableFS < FrameSize || allowableDPB < bufferSize || dimensionRestriction < hBlocks || dimensionRestriction < vBlocks)) { settings.AVCLevel = settings.AVCLevel + 1; allowableBPS = this.getMaxMBPS(settings.AVCLevel); allowableFS = this.getMaxFS(settings.AVCLevel); dimensionRestriction = Math.Ceiling(Math.Sqrt((double)(allowableFS) * 8)); allowableDPB = this.getMaxDPB(settings.AVCLevel) * 3 / 8 * 1024; } compliantLevel = settings.AVCLevel; return(false); } }
/// <summary> /// Checks a collection of x264Settings and modifies them if needed to fit within the level constraints. /// </summary> /// <param name="level">the level to enforce</param> /// <param name="inputSettings">the collection of x264Settings to check</param> /// <param name="frameSize">the size of the decoded video frame in bytes</param> /// <returns>A compliant set of x264Settings</returns> public x264Settings EnforceSettings(int level, x264Settings inputSettings, double frameSize, out AVCLevelEnforcementReturn enforcement) { x264Settings enforcedSettings = (x264Settings)inputSettings.Clone(); enforcement = new AVCLevelEnforcementReturn(); enforcement.Altered = false; enforcement.EnableP4x4mv = true; enforcement.EnableVBVBufferSize = true; enforcement.EnableVBVMaxRate = true; enforcement.Panic = false; enforcement.PanicString = ""; if (!checkP4x4(level, inputSettings)) { enforcement.Altered = true; enforcedSettings.P4x4mv = false; } if (checkP4x4Enabled(level, inputSettings)) { enforcement.EnableP4x4mv = true; } else { enforcement.EnableP4x4mv = false; } // step through various options to enforce the max decoded picture buffer size while (!this.checkMaxDPB(level, enforcedSettings, frameSize)) { if (enforcedSettings.BFramePyramid) { enforcement.Altered = true; enforcedSettings.BFramePyramid = false; // try turning off pyramid first } else if (enforcedSettings.NbRefFrames > 1) { enforcement.Altered = true; enforcedSettings.NbRefFrames -= 1; // try reducing the number of reference frames } else if (enforcedSettings.NbBframes > 0) { enforcement.Altered = true; enforcedSettings.NbBframes = 0; // try turning off B frames } else { enforcement.Panic = true; enforcement.PanicString = "Can't force settings to conform to level (the frame size is too large)"; // reset output settings to original and set level to unrestrained enforcedSettings = (x264Settings)inputSettings.Clone(); enforcedSettings.Level = 15; return(enforcedSettings); } } // Disallow independent specification of MaxBitrate and MaxBufferSize unless Unrestrained if (level < 15) { enforcement.EnableVBVMaxRate = false; enforcedSettings.VBVMaxBitrate = -1; enforcement.EnableVBVBufferSize = false; enforcedSettings.VBVBufferSize = -1; } else { enforcement.EnableVBVMaxRate = true; enforcement.EnableVBVBufferSize = true; } return(enforcedSettings); }
/// <summary> /// validates a source against a given AVC level taking into account the source properties and the x264 settings /// <param name="bytesPerFrame">bytesize of a single frame</param> /// <param name="FS">frame area in pixels</param> /// <param name="MBPS">macroblocks per second</param> /// <param name="settings">the codec config to test</param> /// <param name="compliantLevel">the first avc level that can be used to encode this source</param> /// <returns>whether or not the current level is okay, if false and compliantLevel is -1, /// the source could not be read</returns> public bool validateAVCLevel( int hRes, int vRes, double framerate, x264Settings settings, out int compliantLevel) { settings = (x264Settings)settings.Clone(); //Otherwise this sets it to the lowest compliant level anyway. const int unrestricted = 15; // maybe this should be set as a global constant compliantLevel = unrestricted; if (settings.Level == unrestricted) // 15 = unrestricted return true; int FrameSize = (int)maxFS(hRes, vRes); int MBPS = maxBPS(hRes, vRes, framerate); int hBlocks = macroblocks(hRes); int vBlocks = macroblocks(vRes); double bufferSize = pictureBufferSize(settings, bytesPerFrame(hRes, vRes)); int allowableBPS = this.getMaxMBPS(settings.Level); int allowableFS = this.getMaxFS(settings.Level); double dimensionRestriction = Math.Ceiling(Math.Sqrt((double)(allowableFS)*8)); double allowableDPB = this.getMaxDPB(settings.Level); if (allowableBPS >= MBPS && allowableFS >= FrameSize && allowableDPB >= bufferSize && dimensionRestriction >= hBlocks && dimensionRestriction >= vBlocks) return true; else { while (settings.Level < unrestricted && (allowableBPS < MBPS || allowableFS < FrameSize || allowableDPB < bufferSize || dimensionRestriction < hBlocks || dimensionRestriction < vBlocks)) { settings.Level = settings.Level + 1; allowableBPS = this.getMaxMBPS(settings.Level); allowableFS = this.getMaxFS(settings.Level); dimensionRestriction = Math.Ceiling(Math.Sqrt((double)(allowableFS)*8)); allowableDPB = this.getMaxDPB(settings.Level); } compliantLevel = settings.Level; return false; } }
/// <summary> /// Checks a collection of x264Settings and modifies them if needed to fit within the level constraints. /// </summary> /// <param name="level">the level to enforce</param> /// <param name="inputSettings">the collection of x264Settings to check</param> /// <param name="frameSize">the size of the decoded video frame in bytes</param> /// <returns>A compliant set of x264Settings</returns> public x264Settings EnforceSettings(int level, x264Settings inputSettings, double frameSize, out AVCLevelEnforcementReturn enforcement) { x264Settings enforcedSettings = (x264Settings) inputSettings.Clone(); enforcement = new AVCLevelEnforcementReturn(); enforcement.Altered = false; enforcement.EnableP4x4mv = true; enforcement.EnableVBVBufferSize = true; enforcement.EnableVBVMaxRate = true; enforcement.Panic = false; enforcement.PanicString = ""; if (!checkP4x4(level, inputSettings)) { enforcement.Altered = true; enforcedSettings.P4x4mv = false; } if (checkP4x4Enabled(level, inputSettings)) enforcement.EnableP4x4mv = true; else enforcement.EnableP4x4mv = false; // step through various options to enforce the max decoded picture buffer size while (!this.checkMaxDPB(level,enforcedSettings, frameSize)) { if (enforcedSettings.NbRefFrames > 1) { enforcement.Altered = true; enforcedSettings.NbRefFrames -= 1; // try reducing the number of reference frames } else { enforcement.Panic = true; enforcement.PanicString = "Can't force settings to conform to level (the frame size is too large)"; // reset output settings to original and set level to unrestrained enforcedSettings = (x264Settings)inputSettings.Clone(); enforcedSettings.Level = 15; return enforcedSettings; } } // Disallow independent specification of MaxBitrate and MaxBufferSize unless Unrestrained if (level < 15) { enforcement.EnableVBVMaxRate = false; enforcedSettings.VBVMaxBitrate = -1; enforcement.EnableVBVBufferSize = false; enforcedSettings.VBVBufferSize = -1; } else { enforcement.EnableVBVMaxRate = true; enforcement.EnableVBVBufferSize = true; } return enforcedSettings; }