From 8730da4b4320e914022b745183379993e519f764 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 8 Aug 2019 14:02:12 +1000 Subject: [PATCH] improved decoder documentation and fixed error with >8bppc media --- app/decoder/ffmpeg/ffmpegdecoder.cpp | 21 ++++++---- app/decoder/ffmpeg/ffmpegdecoder.h | 61 +++++++++++++++++++++++++++- app/node/input/media/media.cpp | 6 ++- 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/app/decoder/ffmpeg/ffmpegdecoder.cpp b/app/decoder/ffmpeg/ffmpegdecoder.cpp index b023d6a54..01e11012b 100644 --- a/app/decoder/ffmpeg/ffmpegdecoder.cpp +++ b/app/decoder/ffmpeg/ffmpegdecoder.cpp @@ -61,7 +61,7 @@ bool FFmpegDecoder::Open() // Handle format context error if (error_code != 0) { - FFmpegErr(error_code); + FFmpegError(error_code); return false; } @@ -70,7 +70,7 @@ bool FFmpegDecoder::Open() // Handle get stream information error if (error_code < 0) { - FFmpegErr(error_code); + FFmpegError(error_code); return false; } @@ -102,7 +102,7 @@ bool FFmpegDecoder::Open() // Handle failure to copy parameters if (error_code < 0) { - FFmpegErr(error_code); + FFmpegError(error_code); return false; } @@ -111,14 +111,14 @@ bool FFmpegDecoder::Open() // Handle failure to set multithreaded decoding if (error_code < 0) { - FFmpegErr(error_code); + FFmpegError(error_code); return false; } // Open codec error_code = avcodec_open2(codec_ctx_, codec, &opts_); if (error_code < 0) { - FFmpegErr(error_code); + FFmpegError(error_code); return false; } @@ -233,7 +233,7 @@ FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &lengt // Handle any errors received during the frame retrieve process if (ret < 0) { - qWarning() << tr("Failed to retrieve frame from FFmpeg decoder: %1").arg(ret); + FFmpegError(ret); return nullptr; } @@ -247,7 +247,7 @@ FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &lengt // Convert pixel format/linesize if necessary uint8_t* dst_data = frame_container->data(); - int dst_linesize = frame_container->width() * 4; + int dst_linesize = frame_container->width() * PixelService::BytesPerPixel(static_cast(output_fmt_)); // Perform pixel conversion sws_scale(scale_ctx_, @@ -309,6 +309,11 @@ void FFmpegDecoder::Close() bool FFmpegDecoder::Probe(Footage *f) { + if (open_) { + qWarning() << "Probe must be called while the Decoder is closed"; + return false; + } + // Variable for receiving errors from FFmpeg int error_code; @@ -404,7 +409,7 @@ bool FFmpegDecoder::Probe(Footage *f) return result; } -void FFmpegDecoder::FFmpegErr(int error_code) +void FFmpegDecoder::FFmpegError(int error_code) { char err[1024]; av_strerror(error_code, err, 1024); diff --git a/app/decoder/ffmpeg/ffmpegdecoder.h b/app/decoder/ffmpeg/ffmpegdecoder.h index 63e9d4066..e4b8b03f4 100644 --- a/app/decoder/ffmpeg/ffmpegdecoder.h +++ b/app/decoder/ffmpeg/ffmpegdecoder.h @@ -46,17 +46,76 @@ public: virtual void Close() override; private: - void FFmpegErr(int error_code); + /** + * @brief Handle an error + * + * Immediately closes the Decoder (freeing memory resources) and sends the string provided to the warning stream. + * As this function closes the Decoder, no further Decoder functions should be performed after this is called + * (unless the Decoder is opened again first). + */ void Error(const QString& s); + /** + * @brief Handle an FFmpeg error code + * + * Uses the FFmpeg API to retrieve a descriptive string for this error code and sends it to Error(). As such, this + * function also automatically closes the Decoder. + * + * @param error_code + */ + void FFmpegError(int error_code); + + /** + * @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_) + * + * @return + * + * An FFmpeg error code, or >= 0 on success + */ int GetFrame(); + /** + * @brief Create an index for this media + * + * Indexes are used to improve speed and reliability of imported media. Calling Retrieve() will automatically check + * for an index and create one if it doesn't exist. + * + * Indexing is slow so it's recommended to do it in a background thread. Index() must be called while the Decoder is + * open, and does not automatically call Open() and Close() the Decoder. The caller must call thse manually. + * + * FIXME: This should perhaps become a common function for the base Decoder class + */ void Index(); + + /** + * @brief Returns the filename for the index + * + * Retrieves the absolute filename of the index file for this stream. Decoder must be open for this to work correctly. + * + * @return + */ QString GetIndexFilename(); + /** + * @brief Used internally to load a frame index into frame_index_ (video only) + * + * @return + * + * TRUE if a frame index was successfully loaded. FALSE usually means the file didn't exist and Index() should be + * run to create it. + */ bool LoadFrameIndex(); + + /** + * @brief Used in Index() to save the just created frame index to a file that can be loaded later + */ void SaveFrameIndex(); + /** + * @brief Returns an AVPixelFormat that can be + * @param pix_fmt + * @return + */ AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt); AVFormatContext* fmt_ctx_; diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index e8a8c982c..be101a03f 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -106,7 +106,11 @@ void MediaInput::Process(const rational &time) if (tex_buf_.IsCreated()) { tex_buf_.Upload(frame->data()); } else { - tex_buf_.Create(QOpenGLContext::currentContext(), static_cast(frame->format()), frame->width(), frame->height(), frame->data()); + tex_buf_.Create(QOpenGLContext::currentContext(), + static_cast(frame->format()), + frame->width(), + frame->height(), + frame->data()); } texture_output_->set_value(tex_buf_.texture());