summaryrefslogtreecommitdiffstats
path: root/demux/demux_mkv.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-11-26 23:41:01 +0100
committerwm4 <wm4@nowhere>2013-11-26 23:43:56 +0100
commitf1eb30a476fa92840d1cdfcdcc13db9e59ad09a6 (patch)
tree55204e9fe5032ac41912c5c8138cac9b664263e4 /demux/demux_mkv.c
parent27d578a8476cda1bdc7b5882282ff2ceff10ec25 (diff)
downloadmpv-f1eb30a476fa92840d1cdfcdcc13db9e59ad09a6.tar.bz2
mpv-f1eb30a476fa92840d1cdfcdcc13db9e59ad09a6.tar.xz
demux_mkv: fix realvideo timestamp handling
This was broken by the recent commits. Apparently realvideo timestamps are severely mangled, and Matroska _of course_ doesn't have the sane, umangled timestamps, but something unusable. The existing unmangling code in demux_mkv.c didn't output proper timestamps either. Instead, it was something weird that triggered sorting. Without sorting (it was disabled by default recently), you'd get decreasing PTS warnings In order to fix this, steal some code from libavcodec. Basically copy the contents of rv34_parser.c (with some changes), which makes everything magically work. (Maybe it would be better to use the libavcodec parser API, but I don't want to do that just for this. An alternative idea would be refusing to read files that have realvideo tracks, and delegate this to demux_lavf.c, but maybe that's too redical too.) I wish I hadn't notice this...
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r--demux/demux_mkv.c87
1 files changed, 40 insertions, 47 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index ec98bc81a9..b0e7ed0ac2 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -129,7 +129,6 @@ typedef struct mkv_track {
int realmedia;
int64_t rv_kf_base;
int rv_kf_pts;
- double rv_pts; /* previous video timestamp */
double ra_pts; /* previous audio timestamp */
/** realaudio descrambling */
@@ -1940,49 +1939,43 @@ static int demux_mkv_read_block_lacing(bstr *buffer, int *laces,
#define SKIP_BITS(n) buffer<<=n
#define SHOW_BITS(n) ((buffer)>>(32-(n)))
-static double real_fix_timestamp(unsigned char *buf, unsigned int timestamp, unsigned int format, int64_t *kf_base, int *kf_pts, double *pts){
- double v_pts;
- unsigned char *s = buf + 1 + (*buf+1)*8;
- uint32_t buffer= (s[0]<<24) + (s[1]<<16) + (s[2]<<8) + s[3];
- unsigned int kf=timestamp;
-
- if(format==MP_FOURCC('R','V','3','0') || format==MP_FOURCC('R','V','4','0')){
- int pict_type;
- if(format==MP_FOURCC('R','V','3','0')){
- SKIP_BITS(3);
- pict_type= SHOW_BITS(2);
- SKIP_BITS(2 + 7);
- }else{
- SKIP_BITS(1);
- pict_type= SHOW_BITS(2);
- SKIP_BITS(2 + 7 + 3);
- }
- kf= SHOW_BITS(13); // kf= 2*SHOW_BITS(12);
-// if(pict_type==0)
- if(pict_type<=1){
- // I frame, sync timestamps:
- *kf_base=(int64_t)timestamp-kf;
- mp_msg(MSGT_DEMUX, MSGL_DBG2,"\nTS: base=%08"PRIX64"\n",*kf_base);
- kf=timestamp;
+static int64_t real_fix_timestamp(unsigned char *buf, int len, int64_t timestamp,
+ unsigned int format, int64_t *kf_base,
+ int *kf_pts)
+{
+ if (format != MP_FOURCC('R', 'V', '3', '0') &&
+ format != MP_FOURCC('R', 'V', '4', '0'))
+ return timestamp;
+
+ if (len < 1) // invalid packet
+ return timestamp;
+
+ int offset = 1 + (buf[0] + 1) * 8;
+ if (offset + 4 > len) // invalid packet
+ return timestamp;
+
+ int hdr = AV_RB32(buf + offset);
+ int pict_type, pts;
+ if (format == MP_FOURCC('R', 'V', '3', '0')) {
+ pict_type = (hdr >> 27) & 3;
+ pts = (hdr >> 7) & 0x1FFF;
+ } else {
+ pict_type = (hdr >> 29) & 3;
+ pts = (hdr >> 6) & 0x1FFF;
+ }
+
+ if (pict_type != 3) {
+ *kf_base = timestamp;
+ *kf_pts = pts;
} else {
- // P/B frame, merge timestamps:
- int64_t tmp=(int64_t)timestamp-*kf_base;
- kf|=tmp&(~0x1fff); // combine with packet timestamp
- if(kf<tmp-4096) kf+=8192; else // workaround wrap-around problems
- if(kf>tmp+4096) kf-=8192;
- kf+=*kf_base;
- }
- if(pict_type != 3){ // P || I frame -> swap timestamps
- unsigned int tmp=kf;
- kf=*kf_pts;
- *kf_pts=tmp;
-// if(kf<=tmp) kf=0;
- }
- }
- v_pts=kf*0.001f;
-// if(pts && (v_pts<*pts || !kf)) v_pts=*pts+frametime;
- if(pts) *pts=v_pts;
- return v_pts;
+ if (pict_type != 3) {
+ timestamp = *kf_base + ((pts - *kf_pts) & 0x1FFF);
+ } else {
+ timestamp = *kf_base - ((*kf_pts - pts) & 0x1FFF);
+ }
+ }
+
+ return timestamp;
}
static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
@@ -1990,19 +1983,19 @@ static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
demux_packet_t *dp;
- uint32_t timestamp = mkv_d->last_pts * 1000;
+ int64_t timestamp = mkv_d->last_pts * 1000;
dp = new_demux_packet_from(data.start, data.len);
if (mkv_d->v_skip_to_keyframe) {
dp->pts = mkv_d->last_pts;
track->rv_kf_base = 0;
- track->rv_kf_pts = timestamp;
+ track->rv_kf_pts = 0;
} else {
dp->pts =
- real_fix_timestamp(dp->buffer, timestamp,
+ real_fix_timestamp(dp->buffer, dp->len, timestamp,
track->stream->video->bih->biCompression,
- &track->rv_kf_base, &track->rv_kf_pts, NULL);
+ &track->rv_kf_base, &track->rv_kf_pts) * 0.001;
}
dp->pos = mkv_d->last_filepos;
dp->keyframe = keyframe;