format_parser 0.21.0 → 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad2245de4a2119c7572c3962ad14abbf16395b2bec4064b218ee9f99d1e7c24b
4
- data.tar.gz: b982bcc7f6626b66684db532317b0c0d35cd062aa89766ea1a230f93e7d996d6
3
+ metadata.gz: 916f22d0efd27a6e32065b50c51a4a482664c344669aa1f9586769ccf2be7b06
4
+ data.tar.gz: 3fd1b2ba7285ca69bb8d4c14c9f83e4001b55fee7e85332d97cbdbd36620597f
5
5
  SHA512:
6
- metadata.gz: 2df2a3763e12e2bb0c70a8f5ec3319fcf6a3210a73461dc8abb5ec2af706028403eca48cf8c589bd40122dff0cfdabce383a79b1253237e219a5c89936ec0a5e
7
- data.tar.gz: 0ca6084649313b2c7ad32204b4c8b745f13dbf6cf2c347cb7c80ca7976b964f00feabd9666c0372e9a6c10e4ed250500ed4e202cdb687372cbd369378b7a0faa
6
+ metadata.gz: df680824b240f15df52fbc6c14d44f9b5fb99a93fb69cf191db6027a9871115f5e3e5bbaec48751853683b01b8e87b4266b0bbfb23700901910f2ce0f8da1137
7
+ data.tar.gz: d944a5db3fb2e1d06435b10bfc6aa0651312b45393180b08cf7a7f0b6237a0804b90a216cdeaf770e50de1af5bf31234f987e6fabc0e72bcb682e59a87cf2e7a
@@ -1,3 +1,8 @@
1
+ ## 0.21.1
2
+ * MPEG: Ensure parsing does not inadvertently return an Integer instead of Result|nil
3
+ * MPEG: Scan further into the MPEG file than previously (scan 32 1KB chunks)
4
+ * MPEG: Ensure the parser does not raise an exception when there is no data to read for scanning beyound the initial header
5
+
1
6
  ## 0.21.0
2
7
  * Adds support for MPEG video files
3
8
 
@@ -1,3 +1,3 @@
1
1
  module FormatParser
2
- VERSION = '0.21.0'
2
+ VERSION = '0.21.1'
3
3
  end
@@ -26,9 +26,8 @@ class FormatParser::MPEGParser
26
26
 
27
27
  PACK_HEADER_START_CODE = [0x00, 0x00, 0x01, 0xBA].pack('C*')
28
28
  SEQUENCE_HEADER_START_CODE = [0xB3].pack('C*')
29
- SEEK_FOR_SEQUENCE_HEADER_TIMES_LIMIT = 4
30
- SEEK_FOR_SEQUENCE_HEADER_START_CODE_TIMES_LIMIT = 4
31
- BYTES_TO_READ_PER_TIME = 1024
29
+ MAX_BLOCK_READS = 32
30
+ BYTES_TO_READ_PER_READ = 1024
32
31
 
33
32
  def self.likely_match?(filename)
34
33
  filename =~ /\.(mpg|mpeg)$/i
@@ -37,18 +36,19 @@ class FormatParser::MPEGParser
37
36
  def self.call(io)
38
37
  return unless matches_mpeg_header?(io)
39
38
 
40
- # We are looping though the stream because there can be several sequence headers and some of them are not usefull.
41
- # If we detect that the header is not usefull, then we look for the next one for SEEK_FOR_SEQUENCE_HEADER_TIMES_LIMIT
39
+ # We are looping though the stream because there can be several sequence headers and some of them are not useful.
40
+ # If we detect that the header is not useful, then we look for the next one for SEEK_FOR_SEQUENCE_HEADER_TIMES_LIMIT
42
41
  # If we reach the EOF, then the mpg is likely to be corrupted and we return nil
