Part1: Overcome the ‘Access Violation Exception’ in the FFMPEG
It is painful when the ‘Access Violation Exception’ is thrown in the FFMPEG, because the debugging process is hard and boring. However, programmers must be faced with the challenge and get ride of this obstacle.
By VC IDE, this exception is caught and the information likes “Unhandled exception at 0x6b0dd484 in ffplay.exe: 0xC0000005: Access violation reading location 0xffffffff .” After clicking “Show Disassembly” button, the block of ASM codes is listed as below. The red sentence marked is the correct position leads to throw exception.
6B0DD47C shufps xmm5,xmm7,88h 6B0DD480 shufps xmm0,xmm7,0DDh 6B0DD484 movaps xmm7,xmmword ptr ds:[6B6CA4D8h] 6B0DD48B movaps xmm1,xmm4 6B0DD48E movaps xmm2,xmmword ptr ds:[6B6CA4E8h] 6B0DD495 movaps xmm3,xmm6 |
Obviously, the un-aligning address of memory raises the fault of movaps(SSE instruction) because ds equals zero in the runtime.
Herein, we have found the root cause, and the next step is how to locate the function including the above block of source codes. Ok, let’s go!
1) Find which module it belongs to.
Check ‘Call Stack’ in VC IDE, and the information likes
> avcodec-52.dll!6b0dd484() [Frames below may be incorrect and/or missing, no symbols loaded for avcodec-52.dll] avcodec-52.dll!6b0ddcb5() avcodec-52.dll!6b0ddce5() avcodec-52.dll!6b0ddd15() avcodec-52.dll!6b0ddf46() avcodec-52.dll!6b0df644() avcodec-52.dll!6adb5efc() kernel32.dll!7c810693() |
Great! It is avcodec-52 module.
2) Find which function it belongs to.
Disassembly the avcodec-52.dll, and find this block of source codes. The disassembly command is shown in the following content.
$ objdump.exe -m i386:intel -D ./avcodec-52.dll > avcodec-52.dll.asm |
After that, please search ‘6B6CA4D8 ’ string in the avcodec-52.dll.asm. It is easy to know the function is fft16_sse in the fft_mmx.asm(Line number is the 311th).
3) Design the bugfix.
Before designing the bugfix, we must analyze the building way in the FFMPEG.
a) *.asm is built by yasm
b) *.c is built by gcc
c) *.o is linked by gcc
As a result, which step does raise this issue?
No way, we must investigate them all!
Step 1) Investigate fft_mmx.o
After linkage | Before linkage |
movaps xmm7,xmmword ptr ds:[6B6CA4D8h] | movaps xmm7,XMMWORD PTR ds:0x0 |
No problems for fft_mmx.o. PASS !
Step 2) Investigate fft.c
DECLARE_ALIGNED_16(FFTSample, ff_cos_16[8]); DECLARE_ALIGNED_16(FFTSample, ff_cos_32[16]); DECLARE_ALIGNED_16(FFTSample, ff_cos_64[32]); DECLARE_ALIGNED_16(FFTSample, ff_cos_128[64]); DECLARE_ALIGNED_16(FFTSample, ff_cos_256[128]); DECLARE_ALIGNED_16(FFTSample, ff_cos_512[256]); DECLARE_ALIGNED_16(FFTSample, ff_cos_1024[512]); DECLARE_ALIGNED_16(FFTSample, ff_cos_2048[1024]); DECLARE_ALIGNED_16(FFTSample, ff_cos_4096[2048]); DECLARE_ALIGNED_16(FFTSample, ff_cos_8192[4096]); DECLARE_ALIGNED_16(FFTSample, ff_cos_16384[8192]); DECLARE_ALIGNED_16(FFTSample, ff_cos_32768[16384]); DECLARE_ALIGNED_16(FFTSample, ff_cos_65536[32768]); |
It is asked to align 16bytes. PASS !
Step 3) Investigate fft.o
00000800 C _ff_cos_1024 00000100 C _ff_cos_128 00000020 C _ff_cos_16 00008000 C _ff_cos_16384 00001000 C _ff_cos_2048 00000200 C _ff_cos_256 00000040 C _ff_cos_32 00010000 C _ff_cos_32768 00002000 C _ff_cos_4096 00000400 C _ff_cos_512 00000080 C _ff_cos_64 00020000 C _ff_cos_65536 00004000 C _ff_cos_8192 00000000 D _ff_cos_tabs |
Match the requirement. PASS !
Step 4) Investigate linker
$ nm ./avcodec-52.dll | egrep 'ff_cos' 6af87fb0 T _ff_cos 6b68c618 B _ff_cos_1024 6b6cc4f8 B _ff_cos_128 6b6ca4d8 B _ff_cos_16 6b68ce18 B _ff_cos_16384 6b694ed8 B _ff_cos_2048 6b6962d8 B _ff_cos_256 6b694e98 B _ff_cos_32 6b6964d8 B _ff_cos_32768 6b6ca4f8 B _ff_cos_4096 6b695ed8 B _ff_cos_512 6b694e18 B _ff_cos_64 6b6a64d8 B _ff_cos_65536 6b6c64d8 B _ff_cos_8192 6b223020 D _ff_cos_tabs |
WOW, it is here! FAIL !
It is a bug of linker of GCC! By searching bugs in the bugzilla of GCC, the #11203 describes this bug. O, My God!!!
How to do?!
As mentioned before, GCC and YASM build the related source codes respectively, and then link together. The issue is caused by the linker not caring the dependence among these *.o files. The simple train of thinking is how to build source codes by using same compiler. Ok, following the clue, let’s check the configure file of FFMPEG.
$ ./configure –help … --disable-neon disable neon optimizations --disable-vis disable VIS optimizations --disable-yasm disable use of yasm assembler … |
It is lucky, and ‘--disable-yasm ’ can handle this issue.
$ ./configure --enable-memalign-hack --enable-shared –disable-static –disable-yasm && make && make install |
For the detailed HOWTO, please refer to FFmpeg Understand(3. How to compile FFMPEG in Windows?) .
Ok, can you enjoy your video now: -) ?!
[Summerization]
1) It is an exploration to solve crash issue of FFMPEG, and the method can be referred for other cases.
2) The simple solution takes heavy performance side-effects. Only FFT module has un-aligning case, but others are implicated by disabling YASM.
3) The better solution should be probed later, and share them in the next articles.