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

_______________________________________________
Libav-user mailing list
[email protected]
http://ffmpeg.org/mailman/listinfo/libav-user

Reply via email to