avformat/aadec: Avoid copying data around

Up until now, the packets have been read in blocks of at most
eight bytes at a time; then these blocks have been decrypted
and copied into a buffer on the stack (that was double the size
needed...). From there they have been copied to the dst packet.

This commit changes this: The data is read in one go; and
the decryption avoids temporary buffers, too, by making
use of the fact that src and dst of av_tea_crypt() can coincide.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt 2021-12-05 20:46:57 +01:00
parent 0a76f8217e
commit a0900a318a
1 changed files with 13 additions and 29 deletions

View File

@ -32,7 +32,6 @@
#include "libavutil/opt.h"
#define AA_MAGIC 1469084982 /* this identifies an audible .aa file */
#define MAX_CODEC_SECOND_SIZE 3982
#define MAX_TOC_ENTRIES 16
#define MAX_DICTIONARY_ENTRIES 128
#define TEA_BLOCK_SIZE 8
@ -247,13 +246,9 @@ static int aa_read_header(AVFormatContext *s)
static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
{
uint8_t dst[TEA_BLOCK_SIZE];
uint8_t src[TEA_BLOCK_SIZE];
int i;
int trailing_bytes;
int blocks;
uint8_t buf[MAX_CODEC_SECOND_SIZE * 2];
int written = 0;
uint8_t *buf;
int ret;
AADemuxContext *c = s->priv_data;
uint64_t pos = avio_tell(s->pb);
@ -272,7 +267,6 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_DEBUG, "Chapter %d (%" PRId64 " bytes)\n", c->chapter_idx, c->current_chapter_size);
c->chapter_idx = c->chapter_idx + 1;
avio_skip(s->pb, 4); // data start offset
pos += 8;
c->current_codec_second_size = c->codec_second_size;
}
@ -281,24 +275,18 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
c->current_codec_second_size = c->current_chapter_size % c->current_codec_second_size;
}
ret = av_get_packet(s->pb, pkt, c->current_codec_second_size);
if (ret != c->current_codec_second_size)
return AVERROR_EOF;
buf = pkt->data;
// decrypt c->current_codec_second_size bytes
// trailing bytes are left unencrypted!
blocks = c->current_codec_second_size / TEA_BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
ret = avio_read(s->pb, src, TEA_BLOCK_SIZE);
if (ret != TEA_BLOCK_SIZE)
return (ret < 0) ? ret : AVERROR_EOF;
av_tea_init(c->tea_ctx, c->file_key, 16);
av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 1);
memcpy(buf + written, dst, TEA_BLOCK_SIZE);
written = written + TEA_BLOCK_SIZE;
}
trailing_bytes = c->current_codec_second_size % TEA_BLOCK_SIZE;
if (trailing_bytes != 0) { // trailing bytes are left unencrypted!
ret = avio_read(s->pb, src, trailing_bytes);
if (ret != trailing_bytes)
return (ret < 0) ? ret : AVERROR_EOF;
memcpy(buf + written, src, trailing_bytes);
written = written + trailing_bytes;
av_tea_crypt(c->tea_ctx, buf, buf, 1, NULL, 1);
buf += TEA_BLOCK_SIZE;
}
// update state
@ -306,16 +294,12 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
if (c->current_chapter_size <= 0)
c->current_chapter_size = 0;
if (c->seek_offset > written)
if (c->seek_offset > c->current_codec_second_size)
c->seek_offset = 0; // ignore wrong estimate
ret = av_new_packet(pkt, written - c->seek_offset);
if (ret < 0)
return ret;
memcpy(pkt->data, buf + c->seek_offset, written - c->seek_offset);
pkt->pos = pos;
pkt->data += c->seek_offset;
pkt->size -= c->seek_offset;
c->seek_offset = 0;
return 0;
}