Reputation: 1338
I'm looking at re-muxing some containers holding audio and video such that I extract the best, first audio stream, and store it in a new container where e.g. only the audio stream is present.
The output context for FFmpeg is created like so:
AVFormatContext* output_context = NULL;
avformat_alloc_output_context2( &output_context, NULL, "mp4", NULL );
I have a shortlist of acceptable outputs, e.g. MP4, M4A, etc … essentially those that are readable by Apple's Audio File Services:
kAudioFileAIFFType = 'AIFF',
kAudioFileAIFCType = 'AIFC',
kAudioFileWAVEType = 'WAVE',
kAudioFileSoundDesigner2Type = 'Sd2f',
kAudioFileNextType = 'NeXT',
kAudioFileMP3Type = 'MPG3', // mpeg layer 3
kAudioFileMP2Type = 'MPG2', // mpeg layer 2
kAudioFileMP1Type = 'MPG1', // mpeg layer 1
kAudioFileAC3Type = 'ac-3',
kAudioFileAAC_ADTSType = 'adts',
kAudioFileMPEG4Type = 'mp4f',
kAudioFileM4AType = 'm4af',
kAudioFileM4BType = 'm4bf',
kAudioFileCAFType = 'caff',
kAudioFile3GPType = '3gpp',
kAudioFile3GP2Type = '3gp2',
kAudioFileAMRType = 'amrf'
My question is this : is there an easy API in FFmpeg that can be leveraged to choose a compatible output container given the codec the audio stream is in?
Upvotes: 5
Views: 2867
Reputation: 366
the ffmpeg API has changed since, enumerating all containers and codecs can be done now like
void enumerate() {
// enumerate all codecs and put into list
std::vector<const AVCodec*> encoderList;
void* codecState = nullptr; //start with null
const AVCodec* codec = av_codec_iterate(&codecState);
while (codec) {
encoderList.push_back(codec);
codec = av_codec_iterate(&codecState);
}
// enumerate all containers available for muxing
void* muxerState = nullptr;
const AVOutputFormat* ofmt = av_muxer_iterate(&muxerState);
while (ofmt) {
std::set<std::string> codecNames;
for (auto codec : encoderList) {
// check if codec can be used in this container
if (avformat_query_codec(ofmt, codec->id, FF_COMPLIANCE_NORMAL) == 1) {
// check for audio codecs here
if (avcodec_get_type(codec->id) == AVMEDIA_TYPE_AUDIO) {
codecNames.insert(avcodec_get_name(codec->id));
}
}
}
// print unique format and codec names
for (auto& codecName : codecNames) {
std::printf("format '%s' codec '%s'\n", ofmt->name, codecName.c_str());
}
// get next format
ofmt = av_muxer_iterate(&muxerState);
}
}
Upvotes: 0
Reputation: 1068
There's a dynamic approach to that problem. This enumerates the codecs for each container, but you also get the inverse:
// enumerate all codecs and put into list
std::vector<AVCodec*> encoderList;
AVCodec * codec = nullptr;
while (codec = av_codec_next(codec))
{
// try to get an encoder from the system
auto encoder = avcodec_find_encoder(codec->id);
if (encoder)
{
encoderList.push_back(encoder);
}
}
// enumerate all containers
AVOutputFormat * outputFormat = nullptr;
while (outputFormat = av_oformat_next(outputFormat))
{
for (auto codec : encoderList)
{
// only add the codec if it can be used with this container
if (avformat_query_codec(outputFormat, codec->id, FF_COMPLIANCE_STRICT) == 1)
{
// add codec for container
}
}
}
If you just want specific containers or codecs you can use a whitelist with their name
or id
fields and use that when enumerating.
Upvotes: 5
Reputation: 93261
For each individual muxer, there is usually a codec tag writing function.That function will check against a list in another source file or work through a switch
statement in the same. There is no central roster or container-matching utility function. Your best bet is to identify the codec id in libavcodec/allcodecs.c
and then grep in libavformat/
for that ID, particularly within files suffixed with enc e.g. matroskaenc.c
.
Upvotes: 1