[Libav-user] Intermittent heap crash with Visual Studio 2005

Rothkin, Steve (NY81) Steve.Rothkin at Honeywell.com
Tue May 21 21:52:57 CEST 2013


I followed the instructions at http://www.ffmpeg.org/platform.html#Crosscompilation-for-Windows-under-Cygwin to build FFMPEG windows DLLs for GPL2. I use the following commands in cygwin to configure and build it:

./configure --target-os=mingw32 --cross-prefix=i686-pc-mingw32-  --enable-shared --disable-static --extra-cflags=-mno-cygwin --extra-libs=-mno-cygwin --disable-programs --disable-doc  --disable-swresample --disable-postproc  --disable-zlib --disable-bzlib --disable-pthreads --disable-os2threads --enable-w32threads --arch=x86 --enable-runtime-cpudetect ; make ; make install

My program is currently built in Visual Studio 2005 (though I will move to 2012 once another team member finishes migrating our projects and getting them all to build correctly).

With just 1 or 2 threads it works fine most of the time (I'm using avformat to read various video clips, and convert/rescale to YUV420P which is what our processing module needs; I'm also using libavcodec to encode and decode JPEGs of single frames).

However, when I get more threads running (e.g. 5 videos being processed in parallel and JPEG frames being streamed to a viewer) I'm getting intermittent crashes in the DLLs. Often the crash is in the heap manager (e.g. mscvrt.dll!_malloc called from avutil-52.dll). Unfortunately, even disabling stripping of the output, Visual Studio doesn't tell me anything about locations within the DLLs (and Bounds Checker probably won't be much help for the same reason), and av_log_set_level(AV_LOG_DEBUG) didn't give me more info. Adding
 --assert-level=2  --enable-memory-poisoning  --enable-ftrapv --disable-stripping
to the configure command makes it crash faster/more often but still doesn't give me any "smoking guns".

I built from http://www.ffmpeg.org/releases/ffmpeg-1.2.1.tar.bz2, but I've also tried 1.2 and http://www.ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2 (last night's build). I had similar results with all 3.

I do have a lock manager registered with av_lockmgr_register(ffmpeg_lockmgr):

extern "C" static int ffmpeg_lockmgr(void **mtx, enum AVLockOp op)
{
    AE_ASSERT(mtx,"ffmpeg_lockmgr: NULL param");
    AE_ASSERT(*mtx || (op == AV_LOCK_CREATE),"ffmpeg_lockmgr: NULL *mtx");

    AE_Mutex *pMutex = (AE_Mutex *) *mtx;

    switch(op) {
    case AV_LOCK_CREATE:
        AE_CALLOC_CHECK_GOTO_VOID(pMutex,AE_Mutex,1);
        AE_CHECK_GOTO_VOID(ae_mutex_init(pMutex));
        *mtx = pMutex;
        return 0;
    case AV_LOCK_OBTAIN:
        AE_CHECK_GOTO_VOID(ae_mutex_lock(pMutex));
        return 0;
    case AV_LOCK_RELEASE:
        ae_mutex_release(pMutex);
        return 0;
    case AV_LOCK_DESTROY:
        ae_mutex_finish(pMutex);
        AE_CLEANUP(*mtx);
        return 0;
    default:
        ae_log(AE_LOG_ERROR,"ffmpeg_lockmgr: unrecognized op %d",op);
    }

error:
    return -1;
}

One thing I've noticed several times (but not every crash) is my lock manager getting called with an op value of 0xCCCCCCCC (the uninitialized variable value). I checked every place in the source code that calls the lock manager callback and hard-coded defines are always used for the op value, so I'm wondering if the calling convention is wrong and I need to add something (or maybe it is just a corruption of the stack backtrace displayed in Visual Studio since the lock manager seems to work fine most of the time and the program breaks quickly with a codec threading warning when I don't register the lock manager).

I also register my own log handler with av_log_set_callback(ffmpeg_log) to redirect the log (though commenting out the registration doesn't avoid the crash).

extern "C" static void ffmpeg_log(void *ptr, int level, const char *fmt, va_list vargs)
{
    int loglevel = av_log_get_level();
    if (level > loglevel)
        return;

    AE_LogType type;

    if (level <= AV_LOG_FATAL) {
        type = AE_LOG_FATAL;
    } else if (level <= AV_LOG_ERROR) {
        type = AE_LOG_ERROR;
    } else if (level <= AV_LOG_WARNING) {
        type = AE_LOG_WARNING;
    } else if (level <= AV_LOG_INFO) {
        type = AE_LOG_INFO;
    } else {
        type = AE_LOG_DEBUG;
    }

    char line[2048];
    static int print_prefix = 1;
    av_log_format_line(ptr, level, fmt, vargs, line, sizeof(line), &print_prefix);

    ae_log(type, "FFMPEG: %s",line);
}

I did find an old (2009) mention at http://japanesesoapbox.blogspot.com/2009/09/ffmpeg-and-mingw.html of some issue with vararg passing, but for the most part my log messages seem to come out correctly so maybe that issue was fixed in the last 4 years.

I tried building FFMPEG with Visual Studio 2012 following the instructions at http://www.ffmpeg.org/platform.html#Microsoft-Visual-C_002b_002b. In MSYS I was able to get the build to go most of the way through but it chokes on some PERL within the scripts/makefiles and I couldn't get past that without trying to debug those make files. Trying to build with Visual Studio in Cygwin doesn't work at all because I end up with clashes between the CL executables from cygwin and visual studio. And I had absolutely no luck at trying to natively compile ffmpeg within the visual studio 2012 IDE (due to the lack of C99 support).

The crash seems to be related to my use of the MJPEG codec to create JPEGs since it goes away if I turn off that code (JPEGging does work fine until it crashes). The JPEGging code (summary without the error handling) is:

    m_pCodec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
    m_pCodecCtx=avcodec_alloc_context3(m_pCodec);
    m_pCodecCtx->pix_fmt = m_targetPixelFormat = AV_PIX_FMT_YUVJ420P;
    m_pCodecCtx->color_range = AVCOL_RANGE_JPEG;
    av_init_packet(&m_packet);
    m_packet.data = NULL;
    m_packet.size = 0;
        m_pCodecCtx->width = m_targetWidth;
        m_pCodecCtx->height = m_targetHeight;
        m_pCodecCtx->time_base.num = 1;
        m_pCodecCtx->time_base.den = 1; // Arbitrary frame rate - 1 fps
avcodec_open2(m_pCodecCtx, m_pCodec,NULL);
        m_pFrame->pts = 0;
    if ((downscaleWidth > 1) || (downscaleHeight > 1))
    {
        // Point m_pFrame directly at data in pImg
        img.GetFfmpegArraysFromImage(m_pFrame->data,m_pFrame->linesize);
        m_pFrame->width  = pImg->size.width;
        m_pFrame->height = pImg->size.height;

        // Convert to target color model / size
        ConvertScaleImg(m_tmpImage2);

        // Now point at converted image
        img.m_pImage = pImg = m_tmpImage2;
    }

    // Finish setting up frame as source for JPEG
    img.GetFfmpegArraysFromImage(m_pFrame->data,m_pFrame->linesize);
    m_pFrame->format = AV_PIX_FMT_YUV420P;
    m_pFrame->width  = m_pCodecCtx->width;
    m_pFrame->height = m_pCodecCtx->height;

avcodec_encode_video2(m_pCodecCtx, &m_packet, m_pFrame, &got_output);

    // Copy JPEG to output buffer
    ae_memcpy(*jpgBuffer,m_packet.data,m_packet.size);
    *jpgSize = m_packet.size;

    av_free_packet(&m_packet);

void CAE_FfmpegCommon::ConvertScaleImg(CAE_FfmpegImage & outImg)
{
    // Get context for converting/scaling image. Reuses current one if possible.
    m_pSwsContext = sws_getCachedContext(m_pSwsContext,
        m_pFrame->width,m_pFrame->height,m_pCodecCtx->pix_fmt,
        m_targetWidth,m_targetHeight,m_targetPixelFormat,
        SWS_BILINEAR,NULL,NULL,NULL);

    /* Setup arrays with pointers to planes of destination image. */
    uint8_t *dst_data[FFMPEG_NUM_PLANES];
    int dst_linesize[FFMPEG_NUM_PLANES];
    outImg.GetFfmpegArraysFromImage(dst_data, dst_linesize);

    // convert to destination format
    sws_scale(m_pSwsContext, m_pFrame->data, m_pFrame->linesize, 0, m_pFrame->height,dst_data, dst_linesize);
}

void CAE_FfmpegImage::GetFfmpegArraysFromImage(uint8_t *pointers[FFMPEG_NUM_PLANES],
                                               int linesizes[FFMPEG_NUM_PLANES])
{
    for (int i=0;i<FFMPEG_NUM_PLANES;i++) {
        pointers[i] = m_pImage->pPlane[i].pPtr;
        linesizes[i] = m_pImage->pPlane[i].stride;
    }
}



Any suggestions for fixing this crash?

Thanks

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130521/b8f27792/attachment.html>


More information about the Libav-user mailing list