}
// override the input codec
if (iacodec != null)
{
ICodec codec = null;
/**
* Looks like they did specify one; let's look it up by name.
*/
codec = ICodec.findDecodingCodecByName(iacodec);
if (codec == null || codec.getType() != ICodec.Type.CODEC_TYPE_AUDIO)
throw new RuntimeException("could not find decoder: " + iacodec);
/**
* Now, tell the output stream coder that it's to use that codec.
*/
mIContainer.setForcedAudioCodec(codec.getID());
}
/**
* Open the input container for Reading.
*/
IMetaData parameters = IMetaData.make();
if (isampleRate > 0)
parameters.setValue("sample_rate", ""+isampleRate);
if (ichannels > 0)
parameters.setValue("channels", ""+ichannels);
IMetaData rejectParameters = IMetaData.make();
retval = mIContainer.open(inputURL, IContainer.Type.READ, iFmt, false, true,
parameters, rejectParameters);
if (retval < 0)
throw new RuntimeException("could not open url: " + inputURL);
if (rejectParameters.getNumKeys() > 0)
throw new RuntimeException("some parameters were rejected: " + rejectParameters);
/**
* If the user EXPLICITLY asked for a output container format, we'll try to
* honor their request here.
*/
if (containerFormat != null)
{
oFmt = IContainerFormat.make();
/**
* Try to find an output format based on what the user specified, or
* failing that, based on the outputURL (e.g. if it ends in .flv, we'll
* guess FLV).
*/
retval = oFmt.setOutputFormat(containerFormat, outputURL, null);
if (retval < 0)
throw new RuntimeException("could not find output container format: "
+ containerFormat);
}
/**
* Open the output container for writing. If oFmt is null, we are telling
* Xuggler to guess the output container format based on the outputURL.
*/
retval = mOContainer.open(outputURL, IContainer.Type.WRITE, oFmt);
if (retval < 0)
throw new RuntimeException("could not open output url: " + outputURL);
/**
* Find out how many streams are there in the input container? For example,
* most FLV files will have 2 -- 1 audio stream and 1 video stream.
*/
int numStreams = mIContainer.getNumStreams();
if (numStreams <= 0)
throw new RuntimeException("not streams in input url: " + inputURL);
/**
* Here we create IStream, IStreamCoders and other objects for each input
* stream.
*
* We make parallel objects for each output stream as well.
*/
mIStreams = new IStream[numStreams];
mICoders = new IStreamCoder[numStreams];
mOStreams = new IStream[numStreams];
mOCoders = new IStreamCoder[numStreams];
mASamplers = new IAudioResampler[numStreams];
mVSamplers = new IVideoResampler[numStreams];
mIVideoPictures = new IVideoPicture[numStreams];
mOVideoPictures = new IVideoPicture[numStreams];
mISamples = new IAudioSamples[numStreams];
mOSamples = new IAudioSamples[numStreams];
/**
* Now let's go through the input streams one by one and explicitly set up
* our contexts.
*/
for (int i = 0; i < numStreams; i++)
{
/**
* Get the IStream for this input stream.
*/
IStream is = mIContainer.getStream(i);
/**
* And get the input stream coder. Xuggler will set up all sorts of
* defaults on this StreamCoder for you (such as the audio sample rate)
* when you open it.
*
* 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))
{
/**
* First, did the user specify an audio codec?
*/
ICodec codec = null;
if (acodec != 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);
}
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.
*/
codec = ICodec.guessEncodingCodec(oFmt, null, outputURL, null,
cType);
if (codec == null)
throw new RuntimeException("could not guess " + cType
+ " encoder for: " + outputURL);
}
/**
* 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(codec);
/**
* 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();
mOStreams[i] = os;
mOCoders[i] = oc;
/**
* Now let's see if the codec can support the input sample format; if not
* we pick the last sample format the codec supports.
*/
Format preferredFormat = ic.getSampleFormat();
List<Format> formats = codec.getSupportedAudioSampleFormats();
for(Format format : formats) {
oc.setSampleFormat(format);
if (format == preferredFormat)
break;
}
final String apreset = cmdLine.getOptionValue("apreset");
if (apreset != null)
Configuration.configure(apreset, oc);
/**
* 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()
|| oc.getSampleFormat() != ic.getSampleFormat())
{
/**
* Create an audio resampler to do that job.
*/
mASamplers[i] = IAudioResampler.make(oc.getChannels(), ic
.getChannels(), oc.getSampleRate(), ic.getSampleRate(),
oc.getSampleFormat(), ic.getSampleFormat());
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(), ic.getSampleFormat());
mOSamples[i] = IAudioSamples.make(1024, oc.getChannels(), oc.getSampleFormat());
}
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.
*/
ICodec codec = null;
if (vcodec != null)
{
codec = ICodec.findEncodingCodecByName(vcodec);
if (codec == null || codec.getType() != cType)
throw new RuntimeException("could not find encoder: " + vcodec);
}
else
{
codec = ICodec.guessEncodingCodec(oFmt, null, outputURL, null,