【问题标题】:EXC_BAD_ACCESS when calling avcodec_encode_video调用 avcodec_encode_video 时的 EXC_BAD_ACCESS
【发布时间】:2011-02-25 06:57:01
【问题描述】:

我有一个 Objective-C 类(尽管我不相信这是任何特定于 Obj-C 的),我正在使用它从一系列 CGImage 将视频写入磁盘。 (我在顶部用于获取像素数据的代码来自 Apple:http://developer.apple.com/mac/library/qa/qa2007/qa1509.html)。我成功地创建了编解码器和上下文——一切都很好,直到它到达 avcodec_encode_video,当我得到 EXC_BAD_ACCESS 时。我认为这应该是一个简单的解决方法,但我就是不知道哪里出错了。

为了简洁起见,我做了一些错误检查。 'c' 是一个成功创建的 AVCodecContext*。

-(void)addFrame:(CGImageRef)img
{
  CFDataRef bitmapData = CGDataProviderCopyData(CGImageGetDataProvider(img));
  long dataLength = CFDataGetLength(bitmapData);
  uint8_t* picture_buff = (uint8_t*)malloc(dataLength);
  CFDataGetBytes(bitmapData, CFRangeMake(0, dataLength), picture_buff);

  AVFrame *picture = avcodec_alloc_frame();
  avpicture_fill((AVPicture*)picture, picture_buff, c->pix_fmt, c->width, c->height);

  int outbuf_size = avpicture_get_size(c->pix_fmt, c->width, c->height);
  uint8_t *outbuf = (uint8_t*)av_malloc(outbuf_size);

  out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture); // ERROR occurs here
  printf("encoding frame %3d (size=%5d)\n", i, out_size);
  fwrite(outbuf, 1, out_size, f);

  CFRelease(bitmapData);
  free(picture_buff);
  free(outbuf);
  av_free(picture);
  i++;
}

我已经经历了几十次。这里有一些数字......

  1. 数据长度 = 408960
  2. picture_buff = 0x5c85000
  3. picture->data[0] = 0x5c85000 -- 我认为这意味着 avpicture_fill 有效...
  4. outbuf_size = 408960

然后我在 avcodec_encode_video 获得 EXC_BAD_ACCESS。不确定它是否相关,但大部分代码来自 api-example.c。我正在使用 XCode,在 Snow Leopard 上为 armv6/armv7 编译。

非常感谢您的帮助!

【问题讨论】:

  • 你解决过这个问题吗?

标签: iphone c objective-c ffmpeg libavcodec


【解决方案1】:

我这里没有足够的信息来指出确切的错误,但我认为问题在于输入图片包含的数据比 avcodec_encode_video() 预期的要少:

avpicture_fill() 只在 AVFrame 结构中设置一些指针和数值。它不复制任何东西,也不检查缓冲区是否足够大(它不能,因为缓冲区大小没有传递给它)。它做了这样的事情(从 ffmpeg 源代码复制):

    size = picture->linesize[0] * height;
    picture->data[0] = ptr;
    picture->data[1] = picture->data[0] + size;
    picture->data[2] = picture->data[1] + size2;
    picture->data[3] = picture->data[1] + size2 + size2;

请注意,宽度和高度是从变量“c”(我假设为 AVCodecContext)传递的,因此它可能大于输入帧的实际大小。

也有可能是宽/高不错,但是输入帧的像素格式和传给avpicture_fill()的不一样。 (请注意,像素格式也来自 AVCodecContext,可能与输入不同)。例如,如果 c->pix_fmt 是 RGBA 并且输入缓冲区是 YUV420 格式(或者,对于 iPhone,更可能是双平面 YCbCr),那么输入缓冲区的大小是 width*height*1.5,但 avpicture_fill() 期望宽*高*4的尺寸。

因此,检查输入/输出几何和像素格式应该会引导您找到错误的原因。如果它没有帮助,我建议你应该先尝试为 i386 编译。为 iPhone 正确编译 FFMPEG 是很棘手的。

【讨论】:

  • 非常感谢您的回答!就像测试一样,我将 picture_buff 放大了 10 倍,我得到了同样的错误。您复制的源需要一个 PIX_FMT_YUV420P(平面)图像,我假设这就是为什么它设置 4 个不同的指针 - 它指向每个通道的开头。我想我应该提到,在我的情况下, c->pix_fmt = PIX_FMT_RGB24 我也做了一个检查: if(CGImageGetWidth(img)!=c->width || CGImageGetHeight(img)!=c->height) { NSLog(@"帧与电影大小不匹配。跳过");返回; } 我还可以提供哪些其他信息来帮助您?
  • 或者——为了帮助我,我应该说:)
  • 好吧,那么我认为错误不在这里,而是在编解码器初始化代码中 - 这更难调试:(最有可能的是你没有在 AVCodecContext 中设置一些参数。你应该检查 avcodec.h 中的 cmets 以查看缺少的内容。如果它没有帮助,除了调试 ffmpeg 代码之外别无他法......(如果你犯了一个微不足道的错误,它实际上会有所帮助!)它是否在 avcodec_encode_video() ? 因为在那个函数中我只看到一件事会崩溃:如果 codecContext->codec 为 NULL(你调用了 av_register_all() 吗?)
  • 这是我不明白的。 avcodec_encode_video 应该将 'picture' 的编码版本放入 'outbuf' 中,对吗? 'picture' 是 408960 字节(已经被赋予了 picture_buff,它是用 dataLength 进行 malloc 的),而 outbuf 是 408960 字节(已经用 outbuf_size 进行了 malloc),那么错误的访问可能发生在哪里?我在这里忽略了哪一部分内存?
  • 我很确定你是对的。我现在直接从我用来解码视频的类中传递编解码器和上下文,它似乎正在工作。我在其他地方还有其他问题,但我会在解决后在这里发布。
【解决方案2】:

您正在编码的编解码器是否支持 RGB 颜色空间?在编码之前,您可能需要使用 libswscale 转换为 I420。你用的是什么编解码器?您可以在初始化编解码器上下文的位置发布代码吗?

【讨论】:

【解决方案3】:

RGBtoYUV420P 功能可能对您有所帮助。 http://www.mail-archive.com/libav-user@mplayerhq.hu/msg03956.html

【讨论】:

    猜你喜欢
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多