⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rateconverter.java

📁 FMJ(freedom media for java)是java视频开发的新选择
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
        	}        	else        		throw new RuntimeException("Unsupported number of channels");	// TODO: check in setInputFormat/setOutputFormat        }                if (stereoToMono)        	requiredOutputBufferLength /= 2;        else if (monoToStereo)        	requiredOutputBufferLength *= 2;        	                        // get/allocate output buffer:        byte[] outputBufferData = (byte []) outputBuffer.getData();        if (outputBufferData == null || outputBufferData.length < requiredOutputBufferLength)        {	outputBufferData = new byte[requiredOutputBufferLength];        	outputBuffer.setData(outputBufferData);        }                final byte[] inputBufferData = (byte []) inputBuffer.getData();        		// so for example if getSampleSizeInBits is 8, this value is 128.		final long outputSignedUnsignedDifference =  1 << (outputAudioFormat.getSampleSizeInBits() - 1);//		 so for example if getSampleSizeInBits is 8, this value is 255.		final long outputUnsignedMax = (1 << outputAudioFormat.getSampleSizeInBits()) - 1;		final long inputSignedUnsignedDifference =  1 << (inputAudioFormat.getSampleSizeInBits() - 1);		// if getSampleSizeInBits is 8, this value is 255:		final long inputUnsignedMax = (1 << inputAudioFormat.getSampleSizeInBits()) - 1;		// if getSampleSizeInBits is 8, this value is 127:		final long inputSignedMax = (1 << (inputAudioFormat.getSampleSizeInBits() - 1)) - 1;		// if getSampleSizeInBits is 8, this value is -128:		final long inputSignedMin = (inputSignedMax + 1) * -1;				double accumulatedRateChangeError = 0.0;	// because in the case of non-integral ratios of sample rate change, we have to 													// output samples occasionally to maintain the correct "slope".  This is much													// like drawing a diagonal line on the screen.		int outputSampleIndex = 0;	// index of next sample in output buffer        for (int i = 0; i < inputSamples; ++i)        {        	if (stereoToMono && i % 2 == 1)        		continue;	// for now, just omit one channel.  TODO: average.        	        	// get the ith sample, converted to a long, taking into account sample size in bits, endian-ness, and signed/unsigned.        	final int byteOffsetOfSample = inputBuffer.getOffset() + i * inputSampleSizeInBytes;        	        	final int inputSampleLiteral = getSample(inputBufferData, byteOffsetOfSample, inputSampleSizeInBytes, inputAudioFormat.getEndian());        	final long inputSampleLongWithoutSign = UnsignedUtils.uIntToLong(inputSampleLiteral);        	final long inputSampleLongWithSign;        	if (inputAudioFormat.getSigned() == AudioFormat.UNSIGNED)        		inputSampleLongWithSign = inputSampleLongWithoutSign;        	else if (inputAudioFormat.getSigned() == AudioFormat.SIGNED)        	{        		if (inputSampleLongWithoutSign > inputSignedMax)        			inputSampleLongWithSign = inputSampleLongWithoutSign - inputUnsignedMax - 1;        		else        			inputSampleLongWithSign = inputSampleLongWithoutSign;        	}        	else        		throw new RuntimeException("input format signed not specified");        		        	// inputSample is now the literal binary value of the sample (0s in unused MSBs), while inputSampleLong is now the literal numeric value of the sample (reflecting sign if applicable).              	// now perform some conversions to get the desired output sample:    		final long outputSampleLongWithSign;    		    		// apply sign change difference if needed:    		if (outputAudioFormat.getSigned() == AudioFormat.SIGNED && inputAudioFormat.getSigned() == AudioFormat.UNSIGNED)    			outputSampleLongWithSign = inputSampleLongWithSign - inputSignedUnsignedDifference;    		else if (outputAudioFormat.getSigned() == AudioFormat.UNSIGNED && inputAudioFormat.getSigned() == AudioFormat.SIGNED)    			outputSampleLongWithSign = inputSampleLongWithSign + inputSignedUnsignedDifference;    		else    			outputSampleLongWithSign = inputSampleLongWithSign;    		        	// now we have to deal with sample rate issues.  we either have more or less samples.  If we have more in the output, then        	// we repeat the input (a better solution would be to smooth).  if we have less, we average.        	if (sampleRateRatio == 1.0)        	{	// no sample rate change: output a single sample for each input sample	        		final long outputSampleLongWithoutSign = getOutputSampleLongWithoutSign(outputSampleLongWithSign, inputUnsignedMax, inputAudioFormat, outputAudioFormat);        		for (int c = 0; c < outputChannelRepeatCount; ++c)        			putSample(outputSampleLongWithoutSign, outputBufferData, (outputSampleIndex++) * outputSampleSizeInBytes, outputSampleSizeInBytes, outputAudioFormat.getEndian());         		        			        	}    		else if (sampleRateRatio > 1.0)        	{	        		// more output than input - repeat samples    			        		// figure out which channel we are outputting to, so we know which Averager to use:        		final int outputChannel;        		if (outputAudioFormat.getChannels() == 1)        			outputChannel = 0;        		else        			outputChannel = i % 2; // this requires that a buffer always has a complete frame, that is, the buffer always starts with channel 0.                final Averager a = averagers[outputChannel];                            		                // the input sample can be divided into 2 parts:                // 1. the part that will be output as part of the current output samples (combined with whatever has been accumulated)                // 2. the rest, which will be accumulated for the next time.                                // the averager is used as follows:                // sampleWeight is expressed as a fraction of the input sample size.                        		                final double[] sampleWeights;	// TODO: don't allocate array each time.                if ((a.numAccumulatedSamples + 1) > 1.0)                   {	// we are going to be averaging 2 input samples for the output sample(s)                	final double sampleWeight = sampleRateInverseRatio - a.numAccumulatedSamples;	                	final double sampleWeight2 = 1.0 - sampleWeight;                	sampleWeights = new double[] {sampleWeight, sampleWeight2};                }                else                {   final double sampleWeight = 1.0;                	sampleWeights = new double[] {sampleWeight};                }                                                for (double sampleWeight : sampleWeights)                {	                a.accumulatedSample += outputSampleLongWithSign * sampleWeight;	        		a.numAccumulatedSamples += sampleWeight;                	        			        		final int repeatCount = (int) (a.numAccumulatedSamples * sampleRateRatio);	        		if (repeatCount > 0)	// this will always be > 0, because sampleRateRatio > 1.0	        		{	        			final long outputSampleLongWithSignAvg = (long) Math.round(a.accumulatedSample / a.numAccumulatedSamples);	        				        			final long outputSampleLongWithoutSign = getOutputSampleLongWithoutSign(outputSampleLongWithSignAvg, inputUnsignedMax, inputAudioFormat, outputAudioFormat);			        		for (int j = 0; j < repeatCount; ++j)		        		{		            		for (int c = 0; c < outputChannelRepeatCount; ++c)		            			putSample(outputSampleLongWithoutSign, outputBufferData, (outputSampleIndex++) * outputSampleSizeInBytes, outputSampleSizeInBytes, outputAudioFormat.getEndian()); 		        				            		final double oldAccumulatedSamples = a.numAccumulatedSamples;		            		// TODO: this introduces small errors, subtracting each time		            		a.numAccumulatedSamples -= sampleRateInverseRatio;		            		a.accumulatedSample = a.accumulatedSample * a.numAccumulatedSamples / oldAccumulatedSamples;		        		}	        		}                }        		        	}        	else if (sampleRateInverseRatio > 1.0)        	{	//        		 more input than output - average samples        		// figure out which channel we are outputting to, so we know which Averager to use:        		final int outputChannel;        		if (outputAudioFormat.getChannels() == 1)        			outputChannel = 0;        		else        			outputChannel = i % 2; // this requires that a buffer always has a complete frame, that is, the buffer always starts with channel 0.                final Averager a = averagers[outputChannel];            		                final double sampleWeight;                if ((a.numAccumulatedSamples + 1) * sampleRateRatio > 1.0)    // if we will output a sample, and another full sample would spill over into the output sample after this one               		sampleWeight = sampleRateInverseRatio - a.numAccumulatedSamples;	// on a scale from 0 to 1, how much of the new input sample overlaps the output sample                else                    sampleWeight = 1.0;        		a.accumulatedSample += outputSampleLongWithSign * sampleWeight;        		a.numAccumulatedSamples += sampleWeight;                                		        		final boolean doOutput = a.numAccumulatedSamples * sampleRateRatio >= 1.0;        		if (doOutput)        		{					final long outputSampleLongWithSignAvg = (long) Math.round(a.accumulatedSample / a.numAccumulatedSamples);					a.accumulatedSample = outputSampleLongWithSignAvg * (1.0 - sampleWeight);  // un-averaged part of current sample        			a.numAccumulatedSamples = (1.0 - sampleWeight);        			        			final long outputSampleLongWithoutSign = getOutputSampleLongWithoutSign(outputSampleLongWithSignAvg, inputUnsignedMax, inputAudioFormat, outputAudioFormat);            		for (int c = 0; c < outputChannelRepeatCount; ++c)            			putSample(outputSampleLongWithoutSign, outputBufferData, (outputSampleIndex++) * outputSampleSizeInBytes, outputSampleSizeInBytes, outputAudioFormat.getEndian());         		}        	        	        	}        }                outputBuffer.setLength(outputSampleIndex * outputSampleSizeInBytes);        outputBuffer.setOffset(0);        outputBuffer.setFormat(outputFormat);                final int result = BUFFER_PROCESSED_OK;                		if (TRACE)		{	dump("input ", inputBuffer);			dump("output", outputBuffer);					System.out.println("Result=" + MediaCGUtils.plugInResultToStr(result));		}		return result;	}                private double fractional(double d)        {             return d - (Math.floor(d));        }        		private static long getOutputSampleLongWithoutSign(long outputSampleLongWithSign, long inputUnsignedMax, AudioFormat inputAudioFormat, AudioFormat outputAudioFormat)	{		// here we want -1 to become 255 for an 8-bit value.		long outputSampleLongWithoutSign;		if (outputSampleLongWithSign >= 0)			outputSampleLongWithoutSign = outputSampleLongWithSign;		else			outputSampleLongWithoutSign = inputUnsignedMax + 1 + outputSampleLongWithSign;				return getOutputSampleLongWithoutSign(outputSampleLongWithoutSign, inputAudioFormat, outputAudioFormat);	}	private static long getOutputSampleLongWithoutSign(long outputSampleLongWithoutSign, AudioFormat inputAudioFormat, AudioFormat outputAudioFormat)	{		// do calculation with unsigned long, so that sign bits are not shifted in.		// apply sample size (truncates, does not round, when going to smaller sample size)		if (outputAudioFormat.getSampleSizeInBits() > inputAudioFormat.getSampleSizeInBits())		{			outputSampleLongWithoutSign <<= (outputAudioFormat.getSampleSizeInBits() - inputAudioFormat.getSampleSizeInBits());		}		else if (inputAudioFormat.getSampleSizeInBits() > outputAudioFormat.getSampleSizeInBits())		{			outputSampleLongWithoutSign >>= (inputAudioFormat.getSampleSizeInBits() - outputAudioFormat.getSampleSizeInBits());		}		return outputSampleLongWithoutSign;	}	/** bit-wise literal.  Is in general unsigned, but may be signed if all 32 bits are used. */	private static int getSample(byte[] inputBufferData, int byteOffsetOfSample, int inputSampleSizeInBytes, int inputEndian)	{       	int sample = 0;    	for (int j = 0; j < inputSampleSizeInBytes; ++j)    	{    		// offset within sample handles endian-ness:    		final int offsetWithinSample = inputEndian == AudioFormat.BIG_ENDIAN ? j : (inputSampleSizeInBytes - 1 - j);    		final byte b = inputBufferData[byteOffsetOfSample + offsetWithinSample];    		sample <<= 8;    		sample |= b & 0xff;        }    	// handle signed-ness.    	return sample;	}	private static void putSample(long sampleLong, byte[] inputBufferData, int byteOffsetOfSample, int outputSampleSizeInBytes, int outputEndian)	{    	// handle signed-ness.       	int sample = (int) sampleLong;    	for (int j = 0; j < outputSampleSizeInBytes; ++j)    	{    		// offset within sample handles endian-ness:    		final int offsetWithinSample = outputEndian == AudioFormat.LITTLE_ENDIAN ? j : (outputSampleSizeInBytes - 1 - j);    		final byte b = (byte) ((sample >> (8 * j)) & 0xff);    		try    		{    			inputBufferData[byteOffsetOfSample + offsetWithinSample] = b;    		}    		catch (ArrayIndexOutOfBoundsException e)    		{    			throw e;    		}    	}	}		public Format setInputFormat(Format arg0)	{		// TODO: force sample size, etc		if (TRACE) System.out.println("setInputFormat: " + MediaCGUtils.formatToStr(arg0));		return super.setInputFormat(arg0);	}	public Format setOutputFormat(Format arg0)	{		if (TRACE) System.out.println("setOutputFormat: " + MediaCGUtils.formatToStr(arg0));		return super.setOutputFormat(arg0);	}	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -