Browse code

oggdec: Support chained streams, support replacing streams in multistream files.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Conflicts:

Changelog

Michael Niedermayer authored on 2013/01/17 03:58:59
Showing 2 changed files
... ...
@@ -5,6 +5,7 @@ version <next>:
5 5
 - VDPAU hardware acceleration through normal hwaccel
6 6
 - SRTP support
7 7
 - Error diffusion dither in Swscale
8
+- Chained Ogg support
8 9
 
9 10
 
10 11
 version 1.1:
... ...
@@ -57,6 +57,7 @@ static const struct ogg_codec * const ogg_codecs[] = {
57 57
 };
58 58
 
59 59
 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
60
+static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
60 61
 
61 62
 //FIXME We could avoid some structure duplication
62 63
 static int ogg_save(AVFormatContext *s)
... ...
@@ -169,30 +170,48 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
169 169
  * situation where a new audio stream spawn (identified with a new serial) and
170 170
  * must replace the previous one (track switch).
171 171
  */
172
-static int ogg_replace_stream(AVFormatContext *s, uint32_t serial)
172
+static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
173 173
 {
174 174
     struct ogg *ogg = s->priv_data;
175 175
     struct ogg_stream *os;
176 176
     unsigned bufsize;
177 177
     uint8_t *buf;
178 178
     const struct ogg_codec *codec;
179
-
180
-    if (ogg->nstreams != 1) {
179
+    int i = 0;
180
+
181
+    if (s->pb->seekable) {
182
+        uint8_t magic[8];
183
+        int64_t pos = avio_tell(s->pb);
184
+        avio_skip(s->pb, nsegs);
185
+        avio_read(s->pb, magic, sizeof(magic));
186
+        avio_seek(s->pb, pos, SEEK_SET);
187
+        codec = ogg_find_codec(magic, sizeof(magic));
188
+        if (!codec) {
189
+            av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
190
+            return AVERROR_INVALIDDATA;
191
+        }
192
+        for (i = 0; i < ogg->nstreams; i++) {
193
+            if (ogg->streams[i].codec == codec)
194
+                break;
195
+        }
196
+        if (i >= ogg->nstreams)
197
+            return ogg_new_stream(s, serial);
198
+    } else if (ogg->nstreams != 1) {
181 199
         av_log_missing_feature(s, "Changing stream parameters in multistream ogg", 0);
182 200
         return AVERROR_PATCHWELCOME;
183 201
     }
184 202
 
185
-    os = &ogg->streams[0];
203
+    os = &ogg->streams[i];
186 204
 
187 205
     os->serial  = serial;
188
-    return 0;
206
+    return i;
189 207
 
190 208
     buf     = os->buf;
191 209
     bufsize = os->bufsize;
192 210
     codec   = os->codec;
193 211
 
194
-    if (!ogg->state || ogg->state->streams[0].private != os->private)
195
-        av_freep(&ogg->streams[0].private);
212
+    if (!ogg->state || ogg->state->streams[i].private != os->private)
213
+        av_freep(&ogg->streams[i].private);
196 214
 
197 215
     /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
198 216
      * also re-use the ogg_stream allocated buffer */
... ...
@@ -203,7 +222,7 @@ static int ogg_replace_stream(AVFormatContext *s, uint32_t serial)
203 203
     os->header  = -1;
204 204
     os->codec   = codec;
205 205
 
206
-    return 0;
206
+    return i;
207 207
 }
208 208
 
209 209
 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
... ...
@@ -334,7 +353,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid)
334 334
     idx = ogg_find_stream(ogg, serial);
335 335
     if (idx < 0) {
336 336
         if (data_packets_seen(ogg))
337
-            idx = ogg_replace_stream(s, serial);
337
+            idx = ogg_replace_stream(s, serial, nsegs);
338 338
         else
339 339
             idx = ogg_new_stream(s, serial);
340 340