swscaler 错误的 src 图像指针

2024-02-26

我完全迷路了。我正在尝试捕获 30 个屏幕截图并将它们放入视频中FFMPEG在 Windows 10 下。它一直告诉我[swscaler @ 073890a0] bad src image pointers。结果视频完全是绿色的。如果我将格式更改为dshow using video=screen-capture-recorder该视频看起来大部分都是垃圾。这是我的简短代码。我完全陷入困境,甚至不知道该往哪个方向看。

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFuture>
#include <QFutureWatcher>
#include <QMutex>
#include <QMutexLocker>

extern "C" {
#include "libavcodec/avcodec.h"
#include "libavcodec/avfft.h"

#include "libavdevice/avdevice.h"

#include "libavfilter/avfilter.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"

#include "libavformat/avformat.h"
#include "libavformat/avio.h"

#include "libavutil/opt.h"
#include "libavutil/common.h"
#include "libavutil/channel_layout.h"
#include "libavutil/imgutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/file.h"

#include "libswscale/swscale.h"
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    AVFormatContext *inputFormatContext = nullptr;
    AVFormatContext *outFormatContext = nullptr;

    AVStream* videoStream = nullptr;

    AVDictionary* options = nullptr;

    AVCodec* outCodec = nullptr;
    AVCodec* inputCodec = nullptr;
    AVCodecContext* inputCodecContext = nullptr;
    AVCodecContext* outCodecContext = nullptr;
    SwsContext* swsContext = nullptr;

private:
    void init();
    void initOutFile();
    void collectFrame();
};

#endif // MAINWINDOW_H

主窗口.cpp

#include "MainWindow.h"

#include <QGuiApplication>
#include <QLabel>
#include <QScreen>
#include <QTimer>
#include <QLayout>
#include <QImage>
#include <QtConcurrent/QtConcurrent>
#include <QThreadPool>

#include "ScreenCapture.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    resize(800, 600);

    auto label = new QLabel();
    label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);

    auto layout = new QHBoxLayout();
    layout->addWidget(label);

    auto widget = new QWidget();
    widget->setLayout(layout);
    setCentralWidget(widget);

    init();
    initOutFile();
    collectFrame();
}

MainWindow::~MainWindow()
{
    avformat_close_input(&inputFormatContext);
    avformat_free_context(inputFormatContext);

    QThreadPool::globalInstance()->waitForDone();
}

