100 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
| // Copyright 2020 Google LLC
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #include <stddef.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "opus.h"
 | |
| #include "opus_multistream.h"
 | |
| 
 | |
| struct TocInfo {
 | |
|   opus_int32 frequency;  // in [Hz*1000]
 | |
|   int channels;          // number of channels; either 1 or 2
 | |
|   int frame_len_x2;      // in [ms*2]. x2 is to avoid float value of 2.5 ms
 | |
| };
 | |
| 
 | |
| void extractTocInfo(const uint8_t toc, struct TocInfo *const info) {
 | |
|   const int frame_lengths_x2[3][4] = {
 | |
|     {20, 40, 80, 120},
 | |
|     {20, 40, 20, 40},
 | |
|     {5, 10, 20, 40}
 | |
|   };
 | |
| 
 | |
|   info->channels = toc & 4 ? 2 : 1;
 | |
| 
 | |
|   const uint8_t config = toc >> 3;
 | |
| 
 | |
|   int len_index;
 | |
|   if (config < 12) {
 | |
|     len_index = 0;
 | |
|   } else if (config < 16) {
 | |
|     len_index = 1;
 | |
|   } else {
 | |
|     len_index = 2;
 | |
|   }
 | |
|   info->frame_len_x2 = frame_lengths_x2[len_index][config & 3];
 | |
| 
 | |
|   switch (config >> 2) {
 | |
|     case 0: info->frequency = 8; break;
 | |
|     case 1: info->frequency = 12; break;
 | |
|     case 2: info->frequency = 16; break;
 | |
|     case 3: info->frequency = (config < 14) ? 24 : 48; break;
 | |
|     case 4: info->frequency = 8; break;
 | |
|     case 5: info->frequency = 16; break;
 | |
|     case 6: info->frequency = 24; break;
 | |
|     default: info->frequency = 48; break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 | |
|   if (size < 3 || size > 1000000) return 0;
 | |
| 
 | |
|   // Using last byte as a number of streams (instead of rand_r). Each stream
 | |
|   // should be at least 3 bytes long hence divmod.
 | |
|   int streams = 1 + data[size - 1] % (size / 3);
 | |
|   if (streams > 255) streams = 255;
 | |
|   unsigned char *mapping = (unsigned char*) malloc(sizeof(unsigned char)*streams);
 | |
|   if (!mapping) return 0;
 | |
| 
 | |
|   for (int i = 0; i < streams; ++i) {
 | |
|     mapping[i] = i;
 | |
|   }
 | |
| 
 | |
|   struct TocInfo info;
 | |
|   extractTocInfo(*data, &info);
 | |
| 
 | |
|   int error = 0;
 | |
|   OpusMSDecoder *const decoder = opus_multistream_decoder_create(
 | |
|       info.frequency * 1000, streams, streams, 0, mapping, &error);
 | |
| 
 | |
|   if (!decoder || error) return 0;
 | |
| 
 | |
|   const int frame_size = (info.frequency * info.frame_len_x2) / 2;
 | |
|   opus_int16 *pcm = (opus_int16*) malloc(sizeof(opus_int16)*frame_size*streams);
 | |
|   if (!pcm) goto exit;
 | |
| 
 | |
|   // opus_decode wants us to use its return value, but we don't really care.
 | |
|   const int foo =
 | |
|       opus_multistream_decode(decoder, data, size, pcm, frame_size, 0);
 | |
|   (void)foo;
 | |
| 
 | |
|   opus_multistream_decoder_destroy(decoder);
 | |
| 
 | |
|   free(pcm);
 | |
| 
 | |
| exit:
 | |
|   free(mapping);
 | |
|   return 0;
 | |
| }
 |