Есть ли быстрый способ читать альтернативные байты в дд - PullRequest
2 голосов
/ 24 апреля 2019

Я пытаюсь прочитать все остальные пары байтов в двоичном файле, используя dd в цикле, но это необычно медленно.

У меня есть двоичный файл на встроенном устройстве BusyBox, содержащий данные вФормат rgb565.Каждый пиксель составляет 2 байта, и я пытаюсь считывать каждый второй пиксель, чтобы выполнить базовое масштабирование изображения, чтобы уменьшить размер файла.

Общий размер составляет 640x480, и я смог прочитать все остальные строки"пикселей путем циклического преобразования dd с размером блока 960 байт.Но делать то же самое для каждого другого «столбца», который остается, проходя по циклу с размером блока 2 байта, - смехотворно медленно даже в моей локальной системе.

i=1
while [[ $i -le 307200 ]]
do
        dd bs=2 skip=$((i-1)) seek=$((i-1)) count=1 if=./tmpfile >> ./outfile 2>/dev/null
        let i=i+2
done

Пока я получаю выводЯ ожидаю, этот метод непригоден для использования.

Есть ли какой-то менее очевидный способ, позволяющий dd быстро копировать все остальные пары байтов?

К сожалению, я не контролирую, что компилируется в BusyBox.Я открыт для других возможных методов, но я могу использовать решение dd / sh.Например, в одной сборке пропущен head -c ...

Я ценю все отзывы.Я проверю каждое из различных предложений и вернусь с результатами.

Ответы [ 3 ]

3 голосов
/ 24 апреля 2019

Пропуск каждого другого символа тривиален для таких инструментов, как sed или awk, если вам не нужно справляться с символами новой строки и нулевыми байтами.Но поддержка Busybox для нулевых байтов в sed и awk достаточно слабая, поэтому я не думаю, что вы вообще справитесь с ними.Можно работать с символами новой строки, но это огромная боль, потому что приходится иметь дело с 16 различными комбинациями в зависимости от того, является ли каждая позиция в 4-байтовом блоке новой строкой или нет.

Поскольку произвольные двоичные данные являютсяболь, давайте переведем на шестнадцатеричный или восьмеричный!Я черпаю вдохновение из сценариев bin2hex и hex2bin Стефана Шазеласа .Поскольку нам не важен промежуточный формат, я буду использовать восьмеричный, с которым гораздо проще иметь дело, потому что на последнем шаге используется printf, который поддерживает только восьмеричный.hex2bin Стефана использует awk для шестнадцатеричного преобразования в восьмеричное;oct2bin может использовать sed.Итак, в конце вам понадобятся sh, od, sed и printf.Я не думаю, что вы можете избежать printf: это важно для вывода нулевых байтов.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * od является существенным, большинство его опций - нет, поэтому должна быть возможность настроить этот код для поддержки очень урезанного кода с немного большей постобработкой.

od -An -v -t o1 -w4 |
sed 's/^ \([0-7]*\) \([0-7]*\).*/printf \\\\\1\\\\\2/' |
sh

Причина этогопо сравнению с вашим подходом, основанным на dd, настолько быстро, что BusyBox запускает printf в родительском процессе, тогда как dd требует своего собственного процессаФоркинг медленный.Если я правильно помню, есть опция компиляции, которая делает BusyBox форком для всех утилит.В этом случае мой подход, вероятно, будет таким же медленным, как и ваш.Вот промежуточный подход, использующий dd, который не может избежать разветвлений, но, по крайней мере, избегает открытия и закрытия файла каждый раз.Это должно быть немного быстрее, чем у вас.

i=$(($(wc -c <"$1") / 4))
exec <"$1"
dd ibs=2 count=1 conv=notrunc 2>/dev/null
while [ $i -gt 1 ]; do
  dd ibs=2 count=1 skip=1 conv=notrunc 2>/dev/null
  i=$((i - 1))
done
1 голос
/ 24 апреля 2019

Не знаю, будет ли это быстрее или даже возможно с BusyBox, но это мысль ...

#!/bin/bash

# Empty result file
> result

exec 3< datafile
while true; do
    # Read 2 bytes into file "short"
    dd bs=2 count=1 <&3 > short 2> /dev/null
    [ ! -s short ] && break
    # Accumulate result file
    cat short >> result
    # Read two bytes and discard
    dd bs=2 count=1 <&3 > short 2> /dev/null
    [ ! -s short ] && break
done

Или это должно быть более эффективным:

#!/bin/bash

exec 3< datafile
for ((i=0;i<76800;i++)) ; do
    # Skip 2 bytes then read 2 bytes
    dd bs=2 count=1 skip=1 <&3 2> /dev/null
done > result

Или, может быть, вы могли бы использовать netcat или ssh, чтобы отправить файл на разумный (более мощный) компьютер с надлежащими инструментами для его обработки и возврата.Например, если на удаленном компьютере установлен ImageMagick , он может очень просто уменьшить изображение.

0 голосов
/ 25 апреля 2019

Другим вариантом может быть использование Lua , который имеет репутацию небольшого, быстрого и хорошо подходящего для встраиваемых систем - см. Сайт Lua . Там тоже есть готовые загружаемые файлы. Это также предлагается на веб-сайте Busybox здесь .

Я никогда раньше не писал ни одного Lua, поэтому возможны некоторые неэффективности, но, похоже, это работает довольно хорошо и обрабатывает изображение 640x480 RGB565 за несколько миллисекунд на моем рабочем столе.

-- scale.lua
-- Usage: lua scale.lua input.bin output.bin
-- Scale an image by skipping alternate lines and alternate columns

-- Set up width, height and bytes per pixel
w   = 640
h   = 480
bpp = 2    

-- Open first argument for input, second for output
inp = assert(io.open(arg[1], "rb"))
out = assert(io.open(arg[2], "wb"))

-- Read image, one line at a time
for i = 0, h-1, 1 do
   -- Read a whole line
   line = inp:read(w*bpp)

   -- Only use every second line
   if (i % 2) == 0 then
      io.write("DEBUG: Processing row: ",i,"\n")
      -- Build up new, reduced line by picking substrings
      reduced=""
      for p = 1, w*bpp, bpp*2 do
         reduced = reduced .. string.sub(line,p,p+bpp-1)
      end
      io.write("DEBUG: New line length in bytes: ",#reduced,"\n")
      out:write(reduced)
   end
end

assert(out:close())

Я создал тестовое изображение в оттенках серого с помощью ImageMagick следующим образом:

magick -depth 16 -size 640x480 gradient: gray:image.bin

Затем я запустил вышеупомянутый скрипт Lua с помощью:

lua scale.lua image.bin smaller.bin

Затем я сделал JPEG, который смог просмотреть для тестирования:

magick -depth 16 -size 320x240 gray:smaller.bin smaller.jpg
...