avcodec_encode_video2 时出现分段错误

2023-12-01

我在尝试将 AVFrame 编码到数据包时遇到一些问题。

在阅读整个代码之前,输入的东西正在工作,我测试了它。输出内容来自示例here。我认为是有问题的。但分段错误发生在接近末尾的循环中。

这是我的简化代码:

void nmain() {

  // input stuff
  AVFormatContext *formatCtxIn=0;
  AVInputFormat *formatIn=0;
  AVCodecContext *codecCtxIn=0;
  AVCodec *codecIn;
  AVPacket *pktIn;

  av_register_all();
  avdevice_register_all();
  avcodec_register_all();


  formatIn = av_find_input_format("dshow");

  if(!formatIn)
    return;


  AVDictionary *avoption=0;
  av_dict_set(&avoption, "rtbufsize", "1000000000", NULL);

  if(avformat_open_input(&formatCtxIn, "video=Integrated Camera", formatIn, &avoption)!=0)
    return;

  if(avformat_find_stream_info(formatCtxIn, NULL)<0)
    return;

  codecCtxIn = formatCtxIn->streams[0]->codec;
  codecIn = avcodec_find_decoder(codecCtxIn->codec_id);

  if(avcodec_open2(codecCtxIn, codecIn, NULL)<0)
    return;


  // end input stuff  
//------------------------------------------------------------------------------
  // output stuff

  AVOutputFormat *formatOut=0;
  AVFormatContext *formatCtxOut=0;
  AVStream *streamOut=0;
  AVFrame *frame=0;
  AVCodec *codecOut=0;
  AVPacket *pktOut;

  const char *filename = "test.mpeg";

  formatOut = av_guess_format(NULL, filename, NULL);
  if(!formatOut)
    formatOut = av_guess_format("mpeg", NULL, NULL);
  if(!formatOut)
    return;

  formatCtxOut = avformat_alloc_context();
  if(!formatCtxOut)
    return;

  formatCtxOut->oformat = formatOut;

  sprintf(formatCtxOut->filename, "%s", filename);

  if(formatOut->video_codec != AV_CODEC_ID_NONE) {
    AVCodecContext *ctx;

    codecOut = avcodec_find_encoder(formatOut->video_codec);
    if(!codecOut)
      return;

    streamOut = avformat_new_stream(formatCtxOut, codecOut);
    if(!streamOut)
      return;

    ctx = streamOut->codec;

    ctx->bit_rate = 400000;
    ctx->width    = 352;
    ctx->height   = 288;
    ctx->time_base.den = 25;
    ctx->time_base.num = 1;
    ctx->gop_size      = 12;
    ctx->pix_fmt       = AV_PIX_FMT_YUV420P;

    if(ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
      ctx->max_b_frames = 2;
    if(ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
      ctx->mb_decision = 2;


    if(formatCtxOut->oformat->flags & AVFMT_GLOBALHEADER)
      ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
  }

  if(streamOut) {
    AVCodecContext *ctx;
    ctx = streamOut->codec;

    if(avcodec_open2(ctx, codecOut, NULL) < 0)
      return;
  }

  if(!(formatCtxOut->flags & AVFMT_NOFILE))
    if(avio_open(&formatCtxOut->pb, filename, AVIO_FLAG_WRITE) < 0)
      return;

  avformat_write_header(formatCtxOut, NULL);


  // doit

  pktIn = new AVPacket;
  pktOut = new AVPacket;
  av_init_packet(pktOut);
  pktOut->data = 0;

  frame = avcodec_alloc_frame();
  if(!frame)
    return;

  for(;;) {
    if(av_read_frame(formatCtxIn, pktIn) >= 0) {
      av_dup_packet(pktIn);

      int fff;
      if(avcodec_decode_video2(codecCtxIn, frame, &fff, pktIn) < 0)
        std::cout << "bad frame" << std::endl;

      if(!fff)
        return;  // ok

      static int counter=0;
      SaveFrame(frame, codecCtxIn->width, codecCtxIn->height, counter++);  // work fine

      // here a segmentation fault is occured.
      if(avcodec_encode_video2(streamOut->codec, pktOut, frame, &fff) < 0)
        std::cout << "bad frame" << std::endl;
    }
  }
}


// only for testing
// add to ensure frame is valid
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  FILE *pFile;
  char szFilename[32];
  int y;

  // Open file
  sprintf(szFilename, "frame%d.ppm", iFrame);
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
      return;

  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);

  // Write pixel data
  for(y=0; y<height; y++)
      fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

  // Close file
  fclose(pFile);
}

