]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/matroskadec.c
Merge commit '41776ba9c0ebbb71394cefdf7dd1b243e6c852d5'
[ffmpeg] / libavformat / matroskadec.c
index 956abbaa2a0109ddf812cbb7846c69c165589967..213767c646828065f50c59b9a688732d89c452c1 100644 (file)
@@ -48,6 +48,7 @@
 #include "libavutil/mathematics.h"
 
 #include "libavcodec/bytestream.h"
+#include "libavcodec/flac.h"
 #include "libavcodec/mpeg4audio.h"
 
 #include "avformat.h"
@@ -55,6 +56,7 @@
 #include "internal.h"
 #include "isom.h"
 #include "matroska.h"
+#include "oggdec.h"
 /* For ff_codec_get_id(). */
 #include "riff.h"
 #include "rmsipr.h"
@@ -1570,12 +1572,67 @@ static void matroska_metadata_creation_time(AVDictionary **metadata, int64_t dat
     av_dict_set(metadata, "creation_time", buffer, 0);
 }
 
+static int matroska_parse_flac(AVFormatContext *s,
+                               MatroskaTrack *track,
+                               int *offset)
+{
+    AVStream *st = track->stream;
+    uint8_t *p = track->codec_priv.data;
+    int size   = track->codec_priv.size;
+
+    if (size < 8 + FLAC_STREAMINFO_SIZE || p[4] & 0x7f) {
+        av_log(s, AV_LOG_WARNING, "Invalid FLAC private data\n");
+        track->codec_priv.size = 0;
+        return 0;
+    }
+    *offset = 8;
+    track->codec_priv.size = 8 + FLAC_STREAMINFO_SIZE;
+
+    p    += track->codec_priv.size;
+    size -= track->codec_priv.size;
+
+    /* parse the remaining metadata blocks if present */
+    while (size >= 4) {
+        int block_last, block_type, block_size;
+
+        flac_parse_block_header(p, &block_last, &block_type, &block_size);
+
+        p    += 4;
+        size -= 4;
+        if (block_size > size)
+            return 0;
+
+        /* check for the channel mask */
+        if (block_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
+            AVDictionary *dict = NULL;
+            AVDictionaryEntry *chmask;
+
+            ff_vorbis_comment(s, &dict, p, block_size, 0);
+            chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
+            if (chmask) {
+                uint64_t mask = strtol(chmask->value, NULL, 0);
+                if (!mask || mask & ~0x3ffffULL) {
+                    av_log(s, AV_LOG_WARNING,
+                           "Invalid value of WAVEFORMATEXTENSIBLE_CHANNEL_MASK\n");
+                } else
+                    st->codec->channel_layout = mask;
+            }
+            av_dict_free(&dict);
+        }
+
+        p    += block_size;
+        size -= block_size;
+    }
+
+    return 0;
+}
+
 static int matroska_parse_tracks(AVFormatContext *s)
 {
     MatroskaDemuxContext *matroska = s->priv_data;
     MatroskaTrack *tracks = matroska->tracks.elem;
     AVStream *st;
-    int i, j;
+    int i, j, ret;
     int k;
 
     for (i = 0; i < matroska->tracks.nb_elem; i++) {
@@ -1854,6 +1911,10 @@ static int matroska_parse_tracks(AVFormatContext *s)
                 st->codec->block_align = track->audio.sub_packet_size;
                 extradata_offset       = 78;
             }
+        } else if (codec_id == AV_CODEC_ID_FLAC && track->codec_priv.size) {
+            ret = matroska_parse_flac(s, track, &extradata_offset);
+            if (ret < 0)
+                return ret;
         } else if (codec_id == AV_CODEC_ID_PRORES && track->codec_priv.size == 4) {
             fourcc = AV_RL32(track->codec_priv.data);
         }
@@ -2957,7 +3018,7 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
                 tracks[i].stream, st->index_entries[index].timestamp,
                 AVSEEK_FLAG_BACKWARD);
             while (index_sub >= 0 &&
-                  index_min >= 0 &&
+                  index_min > 0 &&
                   tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos &&
                   st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000 / matroska->time_scale)
                 index_min--;