skype的语音编码方案开源的组件是silk,越来越多的APP采用此方案,差了些资料,找到了对应的解码代码,共享下。
官方的解码示例:
int main( int argc, char* argv[] ) { unsigned long tottime, starttime; double filetime; size_t counter; SKP_int32 args, totPackets, i, k; SKP_int16 ret, len, tot_len; SKP_int16 nBytes; SKP_uint8 payload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES * ( MAX_LBRR_DELAY + 1 ) ]; SKP_uint8 *payloadEnd = NULL, *payloadToDec = NULL; SKP_uint8 FECpayload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES ], *payloadPtr; SKP_int16 nBytesFEC; SKP_int16 nBytesPerPacket[ MAX_LBRR_DELAY + 1 ], totBytes; SKP_int16 out[ ( ( FRAME_LENGTH_MS * MAX_API_FS_KHZ ) << 1 ) * MAX_INPUT_FRAMES ], *outPtr; char speechOutFileName[ 150 ], bitInFileName[ 150 ]; FILE *bitInFile, *speechOutFile; SKP_int32 packetSize_ms=0, API_Fs_Hz = 0; SKP_int32 decSizeBytes; void *psDec; SKP_float loss_prob; SKP_int32 frames, lost, quiet; SKP_SILK_SDK_DecControlStruct DecControl; if( argc < 3 ) { print_usage( argv ); exit( 0 ); } /* default settings */ quiet = 0; loss_prob = 0.0f; /* get arguments */ args = 1; strcpy( bitInFileName, argv[ args ] ); args++; strcpy( speechOutFileName, argv[ args ] ); args++; while( args < argc ) { if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) { sscanf( argv[ args + 1 ], "%f", &loss_prob ); args += 2; } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_API" ) == 0 ) { sscanf( argv[ args + 1 ], "%d", &API_Fs_Hz ); args += 2; } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-quiet" ) == 0 ) { quiet = 1; args++; } else { printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); print_usage( argv ); exit( 0 ); } } if( !quiet ) { printf("********** Silk Decoder (Fixed Point) v %s ********************\n", SKP_Silk_SDK_get_version()); printf("********** Compiled for %d bit cpu *******************************\n", (int)sizeof(void*) * 8 ); printf( "Input: %s\n", bitInFileName ); printf( "Output: %s\n", speechOutFileName ); } /* Open files */ bitInFile = fopen( bitInFileName, "rb" ); if( bitInFile == NULL ) { printf( "Error: could not open input file %s\n", bitInFileName ); exit( 0 ); } /* Check Silk header */ { char header_buf[ 50 ]; counter = fread( header_buf, sizeof( char ), strlen( "#!SILK_V3" ), bitInFile ); header_buf[ strlen( "#!SILK_V3" ) ] = '\0'; /* Terminate with a null character */ if( strcmp( header_buf, "#!SILK_V3" ) != 0 ) { /* Non-equal strings */ printf( "Error: Wrong Header %s\n", header_buf ); exit( 0 ); } } speechOutFile = fopen( speechOutFileName, "wb" ); if( speechOutFile == NULL ) { printf( "Error: could not open output file %s\n", speechOutFileName ); exit( 0 ); } /* Set the samplingrate that is requested for the output */ if( API_Fs_Hz == 0 ) { DecControl.API_sampleRate = 24000; } else { DecControl.API_sampleRate = API_Fs_Hz; } /* Initialize to one frame per packet, for proper concealment before first packet arrives */ DecControl.framesPerPacket = 1; /* Create decoder */ ret = SKP_Silk_SDK_Get_Decoder_Size( &decSizeBytes ); if( ret ) { printf( "\nSKP_Silk_SDK_Get_Decoder_Size returned %d", ret ); } psDec = malloc( decSizeBytes ); /* Reset decoder */ ret = SKP_Silk_SDK_InitDecoder( psDec ); if( ret ) { printf( "\nSKP_Silk_InitDecoder returned %d", ret ); } totPackets = 0; tottime = 0; payloadEnd = payload; /* Simulate the jitter buffer holding MAX_FEC_DELAY packets */ for( i = 0; i < MAX_LBRR_DELAY; i++ ) { /* Read payload size */ counter = fread( &nBytes, sizeof( SKP_int16 ), 1, bitInFile ); #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( &nBytes, 1 ); #endif /* Read payload */ counter = fread( payloadEnd, sizeof( SKP_uint8 ), nBytes, bitInFile ); if( ( SKP_int16 )counter < nBytes ) { break; } nBytesPerPacket[ i ] = nBytes; payloadEnd += nBytes; totPackets++; } while( 1 ) { /* Read payload size */ counter = fread( &nBytes, sizeof( SKP_int16 ), 1, bitInFile ); #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( &nBytes, 1 ); #endif if( nBytes < 0 || counter < 1 ) { break; } /* Read payload */ counter = fread( payloadEnd, sizeof( SKP_uint8 ), nBytes, bitInFile ); if( ( SKP_int16 )counter < nBytes ) { break; } /* Simulate losses */ rand_seed = SKP_RAND( rand_seed ); if( ( ( ( float )( ( rand_seed >> 16 ) + ( 1 << 15 ) ) ) / 65535.0f >= ( loss_prob / 100.0f ) ) && ( counter > 0 ) ) { nBytesPerPacket[ MAX_LBRR_DELAY ] = nBytes; payloadEnd += nBytes; } else { nBytesPerPacket[ MAX_LBRR_DELAY ] = 0; } if( nBytesPerPacket[ 0 ] == 0 ) { /* Indicate lost packet */ lost = 1; /* Packet loss. Search after FEC in next packets. Should be done in the jitter buffer */ payloadPtr = payload; for( i = 0; i < MAX_LBRR_DELAY; i++ ) { if( nBytesPerPacket[ i + 1 ] > 0 ) { starttime = GetHighResolutionTime(); SKP_Silk_SDK_search_for_LBRR( payloadPtr, nBytesPerPacket[ i + 1 ], ( i + 1 ), FECpayload, &nBytesFEC ); tottime += GetHighResolutionTime() - starttime; if( nBytesFEC > 0 ) { payloadToDec = FECpayload; nBytes = nBytesFEC; lost = 0; break; } } payloadPtr += nBytesPerPacket[ i + 1 ]; } } else { lost = 0; nBytes = nBytesPerPacket[ 0 ]; payloadToDec = payload; } /* Silk decoder */ outPtr = out; tot_len = 0; starttime = GetHighResolutionTime(); if( lost == 0 ) { /* No Loss: Decode all frames in the packet */ frames = 0; do { /* Decode 20 ms */ ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 0, payloadToDec, nBytes, outPtr, &len ); if( ret ) { printf( "\nSKP_Silk_SDK_Decode returned %d", ret ); } frames++; outPtr += len; tot_len += len; if( frames > MAX_INPUT_FRAMES ) { /* Hack for corrupt stream that could generate too many frames */ outPtr = out; tot_len = 0; frames = 0; } /* Until last 20 ms frame of packet has been decoded */ } while( DecControl.moreInternalDecoderFrames ); } else { /* Loss: Decode enough frames to cover one packet duration */ for( i = 0; i < DecControl.framesPerPacket; i++ ) { /* Generate 20 ms */ ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 1, payloadToDec, nBytes, outPtr, &len ); if( ret ) { printf( "\nSKP_Silk_Decode returned %d", ret ); } outPtr += len; tot_len += len; } } packetSize_ms = tot_len / ( DecControl.API_sampleRate / 1000 ); tottime += GetHighResolutionTime() - starttime; totPackets++; /* Write output to file */ #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( out, tot_len ); #endif fwrite( out, sizeof( SKP_int16 ), tot_len, speechOutFile ); /* Update buffer */ totBytes = 0; for( i = 0; i < MAX_LBRR_DELAY; i++ ) { totBytes += nBytesPerPacket[ i + 1 ]; } SKP_memmove( payload, &payload[ nBytesPerPacket[ 0 ] ], totBytes * sizeof( SKP_uint8 ) ); payloadEnd -= nBytesPerPacket[ 0 ]; SKP_memmove( nBytesPerPacket, &nBytesPerPacket[ 1 ], MAX_LBRR_DELAY * sizeof( SKP_int16 ) ); if( !quiet ) { fprintf( stderr, "\rPackets decoded: %d", totPackets ); } } /* Empty the recieve buffer */ for( k = 0; k < MAX_LBRR_DELAY; k++ ) { if( nBytesPerPacket[ 0 ] == 0 ) { /* Indicate lost packet */ lost = 1; /* Packet loss. Search after FEC in next packets. Should be done in the jitter buffer */ payloadPtr = payload; for( i = 0; i < MAX_LBRR_DELAY; i++ ) { if( nBytesPerPacket[ i + 1 ] > 0 ) { starttime = GetHighResolutionTime(); SKP_Silk_SDK_search_for_LBRR( payloadPtr, nBytesPerPacket[ i + 1 ], ( i + 1 ), FECpayload, &nBytesFEC ); tottime += GetHighResolutionTime() - starttime; if( nBytesFEC > 0 ) { payloadToDec = FECpayload; nBytes = nBytesFEC; lost = 0; break; } } payloadPtr += nBytesPerPacket[ i + 1 ]; } } else { lost = 0; nBytes = nBytesPerPacket[ 0 ]; payloadToDec = payload; } /* Silk decoder */ outPtr = out; tot_len = 0; starttime = GetHighResolutionTime(); if( lost == 0 ) { /* No loss: Decode all frames in the packet */ frames = 0; do { /* Decode 20 ms */ ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 0, payloadToDec, nBytes, outPtr, &len ); if( ret ) { printf( "\nSKP_Silk_SDK_Decode returned %d", ret ); } frames++; outPtr += len; tot_len += len; if( frames > MAX_INPUT_FRAMES ) { /* Hack for corrupt stream that could generate too many frames */ outPtr = out; tot_len = 0; frames = 0; } /* Until last 20 ms frame of packet has been decoded */ } while( DecControl.moreInternalDecoderFrames ); } else { /* Loss: Decode enough frames to cover one packet duration */ /* Generate 20 ms */ for( i = 0; i < DecControl.framesPerPacket; i++ ) { ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 1, payloadToDec, nBytes, outPtr, &len ); if( ret ) { printf( "\nSKP_Silk_Decode returned %d", ret ); } outPtr += len; tot_len += len; } } packetSize_ms = tot_len / ( DecControl.API_sampleRate / 1000 ); tottime += GetHighResolutionTime() - starttime; totPackets++; /* Write output to file */ #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( out, tot_len ); #endif fwrite( out, sizeof( SKP_int16 ), tot_len, speechOutFile ); /* Update Buffer */ totBytes = 0; for( i = 0; i < MAX_LBRR_DELAY; i++ ) { totBytes += nBytesPerPacket[ i + 1 ]; } SKP_memmove( payload, &payload[ nBytesPerPacket[ 0 ] ], totBytes * sizeof( SKP_uint8 ) ); payloadEnd -= nBytesPerPacket[ 0 ]; SKP_memmove( nBytesPerPacket, &nBytesPerPacket[ 1 ], MAX_LBRR_DELAY * sizeof( SKP_int16 ) ); if( !quiet ) { fprintf( stderr, "\rPackets decoded: %d", totPackets ); } } if( !quiet ) { printf( "\nDecoding Finished \n" ); } /* Free decoder */ free( psDec ); /* Close files */ fclose( speechOutFile ); fclose( bitInFile ); filetime = totPackets * 1e-3 * packetSize_ms; if( !quiet ) { printf("\nFile length: %.3f s", filetime); printf("\nTime for decoding: %.3f s (%.3f%% of realtime)", 1e-6 * tottime, 1e-4 * tottime / filetime); printf("\n\n"); } else { /* print time and % of realtime */ printf( "%.3f %.3f %d\n", 1e-6 * tottime, 1e-4 * tottime / filetime, totPackets ); } return 0; }
修修改改调整下即可使用,测试通过。
至于里面包含的头和lib可以直接google源码下载直接编译出来即可,太多了,比如https://github.com/Voxer/silk-arm-ios ,里面附带了VS工程,可以直接编译。
http://developer.skype.com/silk这个地址打开就跳到http://skype.gmw.cn/去了
VLC player 好像沒有SILK_V3 decoder.
我有一些微信voice message,用HexEditor打开,“.#!SILK_V3..”
真后悔年青时没好好学编码。。。