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 +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/format_parser/version.rb +1 -1
- data/lib/parsers/mpeg_parser.rb +13 -17
- data/spec/parsers/mpeg_parser_spec.rb +21 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 916f22d0efd27a6e32065b50c51a4a482664c344669aa1f9586769ccf2be7b06
|
4
|
+
data.tar.gz: 3fd1b2ba7285ca69bb8d4c14c9f83e4001b55fee7e85332d97cbdbd36620597f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df680824b240f15df52fbc6c14d44f9b5fb99a93fb69cf191db6027a9871115f5e3e5bbaec48751853683b01b8e87b4266b0bbfb23700901910f2ce0f8da1137
|
7
|
+
data.tar.gz: d944a5db3fb2e1d06435b10bfc6aa0651312b45393180b08cf7a7f0b6237a0804b90a216cdeaf770e50de1af5bf31234f987e6fabc0e72bcb682e59a87cf2e7a
|
data/CHANGELOG.md
CHANGED
@@ -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
|
|
data/lib/parsers/mpeg_parser.rb
CHANGED
@@ -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
|
-
|
30
|
-
|
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
|
41
|
-
# If we detect that the header is not
|
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
|
-
|
44
|
-
|
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.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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.
|
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-
|
12
|
+
date: 2020-04-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ks
|