Как перезаписать i-кадры видео? - PullRequest
3 голосов
/ 12 апреля 2010

Я хочу уничтожить все i-кадры видео. Делая это, я хочу проверить, достаточно ли шифрования только i-кадров видео, чтобы сделать его недоступным для просмотра. Как я могу это сделать? Только удаление их и повторное сжатие видео не будет таким же, как перезапись i-кадра в потоке без перерасчета b-кадров и т. Д.

Ответы [ 2 ]

5 голосов
/ 12 апреля 2010

Используя libavformat (библиотека из ffmpeg), вы можете демультиплексировать видео в пакеты, представляющие один кадр. Затем вы можете зашифровать данные в пакетах, помеченных как ключевые кадры. Наконец, вы можете повторно мультиплексировать видео в новый файл. Здесь есть хорошее руководство по libavformat / libavcodec здесь . Вам не нужно будет фактически декодировать / кодировать кадры, потому что я предполагаю, что вы просто хотите зашифровать сжатые данные. В этом случае, прочитав AVPacket, просто зашифруйте его данные, если это ключевой кадр (packet->flags & PKT_FLAG_KEY). Затем вам нужно будет записать пакеты в новый файл.

Следует отметить, что вам, возможно, придется соблюдать осторожность, когда вы просто шифруете пакеты I-кадра, возвращаемые из libavformat или другого программного обеспечения для демультиплексирования, поскольку они могут включать данные из других заголовков, которые хранятся в битовом потоке. Например, я часто видел возвращаемую последовательность libavformat или группу заголовков изображения как часть пакета видеокадра. Уничтожение этой информации может сделать ваш тест недействительным.

Возможно, более простым способом решения этой проблемы было бы исследование синтаксиса битового потока кодека, используемого для кодирования видео, и использования стартовых кодов, чтобы определить, где начинаются кадры и являются ли они I-кадрами. Одна из проблем заключается в том, что большинство видеофайлов имеют контейнер (AVI, MP4, MPEG-PS / TS) вокруг фактически сжатых данных, и вам не нужно ничего шифровать в этой области. Скорее всего, вы найдете информацию заголовка, относящуюся к формату контейнера, вкрапленную в сжатые данные одного кадра. Таким образом, вы можете использовать ffmpeg из командной строки для вывода только необработанных сжатых видеоданных:

ffmpeg -i filename -an -vcodec copy -f rawvideo output_filename

Это создаст файл только с видеоданными (без звука) без контейнера. Отсюда вы можете использовать стартовые коды определенного формата видео, чтобы найти диапазоны байтов в файле, которые соответствуют I-кадрам.

Например, в MPEG-4 вы должны искать 32-битный стартовый код 0x000001b6, чтобы указать начало VOP (плоскости видеообъекта). Вы можете определить, является ли это I-кадр или нет, проверив, равны ли два бита, непосредственно следующие за начальным кодом, 00. Если это I-кадр, шифруйте данные, пока не получите следующий стартовый код (24-битный 0x000001). Возможно, вы захотите оставить начальный код и код типа фрейма без изменений, чтобы позже можно было указать, с чего начать расшифровку.

Относительно результатов вашего теста относительно того, сделает ли шифрование I-кадров видео недоступным для просмотра; это зависит от вашего значения unwatchable. Я ожидаю, что вы сможете разглядеть основную форму, которая существовала в оригинальном видео, если оно находится в движении, поскольку его информация должна быть закодирована в кадрах B или P, но цвет и детализация все равно будут мусором. Я видел одну битовую ошибку в I-кадре, из-за которой вся группа изображений (I-кадр и все зависящие от него кадры) выглядят как мусор. Целью сжатия является уменьшение избыточности до такой степени, что каждый бит является жизненно важным. Уничтожение всего I-кадра почти наверняка сделает его недоступным для просмотра.

Редактировать: Ответ на комментарий

Стартовые коды гарантированно выровнены по байтам, поэтому вы можете прочитать файл по байтам за раз в 4-байтовый буфер и проверить, равен ли он стартовому коду. В C ++ вы можете сделать это следующим образом:

#include <iostream>
using namespace std;
//...

//...
ifstream ifs("filename", ios::in | ios::binary);
//initialize buffer to 0xffffffff
unsigned char buffer[4] = {0xff, 0xff, 0xff, 0xff};
while(!ifs.eof())
{
    //Shift to make space for new read.
    buffer[0] = buffer[1];
    buffer[1] = buffer[2];
    buffer[2] = buffer[3];

    //read next byte from file
    buffer[3] = ifs.get();

    //see if the current buffer contains the start code.
    if(buffer[0]==0x00 && buffer[1]==0x00 && buffer[2]==0x01 && buffer[3]==0xb6)
    {
        //vop start code found
        //Test for I-frame
        unsigned char ch = ifs.get();
        int vop_coding_type = (ch & 0xc0) >> 6;   //masks out the first 2 bits and shifts them to the least significant bits of the uchar
        if(vop_coding_type == 0)
        {
            //It is an I-frame
            //...
        }
    }
}

Поиск 24-битного стартового кода аналогичен, просто используйте 3-байтовый буфер. Помните, что вы должны удалить видео контейнер с помощью ffmpeg, прежде чем делать это, иначе вы можете уничтожить некоторую информацию о контейнере.

0 голосов
/ 12 апреля 2010

В Windows вы можете скопировать файл без повторного сжатия, используя VFW и пропустить I-кадры. Чтобы найти I-кадры, вы можете использовать функцию FindSample с флагом FIND_KEY.

...