Class: DicomS::MetaCodec
- Inherits:
-
Object
- Object
- DicomS::MetaCodec
- Defined in:
- lib/dicoms/meta_codec.rb
Overview
Inserting/extracting DICOM metadata in video files with FFMpeg
Example of use:
# Add metadata to a file
dicom = DICOM::DObject.read(dicom_file)
= MetaCodec.new(mode: :chunked)
= 'ffmetadata'
.(dicom, , dx: 111, dy: 222, dz: 333)
input_file = 'video.mkv'
output_file = 'video_with_metadata.mkv'
`ffmpeg -i #{input_file} -i #{} -map_metadata 1 -codec copy #{output_file}`
# Extract metadata from a file
`ffmpeg -i #{output_file} -f ffmetadata #{}`
dicom_elements, additional_values = .()
Instance Method Summary collapse
- #decode_metadata(txt) ⇒ Object
- #encode_metadata(dicom, additional_metadata = {}, &blk) ⇒ Object
-
#initialize(options = {}) ⇒ MetaCodec
constructor
Two encoding modes: * :chunked : use few metadata entries (dicom_0) that encode all the DICOM elements (several are used because there’s a limit in the length of a single metadata entry) * :individual : use individual metadata entries for each DICOM tag.
-
#read_metadata(metadatafile) ⇒ Object
Can extract the metadatafile from a video input_file with: ‘ffmpeg -i #input_file -f ffmetadata #metadatafile`.
-
#write_metadata(dicom, metadatafile, additional_metadata = {}, &blk) ⇒ Object
Write DICOM metatada encoded for FFMpeg into a metadatafile The file can be attached to a video input_file with: ‘ffmpeg -i #input_file -i #metadatafile -map_metadata 1 -codec copy #output_file`.
Constructor Details
#initialize(options = {}) ⇒ MetaCodec
Two encoding modes:
-
:chunked : use few metadata entries (dicom_0) that encode all the DICOM elements (several are used because there’s a limit in the length of a single metadata entry)
-
:individual : use individual metadata entries for each DICOM tag
25 26 27 |
# File 'lib/dicoms/meta_codec.rb', line 25 def initialize( = {}) @mode = [:mode] || :individual end |
Instance Method Details
#decode_metadata(txt) ⇒ Object
62 63 64 65 66 67 68 69 |
# File 'lib/dicoms/meta_codec.rb', line 62 def (txt) txt = unescape(txt) data = txt.split(PAIR_SEPARATOR).map{|pair| pair.split(VALUE_SEPARATOR)} data = data.map{|tag, value| [inner_unescape(tag), inner_unescape(value)]} data.map{|tag, value| DICOM::Element.new(tag, value) } end |
#encode_metadata(dicom, additional_metadata = {}, &blk) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/dicoms/meta_codec.rb', line 29 def (dicom, = {}, &blk) elements = dicom.elements.select{|e| !e.value.nil?} elements = elements.select(&blk) if blk elements = elements.map{|e| [e.tag, e.value]} case @mode when :chunked txt = elements.map{|tag, value| "#{inner_escape(tag)}#{VALUE_SEPARATOR}#{inner_escape(value)}"}.join(PAIR_SEPARATOR) chunks = in_chunks(txt, CHUNK_SIZE).map{|txt| escape(txt)} = Hash[chunks.each_with_index.to_a.map(&:reverse)] else pairs = elements.map { |tag, value| group, tag = tag.split(',') ["#{group}_#{tag}", escape(value)] } = Hash[pairs] end .merge() end |
#read_metadata(metadatafile) ⇒ Object
Can extract the metadatafile from a video input_file with:
`ffmpeg -i #{input_file} -f ffmetadata #{}`
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 |
# File 'lib/dicoms/meta_codec.rb', line 73 def () lines = File.read().lines[1..-1] lines = lines.reject { |line| line = line.strip line.empty? || line[0, 1] == '#' || line[0, 1] == ';' } chunks = [] elements = [] = {} lines.each do |line| key, value = line.strip.split('=') key = key.downcase if match = key.match(/\Adicom_(\d+)\Z/) i = match[1].to_i chunks << [i, value] elsif match = key.match(/\Adicom_(\h+)_(\h+)\Z/) group = match[1] tag = match[2] tag = "#{group},#{tag}" elements << DICOM::Element.new(tag, unescape(value)) elsif match = key.match(/\Adicom_(.+)\Z/) [match[1].downcase.to_sym] = value # TODO: type conversion? end end if chunks.size > 0 elements += (chunks.sort_by(&:first).map(&:last).join) end [elements, ] end |
#write_metadata(dicom, metadatafile, additional_metadata = {}, &blk) ⇒ Object
Write DICOM metatada encoded for FFMpeg into a metadatafile The file can be attached to a video input_file with:
`ffmpeg -i #{input_file} -i #{} -map_metadata 1 -codec copy #{output_file}`
52 53 54 55 56 57 58 59 60 |
# File 'lib/dicoms/meta_codec.rb', line 52 def (dicom, , = {}, &blk) = (dicom, , &blk) File.open(, 'w') do |file| file.puts ";FFMETADATA1" .each do |name, value| file.puts "dicom_#{name}=#{value}" end end end |