Optimization of memory and draw operations, and proper treatment of filled…

Optimization of memory and draw operations, and proper treatment of filled regions (as far as we can infer from the specs)
parent 0c49b81b
...@@ -15,9 +15,6 @@ ...@@ -15,9 +15,6 @@
*/ */
package com.google.android.exoplayer2.text.dvbsubs; package com.google.android.exoplayer2.text.dvbsubs;
import android.graphics.Bitmap;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.Subtitle; import com.google.android.exoplayer2.text.Subtitle;
...@@ -28,12 +25,11 @@ import java.util.List; ...@@ -28,12 +25,11 @@ import java.util.List;
final class DvbSubsSubtitle implements Subtitle { final class DvbSubsSubtitle implements Subtitle {
private final List<Cue> cues; private final List<Cue> cues;
public DvbSubsSubtitle(Bitmap data) { public DvbSubsSubtitle(List<Cue> cues) {
if (data == null) { if (cues == null) {
this.cues = Collections.emptyList(); this.cues = Collections.emptyList();
} else { } else {
Cue cue = new Cue(data, 0, Cue.ANCHOR_TYPE_START, 0, Cue.ANCHOR_TYPE_START, 1, (float) data.getWidth()/data.getHeight()); this.cues = cues;
this.cues = Collections.singletonList(cue);
} }
} }
......
...@@ -28,8 +28,12 @@ import android.util.Log; ...@@ -28,8 +28,12 @@ import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.core.BuildConfig; import com.google.android.exoplayer2.core.BuildConfig;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableBitArray;
import java.util.ArrayList;
import java.util.List;
public class DvbSubtitlesParser { public class DvbSubtitlesParser {
...@@ -111,17 +115,15 @@ public class DvbSubtitlesParser { ...@@ -111,17 +115,15 @@ public class DvbSubtitlesParser {
/* Constants */ /* Constants */
private static final int UNDEF_PAGE = -1; private static final int UNDEF_PAGE = -1;
private final int NUM_BITMAPS = 4;
/* instance variables */ /* instance variables */
private Paint defaultPaintObject = new Paint(); private Paint defaultPaint = new Paint();
private Paint fillRegionPaintObject = new Paint(); private Paint fillRegionPaint = new Paint();
private Paint debugRegionPaintObject = new Paint(); private Paint debugRegionPaint = new Paint();
private Paint debugObjectPaintObject = new Paint(); private Paint debugObjectPaint = new Paint();
private Canvas[] canvasObjects = new Canvas[NUM_BITMAPS]; private Canvas canvas = new Canvas();
private Bitmap[] bitmaps = new Bitmap[NUM_BITMAPS]; private Bitmap bitmap;
private Bitmap lastValidBitmap;
private int currentBitmap = 0;
private static ParsableBitArray tsStream; private static ParsableBitArray tsStream;
private SubtitleService subtitleService; private SubtitleService subtitleService;
...@@ -133,13 +135,13 @@ public class DvbSubtitlesParser { ...@@ -133,13 +135,13 @@ public class DvbSubtitlesParser {
// subtitle page // subtitle page
DisplayDefinition displayDefinition; DisplayDefinition displayDefinition;
PageComposition pageComposition; PageComposition pageComposition;
SparseArray<RegionComposition> regions = new SparseArray<RegionComposition>(); SparseArray<RegionComposition> regions = new SparseArray<>();
SparseArray<ClutDefinition> cluts = new SparseArray<ClutDefinition>(); SparseArray<ClutDefinition> cluts = new SparseArray<>();
SparseArray<ObjectData> objects = new SparseArray<ObjectData>(); SparseArray<ObjectData> objects = new SparseArray<>();
// ancillary page // ancillary page
SparseArray<ClutDefinition> ancillaryCluts = new SparseArray<ClutDefinition>(); SparseArray<ClutDefinition> ancillaryCluts = new SparseArray<>();
SparseArray<ObjectData> ancillaryObjects = new SparseArray<ObjectData>(); SparseArray<ObjectData> ancillaryObjects = new SparseArray<>();
} }
/* The displays dimensions [7.2.1] */ /* The displays dimensions [7.2.1] */
...@@ -157,11 +159,9 @@ public class DvbSubtitlesParser { ...@@ -157,11 +159,9 @@ public class DvbSubtitlesParser {
int displayWindowVerticalPositionMaximum = 575; int displayWindowVerticalPositionMaximum = 575;
void updateBitmapResolution() { void updateBitmapResolution() {
for (int i = 0; i < NUM_BITMAPS; i++) { bitmap = Bitmap.createBitmap(this.displayWidth + 1, this.displayHeight + 1,
bitmaps[i] = Bitmap.createBitmap(this.displayWidth + 1, this.displayHeight + 1, Bitmap.Config.ARGB_8888);
Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmap);
canvasObjects[i] = new Canvas(bitmaps[i]);
}
} }
} }
...@@ -171,7 +171,7 @@ public class DvbSubtitlesParser { ...@@ -171,7 +171,7 @@ public class DvbSubtitlesParser {
int pageTimeOut; /* in seconds */ int pageTimeOut; /* in seconds */
int pageVersionNumber; int pageVersionNumber;
int pageState; int pageState;
SparseArray<PageRegion> pageRegions = new SparseArray<PageRegion>(); SparseArray<PageRegion> pageRegions = new SparseArray<>();
} }
private class PageRegion { private class PageRegion {
...@@ -196,6 +196,7 @@ public class DvbSubtitlesParser { ...@@ -196,6 +196,7 @@ public class DvbSubtitlesParser {
int region4bitPixelCode; int region4bitPixelCode;
int region2bitPixelCode; int region2bitPixelCode;
SparseArray<RegionObject> regionObjects = new SparseArray<>(); SparseArray<RegionObject> regionObjects = new SparseArray<>();
Cue cue;
} }
/* The entry in the palette CLUT */ /* The entry in the palette CLUT */
...@@ -435,30 +436,27 @@ public class DvbSubtitlesParser { ...@@ -435,30 +436,27 @@ public class DvbSubtitlesParser {
this.subtitleService = new SubtitleService(); this.subtitleService = new SubtitleService();
this.flags = flags; this.flags = flags;
this.defaultPaintObject.setStyle(Paint.Style.FILL_AND_STROKE); this.defaultPaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.defaultPaintObject.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); this.defaultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
this.defaultPaintObject.setPathEffect(null); this.defaultPaint.setPathEffect(null);
this.fillRegionPaintObject.setStyle(Paint.Style.FILL); this.fillRegionPaint.setStyle(Paint.Style.FILL);
this.fillRegionPaintObject.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); this.fillRegionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
this.fillRegionPaintObject.setPathEffect(null); this.fillRegionPaint.setPathEffect(null);
this.debugRegionPaintObject.setColor(0xff00ff00); this.debugRegionPaint.setColor(0xff00ff00);
this.debugRegionPaintObject.setStyle(Paint.Style.STROKE); this.debugRegionPaint.setStyle(Paint.Style.STROKE);
this.debugRegionPaintObject.setPathEffect(new DashPathEffect(new float[] {2,2}, 0)); this.debugRegionPaint.setPathEffect(new DashPathEffect(new float[] {2,2}, 0));
this.debugObjectPaintObject.setColor(0xffff0000); this.debugObjectPaint.setColor(0xffff0000);
this.debugObjectPaintObject.setStyle(Paint.Style.STROKE); this.debugObjectPaint.setStyle(Paint.Style.STROKE);
this.debugObjectPaintObject.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0)); this.debugObjectPaint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
this.subtitleService.subtitlePage = subtitlePage; this.subtitleService.subtitlePage = subtitlePage;
this.subtitleService.ancillaryPage = ancillaryPage; this.subtitleService.ancillaryPage = ancillaryPage;
this.subtitleService.displayDefinition = new DisplayDefinition(); this.subtitleService.displayDefinition = new DisplayDefinition();
this.subtitleService.displayDefinition.updateBitmapResolution(); this.subtitleService.displayDefinition.updateBitmapResolution();
this.currentBitmap = 0;
this.lastValidBitmap = bitmaps[currentBitmap];
} }
private void parseSubtitlingSegment() { private void parseSubtitlingSegment() {
...@@ -492,7 +490,6 @@ public class DvbSubtitlesParser { ...@@ -492,7 +490,6 @@ public class DvbSubtitlesParser {
tempDisplay.flags != subtitleService.displayDefinition.flags) { tempDisplay.flags != subtitleService.displayDefinition.flags) {
subtitleService.displayDefinition = tempDisplay; subtitleService.displayDefinition = tempDisplay;
subtitleService.displayDefinition.updateBitmapResolution(); subtitleService.displayDefinition.updateBitmapResolution();
lastValidBitmap = bitmaps[currentBitmap];
} else { } else {
subtitleService.displayDefinition.versionNumber = tempDisplay.versionNumber; subtitleService.displayDefinition.versionNumber = tempDisplay.versionNumber;
} }
...@@ -938,7 +935,7 @@ public class DvbSubtitlesParser { ...@@ -938,7 +935,7 @@ public class DvbSubtitlesParser {
ObjectData object = new ObjectData(); ObjectData object = new ObjectData();
object.pageId = tsStream.readBits(16); object.pageId = tsStream.readBits(16);
int remainingSegmentLength = tsStream.readBits(16); tsStream.skipBits(16); // remainingSegmentLength
object.objectId = tsStream.readBits(16); object.objectId = tsStream.readBits(16);
object.objectVersionNumber = tsStream.readBits(4); object.objectVersionNumber = tsStream.readBits(4);
object.objectCodingMethod = tsStream.readBits(2); object.objectCodingMethod = tsStream.readBits(2);
...@@ -947,21 +944,17 @@ public class DvbSubtitlesParser { ...@@ -947,21 +944,17 @@ public class DvbSubtitlesParser {
} }
tsStream.skipBits(1); tsStream.skipBits(1);
remainingSegmentLength -= 3;
if (object.objectCodingMethod == DVBSUB_ODS_CHAR_CODED) { if (object.objectCodingMethod == DVBSUB_ODS_CHAR_CODED) {
/* not implemented yet */ /* not implemented yet */
object.numberOfCodes = tsStream.readBits(8); object.numberOfCodes = tsStream.readBits(8);
tsStream.skipBits(object.numberOfCodes * 16); tsStream.skipBits(object.numberOfCodes * 16);
remainingSegmentLength -= object.numberOfCodes * 2;
} else if (object.objectCodingMethod == DVBSUB_ODS_PIXEL_CODED) { } else if (object.objectCodingMethod == DVBSUB_ODS_PIXEL_CODED) {
object.topFieldDataLength = tsStream.readBits(16); object.topFieldDataLength = tsStream.readBits(16);
object.bottomFieldDataLength = tsStream.readBits(16); object.bottomFieldDataLength = tsStream.readBits(16);
remainingSegmentLength -= 4;
object.topFieldData = new byte[object.topFieldDataLength]; object.topFieldData = new byte[object.topFieldDataLength];
System.arraycopy(tsStream.data, tsStream.getPosition() / 8, object.topFieldData, 0, object.topFieldDataLength); System.arraycopy(tsStream.data, tsStream.getPosition() / 8, object.topFieldData, 0, object.topFieldDataLength);
tsStream.skipBits(object.topFieldDataLength * 8); tsStream.skipBits(object.topFieldDataLength * 8);
remainingSegmentLength -= object.topFieldDataLength;
object.bottomFieldData = new byte[object.bottomFieldDataLength]; object.bottomFieldData = new byte[object.bottomFieldDataLength];
if (object.bottomFieldDataLength == 0) { if (object.bottomFieldDataLength == 0) {
...@@ -970,8 +963,6 @@ public class DvbSubtitlesParser { ...@@ -970,8 +963,6 @@ public class DvbSubtitlesParser {
System.arraycopy(tsStream.data, tsStream.getPosition() / 8, object.bottomFieldData, 0, object.bottomFieldDataLength); System.arraycopy(tsStream.data, tsStream.getPosition() / 8, object.bottomFieldData, 0, object.bottomFieldDataLength);
tsStream.skipBits(object.bottomFieldDataLength * 8); tsStream.skipBits(object.bottomFieldDataLength * 8);
} }
remainingSegmentLength -= object.bottomFieldDataLength;
} }
return object; return object;
...@@ -1190,9 +1181,9 @@ public class DvbSubtitlesParser { ...@@ -1190,9 +1181,9 @@ public class DvbSubtitlesParser {
if (runLength != 0 && paint) { if (runLength != 0 && paint) {
colour = clutMapTable != null ? clutEntries[clutMapTable[clutIdx]].ARGB colour = clutMapTable != null ? clutEntries[clutMapTable[clutIdx]].ARGB
: clutEntries[clutIdx].ARGB; : clutEntries[clutIdx].ARGB;
defaultPaintObject.setColor(colour); defaultPaint.setColor(colour);
canvasObjects[currentBitmap].drawRect( canvas.drawRect(
column, line, column + runLength, line + lineHeigth, defaultPaintObject); column, line, column + runLength, line + lineHeigth, defaultPaint);
} }
column += runLength; column += runLength;
...@@ -1292,9 +1283,9 @@ public class DvbSubtitlesParser { ...@@ -1292,9 +1283,9 @@ public class DvbSubtitlesParser {
if (runLength != 0 && paint) { if (runLength != 0 && paint) {
colour = clutMapTable != null ? clutEntries[clutMapTable[clutIdx]].ARGB colour = clutMapTable != null ? clutEntries[clutMapTable[clutIdx]].ARGB
: clutEntries[clutIdx].ARGB; : clutEntries[clutIdx].ARGB;
defaultPaintObject.setColor(colour); defaultPaint.setColor(colour);
canvasObjects[currentBitmap].drawRect( canvas.drawRect(
column, line, column + runLength, line + lineHeigth, defaultPaintObject); column, line, column + runLength, line + lineHeigth, defaultPaint);
} }
column += runLength; column += runLength;
...@@ -1359,9 +1350,9 @@ public class DvbSubtitlesParser { ...@@ -1359,9 +1350,9 @@ public class DvbSubtitlesParser {
if (runLength != 0 && paint) { if (runLength != 0 && paint) {
colour = clutMapTable != null ? clutEntries[clutMapTable[clutIdx]].ARGB colour = clutMapTable != null ? clutEntries[clutMapTable[clutIdx]].ARGB
: clutEntries[clutIdx].ARGB; : clutEntries[clutIdx].ARGB;
defaultPaintObject.setColor(colour); defaultPaint.setColor(colour);
canvasObjects[currentBitmap].drawRect( canvas.drawRect(
column, line, column + runLength, line + lineHeigth, defaultPaintObject); column, line, column + runLength, line + lineHeigth, defaultPaint);
} }
column += runLength; column += runLength;
...@@ -1370,7 +1361,7 @@ public class DvbSubtitlesParser { ...@@ -1370,7 +1361,7 @@ public class DvbSubtitlesParser {
return column - savedColumn; return column - savedColumn;
} }
public Bitmap dvbSubsDecode(byte[] input, int inputSize) { List<Cue> dvbSubsDecode(byte[] input, int inputSize) {
/* process PES PACKET. ETSI EN 300 743 7.1 /* process PES PACKET. ETSI EN 300 743 7.1
...@@ -1416,6 +1407,7 @@ public class DvbSubtitlesParser { ...@@ -1416,6 +1407,7 @@ public class DvbSubtitlesParser {
if (sync == 0xff || (isSet(FLAG_PES_STRIPPED_DVBSUB) && tsStream.bitsLeft() == 0)) { // end_of_PES_data_field_marker if (sync == 0xff || (isSet(FLAG_PES_STRIPPED_DVBSUB) && tsStream.bitsLeft() == 0)) { // end_of_PES_data_field_marker
// paint the current Subtitle definition // paint the current Subtitle definition
if (subtitleService.pageComposition != null) { if (subtitleService.pageComposition != null) {
List<Cue> cueList = new ArrayList<>();
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Log.d(TAG, "Rendering subtitle. w: " + subtitleService.displayDefinition.displayWidth + Log.d(TAG, "Rendering subtitle. w: " + subtitleService.displayDefinition.displayWidth +
...@@ -1456,7 +1448,7 @@ public class DvbSubtitlesParser { ...@@ -1456,7 +1448,7 @@ public class DvbSubtitlesParser {
} }
// clip object drawing to the current region and display definition window // clip object drawing to the current region and display definition window
canvasObjects[currentBitmap].clipRect( canvas.clipRect(
baseHorizontalAddress, baseVerticalAddress, baseHorizontalAddress, baseVerticalAddress,
Math.min(baseHorizontalAddress + regionComposition.regionWidth, Math.min(baseHorizontalAddress + regionComposition.regionWidth,
subtitleService.displayDefinition.displayWindowHorizontalPositionMaximum), subtitleService.displayDefinition.displayWindowHorizontalPositionMaximum),
...@@ -1470,26 +1462,6 @@ public class DvbSubtitlesParser { ...@@ -1470,26 +1462,6 @@ public class DvbSubtitlesParser {
} }
} }
// fill the region if needed
if ((regionComposition.flags & REGION_FILL_FLAG )!= 0) {
int colour;
if (regionComposition.regionDepth == DVBSUB_RCS_BITDEPTH_8) {
colour = clut.clutEntries8bit[regionComposition.region8bitPixelCode].ARGB;
} else if (regionComposition.regionDepth == DVBSUB_RCS_BITDEPTH_4) {
colour = clut.clutEntries4bit[regionComposition.region4bitPixelCode].ARGB;
} else {
colour = clut.clutEntries2bit[regionComposition.region2bitPixelCode].ARGB;
}
fillRegionPaintObject.setColor(colour);
canvasObjects[currentBitmap].drawRect(
baseHorizontalAddress, baseVerticalAddress,
baseHorizontalAddress + regionComposition.regionWidth ,
baseVerticalAddress + regionComposition.regionHeight,
fillRegionPaintObject);
}
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Log.d(TAG, " Region: " + regionKey + " (x/y/w/h): (" + Log.d(TAG, " Region: " + regionKey + " (x/y/w/h): (" +
baseHorizontalAddress + "/" + baseVerticalAddress + "/" + baseHorizontalAddress + "/" + baseVerticalAddress + "/" +
...@@ -1497,11 +1469,11 @@ public class DvbSubtitlesParser { ...@@ -1497,11 +1469,11 @@ public class DvbSubtitlesParser {
(baseVerticalAddress + regionComposition.regionHeight - 1) + ")" (baseVerticalAddress + regionComposition.regionHeight - 1) + ")"
); );
canvasObjects[currentBitmap].drawRect( canvas.drawRect(
baseHorizontalAddress, baseVerticalAddress, baseHorizontalAddress, baseVerticalAddress,
baseHorizontalAddress + regionComposition.regionWidth - 1, baseHorizontalAddress + regionComposition.regionWidth - 1,
baseVerticalAddress + regionComposition.regionHeight - 1, baseVerticalAddress + regionComposition.regionHeight - 1,
debugRegionPaintObject); debugRegionPaint);
} }
RegionObject regionObject; RegionObject regionObject;
...@@ -1517,12 +1489,12 @@ public class DvbSubtitlesParser { ...@@ -1517,12 +1489,12 @@ public class DvbSubtitlesParser {
(baseVerticalAddress + regionObject.objectVerticalPosition) + ")" (baseVerticalAddress + regionObject.objectVerticalPosition) + ")"
); );
canvasObjects[currentBitmap].drawRect( canvas.drawRect(
baseHorizontalAddress + regionObject.objectHorizontalPosition, baseHorizontalAddress + regionObject.objectHorizontalPosition,
baseVerticalAddress + regionObject.objectVerticalPosition, baseVerticalAddress + regionObject.objectVerticalPosition,
baseHorizontalAddress + regionObject.objectHorizontalPosition + regionComposition.regionWidth - 1, baseHorizontalAddress + regionObject.objectHorizontalPosition + regionComposition.regionWidth - 1,
baseVerticalAddress + regionObject.objectVerticalPosition + regionComposition.regionHeight - 1, baseVerticalAddress + regionObject.objectVerticalPosition + regionComposition.regionHeight - 1,
debugObjectPaintObject); debugObjectPaint);
} }
if ((object = subtitleService.objects.get(regionObject.objectId)) == null) { if ((object = subtitleService.objects.get(regionObject.objectId)) == null) {
...@@ -1536,18 +1508,41 @@ public class DvbSubtitlesParser { ...@@ -1536,18 +1508,41 @@ public class DvbSubtitlesParser {
baseVerticalAddress + regionObject.objectVerticalPosition); baseVerticalAddress + regionObject.objectVerticalPosition);
} }
}
lastValidBitmap = bitmaps[currentBitmap]; // fill the region if needed
currentBitmap = (currentBitmap + 1) % NUM_BITMAPS; if ((regionComposition.flags & REGION_FILL_FLAG )!= 0) {
canvasObjects[currentBitmap].clipRect(0,0, int colour;
subtitleService.displayDefinition.displayWidth, if (regionComposition.regionDepth == DVBSUB_RCS_BITDEPTH_8) {
subtitleService.displayDefinition.displayHeight, colour = clut.clutEntries8bit[regionComposition.region8bitPixelCode].ARGB;
Region.Op.REPLACE); } else if (regionComposition.regionDepth == DVBSUB_RCS_BITDEPTH_4) {
canvasObjects[currentBitmap].drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); colour = clut.clutEntries4bit[regionComposition.region4bitPixelCode].ARGB;
} else {
colour = clut.clutEntries2bit[regionComposition.region2bitPixelCode].ARGB;
}
fillRegionPaint.setColor(colour);
return lastValidBitmap; canvas.drawRect(
} baseHorizontalAddress, baseVerticalAddress,
baseHorizontalAddress + regionComposition.regionWidth ,
baseVerticalAddress + regionComposition.regionHeight,
fillRegionPaint);
}
Bitmap cueBitmap = Bitmap.createBitmap(bitmap,
baseHorizontalAddress, baseVerticalAddress,
regionComposition.regionWidth, regionComposition.regionHeight);
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
regionComposition.cue = new Cue(cueBitmap,
(float) baseHorizontalAddress / subtitleService.displayDefinition.displayWidth, Cue.ANCHOR_TYPE_START,
(float) baseVerticalAddress / subtitleService.displayDefinition.displayHeight, Cue.ANCHOR_TYPE_START,
(float) regionComposition.regionWidth / subtitleService.displayDefinition.displayWidth,
(float) subtitleService.displayDefinition.displayWidth / subtitleService.displayDefinition.displayHeight);
cueList.add(regionComposition.cue);
}
return cueList; }
} else { } else {
Log.d(TAG,"Unexpected..."); Log.d(TAG,"Unexpected...");
} }
......
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 sign in to comment