Class: FilesHunter::Decoders::FLAC
- Inherits:
-
BeginPatternDecoder
- Object
- FilesHunter::Decoder
- BeginPatternDecoder
- FilesHunter::Decoders::FLAC
- Defined in:
- lib/fileshunter/Decoders/FLAC.rb,
ext/fileshunter/Decoders/_FLAC.c
Constant Summary collapse
- BEGIN_PATTERN_FLAC =
'fLaC'.force_encoding(Encoding::ASCII_8BIT)
Instance Method Summary collapse
- #decode(offset) ⇒ Object
-
#decode_rice(rb_cursor, rb_cursor_bits, rb_nbr_samples, rb_rice_parameter) ⇒ Object
Decode data at a given cursor and cursor_bits position as a given number of samples encoded in a Rice partition.
- #get_begin_pattern ⇒ Object
Methods inherited from BeginPatternDecoder
Methods inherited from FilesHunter::Decoder
Instance Method Details
#decode(offset) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/fileshunter/Decoders/FLAC.rb', line 15 def decode(offset) ending_offset = nil # Read all Metadata blocks cursor = offset+4 = false nbr_bits_per_sample_header = nil while (!) c = @data[cursor].ord = (c > 128) = (c & 127) invalid_data("@#{cursor} - Invalid Metadata type: #{c}") if ( > 6) if ( == 0) nbr_bits_per_sample_header = ((@data[cursor+16].ord & 1) << 4) + ((@data[cursor+17].ord & 240) >> 4) + 1 end = BinData::Uint24be.read(@data[cursor+1..cursor+3]) cursor += 4 + progress(cursor) end invalid_data("@#{offset} - Missing METADATA_BLOCK_STREAMINFO from headers") if (nbr_bits_per_sample_header == nil) found_relevant_data(:flac) ( :nbr_bits_per_sample_header => nbr_bits_per_sample_header ) # Read frames nbr_frames = 0 while (ending_offset == nil) log_debug "@#{cursor} - Reading new frame" # Check frame header header_bytes = @data[cursor..cursor+4].bytes.to_a if ((header_bytes[0] != 255) or ((header_bytes[1] & 254) != 248) or ((header_bytes[2] & 240) == 0) or ((header_bytes[2] & 15) == 15) or (header_bytes[3] >= 176) or ((header_bytes[3] & 14) == 6) or ((header_bytes[3] & 14) == 14) or (header_bytes[3].odd?)) if (nbr_frames == 0) invalid_data("@#{cursor} - Incorrect frame header") else log_debug "@#{cursor} - Incorrect frame header. Consider the file is finished." ending_offset = cursor end else utf8_number_size = get_utf8_size(header_bytes[4]) invalid_data("@#{cursor} - Incorrect UTF-8 size") if ((header_bytes[1].even?) and (utf8_number_size >= 7)) cursor += 4 + utf8_number_size block_size = 0 block_size_byte = ((header_bytes[2] & 240) >> 4) log_debug "@#{cursor} - block_size_byte=#{block_size_byte}" case block_size_byte when 1 block_size = 192 when 2..5 block_size = 576 * (2**(block_size_byte-2)) when 6 # Blocksize is coded here on 8 bits block_size = @data[cursor].ord + 1 cursor += 1 when 7 # Blocksize is coded here on 16 bits block_size = BinData::Uint16be.read(@data[cursor..cursor+1]) + 1 cursor += 2 else block_size = 256 * (2**(block_size_byte-8)) end case (header_bytes[2] & 15) when 12 # Sample rate is coded here on 8 bits cursor += 1 when 13, 14 # Sample rate is coded here on 16 bits cursor += 2 end cursor += 1 # CRC # Decode some values needed further nbr_channels = ((header_bytes[3] & 240) >> 4) + 1 # Channels encoding side (differences) always have +1 bit per sample bps_inc = nil case nbr_channels when 9, 11 bps_inc = [ 0, 1 ] when 10 bps_inc = [ 1, 0 ] else bps_inc = [ 0, 0 ] end nbr_channels = 2 if (nbr_channels > 8) nbr_bits_per_sample_frame_header = 0 case ((header_bytes[3] & 14) >> 1) when 0 nbr_bits_per_sample_frame_header = nbr_bits_per_sample_header when 1 nbr_bits_per_sample_frame_header = 8 when 2 nbr_bits_per_sample_frame_header = 12 when 4 nbr_bits_per_sample_frame_header = 16 when 5 nbr_bits_per_sample_frame_header = 20 when 6 nbr_bits_per_sample_frame_header = 24 end log_debug "@#{cursor} - block_size=#{block_size} nbr_channels=#{nbr_channels} nbr_bits_per_sample_frame_header=#{nbr_bits_per_sample_frame_header} bps_inc=#{bps_inc.inspect}" progress(cursor) # Here cursor is on the next byte after the frame header # We have nbr_channels subframes # !!! Starting from here, we have to track bits shifting cursor_bits = 0 nbr_channels.times do |idx_channel| nbr_bits_per_sample = nbr_bits_per_sample_frame_header + ((bps_inc[idx_channel] == nil) ? 0 : bps_inc[idx_channel]) log_debug "@#{cursor},#{cursor_bits} - Reading Subframe" nbr_encoded_partitions = 0 # Decode the sub-frame header sub_header_first_byte, cursor, cursor_bits = decode_bits(cursor, cursor_bits, 8) invalid_data("@#{cursor},#{cursor_bits} - Invalid Sub frame header: #{sub_header_first_byte}") if ((sub_header_first_byte > 127) or ((sub_header_first_byte & 124) == 4) or ((sub_header_first_byte & 240) == 8) or ((sub_header_first_byte & 96) == 32)) wasted_bits = 0 if (sub_header_first_byte.odd?) wasted_bits, cursor, cursor_bits = decode_unary(cursor, cursor_bits) end log_debug "@#{cursor},#{cursor_bits} - Found #{wasted_bits} wasted bits" cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, wasted_bits) # Now decode the Subframe itself if ((sub_header_first_byte & 126) == 0) # SUBFRAME_CONSTANT log_debug "@#{cursor},#{cursor_bits} - Found Subframe header SUBFRAME_CONSTANT" cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, nbr_bits_per_sample) elsif ((sub_header_first_byte & 126) == 1) # SUBFRAME_VERBATIM log_debug "@#{cursor},#{cursor_bits} - Found Subframe header SUBFRAME_VERBATIM" cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, nbr_bits_per_sample * block_size) elsif ((sub_header_first_byte & 112) == 16) # SUBFRAME_FIXED order = ((sub_header_first_byte & 14) >> 1) invalid_data("@#{cursor},#{cursor_bits} - Invalid SUBFRAME_FIXED") if (order > 4) log_debug "@#{cursor},#{cursor_bits} - Found Subframe header SUBFRAME_FIXED of order #{order}" cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, nbr_bits_per_sample * order) cursor, cursor_bits, nbr_encoded_partitions = decode_residual(cursor, cursor_bits, nbr_bits_per_sample, block_size, order, nbr_encoded_partitions) else # SUBFRAME_LPC lpc_order = ((sub_header_first_byte & 62) >> 1) + 1 log_debug "@#{cursor},#{cursor_bits} - Found Subframe header SUBFRAME_LPC of order #{lpc_order}" cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, nbr_bits_per_sample * lpc_order) qlpc_precision, cursor, cursor_bits = decode_bits(cursor, cursor_bits, 4) invalid_data("@#{cursor},#{cursor_bits} - Invalid qlpc_precision: #{qlpc_precision}") if (qlpc_precision == 15) qlpc_precision += 1 log_debug "@#{cursor},#{cursor_bits} - qlpc_precision=#{qlpc_precision}" # DEBUG only # qlpc_shift, cursor, cursor_bits = decode_bits(cursor, cursor_bits, 5) # qlpc_shift = -((qlpc_shift - 1) ^ 31) if ((qlpc_shift & 16) != 0) # log_debug "@#{cursor},#{cursor_bits} - qlpc_shift=#{qlpc_shift}" # lpc_order.times do |idx_coeff| # coeff, cursor, cursor_bits = decode_bits(cursor, cursor_bits, qlpc_precision) # # Negative value # coeff = -((coeff - 1) ^ ((1 << qlpc_precision) - 1)) if ((coeff & (1 << (qlpc_precision-1))) != 0) # log_debug "@#{cursor},#{cursor_bits} - qlpc_coeff[#{idx_coeff}]=#{coeff}" # end # NON DEBUG only cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, 5) cursor, cursor_bits = inc_cursor_bits(cursor, cursor_bits, qlpc_precision * lpc_order) cursor, cursor_bits, nbr_encoded_partitions = decode_residual(cursor, cursor_bits, nbr_bits_per_sample, block_size, lpc_order, nbr_encoded_partitions) end progress(cursor) end # We align back to byte cursor += 1 if (cursor_bits > 0) # Frame footer cursor += 2 progress(cursor) nbr_frames += 1 ending_offset = cursor if (cursor == @end_offset) end end ( :nbr_frames => nbr_frames ) return ending_offset end |
#decode_rice(rb_cursor, rb_cursor_bits, rb_nbr_samples, rb_rice_parameter) ⇒ Object
Decode data at a given cursor and cursor_bits position as a given number of samples encoded in a Rice partition
- Parameters
-
rb_self (FLAC): Self
-
rb_cursor (Fixnum): Current cursor
-
rb_cursor_bits (Fixnum): Current cursor_bits
-
rb_nbr_samples (Fixnum): Number of samples to decode
-
rb_rice_parameter (Fixnum): Rice parameter
- Return
-
Fixnum: New cursor
-
Fixnum: New cursor_bits
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'ext/fileshunter/Decoders/_FLAC.c', line 52
static VALUE flac_decode_rice(
VALUE rb_self,
VALUE rb_cursor,
VALUE rb_cursor_bits,
VALUE rb_nbr_samples,
VALUE rb_rice_parameter) {
// Translate Ruby objects
uint32_t cursor = FIX2INT(rb_cursor);
uint32_t cursor_bits = FIX2INT(rb_cursor_bits);
uint32_t nbr_samples = FIX2INT(rb_nbr_samples);
uint32_t rice_parameter = FIX2INT(rb_rice_parameter);
VALUE rb_data = rb_ivar_get(rb_self, rb_intern("@data"));
// Initialize the data stream
int last_data_block = 0;
uint8_t* str_cursor;
uint8_t* str_cursor_start;
uint8_t* str_cursor_end;
load_next_block(rb_self, rb_data, cursor, &str_cursor, &str_cursor_start, &str_cursor_end, &last_data_block);
// Temporary variables
uint8_t current_byte;
int found;
uint32_t bits_count;
uint32_t idx_sample;
#ifdef DEBUG
uint32_t high_part;
uint32_t low_part;
uint32_t remaining_bits_to_decode;
int32_t value;
uint32_t temp;
#endif
// Loop on samples
for (idx_sample = 0; idx_sample < nbr_samples; ++idx_sample) {
// cursor is the offset of str_cursor_start in the data stream.
// str_cursor, cursor_bits point to the data being decoded.
// str_cursor_start points to the beginning of the current data block
// str_cursor_end points to the end of the current data block
// last_data_block indicates if this is the last block
// 1. Decode next bits as a unary encoded number: this will be the high bits of the value
//printf("@%u,%u - 0 cursor=%u str_cursor=%u str_cursor_end=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, cursor, str_cursor-str_cursor_start, str_cursor_end-str_cursor_start);
#ifdef DEBUG
printf("@%u,%u - Reading %u\n", cursor+str_cursor-str_cursor_start, cursor_bits, *str_cursor);
high_part = 0;
#endif
found = 0;
if (cursor_bits > 0) {
// Consider ending bits of current byte
current_byte = *str_cursor;
while ((cursor_bits < 8) &&
((current_byte & (1 << (7-cursor_bits))) == 0)) {
++cursor_bits;
#ifdef DEBUG
++high_part;
#endif
}
if (cursor_bits == 8) {
// Not found in the current byte
++str_cursor;
} else {
// Found it
found = 1;
}
}
//printf("@%u,%u - 0.5 cursor=%u str_cursor=%u str_cursor_end=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, cursor, str_cursor-str_cursor_start, str_cursor_end-str_cursor_start);
if (!found) {
// Here we are byte-aligned
// str_cursor points on the byte we are starting to search from (can be at the end of our current block)
// cursor_bits has no significant value
// First check if we need to read an extra block
if (str_cursor == str_cursor_end) {
cursor += str_cursor - str_cursor_start;
load_next_block(rb_self, rb_data, cursor, &str_cursor, &str_cursor_start, &str_cursor_end, &last_data_block);
}
// Now we can continue our inspection
// Loop until we find a non-null byte
while (!found) {
while ((str_cursor != str_cursor_end) &&
((*str_cursor) == 0)) {
++str_cursor;
#ifdef DEBUG
high_part += 8;
#endif
}
if (str_cursor == str_cursor_end) {
cursor += str_cursor - str_cursor_start;
load_next_block(rb_self, rb_data, cursor, &str_cursor, &str_cursor_start, &str_cursor_end, &last_data_block);
} else {
found = 1;
}
}
//printf("@%u,%u - 0.8 cursor=%u str_cursor=%u str_cursor_end=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, cursor, str_cursor-str_cursor_start, str_cursor_end-str_cursor_start);
// Here, str_cursor points on the first non-null byte
current_byte = *str_cursor;
cursor_bits = 0;
while ((cursor_bits < 8) &&
((current_byte & (1 << (7-cursor_bits))) == 0)) {
++cursor_bits;
#ifdef DEBUG
++high_part;
#endif
}
}
// Here, str_cursor and cursor_bits point on the first bit set to 1
//printf("@%u,%u - 1 cursor=%u str_cursor=%u str_cursor_end=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, cursor, str_cursor-str_cursor_start, str_cursor_end-str_cursor_start);
// 2. Read the next rice_parameter bits: this will be the low bits of the value
#ifdef DEBUG
printf("@%u,%u - Got high part (%u). Now decode low value (%u bits)\n", cursor+str_cursor-str_cursor_start, cursor_bits, high_part, rice_parameter);
++cursor_bits;
if (cursor_bits == 8) {
cursor_bits = 0;
++str_cursor;
if (str_cursor == str_cursor_end) {
cursor += str_cursor - str_cursor_start;
load_next_block(rb_self, rb_data, cursor, &str_cursor, &str_cursor_start, &str_cursor_end, &last_data_block);
}
}
if (cursor_bits + rice_parameter <= 8) {
// The value can be decoded using current byte only
low_part = ((*str_cursor) & ((1 << (8-cursor_bits)) - 1)) >> (8-cursor_bits-rice_parameter);
cursor_bits += rice_parameter;
} else {
// Decode current byte and go on next ones
low_part = (*str_cursor) & ((1 << (8-cursor_bits)) - 1);
printf("@%u,%u - A - low_part=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, low_part);
++str_cursor;
remaining_bits_to_decode = rice_parameter - 8 + cursor_bits;
cursor_bits = 0;
while (remaining_bits_to_decode > 0) {
// Here we are byte aligned
if (str_cursor == str_cursor_end) {
cursor += str_cursor - str_cursor_start;
load_next_block(rb_self, rb_data, cursor, &str_cursor, &str_cursor_start, &str_cursor_end, &last_data_block);
}
if (remaining_bits_to_decode >= 8) {
low_part = (low_part << 8) + (*str_cursor);
printf("@%u,%u - B (%u) - low_part=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, remaining_bits_to_decode, low_part);
++str_cursor;
remaining_bits_to_decode -= 8;
} else {
// This byte is the last one to decode
temp = low_part;
low_part = (low_part << remaining_bits_to_decode) + ((*str_cursor) >> (8-remaining_bits_to_decode));
printf("@%u,%u - C (%u) - low_part=%u (%u + %u)\n", cursor+str_cursor-str_cursor_start, cursor_bits, remaining_bits_to_decode, low_part, (temp << remaining_bits_to_decode), (current_byte >> (8-remaining_bits_to_decode)));
cursor_bits = remaining_bits_to_decode;
remaining_bits_to_decode = 0;
}
}
}
// Here we have high_part and low_part
value = (high_part << (rice_parameter-1)) + (low_part >> 1);
if ((low_part & 1) == 1) {
value = -value-1;
}
printf("@%u,%u - Residual[%u]=%d (%u and %u)\n", cursor+str_cursor-str_cursor_start, cursor_bits, idx_sample, value, high_part, low_part);
#else
bits_count = cursor_bits + 1 + rice_parameter;
cursor_bits = (bits_count & 7);
str_cursor += (bits_count >> 3);
if (str_cursor >= str_cursor_end) {
cursor += str_cursor - str_cursor_start;
load_next_block(rb_self, rb_data, cursor, &str_cursor, &str_cursor_start, &str_cursor_end, &last_data_block);
}
//printf("@%u,%u - 2 cursor=%u str_cursor=%u str_cursor_end=%u\n", cursor+str_cursor-str_cursor_start, cursor_bits, cursor, str_cursor-str_cursor_start, str_cursor_end-str_cursor_start);
#endif
}
return rb_ary_new3(2, INT2FIX(cursor+str_cursor-str_cursor_start), INT2FIX(cursor_bits));
}
|
#get_begin_pattern ⇒ Object
11 12 13 |
# File 'lib/fileshunter/Decoders/FLAC.rb', line 11 def get_begin_pattern return BEGIN_PATTERN_FLAC, { :offset_inc => 4 } end |