avcpp
avcpp copied to clipboard
Why do you use new Codec() object in examples?
Hello! I am examining your project and decode/encode examples.
I found some strange places in the examples
Decode:
if (vst.isValid()) {
vdec = VideoDecoderContext(vst);
vdec.setRefCountedFrames(true);
vdec.open(Codec(), ec);
if (ec) {
cerr << "Can't open codec\n";
return 1;
}
}
During initialization of VideoDecoderContext your code initializes Codec object and sets the code to the context
} else {
m_raw->codec_id = !codec.isNull() ? codec.raw()->id : AV_CODEC_ID_NONE;
m_raw->codec_type = type;
m_raw->codec = codec.raw();
if (!codec.isNull()) {
if (codec.raw()->pix_fmts != 0)
m_raw->pix_fmt = *(codec.raw()->pix_fmts); // assign default value
if (codec.raw()->sample_fmts != 0)
m_raw->sample_fmt = *(codec.raw()->sample_fmts);
}
}
After that you call open() function with new object Codec().
However, in the example from ffmpeg documentation the codec initialized with avcodec_find_decoder is passed to the avcodec_open2.
The similar strange thing is with encode example:
OutputFormat ofrmt;
FormatContext octx;
ofrmt.setFormat(string(), out);
octx.setFormat(ofrmt);
Codec ocodec = findEncodingCodec(ofrmt);
Stream ost = octx.addStream(ocodec);
VideoEncoderContext encoder {ost};
....
encoder.open(Codec(), ec);
if (ec) {
cerr << "Can't opent encodec\n";
return 1;
}
You create ocodec, but pass to encoder some new object.
Could you please explain why do you use uninitialized Codec object when you open decoder and encoder ?
Hi,
All magic located here:
vdec = VideoDecoderContext(vst);
Just look into CodecContext2::CodecContext2(const Stream &st, const Codec &codec, Direction direction, AVMediaType type)
To simplify research, CodecContext2() called like:
CodecContext2(vst, Codec(), Direction::Decoding, AVMEDIA_TYPE_VIDEO)
Null Codec here means "use vst for the codec selection" and needed only for some corner cases, when codec overriding are needed:
... CodecContext2()...
...
Codec c = codec;
if (codec.isNull())
{
if (st.direction() == Direction::Decoding)
c = findDecodingCodec(codecId);
else
c = findEncodingCodec(codecId);
}
...
Open routine can be simplified to:
vdec.open(ec);
This mostly same to
vdec.open(Codec(), ec);
For opening this routine are used:
void CodecContext2::open(const Codec &codec, AVDictionary **options, OptionalErrorCode ec)
{
clear_if(ec);
if (isOpened() || !isValid()) {
throws_if(ec, isOpened() ? Errors::CodecAlreadyOpened : Errors::CodecInvalid);
return;
}
int stat = avcodec_open2(m_raw, codec.raw(), options);
if (stat < 0)
throws_if(ec, stat, ffmpeg_category());
}
You may be confused, that avcodec_open2() calls with NULL codec. But, look into avcodec_open2() description:
* @param codec The codec to open this context for. If a non-NULL codec has been
* previously passed to avcodec_alloc_context3() or
* for this context, then this parameter MUST be either NULL or
* equal to the previously passed codec.
We are initialized VideoDecoderContext with the Stream reference. And already pass correct codec to the avcodec_alloc_context3(). So, now you have two ways:
- Add extra unuseful code to pass correct codec into
open() - Or just pass Empty/Null codec in to it )
Ah! Codec() provides Null Codec :-)
And sorry for the long delay :-)