[FFmpeg-devel] Patch for libavformat/crypto to add seeking on read

Michael Niedermayer michael at niedermayer.cc
Tue Aug 30 03:10:20 EEST 2016


On Mon, Aug 29, 2016 at 09:56:59PM +0100, Simon H wrote:
> thanks Michael,
> 
> try the attached file.  I assume the corruption came from email word
> wrapping?

likely

> or was there something else wrong?
[...]

> example:
> take 25.mp4 created with:
> ffmpeg -f lavfi -i sine=frequency=1000:beep_factor=2:r=48000:duration=720.0 -f lavfi -i testsrc=duration=720.0:rate=25 -vcodec libx264 -cmp 22 -timecode 10:00:00:00 -r 25 -y out\25.mp4
>
> encrypt with:
> openssl enc -aes-128-cbc -K 12345678901234567890123456789012 -iv 12345678901234567890123456789012 -in 25.mp4 -out 25.enc
> then to transcode in ffmpeg:
> ffmpeg -key 12345678901234567890123456789012 -iv 12345678901234567890123456789012 -i crypto:25.enc -vcodec mpeg4 -r 25 -y 25dec.mp4
>
> prior to this modification, the transcode would fail.
> 
> Note also:  crypto previously marked both reads and writes as streamed, which caused the whole file
> to be read before the transcode started.  Now, for read only, if the underlying layer is not marked as streamed,
> then crypto is not.  This should enable efficient reading of encrypted containers which require seeking.
> ---
>  libavformat/crypto.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 112 insertions(+), 3 deletions(-)
> 
> diff --git a/libavformat/crypto.c b/libavformat/crypto.c
> index 2999f50..23bc0a6 100644
> --- a/libavformat/crypto.c
> +++ b/libavformat/crypto.c

> @@ -26,7 +26,8 @@
>  #include "internal.h"
>  #include "url.h"
>  
> -#define MAX_BUFFER_BLOCKS 150
> +// encourage reads of 4096 bytes - 1 block is always retained.
> +#define MAX_BUFFER_BLOCKS 257
>  #define BLOCKSIZE 16
>  
>  typedef struct CryptoContext {

this should be in a separate patch



> @@ -36,6 +37,8 @@ typedef struct CryptoContext {
>              outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS];
>      uint8_t *outptr;
>      int indata, indata_used, outdata;
> +    int64_t position;  // position in file - used in seek
> +    int flags;
>      int eof;
>      uint8_t *key;
>      int keylen;
> @@ -109,6 +112,7 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
>      const char *nested_url;
>      int ret = 0;
>      CryptoContext *c = h->priv_data;
> +    c->flags = flags;
>  
>      if (!av_strstart(uri, "crypto+", &nested_url) &&
>          !av_strstart(uri, "crypto:", &nested_url)) {
> @@ -117,6 +121,8 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
>          goto err;
>      }
>  
> +    c->position = 0L;
> +
>      if (flags & AVIO_FLAG_READ) {
>          if ((ret = set_aes_arg(c, &c->decrypt_key, &c->decrypt_keylen,
>                                 c->key, c->keylen, "decryption key")) < 0)
> @@ -152,6 +158,10 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
>          ret = av_aes_init(c->aes_decrypt, c->decrypt_key, BLOCKSIZE*8, 1);
>          if (ret < 0)
>              goto err;
> +
> +        // pass back information about the context we openned
> +        if (c->hd->is_streamed)
> +            h->is_streamed = c->hd->is_streamed;
>      }
>  
>      if (flags & AVIO_FLAG_WRITE) {
> @@ -163,12 +173,13 @@ static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary
>          ret = av_aes_init(c->aes_encrypt, c->encrypt_key, BLOCKSIZE*8, 0);
>          if (ret < 0)
>              goto err;
> +        // for write, we must be streamed
> +        // - linear write only for crytpo aes-128-cbc
> +        h->is_streamed = 1;
>      }
>  
>      c->pad_len = 0;
>  
> -    h->is_streamed = 1;
> -
>  err:
>      return ret;
>  }
> @@ -183,6 +194,7 @@ retry:
>          memcpy(buf, c->outptr, size);
>          c->outptr  += size;
>          c->outdata -= size;
> +        c->position = c->position + size;
>          return size;
>      }
>      // We avoid using the last block until we've found EOF,

> @@ -222,6 +234,102 @@ retry:
>      goto retry;
>  }
>  
> +static int64_t crypto_seek(URLContext *h, int64_t pos, int whence)
> +{
> +    CryptoContext *c = h->priv_data;
> +    int64_t block;
> +    int64_t newpos;
> +
> +    if (c->flags & AVIO_FLAG_WRITE) {
> +        av_log(h, AV_LOG_ERROR,
> +            "Crypto: seek not supported for write\r\n");
> +        return -1L;

should be a AVERROR* code



> +    }
> +
> +    // reset eof, else we won't read it correctly if we already hit eof.
> +    c->eof = 0;
> +
> +    switch (whence) {
> +    case SEEK_SET:
> +        break;
> +    case SEEK_CUR:
> +        pos = pos + c->position;
> +        break;
> +    case SEEK_END: {
> +        int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE );
> +        if (newpos < 0) {

> +            av_log(h, AV_LOG_ERROR,
> +                "Crypto: seek_end - can't get file size (pos=%lld)\r\n", pos);

libavformat/crypto.c: In function ‘crypto_seek’:
libavformat/crypto.c:262:17: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 4 has type ‘int64_t’ [-Wformat]


> +            return newpos;
> +        }
> +        pos = newpos - pos;
> +        }
> +        break;
> +    case AVSEEK_SIZE:

> +        return ffurl_seek( c->hd, pos, AVSEEK_SIZE );

please use the same formating as the surrounding code


> +    default:
> +        av_log(h, AV_LOG_ERROR,
> +            "Crypto: no support for seek where 'whence' is %d\r\n", whence);
> +        return -1L;
> +    }
> +
> +    c->outdata = 0;
> +    c->indata = 0;
> +    c->indata_used = 0;
> +    c->outptr = c->outbuffer;
> +
> +    // identify the block containing the IV for the
> +    // next block we will decrypt

> +    block = pos/16L;

many of the L suffixes are unneeded

thx

[...]


-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Let us carefully observe those good qualities wherein our enemies excel us
and endeavor to excel them, by avoiding what is faulty, and imitating what
is excellent in them. -- Plutarch
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160830/0852f377/attachment.sig>


More information about the ffmpeg-devel mailing list