Class: FormatParser::MPEGParser
- Inherits:
-
Object
- Object
- FormatParser::MPEGParser
show all
- Extended by:
- IOUtils
- Defined in:
- lib/parsers/mpeg_parser.rb
Overview
Constant Summary
collapse
- ASPECT_RATIOS =
{
1 => '1:1',
2 => '4:3',
3 => '16:9',
4 => '2.21:1'
}
- FRAME_RATES =
{
1 => '23.976',
2 => '24',
3 => '25',
4 => '29.97',
5 => '30',
6 => '50',
7 => '59.94',
8 => '60'
}
[0x00, 0x00, 0x01, 0xBA].pack('C*')
[0xB3].pack('C*')
- MAX_BLOCK_READS =
32
- BYTES_TO_READ_PER_READ =
1024
Constants included
from IOUtils
IOUtils::INTEGER_DIRECTIVES
Class Method Summary
collapse
Methods included from IOUtils
read_bytes, read_fixed_point, read_int, safe_read, safe_skip, skip_bytes
Class Method Details
.call(io) ⇒ Object
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
# File 'lib/parsers/mpeg_parser.rb', line 36
def self.call(io)
return unless (io)
MAX_BLOCK_READS.times do
next unless pos = (io)
io.seek(pos + 1)
horizontal_size, vertical_size = parse_image_size(io)
ratio_code, rate_code = parse_rate_information(io)
return file_info(horizontal_size, vertical_size, ratio_code, rate_code) if valid_aspect_ratio_code?(ratio_code) && valid_frame_rate_code?(rate_code)
end
nil rescue FormatParser::IOUtils::InvalidRead
nil
end
|
.convert_3_bytes_to_bits(bytes) ⇒ Object
103
104
105
106
|
# File 'lib/parsers/mpeg_parser.rb', line 103
def self.convert_3_bytes_to_bits(bytes)
bytes = bytes.unpack('CCC')
(bytes[0] << 16) | (bytes[1] << 8) | (bytes[2])
end
|
.file_info(width_px, height_px, ratio_code, rate_code) ⇒ Object
54
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/parsers/mpeg_parser.rb', line 54
def self.file_info(width_px, height_px, ratio_code, rate_code)
FormatParser::Video.new(
format: :mpg,
width_px: width_px,
height_px: height_px,
intrinsics: {
aspect_ratio: ASPECT_RATIOS.fetch(ratio_code),
frame_rate: FRAME_RATES.fetch(rate_code)
},
)
end
|
Returns the position of the next sequence package content in the stream 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 If the package is not found, then it returns nil.
.likely_match?(filename) ⇒ Boolean
32
33
34
|
# File 'lib/parsers/mpeg_parser.rb', line 32
def self.likely_match?(filename)
filename =~ /\.(mpg|mpeg)$/i
end
|
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.
99
100
101
|
# File 'lib/parsers/mpeg_parser.rb', line 99
def self.(io)
safe_read(io, 4) == PACK_HEADER_START_CODE
end
|
.parse_image_size(io) ⇒ Object
The following 3 bytes after the sequence header code, gives us information about the px size 1.5 bytes (12 bits) for horizontal size and 1.5 bytes for vertical size
68
69
70
71
|
# File 'lib/parsers/mpeg_parser.rb', line 68
def self.parse_image_size(io)
image_size = convert_3_bytes_to_bits(safe_read(io, 3))
[read_first_12_bits(image_size), read_last_12_bits(image_size)]
end
|
The following byte gives us information about the aspect ratio and frame rate 4 bits corresponds to the aspect ratio and 4 bits to the frame rate code
75
76
77
78
|
# File 'lib/parsers/mpeg_parser.rb', line 75
def self.parse_rate_information(io)
rate_information = safe_read(io, 1).unpack('C').first
[read_first_4_bits(rate_information), read_last_4_bits(rate_information)]
end
|
.read_first_12_bits(bits) ⇒ Object
108
109
110
|
# File 'lib/parsers/mpeg_parser.rb', line 108
def self.read_first_12_bits(bits)
bits >> 12 & 0x0fff
end
|
.read_first_4_bits(byte) ⇒ Object
116
117
118
|
# File 'lib/parsers/mpeg_parser.rb', line 116
def self.read_first_4_bits(byte)
byte >> 4
end
|
.read_last_12_bits(bits) ⇒ Object
112
113
114
|
# File 'lib/parsers/mpeg_parser.rb', line 112
def self.read_last_12_bits(bits)
bits & 0x0fff
end
|
.read_last_4_bits(byte) ⇒ Object
120
121
122
|
# File 'lib/parsers/mpeg_parser.rb', line 120
def self.read_last_4_bits(byte)
byte & 0x0F
end
|
.valid_aspect_ratio_code?(ratio_code) ⇒ Boolean
80
81
82
|
# File 'lib/parsers/mpeg_parser.rb', line 80
def self.valid_aspect_ratio_code?(ratio_code)
ASPECT_RATIOS.include?(ratio_code)
end
|
.valid_frame_rate_code?(rate_code) ⇒ Boolean
84
85
86
|
# File 'lib/parsers/mpeg_parser.rb', line 84
def self.valid_frame_rate_code?(rate_code)
FRAME_RATES.include?(rate_code)
end
|