Windows 7 64 bit environment. C# Windows Forms application calling FFmpeg libraries through C++ bridge DLL including avcodec-57.dll, avformat-57.dll, avutil-55.dll, swresample-2.dll and swscale-4.dll to write MPEG-4 file using H.264/MPEG-4 AVC codec. When writing a single MP4 file, never a problem. When writing multiple MP4 files concurrently, via multiple C# threads, occasionally get av_interleaved_write_frame failure -22 which is invalid parameter on one or two but never all files. Needless to say, the parameters never change. Does FFmpeg use temporary files? Is it possible that there is a fratricidal effect when using the same DLLs to write multiple files concurrently? Edit: placed mutex at entry/exit to my write frame function, see source below, and can no longer reproduce the problem. It would appear something about FFmpeg is not thread-safe.
extern "C" __declspec(dllexport) int ffmpeg_write_video_frame(FFMPEG_CONTEXT *ffmpegContext, uint8_t *frameBuffer)
{
#ifdef SINGLE_THREAD
WaitForSingleObject(hMutex, INFINITE);
#endif
AVFrame *frame = ffmpeg_get_video_frame(&ffmpegContext->video, frameBuffer);
if (frame == NULL)
{
MessageBox(GetActiveWindow(), "ffmpeg_get_video_frame returned NULL", "ffmpeg_write_video_frame", MB_OK);
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return(-1);
}
AVPacket pkt = { 0 };
av_init_packet(&pkt);
// encode the image
int got_packet = 0;
int result = avcodec_encode_video2(ffmpegContext->video.avCodecContext, &pkt, frame, &got_packet);
if (result < 0)
{
char text[256];
sprintf_s(text, sizeof(text), "avcodec_encode_videos failure=%d", result);
MessageBox(GetActiveWindow(), text, "ffmpeg_write_video_frame", MB_OK);
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return(result);
}
// if the encoder has produced an output packet
if (got_packet)
{
result = ffmpeg_write_frame(ffmpegContext->avFormatContext, &ffmpegContext->video.avCodecContext->time_base, ffmpegContext->video.avStream, &pkt);
if (result < 0)
{
char text[256];
sprintf_s(text, sizeof(text), "ffmpeg_write_frame failure=%d", result);
MessageBox(GetActiveWindow(), text, "ffmpeg_write_video_frame", MB_OK);
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return(result);
}
}
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return (0);
}
extern "C" int ffmpeg_write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
/* rescale output packet timestamp values from codec to stream timebase */
av_packet_rescale_ts(pkt, *time_base, st->time_base);
pkt->stream_index = st->index;
/* Write the compressed frame to the media file. */
#if 0
log_packet(fmt_ctx, pkt);
#endif
int result = av_interleaved_write_frame(fmt_ctx, pkt);
if (result < 0)
{
char text[256];
sprintf_s(text, sizeof(text), "av_interleaved_write_frame failure=%d", result);
MessageBox(GetActiveWindow(), text, "ffmpeg_write_frame", MB_OK);
}
return(result);
}