]> git.sesse.net Git - nageru/commitdiff
More refactoring in FFmpegCapture.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 May 2017 14:43:27 +0000 (16:43 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 28 May 2017 14:43:27 +0000 (16:43 +0200)
ffmpeg_capture.cpp
ffmpeg_capture.h
ffmpeg_raii.cpp
ffmpeg_raii.h

index 305a4d706fbcf6f70686d7439216f10c3580b3df..7ff8226de4900b10be564f5ec85813010533d417 100644 (file)
@@ -371,10 +371,6 @@ bool FFmpegCapture::play_video(const string &pathname)
 
        internal_rewind();
 
-       unique_ptr<SwsContext, decltype(sws_freeContext)*> sws_ctx(nullptr, sws_freeContext);
-       int sws_last_width = -1, sws_last_height = -1, sws_last_src_format = -1;
-       AVPixelFormat sws_dst_format = AVPixelFormat(-1);  // In practice, always initialized.
-
        // Main loop.
        while (!producer_thread_should_quit.should_quit()) {
                if (process_queued_commands(format_ctx.get(), pathname, last_modified)) {
@@ -402,77 +398,12 @@ bool FFmpegCapture::play_video(const string &pathname)
                        internal_rewind();
                        continue;
                }
-
-               if (sws_ctx == nullptr ||
-                   sws_last_width != frame->width ||
-                   sws_last_height != frame->height ||
-                   sws_last_src_format != frame->format) {
-                       sws_dst_format = decide_dst_format(AVPixelFormat(frame->format), pixel_format);
-                       sws_ctx.reset(
-                               sws_getContext(frame->width, frame->height, AVPixelFormat(frame->format),
-                                       width, height, sws_dst_format,
-                                       SWS_BICUBIC, nullptr, nullptr, nullptr));
-                       sws_last_width = frame->width;
-                       sws_last_height = frame->height;
-                       sws_last_src_format = frame->format;
-               }
-               if (sws_ctx == nullptr) {
-                       fprintf(stderr, "%s: Could not create scaler context\n", pathname.c_str());
-                       return false;
-               }
-
-               VideoFormat video_format;
-               video_format.width = width;
-               video_format.height = height;
-               if (pixel_format == bmusb::PixelFormat_8BitBGRA) {
-                       video_format.stride = width * 4;
-               } else {
-                       assert(pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar);
-                       video_format.stride = width;
-               }
-               video_format.frame_rate_nom = video_timebase.den;
-               video_format.frame_rate_den = av_frame_get_pkt_duration(frame.get()) * video_timebase.num;
-               if (video_format.frame_rate_nom == 0 || video_format.frame_rate_den == 0) {
-                       // Invalid frame rate.
-                       video_format.frame_rate_nom = 60;
-                       video_format.frame_rate_den = 1;
-               }
-               video_format.has_signal = true;
-               video_format.is_connected = true;
-
-               next_frame_start = compute_frame_start(frame->pts, pts_origin, video_timebase, start, rate);
                last_pts = frame->pts;
 
-               FrameAllocator::Frame video_frame = video_frame_allocator->alloc_frame();
-               if (video_frame.data != nullptr) {
-                       uint8_t *pic_data[4] = { nullptr, nullptr, nullptr, nullptr };
-                       int linesizes[4] = { 0, 0, 0, 0 };
-                       if (pixel_format == bmusb::PixelFormat_8BitBGRA) {
-                               pic_data[0] = video_frame.data;
-                               linesizes[0] = video_format.stride;
-                               video_frame.len = video_format.stride * height;
-                       } else {
-                               assert(pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar);
-                               const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(sws_dst_format);
-
-                               int chroma_width = AV_CEIL_RSHIFT(int(width), desc->log2_chroma_w);
-                               int chroma_height = AV_CEIL_RSHIFT(int(height), desc->log2_chroma_h);
-
-                               pic_data[0] = video_frame.data;
-                               linesizes[0] = width;
-
-                               pic_data[1] = pic_data[0] + width * height;
-                               linesizes[1] = chroma_width;
-
-                               pic_data[2] = pic_data[1] + chroma_width * chroma_height;
-                               linesizes[2] = chroma_width;
-
-                               video_frame.len = width * height + 2 * chroma_width * chroma_height;
-
-                               current_frame_ycbcr_format = decode_ycbcr_format(desc, frame.get());
-                       }
-                       sws_scale(sws_ctx.get(), frame->data, frame->linesize, 0, frame->height, pic_data, linesizes);
-                       video_frame.received_timestamp = next_frame_start;
+               VideoFormat video_format = construct_video_format(frame.get(), video_timebase);
+               FrameAllocator::Frame video_frame = make_video_frame(frame.get(), pathname, &error);
+               if (error) {
+                       return false;
                }
 
                FrameAllocator::Frame audio_frame;
@@ -480,6 +411,8 @@ bool FFmpegCapture::play_video(const string &pathname)
                 audio_format.bits_per_sample = 32;
                 audio_format.num_channels = 8;
 
+               next_frame_start = compute_frame_start(frame->pts, pts_origin, video_timebase, start, rate);
+               video_frame.received_timestamp = next_frame_start;
                producer_thread_should_quit.sleep_until(next_frame_start);
                frame_callback(timecode++,
                        video_frame, 0, video_format,
@@ -573,3 +506,85 @@ AVFrameWithDeleter FFmpegCapture::decode_frame(AVFormatContext *format_ctx, AVCo
        else
                return AVFrameWithDeleter(nullptr);
 }
+
+VideoFormat FFmpegCapture::construct_video_format(const AVFrame *frame, AVRational video_timebase)
+{
+       VideoFormat video_format;
+       video_format.width = width;
+       video_format.height = height;
+       if (pixel_format == bmusb::PixelFormat_8BitBGRA) {
+               video_format.stride = width * 4;
+       } else {
+               assert(pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar);
+               video_format.stride = width;
+       }
+       video_format.frame_rate_nom = video_timebase.den;
+       video_format.frame_rate_den = av_frame_get_pkt_duration(frame) * video_timebase.num;
+       if (video_format.frame_rate_nom == 0 || video_format.frame_rate_den == 0) {
+               // Invalid frame rate.
+               video_format.frame_rate_nom = 60;
+               video_format.frame_rate_den = 1;
+       }
+       video_format.has_signal = true;
+       video_format.is_connected = true;
+       return video_format;
+}
+
+FrameAllocator::Frame FFmpegCapture::make_video_frame(const AVFrame *frame, const string &pathname, bool *error)
+{
+       *error = false;
+
+       FrameAllocator::Frame video_frame = video_frame_allocator->alloc_frame();
+       if (video_frame.data == nullptr) {
+               return video_frame;
+       }
+
+       if (sws_ctx == nullptr ||
+           sws_last_width != frame->width ||
+           sws_last_height != frame->height ||
+           sws_last_src_format != frame->format) {
+               sws_dst_format = decide_dst_format(AVPixelFormat(frame->format), pixel_format);
+               sws_ctx.reset(
+                       sws_getContext(frame->width, frame->height, AVPixelFormat(frame->format),
+                               width, height, sws_dst_format,
+                               SWS_BICUBIC, nullptr, nullptr, nullptr));
+               sws_last_width = frame->width;
+               sws_last_height = frame->height;
+               sws_last_src_format = frame->format;
+       }
+       if (sws_ctx == nullptr) {
+               fprintf(stderr, "%s: Could not create scaler context\n", pathname.c_str());
+               *error = true;
+               return video_frame;
+       }
+
+       uint8_t *pic_data[4] = { nullptr, nullptr, nullptr, nullptr };
+       int linesizes[4] = { 0, 0, 0, 0 };
+       if (pixel_format == bmusb::PixelFormat_8BitBGRA) {
+               pic_data[0] = video_frame.data;
+               linesizes[0] = width * 4;
+               video_frame.len = (width * 4) * height;
+       } else {
+               assert(pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar);
+               const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(sws_dst_format);
+
+               int chroma_width = AV_CEIL_RSHIFT(int(width), desc->log2_chroma_w);
+               int chroma_height = AV_CEIL_RSHIFT(int(height), desc->log2_chroma_h);
+
+               pic_data[0] = video_frame.data;
+               linesizes[0] = width;
+
+               pic_data[1] = pic_data[0] + width * height;
+               linesizes[1] = chroma_width;
+
+               pic_data[2] = pic_data[1] + chroma_width * chroma_height;
+               linesizes[2] = chroma_width;
+
+               video_frame.len = width * height + 2 * chroma_width * chroma_height;
+
+               current_frame_ycbcr_format = decode_ycbcr_format(desc, frame);
+       }
+       sws_scale(sws_ctx.get(), frame->data, frame->linesize, 0, frame->height, pic_data, linesizes);
+
+       return video_frame;
+}
index 619266de9e74921adf2e0e8565319ca1cba63ec0..55eb8979632e62e65ca698dcd49e613c9f1be1ab 100644 (file)
 
 #include <movit/ycbcr.h>
 
+extern "C" {
+#include <libavutil/pixfmt.h>
+}
+
 #include "bmusb/bmusb.h"
 #include "ffmpeg_raii.h"
 #include "quittable_sleeper.h"
 
 struct AVFormatContext;
+struct AVFrame;
+struct AVRational;
 
 class FFmpegCapture : public bmusb::CaptureInterface
 {
@@ -159,6 +165,9 @@ private:
        // 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);
 
+       bmusb::VideoFormat construct_video_format(const AVFrame *frame, AVRational video_timebase);
+       bmusb::FrameAllocator::Frame make_video_frame(const AVFrame *frame, const std::string &pathname, bool *error);
+
        std::string description, filename;
        uint16_t timecode = 0;
        unsigned width, height;
@@ -178,6 +187,10 @@ private:
        std::unique_ptr<bmusb::FrameAllocator> owned_audio_frame_allocator;
        bmusb::frame_callback_t frame_callback = nullptr;
 
+       SwsContextWithDeleter sws_ctx;
+       int sws_last_width = -1, sws_last_height = -1, sws_last_src_format = -1;
+       AVPixelFormat sws_dst_format = AVPixelFormat(-1);  // In practice, always initialized.
+
        QuittableSleeper producer_thread_should_quit;
        std::thread producer_thread;
 
index b57de95124b18d2951263e489703592c2f0ae62a..a11075f81d0d8b84e6c17380e15c82683e476d41 100644 (file)
@@ -5,6 +5,7 @@ extern "C" {
 #include <libavformat/avformat.h>
 #include <libavutil/dict.h>
 #include <libavutil/frame.h>
+#include <libswscale/swscale.h>
 }
 
 using namespace std;
@@ -59,3 +60,9 @@ AVFrameWithDeleter av_frame_alloc_unique()
        return AVFrameWithDeleter(av_frame_alloc());
 }
 
+// SwsContext
+
+void sws_free_context_unique::operator() (SwsContext *context) const
+{
+       sws_freeContext(context);
+}
index 0b112345d59727ca83728e638135bb3a0ab41159..c0c4a47dc170aa954862eacaa56eb9326cb739d2 100644 (file)
@@ -18,7 +18,7 @@ struct AVDictionary;
 struct AVFormatContext;
 struct AVFrame;
 struct AVInputFormat;
-
+struct SwsContext;
 
 // AVFormatContext
 struct avformat_close_input_unique {
@@ -62,4 +62,12 @@ typedef std::unique_ptr<AVFrame, av_frame_free_unique>
 
 AVFrameWithDeleter av_frame_alloc_unique();
 
+// SwsContext
+struct sws_free_context_unique {
+       void operator() (SwsContext *context) const;
+};
+
+typedef std::unique_ptr<SwsContext, sws_free_context_unique>
+       SwsContextWithDeleter;
+
 #endif  // !defined(_FFMPEG_RAII_H)