[FFmpeg-devel] [PATCH] aadec: alternate mp3 seek handling
Karsten Otto
ottoka at posteo.de
Wed Aug 8 11:41:02 EEST 2018
Ping. Any thoughts on this?
Cheers, Karsten
> Am 31.07.2018 um 21:16 schrieb Karsten Otto <ottoka at posteo.de>:
>
> After seeking, determine the offset of the next frame in the decrypted
> buffer by scanning the first few bytes for a valid mp3 header.
> This significantly improves the listening experience for audio content
> with untypical encoding.
> ---
> This is a refinement of an earlier patch iteration, according to lessons
> learned and discussions on the mailing list: Scan a limited range to find
> the first shifted frame only, check for a very specific bit pattern, and
> add extra checks and guards for better code maintainability.
>
> Unfortunately, this variant violates the architectural layering between
> demuxer and codec. But I did some more testing with untypical encodings,
> where the current estimation mechanism fails, and the resulting audio on
> seek was just too horribly annoying.
>
> I believe the better listening experience outweighs the architectural
> uglyness, so this should be in the official code base. But if you think
> otherwise, just let me know, and I will keep this a private patch.
>
> libavformat/aadec.c | 45 ++++++++++++++++++++++++++++-----------------
> 1 file changed, 28 insertions(+), 17 deletions(-)
>
> diff --git a/libavformat/aadec.c b/libavformat/aadec.c
> index d83f283ffe..9b1495c218 100644
> --- a/libavformat/aadec.c
> +++ b/libavformat/aadec.c
> @@ -37,7 +37,7 @@
> #define TEA_BLOCK_SIZE 8
> #define CHAPTER_HEADER_SIZE 8
> #define TIMEPREC 1000
> -#define MP3_FRAME_SIZE 104
> +#define MP3_FRAME_SIZE 105
>
> typedef struct AADemuxContext {
> AVClass *class;
> @@ -51,7 +51,7 @@ typedef struct AADemuxContext {
> int64_t current_chapter_size;
> int64_t content_start;
> int64_t content_end;
> - int seek_offset;
> + int did_seek;
> } AADemuxContext;
>
> static int get_second_size(char *codec_name)
> @@ -179,7 +179,7 @@ static int aa_read_header(AVFormatContext *s)
> st->codecpar->sample_rate = 22050;
> st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
> avpriv_set_pts_info(st, 64, 8, 32000 * TIMEPREC);
> - // encoded audio frame is MP3_FRAME_SIZE bytes (+1 with padding, unlikely)
> + // encoded audio frame is MP3_FRAME_SIZE bytes (-1 without padding)
> } else if (!strcmp(codec_name, "acelp85")) {
> st->codecpar->codec_id = AV_CODEC_ID_SIPR;
> st->codecpar->block_align = 19;
> @@ -231,7 +231,7 @@ static int aa_read_header(AVFormatContext *s)
> ff_update_cur_dts(s, st, 0);
> avio_seek(pb, start, SEEK_SET);
> c->current_chapter_size = 0;
> - c->seek_offset = 0;
> + c->did_seek = 0;
>
> return 0;
> }
> @@ -244,7 +244,7 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
> int trailing_bytes;
> int blocks;
> uint8_t buf[MAX_CODEC_SECOND_SIZE * 2];
> - int written = 0;
> + int written = 0, offset = 0;
> int ret;
> AADemuxContext *c = s->priv_data;
> uint64_t pos = avio_tell(s->pb);
> @@ -297,16 +297,33 @@ 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)
> - c->seek_offset = 0; // ignore wrong estimate
> + if (c->did_seek) {
> + c->did_seek = 0;
> +
> + if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3 && written >= MP3_FRAME_SIZE + 3) {
> + for (offset = 0; offset < MP3_FRAME_SIZE; ++offset) {
> + // find mp3 header: sync, v2, layer3, no crc, 32kbps, 22kHz, mono
> + if ((buf[offset + 0] ) == 0xff &&
> + (buf[offset + 1] ) == 0xf3 &&
> + (buf[offset + 2] & 0xfc) == 0x40 &&
> + (buf[offset + 3] & 0xf0) == 0xc0)
> + break;
> + }
> + if (offset == MP3_FRAME_SIZE) offset = 0; // not found, just use as is
> + }
> +
> + ff_update_cur_dts(s, s->streams[0],
> + (pos + offset - c->content_start - CHAPTER_HEADER_SIZE * (c->chapter_idx - 1))
> + * TIMEPREC);
> + }
>
> - ret = av_new_packet(pkt, written - c->seek_offset);
> + if (offset > written) offset = 0;
> + ret = av_new_packet(pkt, written - offset);
> if (ret < 0)
> return ret;
> - memcpy(pkt->data, buf + c->seek_offset, written - c->seek_offset);
> + memcpy(pkt->data, buf + offset, written - offset);
> pkt->pos = pos;
>
> - c->seek_offset = 0;
> return 0;
> }
>
> @@ -349,13 +366,7 @@ static int aa_read_seek(AVFormatContext *s,
> c->current_codec_second_size = c->codec_second_size;
> c->current_chapter_size = chapter_size - chapter_pos;
> c->chapter_idx = 1 + chapter_idx;
> -
> - // for unaligned frames, estimate offset of first frame in block (assume no padding)
> - if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3) {
> - c->seek_offset = (MP3_FRAME_SIZE - chapter_pos % MP3_FRAME_SIZE) % MP3_FRAME_SIZE;
> - }
> -
> - ff_update_cur_dts(s, s->streams[0], ch->start + (chapter_pos + c->seek_offset) * TIMEPREC);
> + c->did_seek = 1;
>
> return 1;
> }
> --
> 2.14.3 (Apple Git-98)
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
More information about the ffmpeg-devel
mailing list