lib/mp3file/mp3_file.rb in mp3file-1.1.5 vs lib/mp3file/mp3_file.rb in mp3file-1.2.0
- old
+ new
@@ -123,12 +123,29 @@
# Some files have more than one ID3v2 tag. If we can't find an
# MP3 header in the next 4k, try reading another ID3v2 tag and
# repeat.
@extra_id3v2_tags = []
begin
- # Try to find the first MP3 header.
- @first_header_offset, @first_header = get_next_header(@file)
+ # Try to find the first two MP3 headers.
+ loop do
+ @first_header_offset, @first_header = get_next_header(@file)
+ @file.seek(@first_header_offset + @first_header.frame_size, IO::SEEK_SET)
+ second_header_offset = @file.tell - 4
+ second_header =
+ begin
+ MP3Header.new(@file)
+ rescue InvalidMP3HeaderError
+ nil
+ end
+
+ # Pretend we didn't read the second header.
+ @file.seek(@first_header_offset + 4)
+
+ if second_header && @first_header.same_header?(second_header)
+ break
+ end
+ end
rescue InvalidMP3FileError
if @id3v2_tag
end_of_tags = @id3v2_tag.size + @extra_id3v2_tags.map(&:last).map(&:size).reduce(:+).to_i
@file.seek(end_of_tags, IO::SEEK_SET)
@@ -204,35 +221,45 @@
# / CBR call. Assume that Xing headers, when present in a CBR
# file, are called "Info".
@vbr = !@xing_header.nil? && @xing_header.name == "Xing"
end
- # puts "@num_frames = #{@num_frames.inspect}"
- # puts "@xing_header = #{@xing_header.inspect}"
+ # puts "@num_frames (1) = #{@num_frames.inspect}"
+ # puts "@bitrate (1) = #{@bitrate.inspect}"
+ # puts "@vbr = #{@vbr.inspect}"
+ # puts "@xing_header.frames = #{@xing_header && @xing_header.frames.inspect}"
+ # puts "@xing_header.bytes = #{@xing_header && @xing_header.bytes.inspect}"
# puts "@audio_size = #{@audio_size.inspect}"
# puts "@first_header size = #{@first_header.frame_size.inspect}"
- # Find the number of frames. Prefer the actual frame count we
- # did (if we scanned all the frames) over the Xing
- # header. Prefer the Xing header over file size math.
- @num_frames = @num_frames ||
- (@xing_header && (@xing_header.frames + 1)) ||
+ # Find the number of frames, in this order:
+ # 1. The frame count from the Xing (or Info) header.
+ # 2. The number of frames we actually counted by scanning the
+ # whole file, which we might not have done.
+ # 3. Assume it's CBR and divide the file size by the frame size.
+ @num_frames =
+ (@xing_header && @xing_header.frames) ||
+ @num_frames ||
(@audio_size / @first_header.frame_size)
+ # puts "@num_frames (2) = #{@num_frames.inspect}"
+
# Figure out the total samples and the time duration.
@total_samples = @num_frames * @first_header.samples
@length = @total_samples.to_f / @samplerate.to_f
+ # puts "@total_samples = #{@total_samples.inspect}"
+ # puts "@length = #{@length.inspect}"
+
# If the file looks like it's a VBR file, do an averate bitrate
# calculation, either using the Xing header's idea of the file
# size or the one we found.
if @vbr
@bitrate = ((@xing_header && @xing_header.bytes) || @audio_size) / @length.to_f * 8 / 1000
end
- # puts "@vbr = #{@vbr.inspect}"
- # puts "@bitrate = #{@bitrate.inspect}"
+ # puts "@bitrate (2) = #{@bitrate.inspect}"
@file.close
end
def get_next_header(file, offset = nil)
@@ -245,10 +272,10 @@
header_offset = file.tell
while header.nil?
begin
header = MP3Header.new(file)
- header_offset = file.tell - 4
+ header_offset = file.tell - 4
rescue InvalidMP3HeaderError
header_offset += 1
if header_offset - initial_header_offset > 4096
raise InvalidMP3FileError, "Could not find a valid MP3 header in the first 4096 bytes."
else