Przeglądaj źródła

Fix lateTime, added bw filter

Dominic Szablewski 12 lat temu
rodzic
commit
a771daeb7a
1 zmienionych plików z 64 dodań i 11 usunięć
  1. 64 11
      jsmpg.js

+ 64 - 11
jsmpg.js Wyświetl plik

@@ -30,6 +30,8 @@ var jsmpeg = window.jsmpeg = function( url, opts ) {
30 30
 	this.autoplay = !!opts.autoplay;
31 31
 	this.loop = !!opts.loop;
32 32
 	this.externalLoadCallback = opts.onload || null;
33
+	this.bwFilter = opts.bwFilter || false;
34
+	this.externalDecodeCallback = opts.ondecodeframe || null;
33 35
 
34 36
 	this.customIntraQuantMatrix = new Uint8Array(64);
35 37
 	this.customNonIntraQuantMatrix = new Uint8Array(64);
@@ -53,6 +55,8 @@ var jsmpeg = window.jsmpeg = function( url, opts ) {
53 55
 
54 56
 jsmpeg.prototype.waitForIntraFrame = true;
55 57
 jsmpeg.prototype.socketBufferSize = 512 * 1024; // 512kb each
58
+jsmpeg.prototype.onlostconnection = null;
59
+
56 60
 jsmpeg.prototype.initSocketClient = function( client ) {
57 61
 	this.buffer = new BitReader(new ArrayBuffer(this.socketBufferSize));
58 62
 
@@ -119,9 +123,8 @@ jsmpeg.prototype.receiveSocketMessage = function( event ) {
119 123
 
120 124
 	// If we are still here, we found the next picture start code!
121 125
 
122
-
123
-
124
-	// Skip picture decoding until we find the first intra frame
126
+	
127
+	// Skip picture decoding until we find the first intra frame?
125 128
 	if( this.waitForIntraFrame ) {
126 129
 		next.advance(10); // skip temporalReference
127 130
 		if( next.getBits(3) == PICTURE_TYPE_I ) {
@@ -138,7 +141,7 @@ jsmpeg.prototype.receiveSocketMessage = function( event ) {
138 141
 	}
139 142
 
140 143
 	
141
-	// Copy the picture chunk over to 'buffer' and schedule decoding.
144
+	// Copy the picture chunk over to 'this.buffer' and schedule decoding.
142 145
 	var chunkEnd = ((next.index) >> 3);
143 146
 
144 147
 	if( chunkEnd > next.chunkBegin ) {
@@ -181,9 +184,12 @@ jsmpeg.prototype.didStartRecordingCallback = null;
181 184
 
182 185
 jsmpeg.prototype.recordBuffers = [];
183 186
 
187
+jsmpeg.prototype.canRecord = function(){
188
+	return (this.client && this.client.readyState == this.client.OPEN);
189
+};
190
+
184 191
 jsmpeg.prototype.startRecording = function(callback) {
185
-	if( !this.client ) {
186
-		throw("Can't record when loading from file.");
192
+	if( !this.canRecord() ) {
187 193
 		return;
188 194
 	}
189 195
 	
@@ -192,6 +198,9 @@ jsmpeg.prototype.startRecording = function(callback) {
192 198
 	this.isRecording = true;
193 199
 	this.recorderWaitForIntraFrame = true;
194 200
 	this.didStartRecordingCallback = callback || null;
201
+
202
+	this.recordedFrames = 0;
203
+	this.recordedSize = 0;
195 204
 	
196 205
 	// Fudge a simple Sequence Header for the MPEG file
197 206
 	
@@ -300,6 +309,7 @@ jsmpeg.prototype.loadCallback = function(file) {
300 309
 
301 310
 jsmpeg.prototype.play = function(file) {
302 311
 	if( this.playing ) { return; }
312
+	this.targetTime = Date.now();
303 313
 	this.playing = true;
304 314
 	this.scheduleNextFrame();
305 315
 };
@@ -360,6 +370,7 @@ jsmpeg.prototype.firstSequenceHeader = 0;
360 370
 jsmpeg.prototype.targetTime = 0;
361 371
 
362 372
 jsmpeg.prototype.nextFrame = function() {
373
+	if( !this.buffer ) { return; }
363 374
 	while(true) {
364 375
 		var code = this.buffer.findNextMPEGStartCode();
365 376
 		
@@ -389,9 +400,9 @@ jsmpeg.prototype.nextFrame = function() {
389 400
 };
390 401
 
391 402
 jsmpeg.prototype.scheduleNextFrame = function() {
392
-	var wait = (1000/this.pictureRate) - this.lateTime;
403
+	this.lateTime = Date.now() - this.targetTime;
404
+	var wait = Math.max(0, (1000/this.pictureRate) - this.lateTime);
393 405
 	this.targetTime = Date.now() + wait;
394
-
395 406
 	if( wait < 18 ) {
396 407
 		this.scheduleAnimation();
397 408
 	}
@@ -472,6 +483,7 @@ jsmpeg.prototype.initBuffers = function() {
472 483
 	this.canvas.height = this.height;
473 484
 	
474 485
 	this.currentRGBA = this.canvasContext.getImageData(0, 0, this.width, this.height);
486
+	this.currentRGBA32 = new Uint32Array( this.currentRGBA.data.buffer );
475 487
 	this.fillArray(this.currentRGBA.data, 255);
476 488
 };
477 489
 
@@ -541,8 +553,17 @@ jsmpeg.prototype.decodePicture = function(skipOutput) {
541 553
 	
542 554
 	
543 555
 	if( skipOutput != DECODE_SKIP_OUTPUT ) {
544
-		this.YCbCrToRGBA();
556
+		if( this.bwFilter ) {
557
+			this.YToRGBA();
558
+		}
559
+		else {
560
+			this.YCbCrToRGBA();	
561
+		}
545 562
 		this.canvasContext.putImageData(this.currentRGBA, 0, 0);
563
+
564
+		if(this.externalDecodeCallback) {
565
+			this.externalDecodeCallback(this, this.canvas);
566
+		}
546 567
 	}
547 568
 	
548 569
 	// If this is a reference picutre then rotate the prediction pointers
@@ -577,10 +598,11 @@ jsmpeg.prototype.YCbCrToRGBA = function() {
577 598
 	var pCr = this.currentCr;
578 599
 	var pRGBA = this.currentRGBA.data;
579 600
 
580
-
581
-
582 601
 	// Chroma values are the same for each block of 4 pixels, so we proccess
583 602
 	// 2 lines at a time, 2 neighboring pixels each.
603
+	// I wish we could use 32bit writes to the RGBA buffer instead of writing
604
+	// each byte separately, but we need the automatic clamping of the RGBA
605
+	// buffer.
584 606
 
585 607
 	var yIndex1 = 0;
586 608
 	var yIndex2 = this.codedWidth;
@@ -643,6 +665,31 @@ jsmpeg.prototype.YCbCrToRGBA = function() {
643 665
 	}
644 666
 };
645 667
 
668
+jsmpeg.prototype.YToRGBA = function() {	
669
+	// Luma only
670
+
671
+	var pY = this.currentY;
672
+	var pRGBA = this.currentRGBA32;
673
+
674
+	var yIndex = 0;
675
+	var yNext2Lines = (this.codedWidth - this.width);
676
+
677
+	var rgbaIndex = 0;	
678
+	var cols = this.width;
679
+	var rows = this.height;
680
+
681
+	var y;
682
+
683
+	for( var row = 0; row < rows; row++ ) {
684
+		for( var col = 0; col < cols; col++ ) {
685
+			y = pY[yIndex++];
686
+			pRGBA[rgbaIndex++] = 0xff000000 | y << 16 | y << 8 | y;
687
+		}
688
+		
689
+		yIndex += yNext2Lines;
690
+	}
691
+};
692
+
646 693
 
647 694
 
648 695
 
@@ -857,6 +904,7 @@ jsmpeg.prototype.copyMacroblock = function(motionH, motionV, sY, sCr, sCb ) {
857 904
 		H, V, oddH, oddV,
858 905
 		src, dest, last;
859 906
 
907
+	// We use 32bit writes here
860 908
 	var dY = this.currentY32;
861 909
 	var dCb = this.currentCb32;
862 910
 	var dCr = this.currentCr32;
@@ -948,7 +996,12 @@ jsmpeg.prototype.copyMacroblock = function(motionH, motionV, sY, sCr, sCb ) {
948 996
 		}
949 997
 	}
950 998
 	
999
+	if( this.bwFilter ) {
1000
+		// No need to copy chrominance when black&white filter is active
1001
+		return;
1002
+	}
951 1003
 	
1004
+
952 1005
 	// Chrominance
953 1006
 	
954 1007
 	width = this.halfWidth;