我究竟做错了什么?

调试时我没有发现参数有任何问题。streamOut->codec充满。pktOut被分配并且frame填充的是之前编码的图片。 我认为问题出在创建输出编解码器时,但观看示例并查看 doxypages 似乎是正确的。

test

跟踪路由来自使用 msvc11 和框架 5 的 QT。

我也尝试和博士一起跑步。记忆并得到这个:

Error #26: UNADDRESSABLE ACCESS: reading 0x00000000-0x00000004 4 byte(s)
# 0 replace_memcpy                      [d:\derek\drmemory\withwiki\trunk\drmemory\replace.c:203]
# 1 avcodec-54.dll!ff_dct_quantize_c   +0xd463   (0x6a482364 <avcodec-54.dll+0x3c2364>)
# 2 avcodec-54.dll!avcodec_encode_video2+0xb7     (0x6a56a5b8 <avcodec-54.dll+0x4aa5b8>)
# 3 nmain                               [d:\prg\tests\recording system-qt\libav\recsys\main.cpp:610]
# 4 main                                [d:\prg\tests\recording system-qt\libav\recsys\main.cpp:182]
Note: @0:00:06.318 in thread 5312
Note: instruction: mov    (%edx) -> %ebx

看来 memcpy 的读取过程出了问题。


Version:

我忘了提及我正在使用的 libav/ffmpeg 版本:

libavutil      51. 76.100 / 51. 76.100
libavcodec     54. 67.100 / 54. 67.100
libavformat    54. 33.100 / 54. 33.100
libavdevice    54.  3.100 / 54.  3.100
libavfilter     3. 19.103 /  3. 19.103
libswscale      2.  1.101 /  2.  1.101
libswresample   0. 16.100 /  0. 16.100
libpostproc    52.  1.100 / 52.  1.100

附录:

功能SafeFrame复制自教程1.


最后我解决了我的问题。

问题是(除了 libav 的文档)avpacket 不是数据包中图片的(真实)副本。它只是指向数据包的数据。你必须复制一份,或者最好让 libav 来做。

所以首先我为输出创建了一个新的 avframe 以及输出 avframe 指向的缓冲区。

AVFrame *outpic = avcodec_alloc_frame();
nbytes = avpicture_get_size(codecCtxOut->pix_fmt, codecCtxOut->width, codecCtxOut->height);
uint8_t* outbuffer = (uint8_t*)av_malloc(nbytes);

该缓冲区用于从输入到输出的转换。然后在循环中我必须用缓冲区填充outpic(avframe)。 我在代码中发现该函数正在用缓冲区填充平面指针。see here

avpicture_fill((AVPicture*)outpic, outbuffer, AV_PIX_FMT_YUV420P, codecCtxOut->width, codecCtxOut->height);

然后我使用将 inpic 转换为 outpicsws_scale。但首先您必须设置 swscontext。

SwsContext* swsCtx_ = sws_getContext(codecCtxIn->width, codecCtxIn->height,
                                     codecCtxIn->pix_fmt,
                                     codecCtxOut->width, codecCtxOut->height,
                                     codecCtxOut->pix_fmt,
                                     SWS_BICUBIC, NULL, NULL, NULL);

sws_scale(swsCtx_, inpic->data, inpic->linesize, 0, codecCtxIn->height, outpic->data, outpic->linesize);

然后您可以将 outpic 编码为 pktout(用于输出的 avpacket)。但首先要释放输出数据包,否则你会得到一个错误和泄漏......see here

av_free_packet(pktOut);

if(avcodec_encode_video2(streamOut->codec, pktOut, outpic, &fff) < 0) {
  std::cout << "shit frame" << std::endl;
  continue;
}
// and write it to the file
formatOut->write_packet(formatCtxOut, pktOut);

