]> git.sesse.net Git - nageru/commitdiff
In FFmpegCapture, frame decoding into its own function.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 May 2017 14:15:17 +0000 (16:15 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 May 2017 14:15:17 +0000 (16:15 +0200)
ffmpeg_capture.cpp
ffmpeg_capture.h

index b5768770dae37201ba5dd7064901f6059196dfe5..305a4d706fbcf6f70686d7439216f10c3580b3df 100644 (file)
@@ -381,41 +381,12 @@ bool FFmpegCapture::play_video(const string &pathname)
                        return true;
                }
 
-               // Read packets until we have a frame or there are none left.
-               int frame_finished = 0;
-               AVFrameWithDeleter frame = av_frame_alloc_unique();
-               bool eof = false;
-               do {
-                       AVPacket pkt;
-                       unique_ptr<AVPacket, decltype(av_packet_unref)*> pkt_cleanup(
-                               &pkt, av_packet_unref);
-                       av_init_packet(&pkt);
-                       pkt.data = nullptr;
-                       pkt.size = 0;
-                       if (av_read_frame(format_ctx.get(), &pkt) == 0) {
-                               if (pkt.stream_index != video_stream_index) {
-                                       // Ignore audio for now.
-                                       continue;
-                               }
-                               if (avcodec_send_packet(codec_ctx.get(), &pkt) < 0) {
-                                       fprintf(stderr, "%s: Cannot send packet to codec.\n", pathname.c_str());
-                                       return false;
-                               }
-                       } else {
-                               eof = true;  // Or error, but ignore that for the time being.
-                       }
-
-                       int err = avcodec_receive_frame(codec_ctx.get(), frame.get());
-                       if (err == 0) {
-                               frame_finished = true;
-                               break;
-                       } else if (err != AVERROR(EAGAIN)) {
-                               fprintf(stderr, "%s: Cannot receive frame from codec.\n", pathname.c_str());
-                               return false;
-                       }
-               } while (!eof);
-
-               if (!frame_finished) {
+               bool error;
+               AVFrameWithDeleter frame = decode_frame(format_ctx.get(), codec_ctx.get(), pathname, video_stream_index, &error);
+               if (error) {
+                       return false;
+               }
+               if (frame == nullptr) {
                        // EOF. Loop back to the start if we can.
                        if (av_seek_frame(format_ctx.get(), /*stream_index=*/-1, /*timestamp=*/0, /*flags=*/0) < 0) {
                                fprintf(stderr, "%s: Rewind failed, not looping.\n", pathname.c_str());
@@ -556,3 +527,49 @@ bool FFmpegCapture::process_queued_commands(AVFormatContext *format_ctx, const s
        }
        return false;
 }
+
+AVFrameWithDeleter FFmpegCapture::decode_frame(AVFormatContext *format_ctx, AVCodecContext *codec_ctx, const std::string &pathname, int video_stream_index, bool *error)
+{
+       *error = false;
+
+       // Read packets until we have a frame or there are none left.
+       bool frame_finished = false;
+       AVFrameWithDeleter frame = av_frame_alloc_unique();
+       bool eof = false;
+       do {
+               AVPacket pkt;
+               unique_ptr<AVPacket, decltype(av_packet_unref)*> pkt_cleanup(
+                       &pkt, av_packet_unref);
+               av_init_packet(&pkt);
+               pkt.data = nullptr;
+               pkt.size = 0;
+               if (av_read_frame(format_ctx, &pkt) == 0) {
+                       if (pkt.stream_index != video_stream_index) {
+                               // Ignore audio for now.
+                               continue;
+                       }
+                       if (avcodec_send_packet(codec_ctx, &pkt) < 0) {
+                               fprintf(stderr, "%s: Cannot send packet to codec.\n", pathname.c_str());
+                               *error = true;
+                               return AVFrameWithDeleter(nullptr);
+                       }
+               } else {
+                       eof = true;  // Or error, but ignore that for the time being.
+               }
+
+               int err = avcodec_receive_frame(codec_ctx, frame.get());
+               if (err == 0) {
+                       frame_finished = true;
+                       break;
+               } else if (err != AVERROR(EAGAIN)) {
+                       fprintf(stderr, "%s: Cannot receive frame from codec.\n", pathname.c_str());
+                       *error = true;
+                       return AVFrameWithDeleter(nullptr);
+               }
+       } while (!eof);
+
+       if (frame_finished)
+               return frame;
+       else
+               return AVFrameWithDeleter(nullptr);
+}
index cde99c497fd596a4e7768dc51adce45ec1e3c6b6..619266de9e74921adf2e0e8565319ca1cba63ec0 100644 (file)
@@ -31,6 +31,7 @@
 #include <movit/ycbcr.h>
 
 #include "bmusb/bmusb.h"
+#include "ffmpeg_raii.h"
 #include "quittable_sleeper.h"
 
 struct AVFormatContext;
@@ -155,6 +156,9 @@ private:
        // Returns true if there was an error.
        bool process_queued_commands(AVFormatContext *format_ctx, const std::string &pathname, timespec last_modified);
 
+       // Returns nullptr if no frame was decoded (e.g. EOF).
+       AVFrameWithDeleter decode_frame(AVFormatContext *format_ctx, AVCodecContext *codec_ctx, const std::string &pathname, int video_stream_index, bool *error);
+
        std::string description, filename;
        uint16_t timecode = 0;
        unsigned width, height;