diff mbox

[FFmpeg-devel,7/7] lavf/flacenc: generate timestamps internally

Message ID 1501569234-29896-7-git-send-email-rodger.combs@gmail.com
State Superseded
Headers show

Commit Message

Rodger Combs Aug. 1, 2017, 6:33 a.m. UTC
---
 libavformat/flacenc.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 85 insertions(+), 3 deletions(-)

Comments

Rostislav Pehlivanov Nov. 22, 2017, 1:04 a.m. UTC | #1
On 1 August 2017 at 07:33, Rodger Combs <rodger.combs@gmail.com> wrote:

> ---
>  libavformat/flacenc.c | 88 ++++++++++++++++++++++++++++++
> +++++++++++++++++++--
>  1 file changed, 85 insertions(+), 3 deletions(-)
>
> diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
> index 1906aee..f569c14 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,
> @@ -263,11 +267,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,
> @@ -281,8 +291,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;
>  }
>
> @@ -326,7 +405,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 {
> --
> 2.6.4
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

I'm not sure this is a good idea, should the demuxer/decoder handle
duration calculations with arbitrary timestamp offsets?
diff mbox

Patch

diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index 1906aee..f569c14 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,
@@ -263,11 +267,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,
@@ -281,8 +291,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;
 }
 
@@ -326,7 +405,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 {