所以现在它对我来说很有效(几乎很好)。仍然是一个小内存泄漏,但我稍后可以发现。

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

avcodec_encode_video2 时出现分段错误 的相关文章

  • 如何向 UWP 项目添加 .NET dll 引用?

    我有几个适用于 NETv4 x 的 NET dll 项目 我将版本更改为 4 6 1 并重新构建 没有出现问题 当我尝试从 UWP 项目向它们添加引用时 出现错误 项目的目标是 NETCore 而文件引用的目标是 NET框架 这不是受支持的
  • 如何调试参数化 SQL 查询

    我使用 C 连接到数据库 然后使用 Ad hoc SQL 来获取数据 这个简单的 SQL 查询非常方便调试 因为我可以记录 SQL 查询字符串 如果我使用参数化 SQL 查询命令 有没有办法记录 sql 查询字符串以进行调试 我想就是这样的
  • 将 2D 数组映射到 1D 数组

    我想用一维数组来表示一个二维数组 函数将传递两个索引 x y 和要存储的值 这两个索引代表一维数组的单个元素 并相应地设置它 我知道一维数组需要具有 arrayWidth arrayHeight 的大小 但我不知道如何设置每个元素 例如 如
  • 测试 hdf5/c++ 中的组是否存在

    我正在打开一个现有的 HDF5 文件来附加数据 我想向那个叫做的小组保证 A存在以供后续访问 我正在寻找一种简单的方法来创建 A有条件地 如果不存在则创建并返回新组 或者返回现有组 一种方法是测试 A存在 我怎样才能高效地做到这一点 根据
  • 处理 LINQ sum 表达式中的 null

    我正在使用 LINQ 查询来查找列的总和 并且在少数情况下该值有可能为空 我现在使用的查询是 int score dbContext domainmaps Where p gt p SchoolId schoolid Sum v gt v
  • 浮点提升:stroustrup vs 编译器 - 谁是对的?

    在 Stroustrup 的新书 C 编程语言 第四版 第 10 5 1 节中 他说 在执行算术运算之前 整数提升用于从较短的整数类型创建整数 类似地 浮点提升是用于从浮点数创建双精度数 我用以下代码确认了第一个声明 include
  • Linq Where 本地计数器关闭在 VS watch 中的结果不同

    我尝试删除前 3 个元素array与 LinQWhere扩展功能 这是一个例子 var array new 1 2 3 4 5 6 7 8 9 var count 3 var deletedTest1 0 var test1 array W
  • 使用 VSTO 更改 Outlook 设置

    我刚刚花了大约 4 个小时试图弄清楚如何以编程方式检索 设置 Microsoft Outlook 2010 的 Outlook 设置 我所说的 设置 是指文件 选项 邮件下的设置 我想做的是检索用户设置的设置列表 自动化我们每天需要在某些消
  • 如何检测斑点并将其裁剪成 png 文件?

    我一直在开发一个网络应用程序 我陷入了一个有问题的问题 我会尝试解释我想要做什么 在这里您看到第一个大图像 其中有绿色形状 我想要做的是将这些形状裁剪成不同的 png 文件 并使它们的背景透明 就像大图像下面的示例裁剪图像一样 第一张图像将
  • C#:使用 System.Text 和 System.Text.RegularExpressions 之间的区别

    在 ASP NET C 应用程序中 我注意到为了使用 Regex 和 StringBuilder 我必须将两者都放在 using System Text using System Text RegularExpressions 从简单的角度
  • 推送 Lua 表

    我已经创建了一个Lua表C 但我不知道如何将该表推入堆栈顶部 以便我可以将其传递给 Lua 函数 有谁知道如何做到这一点 这是我当前的代码 lua createtable state libraries size 0 int table i
  • _mm_max_ss 在 clang 和 gcc 之间有不同的行为

    我正在尝试使用 clang 和 gcc 交叉编译一个项目 但在使用时发现一些奇怪的差异 mm max ss e g m128 a mm set ss std numeric limits
  • 在 C# 中赋值后如何保留有关对象的信息?

    我一直在问我的想法可能是解决方案 https stackoverflow com questions 35254467 is it possible in c sharp to get the attributes attached to
  • 为什么 C 函数不能返回数组类型?

    我是 C 语言新手 想知道 为什么 C 函数不能返回数组类型 我知道数组名是数组第一个值的地址 而数组是 C 中的二等公民 您自己已经回答了这个问题 数组是二等公民 C 按值返回 数组不能按值传递 因此不能返回它们 至于为什么数组不能按值传
  • 如何使用 Clang 查找内存泄漏

    我在我的机器 ubuntu 中安装了 Clang 以便发现我的 C 代码中的内存泄漏 我编写了一个示例代码来检查它的工作情况 如下所示 File hello c for leak detection include
  • 通过 MSBuild 调用 cl.exe 时无限期挂起

    我正在尝试在我的 主要是 C 项目上运行 MSBuild 想象一下一个非常庞大的代码库 Visual Studio 2015 是有问题的工具集 Windows 7 SP1 和 VS 2015 更新 2 即使使用 m 1 从而迫使它仅使用一个
  • 改进C++逐行读取文件的能力?

    我正在解析大约 500GB 的日志文件 我的 C 版本需要 3 5 分钟 我的 Go 版本需要 1 2 分钟 我正在使用 C 的流来流式传输文件的每一行以进行解析 include
  • 多个同名内存数据库

    关系到这个答案 https stackoverflow com a 48446491 596758 我试图通过设置让多个上下文工作UseInMemoryDatabase以同名 下面的测试失败 第二个上下文为空 我还需要做什么才能在内存数据库
  • 从 C# 中的 .NET SecureString 读取单个字符?

    WPF 的PasswordBox 返回一个SecureString 它对窥探者隐藏密码 问题是你最终必须获得密码的值 而我在网上找到的建议都涉及将值复制到字符串中 这会让你回到窥探者的问题 IntPtr bstr Marshal Secur
  • 如何仅更改 DateTime 的日期部分,同时保留时间部分?

    我在代码中使用了很多 DateTime 我想将这些日期时间更改为我的特定日期并保留 时间 1 2012 02 02 06 00 00 gt 2015 12 12 06 00 00 2 2013 02 02 12 00 00 gt 2015