void MainWindow::init()
{
    av_register_all();
    avcodec_register_all();
    avdevice_register_all();
    avformat_network_init();

    auto screen = QGuiApplication::screens()[0];
    QRect geometry = screen->geometry();

    inputFormatContext = avformat_alloc_context();

    options = NULL;
    av_dict_set(&options, "framerate", "30", NULL);
    av_dict_set(&options, "offset_x", QString::number(geometry.x()).toLatin1().data(), NULL);
    av_dict_set(&options, "offset_y", QString::number(geometry.y()).toLatin1().data(), NULL);
    av_dict_set(&options, "video_size", QString(QString::number(geometry.width()) + "x" + QString::number(geometry.height())).toLatin1().data(), NULL);
    av_dict_set(&options, "show_region", "1", NULL);

    AVInputFormat* inputFormat = av_find_input_format("gdigrab");
    avformat_open_input(&inputFormatContext, "desktop", inputFormat, &options);

    int videoStreamIndex = av_find_best_stream(inputFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

    inputCodecContext = inputFormatContext->streams[videoStreamIndex]->codec;
    inputCodecContext->width = geometry.width();
    inputCodecContext->height = geometry.height();
    inputCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;

    inputCodec = avcodec_find_decoder(inputCodecContext->codec_id);
    avcodec_open2(inputCodecContext, inputCodec, NULL);
}

void MainWindow::initOutFile()
{
    const char* filename = "C:/Temp/output.mp4";

    avformat_alloc_output_context2(&outFormatContext, NULL, NULL, filename);

    outCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);

    videoStream = avformat_new_stream(outFormatContext, outCodec);
    videoStream->time_base = {1, 30};

    outCodecContext = videoStream->codec;
    outCodecContext->codec_id = AV_CODEC_ID_MPEG4;
    outCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
    outCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
    outCodecContext->bit_rate = 400000;
    outCodecContext->width = inputCodecContext->width;
    outCodecContext->height = inputCodecContext->height;
    outCodecContext->gop_size = 3;
    outCodecContext->max_b_frames = 2;
    outCodecContext->time_base = videoStream->time_base;

    if (outFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
        outCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    avcodec_open2(outCodecContext, outCodec, NULL);

    if (!(outFormatContext->flags & AVFMT_NOFILE))
        avio_open2(&outFormatContext->pb, filename, AVIO_FLAG_WRITE, NULL, NULL);

    swsContext = sws_getContext(inputCodecContext->width,
                                inputCodecContext->height,
                                inputCodecContext->pix_fmt,
                                outCodecContext->width,
                                outCodecContext->height,
                                outCodecContext->pix_fmt,
                                SWS_BICUBIC, NULL, NULL, NULL);

    avformat_write_header(outFormatContext, &options);
}

void MainWindow::collectFrame()
{
    AVFrame* frame = av_frame_alloc();
    frame->data[0] = NULL;
    frame->width = inputCodecContext->width;
    frame->height = inputCodecContext->height;
    frame->format = inputCodecContext->pix_fmt;

    av_image_alloc(frame->data, frame->linesize, inputCodecContext->width, inputCodecContext->height, (AVPixelFormat)frame->format, 32);

    AVFrame* outFrame = av_frame_alloc();
    outFrame->data[0] = NULL;
    outFrame->width = outCodecContext->width;
    outFrame->height = outCodecContext->height;
    outFrame->format = outCodecContext->pix_fmt;

    av_image_alloc(outFrame->data, outFrame->linesize, outCodecContext->width, outCodecContext->height, (AVPixelFormat)outFrame->format, 32);

    int bufferSize = av_image_get_buffer_size(outCodecContext->pix_fmt,
                                              outCodecContext->width,
                                              outCodecContext->height,
                                              24);

    uint8_t* outBuffer = (uint8_t*)av_malloc(bufferSize);

    avpicture_fill((AVPicture*)outFrame, outBuffer,
                   AV_PIX_FMT_YUV420P,
                   outCodecContext->width, outCodecContext->height);

    int frameCount = 30;
    int count = 0;

    AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
    av_init_packet(packet);

    while(av_read_frame(inputFormatContext, packet) >= 0)
    {
        if(packet->stream_index == videoStream->index)
        {
            int frameFinished = 0;
            avcodec_decode_video2(inputCodecContext, frame, &frameFinished, packet);

            if(frameFinished)
            {
                if(++count > frameCount)
                {
                    qDebug() << "FINISHED!";
                    break;
                }

                sws_scale(swsContext, frame->data, frame->linesize, 0, inputCodecContext->height, outFrame->data, outFrame->linesize);

                AVPacket outPacket;
                av_init_packet(&outPacket);
                outPacket.data = NULL;
                outPacket.size = 0;

                int got_picture = 0;
                avcodec_encode_video2(outCodecContext, &outPacket, outFrame, &got_picture);

                if(got_picture)
                {
                    if(outPacket.pts != AV_NOPTS_VALUE) outPacket.pts = av_rescale_q(outPacket.pts, videoStream->codec->time_base, videoStream->time_base);
                    if(outPacket.dts != AV_NOPTS_VALUE) outPacket.dts = av_rescale_q(outPacket.dts, videoStream->codec->time_base, videoStream->time_base);

                    av_write_frame(outFormatContext , &outPacket);
                }

                av_packet_unref(&outPacket);
            }
        }
    }

    av_write_trailer(outFormatContext);

    av_free(outBuffer);
}

我认为问题是你使用了一些不必要的代码和一些不推荐使用的函数,这些行是不必要的:

int bufferSize = av_image_get_buffer_size(outCodecContext->pix_fmt,
                                          outCodecContext->width,
                                          outCodecContext->height,
                                          24);
uint8_t* outBuffer = (uint8_t*)av_malloc(bufferSize);

avpicture_fill((AVPicture*)outFrame, outBuffer,
                AV_PIX_FMT_YUV420P,
                outCodecContext->width, outCodecContext->height);

这样做会破坏已经正常的帧,也会导致内存泄漏问题。因为您已经为 yuv420p 平面缓冲区分配了正确的空间av_image_alloc尽管您没有在失败时检查其返回代码。您可以保留缓冲区大小用于其他目的。哦,别忘了删除av_free(outBuffer) also.

这些应该被替换:

AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
av_init_packet(packet);

有了这个:

AVPacket *packet = av_packet_alloc(); // also inits to defaults
if (packet == NULL) {
    //hande error
}

其他的事情是,你的avcodec_decode_video2 and avcodec_encode_video2也已弃用,但应该仍然有效。最后根据我的经验av_interleaved_write_frame那么效果更好av_write_frame.

新的解码和编码 api 示例可以在这里找到:https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples

希望有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

swscaler 错误的 src 图像指针 的相关文章

  • 使用链表进行堆排序

    我想知道是否有人曾经使用链表进行堆排序 如果他们可以提供代码 我已经能够使用数组进行堆排序 但尝试在链表中进行排序似乎不切实际 而且在你知道的地方很痛苦 我必须为我正在做的项目实现链接列表 任何帮助将不胜感激 我也用C 答案是 你不想在链表
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • 捕获 .aspx 和 .ascx 页面中的异常

    问题说明了一切 请看以下示例代码 ul li li ul
  • 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争

    我有以下逻辑 public void InQueueTable DataTable Table int incomingRows Table Rows Count if incomingRows gt RowsThreshold async
  • 无法继承形状

    为什么我不能使用继承 a 的类Shapes class http msdn microsoft com en us library ms604615 28v vs 90 29 我需要延长Rectangle具有一些方法的类 但我想以与使用相同
  • Selenium - C# - Webdriver - 无法找到元素

    在 C 中使用 selenium 我试图打开浏览器 导航到 Google 并找到文本搜索字段 我尝试下面的 IWebDriver driver new InternetExplorerDriver C driver Navigate GoT
  • 防止控制台应用程序中的内存工作集最小化?

    我想防止控制台应用程序中的内存工作集最小化 在Windows应用程序中 我可以这样做覆盖 SC MINIMIZE 消息 http support microsoft com kb 293215 en us fr 1 但是 如何在控制台应用程
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • Linux 上的 RTLD_LOCAL 和dynamic_cast

    我们有一个由应用程序中的一些共享库构成的插件 我们需要在应用程序运行时更新它 出于性能原因 我们在卸载旧插件之前加载并开始使用新插件 并且只有当所有线程都使用旧插件完成后 我们才卸载它 由于新插件和旧插件的库具有相同的符号 我们dlopen
  • 来自嵌入图像的 BitmapSource

    我的目标是在 WPF 窗口上重写 OnRender 方法中绘制图像 someImage png 它是嵌入资源 protected override void OnRender System Windows Media DrawingCont
  • Unity c# 四元数:将 y 轴与 z 轴交换

    我需要旋转一个对象以相对于现实世界进行精确旋转 因此调用Input gyro attitude返回表示设备位置的四元数 另一方面 这迫使我根据这个四元数作为默认旋转来计算每个旋转 将某些对象设置为朝上的简单方法如下 Vector3 up I
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 我们可以通过指针来改变const定义的对象的值吗?

    include
  • SQLAPI++ 的免费替代品? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有任何免费 也许是开源 的替代品SQLAPI http www sqlapi com 这个库看起来
  • .NET 和 Mono 之间的开发差异

    我正在研究 Mono 和 NET C 将来当项目开发时我们需要在 Linux 服务器上运行代码 此时我一直在研究 ASP NET MVC 和 Mono 我运行 Ubuntu 发行版 想要开发 Web 应用程序 其他一些开发人员使用 Wind
  • 如何在C#中控制datagridview光标移动

    我希望 datagridview 光标向右移动到下一列 而不是在向单元格输入数据后移动到下一行 我试图通过 dataGridView1 KeyDown 事件捕获键来控制光标 但这并不能阻止光标在将数据输入到单元格后移动到下一行 提前感谢你的
  • 如何获取带有某个属性注释的所有属性?

    我刚刚从 Roslyn 开始 我想找到所有用属性名称 OneToOne 注释的属性 我启动了 SyntaxVisualizer 并能够获取对该节点的引用 但我想知道是否有更简单的方法来实现此目的 这就是我所拥有的 var prop docu
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助
  • 如何为有时异步的操作创建和实现接口

    假设我有数百个类 它们使用 计算 方法实现公共接口 一些类将执行异步 例如读取文件 而实现相同接口的其他类将执行同步代码 例如将两个数字相加 为了维护和性能 对此进行编码的好方法是什么 到目前为止我读到的帖子总是建议将异步 等待方法冒泡给调

随机推荐