Message ID | 1494218184-17850-7-git-send-email-rodger.combs@gmail.com |
---|---|
State | Superseded |
Headers | show |
On Sun, May 07, 2017 at 11:36:24PM -0500, Rodger Combs wrote: > --- > libavformat/flacenc.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 85 insertions(+), 3 deletions(-) > > diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c > index b8800cc..0e948ac 100644 > --- a/libavformat/flacenc.c > +++ b/libavformat/flacenc.c > @@ -30,6 +30,7 @@ > #include "internal.h" > #include "vorbiscomment.h" > #include "libavcodec/bytestream.h" > +#include "libavutil/crc.h" > > > typedef struct FlacMuxerContext { > @@ -46,6 +47,9 @@ typedef struct FlacMuxerContext { > uint8_t *streaminfo; > > unsigned attached_types; > + > + uint64_t samples; > + unsigned last_bs; > } FlacMuxerContext; > > static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_bytes, > @@ -256,11 +260,17 @@ static int flac_write_header(struct AVFormatContext *s) > return ret; > } > > +static const int32_t blocksize_table[16] = { > + 0, 192, 576<<0, 576<<1, 576<<2, 576<<3, 0, 0, > +256<<0, 256<<1, 256<<2, 256<<3, 256<<4, 256<<5, 256<<6, 256<<7 > +}; > + > static int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt) > { > FlacMuxerContext *c = s->priv_data; > uint8_t *streaminfo; > int streaminfo_size; > + char header[16]; > > /* check for updated streaminfo */ > streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, > @@ -274,8 +284,77 @@ static int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt) > memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE); > } > > - if (pkt->size) > - avio_write(s->pb, pkt->data, pkt->size); > + if (pkt->size) { > + uint8_t tmp; > + uint64_t pts = c->samples; > + int offset = 5; > + int headerlen = 4; > + int bscode, bs; > + int crc; > + if (pkt->size < FLAC_MIN_FRAME_SIZE) > + return AVERROR_INVALIDDATA; > + memcpy(header, pkt->data, 4); > + if (pkt->pts == AV_NOPTS_VALUE) > + pts = 0; > + if ((pkt->data[4] & 0xC0) == 0xC0) > + offset += ff_clz((unsigned char)~pkt->data[4]) - 25; > + else if (pkt->data[4] & 0x80) > + return AVERROR_INVALIDDATA; > + if (pkt->size <= offset + 1) > + return AVERROR_INVALIDDATA; > + > + bscode = (unsigned char)header[2] >> 4; > + bs = blocksize_table[bscode]; > + if (bscode == 0) > + return AVERROR_INVALIDDATA; > + if (bscode == 6) { > + if (pkt->size <= offset + 1) > + return AVERROR_INVALIDDATA; > + bs = pkt->data[offset] + 1; > + } else if (bscode == 7) { > + if (pkt->size <= offset + 2) > + return AVERROR_INVALIDDATA; > + bs = AV_RB16(&pkt->data[offset]) + 1; > + } > + if ((header[1] & 1) == 0) > + pts /= c->last_bs ? c->last_bs : bs; > + > + c->last_bs = bs; > + > + c->samples += bs; > + > + PUT_UTF8(pts, tmp, header[headerlen++] = tmp;) > + if (headerlen > 11) > + return AVERROR_INVALIDDATA; > + if ((bscode & 0xE) == 0x6) > + header[headerlen++] = pkt->data[offset++]; > + if (pkt->size <= offset + 1) > + return AVERROR_INVALIDDATA; > + if (bscode == 0x7) > + header[headerlen++] = pkt->data[offset++]; > + if (pkt->size <= offset + 1) > + return AVERROR_INVALIDDATA; > + if ((header[2] & 0xC) == 0xC) { > + header[headerlen++] = pkt->data[offset++]; > + if (pkt->size <= offset + 1) > + return AVERROR_INVALIDDATA; > + if ((header[2] & 0x3) == 0x3) > + return AVERROR_INVALIDDATA; > + else if (header[2] & 0x3) { > + header[headerlen++] = pkt->data[offset++]; > + if (pkt->size <= offset + 1) > + return AVERROR_INVALIDDATA; > + } > + } > + header[headerlen] = av_crc(av_crc_get_table(AV_CRC_8_ATM), 0, header, headerlen); > + headerlen++; offset++; > + crc = av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, header, headerlen); > + if (pkt->size < offset + 3) > + return AVERROR_INVALIDDATA; > + avio_write(s->pb, header, headerlen); > + avio_write(s->pb, pkt->data + offset, pkt->size - offset - 2); > + avio_wl16(s->pb, av_crc(av_crc_get_table(AV_CRC_16_ANSI), crc, pkt->data + offset, pkt->size - offset - 2)); > + } I dont think the muxer should rewrite codec headers unconditionally It makes of course only a difference if theres a inconsistancy leading to an actual change, but if there is, this can introduce errors i think. Please correct me if iam wrong but for example if one has flac data (raw or muxed) and some of it is damaged or packets lost then this would change correct timestamps into wrong ones [...]
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c index b8800cc..0e948ac 100644 --- a/libavformat/flacenc.c +++ b/libavformat/flacenc.c @@ -30,6 +30,7 @@ #include "internal.h" #include "vorbiscomment.h" #include "libavcodec/bytestream.h" +#include "libavutil/crc.h" typedef struct FlacMuxerContext { @@ -46,6 +47,9 @@ typedef struct FlacMuxerContext { uint8_t *streaminfo; unsigned attached_types; + + uint64_t samples; + unsigned last_bs; } FlacMuxerContext; static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_bytes, @@ -256,11 +260,17 @@ static int flac_write_header(struct AVFormatContext *s) return ret; } +static const int32_t blocksize_table[16] = { + 0, 192, 576<<0, 576<<1, 576<<2, 576<<3, 0, 0, +256<<0, 256<<1, 256<<2, 256<<3, 256<<4, 256<<5, 256<<6, 256<<7 +}; + static int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt) { FlacMuxerContext *c = s->priv_data; uint8_t *streaminfo; int streaminfo_size; + char header[16]; /* check for updated streaminfo */ streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, @@ -274,8 +284,77 @@ static int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt) memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE); } - if (pkt->size) - avio_write(s->pb, pkt->data, pkt->size); + if (pkt->size) { + uint8_t tmp; + uint64_t pts = c->samples; + int offset = 5; + int headerlen = 4; + int bscode, bs; + int crc; + if (pkt->size < FLAC_MIN_FRAME_SIZE) + return AVERROR_INVALIDDATA; + memcpy(header, pkt->data, 4); + if (pkt->pts == AV_NOPTS_VALUE) + pts = 0; + if ((pkt->data[4] & 0xC0) == 0xC0) + offset += ff_clz((unsigned char)~pkt->data[4]) - 25; + else if (pkt->data[4] & 0x80) + return AVERROR_INVALIDDATA; + if (pkt->size <= offset + 1) + return AVERROR_INVALIDDATA; + + bscode = (unsigned char)header[2] >> 4; + bs = blocksize_table[bscode]; + if (bscode == 0) + return AVERROR_INVALIDDATA; + if (bscode == 6) { + if (pkt->size <= offset + 1) + return AVERROR_INVALIDDATA; + bs = pkt->data[offset] + 1; + } else if (bscode == 7) { + if (pkt->size <= offset + 2) + return AVERROR_INVALIDDATA; + bs = AV_RB16(&pkt->data[offset]) + 1; + } + if ((header[1] & 1) == 0) + pts /= c->last_bs ? c->last_bs : bs; + + c->last_bs = bs; + + c->samples += bs; + + PUT_UTF8(pts, tmp, header[headerlen++] = tmp;) + if (headerlen > 11) + return AVERROR_INVALIDDATA; + if ((bscode & 0xE) == 0x6) + header[headerlen++] = pkt->data[offset++]; + if (pkt->size <= offset + 1) + return AVERROR_INVALIDDATA; + if (bscode == 0x7) + header[headerlen++] = pkt->data[offset++]; + if (pkt->size <= offset + 1) + return AVERROR_INVALIDDATA; + if ((header[2] & 0xC) == 0xC) { + header[headerlen++] = pkt->data[offset++]; + if (pkt->size <= offset + 1) + return AVERROR_INVALIDDATA; + if ((header[2] & 0x3) == 0x3) + return AVERROR_INVALIDDATA; + else if (header[2] & 0x3) { + header[headerlen++] = pkt->data[offset++]; + if (pkt->size <= offset + 1) + return AVERROR_INVALIDDATA; + } + } + header[headerlen] = av_crc(av_crc_get_table(AV_CRC_8_ATM), 0, header, headerlen); + headerlen++; offset++; + crc = av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, header, headerlen); + if (pkt->size < offset + 3) + return AVERROR_INVALIDDATA; + avio_write(s->pb, header, headerlen); + avio_write(s->pb, pkt->data + offset, pkt->size - offset - 2); + avio_wl16(s->pb, av_crc(av_crc_get_table(AV_CRC_16_ANSI), crc, pkt->data + offset, pkt->size - offset - 2)); + } return 0; } @@ -319,7 +398,10 @@ static int flac_write_trailer(struct AVFormatContext *s) /* rewrite the STREAMINFO header block data */ file_size = avio_tell(pb); avio_seek(pb, 8, SEEK_SET); - avio_write(pb, streaminfo, FLAC_STREAMINFO_SIZE); + avio_write(pb, streaminfo, 13); + avio_w8(pb, (streaminfo[13] & 0xF0) | ((c->samples >> 32) & 0xF)); + avio_wb32(pb, c->samples); + avio_write(pb, streaminfo + 18, FLAC_STREAMINFO_SIZE - 18); avio_seek(pb, file_size, SEEK_SET); avio_flush(pb); } else {