随机推荐

  • Realm 数据库中的搜索操作速度

    这是我的模型RealmObject class public class ARDatabase extends RealmObject PrimaryKey private String uid private String namex p
  • 未捕获的类型错误:无法调用未定义的方法“hasChildNodes”

    我正在尝试使用 jquery 中的 ajax 请求读取 XML 下面是代码 它在 IE 中工作正常 但是当我在 Chrome 上运行它时 我遇到了这个错误 未捕获的类型错误 无法调用未定义的方法 hasChildNodes ajax typ
  • 如何从 querySelectorAll 获取所有元素并与 addEventListener 一起使用

    我有一个块 当我单击加号时 会创建 4 个子块 当我单击任何子块加号按钮时 我必须添加 rooms guests plus类 它们增加自0 to 5当单击减号按钮时 rooms guests minus类 以同样的方式减少 const ro
  • 在 Android 上运行模拟器时出错

    我正在尝试在 Android 上运行 PhoneGap 应用程序 当我运行命令时 phonegap run android emulator verbose 我收到这个错误 Running command getprop emu uuid
  • 具有连续分隔符的 strtok_s 行为

    我正在并行解析 3 个值 这些值用特定的分隔符分隔 token1 strtok s str1 separator nextToken1 token2 strtok s str2 separator nextToken2 token3 str
  • Python“使用错误的参数类型调用”错误

    我明白为什么我会收到此错误 它正在寻找我的对象作为参数 并接收字符串值 但我很困惑 不知道解决方案是什么 以下代码片段只是尝试运行此命令 self buttonGroup addButton self ui m001 x 次数 num 0
  • 如何在 Struts 2 中使用 DispatcherListener

    有一个界面DispatcherListener在Struts2中 文档说 一个接口来标记那些想要在init and destroy of a Dispatcher 但是这个接口怎么用呢 如果我创建一个实现这个接口的类 我应该如何将它配置到S
  • 我如何使用空手道测试以 AVRO 格式给出响应的其余端点?

    Karate 对于验证我们提供 json 响应的其余 api 非常有帮助 现在我们有了 api 它可以为我们提供 avro 格式的响应 可能还需要以 avro 格式发送有效负载 我如何使用空手道测试以 AVRO 格式给出响应的其余端点 有什
  • Python/Pandas:如果列有多个值,则转换为列表中具有多个值的单行

    在我的数据框中 我有很多相同的实例AutoNumber有不同的KeyValue String 我想将这些实例转换为单行 其中KeyValue String是由多个唯一值组成的列表 AutoNumber KeyValue String Ref
  • 如何连续向下滚动页面直到找到某个元素? Python 硒

    我对 Linkedin 技能部分的加载更多按钮感到困惑 我在查找按钮的 xpath 时收到此错误 selenium common exceptions NoSuchElementException Message no such eleme
  • xmlHttpRequest abort() 方法不会关闭 Internet Explorer 中的连接

    我有多个xmlHttpRequest在我的页面上 我正在尝试调用abort 对他们所有人的方法 在 FF 中效果很好 另一方面 IE 却没有做任何该死的事情 连接不会关闭 并且在请求完成之前我无法导航到另一个页面 这是什么 为什么 IE 不
  • 从 Angular 5 Universal 获取域名始终返回 127.0.0.1

    我在 Angular 5 应用程序的服务器端渲染方面遇到问题 我需要域来创建正确的链接 应用程序在不同的环境中使用 并且为每个端点创建几个包是个坏主意 所以我尝试使用堆栈中的选项 但我总是得到 127 0 0 1 4000 作为域 主机 我
  • 快速执行命令后获取终端输出

    我使用以下代码在终端中运行一些命令 system the command here 在我想知道运行这个命令的结果是什么之后 例如如果我跑 system git status 我想阅读有关我的存储库中更改的实际信息 有什么办法可以快速做到这一
  • 链表删除节点、简单链表

    我正在尝试实现一个从链表中删除节点的函数 到目前为止 我只能删除列表的第一个节点 3 我尝试从delete转到for循环 我以为内存没有分配好 我已经挣扎了几天 我不明白 请帮助我一点 这是我从大学收到的主题 include
  • 如何在 ASP.NET MVC 中禁用路由值的绑定?

    据我所知 ValueProviderDictionary 从 3 个地方获取绑定值 来自邮寄表格 来自路线值 来自查询字符串 我希望能够禁用第二个和第三个选项 我在这里看到的唯一解决方案是创建我自己的自定义 ValueProvider 复制
  • 网络浏览器打印

    Hi我正在使用 C WPF webbrowser 控件在本地计算机中显示 html 文件 我通过执行 webbrowser 控件的打印命令向我的应用程序添加了打印功能 但 Internet Explorer 的默认行为是在屏幕底部打印文件
  • ggplot2 PDF 输出中的 Unicode 字符

    如何在使用 ggplot2 创建的 PDF 绘图中使用 Unicode 字符作为标签 标题和类似内容 考虑以下示例 library ggplot2 qplot Sepal Length Petal Length data iris main
  • Python PyQT:如何从工作线程调用 GUI 函数?

    我有一个 pyqt gui 并调用一个长进程 ffmpeg 我将其放在一个单独的线程上以不阻塞 gui 然后 我想在较长命令列表中的一个命令完成时更新进度栏 问题是 我无法在工作线程之外调用 gui 线程中的函数 所以我让在工作线程中运行一
  • JCAPS 地狱小盒子

    Has anyone out there in SO land had to deal with this when you go to build a new deployment profile in JCAPS you have qu
  • avcodec_encode_video2 时出现分段错误

    我在尝试将 AVFrame 编码到数据包时遇到一些问题 在阅读整个代码之前 输入的东西正在工作 我测试了它 输出内容来自示例here 我认为是有问题的 但分段错误发生在接近末尾的循环中 这是我的简化代码 void nmain input s