43
- SEEK_FOR_SEQUENCE_HEADER_TIMES_LIMIT.times do
44
- return if fetch_next_sequence_header_code_position(io).nil?
42
+ MAX_BLOCK_READS.times do
43
+ next unless pos = find_next_header_code_pos(io)
44
+ io.seek(pos + 1)
45
45
  horizontal_size, vertical_size = parse_image_size(io)
46
46
  ratio_code, rate_code = parse_rate_information(io)
47
-
48
47
  if valid_aspect_ratio_code?(ratio_code) && valid_frame_rate_code?(rate_code)
49
48
  return file_info(horizontal_size, vertical_size, ratio_code, rate_code)
50
49
  end
51
50
  end
51
+ nil # otherwise the return value of Integer#times will be returned
52
52
  rescue FormatParser::IOUtils::InvalidRead
53
53
  nil
54
54
  end
@@ -90,15 +90,11 @@ class FormatParser::MPEGParser
90
90
  # Returns the position of the next sequence package content in the stream
91
91
  # This method will read BYTES_TO_READ_PER_TIME in each loop for a maximum amount of SEEK_FOR_SEQUENCE_HEADER_START_CODE_TIMES_LIMIT times
92
92
  # If the package is not found, then it returns nil.
93
- def self.fetch_next_sequence_header_code_position(io)
94
- SEEK_FOR_SEQUENCE_HEADER_START_CODE_TIMES_LIMIT.times do
95
- bytes_stream_read = io.read(BYTES_TO_READ_PER_TIME)
96
- header_relative_index = bytes_stream_read.index(SEQUENCE_HEADER_START_CODE)
97
- next if header_relative_index.nil?
98
- new_io_pos = io.pos - BYTES_TO_READ_PER_TIME + header_relative_index + 1
99
- io.seek(new_io_pos)
100
- return new_io_pos
101
- end
93
+ def self.find_next_header_code_pos(io)
94
+ pos_before_read = io.pos
95
+ bin_str = io.read(BYTES_TO_READ_PER_READ) # bin_str might be nil if we are at EOF
96
+ header_relative_index = bin_str && bin_str.index(SEQUENCE_HEADER_START_CODE)
97
+ return pos_before_read + header_relative_index if header_relative_index
102
98
  end
103
99
 
104
100
  # If the first 4 bytes of the stream are equal to 00 00 01 BA, the pack start code for the Pack Header, then it's an MPEG file.
@@ -12,6 +12,27 @@ describe FormatParser::MPEGParser do
12
12
  expect(parse_result.intrinsics[:frame_rate]).to eq('30')
13
13
  end
14
14
 
15
+ it 'returns a nil if it is necessary to iterate over a very large number of bytes and the requisite sequences are not detected' do
16
+ bytes_buffer = StringIO.new
17
+ bytes_buffer.write([0x00, 0x00, 0x01, 0xBA].pack('C*')) # MPEG header
18
+ zero_bytes = [0x00].pack('C') * (1024 * 1024 * 5)
19
+ bytes_buffer.write(zero_bytes)
20
+
21
+ bytes_buffer.rewind
22
+
23
+ parse_result = described_class.call(bytes_buffer)
24
+ expect(parse_result).to be_nil
25
+ end
26
+
27
+ it 'returns a nil if the IO only contains the MPEG header bytes at the start and nothing else' do
28
+ bytes_buffer = StringIO.new
29
+ bytes_buffer.write([0x00, 0x00, 0x01, 0xBA].pack('C*')) # MPEG header
30
+ bytes_buffer.rewind
31
+
32
+ parse_result = described_class.call(bytes_buffer)
33
+ expect(parse_result).to be_nil
34
+ end
35
+
15
36
  it 'parses a file with mpeg extension' do
16
37
  parse_result = described_class.call(File.open(__dir__ + '/../fixtures/MPG/video2.mpeg', 'rb'))
17
38
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: format_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.21.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Berman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-03-27 00:00:00.000000000 Z
12
+ date: 2020-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ks