[2/2,v3] matroskaenc: write updated STREAMINFO metadata for FLAC streams if available

Message ID 20161109213824.8036-2-jamrial@gmail.com
State New
Headers show

Commit Message

James Almer Nov. 9, 2016, 9:38 p.m.
FLAC streams originating from the FLAC encoder send updated and more
complete STREAMINFO metadata as part of the last packet, so write that
to CodecPrivate instead of the incomplete one available in extradata
during init.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/matroskaenc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

Comments

Anton Khirnov Nov. 10, 2016, 8:13 a.m. | #1
Quoting James Almer (2016-11-09 22:38:24)
> FLAC streams originating from the FLAC encoder send updated and more
> complete STREAMINFO metadata as part of the last packet, so write that
> to CodecPrivate instead of the incomplete one available in extradata
> during init.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavformat/matroskaenc.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
> index 5593237..08d258d 100644
> --- a/libavformat/matroskaenc.c
> +++ b/libavformat/matroskaenc.c
> @@ -83,6 +83,7 @@ typedef struct mkv_track {
>      int             write_dts;
>      int             sample_rate;
>      int64_t         sample_rate_offset;
> +    int64_t         codecpriv_offset;
>      int64_t         ts_offset;
>  } mkv_track;
>  
> @@ -931,6 +932,7 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
>          break;
>      }
>  
> +    mkv->tracks[i].codecpriv_offset = avio_tell(pb);
>      ret = mkv_write_codecprivate(s, pb, par, native_id, qt_id);
>      if (ret < 0)
>          return ret;
> @@ -1586,6 +1588,29 @@ static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt)
>              return AVERROR(EINVAL);
>          }
>          break;
> +    case AV_CODEC_ID_FLAC:
> +        if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
> +            AVCodecParameters *codecpriv_par;
> +            int64_t curpos;
> +            if (side_data_size != par->extradata_size) {
> +                av_log(s, AV_LOG_ERROR, "Invalid FLAC STREAMINFO metadata for output stream %d\n",
> +                       pkt->stream_index);
> +                return AVERROR(EINVAL);
> +            }
> +            codecpriv_par = avcodec_parameters_alloc();
> +            if (!codecpriv_par)
> +                return AVERROR(ENOMEM);
> +            ret = avcodec_parameters_copy(codecpriv_par, par);
> +            if (ret < 0)
> +                return ret;

This is leaking codecpriv_par. No need to resend, I'll add the missing
free myself on push.

> +            memcpy(codecpriv_par->extradata, side_data, side_data_size);
> +            curpos = avio_tell(s->pb);
> +            avio_seek(s->pb, track->codecpriv_offset, SEEK_SET);
> +            mkv_write_codecprivate(s, s->pb, codecpriv_par, 1, 0);
> +            avio_seek(s->pb, curpos, SEEK_SET);
> +            avcodec_parameters_free(&codecpriv_par);
> +        }
> +        break;
>      default:
>          if (side_data_size)
>              av_log(s, AV_LOG_DEBUG, "Ignoring new extradata in a packet for stream %d.\n", pkt->stream_index);
> -- 
> 2.10.1

Otherwise the set looks fine now, queuing.

Patch

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 5593237..08d258d 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -83,6 +83,7 @@  typedef struct mkv_track {
     int             write_dts;
     int             sample_rate;
     int64_t         sample_rate_offset;
+    int64_t         codecpriv_offset;
     int64_t         ts_offset;
 } mkv_track;
 
@@ -931,6 +932,7 @@  static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
         break;
     }
 
+    mkv->tracks[i].codecpriv_offset = avio_tell(pb);
     ret = mkv_write_codecprivate(s, pb, par, native_id, qt_id);
     if (ret < 0)
         return ret;
@@ -1586,6 +1588,29 @@  static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt)
             return AVERROR(EINVAL);
         }
         break;
+    case AV_CODEC_ID_FLAC:
+        if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+            AVCodecParameters *codecpriv_par;
+            int64_t curpos;
+            if (side_data_size != par->extradata_size) {
+                av_log(s, AV_LOG_ERROR, "Invalid FLAC STREAMINFO metadata for output stream %d\n",
+                       pkt->stream_index);
+                return AVERROR(EINVAL);
+            }
+            codecpriv_par = avcodec_parameters_alloc();
+            if (!codecpriv_par)
+                return AVERROR(ENOMEM);
+            ret = avcodec_parameters_copy(codecpriv_par, par);
+            if (ret < 0)
+                return ret;
+            memcpy(codecpriv_par->extradata, side_data, side_data_size);
+            curpos = avio_tell(s->pb);
+            avio_seek(s->pb, track->codecpriv_offset, SEEK_SET);
+            mkv_write_codecprivate(s, s->pb, codecpriv_par, 1, 0);
+            avio_seek(s->pb, curpos, SEEK_SET);
+            avcodec_parameters_free(&codecpriv_par);
+        }
+        break;
     default:
         if (side_data_size)
             av_log(s, AV_LOG_DEBUG, "Ignoring new extradata in a packet for stream %d.\n", pkt->stream_index);