Commit 8594e07a authored by conrad's avatar conrad

matroskaenc: Mux clusters better

Start them on keyframes when reasonable, and delay writing audio packets
to help ensure that there's audio samples available for the first frame in
clusters.

Patch by James Zern <jzern at google>

git-svn-id: file:///var/local/repositories/ffmpeg/trunk@23473 9553f0bf-9b14-0410-a0b8-cfaf0461ba5b
parent addd46ed
...@@ -81,6 +81,8 @@ typedef struct MatroskaMuxContext { ...@@ -81,6 +81,8 @@ typedef struct MatroskaMuxContext {
mkv_track *tracks; mkv_track *tracks;
struct AVMD5 *md5_ctx; struct AVMD5 *md5_ctx;
unsigned int audio_buffer_size;
AVPacket cur_audio_pkt;
} MatroskaMuxContext; } MatroskaMuxContext;
...@@ -746,6 +748,10 @@ static int mkv_write_header(AVFormatContext *s) ...@@ -746,6 +748,10 @@ static int mkv_write_header(AVFormatContext *s)
if (mkv->cues == NULL) if (mkv->cues == NULL)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
av_init_packet(&mkv->cur_audio_pkt);
mkv->cur_audio_pkt.size = 0;
mkv->audio_buffer_size = 0;
put_flush_packet(pb); put_flush_packet(pb);
return 0; return 0;
} }
...@@ -861,7 +867,7 @@ static void mkv_flush_dynbuf(AVFormatContext *s) ...@@ -861,7 +867,7 @@ static void mkv_flush_dynbuf(AVFormatContext *s)
mkv->dyn_bc = NULL; mkv->dyn_bc = NULL;
} }
static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
{ {
MatroskaMuxContext *mkv = s->priv_data; MatroskaMuxContext *mkv = s->priv_data;
ByteIOContext *pb = s->pb; ByteIOContext *pb = s->pb;
...@@ -910,9 +916,38 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -910,9 +916,38 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
if (ret < 0) return ret; if (ret < 0) return ret;
} }
// start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming mkv->duration = FFMAX(mkv->duration, ts + duration);
if ((url_is_streamed(s->pb) && (url_ftell(pb) > 32*1024 || ts > mkv->cluster_pts + 1000)) return 0;
|| url_ftell(pb) > mkv->cluster_pos + 5*1024*1024 || ts > mkv->cluster_pts + 5000) { }
static int mkv_copy_packet(MatroskaMuxContext *mkv, const AVPacket *pkt)
{
uint8_t *data = mkv->cur_audio_pkt.data;
mkv->cur_audio_pkt = *pkt;
mkv->cur_audio_pkt.data = av_fast_realloc(data, &mkv->audio_buffer_size, pkt->size);
if (!mkv->cur_audio_pkt.data)
return AVERROR(ENOMEM);
memcpy(mkv->cur_audio_pkt.data, pkt->data, pkt->size);
mkv->cur_audio_pkt.size = pkt->size;
return 0;
}
static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
ByteIOContext *pb = url_is_streamed(s->pb) ? mkv->dyn_bc : s->pb;
AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
int ret, keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY);
int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
int cluster_size = url_ftell(pb) - (url_is_streamed(s->pb) ? 0 : mkv->cluster_pos);
// start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or
// after 4k and on a keyframe
if (mkv->cluster_pos &&
((url_is_streamed(s->pb) && (cluster_size > 32*1024 || ts > mkv->cluster_pts + 1000))
|| cluster_size > 5*1024*1024 || ts > mkv->cluster_pts + 5000
|| (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe && cluster_size > 4*1024))) {
av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64 av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64
" bytes, pts %" PRIu64 "\n", url_ftell(pb), ts); " bytes, pts %" PRIu64 "\n", url_ftell(pb), ts);
end_ebml_master(pb, mkv->cluster); end_ebml_master(pb, mkv->cluster);
...@@ -921,8 +956,23 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -921,8 +956,23 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
mkv_flush_dynbuf(s); mkv_flush_dynbuf(s);
} }
mkv->duration = FFMAX(mkv->duration, ts + duration); // check if we have an audio packet cached
return 0; if (mkv->cur_audio_pkt.size > 0) {
ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt);
mkv->cur_audio_pkt.size = 0;
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret);
return ret;
}
}
// buffer an audio packet to ensure the packet containing the video
// keyframe's timecode is contained in the same cluster for WebM
if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
ret = mkv_copy_packet(mkv, pkt);
else
ret = mkv_write_packet_internal(s, pkt);
return ret;
} }
static int mkv_write_trailer(AVFormatContext *s) static int mkv_write_trailer(AVFormatContext *s)
...@@ -932,6 +982,16 @@ static int mkv_write_trailer(AVFormatContext *s) ...@@ -932,6 +982,16 @@ static int mkv_write_trailer(AVFormatContext *s)
int64_t currentpos, second_seekhead, cuespos; int64_t currentpos, second_seekhead, cuespos;
int ret; int ret;
// check if we have an audio packet cached
if (mkv->cur_audio_pkt.size > 0) {
ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt);
mkv->cur_audio_pkt.size = 0;
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret);
return ret;
}
}
if (mkv->dyn_bc) { if (mkv->dyn_bc) {
end_ebml_master(mkv->dyn_bc, mkv->cluster); end_ebml_master(mkv->dyn_bc, mkv->cluster);
mkv_flush_dynbuf(s); mkv_flush_dynbuf(s);
...@@ -970,6 +1030,7 @@ static int mkv_write_trailer(AVFormatContext *s) ...@@ -970,6 +1030,7 @@ static int mkv_write_trailer(AVFormatContext *s)
end_ebml_master(pb, mkv->segment); end_ebml_master(pb, mkv->segment);
av_free(mkv->md5_ctx); av_free(mkv->md5_ctx);
av_free(mkv->tracks); av_free(mkv->tracks);
av_destruct_packet(&mkv->cur_audio_pkt);
put_flush_packet(pb); put_flush_packet(pb);
return 0; return 0;
} }
......
...@@ -22,11 +22,11 @@ stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444 ...@@ -22,11 +22,11 @@ stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444
1058444 ./tests/data/acodec/pcm_s16le.wav 1058444 ./tests/data/acodec/pcm_s16le.wav
95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/pcm.acodec.out.wav 95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/pcm.acodec.out.wav
stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444 stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444
43440f8078f2383c0dd618ad606f6830 *./tests/data/acodec/pcm_s16be.mkv fca887459876a7fdc4b9580691acd835 *./tests/data/acodec/pcm_s16be.mkv
1060693 ./tests/data/acodec/pcm_s16be.mkv 1060693 ./tests/data/acodec/pcm_s16be.mkv
95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/pcm.acodec.out.wav 95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/pcm.acodec.out.wav
stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444 stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444
1e63166f1672b7eb00877c697c06743c *./tests/data/acodec/pcm_s16le.mkv 2817e2a028a9117d4809604fa0f81a80 *./tests/data/acodec/pcm_s16le.mkv
1060693 ./tests/data/acodec/pcm_s16le.mkv 1060693 ./tests/data/acodec/pcm_s16le.mkv
95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/pcm.acodec.out.wav 95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/pcm.acodec.out.wav
stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444 stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444
......
cf230e089e737ed9449fbfb3cb87da92 *./tests/data/lavf/lavf.mkv 5e906a7003f893cf6481f186c92dc16c *./tests/data/lavf/lavf.mkv
320471 ./tests/data/lavf/lavf.mkv 320537 ./tests/data/lavf/lavf.mkv
./tests/data/lavf/lavf.mkv CRC=0x2a83e6b0 ./tests/data/lavf/lavf.mkv CRC=0x2a83e6b0
...@@ -2,35 +2,35 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ...@@ -2,35 +2,35 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st:-1 flags:0 ts:-1.000000 ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st:-1 flags:1 ts: 1.894167 ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291902 size: 27834 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291934 size: 27834
ret: 0 st: 0 flags:0 ts: 0.788000 ret: 0 st: 0 flags:0 ts: 0.788000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291902 size: 27834 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291934 size: 27834
ret: 0 st: 0 flags:1 ts:-0.317000 ret: 0 st: 0 flags:1 ts:-0.317000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st: 1 flags:0 ts: 2.577000 ret: 0 st: 1 flags:0 ts: 2.577000
ret:-EOF ret:-EOF
ret: 0 st: 1 flags:1 ts: 1.471000 ret: 0 st: 1 flags:1 ts: 1.471000
ret: 0 st: 1 flags:1 dts: 1.019000 pts: 1.019000 pos: 320175 size: 209 ret: 0 st: 1 flags:1 dts: 1.019000 pts: 1.019000 pos: 320207 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002 ret: 0 st:-1 flags:0 ts: 0.365002
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146687 size: 27925 ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146703 size: 27925
ret: 0 st:-1 flags:1 ts:-0.740831 ret: 0 st:-1 flags:1 ts:-0.740831
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st: 0 flags:0 ts: 2.153000 ret: 0 st: 0 flags:0 ts: 2.153000
ret:-EOF ret:-EOF
ret: 0 st: 0 flags:1 ts: 1.048000 ret: 0 st: 0 flags:1 ts: 1.048000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291902 size: 27834 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291934 size: 27834
ret: 0 st: 1 flags:0 ts:-0.058000 ret: 0 st: 1 flags:0 ts:-0.058000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st: 1 flags:1 ts: 2.836000 ret: 0 st: 1 flags:1 ts: 2.836000
ret: 0 st: 1 flags:1 dts: 1.019000 pts: 1.019000 pos: 320175 size: 209 ret: 0 st: 1 flags:1 dts: 1.019000 pts: 1.019000 pos: 320207 size: 209
ret: 0 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:0 ts: 1.730004
ret:-EOF ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.624171 ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146687 size: 27925 ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146703 size: 27925
ret: 0 st: 0 flags:0 ts:-0.482000 ret: 0 st: 0 flags:0 ts:-0.482000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st: 0 flags:1 ts: 2.413000 ret: 0 st: 0 flags:1 ts: 2.413000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291902 size: 27834 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291934 size: 27834
ret: 0 st: 1 flags:0 ts: 1.307000 ret: 0 st: 1 flags:0 ts: 1.307000
ret:-EOF ret:-EOF
ret: 0 st: 1 flags:1 ts: 0.201000 ret: 0 st: 1 flags:1 ts: 0.201000
...@@ -38,16 +38,16 @@ ret: 0 st: 1 flags:1 dts: 0.183000 pts: 0.183000 pos: 72083 size: 209 ...@@ -38,16 +38,16 @@ ret: 0 st: 1 flags:1 dts: 0.183000 pts: 0.183000 pos: 72083 size: 209
ret: 0 st:-1 flags:0 ts:-0.904994 ret: 0 st:-1 flags:0 ts:-0.904994
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st:-1 flags:1 ts: 1.989173 ret: 0 st:-1 flags:1 ts: 1.989173
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291902 size: 27834 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291934 size: 27834
ret: 0 st: 0 flags:0 ts: 0.883000 ret: 0 st: 0 flags:0 ts: 0.883000
ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291902 size: 27834 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 291934 size: 27834
ret: 0 st: 0 flags:1 ts:-0.222000 ret: 0 st: 0 flags:1 ts:-0.222000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
ret: 0 st: 1 flags:0 ts: 2.672000 ret: 0 st: 1 flags:0 ts: 2.672000
ret:-EOF ret:-EOF
ret: 0 st: 1 flags:1 ts: 1.566000 ret: 0 st: 1 flags:1 ts: 1.566000
ret: 0 st: 1 flags:1 dts: 1.019000 pts: 1.019000 pos: 320175 size: 209 ret: 0 st: 1 flags:1 dts: 1.019000 pts: 1.019000 pos: 320207 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008 ret: 0 st:-1 flags:0 ts: 0.460008
ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146687 size: 27925 ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146703 size: 27925
ret: 0 st:-1 flags:1 ts:-0.645825 ret: 0 st:-1 flags:1 ts:-0.645825
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 513 size: 27837
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