1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

avformat/mov: Increase support for common encryption.

- Parse schm atom to get different encryption schemes.
- Allow senc atom to appear in track fragments.
- Allow 16-byte IVs.
- Allow constant IVs (specified in tenc).
- Allow only tenc to specify encryption (i.e. no senc/saiz/saio).
- Use sample descriptor to detect clear fragments.

This doesn't support:
- Different sample descriptor holding different encryption info.
  - Only first sample descriptor can be encrypted.
- Encrypted sample groups (i.e. seig).
- Non-'cenc' encryption scheme when using -decryption_key.

Signed-off-by: Jacob Trimble <modmaker@google.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Jacob Trimble 2017-12-06 16:17:54 -08:00 committed by Michael Niedermayer
parent 3717512282
commit f7221d8e67
6 changed files with 457 additions and 89 deletions

View File

@ -27,6 +27,7 @@
#include <stddef.h>
#include <stdint.h>
#include "libavutil/encryption_info.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/spherical.h"
#include "libavutil/stereo3d.h"
@ -108,12 +109,20 @@ typedef struct MOVSbgp {
unsigned int index;
} MOVSbgp;
typedef struct MOVEncryptionIndex {
// Individual encrypted samples. If there are no elements, then the default
// settings will be used.
unsigned int nb_encrypted_samples;
AVEncryptionInfo **encrypted_samples;
} MOVEncryptionIndex;
typedef struct MOVFragmentStreamInfo {
int id;
int64_t sidx_pts;
int64_t first_tfra_pts;
int64_t tfdt_dts;
int index_entry;
MOVEncryptionIndex *encryption_index;
} MOVFragmentStreamInfo;
typedef struct MOVFragmentIndexItem {
@ -215,6 +224,7 @@ typedef struct MOVStreamContext {
int has_sidx; // If there is an sidx entry for this stream.
struct {
// TODO: Remove once old methods are removed from mov.c
int use_subsamples;
uint8_t* auxiliary_info;
uint8_t* auxiliary_info_end;
@ -223,7 +233,11 @@ typedef struct MOVStreamContext {
uint8_t* auxiliary_info_sizes;
size_t auxiliary_info_sizes_count;
int64_t auxiliary_info_index;
struct AVAESCTR* aes_ctr;
unsigned int per_sample_iv_size; // Either 0, 8, or 16.
AVEncryptionInfo *default_encrypted_sample;
MOVEncryptionIndex *encryption_index;
} cenc;
} MOVStreamContext;

View File

@ -1330,6 +1330,7 @@ static int update_frag_index(MOVContext *c, int64_t offset)
frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE;
frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE;
frag_stream_info[i].index_entry = -1;
frag_stream_info[i].encryption_index = NULL;
}
if (index < c->frag_index.nb_items)
@ -5761,57 +5762,250 @@ static int mov_read_frma(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
/**
* Gets the current encryption info and associated current stream context. If
* we are parsing a track fragment, this will return the specific encryption
* info for this fragment; otherwise this will return the global encryption
* info for the current stream.
*/
static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encryption_index, MOVStreamContext **sc)
{
MOVFragmentStreamInfo *frag_stream_info;
AVStream *st;
int i;
frag_stream_info = get_current_frag_stream_info(&c->frag_index);
if (frag_stream_info) {
for (i = 0; i < c->fc->nb_streams; i++) {
if (c->fc->streams[i]->id == frag_stream_info->id) {
st = c->fc->streams[i];
break;
}
}
if (i == c->fc->nb_streams)
return 0;
*sc = st->priv_data;
if (!frag_stream_info->encryption_index) {
frag_stream_info->encryption_index = av_mallocz(sizeof(*frag_stream_info->encryption_index));
if (!frag_stream_info->encryption_index)
return AVERROR(ENOMEM);
}
*encryption_index = frag_stream_info->encryption_index;
return 1;
} else {
// No current track fragment, using stream level encryption info.
if (c->fc->nb_streams < 1)
return 0;
st = c->fc->streams[c->fc->nb_streams - 1];
*sc = st->priv_data;
if (!(*sc)->cenc.encryption_index) {
(*sc)->cenc.encryption_index = av_mallocz(sizeof(*frag_stream_info->encryption_index));
if (!(*sc)->cenc.encryption_index)
return AVERROR(ENOMEM);
}
*encryption_index = (*sc)->cenc.encryption_index;
return 1;
}
}
static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVStreamContext *sc, AVEncryptionInfo **sample, int use_subsamples)
{
int i;
unsigned int subsample_count;
AVSubsampleEncryptionInfo *subsamples;
*sample = av_encryption_info_clone(sc->cenc.default_encrypted_sample);
if (!*sample)
return AVERROR(ENOMEM);
if (sc->cenc.per_sample_iv_size != 0) {
if (avio_read(pb, (*sample)->iv, sc->cenc.per_sample_iv_size) != sc->cenc.per_sample_iv_size) {
av_log(c->fc, AV_LOG_ERROR, "failed to read the initialization vector\n");
av_encryption_info_free(*sample);
*sample = NULL;
return AVERROR_INVALIDDATA;
}
}
if (use_subsamples) {
subsample_count = avio_rb16(pb);
(*sample)->subsamples = av_mallocz_array(subsample_count, sizeof(*subsamples));
if (!(*sample)->subsamples) {
av_encryption_info_free(*sample);
*sample = NULL;
return AVERROR(ENOMEM);
}
for (i = 0; i < subsample_count && !pb->eof_reached; i++) {
(*sample)->subsamples[i].bytes_of_clear_data = avio_rb16(pb);
(*sample)->subsamples[i].bytes_of_protected_data = avio_rb32(pb);
}
if (pb->eof_reached) {
av_log(c->fc, AV_LOG_ERROR, "hit EOF while reading sub-sample encryption info\n");
av_encryption_info_free(*sample);
*sample = NULL;
return AVERROR_INVALIDDATA;
}
(*sample)->subsample_count = subsample_count;
}
return 0;
}
static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
AVEncryptionInfo **encrypted_samples;
MOVEncryptionIndex *encryption_index;
MOVStreamContext *sc;
size_t auxiliary_info_size;
int use_subsamples, ret;
unsigned int sample_count, i, alloc_size = 0;
if (c->decryption_key_len == 0 || c->fc->nb_streams < 1)
ret = get_current_encryption_info(c, &encryption_index, &sc);
if (ret != 1)
return ret;
if (encryption_index->nb_encrypted_samples) {
// This can happen if we have both saio/saiz and senc atoms.
av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in senc\n");
return 0;
st = c->fc->streams[c->fc->nb_streams - 1];
sc = st->priv_data;
if (sc->cenc.aes_ctr) {
av_log(c->fc, AV_LOG_ERROR, "duplicate senc atom\n");
return AVERROR_INVALIDDATA;
}
avio_r8(pb); /* version */
sc->cenc.use_subsamples = avio_rb24(pb) & 0x02; /* flags */
use_subsamples = avio_rb24(pb) & 0x02; /* flags */
avio_rb32(pb); /* entries */
sample_count = avio_rb32(pb);
if (sample_count >= INT_MAX / sizeof(*encrypted_samples))
return AVERROR(ENOMEM);
if (atom.size < 8 || atom.size > FFMIN(INT_MAX, SIZE_MAX)) {
av_log(c->fc, AV_LOG_ERROR, "senc atom size %"PRId64" invalid\n", atom.size);
for (i = 0; i < sample_count; i++) {
unsigned int min_samples = FFMIN(FFMAX(i, 1024 * 1024), sample_count);
encrypted_samples = av_fast_realloc(encryption_index->encrypted_samples, &alloc_size,
min_samples * sizeof(*encrypted_samples));
if (encrypted_samples) {
encryption_index->encrypted_samples = encrypted_samples;
ret = mov_read_sample_encryption_info(
c, pb, sc, &encryption_index->encrypted_samples[i], use_subsamples);
} else {
ret = AVERROR(ENOMEM);
}
if (pb->eof_reached) {
av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading senc\n");
ret = AVERROR_INVALIDDATA;
}
if (ret < 0) {
for (; i > 0; i--)
av_encryption_info_free(encryption_index->encrypted_samples[i - 1]);
av_freep(&encryption_index->encrypted_samples);
return ret;
}
}
encryption_index->nb_encrypted_samples = sample_count;
return 0;
}
static int mov_read_schm(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
MOVStreamContext *sc;
if (c->fc->nb_streams < 1)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
sc = st->priv_data;
if (sc->pseudo_stream_id != 0) {
av_log(c->fc, AV_LOG_ERROR, "schm boxes are only supported in first sample descriptor\n");
return AVERROR_PATCHWELCOME;
}
if (atom.size < 8)
return AVERROR_INVALIDDATA;
avio_rb32(pb); /* version and flags */
if (!sc->cenc.default_encrypted_sample) {
sc->cenc.default_encrypted_sample = av_encryption_info_alloc(0, 16, 16);
if (!sc->cenc.default_encrypted_sample) {
return AVERROR(ENOMEM);
}
}
sc->cenc.default_encrypted_sample->scheme = avio_rb32(pb);
return 0;
}
static int mov_read_tenc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
MOVStreamContext *sc;
unsigned int version, pattern, is_protected, iv_size;
if (c->fc->nb_streams < 1)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
sc = st->priv_data;
if (sc->pseudo_stream_id != 0) {
av_log(c->fc, AV_LOG_ERROR, "tenc atom are only supported in first sample descriptor\n");
return AVERROR_PATCHWELCOME;
}
if (!sc->cenc.default_encrypted_sample) {
sc->cenc.default_encrypted_sample = av_encryption_info_alloc(0, 16, 16);
if (!sc->cenc.default_encrypted_sample) {
return AVERROR(ENOMEM);
}
}
if (atom.size < 20)
return AVERROR_INVALIDDATA;
version = avio_r8(pb); /* version */
avio_rb24(pb); /* flags */
avio_r8(pb); /* reserved */
pattern = avio_r8(pb);
if (version > 0) {
sc->cenc.default_encrypted_sample->crypt_byte_block = pattern >> 4;
sc->cenc.default_encrypted_sample->skip_byte_block = pattern & 0xf;
}
is_protected = avio_r8(pb);
if (is_protected && !sc->cenc.encryption_index) {
// The whole stream should be by-default encrypted.
sc->cenc.encryption_index = av_mallocz(sizeof(MOVEncryptionIndex));
if (!sc->cenc.encryption_index)
return AVERROR(ENOMEM);
}
sc->cenc.per_sample_iv_size = avio_r8(pb);
if (avio_read(pb, sc->cenc.default_encrypted_sample->key_id, 16) != 16) {
av_log(c->fc, AV_LOG_ERROR, "failed to read the default key ID");
return AVERROR_INVALIDDATA;
}
/* save the auxiliary info as is */
auxiliary_info_size = atom.size - 8;
if (is_protected && !sc->cenc.per_sample_iv_size) {
iv_size = avio_r8(pb);
if (iv_size != 8 && iv_size != 16) {
av_log(c->fc, AV_LOG_ERROR, "invalid default_constant_IV_size in tenc atom\n");
return AVERROR_INVALIDDATA;
}
sc->cenc.auxiliary_info = av_malloc(auxiliary_info_size);
if (!sc->cenc.auxiliary_info) {
return AVERROR(ENOMEM);
if (avio_read(pb, sc->cenc.default_encrypted_sample->iv, iv_size) != iv_size) {
av_log(c->fc, AV_LOG_ERROR, "failed to read the default IV");
return AVERROR_INVALIDDATA;
}
}
sc->cenc.auxiliary_info_end = sc->cenc.auxiliary_info + auxiliary_info_size;
sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info;
sc->cenc.auxiliary_info_index = 0;
if (avio_read(pb, sc->cenc.auxiliary_info, auxiliary_info_size) != auxiliary_info_size) {
av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info");
return AVERROR_INVALIDDATA;
}
/* initialize the cipher */
sc->cenc.aes_ctr = av_aes_ctr_alloc();
if (!sc->cenc.aes_ctr) {
return AVERROR(ENOMEM);
}
return av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
return 0;
}
static int mov_read_saiz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@ -5942,78 +6136,103 @@ static int mov_seek_auxiliary_info(MOVContext *c, MOVStreamContext *sc, int64_t
return 0;
}
static int cenc_filter(MOVContext *c, MOVStreamContext *sc, int64_t index, uint8_t *input, int size)
static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size)
{
uint32_t encrypted_bytes;
uint16_t subsample_count;
uint16_t clear_bytes;
uint8_t* input_end = input + size;
int ret;
int i, ret;
if (index != sc->cenc.auxiliary_info_index) {
ret = mov_seek_auxiliary_info(c, sc, index);
if (sample->scheme != MKBETAG('c','e','n','c') || sample->crypt_byte_block != 0 || sample->skip_byte_block != 0) {
av_log(c->fc, AV_LOG_ERROR, "Only the 'cenc' encryption scheme is supported\n");
return AVERROR_PATCHWELCOME;
}
if (!sc->cenc.aes_ctr) {
/* initialize the cipher */
sc->cenc.aes_ctr = av_aes_ctr_alloc();
if (!sc->cenc.aes_ctr) {
return AVERROR(ENOMEM);
}
ret = av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
if (ret < 0) {
return ret;
}
}
/* read the iv */
if (AES_CTR_IV_SIZE > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
av_log(c->fc, AV_LOG_ERROR, "failed to read iv from the auxiliary info\n");
return AVERROR_INVALIDDATA;
}
av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv);
av_aes_ctr_set_iv(sc->cenc.aes_ctr, sc->cenc.auxiliary_info_pos);
sc->cenc.auxiliary_info_pos += AES_CTR_IV_SIZE;
if (!sc->cenc.use_subsamples)
if (!sample->subsample_count)
{
/* decrypt the whole packet */
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size);
return 0;
}
/* read the subsample count */
if (sizeof(uint16_t) > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
av_log(c->fc, AV_LOG_ERROR, "failed to read subsample count from the auxiliary info\n");
return AVERROR_INVALIDDATA;
}
subsample_count = AV_RB16(sc->cenc.auxiliary_info_pos);
sc->cenc.auxiliary_info_pos += sizeof(uint16_t);
for (; subsample_count > 0; subsample_count--)
for (i = 0; i < sample->subsample_count; i++)
{
if (6 > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
av_log(c->fc, AV_LOG_ERROR, "failed to read subsample from the auxiliary info\n");
return AVERROR_INVALIDDATA;
}
/* read the number of clear / encrypted bytes */
clear_bytes = AV_RB16(sc->cenc.auxiliary_info_pos);
sc->cenc.auxiliary_info_pos += sizeof(uint16_t);
encrypted_bytes = AV_RB32(sc->cenc.auxiliary_info_pos);
sc->cenc.auxiliary_info_pos += sizeof(uint32_t);
if ((uint64_t)clear_bytes + encrypted_bytes > input_end - input) {
if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
return AVERROR_INVALIDDATA;
}
/* skip the clear bytes */
input += clear_bytes;
input += sample->subsamples[i].bytes_of_clear_data;
size -= sample->subsamples[i].bytes_of_clear_data;
/* decrypt the encrypted bytes */
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, encrypted_bytes);
input += encrypted_bytes;
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, sample->subsamples[i].bytes_of_protected_data);
input += sample->subsamples[i].bytes_of_protected_data;
size -= sample->subsamples[i].bytes_of_protected_data;
}
if (input < input_end) {
if (size > 0) {
av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
return AVERROR_INVALIDDATA;
}
sc->cenc.auxiliary_info_index++;
return 0;
}
static int cenc_filter(MOVContext *mov, MOVStreamContext *sc, AVPacket *pkt, int current_index)
{
MOVFragmentStreamInfo *frag_stream_info;
MOVEncryptionIndex *encryption_index;
AVEncryptionInfo *encrypted_sample;
int encrypted_index;
frag_stream_info = get_current_frag_stream_info(&mov->frag_index);
encrypted_index = current_index;
encryption_index = NULL;
if (frag_stream_info) {
// Note this only supports encryption info in the first sample descriptor.
if (mov->fragment.stsd_id == 1) {
if (frag_stream_info->encryption_index) {
encrypted_index = current_index - frag_stream_info->index_entry;
encryption_index = frag_stream_info->encryption_index;
} else {
encryption_index = sc->cenc.encryption_index;
}
}
} else {
encryption_index = sc->cenc.encryption_index;
}
if (encryption_index) {
if (!encryption_index->nb_encrypted_samples) {
// Full-sample encryption with default settings.
encrypted_sample = sc->cenc.default_encrypted_sample;
} else if (encrypted_index >= 0 && encrypted_index < encryption_index->nb_encrypted_samples) {
// Per-sample setting override.
encrypted_sample = encryption_index->encrypted_samples[encrypted_index];
} else {
av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info\n");
return AVERROR_INVALIDDATA;
}
if (mov->decryption_key) {
return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size);
}
}
return 0;
}
@ -6142,7 +6361,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('s','i','n','f'), mov_read_default },
{ MKTAG('f','r','m','a'), mov_read_frma },
{ MKTAG('s','e','n','c'), mov_read_senc },
{ MKTAG('s','a','i','z'), mov_read_saiz },
{ MKTAG('s','c','h','m'), mov_read_schm },
{ MKTAG('s','c','h','i'), mov_read_default },
{ MKTAG('t','e','n','c'), mov_read_tenc },
{ MKTAG('d','f','L','a'), mov_read_dfla },
{ MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */
{ MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */
@ -6528,6 +6749,16 @@ static int mov_read_timecode_track(AVFormatContext *s, AVStream *st)
return 0;
}
static void mov_free_encryption_index(MOVEncryptionIndex **index) {
int i;
if (!index || !*index) return;
for (i = 0; i < (*index)->nb_encrypted_samples; i++) {
av_encryption_info_free((*index)->encrypted_samples[i]);
}
av_freep(&(*index)->encrypted_samples);
av_freep(index);
}
static int mov_read_close(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
@ -6570,8 +6801,8 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->extradata);
av_freep(&sc->extradata_size);
av_freep(&sc->cenc.auxiliary_info);
av_freep(&sc->cenc.auxiliary_info_sizes);
mov_free_encryption_index(&sc->cenc.encryption_index);
av_encryption_info_free(sc->cenc.default_encrypted_sample);
av_aes_ctr_free(sc->cenc.aes_ctr);
av_freep(&sc->stereo3d);
@ -6596,6 +6827,10 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&mov->bitrates);
for (i = 0; i < mov->frag_index.nb_items; i++) {
MOVFragmentStreamInfo *frag = mov->frag_index.item[i].stream_info;
for (j = 0; j < mov->frag_index.item[i].nb_stream_info; j++) {
mov_free_encryption_index(&frag[j].encryption_index);
}
av_freep(&mov->frag_index.item[i].stream_info);
}
av_freep(&mov->frag_index.item);
@ -7166,12 +7401,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
if (mov->aax_mode)
aax_filter(pkt->data, pkt->size, mov);
if (sc->cenc.aes_ctr) {
ret = cenc_filter(mov, sc, current_index, pkt->data, pkt->size);
if (ret) {
return ret;
}
}
ret = cenc_filter(mov, sc, pkt, current_index);
if (ret < 0)
return ret;
return 0;
}

