Unverified Commit da03f51a authored by Bruno Korbar's avatar Bruno Korbar Committed by GitHub
Browse files

Attempt to fix FFMPEG 5.0 compatibility (#5644)



* fix for FFMPEG 5.0

* Attempt to fix memory leak

* early stop when mem alloc fails

* fix c lint error

* fix bug

* revert changes

* remove incorrect av_packet_free

* add `av_packet_free` to subtitle stream

* Addressing subtitle stream comments

* addressing decoder changes

* nit

* addressing datumbox concernsz

* averror push

* addressing comments

* Apply suggestions from code review

* add new error code to documentation

* re-introducing timeout

* fix c++ syntax
Co-authored-by: default avatarBruno Korbar <bkorbar@quansight.com>
Co-authored-by: default avatarVasilis Vryniotis <datumbox@users.noreply.github.com>
Co-authored-by: default avatarJoao Gomes <jdsgomes@fb.com>
Co-authored-by: default avatarJoao Gomes <joaopsgomes@gmail.com>
parent 43dbfd2e
...@@ -18,25 +18,6 @@ constexpr size_t kIoBufferSize = 96 * 1024; ...@@ -18,25 +18,6 @@ constexpr size_t kIoBufferSize = 96 * 1024;
constexpr size_t kIoPaddingSize = AV_INPUT_BUFFER_PADDING_SIZE; constexpr size_t kIoPaddingSize = AV_INPUT_BUFFER_PADDING_SIZE;
constexpr size_t kLogBufferSize = 1024; constexpr size_t kLogBufferSize = 1024;
int ffmpeg_lock(void** mutex, enum AVLockOp op) {
std::mutex** handle = (std::mutex**)mutex;
switch (op) {
case AV_LOCK_CREATE:
*handle = new std::mutex();
break;
case AV_LOCK_OBTAIN:
(*handle)->lock();
break;
case AV_LOCK_RELEASE:
(*handle)->unlock();
break;
case AV_LOCK_DESTROY:
delete *handle;
break;
}
return 0;
}
bool mapFfmpegType(AVMediaType media, MediaType* type) { bool mapFfmpegType(AVMediaType media, MediaType* type) {
switch (media) { switch (media) {
case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_AUDIO:
...@@ -202,8 +183,6 @@ void Decoder::initOnce() { ...@@ -202,8 +183,6 @@ void Decoder::initOnce() {
avcodec_register_all(); avcodec_register_all();
#endif #endif
avformat_network_init(); avformat_network_init();
// register ffmpeg lock manager
av_lockmgr_register(&ffmpeg_lock);
av_log_set_callback(Decoder::logFunction); av_log_set_callback(Decoder::logFunction);
av_log_set_level(AV_LOG_ERROR); av_log_set_level(AV_LOG_ERROR);
VLOG(1) << "Registered ffmpeg libs"; VLOG(1) << "Registered ffmpeg libs";
...@@ -277,7 +256,7 @@ bool Decoder::init( ...@@ -277,7 +256,7 @@ bool Decoder::init(
break; break;
} }
fmt = av_find_input_format(fmtName); fmt = (AVInputFormat*)av_find_input_format(fmtName);
} }
const size_t avioCtxBufferSize = kIoBufferSize; const size_t avioCtxBufferSize = kIoBufferSize;
...@@ -495,8 +474,8 @@ void Decoder::cleanUp() { ...@@ -495,8 +474,8 @@ void Decoder::cleanUp() {
// function does actual work, derived class calls it in working thread // function does actual work, derived class calls it in working thread
// periodically. On success method returns 0, ENODATA on EOF, ETIMEDOUT if // periodically. On success method returns 0, ENODATA on EOF, ETIMEDOUT if
// no frames got decoded in the specified timeout time, and error on // no frames got decoded in the specified timeout time, AVERROR_BUFFER_TOO_SMALL
// unrecoverable error. // when unable to allocate packet and error on unrecoverable error
int Decoder::getFrame(size_t workingTimeInMs) { int Decoder::getFrame(size_t workingTimeInMs) {
if (inRange_.none()) { if (inRange_.none()) {
return ENODATA; return ENODATA;
...@@ -505,10 +484,15 @@ int Decoder::getFrame(size_t workingTimeInMs) { ...@@ -505,10 +484,15 @@ int Decoder::getFrame(size_t workingTimeInMs) {
// once decode() method gets called and grab some bytes // once decode() method gets called and grab some bytes
// run this method again // run this method again
// init package // init package
AVPacket avPacket; // update 03/22: moving memory management to ffmpeg
av_init_packet(&avPacket); AVPacket* avPacket;
avPacket.data = nullptr; avPacket = av_packet_alloc();
avPacket.size = 0; if (avPacket == nullptr) {
LOG(ERROR) << "decoder as not able to allocate the packet.";
return AVERROR_BUFFER_TOO_SMALL;
}
avPacket->data = nullptr;
avPacket->size = 0;
auto end = std::chrono::steady_clock::now() + auto end = std::chrono::steady_clock::now() +
std::chrono::milliseconds(workingTimeInMs); std::chrono::milliseconds(workingTimeInMs);
...@@ -520,8 +504,12 @@ int Decoder::getFrame(size_t workingTimeInMs) { ...@@ -520,8 +504,12 @@ int Decoder::getFrame(size_t workingTimeInMs) {
int result = 0; int result = 0;
size_t decodingErrors = 0; size_t decodingErrors = 0;
bool decodedFrame = false; bool decodedFrame = false;
while (!interrupted_ && inRange_.any() && !decodedFrame && watcher()) { while (!interrupted_ && inRange_.any() && !decodedFrame) {
result = av_read_frame(inputCtx_, &avPacket); if (watcher() == false) {
result = ETIMEDOUT;
break;
}
result = av_read_frame(inputCtx_, avPacket);
if (result == AVERROR(EAGAIN)) { if (result == AVERROR(EAGAIN)) {
VLOG(4) << "Decoder is busy..."; VLOG(4) << "Decoder is busy...";
std::this_thread::yield(); std::this_thread::yield();
...@@ -538,10 +526,11 @@ int Decoder::getFrame(size_t workingTimeInMs) { ...@@ -538,10 +526,11 @@ int Decoder::getFrame(size_t workingTimeInMs) {
break; break;
} }
// get stream // get stream; if stream cannot be found reset the packet to
auto stream = findByIndex(avPacket.stream_index); // default settings
auto stream = findByIndex(avPacket->stream_index);
if (stream == nullptr || !inRange_.test(stream->getIndex())) { if (stream == nullptr || !inRange_.test(stream->getIndex())) {
av_packet_unref(&avPacket); av_packet_unref(avPacket);
continue; continue;
} }
...@@ -553,7 +542,7 @@ int Decoder::getFrame(size_t workingTimeInMs) { ...@@ -553,7 +542,7 @@ int Decoder::getFrame(size_t workingTimeInMs) {
bool hasMsg = false; bool hasMsg = false;
// packet either got consumed completely or not at all // packet either got consumed completely or not at all
if ((result = processPacket( if ((result = processPacket(
stream, &avPacket, &gotFrame, &hasMsg, params_.fastSeek)) < 0) { stream, avPacket, &gotFrame, &hasMsg, params_.fastSeek)) < 0) {
LOG(ERROR) << "processPacket failed with code: " << result; LOG(ERROR) << "processPacket failed with code: " << result;
break; break;
} }
...@@ -585,11 +574,10 @@ int Decoder::getFrame(size_t workingTimeInMs) { ...@@ -585,11 +574,10 @@ int Decoder::getFrame(size_t workingTimeInMs) {
result = 0; result = 0;
av_packet_unref(&avPacket); av_packet_unref(avPacket);
} }
av_packet_unref(&avPacket); av_packet_free(&avPacket);
VLOG(2) << "Interrupted loop" VLOG(2) << "Interrupted loop"
<< ", interrupted_ " << interrupted_ << ", inRange_.any() " << ", interrupted_ " << interrupted_ << ", inRange_.any() "
<< inRange_.any() << ", decodedFrame " << decodedFrame << ", result " << inRange_.any() << ", decodedFrame " << decodedFrame << ", result "
...@@ -597,8 +585,7 @@ int Decoder::getFrame(size_t workingTimeInMs) { ...@@ -597,8 +585,7 @@ int Decoder::getFrame(size_t workingTimeInMs) {
// loop can be terminated, either by: // loop can be terminated, either by:
// 1. explcitly iterrupted // 1. explcitly iterrupted
// 2. terminated by workable timeout // 3. unrecoverable error or ENODATA (end of stream) or ETIMEDOUT (timeout)
// 3. unrecoverable error or ENODATA (end of stream)
// 4. decoded frames pts are out of the specified range // 4. decoded frames pts are out of the specified range
// 5. success decoded frame // 5. success decoded frame
if (interrupted_) { if (interrupted_) {
......
...@@ -28,7 +28,7 @@ Stream::~Stream() { ...@@ -28,7 +28,7 @@ Stream::~Stream() {
// look up the proper CODEC querying the function // look up the proper CODEC querying the function
AVCodec* Stream::findCodec(AVCodecParameters* params) { AVCodec* Stream::findCodec(AVCodecParameters* params) {
return avcodec_find_decoder(params->codec_id); return (AVCodec*)avcodec_find_decoder(params->codec_id);
} }
// Allocate memory for the AVCodecContext, which will hold the context for // Allocate memory for the AVCodecContext, which will hold the context for
......
...@@ -43,21 +43,34 @@ int SubtitleStream::initFormat() { ...@@ -43,21 +43,34 @@ int SubtitleStream::initFormat() {
int SubtitleStream::analyzePacket(const AVPacket* packet, bool* gotFrame) { int SubtitleStream::analyzePacket(const AVPacket* packet, bool* gotFrame) {
// clean-up // clean-up
releaseSubtitle(); releaseSubtitle();
// FIXME: should this even be created?
AVPacket* avPacket;
avPacket = av_packet_alloc();
if (avPacket == nullptr) {
LOG(ERROR)
<< "decoder as not able to allocate the subtitle-specific packet.";
// alternative to ENOMEM
return AVERROR_BUFFER_TOO_SMALL;
}
avPacket->data = nullptr;
avPacket->size = 0;
// check flush packet // check flush packet
AVPacket avPacket; auto pkt = packet ? packet : avPacket;
av_init_packet(&avPacket);
avPacket.data = nullptr;
avPacket.size = 0;
auto pkt = packet ? *packet : avPacket;
int gotFramePtr = 0; int gotFramePtr = 0;
int result = avcodec_decode_subtitle2(codecCtx_, &sub_, &gotFramePtr, &pkt); // is these a better way than cast from const?
int result =
avcodec_decode_subtitle2(codecCtx_, &sub_, &gotFramePtr, (AVPacket*)pkt);
if (result < 0) { if (result < 0) {
LOG(ERROR) << "avcodec_decode_subtitle2 failed, err: " LOG(ERROR) << "avcodec_decode_subtitle2 failed, err: "
<< Util::generateErrorDesc(result); << Util::generateErrorDesc(result);
// free the packet we've created
av_packet_free(&avPacket);
return result; return result;
} else if (result == 0) { } else if (result == 0) {
result = pkt.size; // discard the rest of the package result = pkt->size; // discard the rest of the package
} }
sub_.release = gotFramePtr; sub_.release = gotFramePtr;
...@@ -66,9 +79,10 @@ int SubtitleStream::analyzePacket(const AVPacket* packet, bool* gotFrame) { ...@@ -66,9 +79,10 @@ int SubtitleStream::analyzePacket(const AVPacket* packet, bool* gotFrame) {
// set proper pts in us // set proper pts in us
if (gotFramePtr) { if (gotFramePtr) {
sub_.pts = av_rescale_q( sub_.pts = av_rescale_q(
pkt.pts, inputCtx_->streams[format_.stream]->time_base, timeBaseQ); pkt->pts, inputCtx_->streams[format_.stream]->time_base, timeBaseQ);
} }
av_packet_free(&avPacket);
return result; return result;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment