Skip to content

Caffe2 uses FFMPEG functions that are deprecated in FFMPEG 4.0 and gone in 5.0 #72254

@gspr

Description

@gspr

Describe the bug

caffe2/video/video_decoder.cc use several parts of the FFMPEG API that have been deprecated for a while, and that have been removed in the recent FFMPEG 5.0 release. This naturally makes the Caffe2 part of PyTorch unbuildable with FFMPEG 5.0.

See also this Debian bug.

Partial fix

Many of the changes are very mechanical to implement. As an example, this patch against an older PyTorch (but representative of the changes needed in git HEAD too)

---
 caffe2/video/video_decoder.cc | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/caffe2/video/video_decoder.cc b/caffe2/video/video_decoder.cc
index d40bc05..a496380 100644
--- a/caffe2/video/video_decoder.cc
+++ b/caffe2/video/video_decoder.cc
@@ -12,8 +12,10 @@ VideoDecoder::VideoDecoder() {
   static std::mutex gMutex;
   std::unique_lock<std::mutex> lock(gMutex);
   if (!gInitialized) {
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
     av_register_all();
     avcodec_register_all();
+#endif
     avformat_network_init();
     gInitialized = true;
   }
@@ -185,12 +187,12 @@ void VideoDecoder::decodeLoop(
     if (params.streamIndex_ == -1) {
       for (int i = 0; i < inputContext->nb_streams; i++) {
         auto stream = inputContext->streams[i];
-        if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
             videoStreamIndex_ == -1) {
           videoStreamIndex_ = i;
           videoStream_ = stream;
         } else if (
-            stream->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+            stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
             audioStreamIndex_ == -1) {
           audioStreamIndex_ = i;
         }
@@ -207,7 +209,11 @@ void VideoDecoder::decodeLoop(
 
     // Initialize codec
     AVDictionary* opts = nullptr;
-    videoCodecContext_ = videoStream_->codec;
+    ret = avcodec_parameters_to_context(videoCodecContext_, videoStream_->codecpar);
+    if (ret < 0) {
+      LOG(ERROR) << "Cannot get codec context from parameters";
+      return;
+    }
     try {
       ret = avcodec_open2(
           videoCodecContext_,
@@ -452,12 +458,12 @@ void VideoDecoder::decodeLoop(
           ret = av_read_frame(inputContext, &packet);
           if (ret == AVERROR_EOF) {
             eof = 1;
-            av_free_packet(&packet);
+            av_packet_unref(&packet);
             packet.data = nullptr;
             packet.size = 0;
             // stay in the while loop to flush frames
           } else if (ret == AVERROR(EAGAIN)) {
-            av_free_packet(&packet);
+            av_packet_unref(&packet);
             continue;
           } else if (ret < 0) {
             LOG(ERROR) << "Error reading packet : " << ffmpegErrorStr(ret);
@@ -483,7 +489,7 @@ void VideoDecoder::decodeLoop(
           }
 
           if (si != videoStreamIndex_) {
-            av_free_packet(&packet);
+            av_packet_unref(&packet);
             continue;
           }
         }
@@ -497,7 +503,7 @@ void VideoDecoder::decodeLoop(
         try {
           // Nothing to do without a picture
           if (!gotPicture) {
-            av_free_packet(&packet);
+            av_packet_unref(&packet);
             continue;
           }
           frameIndex++;
@@ -534,7 +540,7 @@ void VideoDecoder::decodeLoop(
             if (!keyFrame) {
               // if fps == SpecialFps::SAMPLE_NO_FRAME (0), don't sample at all
               if (currFps == SpecialFps::SAMPLE_NO_FRAME) {
-                av_free_packet(&packet);
+                av_packet_unref(&packet);
                 continue;
               }
 
@@ -560,7 +566,7 @@ void VideoDecoder::decodeLoop(
                    timestamp >= lastFrameTimestamp + (1 / currFps));
 
               if (!fpsReached) {
-                av_free_packet(&packet);
+                av_packet_unref(&packet);
                 continue;
               }
             }
@@ -571,7 +577,7 @@ void VideoDecoder::decodeLoop(
             if (params.maximumOutputFrames_ != -1 &&
                 outputFrameIndex >= params.maximumOutputFrames_) {
               // enough frames
-              av_free_packet(&packet);
+              av_packet_unref(&packet);
               break;
             }
 
@@ -628,9 +634,9 @@ void VideoDecoder::decodeLoop(
           av_frame_unref(audioStreamFrame_);
         }
 
-        av_free_packet(&packet);
+        av_packet_unref(&packet);
       } catch (const std::exception&) {
-        av_free_packet(&packet);
+        av_packet_unref(&packet);
       }
     } // of while loop
     callback.videoDecodingEnded(timestamp);

seems to take care of a lot of them. However, replacing avcodec_decode_video2 and friends with the newer avcodec_receive_frame probably takes some care and thought.

Versions

This behavior is present in the current master HEAD at the time of writing, although the partial patch above is for an older version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    caffe2module: dependency bugProblem is not caused by us, but caused by an upstream library we usetriagedThis issue has been looked at a team member, and triaged and prioritized into an appropriate module

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions