Class: FilesHunter::Decoders::FLAC

Inherits:
BeginPatternDecoder show all
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

Methods inherited from BeginPatternDecoder

#find_segments

Methods inherited from FilesHunter::Decoder

#segments_found, #setup

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_patternObject



11
12
13
# File 'lib/fileshunter/Decoders/FLAC.rb', line 11

def get_begin_pattern
  return BEGIN_PATTERN_FLAC, { :offset_inc => 4 }
end