|
|
|
@ -57,6 +57,7 @@ static const struct ogg_codec * const ogg_codecs[] = { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts); |
|
|
|
|
static int ogg_new_stream(AVFormatContext *s, uint32_t serial); |
|
|
|
|
|
|
|
|
|
//FIXME We could avoid some structure duplication
|
|
|
|
|
static int ogg_save(AVFormatContext *s) |
|
|
|
@ -169,30 +170,48 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size) |
|
|
|
|
* situation where a new audio stream spawn (identified with a new serial) and |
|
|
|
|
* must replace the previous one (track switch). |
|
|
|
|
*/ |
|
|
|
|
static int ogg_replace_stream(AVFormatContext *s, uint32_t serial) |
|
|
|
|
static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs) |
|
|
|
|
{ |
|
|
|
|
struct ogg *ogg = s->priv_data; |
|
|
|
|
struct ogg_stream *os; |
|
|
|
|
unsigned bufsize; |
|
|
|
|
uint8_t *buf; |
|
|
|
|
const struct ogg_codec *codec; |
|
|
|
|
|
|
|
|
|
if (ogg->nstreams != 1) { |
|
|
|
|
int i = 0; |
|
|
|
|
|
|
|
|
|
if (s->pb->seekable) { |
|
|
|
|
uint8_t magic[8]; |
|
|
|
|
int64_t pos = avio_tell(s->pb); |
|
|
|
|
avio_skip(s->pb, nsegs); |
|
|
|
|
avio_read(s->pb, magic, sizeof(magic)); |
|
|
|
|
avio_seek(s->pb, pos, SEEK_SET); |
|
|
|
|
codec = ogg_find_codec(magic, sizeof(magic)); |
|
|
|
|
if (!codec) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n"); |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
for (i = 0; i < ogg->nstreams; i++) { |
|
|
|
|
if (ogg->streams[i].codec == codec) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (i >= ogg->nstreams) |
|
|
|
|
return ogg_new_stream(s, serial); |
|
|
|
|
} else if (ogg->nstreams != 1) { |
|
|
|
|
av_log_missing_feature(s, "Changing stream parameters in multistream ogg", 0); |
|
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
os = &ogg->streams[0]; |
|
|
|
|
os = &ogg->streams[i]; |
|
|
|
|
|
|
|
|
|
os->serial = serial; |
|
|
|
|
return 0; |
|
|
|
|
return i; |
|
|
|
|
|
|
|
|
|
buf = os->buf; |
|
|
|
|
bufsize = os->bufsize; |
|
|
|
|
codec = os->codec; |
|
|
|
|
|
|
|
|
|
if (!ogg->state || ogg->state->streams[0].private != os->private) |
|
|
|
|
av_freep(&ogg->streams[0].private); |
|
|
|
|
if (!ogg->state || ogg->state->streams[i].private != os->private) |
|
|
|
|
av_freep(&ogg->streams[i].private); |
|
|
|
|
|
|
|
|
|
/* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
|
|
|
|
|
* also re-use the ogg_stream allocated buffer */ |
|
|
|
@ -203,7 +222,7 @@ static int ogg_replace_stream(AVFormatContext *s, uint32_t serial) |
|
|
|
|
os->header = -1; |
|
|
|
|
os->codec = codec; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
return i; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ogg_new_stream(AVFormatContext *s, uint32_t serial) |
|
|
|
@ -334,7 +353,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid) |
|
|
|
|
idx = ogg_find_stream(ogg, serial); |
|
|
|
|
if (idx < 0) { |
|
|
|
|
if (data_packets_seen(ogg)) |
|
|
|
|
idx = ogg_replace_stream(s, serial); |
|
|
|
|
idx = ogg_replace_stream(s, serial, nsegs); |
|
|
|
|
else |
|
|
|
|
idx = ogg_new_stream(s, serial); |
|
|
|
|
|
|
|
|
|