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>
pull/298/head
Jacob Trimble 7 years ago committed by Michael Niedermayer
parent 3717512282
commit f7221d8e67
  1. 14
      libavformat/isom.h
  2. 384
      libavformat/mov.c
  3. 2
      libavutil/encryption_info.h
  4. 8
      tests/fate/mov.mak
  5. 57
      tests/ref/fate/mov-frag-encrypted
  6. 57
      tests/ref/fate/mov-tenc-only-encrypted

@ -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;

@ -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;
}
static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
/**
* 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;
MOVStreamContext *sc;
size_t auxiliary_info_size;
int i;
if (c->decryption_key_len == 0 || c->fc->nb_streams < 1)
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;
*sc = st->priv_data;
if (sc->cenc.aes_ctr) {
av_log(c->fc, AV_LOG_ERROR, "duplicate senc atom\n");
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;
}
}
avio_r8(pb); /* version */
sc->cenc.use_subsamples = avio_rb24(pb) & 0x02; /* flags */
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);
}
avio_rb32(pb); /* entries */
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 (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);
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)
{
AVEncryptionInfo **encrypted_samples;
MOVEncryptionIndex *encryption_index;
MOVStreamContext *sc;
int use_subsamples, ret;
unsigned int sample_count, i, alloc_size = 0;
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;
}
/* save the auxiliary info as is */
auxiliary_info_size = atom.size - 8;
avio_r8(pb); /* version */
use_subsamples = avio_rb24(pb) & 0x02; /* flags */
sc->cenc.auxiliary_info = av_malloc(auxiliary_info_size);
if (!sc->cenc.auxiliary_info) {
sample_count = avio_rb32(pb);
if (sample_count >= INT_MAX / sizeof(*encrypted_samples))
return AVERROR(ENOMEM);
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;
}
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 (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;
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 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);
}
}
/* initialize the cipher */
sc->cenc.aes_ctr = av_aes_ctr_alloc();
if (!sc->cenc.aes_ctr) {
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;
return av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
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;
}
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;
}
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;
}
}
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 (ret < 0) {
return ret;
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);
}
/* 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;
ret = av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
if (ret < 0) {
return ret;
}
}
av_aes_ctr_set_iv(sc->cenc.aes_ctr, sc->cenc.auxiliary_info_pos);
sc->cenc.auxiliary_info_pos += AES_CTR_IV_SIZE;
av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv);
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");
for (i = 0; i < sample->subsample_count; i++)
{
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;
}
subsample_count = AV_RB16(sc->cenc.auxiliary_info_pos);
sc->cenc.auxiliary_info_pos += sizeof(uint16_t);
/* skip the clear bytes */
input += sample->subsamples[i].bytes_of_clear_data;
size -= sample->subsamples[i].bytes_of_clear_data;
for (; subsample_count > 0; subsample_count--)
{
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;
/* decrypt the 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;
}
/* 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) {
av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
if (size > 0) {
av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
return AVERROR_INVALIDDATA;
}
/* skip the clear bytes */
input += clear_bytes;
return 0;
}
/* decrypt the encrypted bytes */
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, encrypted_bytes);
input += encrypted_bytes;
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 (input < input_end) {
av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
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;
}
sc->cenc.auxiliary_info_index++;
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) {
ret = cenc_filter(mov, sc, pkt, current_index);
if (ret < 0)
return ret;
}
}
return 0;
}

@ -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;
/**

@ -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

@ -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

@ -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
Loading…
Cancel
Save