*
* You can create IStreamCoders yourself using
* IStreamCoder#make(IStreamCoder.Direction), but then you have to set all
* parameters yourself.
*/
IStreamCoder ic = is.getStreamCoder();
/**
* Find out what Codec Xuggler guessed the input stream was encoded with.
*/
ICodec.Type cType = ic.getCodecType();
mIStreams[i] = is;
mICoders[i] = ic;
mOStreams[i] = null;
mOCoders[i] = null;
mASamplers[i] = null;
mVSamplers[i] = null;
mIVideoPictures[i] = null;
mOVideoPictures[i] = null;
mISamples[i] = null;
mOSamples[i] = null;
if (cType == ICodec.Type.CODEC_TYPE_AUDIO && mHasAudio
&& (astream == -1 || astream == i))
{
/**
* So it looks like this stream as an audio stream. Now we add an audio
* stream to the output container that we will use to encode our
* resampled audio.
*/
IStream os = mOContainer.addNewStream(i);
/**
* And we ask the IStream for an appropriately configured IStreamCoder
* for output.
*
* Unfortunately you still need to specify a lot of things for
* outputting (because we can't really guess what you want to encode
* as).
*/
IStreamCoder oc = os.getStreamCoder();
String apreset = cmdLine.getOptionValue("apreset");
if (apreset != null)
Configuration.configure(apreset, oc);
mOStreams[i] = os;
mOCoders[i] = oc;
/**
* First, did the user specify an audio codec?
*/
if (acodec != null)
{
ICodec codec = null;
/**
* Looks like they did specify one; let's look it up by name.
*/
codec = ICodec.findEncodingCodecByName(acodec);
if (codec == null || codec.getType() != cType)
throw new RuntimeException("could not find encoder: " + acodec);
/**
* Now, tell the output stream coder that it's to use that codec.
*/
oc.setCodec(codec);
}
else
{
/**
* Looks like the user didn't specify an output coder for audio.
*
* So we ask Xuggler to guess an appropriate output coded based on the
* URL, container format, and that it's audio.
*/
ICodec codec = ICodec.guessEncodingCodec(oFmt, null, outputURL, null,
cType);
if (codec == null)
throw new RuntimeException("could not guess " + cType
+ " encoder for: " + outputURL);
/**
* Now let's use that.
*/
oc.setCodec(codec);
}
/**
* In general a IStreamCoder encoding audio needs to know: 1) A ICodec
* to use. 2) The sample rate and number of channels of the audio. Most
* everything else can be defaulted.
*/
/**
* If the user didn't specify a sample rate to encode as, then just use
* the same sample rate as the input.
*/
if (sampleRate == 0)
sampleRate = ic.getSampleRate();
oc.setSampleRate(sampleRate);
/**
* If the user didn't specify a bit rate to encode as, then just use the
* same bit as the input.
*/
if (abitrate == 0)
abitrate = ic.getBitRate();
if (abitrate == 0)
// some containers don't give a bit-rate
abitrate = 64000;
oc.setBitRate(abitrate);
/**
* If the user didn't specify the number of channels to encode audio as,
* just assume we're keeping the same number of channels.
*/
if (channels == 0)
channels = ic.getChannels();
oc.setChannels(channels);
/**
* And set the quality (which defaults to 0, or highest, if the user
* doesn't tell us one).
*/
oc.setGlobalQuality(aquality);
/**
* Now check if our output channels or sample rate differ from our input
* channels or sample rate.
*
* If they do, we're going to need to resample the input audio to be in
* the right format to output.
*/
if (oc.getChannels() != ic.getChannels()
|| oc.getSampleRate() != ic.getSampleRate())
{
/**
* Create an audio resampler to do that job.
*/
mASamplers[i] = IAudioResampler.make(oc.getChannels(), ic
.getChannels(), oc.getSampleRate(), ic.getSampleRate());
if (mASamplers[i] == null)
{
throw new RuntimeException(
"could not open audio resampler for stream: " + i);
}
}
else
{
mASamplers[i] = null;
}
/**
* Finally, create some buffers for the input and output audio
* themselves.
*
* We'll use these repeated during the #run(CommandLine) method.
*/
mISamples[i] = IAudioSamples.make(1024, ic.getChannels());
mOSamples[i] = IAudioSamples.make(1024, oc.getChannels());
}
else if (cType == ICodec.Type.CODEC_TYPE_VIDEO && mHasVideo
&& (vstream == -1 || vstream == i))
{
/**
* If you're reading these commends, this does the same thing as the
* above branch, only for video. I'm going to assume you read those
* comments and will only document something substantially different
* here.
*/
IStream os = mOContainer.addNewStream(i);
IStreamCoder oc = os.getStreamCoder();
String vpreset = cmdLine.getOptionValue("vpreset");
if (vpreset != null)
Configuration.configure(vpreset, oc);
mOStreams[i] = os;
mOCoders[i] = oc;
if (vcodec != null)
{
ICodec codec = null;
codec = ICodec.findEncodingCodecByName(vcodec);
if (codec == null || codec.getType() != cType)
throw new RuntimeException("could not find encoder: " + vcodec);
oc.setCodec(codec);
oc.setGlobalQuality(0);
}
else
{
ICodec codec = ICodec.guessEncodingCodec(oFmt, null, outputURL, null,
cType);
if (codec == null)
throw new RuntimeException("could not guess " + cType
+ " encoder for: " + outputURL);
oc.setCodec(codec);
}
/**
* In general a IStreamCoder encoding video needs to know: 1) A ICodec
* to use. 2) The Width and Height of the Video 3) The pixel format
* (e.g. IPixelFormat.Type#YUV420P) of the video data. Most everything
* else can be defaulted.
*/
if (vbitrate == 0)
vbitrate = ic.getBitRate();
if (vbitrate == 0)
vbitrate = 250000;
oc.setBitRate(vbitrate);
if (vbitratetolerance > 0)
oc.setBitRateTolerance(vbitratetolerance);
int oWidth = ic.getWidth();
int oHeight = ic.getHeight();
if (oHeight <= 0 || oWidth <= 0)
throw new RuntimeException("could not find width or height in url: "
+ inputURL);
/**
* For this program we don't allow the user to specify the pixel format
* type; we force the output to be the same as the input.
*/
oc.setPixelType(ic.getPixelType());
if (vscaleFactor != 1.0)
{
/**
* In this case, it looks like the output video requires rescaling, so
* we create a IVideoResampler to do that dirty work.
*/
oWidth = (int) (oWidth * vscaleFactor);
oHeight = (int) (oHeight * vscaleFactor);
mVSamplers[i] = IVideoResampler
.make(oWidth, oHeight, oc.getPixelType(), ic.getWidth(), ic
.getHeight(), ic.getPixelType());
if (mVSamplers[i] == null)
{
throw new RuntimeException(
"This version of Xuggler does not support video resampling "
+ i);
}
}
else
{
mVSamplers[i] = null;
}
oc.setHeight(oHeight);
oc.setWidth(oWidth);
if (vquality >= 0)
{
oc.setFlag(IStreamCoder.Flags.FLAG_QSCALE, true);
oc.setGlobalQuality(vquality);
}
/**
* TimeBases are important, especially for Video. In general Audio
* encoders will assume that any new audio happens IMMEDIATELY after any
* prior audio finishes playing. But for video, we need to make sure
* it's being output at the right rate.
*
* In this case we make sure we set the same time base as the input, and
* then we don't change the time stamps of any IVideoPictures.
*
* But take my word that time stamps are tricky, and this only touches
* the envelope. The good news is, it's easier in Xuggler than some
* other systems.
*/
IRational num = null;
num = ic.getFrameRate();
oc.setFrameRate(num);
oc.setTimeBase(IRational.make(num.getDenominator(), num
.getNumerator()));
num = null;
/**
* And allocate buffers for us to store decoded and resample video
* pictures.
*/
mIVideoPictures[i] = IVideoPicture.make(ic.getPixelType(), ic
.getWidth(), ic.getHeight());
mOVideoPictures[i] = IVideoPicture.make(oc.getPixelType(), oc
.getWidth(), oc.getHeight());
}
else
{
log.warn("Ignoring input stream {} of type {}", i, cType);
}