Commit 37b74c86 authored by Baptiste Coudurier's avatar Baptiste Coudurier

Fix issue 338:

Correctly interleave ogg packets per granule
and set eos correctly, 2 packets buffering is needed.
It duplicates interleave_per_dts a bit,
if someone has a good solution, I'll implement it.

Originally committed as revision 11867 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 2dd3c9e0
......@@ -33,6 +33,7 @@ typedef struct {
int kfgshift;
int64_t last_kf_pts;
int vrev;
int eos;
} OGGStreamContext;
static void ogg_update_checksum(AVFormatContext *s, offset_t crc_offset)
......@@ -54,7 +55,8 @@ static int ogg_write_page(AVFormatContext *s, const uint8_t *data, int size,
if (size >= 255*255) {
granule = -1;
size = 255*255;
}
} else if (oggstream->eos)
flags |= 4;
page_segments = FFMIN((size/255)+!!size, 255);
......@@ -200,6 +202,65 @@ static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
int ogg_interleave_per_granule(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush)
{
AVPacketList *pktl, **next_point, *this_pktl;
int stream_count = 0;
int streams[MAX_STREAMS] = {0};
int interleaved = 0;
if (pkt) {
AVStream *st = s->streams[pkt->stream_index];
this_pktl = av_mallocz(sizeof(AVPacketList));
this_pktl->pkt = *pkt;
if (pkt->destruct == av_destruct_packet)
pkt->destruct = NULL; // not shared -> must keep original from being freed
else
av_dup_packet(&this_pktl->pkt); // shared -> must dup
next_point = &s->packet_buffer;
while (*next_point) {
AVStream *st2 = s->streams[(*next_point)->pkt.stream_index];
AVPacket *next_pkt = &(*next_point)->pkt;
int64_t cur_granule, next_granule;
next_granule = av_rescale_q(next_pkt->pts + next_pkt->duration,
st2->time_base, AV_TIME_BASE_Q);
cur_granule = av_rescale_q(pkt->pts + pkt->duration,
st->time_base, AV_TIME_BASE_Q);
if (next_granule > cur_granule)
break;
next_point= &(*next_point)->next;
}
this_pktl->next= *next_point;
*next_point= this_pktl;
}
pktl = s->packet_buffer;
while (pktl) {
if (streams[pktl->pkt.stream_index] == 0)
stream_count++;
streams[pktl->pkt.stream_index]++;
// need to buffer at least one packet to set eos flag
if (streams[pktl->pkt.stream_index] == 2)
interleaved++;
pktl = pktl->next;
}
if ((s->nb_streams == stream_count && interleaved == stream_count) ||
(flush && stream_count)) {
pktl= s->packet_buffer;
*out= pktl->pkt;
s->packet_buffer = pktl->next;
if (flush && streams[out->stream_index] == 1) {
OGGStreamContext *ogg = s->streams[out->stream_index]->priv_data;
ogg->eos = 1;
}
av_freep(&pktl);
return 1;
} else {
av_init_packet(out);
return 0;
}
}
static int ogg_write_trailer(AVFormatContext *s)
{
......@@ -207,7 +268,6 @@ static int ogg_write_trailer(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
OGGStreamContext *oggstream = st->priv_data;
ogg_write_page(s, NULL, 0, oggstream->duration, i, 4); // eos
if (st->codec->codec_id == CODEC_ID_FLAC) {
av_free(oggstream->header[0]);
av_free(oggstream->header[1]);
......@@ -228,4 +288,5 @@ AVOutputFormat ogg_muxer = {
ogg_write_header,
ogg_write_packet,
ogg_write_trailer,
.interleave_packet = ogg_interleave_per_granule,
};
......@@ -84,8 +84,8 @@ ae3a23a7ea13c92a2909445ca8144dcd *./tests/data/b-libav.aif
8d117c49d6b210abe783d1b0b897cec7 *./tests/data/b-libav.voc
32768 ./tests/data/b-libav.voc
./tests/data/b-libav.voc CRC=0x49972c8c
f77f5d44edf767bcc47959787eaaf188 *./tests/data/b-libav.ogg
23651 ./tests/data/b-libav.ogg
d7e6e9091a600b7208b29500be94aa89 *./tests/data/b-libav.ogg
23624 ./tests/data/b-libav.ogg
./tests/data/b-libav.ogg CRC=0x93baa056
ce356ce2708cb6033ab5d762da93cfd4 *./tests/data/b-libav-yuv420p.yuv
304128 ./tests/data/b-libav-yuv420p.yuv
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment