如何覆盖视频的I帧? [英] How to overwrite i-frames of a video?

查看:231
本文介绍了如何覆盖视频的I帧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要毁掉一个视频的所有I帧。这样做我想检查一个视频只加密I帧就足以使其无法观看。我怎样才能做到这一点?仅除去它们并重新压缩视频不会一样真正覆盖流中的I帧,而不重新计算B帧等


解决方案

使用libavformat流(从库中的ffmpeg),你可以解复用视频转换成表示一帧数据包。然后,您可以在标记为关键帧数据包加密数据。最后,你可以remultiplex视频到一个新文件。这是一个很好了libavformat / libavcodec的教程这里。你不会有实际解码/编码的帧,因为我认为你只是想压缩的数据进行加密。在这种情况下,一旦你读 AVPacket ,只是加密的数据,如果它是一个关键帧(分组>标志和放大器; PKT_FLAG_KEY )。那么你会写数据包到一个新文件。



有一点要注意的是,你可能要小心,当你只是加密返回的I帧数据包从libav库格式或一些其它多路分解软件,因为它们可以包括从存储在比特流中的其他标题的数据。举例来说,我经常看见了libavformat返回序列或图片头组作为一个视频帧数据包的一部分。销毁这些信息可能会使您的测试。



一个可能更容易解决这个问题将是研究用于编码视频的编解码器的比特流语法和使用的启动方式码,以确定帧开始,它们是否是I帧。一个问题是,大多数视频文件有一个容器(AVI,MP4,MPEG-PS / TS)各地实际压缩数据,你不会希望加密在这方面东西。你很可能会发现属于单个帧的压缩数据中穿插的容器格式头信息。所以,你可以使用的ffmpeg 命令行输出只是原始压缩的视频数据:

 的ffmpeg -i文件名-an -vcodec复制-f rawvideo输出文件名

这将创建只有无容器的视频数据(没有音频)的文件。从这里你可以使用特定的视频格式的起始码找到对应的I帧文件中的字节的范围。



例如,在MPEG-4,你要寻找的32位起始码 0x000001b6 来表示一个VOP(视频目标平面)的开始。你能确定它是否是一个I-帧或不通过测试是否立即两个比特之后,在开始代码是等于 00 。如果它是一个I帧,直到你到达下一个起始码加密数据(24位 0x000001 )。你可能会想离开起始码和帧类型代码不变,所以你可以告诉以后从哪里开始解密。



关于您的测试成果,以与否加密I帧进行视频不可观看;这取决于你的意思无法观看。我希望你也许能够做出来,在原始视频存在,如果它是在运动中,因为其信息将在B或P帧进行编码的主要形态,但颜色和细节仍然是垃圾。我已经看到了一个I帧单比特错误使图像(I帧,并依赖于它的所有帧)看起来像垃圾的整个组。压缩的目的是为了减少冗余,每个比特是重要的点。 。摧毁整个I帧将几乎可以肯定,使其无法观看



编辑:回应置评



启动代码保证是字节对齐,这样你就可以读取文件,一次一个字节到一个4字节的缓冲区,并测试它是否等于起始码。在C ++中,你可以通过下面的做到这一点:

 的#include<&iostream的GT; 
使用命名空间std;
// ...

// ...
ifstream的IFS(文件名,内部监督办公室::在| IOS ::二进制);
//初始化缓冲区为0xffffffff
无符号字符缓冲区[4] = {0xFF的,为0xFF,0xFF的,0xFF的};
,而(!ifs.eof())
{
//按住Shift键,以腾出空间为新的读取。
缓冲液[0] =缓冲液[1];
缓冲液[1] =缓冲液[2];
缓冲液[2] =缓冲液[3];

// [3] = ifs.get()从文件中读取
缓冲液下一个字节;

//看到,如果当前的缓冲器包含开始码。
如果(缓冲[0] == 0×00和放大器;&放大器;缓冲液[1] == 0×00和放大器;&放大器;缓冲液[2] == 0×01和放大器;&放大器;缓冲液[3] == 0xb6)
{
// VOP开始代码中发现
//试验I帧
unsigned char型CH = ifs.get();
INT vop_coding_type =(CH&安培;将0xC0)GT;> 6; //掩模出的前2比特,并将其转移到UCHAR
的至少显著位如果(vop_coding_type == 0)
{
//这是一个I帧
// ...
}
}
}

找到一个24位的起始码类似,只使用一个3字节的缓冲区。请记住,你必须在此之前的有关ffmpeg删除视频容器或你可以消灭一些容器的信息。


I want to destroy all i-frames of a video. Doing this I want to check if encrypting only the i-frames of a video would be sufficient for making it unwatchable. How can I do this? Only removing them and recompressing the video would not be the same as really overwriting the i-frame in the stream without recalculating b-frames etc.

解决方案

Using libavformat (library from ffmpeg), you can demultiplex the video into packets that represent a single frame. You can then encrypt data in the packets that are marked as key frames. Finally you can remultiplex the video into a new file. There is a good libavformat/libavcodec tutorial here. You will not have to actually decode/encode the frames because I assume you just want to encrypt the compressed data. In this case, once you read the AVPacket, just encrypt its data if it's a key frame (packet->flags & PKT_FLAG_KEY). You would then have to write the packets to a new file.

One thing to note is that you might have to be careful when you just encrypt the I-frame packets returned from libavformat or some other demuxing software since they may include data from other headers that are stored in the bitstream. For instance, I have often seen libavformat return sequence or group of picture headers as part of a video frame packet. Destroying this information may invalidate your test.

A possibly easier way to approach the problem would be to research the bitstream syntax of the codec used to encode the video and use the start codes to determine where frames start and whether or not they are I-frames. One problem is that most video files have a container (AVI, MP4, MPEG-PS/TS) around the actual compressed data and you would not want to encrypt anything in that area. You will most likely find header information belonging to the container format interspersed within the compressed data of a single frame. So you could use ffmpeg from the command line to output just the raw compressed video data:

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

This will create a file with only the video data(no audio) with no container. From here you can use the start codes of the specific video format to find the ranges of bytes in the file that correspond to I-frames.

For instance, in MPEG-4, you would be looking for the 32-bit start code 0x000001b6 to indicate the start of a VOP (video object plane). You could determine whether it is an I-frame or not by testing whether two bits immediately following the start code are equal to 00. If it is an I frame, encrypt the data until you reach the next start code (24-bit 0x000001). You'll probably want to leave the start code and frame type code untouched so you can tell later where to start decrypting.

Concerning outcome of your test as to whether or not encrypting I-frames will make a video unwatchable; it depends on your meaning of unwatchable. I would expect that you may be able to make out a major shape that existed in the original video if it is in motion since its information would have to be encoded in the B or P frames, but the color and detail would still be garbage. I have seen a single bit error in an I-frame make the entire group of pictures (the I-frame and all frames that depend on it) look like garbage. The purpose of the compression is to reduce redundancy to the point that each bit is vital. Destroying the entire I-frame will almost definitely make it unwatchable.

Edit: Response to comment

Start codes are guaranteed to be byte-aligned, so you can read the file a byte at a time into a 4 byte buffer and test whether it is equal to the start code. In C++, you can do this by the following:

#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
            //...
        }
    }
}

Finding a 24-bit start code is similar, just use a 3 byte buffer. Remember that you must remove the video container with ffmpeg before doing this or you may destroy some of the container information.

这篇关于如何覆盖视频的I帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