Assembly code snippets
Details
Title | MP3 information [bitrate/time/...] |
---|---|
Author | Thomas |
Submitted by: | Thomas |
Date added: | 2002-04-29 18:23:52 |
Date modified: | 2002-08-31 19:18:53 |
Comments
Parameters:
lpFilename: pointer to the filename of the MP3 to get info from
lpInfoStruct: pointer to an MP3INFO structure that will receive the info on return
This function scans the whole MP3 and calculates the bitrate, time and some other information.
MP3INFO STRUCT
fileSize: size of the MP3 file
fileLength: length of the file, in msecs
bitrate: bitrate in bits per second. This value can be negative, in that case the mp3 has a variable bitrate. The value is the average bitrate, negated.
frequency: frequency of the MP3, in Herz (44100, 22050 etc)
nFrames: number of MPEG frames. Note: do not rely on this value, it isn't always correct (yet).
MP3INFO ENDS
The procedure is optimized for size.
Returns:
false on failure, true otherwise
Snippet
;V1 layer 3 bitrates
bitrateTableV1 dw -1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1
;V2/2.5 layer 3 bitrates
bitrateTableV2 dw -1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1
samplerateTableV1 dw 44100,48000,32000
samplerateTableV2 dw 22050,24000,16000
samplerateTableV2_5 dw 11025,12000,8000
.code
MP3INFO STRUCT
fileSize dword ? ; in bytes
fileLength dword ? ; in miliseconds
bitrate sdword ? ; in bps. if negative:
; variable bitrate,bitrate=negated average
frequency dword ? ; in Hertz
nFrames dword ? ; number of MPEG frames.
; Note: do not rely on this value,
; it isn't always correct (yet).
MP3INFO ENDS
GetMP3Info proc uses esi edi ebx lpFilename:DWORD, lpInfoStruct:DWORD
LOCAL hFile:DWORD
LOCAL hMap:DWORD
LOCAL pMap:DWORD
LOCAL totalbitrate:DWORD
LOCAL srTablePtr:DWORD
xor ebx, ebx
mov hFile, ebx
mov hMap, ebx
mov pMap, ebx
mov edi, lpInfoStruct
push edi
or eax, -1
mov ecx, (sizeof MP3INFO) / 4
rep stosd
mov totalbitrate, ebx
assume edi:PTR MP3INFO
pop edi
mov [edi].nFrames, ebx
invoke CreateFile, lpFilename, GENERIC_READ, FILE_SHARE_READ,
ebx, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN OR FILE_FLAG_NO_BUFFERING, ebx
cmp eax, INVALID_HANDLE_VALUE
je _invalid
mov hFile, eax
invoke CreateFileMapping, eax, ebx, PAGE_READONLY, ebx,ebx,ebx
or eax, eax
jz _invalid
mov hMap, eax
invoke MapViewOfFile, eax, FILE_MAP_READ,ebx,ebx,ebx
or eax, eax
jz _invalid
mov pMap, eax
mov esi, eax
invoke GetFileSize, hFile, NULL
mov [edi].fileSize, eax
lea ebx, [eax+esi]
_gotonextframe:
; find first 8 bits of sync bits
cmp byte ptr [esi], 0FFh
je @F
inc esi
cmp esi, ebx
jb _gotonextframe
jmp _done
;possible first 8 sync bits found
@@:
inc esi
cmp esi, ebx
jae _done
mov al, [esi]
mov cl, al
and cl, 11100000b
cmp cl, 11100000b
jne _gotonextframe
inc esi
_frame_found:
mov cl, al
and cl, 00011110b
mov edx, offset bitrateTableV1
mov srTablePtr, offset samplerateTableV1
cmp cl, 00011010b ;MPEG v1, layer 3?
je _frame_continue
mov edx, offset bitrateTableV2
mov srTablePtr, offset samplerateTableV2
cmp cl, 00010010b ;MPEG v2, layer 3?
je _frame_continue
mov srTablePtr, offset samplerateTableV2_5
cmp cl, 00000010b ;MPEG v2.5, layer 3
jne _gotonextframe ;find next frame
PrintText "falling"
;fall through...
_frame_continue:
PrintText "---frame continue---"
mov eax, ebx
sub eax, esi
cmp eax, 2 ;at least 2 bytes readable?
jb _done
movzx eax, byte ptr [esi]
mov ecx, eax
shr al, 4
movsx eax, word ptr [edx][2*eax]
cmp eax, -1
je _gotonextframe
sub esi, 2 ;point back to start of frame, as framesize is added later
; eax is bitrate
add totalbitrate, eax
mov edx, [edi].bitrate
cmp edx, -1
jne _bitrate_already_set
mov [edi].bitrate, eax
jmp _fixed_bitrate_so_far
_bitrate_already_set:
cmp eax, edx ;current bitrate same as set bitrate?
je _fixed_bitrate_so_far
;variable bitrate
and [edi].bitrate, 0 ;set to zero indicating variable bitrate
;fall through...
_fixed_bitrate_so_far:
xor edx, edx ; init framesize to zero
shr ecx, 2
setc dl ;last bit shifted out is padding bit,
; if set increase framesize by one
and ecx, 3
cmp ecx, 3
jne @F
inc esi
cmp esi, ebx
jae _done
jmp _gotonextframe
@@:
shl ecx, 1
add ecx, srTablePtr
movzx ecx, word ptr [ecx]
mov [edi].frequency, ecx
;FrameSize = 144 * BitRate / SampleRate + Padding
; eax = bitrate(in kbps, needs to be converted to bps yet)
; ecx = sampleRate
; edx = padding
; framesize = 144 * eax / ecx + edx
push edx
mov edx, 144*1000
cmp srTablePtr, offset samplerateTableV1
je @F
mov edx, 72*1000
@@:
mul edx
div ecx
pop edx
add edx, eax
; edx is framesize now
add esi, edx
cmp esi, ebx
jae _done ; frame bigger than file, file is cut
inc [edi].nFrames
jmp _gotonextframe
_invalid:
xor eax, eax
jmp _exit
_done:
mov ebx, 1000
mov ecx, [edi].nFrames ;get number of frames
mov eax, [edi].bitrate ;get bitrate in kbps
mul ebx ;*1000, in bpsd
mov [edi].bitrate, eax ;set new bitrate, in bps
or eax, eax ;bitrate zero?
jnz _fixed_bitrate ;if not, fixed
mov eax, totalbitrate ;else, variable. get total (sum of all bitrates)
mul ebx ;multiple by 1000
or ecx, ecx ;no frames?
jz _invalid ;bye
div ecx ;divide by number of frames
neg eax ;negate, indicating a variable bitrate
mov [edi].bitrate, eax
_fixed_bitrate:
; 1152 = # of samples in one frame for layer 3 mpegs
mov ebx, 1152*1000
mov eax, [edi].nFrames
xor edx, edx
mul ebx
mov ebx, [edi].frequency
or ebx, ebx
jz _invalid
div ebx
mov [edi].fileLength, eax ;set filelengths, in msecs
;calculate time
;bitrate
assume edi:nothing
xor eax, eax
inc eax
_exit:
push eax
mov eax, pMap
or eax, eax
jz @F
invoke UnmapViewOfFile, eax
@@:
mov eax, hMap
or eax, eax
jz @F
invoke CloseHandle, eax
@@:
mov eax, hFile
or eax, eax
jz @F
invoke CloseHandle, eax
@@:
pop eax
ret
GetMP3Info endp