openbsd-ports/graphics/ffmpeg/patches/patch-libavformat_oggdec_c

163 lines
5.6 KiB
Plaintext

$OpenBSD: patch-libavformat_oggdec_c,v 1.3 2011/08/28 11:17:48 sthen Exp $
- Fix demuxing chained audio streams.
- Correct duration.
- Abort header parsing when encountering a data packet.
- Prevent heap corruption.
- Make sure start time correction is applied once to each stream.
--- libavformat/oggdec.c.orig Tue Apr 5 19:28:59 2011
+++ libavformat/oggdec.c Wed Aug 24 18:18:44 2011
@@ -148,7 +148,7 @@ ogg_find_codec (uint8_t * buf, int size)
}
static int
-ogg_new_stream (AVFormatContext * s, uint32_t serial)
+ogg_new_stream (AVFormatContext *s, uint32_t serial, int new_avstream)
{
struct ogg *ogg = s->priv_data;
@@ -165,12 +165,14 @@ ogg_new_stream (AVFormatContext * s, uint32_t serial)
os->buf = av_malloc(os->bufsize);
os->header = -1;
- st = av_new_stream (s, idx);
- if (!st)
- return AVERROR(ENOMEM);
+ if (new_avstream) {
+ st = av_new_stream(s, idx);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ av_set_pts_info(st, 64, 1, 1000000);
+ }
- av_set_pts_info(st, 64, 1, 1000000);
-
return idx;
}
@@ -241,7 +243,20 @@ ogg_read_page (AVFormatContext * s, int *str)
idx = ogg_find_stream (ogg, serial);
if (idx < 0){
- idx = ogg_new_stream (s, serial);
+ if (ogg->headers) {
+ int n;
+
+ for (n = 0; n < ogg->nstreams; n++) {
+ av_freep(&ogg->streams[n].buf);
+ if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
+ av_freep(&ogg->streams[n].private);
+ }
+ ogg->curidx = -1;
+ ogg->nstreams = 0;
+ idx = ogg_new_stream(s, serial, 0);
+ } else {
+ idx = ogg_new_stream(s, serial, 1);
+ }
if (idx < 0)
return -1;
}
@@ -376,8 +391,7 @@ ogg_packet (AVFormatContext * s, int *str, int *dstart
// We have reached the first non-header packet in this stream.
// Unfortunately more header packets may still follow for others,
- // so we reset this later unless we are done with the headers
- // for all streams.
+ // but if we continue with header parsing we may lose data packets.
ogg->headers = 1;
// Update the header state for all streams and
@@ -386,8 +400,6 @@ ogg_packet (AVFormatContext * s, int *str, int *dstart
s->data_offset = os->sync_pos;
for (i = 0; i < ogg->nstreams; i++) {
struct ogg_stream *cur_os = ogg->streams + i;
- if (cur_os->header > 0)
- ogg->headers = 0;
// if we have a partial non-header packet, its start is
// obviously at or after the data start
@@ -413,6 +425,8 @@ ogg_packet (AVFormatContext * s, int *str, int *dstart
*fpos = os->sync_pos;
os->pstart += os->psize;
os->psize = 0;
+ if(os->pstart == os->bufpos)
+ os->bufpos = os->pstart = 0;
os->sync_pos = os->page_pos;
}
@@ -454,6 +468,7 @@ ogg_get_length (AVFormatContext * s)
struct ogg *ogg = s->priv_data;
int i;
int64_t size, end;
+ int streams_left=0;
if(!s->pb->seekable)
return 0;
@@ -475,13 +490,37 @@ ogg_get_length (AVFormatContext * s)
ogg->streams[i].codec) {
s->streams[i]->duration =
ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
- if (s->streams[i]->start_time != AV_NOPTS_VALUE)
+ if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
s->streams[i]->duration -= s->streams[i]->start_time;
+ streams_left-= (ogg->streams[i].got_start==-1);
+ ogg->streams[i].got_start= 1;
+ }else if(!ogg->streams[i].got_start){
+ ogg->streams[i].got_start= -1;
+ streams_left++;
+ }
}
}
ogg_restore (s, 0);
+ ogg_save (s);
+ avio_seek (s->pb, 0, SEEK_SET);
+ while (!ogg_read_page (s, &i)){
+ if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
+ ogg->streams[i].codec) {
+ if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
+ int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
+ if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE)
+ s->streams[i]->duration -= start;
+ ogg->streams[i].got_start= 1;
+ streams_left--;
+ }
+ if(streams_left<=0)
+ break;
+ }
+ }
+ ogg_restore (s, 0);
+
return 0;
}
@@ -600,15 +639,15 @@ ogg_read_timestamp (AVFormatContext * s, int stream_in
int64_t pos_limit)
{
struct ogg *ogg = s->priv_data;
- struct ogg_stream *os = ogg->streams + stream_index;
AVIOContext *bc = s->pb;
int64_t pts = AV_NOPTS_VALUE;
- int i;
+ int i = -1;
avio_seek(bc, *pos_arg, SEEK_SET);
ogg_reset(ogg);
while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
if (i == stream_index) {
+ struct ogg_stream *os = ogg->streams + stream_index;
pts = ogg_calc_pts(s, i, NULL);
if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
pts = AV_NOPTS_VALUE;
@@ -633,6 +672,7 @@ static int ogg_read_seek(AVFormatContext *s, int strea
os->keyframe_seek = 1;
ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
+ os = ogg->streams + stream_index;
if (ret < 0)
os->keyframe_seek = 0;
return ret;