View File

@ -41,7 +41,7 @@ typedef struct AVSubsampleEncryptionInfo {
* The size of this struct is not part of the public ABI.
*/
typedef struct AVEncryptionInfo {
/** The fourcc encryption scheme. */
/** The fourcc encryption scheme, in big-endian byte order. */
uint32_t scheme;
/**

View File

@ -6,6 +6,8 @@ FATE_MOV = fate-mov-3elist \
fate-mov-1elist-ends-last-bframe \
fate-mov-2elist-elist1-ends-bframe \
fate-mov-3elist-encrypted \
fate-mov-frag-encrypted \
fate-mov-tenc-only-encrypted \
fate-mov-invalid-elst-entry-count \
fate-mov-gpmf-remux \
fate-mov-440hz-10ms \
@ -39,6 +41,12 @@ fate-mov-3elist-1ctts: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-3elist-1ctts.
# Edit list with encryption
fate-mov-3elist-encrypted: CMD = framemd5 -decryption_key 12345678901234567890123456789012 -i $(TARGET_SAMPLES)/mov/mov-3elist-encrypted.mov
# Fragmented encryption with senc boxes in movie fragments.
fate-mov-frag-encrypted: CMD = framemd5 -decryption_key 12345678901234567890123456789012 -i $(TARGET_SAMPLES)/mov/mov-frag-encrypted.mp4
# Full-sample encryption and constant IV using only tenc atom (no senc/saio/saiz).
fate-mov-tenc-only-encrypted: CMD = framemd5 -decryption_key 12345678901234567890123456789012 -i $(TARGET_SAMPLES)/mov/mov-tenc-only-encrypted.mp4
# Makes sure that the CTTS is also modified when we fix avindex in mov.c while parsing edit lists.
fate-mov-elist-starts-ctts-2ndsample: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-elist-starts-ctts-2ndsample.mov

View File

@ -0,0 +1,57 @@
#format: frame checksums
#version: 2
#hash: MD5
#tb 0: 1/24
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 120x52
#sar 0: 544/545
#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 9360, 920bdc277a6a31c1daed9aca44b10caf
0, 1, 1, 1, 9360, f1c0b61fef593de57cb97be7fa846569
0, 2, 2, 1, 9360, 6ef32d9d4398355aebf6d3fb11d51d3f
0, 3, 3, 1, 9360, d38fd3ef1e5a92fc109b8dd9eb6dadeb
0, 4, 4, 1, 9360, 54cc0c8a25d2f14f32663837d5e646f1
0, 5, 5, 1, 9360, b4b6829726dc3decb8b80ba0c35bcf30
0, 6, 6, 1, 9360, fca3f941e60a2f0a4ce30d5e0efbec3c
0, 7, 7, 1, 9360, cda6e26b6c1039ff3d229b262c9210c3
0, 8, 8, 1, 9360, f0d69255e3a27a8b4ae8a4b7b210929d
0, 9, 9, 1, 9360, 12cb23dd4e32af9c3b35f943714e3fdd
0, 10, 10, 1, 9360, 082aaf3216124ddcecb422fe5c832e82
0, 11, 11, 1, 9360, ff37bb8cd6bd0412a3b3cb45db54afc9
0, 12, 12, 1, 9360, dfb9085441575732844b6c2f05d5f542
0, 13, 13, 1, 9360, 0017100feaaa9fc7eacd2447d50d7542
0, 14, 14, 1, 9360, 4e2f1b8c4e04c59934c2f58541e62613
0, 15, 15, 1, 9360, 27a44dfea7cd2d30e488194c34ab473c
0, 16, 16, 1, 9360, fc7b56bd95e990a33cf575d1ef820902
0, 17, 17, 1, 9360, fa2d1609e69714dffc410e65f3c8b755
0, 18, 18, 1, 9360, 705d7429f447cb13febe202d567795f2
0, 19, 19, 1, 9360, 234802ce86e868faaf2cd40a286846ea
0, 20, 20, 1, 9360, 2f0354b40d211d0a4ade4568bea4f85e
0, 21, 21, 1, 9360, e96af3b6c0cc931463ca77d6be0f1148
0, 22, 22, 1, 9360, 04a904d798361959971361401879c7e4
0, 23, 23, 1, 9360, 2f119642340df6d25362b5590ded46b7
0, 24, 24, 1, 9360, 5993fca2e60050706f857ac76e48f386
0, 25, 25, 1, 9360, 2ff3b5775fed3d527bfbbeea786787fe
0, 26, 26, 1, 9360, 42024dbe23d3fb5b0d8987ae1ce390a8
0, 27, 27, 1, 9360, d804204f0bd9db5f6a758e2c934d9e38
0, 28, 28, 1, 9360, e322712e6e34c58ec1a2ab5e2c1e3bfe
0, 29, 29, 1, 9360, 3975bd1a5f6a6b6260276777f9de611e
0, 30, 30, 1, 9360, 4388f0412efc6310706a7cdedc859ea9
0, 31, 31, 1, 9360, b4b9a11b0b86635267345a569640e8d4
0, 32, 32, 1, 9360, 31879c7b8d6b67a4209ffde786bb8cb4
0, 33, 33, 1, 9360, 4b6dc02d7c889fe4abd4e013b25f585a
0, 34, 34, 1, 9360, dc73aae82bd39a1220d1106c8d3e8252
0, 35, 35, 1, 9360, 54c7dfbd49f312806f6c1a89f7c2c36f
0, 36, 36, 1, 9360, 150abc64f8994d444a521ea90570443c
0, 37, 37, 1, 9360, d277cdc7dcadbe0016f2e950459e7ebf
0, 38, 38, 1, 9360, 2196bf338ead90ea54687b85c73c8229
0, 39, 39, 1, 9360, 53ce5da5365abc0bd3217dd98e7c465d
0, 40, 40, 1, 9360, 34ee9832aea55c0c4e6f4381c413c10e
0, 41, 41, 1, 9360, 1769c7b5849e4681119067a06ac29a4f
0, 42, 42, 1, 9360, 71f53df739ef283a5184c91ef4b158e8
0, 43, 43, 1, 9360, d2d394739e9a59c06f0354c16843cb63
0, 44, 44, 1, 9360, d8e458e92ae29344505a24a3059fc584
0, 45, 45, 1, 9360, 0f1b11a09911851b798df2ef76253a7f
0, 46, 46, 1, 9360, 5c4a9f22baecf4e749c0d5c65a4f1007
0, 47, 47, 1, 9360, 3e2b7e7262fdca08d9d1ef6070125c4b

View File

@ -0,0 +1,57 @@
#format: frame checksums
#version: 2
#hash: MD5
#tb 0: 1/24
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 1024x436
#sar 0: 1/1
#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 669696, f48f296a85eda5ba069dc851a3228bef
0, 1, 1, 1, 669696, a50c5f69bfa3387d49b5bdf738e6529c
0, 2, 2, 1, 669696, 05061299003760f6a4795b408f72aa31
0, 3, 3, 1, 669696, 2572119f0b0cdd83f8a7e06252cecd3b
0, 4, 4, 1, 669696, 29fe6a6bdb4a69018e318886a297f07e
0, 5, 5, 1, 669696, e8233c7fbaecfbff965c7dfdd3982b1b
0, 6, 6, 1, 669696, d9259df9880ff5d4a4b38282e67f407b
0, 7, 7, 1, 669696, 3e8d795195038993503ea9ab6984c915
0, 8, 8, 1, 669696, bc4e2d253b715a34f85aae1b080e3460
0, 9, 9, 1, 669696, 09aba8b3a96f53f9268e7420a10bfab6
0, 10, 10, 1, 669696, 179447977dd580da8b35fb5310a809ca
0, 11, 11, 1, 669696, 7a0eea9d54577990345f5705ab9882be
0, 12, 12, 1, 669696, 5bb96eb76f461825740e5938456df759
0, 13, 13, 1, 669696, bd4ac4a760ead774b9422a27dc071964
0, 14, 14, 1, 669696, 1cc05f760a9b751fc89e77f2bcc97259
0, 15, 15, 1, 669696, 825d0dee6f0174ba7102892c7de30b4d
0, 16, 16, 1, 669696, d26a2ef5267f6bb03c4e1d8514eee0df
0, 17, 17, 1, 669696, c916ffdeadca76596a8f7fd47914b5ef
0, 18, 18, 1, 669696, 6e085acfa7fee0658ea0ae6188274c17
0, 19, 19, 1, 669696, 1e95fa5b3561283f05bf0bd44cb91721
0, 20, 20, 1, 669696, 37e3d135aba9dfb8b87e441753115374
0, 21, 21, 1, 669696, 9c398310e8564491de624393c16265ce
0, 22, 22, 1, 669696, c87209e4d2617bc2ab40a75f455f09da
0, 23, 23, 1, 669696, 2679c2f8d1d1af21982e245945c1ee60
0, 24, 24, 1, 669696, 6151ab4781f31c5beb66b356ad547122
0, 25, 25, 1, 669696, f7ef6293bfb3a6a329061cb6a5ed5a38
0, 26, 26, 1, 669696, 2f6e666d14dfc407ca0c0f347b13eb08
0, 27, 27, 1, 669696, 3454fa1730d79b1aa8dbbc865dc150f4
0, 28, 28, 1, 669696, e93dc683e2453419a0419ab9af0f8f95
0, 29, 29, 1, 669696, 031eb3154f7f83cf86d42bee66be9cf7
0, 30, 30, 1, 669696, 1205c36723e88811206c68892d3aaed6
0, 31, 31, 1, 669696, 7dd7a8a19dcd73b31ddc6a6d0c597a42
0, 32, 32, 1, 669696, 7c91115368ea2531262a1197468bc3f4
0, 33, 33, 1, 669696, 3cf6d9ba385e0fff76da33299ed5380c
0, 34, 34, 1, 669696, 859fc8c3ef049e3c1175a85fb0a90a3d
0, 35, 35, 1, 669696, 1d09ce6c7027103d99a4d5799f6e72ab
0, 36, 36, 1, 669696, 3dcb8357408ac88abd734128d8f5dd6f
0, 37, 37, 1, 669696, 4dafce137a0a5178f6efaec878e64d36
0, 38, 38, 1, 669696, 44c478f29a1399ed03275a7357f57d48
0, 39, 39, 1, 669696, 6e9edaac7414c0e14591ac3d4d0b1ac4
0, 40, 40, 1, 669696, 522e4aaeea0825da27f631a9e690d654
0, 41, 41, 1, 669696, 85f2502a718440834c40051d30f8a65e
0, 42, 42, 1, 669696, ae8816f7bd4645ef1a17ee6d09b4c8d2
0, 43, 43, 1, 669696, 914b006fa92f1eb3e590245749f6810d
0, 44, 44, 1, 669696, 9406901542e94c429dff46108782ed69
0, 45, 45, 1, 669696, 324c13641c39eef5c476023e358c0391
0, 46, 46, 1, 669696, 4058e886e17c22e4eb9da1dd0d6ad891
0, 47, 47, 1, 669696, 9edf9cd15eea985b42fd1f5035b1d693